blob: 2893e752745bbab07ddf46d35e4cff2403f209b4 [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 */
79};
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081struct budget_ci {
82 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 struct tasklet_struct ciintf_irq_tasklet;
84 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -030085 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -020087 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -070088 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -070089};
90
91/* from reading the following remotes:
92 Zenith Universal 7 / TV Mode 807 / VCR Mode 837
93 Hauppauge (from NOVA-CI-s box product)
94 i've taken a "middle of the road" approach and note the differences
95*/
96static u16 key_map[64] = {
97 /* 0x0X */
98 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
99 KEY_9,
100 KEY_ENTER,
101 KEY_RED,
102 KEY_POWER, /* RADIO on Hauppauge */
103 KEY_MUTE,
104 0,
105 KEY_A, /* TV on Hauppauge */
106 /* 0x1X */
107 KEY_VOLUMEUP, KEY_VOLUMEDOWN,
108 0, 0,
109 KEY_B,
110 0, 0, 0, 0, 0, 0, 0,
111 KEY_UP, KEY_DOWN,
112 KEY_OPTION, /* RESERVED on Hauppauge */
113 KEY_BREAK,
114 /* 0x2X */
115 KEY_CHANNELUP, KEY_CHANNELDOWN,
116 KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
117 0, KEY_RESTART, KEY_OK,
118 KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
119 0,
120 KEY_ENTER, /* VCR mode on Zenith */
121 KEY_PAUSE,
122 0,
123 KEY_RIGHT, KEY_LEFT,
124 0,
125 KEY_MENU, /* FULL SCREEN on Hauppauge */
126 0,
127 /* 0x3X */
128 KEY_SLOW,
129 KEY_PREVIOUS, /* VCR mode on Zenith */
130 KEY_REWIND,
131 0,
132 KEY_FASTFORWARD,
133 KEY_PLAY, KEY_STOP,
134 KEY_RECORD,
135 KEY_TUNER, /* TV/VCR on Zenith */
136 0,
137 KEY_C,
138 0,
139 KEY_EXIT,
140 KEY_POWER2,
141 KEY_TUNER, /* VCR mode on Zenith */
142 0,
143};
144
145static void msp430_ir_debounce(unsigned long data)
146{
147 struct input_dev *dev = (struct input_dev *) data;
148
149 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300150 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
151 } else {
152 dev->rep[0] = 0;
153 dev->timer.expires = jiffies + HZ * 350 / 1000;
154 add_timer(&dev->timer);
155 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156 }
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300157 input_sync(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158}
159
160static void msp430_ir_interrupt(unsigned long data)
161{
162 struct budget_ci *budget_ci = (struct budget_ci *) data;
David Hardemandd2f3982006-12-02 21:16:05 -0200163 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 unsigned int code =
165 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
166
167 if (code & 0x40) {
168 code &= 0x3f;
169
170 if (timer_pending(&dev->timer)) {
171 if (code == dev->repeat_key) {
172 ++dev->rep[0];
173 return;
174 }
175 del_timer(&dev->timer);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300176 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 }
178
179 if (!key_map[code]) {
180 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
181 return;
182 }
183
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300184 input_event(dev, EV_KEY, key_map[code], 1);
185 input_sync(dev);
186
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 /* initialize debounce and repeat */
188 dev->repeat_key = code;
189 /* Zenith remote _always_ sends 2 sequences */
190 dev->rep[0] = ~0;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300191 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(350));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 }
193}
194
195static int msp430_ir_init(struct budget_ci *budget_ci)
196{
197 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200198 struct input_dev *input_dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 int i;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300200 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
David Hardemandd2f3982006-12-02 21:16:05 -0200202 budget_ci->ir.dev = input_dev = input_allocate_device();
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500203 if (!input_dev)
204 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
David Hardemandd2f3982006-12-02 21:16:05 -0200206 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
207 "Budget-CI dvb ir receiver %s", saa->name);
208 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500210 set_bit(EV_KEY, input_dev->evbit);
211 for (i = 0; i < ARRAY_SIZE(key_map); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 if (key_map[i])
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500213 set_bit(key_map[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300215 err = input_register_device(input_dev);
216 if (err) {
217 input_free_device(input_dev);
218 return err;
219 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
David Hardemandd2f3982006-12-02 21:16:05 -0200221 input_register_device(budget_ci->ir.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222
David Hardemandd2f3982006-12-02 21:16:05 -0200223 input_dev->timer.function = msp430_ir_debounce;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300224
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
227
228 return 0;
229}
230
231static void msp430_ir_deinit(struct budget_ci *budget_ci)
232{
233 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200234 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
236 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
237 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
238
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300239 if (del_timer(&dev->timer)) {
240 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
241 input_sync(dev);
242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 input_unregister_device(dev);
245}
246
247static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
248{
249 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
250
251 if (slot != 0)
252 return -EINVAL;
253
254 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
255 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
256}
257
258static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
259{
260 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
261
262 if (slot != 0)
263 return -EINVAL;
264
265 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
266 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
267}
268
269static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
270{
271 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
272
273 if (slot != 0)
274 return -EINVAL;
275
276 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
277 DEBIADDR_IO | (address & 3), 1, 1, 0);
278}
279
280static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
281{
282 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
283
284 if (slot != 0)
285 return -EINVAL;
286
287 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
288 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
289}
290
291static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
292{
293 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
294 struct saa7146_dev *saa = budget_ci->budget.dev;
295
296 if (slot != 0)
297 return -EINVAL;
298
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300299 if (budget_ci->ci_irq) {
300 // trigger on RISING edge during reset so we know when READY is re-asserted
301 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303 budget_ci->slot_status = SLOTSTATUS_RESET;
304 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
305 msleep(1);
306 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
307 CICONTROL_RESET, 1, 0);
308
309 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
310 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
311 return 0;
312}
313
314static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
315{
316 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
317 struct saa7146_dev *saa = budget_ci->budget.dev;
318
319 if (slot != 0)
320 return -EINVAL;
321
322 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
323 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
324 return 0;
325}
326
327static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
328{
329 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
330 struct saa7146_dev *saa = budget_ci->budget.dev;
331 int tmp;
332
333 if (slot != 0)
334 return -EINVAL;
335
336 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
337
338 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
339 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
340 tmp | CICONTROL_ENABLETS, 1, 0);
341
342 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
343 return 0;
344}
345
346static void ciintf_interrupt(unsigned long data)
347{
348 struct budget_ci *budget_ci = (struct budget_ci *) data;
349 struct saa7146_dev *saa = budget_ci->budget.dev;
350 unsigned int flags;
351
352 // ensure we don't get spurious IRQs during initialisation
353 if (!budget_ci->budget.ci_present)
354 return;
355
356 // read the CAM status
357 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
358 if (flags & CICONTROL_CAMDETECT) {
359
360 // GPIO should be set to trigger on falling edge if a CAM is present
361 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
362
363 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
364 // CAM insertion IRQ
365 budget_ci->slot_status = SLOTSTATUS_PRESENT;
366 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
367 DVB_CA_EN50221_CAMCHANGE_INSERTED);
368
369 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
370 // CAM ready (reset completed)
371 budget_ci->slot_status = SLOTSTATUS_READY;
372 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
373
374 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
375 // FR/DA IRQ
376 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
377 }
378 } else {
379
380 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
381 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
382 // the CAM might not actually be ready yet.
383 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
384
385 // generate a CAM removal IRQ if we haven't already
386 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
387 // CAM removal IRQ
388 budget_ci->slot_status = SLOTSTATUS_NONE;
389 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
390 DVB_CA_EN50221_CAMCHANGE_REMOVED);
391 }
392 }
393}
394
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300395static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
396{
397 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
398 unsigned int flags;
399
400 // ensure we don't get spurious IRQs during initialisation
401 if (!budget_ci->budget.ci_present)
402 return -EINVAL;
403
404 // read the CAM status
405 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
406 if (flags & CICONTROL_CAMDETECT) {
407 // mark it as present if it wasn't before
408 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
409 budget_ci->slot_status = SLOTSTATUS_PRESENT;
410 }
411
412 // during a RESET, we check if we can read from IO memory to see when CAM is ready
413 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
414 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
415 budget_ci->slot_status = SLOTSTATUS_READY;
416 }
417 }
418 } else {
419 budget_ci->slot_status = SLOTSTATUS_NONE;
420 }
421
422 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
423 if (budget_ci->slot_status & SLOTSTATUS_READY) {
424 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
425 }
426 return DVB_CA_EN50221_POLL_CAM_PRESENT;
427 }
428
429 return 0;
430}
431
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432static int ciintf_init(struct budget_ci *budget_ci)
433{
434 struct saa7146_dev *saa = budget_ci->budget.dev;
435 int flags;
436 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300437 int ci_version;
438 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
441
442 // enable DEBI pins
443 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
444
445 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300446 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
447 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 result = -ENODEV;
449 goto error;
450 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300451
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452 // determine whether a CAM is present or not
453 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
454 budget_ci->slot_status = SLOTSTATUS_NONE;
455 if (flags & CICONTROL_CAMDETECT)
456 budget_ci->slot_status = SLOTSTATUS_PRESENT;
457
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300458 // version 0xa2 of the CI firmware doesn't generate interrupts
459 if (ci_version == 0xa2) {
460 ca_flags = 0;
461 budget_ci->ci_irq = 0;
462 } else {
463 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
464 DVB_CA_EN50221_FLAG_IRQ_FR |
465 DVB_CA_EN50221_FLAG_IRQ_DA;
466 budget_ci->ci_irq = 1;
467 }
468
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 // register CI interface
470 budget_ci->ca.owner = THIS_MODULE;
471 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
472 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
473 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
474 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
475 budget_ci->ca.slot_reset = ciintf_slot_reset;
476 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
477 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300478 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700480 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300482 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 printk("budget_ci: CI interface detected, but initialisation failed.\n");
484 goto error;
485 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300486
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300488 if (budget_ci->ci_irq) {
489 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
490 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
491 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
492 } else {
493 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
494 }
495 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300497
498 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
500 CICONTROL_RESET, 1, 0);
501
502 // success!
503 printk("budget_ci: CI interface initialised\n");
504 budget_ci->budget.ci_present = 1;
505
506 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300507 if (budget_ci->ci_irq) {
508 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
509 if (budget_ci->slot_status != SLOTSTATUS_NONE)
510 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
511 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
512 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514 return 0;
515
516error:
517 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
518 return result;
519}
520
521static void ciintf_deinit(struct budget_ci *budget_ci)
522{
523 struct saa7146_dev *saa = budget_ci->budget.dev;
524
525 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300526 if (budget_ci->ci_irq) {
527 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
528 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
529 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
530 }
531
532 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
534 msleep(1);
535 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
536 CICONTROL_RESET, 1, 0);
537
538 // disable TS data stream to CI interface
539 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
540
541 // release the CA device
542 dvb_ca_en50221_release(&budget_ci->ca);
543
544 // disable DEBI pins
545 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
546}
547
548static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
549{
550 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
551
552 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
553
554 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200555 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556
557 if (*isr & MASK_10)
558 ttpci_budget_irq10_handler(dev, isr);
559
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300560 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
562}
563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564static u8 philips_su1278_tt_inittab[] = {
565 0x01, 0x0f,
566 0x02, 0x30,
567 0x03, 0x00,
568 0x04, 0x5b,
569 0x05, 0x85,
570 0x06, 0x02,
571 0x07, 0x00,
572 0x08, 0x02,
573 0x09, 0x00,
574 0x0C, 0x01,
575 0x0D, 0x81,
576 0x0E, 0x44,
577 0x0f, 0x14,
578 0x10, 0x3c,
579 0x11, 0x84,
580 0x12, 0xda,
581 0x13, 0x97,
582 0x14, 0x95,
583 0x15, 0xc9,
584 0x16, 0x19,
585 0x17, 0x8c,
586 0x18, 0x59,
587 0x19, 0xf8,
588 0x1a, 0xfe,
589 0x1c, 0x7f,
590 0x1d, 0x00,
591 0x1e, 0x00,
592 0x1f, 0x50,
593 0x20, 0x00,
594 0x21, 0x00,
595 0x22, 0x00,
596 0x23, 0x00,
597 0x28, 0x00,
598 0x29, 0x28,
599 0x2a, 0x14,
600 0x2b, 0x0f,
601 0x2c, 0x09,
602 0x2d, 0x09,
603 0x31, 0x1f,
604 0x32, 0x19,
605 0x33, 0xfc,
606 0x34, 0x93,
607 0xff, 0xff
608};
609
610static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
611{
612 stv0299_writereg(fe, 0x0e, 0x44);
613 if (srate >= 10000000) {
614 stv0299_writereg(fe, 0x13, 0x97);
615 stv0299_writereg(fe, 0x14, 0x95);
616 stv0299_writereg(fe, 0x15, 0xc9);
617 stv0299_writereg(fe, 0x17, 0x8c);
618 stv0299_writereg(fe, 0x1a, 0xfe);
619 stv0299_writereg(fe, 0x1c, 0x7f);
620 stv0299_writereg(fe, 0x2d, 0x09);
621 } else {
622 stv0299_writereg(fe, 0x13, 0x99);
623 stv0299_writereg(fe, 0x14, 0x8d);
624 stv0299_writereg(fe, 0x15, 0xce);
625 stv0299_writereg(fe, 0x17, 0x43);
626 stv0299_writereg(fe, 0x1a, 0x1d);
627 stv0299_writereg(fe, 0x1c, 0x12);
628 stv0299_writereg(fe, 0x2d, 0x05);
629 }
630 stv0299_writereg(fe, 0x0e, 0x23);
631 stv0299_writereg(fe, 0x0f, 0x94);
632 stv0299_writereg(fe, 0x10, 0x39);
633 stv0299_writereg(fe, 0x15, 0xc9);
634
635 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
636 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
637 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
638
639 return 0;
640}
641
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300642static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
643 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300645 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 u32 div;
647 u8 buf[4];
648 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
649
650 if ((params->frequency < 950000) || (params->frequency > 2150000))
651 return -EINVAL;
652
653 div = (params->frequency + (500 - 1)) / 500; // round correctly
654 buf[0] = (div >> 8) & 0x7f;
655 buf[1] = div & 0xff;
656 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
657 buf[3] = 0x20;
658
659 if (params->u.qpsk.symbol_rate < 4000000)
660 buf[3] |= 1;
661
662 if (params->frequency < 1250000)
663 buf[3] |= 0;
664 else if (params->frequency < 1550000)
665 buf[3] |= 0x40;
666 else if (params->frequency < 2050000)
667 buf[3] |= 0x80;
668 else if (params->frequency < 2150000)
669 buf[3] |= 0xC0;
670
Patrick Boettcherdea74862006-05-14 05:01:31 -0300671 if (fe->ops.i2c_gate_ctrl)
672 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300673 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 return -EIO;
675 return 0;
676}
677
678static struct stv0299_config philips_su1278_tt_config = {
679
680 .demod_address = 0x68,
681 .inittab = philips_su1278_tt_inittab,
682 .mclk = 64000000UL,
683 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 .skip_reinit = 1,
685 .lock_output = STV0229_LOCKOUTPUT_1,
686 .volt13_op0_op1 = STV0299_VOLT13_OP1,
687 .min_delay_ms = 50,
688 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689};
690
691
692
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300693static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
695 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
696 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
697 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700698 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699 sizeof(td1316_init) };
700
701 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300702 if (fe->ops.i2c_gate_ctrl)
703 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
705 return -EIO;
706 msleep(1);
707
708 // disable the mc44BC374c (do not check for errors)
709 tuner_msg.addr = 0x65;
710 tuner_msg.buf = disable_mc44BC374c;
711 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300712 if (fe->ops.i2c_gate_ctrl)
713 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300715 if (fe->ops.i2c_gate_ctrl)
716 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
718 }
719
720 return 0;
721}
722
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300723static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724{
725 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
726 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700727 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 -0700728 int tuner_frequency = 0;
729 u8 band, cp, filter;
730
731 // determine charge pump
732 tuner_frequency = params->frequency + 36130000;
733 if (tuner_frequency < 87000000)
734 return -EINVAL;
735 else if (tuner_frequency < 130000000)
736 cp = 3;
737 else if (tuner_frequency < 160000000)
738 cp = 5;
739 else if (tuner_frequency < 200000000)
740 cp = 6;
741 else if (tuner_frequency < 290000000)
742 cp = 3;
743 else if (tuner_frequency < 420000000)
744 cp = 5;
745 else if (tuner_frequency < 480000000)
746 cp = 6;
747 else if (tuner_frequency < 620000000)
748 cp = 3;
749 else if (tuner_frequency < 830000000)
750 cp = 5;
751 else if (tuner_frequency < 895000000)
752 cp = 7;
753 else
754 return -EINVAL;
755
756 // determine band
757 if (params->frequency < 49000000)
758 return -EINVAL;
759 else if (params->frequency < 159000000)
760 band = 1;
761 else if (params->frequency < 444000000)
762 band = 2;
763 else if (params->frequency < 861000000)
764 band = 4;
765 else
766 return -EINVAL;
767
768 // setup PLL filter and TDA9889
769 switch (params->u.ofdm.bandwidth) {
770 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300771 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 filter = 0;
773 break;
774
775 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300776 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 filter = 0;
778 break;
779
780 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300781 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 filter = 1;
783 break;
784
785 default:
786 return -EINVAL;
787 }
788
789 // calculate divisor
790 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
791 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
792
793 // setup tuner buffer
794 tuner_buf[0] = tuner_frequency >> 8;
795 tuner_buf[1] = tuner_frequency & 0xff;
796 tuner_buf[2] = 0xca;
797 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
798
Patrick Boettcherdea74862006-05-14 05:01:31 -0300799 if (fe->ops.i2c_gate_ctrl)
800 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
802 return -EIO;
803
804 msleep(1);
805 return 0;
806}
807
808static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
809 const struct firmware **fw, char *name)
810{
811 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
812
813 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
814}
815
816static struct tda1004x_config philips_tdm1316l_config = {
817
818 .demod_address = 0x8,
819 .invert = 0,
820 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700821 .xtal_freq = TDA10046_XTAL_4M,
822 .agc_config = TDA10046_AGC_DEFAULT,
823 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 .request_firmware = philips_tdm1316l_request_firmware,
825};
826
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300827static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700828{
829 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
830 u8 tuner_buf[5];
831 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
832 .flags = 0,
833 .buf = tuner_buf,
834 .len = sizeof(tuner_buf) };
835 int tuner_frequency = 0;
836 u8 band, cp, filter;
837
838 // determine charge pump
839 tuner_frequency = params->frequency + 36125000;
840 if (tuner_frequency < 87000000)
841 return -EINVAL;
842 else if (tuner_frequency < 130000000) {
843 cp = 3;
844 band = 1;
845 } else if (tuner_frequency < 160000000) {
846 cp = 5;
847 band = 1;
848 } else if (tuner_frequency < 200000000) {
849 cp = 6;
850 band = 1;
851 } else if (tuner_frequency < 290000000) {
852 cp = 3;
853 band = 2;
854 } else if (tuner_frequency < 420000000) {
855 cp = 5;
856 band = 2;
857 } else if (tuner_frequency < 480000000) {
858 cp = 6;
859 band = 2;
860 } else if (tuner_frequency < 620000000) {
861 cp = 3;
862 band = 4;
863 } else if (tuner_frequency < 830000000) {
864 cp = 5;
865 band = 4;
866 } else if (tuner_frequency < 895000000) {
867 cp = 7;
868 band = 4;
869 } else
870 return -EINVAL;
871
872 // assume PLL filter should always be 8MHz for the moment.
873 filter = 1;
874
875 // calculate divisor
876 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
877
878 // setup tuner buffer
879 tuner_buf[0] = tuner_frequency >> 8;
880 tuner_buf[1] = tuner_frequency & 0xff;
881 tuner_buf[2] = 0xc8;
882 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
883 tuner_buf[4] = 0x80;
884
Patrick Boettcherdea74862006-05-14 05:01:31 -0300885 if (fe->ops.i2c_gate_ctrl)
886 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700887 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
888 return -EIO;
889
890 msleep(50);
891
Patrick Boettcherdea74862006-05-14 05:01:31 -0300892 if (fe->ops.i2c_gate_ctrl)
893 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700894 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
895 return -EIO;
896
897 msleep(1);
898
899 return 0;
900}
901
902static u8 dvbc_philips_tdm1316l_inittab[] = {
903 0x80, 0x01,
904 0x80, 0x00,
905 0x81, 0x01,
906 0x81, 0x00,
907 0x00, 0x09,
908 0x01, 0x69,
909 0x03, 0x00,
910 0x04, 0x00,
911 0x07, 0x00,
912 0x08, 0x00,
913 0x20, 0x00,
914 0x21, 0x40,
915 0x22, 0x00,
916 0x23, 0x00,
917 0x24, 0x40,
918 0x25, 0x88,
919 0x30, 0xff,
920 0x31, 0x00,
921 0x32, 0xff,
922 0x33, 0x00,
923 0x34, 0x50,
924 0x35, 0x7f,
925 0x36, 0x00,
926 0x37, 0x20,
927 0x38, 0x00,
928 0x40, 0x1c,
929 0x41, 0xff,
930 0x42, 0x29,
931 0x43, 0x20,
932 0x44, 0xff,
933 0x45, 0x00,
934 0x46, 0x00,
935 0x49, 0x04,
936 0x4a, 0x00,
937 0x4b, 0x7b,
938 0x52, 0x30,
939 0x55, 0xae,
940 0x56, 0x47,
941 0x57, 0xe1,
942 0x58, 0x3a,
943 0x5a, 0x1e,
944 0x5b, 0x34,
945 0x60, 0x00,
946 0x63, 0x00,
947 0x64, 0x00,
948 0x65, 0x00,
949 0x66, 0x00,
950 0x67, 0x00,
951 0x68, 0x00,
952 0x69, 0x00,
953 0x6a, 0x02,
954 0x6b, 0x00,
955 0x70, 0xff,
956 0x71, 0x00,
957 0x72, 0x00,
958 0x73, 0x00,
959 0x74, 0x0c,
960 0x80, 0x00,
961 0x81, 0x00,
962 0x82, 0x00,
963 0x83, 0x00,
964 0x84, 0x04,
965 0x85, 0x80,
966 0x86, 0x24,
967 0x87, 0x78,
968 0x88, 0x10,
969 0x89, 0x00,
970 0x90, 0x01,
971 0x91, 0x01,
972 0xa0, 0x04,
973 0xa1, 0x00,
974 0xa2, 0x00,
975 0xb0, 0x91,
976 0xb1, 0x0b,
977 0xc0, 0x53,
978 0xc1, 0x70,
979 0xc2, 0x12,
980 0xd0, 0x00,
981 0xd1, 0x00,
982 0xd2, 0x00,
983 0xd3, 0x00,
984 0xd4, 0x00,
985 0xd5, 0x00,
986 0xde, 0x00,
987 0xdf, 0x00,
988 0x61, 0x38,
989 0x62, 0x0a,
990 0x53, 0x13,
991 0x59, 0x08,
992 0xff, 0xff,
993};
994
995static struct stv0297_config dvbc_philips_tdm1316l_config = {
996 .demod_address = 0x1c,
997 .inittab = dvbc_philips_tdm1316l_inittab,
998 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -0300999 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001000};
1001
1002
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
1004
1005static void frontend_init(struct budget_ci *budget_ci)
1006{
1007 switch (budget_ci->budget.dev->pci->subsystem_device) {
1008 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1009 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001010 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001012 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001013 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014 break;
1015 }
1016 break;
1017
1018 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1019 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001020 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001022 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 break;
1024 }
1025 break;
1026
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001027 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1028 budget_ci->tuner_pll_address = 0x61;
1029 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001030 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001031 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001032 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001033 break;
1034 }
1035 break;
1036
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001038 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001040 dvb_attach(tda10045_attach, &philips_tdm1316l_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.init = philips_tdm1316l_tuner_init;
1043 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 break;
1045 }
1046 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001047
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001048 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001049 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001050 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001051 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001052 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001053 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001054 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1055 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001056 break;
1057 }
1058 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001059
1060 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001061 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001062 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001063 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001064 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1065
Patrick Boettcherdea74862006-05-14 05:01:31 -03001066 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001067 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 -03001068 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001069 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001070 budget_ci->budget.dvb_frontend = NULL;
1071 }
1072 }
1073
1074 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 }
1076
1077 if (budget_ci->budget.dvb_frontend == NULL) {
1078 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1079 budget_ci->budget.dev->pci->vendor,
1080 budget_ci->budget.dev->pci->device,
1081 budget_ci->budget.dev->pci->subsystem_vendor,
1082 budget_ci->budget.dev->pci->subsystem_device);
1083 } else {
1084 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001085 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001087 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 budget_ci->budget.dvb_frontend = NULL;
1089 }
1090 }
1091}
1092
1093static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1094{
1095 struct budget_ci *budget_ci;
1096 int err;
1097
1098 if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
1099 return -ENOMEM;
1100
1101 dprintk(2, "budget_ci: %p\n", budget_ci);
1102
1103 budget_ci->budget.ci_present = 0;
1104
1105 dev->ext_priv = budget_ci;
1106
1107 if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
1108 kfree(budget_ci);
1109 return err;
1110 }
1111
David Hardemandd2f3982006-12-02 21:16:05 -02001112 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 (unsigned long) budget_ci);
1114
1115 msp430_ir_init(budget_ci);
1116
1117 ciintf_init(budget_ci);
1118
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001119 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 frontend_init(budget_ci);
1121
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001122 ttpci_budget_init_hooks(&budget_ci->budget);
1123
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 return 0;
1125}
1126
1127static int budget_ci_detach(struct saa7146_dev *dev)
1128{
1129 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1130 struct saa7146_dev *saa = budget_ci->budget.dev;
1131 int err;
1132
1133 if (budget_ci->budget.ci_present)
1134 ciintf_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001135 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001137 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001138 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 err = ttpci_budget_deinit(&budget_ci->budget);
1140
David Hardemandd2f3982006-12-02 21:16:05 -02001141 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
1143 msp430_ir_deinit(budget_ci);
1144
1145 // disable frontend and CI interface
1146 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1147
1148 kfree(budget_ci);
1149
1150 return err;
1151}
1152
1153static struct saa7146_extension budget_extension;
1154
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001155MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1157MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001158MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001159MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160
1161static struct pci_device_id pci_tbl[] = {
1162 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1163 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001164 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001166 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001167 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 {
1169 .vendor = 0,
1170 }
1171};
1172
1173MODULE_DEVICE_TABLE(pci, pci_tbl);
1174
1175static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001176 .name = "budget_ci dvb",
Oliver Endriss69459f3d2005-12-01 00:51:48 -08001177 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001178
1179 .module = THIS_MODULE,
1180 .pci_tbl = &pci_tbl[0],
1181 .attach = budget_ci_attach,
1182 .detach = budget_ci_detach,
1183
1184 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1185 .irq_func = budget_ci_irq,
1186};
1187
1188static int __init budget_ci_init(void)
1189{
1190 return saa7146_register_extension(&budget_extension);
1191}
1192
1193static void __exit budget_ci_exit(void)
1194{
1195 saa7146_unregister_extension(&budget_extension);
1196}
1197
1198module_init(budget_ci_init);
1199module_exit(budget_ci_exit);
1200
1201MODULE_LICENSE("GPL");
1202MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1203MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1204 "budget PCI DVB cards w/ CI-module produced by "
1205 "Siemens, Technotrend, Hauppauge");