blob: ac0cecb14dc30be72b9d41c25541a227a2400903 [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>
40
41#include "dvb_ca_en50221.h"
42#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070043#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include "tda1004x.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030045#include "lnbp21.h"
46#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030047#include "bsru6.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
David Härdemanecba77f2006-10-27 20:56:51 -030049/*
50 * Regarding DEBIADDR_IR:
51 * Some CI modules hang if random addresses are read.
52 * Using address 0x4000 for the IR read means that we
53 * use the same address as for CI version, which should
54 * be a safe default.
55 */
56#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#define DEBIADDR_CICONTROL 0x0000
58#define DEBIADDR_CIVERSION 0x4000
59#define DEBIADDR_IO 0x1000
60#define DEBIADDR_ATTR 0x3000
61
62#define CICONTROL_RESET 0x01
63#define CICONTROL_ENABLETS 0x02
64#define CICONTROL_CAMDETECT 0x08
65
66#define DEBICICTL 0x00420000
67#define DEBICICAM 0x02420000
68
69#define SLOTSTATUS_NONE 1
70#define SLOTSTATUS_PRESENT 2
71#define SLOTSTATUS_RESET 4
72#define SLOTSTATUS_READY 8
73#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
74
75struct budget_ci {
76 struct budget budget;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -050077 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 struct tasklet_struct msp430_irq_tasklet;
79 struct tasklet_struct ciintf_irq_tasklet;
80 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -030081 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 struct dvb_ca_en50221 ca;
83 char ir_dev_name[50];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -070084 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -070085};
86
87/* from reading the following remotes:
88 Zenith Universal 7 / TV Mode 807 / VCR Mode 837
89 Hauppauge (from NOVA-CI-s box product)
90 i've taken a "middle of the road" approach and note the differences
91*/
92static u16 key_map[64] = {
93 /* 0x0X */
94 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
95 KEY_9,
96 KEY_ENTER,
97 KEY_RED,
98 KEY_POWER, /* RADIO on Hauppauge */
99 KEY_MUTE,
100 0,
101 KEY_A, /* TV on Hauppauge */
102 /* 0x1X */
103 KEY_VOLUMEUP, KEY_VOLUMEDOWN,
104 0, 0,
105 KEY_B,
106 0, 0, 0, 0, 0, 0, 0,
107 KEY_UP, KEY_DOWN,
108 KEY_OPTION, /* RESERVED on Hauppauge */
109 KEY_BREAK,
110 /* 0x2X */
111 KEY_CHANNELUP, KEY_CHANNELDOWN,
112 KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
113 0, KEY_RESTART, KEY_OK,
114 KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
115 0,
116 KEY_ENTER, /* VCR mode on Zenith */
117 KEY_PAUSE,
118 0,
119 KEY_RIGHT, KEY_LEFT,
120 0,
121 KEY_MENU, /* FULL SCREEN on Hauppauge */
122 0,
123 /* 0x3X */
124 KEY_SLOW,
125 KEY_PREVIOUS, /* VCR mode on Zenith */
126 KEY_REWIND,
127 0,
128 KEY_FASTFORWARD,
129 KEY_PLAY, KEY_STOP,
130 KEY_RECORD,
131 KEY_TUNER, /* TV/VCR on Zenith */
132 0,
133 KEY_C,
134 0,
135 KEY_EXIT,
136 KEY_POWER2,
137 KEY_TUNER, /* VCR mode on Zenith */
138 0,
139};
140
141static void msp430_ir_debounce(unsigned long data)
142{
143 struct input_dev *dev = (struct input_dev *) data;
144
145 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
146 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
147 return;
148 }
149
150 dev->rep[0] = 0;
151 dev->timer.expires = jiffies + HZ * 350 / 1000;
152 add_timer(&dev->timer);
153 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
154}
155
156static void msp430_ir_interrupt(unsigned long data)
157{
158 struct budget_ci *budget_ci = (struct budget_ci *) data;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500159 struct input_dev *dev = budget_ci->input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 unsigned int code =
161 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
162
163 if (code & 0x40) {
164 code &= 0x3f;
165
166 if (timer_pending(&dev->timer)) {
167 if (code == dev->repeat_key) {
168 ++dev->rep[0];
169 return;
170 }
171 del_timer(&dev->timer);
172 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
173 }
174
175 if (!key_map[code]) {
176 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
177 return;
178 }
179
180 /* initialize debounce and repeat */
181 dev->repeat_key = code;
182 /* Zenith remote _always_ sends 2 sequences */
183 dev->rep[0] = ~0;
184 /* 350 milliseconds */
185 dev->timer.expires = jiffies + HZ * 350 / 1000;
186 /* MAKE */
187 input_event(dev, EV_KEY, key_map[code], !0);
188 add_timer(&dev->timer);
189 }
190}
191
192static int msp430_ir_init(struct budget_ci *budget_ci)
193{
194 struct saa7146_dev *saa = budget_ci->budget.dev;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500195 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 int i;
197
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500198 budget_ci->input_dev = input_dev = input_allocate_device();
199 if (!input_dev)
200 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500204 input_dev->name = budget_ci->ir_dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500206 set_bit(EV_KEY, input_dev->evbit);
207 for (i = 0; i < ARRAY_SIZE(key_map); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 if (key_map[i])
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500209 set_bit(key_map[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500211 input_register_device(budget_ci->input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500213 input_dev->timer.function = msp430_ir_debounce;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
215 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
217
218 return 0;
219}
220
221static void msp430_ir_deinit(struct budget_ci *budget_ci)
222{
223 struct saa7146_dev *saa = budget_ci->budget.dev;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500224 struct input_dev *dev = budget_ci->input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225
226 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
227 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
228
229 if (del_timer(&dev->timer))
230 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
231
232 input_unregister_device(dev);
233}
234
235static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
236{
237 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
238
239 if (slot != 0)
240 return -EINVAL;
241
242 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
243 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
244}
245
246static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
247{
248 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
249
250 if (slot != 0)
251 return -EINVAL;
252
253 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
254 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
255}
256
257static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
258{
259 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
260
261 if (slot != 0)
262 return -EINVAL;
263
264 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
265 DEBIADDR_IO | (address & 3), 1, 1, 0);
266}
267
268static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
269{
270 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
271
272 if (slot != 0)
273 return -EINVAL;
274
275 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
276 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
277}
278
279static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
280{
281 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
282 struct saa7146_dev *saa = budget_ci->budget.dev;
283
284 if (slot != 0)
285 return -EINVAL;
286
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300287 if (budget_ci->ci_irq) {
288 // trigger on RISING edge during reset so we know when READY is re-asserted
289 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 budget_ci->slot_status = SLOTSTATUS_RESET;
292 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
293 msleep(1);
294 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
295 CICONTROL_RESET, 1, 0);
296
297 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
298 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
299 return 0;
300}
301
302static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
303{
304 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
305 struct saa7146_dev *saa = budget_ci->budget.dev;
306
307 if (slot != 0)
308 return -EINVAL;
309
310 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
311 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
312 return 0;
313}
314
315static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
316{
317 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
318 struct saa7146_dev *saa = budget_ci->budget.dev;
319 int tmp;
320
321 if (slot != 0)
322 return -EINVAL;
323
324 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
325
326 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
327 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
328 tmp | CICONTROL_ENABLETS, 1, 0);
329
330 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
331 return 0;
332}
333
334static void ciintf_interrupt(unsigned long data)
335{
336 struct budget_ci *budget_ci = (struct budget_ci *) data;
337 struct saa7146_dev *saa = budget_ci->budget.dev;
338 unsigned int flags;
339
340 // ensure we don't get spurious IRQs during initialisation
341 if (!budget_ci->budget.ci_present)
342 return;
343
344 // read the CAM status
345 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
346 if (flags & CICONTROL_CAMDETECT) {
347
348 // GPIO should be set to trigger on falling edge if a CAM is present
349 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
350
351 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
352 // CAM insertion IRQ
353 budget_ci->slot_status = SLOTSTATUS_PRESENT;
354 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
355 DVB_CA_EN50221_CAMCHANGE_INSERTED);
356
357 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
358 // CAM ready (reset completed)
359 budget_ci->slot_status = SLOTSTATUS_READY;
360 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
361
362 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
363 // FR/DA IRQ
364 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
365 }
366 } else {
367
368 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
369 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
370 // the CAM might not actually be ready yet.
371 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
372
373 // generate a CAM removal IRQ if we haven't already
374 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
375 // CAM removal IRQ
376 budget_ci->slot_status = SLOTSTATUS_NONE;
377 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
378 DVB_CA_EN50221_CAMCHANGE_REMOVED);
379 }
380 }
381}
382
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300383static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
384{
385 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
386 unsigned int flags;
387
388 // ensure we don't get spurious IRQs during initialisation
389 if (!budget_ci->budget.ci_present)
390 return -EINVAL;
391
392 // read the CAM status
393 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
394 if (flags & CICONTROL_CAMDETECT) {
395 // mark it as present if it wasn't before
396 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
397 budget_ci->slot_status = SLOTSTATUS_PRESENT;
398 }
399
400 // during a RESET, we check if we can read from IO memory to see when CAM is ready
401 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
402 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
403 budget_ci->slot_status = SLOTSTATUS_READY;
404 }
405 }
406 } else {
407 budget_ci->slot_status = SLOTSTATUS_NONE;
408 }
409
410 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
411 if (budget_ci->slot_status & SLOTSTATUS_READY) {
412 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
413 }
414 return DVB_CA_EN50221_POLL_CAM_PRESENT;
415 }
416
417 return 0;
418}
419
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420static int ciintf_init(struct budget_ci *budget_ci)
421{
422 struct saa7146_dev *saa = budget_ci->budget.dev;
423 int flags;
424 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300425 int ci_version;
426 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
429
430 // enable DEBI pins
431 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
432
433 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300434 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
435 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 result = -ENODEV;
437 goto error;
438 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 // determine whether a CAM is present or not
441 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
442 budget_ci->slot_status = SLOTSTATUS_NONE;
443 if (flags & CICONTROL_CAMDETECT)
444 budget_ci->slot_status = SLOTSTATUS_PRESENT;
445
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300446 // version 0xa2 of the CI firmware doesn't generate interrupts
447 if (ci_version == 0xa2) {
448 ca_flags = 0;
449 budget_ci->ci_irq = 0;
450 } else {
451 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
452 DVB_CA_EN50221_FLAG_IRQ_FR |
453 DVB_CA_EN50221_FLAG_IRQ_DA;
454 budget_ci->ci_irq = 1;
455 }
456
Linus Torvalds1da177e2005-04-16 15:20:36 -0700457 // register CI interface
458 budget_ci->ca.owner = THIS_MODULE;
459 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
460 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
461 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
462 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
463 budget_ci->ca.slot_reset = ciintf_slot_reset;
464 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
465 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300466 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700468 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300470 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 printk("budget_ci: CI interface detected, but initialisation failed.\n");
472 goto error;
473 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300474
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300476 if (budget_ci->ci_irq) {
477 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
478 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
479 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
480 } else {
481 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
482 }
483 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300485
486 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
488 CICONTROL_RESET, 1, 0);
489
490 // success!
491 printk("budget_ci: CI interface initialised\n");
492 budget_ci->budget.ci_present = 1;
493
494 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300495 if (budget_ci->ci_irq) {
496 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
497 if (budget_ci->slot_status != SLOTSTATUS_NONE)
498 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
499 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
500 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501
502 return 0;
503
504error:
505 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
506 return result;
507}
508
509static void ciintf_deinit(struct budget_ci *budget_ci)
510{
511 struct saa7146_dev *saa = budget_ci->budget.dev;
512
513 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300514 if (budget_ci->ci_irq) {
515 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
516 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
517 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
518 }
519
520 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
522 msleep(1);
523 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
524 CICONTROL_RESET, 1, 0);
525
526 // disable TS data stream to CI interface
527 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
528
529 // release the CA device
530 dvb_ca_en50221_release(&budget_ci->ca);
531
532 // disable DEBI pins
533 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
534}
535
536static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
537{
538 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
539
540 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
541
542 if (*isr & MASK_06)
543 tasklet_schedule(&budget_ci->msp430_irq_tasklet);
544
545 if (*isr & MASK_10)
546 ttpci_budget_irq10_handler(dev, isr);
547
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300548 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
550}
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552static u8 philips_su1278_tt_inittab[] = {
553 0x01, 0x0f,
554 0x02, 0x30,
555 0x03, 0x00,
556 0x04, 0x5b,
557 0x05, 0x85,
558 0x06, 0x02,
559 0x07, 0x00,
560 0x08, 0x02,
561 0x09, 0x00,
562 0x0C, 0x01,
563 0x0D, 0x81,
564 0x0E, 0x44,
565 0x0f, 0x14,
566 0x10, 0x3c,
567 0x11, 0x84,
568 0x12, 0xda,
569 0x13, 0x97,
570 0x14, 0x95,
571 0x15, 0xc9,
572 0x16, 0x19,
573 0x17, 0x8c,
574 0x18, 0x59,
575 0x19, 0xf8,
576 0x1a, 0xfe,
577 0x1c, 0x7f,
578 0x1d, 0x00,
579 0x1e, 0x00,
580 0x1f, 0x50,
581 0x20, 0x00,
582 0x21, 0x00,
583 0x22, 0x00,
584 0x23, 0x00,
585 0x28, 0x00,
586 0x29, 0x28,
587 0x2a, 0x14,
588 0x2b, 0x0f,
589 0x2c, 0x09,
590 0x2d, 0x09,
591 0x31, 0x1f,
592 0x32, 0x19,
593 0x33, 0xfc,
594 0x34, 0x93,
595 0xff, 0xff
596};
597
598static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
599{
600 stv0299_writereg(fe, 0x0e, 0x44);
601 if (srate >= 10000000) {
602 stv0299_writereg(fe, 0x13, 0x97);
603 stv0299_writereg(fe, 0x14, 0x95);
604 stv0299_writereg(fe, 0x15, 0xc9);
605 stv0299_writereg(fe, 0x17, 0x8c);
606 stv0299_writereg(fe, 0x1a, 0xfe);
607 stv0299_writereg(fe, 0x1c, 0x7f);
608 stv0299_writereg(fe, 0x2d, 0x09);
609 } else {
610 stv0299_writereg(fe, 0x13, 0x99);
611 stv0299_writereg(fe, 0x14, 0x8d);
612 stv0299_writereg(fe, 0x15, 0xce);
613 stv0299_writereg(fe, 0x17, 0x43);
614 stv0299_writereg(fe, 0x1a, 0x1d);
615 stv0299_writereg(fe, 0x1c, 0x12);
616 stv0299_writereg(fe, 0x2d, 0x05);
617 }
618 stv0299_writereg(fe, 0x0e, 0x23);
619 stv0299_writereg(fe, 0x0f, 0x94);
620 stv0299_writereg(fe, 0x10, 0x39);
621 stv0299_writereg(fe, 0x15, 0xc9);
622
623 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
624 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
625 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
626
627 return 0;
628}
629
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300630static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
631 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300633 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 u32 div;
635 u8 buf[4];
636 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
637
638 if ((params->frequency < 950000) || (params->frequency > 2150000))
639 return -EINVAL;
640
641 div = (params->frequency + (500 - 1)) / 500; // round correctly
642 buf[0] = (div >> 8) & 0x7f;
643 buf[1] = div & 0xff;
644 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
645 buf[3] = 0x20;
646
647 if (params->u.qpsk.symbol_rate < 4000000)
648 buf[3] |= 1;
649
650 if (params->frequency < 1250000)
651 buf[3] |= 0;
652 else if (params->frequency < 1550000)
653 buf[3] |= 0x40;
654 else if (params->frequency < 2050000)
655 buf[3] |= 0x80;
656 else if (params->frequency < 2150000)
657 buf[3] |= 0xC0;
658
Patrick Boettcherdea74862006-05-14 05:01:31 -0300659 if (fe->ops.i2c_gate_ctrl)
660 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300661 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 return -EIO;
663 return 0;
664}
665
666static struct stv0299_config philips_su1278_tt_config = {
667
668 .demod_address = 0x68,
669 .inittab = philips_su1278_tt_inittab,
670 .mclk = 64000000UL,
671 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 .skip_reinit = 1,
673 .lock_output = STV0229_LOCKOUTPUT_1,
674 .volt13_op0_op1 = STV0299_VOLT13_OP1,
675 .min_delay_ms = 50,
676 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677};
678
679
680
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300681static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682{
683 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
684 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
685 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700686 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 sizeof(td1316_init) };
688
689 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300690 if (fe->ops.i2c_gate_ctrl)
691 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
693 return -EIO;
694 msleep(1);
695
696 // disable the mc44BC374c (do not check for errors)
697 tuner_msg.addr = 0x65;
698 tuner_msg.buf = disable_mc44BC374c;
699 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300700 if (fe->ops.i2c_gate_ctrl)
701 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300703 if (fe->ops.i2c_gate_ctrl)
704 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
706 }
707
708 return 0;
709}
710
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300711static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712{
713 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
714 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700715 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 -0700716 int tuner_frequency = 0;
717 u8 band, cp, filter;
718
719 // determine charge pump
720 tuner_frequency = params->frequency + 36130000;
721 if (tuner_frequency < 87000000)
722 return -EINVAL;
723 else if (tuner_frequency < 130000000)
724 cp = 3;
725 else if (tuner_frequency < 160000000)
726 cp = 5;
727 else if (tuner_frequency < 200000000)
728 cp = 6;
729 else if (tuner_frequency < 290000000)
730 cp = 3;
731 else if (tuner_frequency < 420000000)
732 cp = 5;
733 else if (tuner_frequency < 480000000)
734 cp = 6;
735 else if (tuner_frequency < 620000000)
736 cp = 3;
737 else if (tuner_frequency < 830000000)
738 cp = 5;
739 else if (tuner_frequency < 895000000)
740 cp = 7;
741 else
742 return -EINVAL;
743
744 // determine band
745 if (params->frequency < 49000000)
746 return -EINVAL;
747 else if (params->frequency < 159000000)
748 band = 1;
749 else if (params->frequency < 444000000)
750 band = 2;
751 else if (params->frequency < 861000000)
752 band = 4;
753 else
754 return -EINVAL;
755
756 // setup PLL filter and TDA9889
757 switch (params->u.ofdm.bandwidth) {
758 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300759 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 filter = 0;
761 break;
762
763 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300764 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 filter = 0;
766 break;
767
768 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300769 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 filter = 1;
771 break;
772
773 default:
774 return -EINVAL;
775 }
776
777 // calculate divisor
778 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
779 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
780
781 // setup tuner buffer
782 tuner_buf[0] = tuner_frequency >> 8;
783 tuner_buf[1] = tuner_frequency & 0xff;
784 tuner_buf[2] = 0xca;
785 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
786
Patrick Boettcherdea74862006-05-14 05:01:31 -0300787 if (fe->ops.i2c_gate_ctrl)
788 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
790 return -EIO;
791
792 msleep(1);
793 return 0;
794}
795
796static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
797 const struct firmware **fw, char *name)
798{
799 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
800
801 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
802}
803
804static struct tda1004x_config philips_tdm1316l_config = {
805
806 .demod_address = 0x8,
807 .invert = 0,
808 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700809 .xtal_freq = TDA10046_XTAL_4M,
810 .agc_config = TDA10046_AGC_DEFAULT,
811 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 .request_firmware = philips_tdm1316l_request_firmware,
813};
814
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300815static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700816{
817 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
818 u8 tuner_buf[5];
819 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
820 .flags = 0,
821 .buf = tuner_buf,
822 .len = sizeof(tuner_buf) };
823 int tuner_frequency = 0;
824 u8 band, cp, filter;
825
826 // determine charge pump
827 tuner_frequency = params->frequency + 36125000;
828 if (tuner_frequency < 87000000)
829 return -EINVAL;
830 else if (tuner_frequency < 130000000) {
831 cp = 3;
832 band = 1;
833 } else if (tuner_frequency < 160000000) {
834 cp = 5;
835 band = 1;
836 } else if (tuner_frequency < 200000000) {
837 cp = 6;
838 band = 1;
839 } else if (tuner_frequency < 290000000) {
840 cp = 3;
841 band = 2;
842 } else if (tuner_frequency < 420000000) {
843 cp = 5;
844 band = 2;
845 } else if (tuner_frequency < 480000000) {
846 cp = 6;
847 band = 2;
848 } else if (tuner_frequency < 620000000) {
849 cp = 3;
850 band = 4;
851 } else if (tuner_frequency < 830000000) {
852 cp = 5;
853 band = 4;
854 } else if (tuner_frequency < 895000000) {
855 cp = 7;
856 band = 4;
857 } else
858 return -EINVAL;
859
860 // assume PLL filter should always be 8MHz for the moment.
861 filter = 1;
862
863 // calculate divisor
864 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
865
866 // setup tuner buffer
867 tuner_buf[0] = tuner_frequency >> 8;
868 tuner_buf[1] = tuner_frequency & 0xff;
869 tuner_buf[2] = 0xc8;
870 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
871 tuner_buf[4] = 0x80;
872
Patrick Boettcherdea74862006-05-14 05:01:31 -0300873 if (fe->ops.i2c_gate_ctrl)
874 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700875 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
876 return -EIO;
877
878 msleep(50);
879
Patrick Boettcherdea74862006-05-14 05:01:31 -0300880 if (fe->ops.i2c_gate_ctrl)
881 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700882 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
883 return -EIO;
884
885 msleep(1);
886
887 return 0;
888}
889
890static u8 dvbc_philips_tdm1316l_inittab[] = {
891 0x80, 0x01,
892 0x80, 0x00,
893 0x81, 0x01,
894 0x81, 0x00,
895 0x00, 0x09,
896 0x01, 0x69,
897 0x03, 0x00,
898 0x04, 0x00,
899 0x07, 0x00,
900 0x08, 0x00,
901 0x20, 0x00,
902 0x21, 0x40,
903 0x22, 0x00,
904 0x23, 0x00,
905 0x24, 0x40,
906 0x25, 0x88,
907 0x30, 0xff,
908 0x31, 0x00,
909 0x32, 0xff,
910 0x33, 0x00,
911 0x34, 0x50,
912 0x35, 0x7f,
913 0x36, 0x00,
914 0x37, 0x20,
915 0x38, 0x00,
916 0x40, 0x1c,
917 0x41, 0xff,
918 0x42, 0x29,
919 0x43, 0x20,
920 0x44, 0xff,
921 0x45, 0x00,
922 0x46, 0x00,
923 0x49, 0x04,
924 0x4a, 0x00,
925 0x4b, 0x7b,
926 0x52, 0x30,
927 0x55, 0xae,
928 0x56, 0x47,
929 0x57, 0xe1,
930 0x58, 0x3a,
931 0x5a, 0x1e,
932 0x5b, 0x34,
933 0x60, 0x00,
934 0x63, 0x00,
935 0x64, 0x00,
936 0x65, 0x00,
937 0x66, 0x00,
938 0x67, 0x00,
939 0x68, 0x00,
940 0x69, 0x00,
941 0x6a, 0x02,
942 0x6b, 0x00,
943 0x70, 0xff,
944 0x71, 0x00,
945 0x72, 0x00,
946 0x73, 0x00,
947 0x74, 0x0c,
948 0x80, 0x00,
949 0x81, 0x00,
950 0x82, 0x00,
951 0x83, 0x00,
952 0x84, 0x04,
953 0x85, 0x80,
954 0x86, 0x24,
955 0x87, 0x78,
956 0x88, 0x10,
957 0x89, 0x00,
958 0x90, 0x01,
959 0x91, 0x01,
960 0xa0, 0x04,
961 0xa1, 0x00,
962 0xa2, 0x00,
963 0xb0, 0x91,
964 0xb1, 0x0b,
965 0xc0, 0x53,
966 0xc1, 0x70,
967 0xc2, 0x12,
968 0xd0, 0x00,
969 0xd1, 0x00,
970 0xd2, 0x00,
971 0xd3, 0x00,
972 0xd4, 0x00,
973 0xd5, 0x00,
974 0xde, 0x00,
975 0xdf, 0x00,
976 0x61, 0x38,
977 0x62, 0x0a,
978 0x53, 0x13,
979 0x59, 0x08,
980 0xff, 0xff,
981};
982
983static struct stv0297_config dvbc_philips_tdm1316l_config = {
984 .demod_address = 0x1c,
985 .inittab = dvbc_philips_tdm1316l_inittab,
986 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -0300987 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700988};
989
990
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992
993static void frontend_init(struct budget_ci *budget_ci)
994{
995 switch (budget_ci->budget.dev->pci->subsystem_device) {
996 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
997 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300998 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001000 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001001 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 break;
1003 }
1004 break;
1005
1006 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1007 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001008 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001010 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 break;
1012 }
1013 break;
1014
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001015 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1016 budget_ci->tuner_pll_address = 0x61;
1017 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001018 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001019 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001020 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001021 break;
1022 }
1023 break;
1024
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001026 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001027 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001028 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001030 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1031 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 break;
1033 }
1034 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001035
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001036 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001037 budget_ci->tuner_pll_address = 0x60;
1038 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001039 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001040 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001041 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1042 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001043 break;
1044 }
1045 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001046
1047 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001048 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001049 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001050 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001051 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1052
Patrick Boettcherdea74862006-05-14 05:01:31 -03001053 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001054 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 -03001055 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001056 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001057 budget_ci->budget.dvb_frontend = NULL;
1058 }
1059 }
1060
1061 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062 }
1063
1064 if (budget_ci->budget.dvb_frontend == NULL) {
1065 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1066 budget_ci->budget.dev->pci->vendor,
1067 budget_ci->budget.dev->pci->device,
1068 budget_ci->budget.dev->pci->subsystem_vendor,
1069 budget_ci->budget.dev->pci->subsystem_device);
1070 } else {
1071 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001072 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001074 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 budget_ci->budget.dvb_frontend = NULL;
1076 }
1077 }
1078}
1079
1080static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1081{
1082 struct budget_ci *budget_ci;
1083 int err;
1084
1085 if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
1086 return -ENOMEM;
1087
1088 dprintk(2, "budget_ci: %p\n", budget_ci);
1089
1090 budget_ci->budget.ci_present = 0;
1091
1092 dev->ext_priv = budget_ci;
1093
1094 if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
1095 kfree(budget_ci);
1096 return err;
1097 }
1098
1099 tasklet_init(&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
1100 (unsigned long) budget_ci);
1101
1102 msp430_ir_init(budget_ci);
1103
1104 ciintf_init(budget_ci);
1105
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001106 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 frontend_init(budget_ci);
1108
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001109 ttpci_budget_init_hooks(&budget_ci->budget);
1110
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 return 0;
1112}
1113
1114static int budget_ci_detach(struct saa7146_dev *dev)
1115{
1116 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1117 struct saa7146_dev *saa = budget_ci->budget.dev;
1118 int err;
1119
1120 if (budget_ci->budget.ci_present)
1121 ciintf_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001122 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001124 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 err = ttpci_budget_deinit(&budget_ci->budget);
1127
1128 tasklet_kill(&budget_ci->msp430_irq_tasklet);
1129
1130 msp430_ir_deinit(budget_ci);
1131
1132 // disable frontend and CI interface
1133 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1134
1135 kfree(budget_ci);
1136
1137 return err;
1138}
1139
1140static struct saa7146_extension budget_extension;
1141
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001142MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1144MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001145MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001146MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
1148static struct pci_device_id pci_tbl[] = {
1149 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1150 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001151 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001153 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001154 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 {
1156 .vendor = 0,
1157 }
1158};
1159
1160MODULE_DEVICE_TABLE(pci, pci_tbl);
1161
1162static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001163 .name = "budget_ci dvb",
Oliver Endriss69459f32005-12-01 00:51:48 -08001164 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166 .module = THIS_MODULE,
1167 .pci_tbl = &pci_tbl[0],
1168 .attach = budget_ci_attach,
1169 .detach = budget_ci_detach,
1170
1171 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1172 .irq_func = budget_ci_irq,
1173};
1174
1175static int __init budget_ci_init(void)
1176{
1177 return saa7146_register_extension(&budget_extension);
1178}
1179
1180static void __exit budget_ci_exit(void)
1181{
1182 saa7146_unregister_extension(&budget_extension);
1183}
1184
1185module_init(budget_ci_init);
1186module_exit(budget_ci_exit);
1187
1188MODULE_LICENSE("GPL");
1189MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1190MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1191 "budget PCI DVB cards w/ CI-module produced by "
1192 "Siemens, Technotrend, Hauppauge");