blob: 0809fb90c2648bf81f6565c09c307bddb30afbb1 [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
David Hardemandd2f3982006-12-02 21:16:05 -020075struct budget_ci_ir {
76 struct input_dev *dev;
77 struct tasklet_struct msp430_irq_tasklet;
78 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -020079 char phys[32];
David Hardemandd2f3982006-12-02 21:16:05 -020080};
81
Linus Torvalds1da177e2005-04-16 15:20:36 -070082struct budget_ci {
83 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 struct tasklet_struct ciintf_irq_tasklet;
85 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -030086 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -020088 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -070089 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -070090};
91
92/* from reading the following remotes:
93 Zenith Universal 7 / TV Mode 807 / VCR Mode 837
94 Hauppauge (from NOVA-CI-s box product)
95 i've taken a "middle of the road" approach and note the differences
96*/
97static u16 key_map[64] = {
98 /* 0x0X */
99 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
100 KEY_9,
101 KEY_ENTER,
102 KEY_RED,
103 KEY_POWER, /* RADIO on Hauppauge */
104 KEY_MUTE,
105 0,
106 KEY_A, /* TV on Hauppauge */
107 /* 0x1X */
108 KEY_VOLUMEUP, KEY_VOLUMEDOWN,
109 0, 0,
110 KEY_B,
111 0, 0, 0, 0, 0, 0, 0,
112 KEY_UP, KEY_DOWN,
113 KEY_OPTION, /* RESERVED on Hauppauge */
114 KEY_BREAK,
115 /* 0x2X */
116 KEY_CHANNELUP, KEY_CHANNELDOWN,
117 KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
118 0, KEY_RESTART, KEY_OK,
119 KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
120 0,
121 KEY_ENTER, /* VCR mode on Zenith */
122 KEY_PAUSE,
123 0,
124 KEY_RIGHT, KEY_LEFT,
125 0,
126 KEY_MENU, /* FULL SCREEN on Hauppauge */
127 0,
128 /* 0x3X */
129 KEY_SLOW,
130 KEY_PREVIOUS, /* VCR mode on Zenith */
131 KEY_REWIND,
132 0,
133 KEY_FASTFORWARD,
134 KEY_PLAY, KEY_STOP,
135 KEY_RECORD,
136 KEY_TUNER, /* TV/VCR on Zenith */
137 0,
138 KEY_C,
139 0,
140 KEY_EXIT,
141 KEY_POWER2,
142 KEY_TUNER, /* VCR mode on Zenith */
143 0,
144};
145
146static void msp430_ir_debounce(unsigned long data)
147{
148 struct input_dev *dev = (struct input_dev *) data;
149
150 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300151 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
152 } else {
153 dev->rep[0] = 0;
154 dev->timer.expires = jiffies + HZ * 350 / 1000;
155 add_timer(&dev->timer);
156 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 }
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300158 input_sync(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159}
160
161static void msp430_ir_interrupt(unsigned long data)
162{
163 struct budget_ci *budget_ci = (struct budget_ci *) data;
David Hardemandd2f3982006-12-02 21:16:05 -0200164 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 unsigned int code =
166 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
167
168 if (code & 0x40) {
169 code &= 0x3f;
170
171 if (timer_pending(&dev->timer)) {
172 if (code == dev->repeat_key) {
173 ++dev->rep[0];
174 return;
175 }
176 del_timer(&dev->timer);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300177 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 }
179
180 if (!key_map[code]) {
181 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
182 return;
183 }
184
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300185 input_event(dev, EV_KEY, key_map[code], 1);
186 input_sync(dev);
187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 /* initialize debounce and repeat */
189 dev->repeat_key = code;
190 /* Zenith remote _always_ sends 2 sequences */
191 dev->rep[0] = ~0;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300192 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(350));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 }
194}
195
196static int msp430_ir_init(struct budget_ci *budget_ci)
197{
198 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200199 struct input_dev *input_dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 int i;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300201 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
David Hardemandd2f3982006-12-02 21:16:05 -0200203 budget_ci->ir.dev = input_dev = input_allocate_device();
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500204 if (!input_dev)
205 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
David Hardemandd2f3982006-12-02 21:16:05 -0200207 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
208 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200209 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
210 "pci-%s/ir0", pci_name(saa->pci));
211
David Hardemandd2f3982006-12-02 21:16:05 -0200212 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
David Hardeman5cc8ae02006-12-02 21:16:05 -0200214 input_dev->phys = budget_ci->ir.phys;
215 input_dev->id.bustype = BUS_PCI;
216 input_dev->id.version = 1;
217 if (saa->pci->subsystem_vendor) {
218 input_dev->id.vendor = saa->pci->subsystem_vendor;
219 input_dev->id.product = saa->pci->subsystem_device;
220 } else {
221 input_dev->id.vendor = saa->pci->vendor;
222 input_dev->id.product = saa->pci->device;
223 }
224# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
225 input_dev->cdev.dev = &saa->pci->dev;
226# else
227 input_dev->dev = &saa->pci->dev;
228# endif
229
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500230 set_bit(EV_KEY, input_dev->evbit);
231 for (i = 0; i < ARRAY_SIZE(key_map); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 if (key_map[i])
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500233 set_bit(key_map[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300235 err = input_register_device(input_dev);
236 if (err) {
237 input_free_device(input_dev);
238 return err;
239 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
David Hardemandd2f3982006-12-02 21:16:05 -0200241 input_register_device(budget_ci->ir.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
David Hardemandd2f3982006-12-02 21:16:05 -0200243 input_dev->timer.function = msp430_ir_debounce;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300244
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
247
248 return 0;
249}
250
251static void msp430_ir_deinit(struct budget_ci *budget_ci)
252{
253 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200254 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
256 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
257 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
258
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300259 if (del_timer(&dev->timer)) {
260 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
261 input_sync(dev);
262 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264 input_unregister_device(dev);
265}
266
267static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
268{
269 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
270
271 if (slot != 0)
272 return -EINVAL;
273
274 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
275 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
276}
277
278static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
279{
280 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
281
282 if (slot != 0)
283 return -EINVAL;
284
285 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
286 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
287}
288
289static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
290{
291 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
292
293 if (slot != 0)
294 return -EINVAL;
295
296 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
297 DEBIADDR_IO | (address & 3), 1, 1, 0);
298}
299
300static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
301{
302 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
303
304 if (slot != 0)
305 return -EINVAL;
306
307 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
308 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
309}
310
311static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
312{
313 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
314 struct saa7146_dev *saa = budget_ci->budget.dev;
315
316 if (slot != 0)
317 return -EINVAL;
318
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300319 if (budget_ci->ci_irq) {
320 // trigger on RISING edge during reset so we know when READY is re-asserted
321 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
322 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 budget_ci->slot_status = SLOTSTATUS_RESET;
324 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
325 msleep(1);
326 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
327 CICONTROL_RESET, 1, 0);
328
329 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
330 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
331 return 0;
332}
333
334static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
335{
336 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
337 struct saa7146_dev *saa = budget_ci->budget.dev;
338
339 if (slot != 0)
340 return -EINVAL;
341
342 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
343 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
344 return 0;
345}
346
347static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
348{
349 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
350 struct saa7146_dev *saa = budget_ci->budget.dev;
351 int tmp;
352
353 if (slot != 0)
354 return -EINVAL;
355
356 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
357
358 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
359 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
360 tmp | CICONTROL_ENABLETS, 1, 0);
361
362 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
363 return 0;
364}
365
366static void ciintf_interrupt(unsigned long data)
367{
368 struct budget_ci *budget_ci = (struct budget_ci *) data;
369 struct saa7146_dev *saa = budget_ci->budget.dev;
370 unsigned int flags;
371
372 // ensure we don't get spurious IRQs during initialisation
373 if (!budget_ci->budget.ci_present)
374 return;
375
376 // read the CAM status
377 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
378 if (flags & CICONTROL_CAMDETECT) {
379
380 // GPIO should be set to trigger on falling edge if a CAM is present
381 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
382
383 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
384 // CAM insertion IRQ
385 budget_ci->slot_status = SLOTSTATUS_PRESENT;
386 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
387 DVB_CA_EN50221_CAMCHANGE_INSERTED);
388
389 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
390 // CAM ready (reset completed)
391 budget_ci->slot_status = SLOTSTATUS_READY;
392 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
393
394 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
395 // FR/DA IRQ
396 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
397 }
398 } else {
399
400 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
401 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
402 // the CAM might not actually be ready yet.
403 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
404
405 // generate a CAM removal IRQ if we haven't already
406 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
407 // CAM removal IRQ
408 budget_ci->slot_status = SLOTSTATUS_NONE;
409 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
410 DVB_CA_EN50221_CAMCHANGE_REMOVED);
411 }
412 }
413}
414
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300415static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
416{
417 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
418 unsigned int flags;
419
420 // ensure we don't get spurious IRQs during initialisation
421 if (!budget_ci->budget.ci_present)
422 return -EINVAL;
423
424 // read the CAM status
425 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
426 if (flags & CICONTROL_CAMDETECT) {
427 // mark it as present if it wasn't before
428 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
429 budget_ci->slot_status = SLOTSTATUS_PRESENT;
430 }
431
432 // during a RESET, we check if we can read from IO memory to see when CAM is ready
433 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
434 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
435 budget_ci->slot_status = SLOTSTATUS_READY;
436 }
437 }
438 } else {
439 budget_ci->slot_status = SLOTSTATUS_NONE;
440 }
441
442 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
443 if (budget_ci->slot_status & SLOTSTATUS_READY) {
444 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
445 }
446 return DVB_CA_EN50221_POLL_CAM_PRESENT;
447 }
448
449 return 0;
450}
451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452static int ciintf_init(struct budget_ci *budget_ci)
453{
454 struct saa7146_dev *saa = budget_ci->budget.dev;
455 int flags;
456 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300457 int ci_version;
458 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459
460 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
461
462 // enable DEBI pins
463 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
464
465 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300466 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
467 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 result = -ENODEV;
469 goto error;
470 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300471
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472 // determine whether a CAM is present or not
473 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
474 budget_ci->slot_status = SLOTSTATUS_NONE;
475 if (flags & CICONTROL_CAMDETECT)
476 budget_ci->slot_status = SLOTSTATUS_PRESENT;
477
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300478 // version 0xa2 of the CI firmware doesn't generate interrupts
479 if (ci_version == 0xa2) {
480 ca_flags = 0;
481 budget_ci->ci_irq = 0;
482 } else {
483 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
484 DVB_CA_EN50221_FLAG_IRQ_FR |
485 DVB_CA_EN50221_FLAG_IRQ_DA;
486 budget_ci->ci_irq = 1;
487 }
488
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 // register CI interface
490 budget_ci->ca.owner = THIS_MODULE;
491 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
492 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
493 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
494 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
495 budget_ci->ca.slot_reset = ciintf_slot_reset;
496 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
497 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300498 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700500 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300502 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 printk("budget_ci: CI interface detected, but initialisation failed.\n");
504 goto error;
505 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300506
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300508 if (budget_ci->ci_irq) {
509 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
510 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
511 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
512 } else {
513 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
514 }
515 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300517
518 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
520 CICONTROL_RESET, 1, 0);
521
522 // success!
523 printk("budget_ci: CI interface initialised\n");
524 budget_ci->budget.ci_present = 1;
525
526 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300527 if (budget_ci->ci_irq) {
528 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
529 if (budget_ci->slot_status != SLOTSTATUS_NONE)
530 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
531 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533
534 return 0;
535
536error:
537 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
538 return result;
539}
540
541static void ciintf_deinit(struct budget_ci *budget_ci)
542{
543 struct saa7146_dev *saa = budget_ci->budget.dev;
544
545 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300546 if (budget_ci->ci_irq) {
547 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
548 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
549 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
550 }
551
552 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
554 msleep(1);
555 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
556 CICONTROL_RESET, 1, 0);
557
558 // disable TS data stream to CI interface
559 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
560
561 // release the CA device
562 dvb_ca_en50221_release(&budget_ci->ca);
563
564 // disable DEBI pins
565 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
566}
567
568static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
569{
570 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
571
572 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
573
574 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200575 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576
577 if (*isr & MASK_10)
578 ttpci_budget_irq10_handler(dev, isr);
579
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300580 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
582}
583
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584static u8 philips_su1278_tt_inittab[] = {
585 0x01, 0x0f,
586 0x02, 0x30,
587 0x03, 0x00,
588 0x04, 0x5b,
589 0x05, 0x85,
590 0x06, 0x02,
591 0x07, 0x00,
592 0x08, 0x02,
593 0x09, 0x00,
594 0x0C, 0x01,
595 0x0D, 0x81,
596 0x0E, 0x44,
597 0x0f, 0x14,
598 0x10, 0x3c,
599 0x11, 0x84,
600 0x12, 0xda,
601 0x13, 0x97,
602 0x14, 0x95,
603 0x15, 0xc9,
604 0x16, 0x19,
605 0x17, 0x8c,
606 0x18, 0x59,
607 0x19, 0xf8,
608 0x1a, 0xfe,
609 0x1c, 0x7f,
610 0x1d, 0x00,
611 0x1e, 0x00,
612 0x1f, 0x50,
613 0x20, 0x00,
614 0x21, 0x00,
615 0x22, 0x00,
616 0x23, 0x00,
617 0x28, 0x00,
618 0x29, 0x28,
619 0x2a, 0x14,
620 0x2b, 0x0f,
621 0x2c, 0x09,
622 0x2d, 0x09,
623 0x31, 0x1f,
624 0x32, 0x19,
625 0x33, 0xfc,
626 0x34, 0x93,
627 0xff, 0xff
628};
629
630static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
631{
632 stv0299_writereg(fe, 0x0e, 0x44);
633 if (srate >= 10000000) {
634 stv0299_writereg(fe, 0x13, 0x97);
635 stv0299_writereg(fe, 0x14, 0x95);
636 stv0299_writereg(fe, 0x15, 0xc9);
637 stv0299_writereg(fe, 0x17, 0x8c);
638 stv0299_writereg(fe, 0x1a, 0xfe);
639 stv0299_writereg(fe, 0x1c, 0x7f);
640 stv0299_writereg(fe, 0x2d, 0x09);
641 } else {
642 stv0299_writereg(fe, 0x13, 0x99);
643 stv0299_writereg(fe, 0x14, 0x8d);
644 stv0299_writereg(fe, 0x15, 0xce);
645 stv0299_writereg(fe, 0x17, 0x43);
646 stv0299_writereg(fe, 0x1a, 0x1d);
647 stv0299_writereg(fe, 0x1c, 0x12);
648 stv0299_writereg(fe, 0x2d, 0x05);
649 }
650 stv0299_writereg(fe, 0x0e, 0x23);
651 stv0299_writereg(fe, 0x0f, 0x94);
652 stv0299_writereg(fe, 0x10, 0x39);
653 stv0299_writereg(fe, 0x15, 0xc9);
654
655 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
656 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
657 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
658
659 return 0;
660}
661
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300662static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
663 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300665 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 u32 div;
667 u8 buf[4];
668 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
669
670 if ((params->frequency < 950000) || (params->frequency > 2150000))
671 return -EINVAL;
672
673 div = (params->frequency + (500 - 1)) / 500; // round correctly
674 buf[0] = (div >> 8) & 0x7f;
675 buf[1] = div & 0xff;
676 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
677 buf[3] = 0x20;
678
679 if (params->u.qpsk.symbol_rate < 4000000)
680 buf[3] |= 1;
681
682 if (params->frequency < 1250000)
683 buf[3] |= 0;
684 else if (params->frequency < 1550000)
685 buf[3] |= 0x40;
686 else if (params->frequency < 2050000)
687 buf[3] |= 0x80;
688 else if (params->frequency < 2150000)
689 buf[3] |= 0xC0;
690
Patrick Boettcherdea74862006-05-14 05:01:31 -0300691 if (fe->ops.i2c_gate_ctrl)
692 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300693 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 return -EIO;
695 return 0;
696}
697
698static struct stv0299_config philips_su1278_tt_config = {
699
700 .demod_address = 0x68,
701 .inittab = philips_su1278_tt_inittab,
702 .mclk = 64000000UL,
703 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 .skip_reinit = 1,
705 .lock_output = STV0229_LOCKOUTPUT_1,
706 .volt13_op0_op1 = STV0299_VOLT13_OP1,
707 .min_delay_ms = 50,
708 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709};
710
711
712
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300713static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
715 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
716 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
717 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700718 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 sizeof(td1316_init) };
720
721 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300722 if (fe->ops.i2c_gate_ctrl)
723 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
725 return -EIO;
726 msleep(1);
727
728 // disable the mc44BC374c (do not check for errors)
729 tuner_msg.addr = 0x65;
730 tuner_msg.buf = disable_mc44BC374c;
731 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300732 if (fe->ops.i2c_gate_ctrl)
733 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300735 if (fe->ops.i2c_gate_ctrl)
736 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
738 }
739
740 return 0;
741}
742
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300743static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744{
745 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
746 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700747 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 -0700748 int tuner_frequency = 0;
749 u8 band, cp, filter;
750
751 // determine charge pump
752 tuner_frequency = params->frequency + 36130000;
753 if (tuner_frequency < 87000000)
754 return -EINVAL;
755 else if (tuner_frequency < 130000000)
756 cp = 3;
757 else if (tuner_frequency < 160000000)
758 cp = 5;
759 else if (tuner_frequency < 200000000)
760 cp = 6;
761 else if (tuner_frequency < 290000000)
762 cp = 3;
763 else if (tuner_frequency < 420000000)
764 cp = 5;
765 else if (tuner_frequency < 480000000)
766 cp = 6;
767 else if (tuner_frequency < 620000000)
768 cp = 3;
769 else if (tuner_frequency < 830000000)
770 cp = 5;
771 else if (tuner_frequency < 895000000)
772 cp = 7;
773 else
774 return -EINVAL;
775
776 // determine band
777 if (params->frequency < 49000000)
778 return -EINVAL;
779 else if (params->frequency < 159000000)
780 band = 1;
781 else if (params->frequency < 444000000)
782 band = 2;
783 else if (params->frequency < 861000000)
784 band = 4;
785 else
786 return -EINVAL;
787
788 // setup PLL filter and TDA9889
789 switch (params->u.ofdm.bandwidth) {
790 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300791 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 filter = 0;
793 break;
794
795 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300796 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 filter = 0;
798 break;
799
800 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300801 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 filter = 1;
803 break;
804
805 default:
806 return -EINVAL;
807 }
808
809 // calculate divisor
810 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
811 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
812
813 // setup tuner buffer
814 tuner_buf[0] = tuner_frequency >> 8;
815 tuner_buf[1] = tuner_frequency & 0xff;
816 tuner_buf[2] = 0xca;
817 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
818
Patrick Boettcherdea74862006-05-14 05:01:31 -0300819 if (fe->ops.i2c_gate_ctrl)
820 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
822 return -EIO;
823
824 msleep(1);
825 return 0;
826}
827
828static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
829 const struct firmware **fw, char *name)
830{
831 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
832
833 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
834}
835
836static struct tda1004x_config philips_tdm1316l_config = {
837
838 .demod_address = 0x8,
839 .invert = 0,
840 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700841 .xtal_freq = TDA10046_XTAL_4M,
842 .agc_config = TDA10046_AGC_DEFAULT,
843 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 .request_firmware = philips_tdm1316l_request_firmware,
845};
846
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300847static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700848{
849 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
850 u8 tuner_buf[5];
851 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
852 .flags = 0,
853 .buf = tuner_buf,
854 .len = sizeof(tuner_buf) };
855 int tuner_frequency = 0;
856 u8 band, cp, filter;
857
858 // determine charge pump
859 tuner_frequency = params->frequency + 36125000;
860 if (tuner_frequency < 87000000)
861 return -EINVAL;
862 else if (tuner_frequency < 130000000) {
863 cp = 3;
864 band = 1;
865 } else if (tuner_frequency < 160000000) {
866 cp = 5;
867 band = 1;
868 } else if (tuner_frequency < 200000000) {
869 cp = 6;
870 band = 1;
871 } else if (tuner_frequency < 290000000) {
872 cp = 3;
873 band = 2;
874 } else if (tuner_frequency < 420000000) {
875 cp = 5;
876 band = 2;
877 } else if (tuner_frequency < 480000000) {
878 cp = 6;
879 band = 2;
880 } else if (tuner_frequency < 620000000) {
881 cp = 3;
882 band = 4;
883 } else if (tuner_frequency < 830000000) {
884 cp = 5;
885 band = 4;
886 } else if (tuner_frequency < 895000000) {
887 cp = 7;
888 band = 4;
889 } else
890 return -EINVAL;
891
892 // assume PLL filter should always be 8MHz for the moment.
893 filter = 1;
894
895 // calculate divisor
896 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
897
898 // setup tuner buffer
899 tuner_buf[0] = tuner_frequency >> 8;
900 tuner_buf[1] = tuner_frequency & 0xff;
901 tuner_buf[2] = 0xc8;
902 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
903 tuner_buf[4] = 0x80;
904
Patrick Boettcherdea74862006-05-14 05:01:31 -0300905 if (fe->ops.i2c_gate_ctrl)
906 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700907 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
908 return -EIO;
909
910 msleep(50);
911
Patrick Boettcherdea74862006-05-14 05:01:31 -0300912 if (fe->ops.i2c_gate_ctrl)
913 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700914 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
915 return -EIO;
916
917 msleep(1);
918
919 return 0;
920}
921
922static u8 dvbc_philips_tdm1316l_inittab[] = {
923 0x80, 0x01,
924 0x80, 0x00,
925 0x81, 0x01,
926 0x81, 0x00,
927 0x00, 0x09,
928 0x01, 0x69,
929 0x03, 0x00,
930 0x04, 0x00,
931 0x07, 0x00,
932 0x08, 0x00,
933 0x20, 0x00,
934 0x21, 0x40,
935 0x22, 0x00,
936 0x23, 0x00,
937 0x24, 0x40,
938 0x25, 0x88,
939 0x30, 0xff,
940 0x31, 0x00,
941 0x32, 0xff,
942 0x33, 0x00,
943 0x34, 0x50,
944 0x35, 0x7f,
945 0x36, 0x00,
946 0x37, 0x20,
947 0x38, 0x00,
948 0x40, 0x1c,
949 0x41, 0xff,
950 0x42, 0x29,
951 0x43, 0x20,
952 0x44, 0xff,
953 0x45, 0x00,
954 0x46, 0x00,
955 0x49, 0x04,
956 0x4a, 0x00,
957 0x4b, 0x7b,
958 0x52, 0x30,
959 0x55, 0xae,
960 0x56, 0x47,
961 0x57, 0xe1,
962 0x58, 0x3a,
963 0x5a, 0x1e,
964 0x5b, 0x34,
965 0x60, 0x00,
966 0x63, 0x00,
967 0x64, 0x00,
968 0x65, 0x00,
969 0x66, 0x00,
970 0x67, 0x00,
971 0x68, 0x00,
972 0x69, 0x00,
973 0x6a, 0x02,
974 0x6b, 0x00,
975 0x70, 0xff,
976 0x71, 0x00,
977 0x72, 0x00,
978 0x73, 0x00,
979 0x74, 0x0c,
980 0x80, 0x00,
981 0x81, 0x00,
982 0x82, 0x00,
983 0x83, 0x00,
984 0x84, 0x04,
985 0x85, 0x80,
986 0x86, 0x24,
987 0x87, 0x78,
988 0x88, 0x10,
989 0x89, 0x00,
990 0x90, 0x01,
991 0x91, 0x01,
992 0xa0, 0x04,
993 0xa1, 0x00,
994 0xa2, 0x00,
995 0xb0, 0x91,
996 0xb1, 0x0b,
997 0xc0, 0x53,
998 0xc1, 0x70,
999 0xc2, 0x12,
1000 0xd0, 0x00,
1001 0xd1, 0x00,
1002 0xd2, 0x00,
1003 0xd3, 0x00,
1004 0xd4, 0x00,
1005 0xd5, 0x00,
1006 0xde, 0x00,
1007 0xdf, 0x00,
1008 0x61, 0x38,
1009 0x62, 0x0a,
1010 0x53, 0x13,
1011 0x59, 0x08,
1012 0xff, 0xff,
1013};
1014
1015static struct stv0297_config dvbc_philips_tdm1316l_config = {
1016 .demod_address = 0x1c,
1017 .inittab = dvbc_philips_tdm1316l_inittab,
1018 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001019 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001020};
1021
1022
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023
1024
1025static void frontend_init(struct budget_ci *budget_ci)
1026{
1027 switch (budget_ci->budget.dev->pci->subsystem_device) {
1028 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1029 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001030 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001032 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001033 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 break;
1035 }
1036 break;
1037
1038 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1039 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001040 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001042 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 break;
1044 }
1045 break;
1046
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001047 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1048 budget_ci->tuner_pll_address = 0x61;
1049 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001050 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001051 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001052 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001053 break;
1054 }
1055 break;
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001058 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001060 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001062 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1063 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 break;
1065 }
1066 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001067
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001068 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001069 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001070 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001071 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001072 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001073 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001074 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1075 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001076 break;
1077 }
1078 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001079
1080 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001081 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001082 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001083 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001084 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1085
Patrick Boettcherdea74862006-05-14 05:01:31 -03001086 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001087 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 -03001088 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001089 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001090 budget_ci->budget.dvb_frontend = NULL;
1091 }
1092 }
1093
1094 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 }
1096
1097 if (budget_ci->budget.dvb_frontend == NULL) {
1098 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1099 budget_ci->budget.dev->pci->vendor,
1100 budget_ci->budget.dev->pci->device,
1101 budget_ci->budget.dev->pci->subsystem_vendor,
1102 budget_ci->budget.dev->pci->subsystem_device);
1103 } else {
1104 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001105 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001107 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 budget_ci->budget.dvb_frontend = NULL;
1109 }
1110 }
1111}
1112
1113static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1114{
1115 struct budget_ci *budget_ci;
1116 int err;
1117
1118 if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
1119 return -ENOMEM;
1120
1121 dprintk(2, "budget_ci: %p\n", budget_ci);
1122
1123 budget_ci->budget.ci_present = 0;
1124
1125 dev->ext_priv = budget_ci;
1126
1127 if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
1128 kfree(budget_ci);
1129 return err;
1130 }
1131
David Hardemandd2f3982006-12-02 21:16:05 -02001132 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 (unsigned long) budget_ci);
1134
1135 msp430_ir_init(budget_ci);
1136
1137 ciintf_init(budget_ci);
1138
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001139 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 frontend_init(budget_ci);
1141
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001142 ttpci_budget_init_hooks(&budget_ci->budget);
1143
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return 0;
1145}
1146
1147static int budget_ci_detach(struct saa7146_dev *dev)
1148{
1149 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1150 struct saa7146_dev *saa = budget_ci->budget.dev;
1151 int err;
1152
1153 if (budget_ci->budget.ci_present)
1154 ciintf_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001155 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001157 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 err = ttpci_budget_deinit(&budget_ci->budget);
1160
David Hardemandd2f3982006-12-02 21:16:05 -02001161 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
1163 msp430_ir_deinit(budget_ci);
1164
1165 // disable frontend and CI interface
1166 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1167
1168 kfree(budget_ci);
1169
1170 return err;
1171}
1172
1173static struct saa7146_extension budget_extension;
1174
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001175MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1177MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001178MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001179MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
1181static struct pci_device_id pci_tbl[] = {
1182 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1183 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001184 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001186 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001187 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 {
1189 .vendor = 0,
1190 }
1191};
1192
1193MODULE_DEVICE_TABLE(pci, pci_tbl);
1194
1195static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001196 .name = "budget_ci dvb",
Oliver Endriss69459f32005-12-01 00:51:48 -08001197 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198
1199 .module = THIS_MODULE,
1200 .pci_tbl = &pci_tbl[0],
1201 .attach = budget_ci_attach,
1202 .detach = budget_ci_detach,
1203
1204 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1205 .irq_func = budget_ci_irq,
1206};
1207
1208static int __init budget_ci_init(void)
1209{
1210 return saa7146_register_extension(&budget_extension);
1211}
1212
1213static void __exit budget_ci_exit(void)
1214{
1215 saa7146_unregister_extension(&budget_extension);
1216}
1217
1218module_init(budget_ci_init);
1219module_exit(budget_ci_exit);
1220
1221MODULE_LICENSE("GPL");
1222MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1223MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1224 "budget PCI DVB cards w/ CI-module produced by "
1225 "Siemens, Technotrend, Hauppauge");