blob: b2869ab8b7b9d5ef0e6a1c55e11f6ffb87baff50 [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) {
205 error = -ENOMEM;
206 goto out1;
207 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
David Hardemandd2f3982006-12-02 21:16:05 -0200209 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
210 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200211 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
212 "pci-%s/ir0", pci_name(saa->pci));
213
David Hardemandd2f3982006-12-02 21:16:05 -0200214 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
David Hardeman5cc8ae02006-12-02 21:16:05 -0200216 input_dev->phys = budget_ci->ir.phys;
217 input_dev->id.bustype = BUS_PCI;
218 input_dev->id.version = 1;
219 if (saa->pci->subsystem_vendor) {
220 input_dev->id.vendor = saa->pci->subsystem_vendor;
221 input_dev->id.product = saa->pci->subsystem_device;
222 } else {
223 input_dev->id.vendor = saa->pci->vendor;
224 input_dev->id.product = saa->pci->device;
225 }
226# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
227 input_dev->cdev.dev = &saa->pci->dev;
228# else
229 input_dev->dev = &saa->pci->dev;
230# endif
231
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500232 set_bit(EV_KEY, input_dev->evbit);
233 for (i = 0; i < ARRAY_SIZE(key_map); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 if (key_map[i])
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500235 set_bit(key_map[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
David Hardeman8cc532e2006-12-02 21:16:05 -0200237 error = input_register_device(input_dev);
238 if (error) {
239 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
240 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300241 }
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
David Hardeman8cc532e2006-12-02 21:16:05 -0200245 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
246 (unsigned long) budget_ci);
247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
250
251 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200252
253out2:
254 input_free_device(input_dev);
255out1:
256 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257}
258
259static void msp430_ir_deinit(struct budget_ci *budget_ci)
260{
261 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200262 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
264 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
265 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200266 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300268 if (del_timer(&dev->timer)) {
269 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
270 input_sync(dev);
271 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
273 input_unregister_device(dev);
274}
275
276static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
277{
278 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
279
280 if (slot != 0)
281 return -EINVAL;
282
283 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
284 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
285}
286
287static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
288{
289 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
290
291 if (slot != 0)
292 return -EINVAL;
293
294 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
295 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
296}
297
298static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
299{
300 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
301
302 if (slot != 0)
303 return -EINVAL;
304
305 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
306 DEBIADDR_IO | (address & 3), 1, 1, 0);
307}
308
309static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
310{
311 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
312
313 if (slot != 0)
314 return -EINVAL;
315
316 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
317 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
318}
319
320static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
321{
322 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
323 struct saa7146_dev *saa = budget_ci->budget.dev;
324
325 if (slot != 0)
326 return -EINVAL;
327
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300328 if (budget_ci->ci_irq) {
329 // trigger on RISING edge during reset so we know when READY is re-asserted
330 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
331 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 budget_ci->slot_status = SLOTSTATUS_RESET;
333 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
334 msleep(1);
335 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
336 CICONTROL_RESET, 1, 0);
337
338 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
339 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
340 return 0;
341}
342
343static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
344{
345 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
346 struct saa7146_dev *saa = budget_ci->budget.dev;
347
348 if (slot != 0)
349 return -EINVAL;
350
351 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
352 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
353 return 0;
354}
355
356static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
357{
358 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
359 struct saa7146_dev *saa = budget_ci->budget.dev;
360 int tmp;
361
362 if (slot != 0)
363 return -EINVAL;
364
365 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
366
367 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
368 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
369 tmp | CICONTROL_ENABLETS, 1, 0);
370
371 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
372 return 0;
373}
374
375static void ciintf_interrupt(unsigned long data)
376{
377 struct budget_ci *budget_ci = (struct budget_ci *) data;
378 struct saa7146_dev *saa = budget_ci->budget.dev;
379 unsigned int flags;
380
381 // ensure we don't get spurious IRQs during initialisation
382 if (!budget_ci->budget.ci_present)
383 return;
384
385 // read the CAM status
386 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
387 if (flags & CICONTROL_CAMDETECT) {
388
389 // GPIO should be set to trigger on falling edge if a CAM is present
390 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
391
392 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
393 // CAM insertion IRQ
394 budget_ci->slot_status = SLOTSTATUS_PRESENT;
395 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
396 DVB_CA_EN50221_CAMCHANGE_INSERTED);
397
398 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
399 // CAM ready (reset completed)
400 budget_ci->slot_status = SLOTSTATUS_READY;
401 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
402
403 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
404 // FR/DA IRQ
405 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
406 }
407 } else {
408
409 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
410 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
411 // the CAM might not actually be ready yet.
412 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
413
414 // generate a CAM removal IRQ if we haven't already
415 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
416 // CAM removal IRQ
417 budget_ci->slot_status = SLOTSTATUS_NONE;
418 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
419 DVB_CA_EN50221_CAMCHANGE_REMOVED);
420 }
421 }
422}
423
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300424static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
425{
426 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
427 unsigned int flags;
428
429 // ensure we don't get spurious IRQs during initialisation
430 if (!budget_ci->budget.ci_present)
431 return -EINVAL;
432
433 // read the CAM status
434 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
435 if (flags & CICONTROL_CAMDETECT) {
436 // mark it as present if it wasn't before
437 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
438 budget_ci->slot_status = SLOTSTATUS_PRESENT;
439 }
440
441 // during a RESET, we check if we can read from IO memory to see when CAM is ready
442 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
443 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
444 budget_ci->slot_status = SLOTSTATUS_READY;
445 }
446 }
447 } else {
448 budget_ci->slot_status = SLOTSTATUS_NONE;
449 }
450
451 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
452 if (budget_ci->slot_status & SLOTSTATUS_READY) {
453 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
454 }
455 return DVB_CA_EN50221_POLL_CAM_PRESENT;
456 }
457
458 return 0;
459}
460
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461static int ciintf_init(struct budget_ci *budget_ci)
462{
463 struct saa7146_dev *saa = budget_ci->budget.dev;
464 int flags;
465 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300466 int ci_version;
467 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468
469 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
470
471 // enable DEBI pins
472 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
473
474 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300475 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
476 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 result = -ENODEV;
478 goto error;
479 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 // determine whether a CAM is present or not
482 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
483 budget_ci->slot_status = SLOTSTATUS_NONE;
484 if (flags & CICONTROL_CAMDETECT)
485 budget_ci->slot_status = SLOTSTATUS_PRESENT;
486
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300487 // version 0xa2 of the CI firmware doesn't generate interrupts
488 if (ci_version == 0xa2) {
489 ca_flags = 0;
490 budget_ci->ci_irq = 0;
491 } else {
492 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
493 DVB_CA_EN50221_FLAG_IRQ_FR |
494 DVB_CA_EN50221_FLAG_IRQ_DA;
495 budget_ci->ci_irq = 1;
496 }
497
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 // register CI interface
499 budget_ci->ca.owner = THIS_MODULE;
500 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
501 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
502 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
503 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
504 budget_ci->ca.slot_reset = ciintf_slot_reset;
505 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
506 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300507 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700509 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300511 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 printk("budget_ci: CI interface detected, but initialisation failed.\n");
513 goto error;
514 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300517 if (budget_ci->ci_irq) {
518 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
519 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
520 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
521 } else {
522 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
523 }
524 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300526
527 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
529 CICONTROL_RESET, 1, 0);
530
531 // success!
532 printk("budget_ci: CI interface initialised\n");
533 budget_ci->budget.ci_present = 1;
534
535 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300536 if (budget_ci->ci_irq) {
537 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
538 if (budget_ci->slot_status != SLOTSTATUS_NONE)
539 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
540 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
541 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542
543 return 0;
544
545error:
546 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
547 return result;
548}
549
550static void ciintf_deinit(struct budget_ci *budget_ci)
551{
552 struct saa7146_dev *saa = budget_ci->budget.dev;
553
554 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300555 if (budget_ci->ci_irq) {
556 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
557 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
558 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
559 }
560
561 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
563 msleep(1);
564 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
565 CICONTROL_RESET, 1, 0);
566
567 // disable TS data stream to CI interface
568 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
569
570 // release the CA device
571 dvb_ca_en50221_release(&budget_ci->ca);
572
573 // disable DEBI pins
574 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
575}
576
577static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
578{
579 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
580
581 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
582
583 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200584 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585
586 if (*isr & MASK_10)
587 ttpci_budget_irq10_handler(dev, isr);
588
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300589 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
591}
592
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593static u8 philips_su1278_tt_inittab[] = {
594 0x01, 0x0f,
595 0x02, 0x30,
596 0x03, 0x00,
597 0x04, 0x5b,
598 0x05, 0x85,
599 0x06, 0x02,
600 0x07, 0x00,
601 0x08, 0x02,
602 0x09, 0x00,
603 0x0C, 0x01,
604 0x0D, 0x81,
605 0x0E, 0x44,
606 0x0f, 0x14,
607 0x10, 0x3c,
608 0x11, 0x84,
609 0x12, 0xda,
610 0x13, 0x97,
611 0x14, 0x95,
612 0x15, 0xc9,
613 0x16, 0x19,
614 0x17, 0x8c,
615 0x18, 0x59,
616 0x19, 0xf8,
617 0x1a, 0xfe,
618 0x1c, 0x7f,
619 0x1d, 0x00,
620 0x1e, 0x00,
621 0x1f, 0x50,
622 0x20, 0x00,
623 0x21, 0x00,
624 0x22, 0x00,
625 0x23, 0x00,
626 0x28, 0x00,
627 0x29, 0x28,
628 0x2a, 0x14,
629 0x2b, 0x0f,
630 0x2c, 0x09,
631 0x2d, 0x09,
632 0x31, 0x1f,
633 0x32, 0x19,
634 0x33, 0xfc,
635 0x34, 0x93,
636 0xff, 0xff
637};
638
639static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
640{
641 stv0299_writereg(fe, 0x0e, 0x44);
642 if (srate >= 10000000) {
643 stv0299_writereg(fe, 0x13, 0x97);
644 stv0299_writereg(fe, 0x14, 0x95);
645 stv0299_writereg(fe, 0x15, 0xc9);
646 stv0299_writereg(fe, 0x17, 0x8c);
647 stv0299_writereg(fe, 0x1a, 0xfe);
648 stv0299_writereg(fe, 0x1c, 0x7f);
649 stv0299_writereg(fe, 0x2d, 0x09);
650 } else {
651 stv0299_writereg(fe, 0x13, 0x99);
652 stv0299_writereg(fe, 0x14, 0x8d);
653 stv0299_writereg(fe, 0x15, 0xce);
654 stv0299_writereg(fe, 0x17, 0x43);
655 stv0299_writereg(fe, 0x1a, 0x1d);
656 stv0299_writereg(fe, 0x1c, 0x12);
657 stv0299_writereg(fe, 0x2d, 0x05);
658 }
659 stv0299_writereg(fe, 0x0e, 0x23);
660 stv0299_writereg(fe, 0x0f, 0x94);
661 stv0299_writereg(fe, 0x10, 0x39);
662 stv0299_writereg(fe, 0x15, 0xc9);
663
664 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
665 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
666 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
667
668 return 0;
669}
670
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300671static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
672 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300674 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 u32 div;
676 u8 buf[4];
677 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
678
679 if ((params->frequency < 950000) || (params->frequency > 2150000))
680 return -EINVAL;
681
682 div = (params->frequency + (500 - 1)) / 500; // round correctly
683 buf[0] = (div >> 8) & 0x7f;
684 buf[1] = div & 0xff;
685 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
686 buf[3] = 0x20;
687
688 if (params->u.qpsk.symbol_rate < 4000000)
689 buf[3] |= 1;
690
691 if (params->frequency < 1250000)
692 buf[3] |= 0;
693 else if (params->frequency < 1550000)
694 buf[3] |= 0x40;
695 else if (params->frequency < 2050000)
696 buf[3] |= 0x80;
697 else if (params->frequency < 2150000)
698 buf[3] |= 0xC0;
699
Patrick Boettcherdea74862006-05-14 05:01:31 -0300700 if (fe->ops.i2c_gate_ctrl)
701 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300702 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return -EIO;
704 return 0;
705}
706
707static struct stv0299_config philips_su1278_tt_config = {
708
709 .demod_address = 0x68,
710 .inittab = philips_su1278_tt_inittab,
711 .mclk = 64000000UL,
712 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 .skip_reinit = 1,
714 .lock_output = STV0229_LOCKOUTPUT_1,
715 .volt13_op0_op1 = STV0299_VOLT13_OP1,
716 .min_delay_ms = 50,
717 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718};
719
720
721
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300722static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723{
724 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
725 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
726 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700727 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 sizeof(td1316_init) };
729
730 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300731 if (fe->ops.i2c_gate_ctrl)
732 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
734 return -EIO;
735 msleep(1);
736
737 // disable the mc44BC374c (do not check for errors)
738 tuner_msg.addr = 0x65;
739 tuner_msg.buf = disable_mc44BC374c;
740 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300741 if (fe->ops.i2c_gate_ctrl)
742 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300744 if (fe->ops.i2c_gate_ctrl)
745 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
747 }
748
749 return 0;
750}
751
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300752static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
754 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
755 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700756 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 -0700757 int tuner_frequency = 0;
758 u8 band, cp, filter;
759
760 // determine charge pump
761 tuner_frequency = params->frequency + 36130000;
762 if (tuner_frequency < 87000000)
763 return -EINVAL;
764 else if (tuner_frequency < 130000000)
765 cp = 3;
766 else if (tuner_frequency < 160000000)
767 cp = 5;
768 else if (tuner_frequency < 200000000)
769 cp = 6;
770 else if (tuner_frequency < 290000000)
771 cp = 3;
772 else if (tuner_frequency < 420000000)
773 cp = 5;
774 else if (tuner_frequency < 480000000)
775 cp = 6;
776 else if (tuner_frequency < 620000000)
777 cp = 3;
778 else if (tuner_frequency < 830000000)
779 cp = 5;
780 else if (tuner_frequency < 895000000)
781 cp = 7;
782 else
783 return -EINVAL;
784
785 // determine band
786 if (params->frequency < 49000000)
787 return -EINVAL;
788 else if (params->frequency < 159000000)
789 band = 1;
790 else if (params->frequency < 444000000)
791 band = 2;
792 else if (params->frequency < 861000000)
793 band = 4;
794 else
795 return -EINVAL;
796
797 // setup PLL filter and TDA9889
798 switch (params->u.ofdm.bandwidth) {
799 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300800 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 filter = 0;
802 break;
803
804 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300805 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 filter = 0;
807 break;
808
809 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300810 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700811 filter = 1;
812 break;
813
814 default:
815 return -EINVAL;
816 }
817
818 // calculate divisor
819 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
820 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
821
822 // setup tuner buffer
823 tuner_buf[0] = tuner_frequency >> 8;
824 tuner_buf[1] = tuner_frequency & 0xff;
825 tuner_buf[2] = 0xca;
826 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
827
Patrick Boettcherdea74862006-05-14 05:01:31 -0300828 if (fe->ops.i2c_gate_ctrl)
829 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
831 return -EIO;
832
833 msleep(1);
834 return 0;
835}
836
837static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
838 const struct firmware **fw, char *name)
839{
840 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
841
842 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
843}
844
845static struct tda1004x_config philips_tdm1316l_config = {
846
847 .demod_address = 0x8,
848 .invert = 0,
849 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700850 .xtal_freq = TDA10046_XTAL_4M,
851 .agc_config = TDA10046_AGC_DEFAULT,
852 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 .request_firmware = philips_tdm1316l_request_firmware,
854};
855
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300856static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700857{
858 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
859 u8 tuner_buf[5];
860 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
861 .flags = 0,
862 .buf = tuner_buf,
863 .len = sizeof(tuner_buf) };
864 int tuner_frequency = 0;
865 u8 band, cp, filter;
866
867 // determine charge pump
868 tuner_frequency = params->frequency + 36125000;
869 if (tuner_frequency < 87000000)
870 return -EINVAL;
871 else if (tuner_frequency < 130000000) {
872 cp = 3;
873 band = 1;
874 } else if (tuner_frequency < 160000000) {
875 cp = 5;
876 band = 1;
877 } else if (tuner_frequency < 200000000) {
878 cp = 6;
879 band = 1;
880 } else if (tuner_frequency < 290000000) {
881 cp = 3;
882 band = 2;
883 } else if (tuner_frequency < 420000000) {
884 cp = 5;
885 band = 2;
886 } else if (tuner_frequency < 480000000) {
887 cp = 6;
888 band = 2;
889 } else if (tuner_frequency < 620000000) {
890 cp = 3;
891 band = 4;
892 } else if (tuner_frequency < 830000000) {
893 cp = 5;
894 band = 4;
895 } else if (tuner_frequency < 895000000) {
896 cp = 7;
897 band = 4;
898 } else
899 return -EINVAL;
900
901 // assume PLL filter should always be 8MHz for the moment.
902 filter = 1;
903
904 // calculate divisor
905 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
906
907 // setup tuner buffer
908 tuner_buf[0] = tuner_frequency >> 8;
909 tuner_buf[1] = tuner_frequency & 0xff;
910 tuner_buf[2] = 0xc8;
911 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
912 tuner_buf[4] = 0x80;
913
Patrick Boettcherdea74862006-05-14 05:01:31 -0300914 if (fe->ops.i2c_gate_ctrl)
915 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700916 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
917 return -EIO;
918
919 msleep(50);
920
Patrick Boettcherdea74862006-05-14 05:01:31 -0300921 if (fe->ops.i2c_gate_ctrl)
922 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700923 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
924 return -EIO;
925
926 msleep(1);
927
928 return 0;
929}
930
931static u8 dvbc_philips_tdm1316l_inittab[] = {
932 0x80, 0x01,
933 0x80, 0x00,
934 0x81, 0x01,
935 0x81, 0x00,
936 0x00, 0x09,
937 0x01, 0x69,
938 0x03, 0x00,
939 0x04, 0x00,
940 0x07, 0x00,
941 0x08, 0x00,
942 0x20, 0x00,
943 0x21, 0x40,
944 0x22, 0x00,
945 0x23, 0x00,
946 0x24, 0x40,
947 0x25, 0x88,
948 0x30, 0xff,
949 0x31, 0x00,
950 0x32, 0xff,
951 0x33, 0x00,
952 0x34, 0x50,
953 0x35, 0x7f,
954 0x36, 0x00,
955 0x37, 0x20,
956 0x38, 0x00,
957 0x40, 0x1c,
958 0x41, 0xff,
959 0x42, 0x29,
960 0x43, 0x20,
961 0x44, 0xff,
962 0x45, 0x00,
963 0x46, 0x00,
964 0x49, 0x04,
965 0x4a, 0x00,
966 0x4b, 0x7b,
967 0x52, 0x30,
968 0x55, 0xae,
969 0x56, 0x47,
970 0x57, 0xe1,
971 0x58, 0x3a,
972 0x5a, 0x1e,
973 0x5b, 0x34,
974 0x60, 0x00,
975 0x63, 0x00,
976 0x64, 0x00,
977 0x65, 0x00,
978 0x66, 0x00,
979 0x67, 0x00,
980 0x68, 0x00,
981 0x69, 0x00,
982 0x6a, 0x02,
983 0x6b, 0x00,
984 0x70, 0xff,
985 0x71, 0x00,
986 0x72, 0x00,
987 0x73, 0x00,
988 0x74, 0x0c,
989 0x80, 0x00,
990 0x81, 0x00,
991 0x82, 0x00,
992 0x83, 0x00,
993 0x84, 0x04,
994 0x85, 0x80,
995 0x86, 0x24,
996 0x87, 0x78,
997 0x88, 0x10,
998 0x89, 0x00,
999 0x90, 0x01,
1000 0x91, 0x01,
1001 0xa0, 0x04,
1002 0xa1, 0x00,
1003 0xa2, 0x00,
1004 0xb0, 0x91,
1005 0xb1, 0x0b,
1006 0xc0, 0x53,
1007 0xc1, 0x70,
1008 0xc2, 0x12,
1009 0xd0, 0x00,
1010 0xd1, 0x00,
1011 0xd2, 0x00,
1012 0xd3, 0x00,
1013 0xd4, 0x00,
1014 0xd5, 0x00,
1015 0xde, 0x00,
1016 0xdf, 0x00,
1017 0x61, 0x38,
1018 0x62, 0x0a,
1019 0x53, 0x13,
1020 0x59, 0x08,
1021 0xff, 0xff,
1022};
1023
1024static struct stv0297_config dvbc_philips_tdm1316l_config = {
1025 .demod_address = 0x1c,
1026 .inittab = dvbc_philips_tdm1316l_inittab,
1027 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001028 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001029};
1030
1031
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032
1033
1034static void frontend_init(struct budget_ci *budget_ci)
1035{
1036 switch (budget_ci->budget.dev->pci->subsystem_device) {
1037 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1038 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001039 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001041 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001042 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 break;
1044 }
1045 break;
1046
1047 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1048 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001049 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001051 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 break;
1053 }
1054 break;
1055
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001056 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1057 budget_ci->tuner_pll_address = 0x61;
1058 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001059 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001060 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001061 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001062 break;
1063 }
1064 break;
1065
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001067 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001069 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001071 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1072 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 break;
1074 }
1075 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001076
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001077 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001078 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001079 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001080 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001081 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001082 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001083 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1084 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001085 break;
1086 }
1087 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001088
1089 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001090 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001091 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001092 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001093 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1094
Patrick Boettcherdea74862006-05-14 05:01:31 -03001095 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001096 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 -03001097 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001098 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001099 budget_ci->budget.dvb_frontend = NULL;
1100 }
1101 }
1102
1103 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001104 }
1105
1106 if (budget_ci->budget.dvb_frontend == NULL) {
1107 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1108 budget_ci->budget.dev->pci->vendor,
1109 budget_ci->budget.dev->pci->device,
1110 budget_ci->budget.dev->pci->subsystem_vendor,
1111 budget_ci->budget.dev->pci->subsystem_device);
1112 } else {
1113 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001114 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001116 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 budget_ci->budget.dvb_frontend = NULL;
1118 }
1119 }
1120}
1121
1122static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1123{
1124 struct budget_ci *budget_ci;
1125 int err;
1126
David Hardeman8cc532e2006-12-02 21:16:05 -02001127 budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL);
1128 if (!budget_ci) {
1129 err = -ENOMEM;
1130 goto out1;
1131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
1133 dprintk(2, "budget_ci: %p\n", budget_ci);
1134
1135 budget_ci->budget.ci_present = 0;
1136
1137 dev->ext_priv = budget_ci;
1138
David Hardeman8cc532e2006-12-02 21:16:05 -02001139 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1140 if (err)
1141 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
David Hardeman8cc532e2006-12-02 21:16:05 -02001143 err = msp430_ir_init(budget_ci);
1144 if (err)
1145 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146
1147 ciintf_init(budget_ci);
1148
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001149 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 frontend_init(budget_ci);
1151
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001152 ttpci_budget_init_hooks(&budget_ci->budget);
1153
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001155
1156out3:
1157 ttpci_budget_deinit(&budget_ci->budget);
1158out2:
1159 kfree(budget_ci);
1160out1:
1161 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162}
1163
1164static int budget_ci_detach(struct saa7146_dev *dev)
1165{
1166 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1167 struct saa7146_dev *saa = budget_ci->budget.dev;
1168 int err;
1169
1170 if (budget_ci->budget.ci_present)
1171 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001172 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001173 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001175 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001176 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 err = ttpci_budget_deinit(&budget_ci->budget);
1178
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 // disable frontend and CI interface
1180 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1181
1182 kfree(budget_ci);
1183
1184 return err;
1185}
1186
1187static struct saa7146_extension budget_extension;
1188
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001189MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1191MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001192MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001193MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194
1195static struct pci_device_id pci_tbl[] = {
1196 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1197 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001198 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001200 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001201 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 {
1203 .vendor = 0,
1204 }
1205};
1206
1207MODULE_DEVICE_TABLE(pci, pci_tbl);
1208
1209static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001210 .name = "budget_ci dvb",
Oliver Endriss69459f32005-12-01 00:51:48 -08001211 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212
1213 .module = THIS_MODULE,
1214 .pci_tbl = &pci_tbl[0],
1215 .attach = budget_ci_attach,
1216 .detach = budget_ci_detach,
1217
1218 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1219 .irq_func = budget_ci_irq,
1220};
1221
1222static int __init budget_ci_init(void)
1223{
1224 return saa7146_register_extension(&budget_extension);
1225}
1226
1227static void __exit budget_ci_exit(void)
1228{
1229 saa7146_unregister_extension(&budget_extension);
1230}
1231
1232module_init(budget_ci_init);
1233module_exit(budget_ci_exit);
1234
1235MODULE_LICENSE("GPL");
1236MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1237MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1238 "budget PCI DVB cards w/ CI-module produced by "
1239 "Siemens, Technotrend, Hauppauge");