blob: c34b5d3bdde5c53bdf702fcfd3ba278733b33502 [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;
David Hardeman8cc532e2006-12-02 21:16:05 -0200201 int error;
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();
David Hardeman8cc532e2006-12-02 21:16:05 -0200204 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200205 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200206 error = -ENOMEM;
207 goto out1;
208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
David Hardemandd2f3982006-12-02 21:16:05 -0200210 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
211 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200212 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
213 "pci-%s/ir0", pci_name(saa->pci));
214
David Hardemandd2f3982006-12-02 21:16:05 -0200215 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
David Hardeman5cc8ae02006-12-02 21:16:05 -0200217 input_dev->phys = budget_ci->ir.phys;
218 input_dev->id.bustype = BUS_PCI;
219 input_dev->id.version = 1;
220 if (saa->pci->subsystem_vendor) {
221 input_dev->id.vendor = saa->pci->subsystem_vendor;
222 input_dev->id.product = saa->pci->subsystem_device;
223 } else {
224 input_dev->id.vendor = saa->pci->vendor;
225 input_dev->id.product = saa->pci->device;
226 }
227# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
228 input_dev->cdev.dev = &saa->pci->dev;
229# else
230 input_dev->dev = &saa->pci->dev;
231# endif
232
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500233 set_bit(EV_KEY, input_dev->evbit);
234 for (i = 0; i < ARRAY_SIZE(key_map); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235 if (key_map[i])
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500236 set_bit(key_map[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
David Hardeman8cc532e2006-12-02 21:16:05 -0200238 error = input_register_device(input_dev);
239 if (error) {
240 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
241 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
David Hardemandd2f3982006-12-02 21:16:05 -0200244 input_dev->timer.function = msp430_ir_debounce;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300245
David Hardeman8cc532e2006-12-02 21:16:05 -0200246 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
247 (unsigned long) budget_ci);
248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
251
252 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200253
254out2:
255 input_free_device(input_dev);
256out1:
257 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258}
259
260static void msp430_ir_deinit(struct budget_ci *budget_ci)
261{
262 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200263 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
265 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
266 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200267 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300269 if (del_timer(&dev->timer)) {
270 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
271 input_sync(dev);
272 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
274 input_unregister_device(dev);
275}
276
277static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
278{
279 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
280
281 if (slot != 0)
282 return -EINVAL;
283
284 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
285 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
286}
287
288static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
289{
290 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
291
292 if (slot != 0)
293 return -EINVAL;
294
295 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
296 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
297}
298
299static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
300{
301 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
302
303 if (slot != 0)
304 return -EINVAL;
305
306 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
307 DEBIADDR_IO | (address & 3), 1, 1, 0);
308}
309
310static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
311{
312 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
313
314 if (slot != 0)
315 return -EINVAL;
316
317 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
318 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
319}
320
321static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
322{
323 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
324 struct saa7146_dev *saa = budget_ci->budget.dev;
325
326 if (slot != 0)
327 return -EINVAL;
328
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300329 if (budget_ci->ci_irq) {
330 // trigger on RISING edge during reset so we know when READY is re-asserted
331 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333 budget_ci->slot_status = SLOTSTATUS_RESET;
334 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
335 msleep(1);
336 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
337 CICONTROL_RESET, 1, 0);
338
339 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
340 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
341 return 0;
342}
343
344static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
345{
346 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
347 struct saa7146_dev *saa = budget_ci->budget.dev;
348
349 if (slot != 0)
350 return -EINVAL;
351
352 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
353 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
354 return 0;
355}
356
357static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
358{
359 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
360 struct saa7146_dev *saa = budget_ci->budget.dev;
361 int tmp;
362
363 if (slot != 0)
364 return -EINVAL;
365
366 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
367
368 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
369 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
370 tmp | CICONTROL_ENABLETS, 1, 0);
371
372 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
373 return 0;
374}
375
376static void ciintf_interrupt(unsigned long data)
377{
378 struct budget_ci *budget_ci = (struct budget_ci *) data;
379 struct saa7146_dev *saa = budget_ci->budget.dev;
380 unsigned int flags;
381
382 // ensure we don't get spurious IRQs during initialisation
383 if (!budget_ci->budget.ci_present)
384 return;
385
386 // read the CAM status
387 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
388 if (flags & CICONTROL_CAMDETECT) {
389
390 // GPIO should be set to trigger on falling edge if a CAM is present
391 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
392
393 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
394 // CAM insertion IRQ
395 budget_ci->slot_status = SLOTSTATUS_PRESENT;
396 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
397 DVB_CA_EN50221_CAMCHANGE_INSERTED);
398
399 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
400 // CAM ready (reset completed)
401 budget_ci->slot_status = SLOTSTATUS_READY;
402 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
403
404 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
405 // FR/DA IRQ
406 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
407 }
408 } else {
409
410 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
411 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
412 // the CAM might not actually be ready yet.
413 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
414
415 // generate a CAM removal IRQ if we haven't already
416 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
417 // CAM removal IRQ
418 budget_ci->slot_status = SLOTSTATUS_NONE;
419 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
420 DVB_CA_EN50221_CAMCHANGE_REMOVED);
421 }
422 }
423}
424
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300425static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
426{
427 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
428 unsigned int flags;
429
430 // ensure we don't get spurious IRQs during initialisation
431 if (!budget_ci->budget.ci_present)
432 return -EINVAL;
433
434 // read the CAM status
435 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
436 if (flags & CICONTROL_CAMDETECT) {
437 // mark it as present if it wasn't before
438 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
439 budget_ci->slot_status = SLOTSTATUS_PRESENT;
440 }
441
442 // during a RESET, we check if we can read from IO memory to see when CAM is ready
443 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
444 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
445 budget_ci->slot_status = SLOTSTATUS_READY;
446 }
447 }
448 } else {
449 budget_ci->slot_status = SLOTSTATUS_NONE;
450 }
451
452 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
453 if (budget_ci->slot_status & SLOTSTATUS_READY) {
454 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
455 }
456 return DVB_CA_EN50221_POLL_CAM_PRESENT;
457 }
458
459 return 0;
460}
461
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462static int ciintf_init(struct budget_ci *budget_ci)
463{
464 struct saa7146_dev *saa = budget_ci->budget.dev;
465 int flags;
466 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300467 int ci_version;
468 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469
470 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
471
472 // enable DEBI pins
473 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
474
475 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300476 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
477 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 result = -ENODEV;
479 goto error;
480 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300481
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 // determine whether a CAM is present or not
483 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
484 budget_ci->slot_status = SLOTSTATUS_NONE;
485 if (flags & CICONTROL_CAMDETECT)
486 budget_ci->slot_status = SLOTSTATUS_PRESENT;
487
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300488 // version 0xa2 of the CI firmware doesn't generate interrupts
489 if (ci_version == 0xa2) {
490 ca_flags = 0;
491 budget_ci->ci_irq = 0;
492 } else {
493 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
494 DVB_CA_EN50221_FLAG_IRQ_FR |
495 DVB_CA_EN50221_FLAG_IRQ_DA;
496 budget_ci->ci_irq = 1;
497 }
498
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 // register CI interface
500 budget_ci->ca.owner = THIS_MODULE;
501 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
502 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
503 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
504 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
505 budget_ci->ca.slot_reset = ciintf_slot_reset;
506 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
507 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300508 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700510 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700511 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300512 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 printk("budget_ci: CI interface detected, but initialisation failed.\n");
514 goto error;
515 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300518 if (budget_ci->ci_irq) {
519 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
520 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
521 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
522 } else {
523 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
524 }
525 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300527
528 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
530 CICONTROL_RESET, 1, 0);
531
532 // success!
533 printk("budget_ci: CI interface initialised\n");
534 budget_ci->budget.ci_present = 1;
535
536 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300537 if (budget_ci->ci_irq) {
538 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
539 if (budget_ci->slot_status != SLOTSTATUS_NONE)
540 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
541 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
542 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543
544 return 0;
545
546error:
547 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
548 return result;
549}
550
551static void ciintf_deinit(struct budget_ci *budget_ci)
552{
553 struct saa7146_dev *saa = budget_ci->budget.dev;
554
555 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300556 if (budget_ci->ci_irq) {
557 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
558 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
559 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
560 }
561
562 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
564 msleep(1);
565 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
566 CICONTROL_RESET, 1, 0);
567
568 // disable TS data stream to CI interface
569 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
570
571 // release the CA device
572 dvb_ca_en50221_release(&budget_ci->ca);
573
574 // disable DEBI pins
575 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
576}
577
578static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
579{
580 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
581
582 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
583
584 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200585 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
587 if (*isr & MASK_10)
588 ttpci_budget_irq10_handler(dev, isr);
589
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300590 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
592}
593
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594static u8 philips_su1278_tt_inittab[] = {
595 0x01, 0x0f,
596 0x02, 0x30,
597 0x03, 0x00,
598 0x04, 0x5b,
599 0x05, 0x85,
600 0x06, 0x02,
601 0x07, 0x00,
602 0x08, 0x02,
603 0x09, 0x00,
604 0x0C, 0x01,
605 0x0D, 0x81,
606 0x0E, 0x44,
607 0x0f, 0x14,
608 0x10, 0x3c,
609 0x11, 0x84,
610 0x12, 0xda,
611 0x13, 0x97,
612 0x14, 0x95,
613 0x15, 0xc9,
614 0x16, 0x19,
615 0x17, 0x8c,
616 0x18, 0x59,
617 0x19, 0xf8,
618 0x1a, 0xfe,
619 0x1c, 0x7f,
620 0x1d, 0x00,
621 0x1e, 0x00,
622 0x1f, 0x50,
623 0x20, 0x00,
624 0x21, 0x00,
625 0x22, 0x00,
626 0x23, 0x00,
627 0x28, 0x00,
628 0x29, 0x28,
629 0x2a, 0x14,
630 0x2b, 0x0f,
631 0x2c, 0x09,
632 0x2d, 0x09,
633 0x31, 0x1f,
634 0x32, 0x19,
635 0x33, 0xfc,
636 0x34, 0x93,
637 0xff, 0xff
638};
639
640static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
641{
642 stv0299_writereg(fe, 0x0e, 0x44);
643 if (srate >= 10000000) {
644 stv0299_writereg(fe, 0x13, 0x97);
645 stv0299_writereg(fe, 0x14, 0x95);
646 stv0299_writereg(fe, 0x15, 0xc9);
647 stv0299_writereg(fe, 0x17, 0x8c);
648 stv0299_writereg(fe, 0x1a, 0xfe);
649 stv0299_writereg(fe, 0x1c, 0x7f);
650 stv0299_writereg(fe, 0x2d, 0x09);
651 } else {
652 stv0299_writereg(fe, 0x13, 0x99);
653 stv0299_writereg(fe, 0x14, 0x8d);
654 stv0299_writereg(fe, 0x15, 0xce);
655 stv0299_writereg(fe, 0x17, 0x43);
656 stv0299_writereg(fe, 0x1a, 0x1d);
657 stv0299_writereg(fe, 0x1c, 0x12);
658 stv0299_writereg(fe, 0x2d, 0x05);
659 }
660 stv0299_writereg(fe, 0x0e, 0x23);
661 stv0299_writereg(fe, 0x0f, 0x94);
662 stv0299_writereg(fe, 0x10, 0x39);
663 stv0299_writereg(fe, 0x15, 0xc9);
664
665 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
666 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
667 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
668
669 return 0;
670}
671
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300672static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
673 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300675 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 u32 div;
677 u8 buf[4];
678 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
679
680 if ((params->frequency < 950000) || (params->frequency > 2150000))
681 return -EINVAL;
682
683 div = (params->frequency + (500 - 1)) / 500; // round correctly
684 buf[0] = (div >> 8) & 0x7f;
685 buf[1] = div & 0xff;
686 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
687 buf[3] = 0x20;
688
689 if (params->u.qpsk.symbol_rate < 4000000)
690 buf[3] |= 1;
691
692 if (params->frequency < 1250000)
693 buf[3] |= 0;
694 else if (params->frequency < 1550000)
695 buf[3] |= 0x40;
696 else if (params->frequency < 2050000)
697 buf[3] |= 0x80;
698 else if (params->frequency < 2150000)
699 buf[3] |= 0xC0;
700
Patrick Boettcherdea74862006-05-14 05:01:31 -0300701 if (fe->ops.i2c_gate_ctrl)
702 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300703 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return -EIO;
705 return 0;
706}
707
708static struct stv0299_config philips_su1278_tt_config = {
709
710 .demod_address = 0x68,
711 .inittab = philips_su1278_tt_inittab,
712 .mclk = 64000000UL,
713 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 .skip_reinit = 1,
715 .lock_output = STV0229_LOCKOUTPUT_1,
716 .volt13_op0_op1 = STV0299_VOLT13_OP1,
717 .min_delay_ms = 50,
718 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719};
720
721
722
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300723static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724{
725 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
726 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
727 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700728 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729 sizeof(td1316_init) };
730
731 // setup PLL configuration
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)
735 return -EIO;
736 msleep(1);
737
738 // disable the mc44BC374c (do not check for errors)
739 tuner_msg.addr = 0x65;
740 tuner_msg.buf = disable_mc44BC374c;
741 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300742 if (fe->ops.i2c_gate_ctrl)
743 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300745 if (fe->ops.i2c_gate_ctrl)
746 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
748 }
749
750 return 0;
751}
752
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300753static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754{
755 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
756 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700757 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 -0700758 int tuner_frequency = 0;
759 u8 band, cp, filter;
760
761 // determine charge pump
762 tuner_frequency = params->frequency + 36130000;
763 if (tuner_frequency < 87000000)
764 return -EINVAL;
765 else if (tuner_frequency < 130000000)
766 cp = 3;
767 else if (tuner_frequency < 160000000)
768 cp = 5;
769 else if (tuner_frequency < 200000000)
770 cp = 6;
771 else if (tuner_frequency < 290000000)
772 cp = 3;
773 else if (tuner_frequency < 420000000)
774 cp = 5;
775 else if (tuner_frequency < 480000000)
776 cp = 6;
777 else if (tuner_frequency < 620000000)
778 cp = 3;
779 else if (tuner_frequency < 830000000)
780 cp = 5;
781 else if (tuner_frequency < 895000000)
782 cp = 7;
783 else
784 return -EINVAL;
785
786 // determine band
787 if (params->frequency < 49000000)
788 return -EINVAL;
789 else if (params->frequency < 159000000)
790 band = 1;
791 else if (params->frequency < 444000000)
792 band = 2;
793 else if (params->frequency < 861000000)
794 band = 4;
795 else
796 return -EINVAL;
797
798 // setup PLL filter and TDA9889
799 switch (params->u.ofdm.bandwidth) {
800 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300801 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 filter = 0;
803 break;
804
805 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300806 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807 filter = 0;
808 break;
809
810 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300811 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812 filter = 1;
813 break;
814
815 default:
816 return -EINVAL;
817 }
818
819 // calculate divisor
820 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
821 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
822
823 // setup tuner buffer
824 tuner_buf[0] = tuner_frequency >> 8;
825 tuner_buf[1] = tuner_frequency & 0xff;
826 tuner_buf[2] = 0xca;
827 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
828
Patrick Boettcherdea74862006-05-14 05:01:31 -0300829 if (fe->ops.i2c_gate_ctrl)
830 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
832 return -EIO;
833
834 msleep(1);
835 return 0;
836}
837
838static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
839 const struct firmware **fw, char *name)
840{
841 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
842
843 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
844}
845
846static struct tda1004x_config philips_tdm1316l_config = {
847
848 .demod_address = 0x8,
849 .invert = 0,
850 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700851 .xtal_freq = TDA10046_XTAL_4M,
852 .agc_config = TDA10046_AGC_DEFAULT,
853 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 .request_firmware = philips_tdm1316l_request_firmware,
855};
856
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300857static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700858{
859 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
860 u8 tuner_buf[5];
861 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
862 .flags = 0,
863 .buf = tuner_buf,
864 .len = sizeof(tuner_buf) };
865 int tuner_frequency = 0;
866 u8 band, cp, filter;
867
868 // determine charge pump
869 tuner_frequency = params->frequency + 36125000;
870 if (tuner_frequency < 87000000)
871 return -EINVAL;
872 else if (tuner_frequency < 130000000) {
873 cp = 3;
874 band = 1;
875 } else if (tuner_frequency < 160000000) {
876 cp = 5;
877 band = 1;
878 } else if (tuner_frequency < 200000000) {
879 cp = 6;
880 band = 1;
881 } else if (tuner_frequency < 290000000) {
882 cp = 3;
883 band = 2;
884 } else if (tuner_frequency < 420000000) {
885 cp = 5;
886 band = 2;
887 } else if (tuner_frequency < 480000000) {
888 cp = 6;
889 band = 2;
890 } else if (tuner_frequency < 620000000) {
891 cp = 3;
892 band = 4;
893 } else if (tuner_frequency < 830000000) {
894 cp = 5;
895 band = 4;
896 } else if (tuner_frequency < 895000000) {
897 cp = 7;
898 band = 4;
899 } else
900 return -EINVAL;
901
902 // assume PLL filter should always be 8MHz for the moment.
903 filter = 1;
904
905 // calculate divisor
906 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
907
908 // setup tuner buffer
909 tuner_buf[0] = tuner_frequency >> 8;
910 tuner_buf[1] = tuner_frequency & 0xff;
911 tuner_buf[2] = 0xc8;
912 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
913 tuner_buf[4] = 0x80;
914
Patrick Boettcherdea74862006-05-14 05:01:31 -0300915 if (fe->ops.i2c_gate_ctrl)
916 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700917 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
918 return -EIO;
919
920 msleep(50);
921
Patrick Boettcherdea74862006-05-14 05:01:31 -0300922 if (fe->ops.i2c_gate_ctrl)
923 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700924 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
925 return -EIO;
926
927 msleep(1);
928
929 return 0;
930}
931
932static u8 dvbc_philips_tdm1316l_inittab[] = {
933 0x80, 0x01,
934 0x80, 0x00,
935 0x81, 0x01,
936 0x81, 0x00,
937 0x00, 0x09,
938 0x01, 0x69,
939 0x03, 0x00,
940 0x04, 0x00,
941 0x07, 0x00,
942 0x08, 0x00,
943 0x20, 0x00,
944 0x21, 0x40,
945 0x22, 0x00,
946 0x23, 0x00,
947 0x24, 0x40,
948 0x25, 0x88,
949 0x30, 0xff,
950 0x31, 0x00,
951 0x32, 0xff,
952 0x33, 0x00,
953 0x34, 0x50,
954 0x35, 0x7f,
955 0x36, 0x00,
956 0x37, 0x20,
957 0x38, 0x00,
958 0x40, 0x1c,
959 0x41, 0xff,
960 0x42, 0x29,
961 0x43, 0x20,
962 0x44, 0xff,
963 0x45, 0x00,
964 0x46, 0x00,
965 0x49, 0x04,
966 0x4a, 0x00,
967 0x4b, 0x7b,
968 0x52, 0x30,
969 0x55, 0xae,
970 0x56, 0x47,
971 0x57, 0xe1,
972 0x58, 0x3a,
973 0x5a, 0x1e,
974 0x5b, 0x34,
975 0x60, 0x00,
976 0x63, 0x00,
977 0x64, 0x00,
978 0x65, 0x00,
979 0x66, 0x00,
980 0x67, 0x00,
981 0x68, 0x00,
982 0x69, 0x00,
983 0x6a, 0x02,
984 0x6b, 0x00,
985 0x70, 0xff,
986 0x71, 0x00,
987 0x72, 0x00,
988 0x73, 0x00,
989 0x74, 0x0c,
990 0x80, 0x00,
991 0x81, 0x00,
992 0x82, 0x00,
993 0x83, 0x00,
994 0x84, 0x04,
995 0x85, 0x80,
996 0x86, 0x24,
997 0x87, 0x78,
998 0x88, 0x10,
999 0x89, 0x00,
1000 0x90, 0x01,
1001 0x91, 0x01,
1002 0xa0, 0x04,
1003 0xa1, 0x00,
1004 0xa2, 0x00,
1005 0xb0, 0x91,
1006 0xb1, 0x0b,
1007 0xc0, 0x53,
1008 0xc1, 0x70,
1009 0xc2, 0x12,
1010 0xd0, 0x00,
1011 0xd1, 0x00,
1012 0xd2, 0x00,
1013 0xd3, 0x00,
1014 0xd4, 0x00,
1015 0xd5, 0x00,
1016 0xde, 0x00,
1017 0xdf, 0x00,
1018 0x61, 0x38,
1019 0x62, 0x0a,
1020 0x53, 0x13,
1021 0x59, 0x08,
1022 0xff, 0xff,
1023};
1024
1025static struct stv0297_config dvbc_philips_tdm1316l_config = {
1026 .demod_address = 0x1c,
1027 .inittab = dvbc_philips_tdm1316l_inittab,
1028 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001029 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001030};
1031
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033
1034
1035static void frontend_init(struct budget_ci *budget_ci)
1036{
1037 switch (budget_ci->budget.dev->pci->subsystem_device) {
1038 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1039 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001040 dvb_attach(stv0299_attach, &alps_bsru6_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 = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001043 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 break;
1045 }
1046 break;
1047
1048 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1049 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001050 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -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 = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 break;
1054 }
1055 break;
1056
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001057 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1058 budget_ci->tuner_pll_address = 0x61;
1059 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001060 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001061 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001062 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001063 break;
1064 }
1065 break;
1066
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001068 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001070 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001072 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1073 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 break;
1075 }
1076 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001077
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001078 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001079 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001080 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001081 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001082 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001083 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001084 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1085 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001086 break;
1087 }
1088 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001089
1090 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001091 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001092 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001093 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001094 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1095
Patrick Boettcherdea74862006-05-14 05:01:31 -03001096 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001097 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 -03001098 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001099 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001100 budget_ci->budget.dvb_frontend = NULL;
1101 }
1102 }
1103
1104 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 }
1106
1107 if (budget_ci->budget.dvb_frontend == NULL) {
1108 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1109 budget_ci->budget.dev->pci->vendor,
1110 budget_ci->budget.dev->pci->device,
1111 budget_ci->budget.dev->pci->subsystem_vendor,
1112 budget_ci->budget.dev->pci->subsystem_device);
1113 } else {
1114 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001115 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001117 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 budget_ci->budget.dvb_frontend = NULL;
1119 }
1120 }
1121}
1122
1123static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1124{
1125 struct budget_ci *budget_ci;
1126 int err;
1127
David Hardemanee579bc2006-12-02 21:16:05 -02001128 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001129 if (!budget_ci) {
1130 err = -ENOMEM;
1131 goto out1;
1132 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133
1134 dprintk(2, "budget_ci: %p\n", budget_ci);
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 dev->ext_priv = budget_ci;
1137
David Hardeman8cc532e2006-12-02 21:16:05 -02001138 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1139 if (err)
1140 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
David Hardeman8cc532e2006-12-02 21:16:05 -02001142 err = msp430_ir_init(budget_ci);
1143 if (err)
1144 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
1146 ciintf_init(budget_ci);
1147
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001148 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149 frontend_init(budget_ci);
1150
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001151 ttpci_budget_init_hooks(&budget_ci->budget);
1152
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001154
1155out3:
1156 ttpci_budget_deinit(&budget_ci->budget);
1157out2:
1158 kfree(budget_ci);
1159out1:
1160 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161}
1162
1163static int budget_ci_detach(struct saa7146_dev *dev)
1164{
1165 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1166 struct saa7146_dev *saa = budget_ci->budget.dev;
1167 int err;
1168
1169 if (budget_ci->budget.ci_present)
1170 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001171 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001172 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001174 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001175 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 err = ttpci_budget_deinit(&budget_ci->budget);
1177
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178 // disable frontend and CI interface
1179 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1180
1181 kfree(budget_ci);
1182
1183 return err;
1184}
1185
1186static struct saa7146_extension budget_extension;
1187
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001188MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1190MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001191MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001192MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
1194static struct pci_device_id pci_tbl[] = {
1195 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1196 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001197 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001199 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001200 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 {
1202 .vendor = 0,
1203 }
1204};
1205
1206MODULE_DEVICE_TABLE(pci, pci_tbl);
1207
1208static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001209 .name = "budget_ci dvb",
Oliver Endriss69459f32005-12-01 00:51:48 -08001210 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
1212 .module = THIS_MODULE,
1213 .pci_tbl = &pci_tbl[0],
1214 .attach = budget_ci_attach,
1215 .detach = budget_ci_detach,
1216
1217 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1218 .irq_func = budget_ci_irq,
1219};
1220
1221static int __init budget_ci_init(void)
1222{
1223 return saa7146_register_extension(&budget_extension);
1224}
1225
1226static void __exit budget_ci_exit(void)
1227{
1228 saa7146_unregister_extension(&budget_extension);
1229}
1230
1231module_init(budget_ci_init);
1232module_exit(budget_ci_exit);
1233
1234MODULE_LICENSE("GPL");
1235MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1236MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1237 "budget PCI DVB cards w/ CI-module produced by "
1238 "Siemens, Technotrend, Hauppauge");