blob: d1b5402cd6fe8167385d9d563955fcf2c80f2c63 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * budget-ci.c: driver for the SAA7146 based Budget DVB cards
3 *
4 * Compiled from various sources by Michael Hunold <michael@mihu.de>
5 *
6 * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
7 * partially based on the Siemens DVB driver by Ralph+Marcus Metzler
8 *
9 * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
27 *
28 *
29 * the project's page is at http://www.linuxtv.org/dvb/
30 */
31
32#include "budget.h"
33
34#include <linux/module.h>
35#include <linux/errno.h>
36#include <linux/slab.h>
37#include <linux/interrupt.h>
38#include <linux/input.h>
39#include <linux/spinlock.h>
David Hardeman2520fff2006-12-02 21:16:05 -020040#include <media/ir-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#include "dvb_ca_en50221.h"
43#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070044#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "tda1004x.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030046#include "lnbp21.h"
47#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030048#include "bsru6.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
David Härdemanecba77f2006-10-27 20:56:51 -030050/*
51 * Regarding DEBIADDR_IR:
52 * Some CI modules hang if random addresses are read.
53 * Using address 0x4000 for the IR read means that we
54 * use the same address as for CI version, which should
55 * be a safe default.
56 */
57#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#define DEBIADDR_CICONTROL 0x0000
59#define DEBIADDR_CIVERSION 0x4000
60#define DEBIADDR_IO 0x1000
61#define DEBIADDR_ATTR 0x3000
62
63#define CICONTROL_RESET 0x01
64#define CICONTROL_ENABLETS 0x02
65#define CICONTROL_CAMDETECT 0x08
66
67#define DEBICICTL 0x00420000
68#define DEBICICAM 0x02420000
69
70#define SLOTSTATUS_NONE 1
71#define SLOTSTATUS_PRESENT 2
72#define SLOTSTATUS_RESET 4
73#define SLOTSTATUS_READY 8
74#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
75
David Hardeman2520fff2006-12-02 21:16:05 -020076/* Milliseconds during which key presses are regarded as key repeat and during
77 * which the debounce logic is active
78 */
79#define IR_REPEAT_TIMEOUT 350
80
81/* Some remotes sends multiple sequences per keypress (e.g. Zenith sends two),
82 * this setting allows the superflous sequences to be ignored
83 */
84static int debounce = 0;
85module_param(debounce, int, 0644);
86MODULE_PARM_DESC(debounce, "ignore repeated IR sequences (default: 0 = ignore no sequences)");
87
David Hardemandd2f3982006-12-02 21:16:05 -020088struct budget_ci_ir {
89 struct input_dev *dev;
90 struct tasklet_struct msp430_irq_tasklet;
91 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -020092 char phys[32];
David Hardeman2520fff2006-12-02 21:16:05 -020093 struct ir_input_state state;
David Hardemandd2f3982006-12-02 21:16:05 -020094};
95
Linus Torvalds1da177e2005-04-16 15:20:36 -070096struct budget_ci {
97 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 struct tasklet_struct ciintf_irq_tasklet;
99 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300100 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -0200102 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700103 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104};
105
David Hardeman2520fff2006-12-02 21:16:05 -0200106static void msp430_ir_keyup(unsigned long data)
107{
108 struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
109 ir_input_nokey(ir->dev, &ir->state);
110}
111
112static void msp430_ir_interrupt(unsigned long data)
113{
114 struct budget_ci *budget_ci = (struct budget_ci *) data;
115 struct input_dev *dev = budget_ci->ir.dev;
116 static int bounces = 0;
117 u32 ir_key;
118 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
119
120 if (command & 0x40) {
121 ir_key = command & 0x3f;
122
123 if (ir_key != dev->repeat_key && del_timer(&dev->timer))
124 /* We were still waiting for a keyup event but this is a new key */
125 ir_input_nokey(dev, &budget_ci->ir.state);
126
127 if (ir_key == dev->repeat_key && bounces > 0 && timer_pending(&dev->timer)) {
128 /* Ignore repeated key sequences if requested */
129 bounces--;
130 return;
131 }
132
133 if (!timer_pending(&dev->timer))
134 /* New keypress */
135 bounces = debounce;
136
137 /* Prepare a keyup event sometime in the future */
138 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT));
139
140 /* Generate a new or repeated keypress */
141 ir_input_keydown(dev, &budget_ci->ir.state, ir_key, command);
142 }
143}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145static void msp430_ir_debounce(unsigned long data)
146{
147 struct input_dev *dev = (struct input_dev *) data;
148
149 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300150 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
151 } else {
152 dev->rep[0] = 0;
153 dev->timer.expires = jiffies + HZ * 350 / 1000;
154 add_timer(&dev->timer);
155 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 }
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300157 input_sync(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158}
159
160static void msp430_ir_interrupt(unsigned long data)
161{
162 struct budget_ci *budget_ci = (struct budget_ci *) data;
David Hardemandd2f3982006-12-02 21:16:05 -0200163 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 unsigned int code =
165 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
166
167 if (code & 0x40) {
168 code &= 0x3f;
169
170 if (timer_pending(&dev->timer)) {
171 if (code == dev->repeat_key) {
172 ++dev->rep[0];
173 return;
174 }
175 del_timer(&dev->timer);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300176 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 }
178
179 if (!key_map[code]) {
180 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
181 return;
182 }
183
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300184 input_event(dev, EV_KEY, key_map[code], 1);
185 input_sync(dev);
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 /* initialize debounce and repeat */
188 dev->repeat_key = code;
189 /* Zenith remote _always_ sends 2 sequences */
190 dev->rep[0] = ~0;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300191 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(350));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 }
193}
194
195static int msp430_ir_init(struct budget_ci *budget_ci)
196{
197 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200198 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200199 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
David Hardemandd2f3982006-12-02 21:16:05 -0200201 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200202 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200203 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200204 error = -ENOMEM;
205 goto out1;
206 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
David Hardemandd2f3982006-12-02 21:16:05 -0200208 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
209 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200210 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
211 "pci-%s/ir0", pci_name(saa->pci));
212
David Hardemandd2f3982006-12-02 21:16:05 -0200213 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
David Hardeman5cc8ae02006-12-02 21:16:05 -0200215 input_dev->phys = budget_ci->ir.phys;
216 input_dev->id.bustype = BUS_PCI;
217 input_dev->id.version = 1;
218 if (saa->pci->subsystem_vendor) {
219 input_dev->id.vendor = saa->pci->subsystem_vendor;
220 input_dev->id.product = saa->pci->subsystem_device;
221 } else {
222 input_dev->id.vendor = saa->pci->vendor;
223 input_dev->id.product = saa->pci->device;
224 }
225# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
226 input_dev->cdev.dev = &saa->pci->dev;
227# else
228 input_dev->dev = &saa->pci->dev;
229# endif
230
David Hardeman2520fff2006-12-02 21:16:05 -0200231 /* Select keymap */
232 switch (budget_ci->budget.dev->pci->subsystem_device) {
233 case 0x100c:
234 case 0x100f:
235 case 0x1010:
236 case 0x1011:
237 case 0x1012:
238 case 0x1017:
239 /* The hauppauge keymap is a superset of these remotes */
240 ir_input_init(input_dev, &budget_ci->ir.state,
241 IR_TYPE_RC5, ir_codes_hauppauge_new);
242 break;
243 default:
244 /* unknown remote */
245 ir_input_init(input_dev, &budget_ci->ir.state,
246 IR_TYPE_RC5, ir_codes_budget_ci_old);
247 break;
248 }
249
250 /* initialise the key-up timeout handler */
251 input_dev->timer.function = msp430_ir_keyup;
252 input_dev->timer.data = (unsigned long) &budget_ci->ir;
253 input_dev->rep[REP_DELAY] = 1;
254 input_dev->rep[REP_PERIOD] = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
David Hardeman8cc532e2006-12-02 21:16:05 -0200256 error = input_register_device(input_dev);
257 if (error) {
258 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
259 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
David Hardeman8cc532e2006-12-02 21:16:05 -0200262 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
263 (unsigned long) budget_ci);
264
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
267
268 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200269
270out2:
271 input_free_device(input_dev);
272out1:
273 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274}
275
276static void msp430_ir_deinit(struct budget_ci *budget_ci)
277{
278 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200279 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
281 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
282 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200283 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300285 if (del_timer(&dev->timer)) {
David Hardeman2520fff2006-12-02 21:16:05 -0200286 ir_input_nokey(dev, &budget_ci->ir.state);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300287 input_sync(dev);
288 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
290 input_unregister_device(dev);
291}
292
293static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
294{
295 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
296
297 if (slot != 0)
298 return -EINVAL;
299
300 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
301 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
302}
303
304static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
305{
306 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
307
308 if (slot != 0)
309 return -EINVAL;
310
311 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
312 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
313}
314
315static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
316{
317 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
318
319 if (slot != 0)
320 return -EINVAL;
321
322 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
323 DEBIADDR_IO | (address & 3), 1, 1, 0);
324}
325
326static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
327{
328 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
329
330 if (slot != 0)
331 return -EINVAL;
332
333 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
334 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
335}
336
337static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
338{
339 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
340 struct saa7146_dev *saa = budget_ci->budget.dev;
341
342 if (slot != 0)
343 return -EINVAL;
344
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300345 if (budget_ci->ci_irq) {
346 // trigger on RISING edge during reset so we know when READY is re-asserted
347 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
348 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 budget_ci->slot_status = SLOTSTATUS_RESET;
350 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
351 msleep(1);
352 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
353 CICONTROL_RESET, 1, 0);
354
355 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
356 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
357 return 0;
358}
359
360static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
361{
362 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
363 struct saa7146_dev *saa = budget_ci->budget.dev;
364
365 if (slot != 0)
366 return -EINVAL;
367
368 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
369 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
370 return 0;
371}
372
373static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
374{
375 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
376 struct saa7146_dev *saa = budget_ci->budget.dev;
377 int tmp;
378
379 if (slot != 0)
380 return -EINVAL;
381
382 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
383
384 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
385 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
386 tmp | CICONTROL_ENABLETS, 1, 0);
387
388 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
389 return 0;
390}
391
392static void ciintf_interrupt(unsigned long data)
393{
394 struct budget_ci *budget_ci = (struct budget_ci *) data;
395 struct saa7146_dev *saa = budget_ci->budget.dev;
396 unsigned int flags;
397
398 // ensure we don't get spurious IRQs during initialisation
399 if (!budget_ci->budget.ci_present)
400 return;
401
402 // read the CAM status
403 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
404 if (flags & CICONTROL_CAMDETECT) {
405
406 // GPIO should be set to trigger on falling edge if a CAM is present
407 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
408
409 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
410 // CAM insertion IRQ
411 budget_ci->slot_status = SLOTSTATUS_PRESENT;
412 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
413 DVB_CA_EN50221_CAMCHANGE_INSERTED);
414
415 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
416 // CAM ready (reset completed)
417 budget_ci->slot_status = SLOTSTATUS_READY;
418 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
419
420 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
421 // FR/DA IRQ
422 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
423 }
424 } else {
425
426 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
427 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
428 // the CAM might not actually be ready yet.
429 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
430
431 // generate a CAM removal IRQ if we haven't already
432 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
433 // CAM removal IRQ
434 budget_ci->slot_status = SLOTSTATUS_NONE;
435 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
436 DVB_CA_EN50221_CAMCHANGE_REMOVED);
437 }
438 }
439}
440
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300441static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
442{
443 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
444 unsigned int flags;
445
446 // ensure we don't get spurious IRQs during initialisation
447 if (!budget_ci->budget.ci_present)
448 return -EINVAL;
449
450 // read the CAM status
451 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
452 if (flags & CICONTROL_CAMDETECT) {
453 // mark it as present if it wasn't before
454 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
455 budget_ci->slot_status = SLOTSTATUS_PRESENT;
456 }
457
458 // during a RESET, we check if we can read from IO memory to see when CAM is ready
459 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
460 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
461 budget_ci->slot_status = SLOTSTATUS_READY;
462 }
463 }
464 } else {
465 budget_ci->slot_status = SLOTSTATUS_NONE;
466 }
467
468 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
469 if (budget_ci->slot_status & SLOTSTATUS_READY) {
470 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
471 }
472 return DVB_CA_EN50221_POLL_CAM_PRESENT;
473 }
474
475 return 0;
476}
477
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478static int ciintf_init(struct budget_ci *budget_ci)
479{
480 struct saa7146_dev *saa = budget_ci->budget.dev;
481 int flags;
482 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300483 int ci_version;
484 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
486 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
487
488 // enable DEBI pins
489 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
490
491 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300492 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
493 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494 result = -ENODEV;
495 goto error;
496 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 // determine whether a CAM is present or not
499 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
500 budget_ci->slot_status = SLOTSTATUS_NONE;
501 if (flags & CICONTROL_CAMDETECT)
502 budget_ci->slot_status = SLOTSTATUS_PRESENT;
503
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300504 // version 0xa2 of the CI firmware doesn't generate interrupts
505 if (ci_version == 0xa2) {
506 ca_flags = 0;
507 budget_ci->ci_irq = 0;
508 } else {
509 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
510 DVB_CA_EN50221_FLAG_IRQ_FR |
511 DVB_CA_EN50221_FLAG_IRQ_DA;
512 budget_ci->ci_irq = 1;
513 }
514
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 // register CI interface
516 budget_ci->ca.owner = THIS_MODULE;
517 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
518 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
519 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
520 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
521 budget_ci->ca.slot_reset = ciintf_slot_reset;
522 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
523 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300524 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700526 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300528 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 printk("budget_ci: CI interface detected, but initialisation failed.\n");
530 goto error;
531 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300532
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300534 if (budget_ci->ci_irq) {
535 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
536 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
537 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
538 } else {
539 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
540 }
541 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300543
544 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
546 CICONTROL_RESET, 1, 0);
547
548 // success!
549 printk("budget_ci: CI interface initialised\n");
550 budget_ci->budget.ci_present = 1;
551
552 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300553 if (budget_ci->ci_irq) {
554 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
555 if (budget_ci->slot_status != SLOTSTATUS_NONE)
556 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
557 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559
560 return 0;
561
562error:
563 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
564 return result;
565}
566
567static void ciintf_deinit(struct budget_ci *budget_ci)
568{
569 struct saa7146_dev *saa = budget_ci->budget.dev;
570
571 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300572 if (budget_ci->ci_irq) {
573 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
574 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
575 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
576 }
577
578 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
580 msleep(1);
581 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
582 CICONTROL_RESET, 1, 0);
583
584 // disable TS data stream to CI interface
585 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
586
587 // release the CA device
588 dvb_ca_en50221_release(&budget_ci->ca);
589
590 // disable DEBI pins
591 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
592}
593
594static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
595{
596 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
597
598 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
599
600 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200601 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602
603 if (*isr & MASK_10)
604 ttpci_budget_irq10_handler(dev, isr);
605
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300606 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
608}
609
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610static u8 philips_su1278_tt_inittab[] = {
611 0x01, 0x0f,
612 0x02, 0x30,
613 0x03, 0x00,
614 0x04, 0x5b,
615 0x05, 0x85,
616 0x06, 0x02,
617 0x07, 0x00,
618 0x08, 0x02,
619 0x09, 0x00,
620 0x0C, 0x01,
621 0x0D, 0x81,
622 0x0E, 0x44,
623 0x0f, 0x14,
624 0x10, 0x3c,
625 0x11, 0x84,
626 0x12, 0xda,
627 0x13, 0x97,
628 0x14, 0x95,
629 0x15, 0xc9,
630 0x16, 0x19,
631 0x17, 0x8c,
632 0x18, 0x59,
633 0x19, 0xf8,
634 0x1a, 0xfe,
635 0x1c, 0x7f,
636 0x1d, 0x00,
637 0x1e, 0x00,
638 0x1f, 0x50,
639 0x20, 0x00,
640 0x21, 0x00,
641 0x22, 0x00,
642 0x23, 0x00,
643 0x28, 0x00,
644 0x29, 0x28,
645 0x2a, 0x14,
646 0x2b, 0x0f,
647 0x2c, 0x09,
648 0x2d, 0x09,
649 0x31, 0x1f,
650 0x32, 0x19,
651 0x33, 0xfc,
652 0x34, 0x93,
653 0xff, 0xff
654};
655
656static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
657{
658 stv0299_writereg(fe, 0x0e, 0x44);
659 if (srate >= 10000000) {
660 stv0299_writereg(fe, 0x13, 0x97);
661 stv0299_writereg(fe, 0x14, 0x95);
662 stv0299_writereg(fe, 0x15, 0xc9);
663 stv0299_writereg(fe, 0x17, 0x8c);
664 stv0299_writereg(fe, 0x1a, 0xfe);
665 stv0299_writereg(fe, 0x1c, 0x7f);
666 stv0299_writereg(fe, 0x2d, 0x09);
667 } else {
668 stv0299_writereg(fe, 0x13, 0x99);
669 stv0299_writereg(fe, 0x14, 0x8d);
670 stv0299_writereg(fe, 0x15, 0xce);
671 stv0299_writereg(fe, 0x17, 0x43);
672 stv0299_writereg(fe, 0x1a, 0x1d);
673 stv0299_writereg(fe, 0x1c, 0x12);
674 stv0299_writereg(fe, 0x2d, 0x05);
675 }
676 stv0299_writereg(fe, 0x0e, 0x23);
677 stv0299_writereg(fe, 0x0f, 0x94);
678 stv0299_writereg(fe, 0x10, 0x39);
679 stv0299_writereg(fe, 0x15, 0xc9);
680
681 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
682 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
683 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
684
685 return 0;
686}
687
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300688static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
689 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300691 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 u32 div;
693 u8 buf[4];
694 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
695
696 if ((params->frequency < 950000) || (params->frequency > 2150000))
697 return -EINVAL;
698
699 div = (params->frequency + (500 - 1)) / 500; // round correctly
700 buf[0] = (div >> 8) & 0x7f;
701 buf[1] = div & 0xff;
702 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
703 buf[3] = 0x20;
704
705 if (params->u.qpsk.symbol_rate < 4000000)
706 buf[3] |= 1;
707
708 if (params->frequency < 1250000)
709 buf[3] |= 0;
710 else if (params->frequency < 1550000)
711 buf[3] |= 0x40;
712 else if (params->frequency < 2050000)
713 buf[3] |= 0x80;
714 else if (params->frequency < 2150000)
715 buf[3] |= 0xC0;
716
Patrick Boettcherdea74862006-05-14 05:01:31 -0300717 if (fe->ops.i2c_gate_ctrl)
718 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300719 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 return -EIO;
721 return 0;
722}
723
724static struct stv0299_config philips_su1278_tt_config = {
725
726 .demod_address = 0x68,
727 .inittab = philips_su1278_tt_inittab,
728 .mclk = 64000000UL,
729 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 .skip_reinit = 1,
731 .lock_output = STV0229_LOCKOUTPUT_1,
732 .volt13_op0_op1 = STV0299_VOLT13_OP1,
733 .min_delay_ms = 50,
734 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735};
736
737
738
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300739static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
741 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
742 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
743 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700744 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 sizeof(td1316_init) };
746
747 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300748 if (fe->ops.i2c_gate_ctrl)
749 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
751 return -EIO;
752 msleep(1);
753
754 // disable the mc44BC374c (do not check for errors)
755 tuner_msg.addr = 0x65;
756 tuner_msg.buf = disable_mc44BC374c;
757 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300758 if (fe->ops.i2c_gate_ctrl)
759 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300761 if (fe->ops.i2c_gate_ctrl)
762 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
764 }
765
766 return 0;
767}
768
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300769static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770{
771 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
772 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700773 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 int tuner_frequency = 0;
775 u8 band, cp, filter;
776
777 // determine charge pump
778 tuner_frequency = params->frequency + 36130000;
779 if (tuner_frequency < 87000000)
780 return -EINVAL;
781 else if (tuner_frequency < 130000000)
782 cp = 3;
783 else if (tuner_frequency < 160000000)
784 cp = 5;
785 else if (tuner_frequency < 200000000)
786 cp = 6;
787 else if (tuner_frequency < 290000000)
788 cp = 3;
789 else if (tuner_frequency < 420000000)
790 cp = 5;
791 else if (tuner_frequency < 480000000)
792 cp = 6;
793 else if (tuner_frequency < 620000000)
794 cp = 3;
795 else if (tuner_frequency < 830000000)
796 cp = 5;
797 else if (tuner_frequency < 895000000)
798 cp = 7;
799 else
800 return -EINVAL;
801
802 // determine band
803 if (params->frequency < 49000000)
804 return -EINVAL;
805 else if (params->frequency < 159000000)
806 band = 1;
807 else if (params->frequency < 444000000)
808 band = 2;
809 else if (params->frequency < 861000000)
810 band = 4;
811 else
812 return -EINVAL;
813
814 // setup PLL filter and TDA9889
815 switch (params->u.ofdm.bandwidth) {
816 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300817 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 filter = 0;
819 break;
820
821 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300822 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 filter = 0;
824 break;
825
826 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300827 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 filter = 1;
829 break;
830
831 default:
832 return -EINVAL;
833 }
834
835 // calculate divisor
836 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
837 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
838
839 // setup tuner buffer
840 tuner_buf[0] = tuner_frequency >> 8;
841 tuner_buf[1] = tuner_frequency & 0xff;
842 tuner_buf[2] = 0xca;
843 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
844
Patrick Boettcherdea74862006-05-14 05:01:31 -0300845 if (fe->ops.i2c_gate_ctrl)
846 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
848 return -EIO;
849
850 msleep(1);
851 return 0;
852}
853
854static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
855 const struct firmware **fw, char *name)
856{
857 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
858
859 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
860}
861
862static struct tda1004x_config philips_tdm1316l_config = {
863
864 .demod_address = 0x8,
865 .invert = 0,
866 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700867 .xtal_freq = TDA10046_XTAL_4M,
868 .agc_config = TDA10046_AGC_DEFAULT,
869 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 .request_firmware = philips_tdm1316l_request_firmware,
871};
872
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300873static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700874{
875 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
876 u8 tuner_buf[5];
877 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
878 .flags = 0,
879 .buf = tuner_buf,
880 .len = sizeof(tuner_buf) };
881 int tuner_frequency = 0;
882 u8 band, cp, filter;
883
884 // determine charge pump
885 tuner_frequency = params->frequency + 36125000;
886 if (tuner_frequency < 87000000)
887 return -EINVAL;
888 else if (tuner_frequency < 130000000) {
889 cp = 3;
890 band = 1;
891 } else if (tuner_frequency < 160000000) {
892 cp = 5;
893 band = 1;
894 } else if (tuner_frequency < 200000000) {
895 cp = 6;
896 band = 1;
897 } else if (tuner_frequency < 290000000) {
898 cp = 3;
899 band = 2;
900 } else if (tuner_frequency < 420000000) {
901 cp = 5;
902 band = 2;
903 } else if (tuner_frequency < 480000000) {
904 cp = 6;
905 band = 2;
906 } else if (tuner_frequency < 620000000) {
907 cp = 3;
908 band = 4;
909 } else if (tuner_frequency < 830000000) {
910 cp = 5;
911 band = 4;
912 } else if (tuner_frequency < 895000000) {
913 cp = 7;
914 band = 4;
915 } else
916 return -EINVAL;
917
918 // assume PLL filter should always be 8MHz for the moment.
919 filter = 1;
920
921 // calculate divisor
922 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
923
924 // setup tuner buffer
925 tuner_buf[0] = tuner_frequency >> 8;
926 tuner_buf[1] = tuner_frequency & 0xff;
927 tuner_buf[2] = 0xc8;
928 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
929 tuner_buf[4] = 0x80;
930
Patrick Boettcherdea74862006-05-14 05:01:31 -0300931 if (fe->ops.i2c_gate_ctrl)
932 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700933 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
934 return -EIO;
935
936 msleep(50);
937
Patrick Boettcherdea74862006-05-14 05:01:31 -0300938 if (fe->ops.i2c_gate_ctrl)
939 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700940 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
941 return -EIO;
942
943 msleep(1);
944
945 return 0;
946}
947
948static u8 dvbc_philips_tdm1316l_inittab[] = {
949 0x80, 0x01,
950 0x80, 0x00,
951 0x81, 0x01,
952 0x81, 0x00,
953 0x00, 0x09,
954 0x01, 0x69,
955 0x03, 0x00,
956 0x04, 0x00,
957 0x07, 0x00,
958 0x08, 0x00,
959 0x20, 0x00,
960 0x21, 0x40,
961 0x22, 0x00,
962 0x23, 0x00,
963 0x24, 0x40,
964 0x25, 0x88,
965 0x30, 0xff,
966 0x31, 0x00,
967 0x32, 0xff,
968 0x33, 0x00,
969 0x34, 0x50,
970 0x35, 0x7f,
971 0x36, 0x00,
972 0x37, 0x20,
973 0x38, 0x00,
974 0x40, 0x1c,
975 0x41, 0xff,
976 0x42, 0x29,
977 0x43, 0x20,
978 0x44, 0xff,
979 0x45, 0x00,
980 0x46, 0x00,
981 0x49, 0x04,
982 0x4a, 0x00,
983 0x4b, 0x7b,
984 0x52, 0x30,
985 0x55, 0xae,
986 0x56, 0x47,
987 0x57, 0xe1,
988 0x58, 0x3a,
989 0x5a, 0x1e,
990 0x5b, 0x34,
991 0x60, 0x00,
992 0x63, 0x00,
993 0x64, 0x00,
994 0x65, 0x00,
995 0x66, 0x00,
996 0x67, 0x00,
997 0x68, 0x00,
998 0x69, 0x00,
999 0x6a, 0x02,
1000 0x6b, 0x00,
1001 0x70, 0xff,
1002 0x71, 0x00,
1003 0x72, 0x00,
1004 0x73, 0x00,
1005 0x74, 0x0c,
1006 0x80, 0x00,
1007 0x81, 0x00,
1008 0x82, 0x00,
1009 0x83, 0x00,
1010 0x84, 0x04,
1011 0x85, 0x80,
1012 0x86, 0x24,
1013 0x87, 0x78,
1014 0x88, 0x10,
1015 0x89, 0x00,
1016 0x90, 0x01,
1017 0x91, 0x01,
1018 0xa0, 0x04,
1019 0xa1, 0x00,
1020 0xa2, 0x00,
1021 0xb0, 0x91,
1022 0xb1, 0x0b,
1023 0xc0, 0x53,
1024 0xc1, 0x70,
1025 0xc2, 0x12,
1026 0xd0, 0x00,
1027 0xd1, 0x00,
1028 0xd2, 0x00,
1029 0xd3, 0x00,
1030 0xd4, 0x00,
1031 0xd5, 0x00,
1032 0xde, 0x00,
1033 0xdf, 0x00,
1034 0x61, 0x38,
1035 0x62, 0x0a,
1036 0x53, 0x13,
1037 0x59, 0x08,
1038 0xff, 0xff,
1039};
1040
1041static struct stv0297_config dvbc_philips_tdm1316l_config = {
1042 .demod_address = 0x1c,
1043 .inittab = dvbc_philips_tdm1316l_inittab,
1044 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001045 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001046};
1047
1048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
1050
1051static void frontend_init(struct budget_ci *budget_ci)
1052{
1053 switch (budget_ci->budget.dev->pci->subsystem_device) {
1054 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1055 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001056 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001058 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001059 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060 break;
1061 }
1062 break;
1063
1064 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1065 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001066 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001068 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 break;
1070 }
1071 break;
1072
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001073 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1074 budget_ci->tuner_pll_address = 0x61;
1075 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001076 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001077 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001078 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001079 break;
1080 }
1081 break;
1082
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001084 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001086 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001088 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1089 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 break;
1091 }
1092 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001093
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001094 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001095 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001096 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001097 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001098 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001099 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001100 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1101 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001102 break;
1103 }
1104 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001105
1106 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001107 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001108 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001109 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001110 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1111
Patrick Boettcherdea74862006-05-14 05:01:31 -03001112 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001113 if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) {
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001114 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001115 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001116 budget_ci->budget.dvb_frontend = NULL;
1117 }
1118 }
1119
1120 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 }
1122
1123 if (budget_ci->budget.dvb_frontend == NULL) {
1124 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1125 budget_ci->budget.dev->pci->vendor,
1126 budget_ci->budget.dev->pci->device,
1127 budget_ci->budget.dev->pci->subsystem_vendor,
1128 budget_ci->budget.dev->pci->subsystem_device);
1129 } else {
1130 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001131 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001133 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 budget_ci->budget.dvb_frontend = NULL;
1135 }
1136 }
1137}
1138
1139static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1140{
1141 struct budget_ci *budget_ci;
1142 int err;
1143
David Hardemanee579bc2006-12-02 21:16:05 -02001144 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001145 if (!budget_ci) {
1146 err = -ENOMEM;
1147 goto out1;
1148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
1150 dprintk(2, "budget_ci: %p\n", budget_ci);
1151
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 dev->ext_priv = budget_ci;
1153
David Hardeman8cc532e2006-12-02 21:16:05 -02001154 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1155 if (err)
1156 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
David Hardeman8cc532e2006-12-02 21:16:05 -02001158 err = msp430_ir_init(budget_ci);
1159 if (err)
1160 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
1162 ciintf_init(budget_ci);
1163
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001164 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 frontend_init(budget_ci);
1166
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001167 ttpci_budget_init_hooks(&budget_ci->budget);
1168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001170
1171out3:
1172 ttpci_budget_deinit(&budget_ci->budget);
1173out2:
1174 kfree(budget_ci);
1175out1:
1176 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177}
1178
1179static int budget_ci_detach(struct saa7146_dev *dev)
1180{
1181 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1182 struct saa7146_dev *saa = budget_ci->budget.dev;
1183 int err;
1184
1185 if (budget_ci->budget.ci_present)
1186 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001187 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001188 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001190 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001191 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192 err = ttpci_budget_deinit(&budget_ci->budget);
1193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 // disable frontend and CI interface
1195 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1196
1197 kfree(budget_ci);
1198
1199 return err;
1200}
1201
1202static struct saa7146_extension budget_extension;
1203
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001204MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1206MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001207MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001208MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209
1210static struct pci_device_id pci_tbl[] = {
1211 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1212 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001213 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001215 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001216 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 {
1218 .vendor = 0,
1219 }
1220};
1221
1222MODULE_DEVICE_TABLE(pci, pci_tbl);
1223
1224static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001225 .name = "budget_ci dvb",
Oliver Endriss69459f32005-12-01 00:51:48 -08001226 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227
1228 .module = THIS_MODULE,
1229 .pci_tbl = &pci_tbl[0],
1230 .attach = budget_ci_attach,
1231 .detach = budget_ci_detach,
1232
1233 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1234 .irq_func = budget_ci_irq,
1235};
1236
1237static int __init budget_ci_init(void)
1238{
1239 return saa7146_register_extension(&budget_extension);
1240}
1241
1242static void __exit budget_ci_exit(void)
1243{
1244 saa7146_unregister_extension(&budget_extension);
1245}
1246
1247module_init(budget_ci_init);
1248module_exit(budget_ci_exit);
1249
1250MODULE_LICENSE("GPL");
1251MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1252MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1253 "budget PCI DVB cards w/ CI-module produced by "
1254 "Siemens, Technotrend, Hauppauge");