blob: 20b5e8dc8739bc9cd7816c2b40b6c235bbe1b06b [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
49#define DEBIADDR_IR 0x1234
50#define DEBIADDR_CICONTROL 0x0000
51#define DEBIADDR_CIVERSION 0x4000
52#define DEBIADDR_IO 0x1000
53#define DEBIADDR_ATTR 0x3000
54
55#define CICONTROL_RESET 0x01
56#define CICONTROL_ENABLETS 0x02
57#define CICONTROL_CAMDETECT 0x08
58
59#define DEBICICTL 0x00420000
60#define DEBICICAM 0x02420000
61
62#define SLOTSTATUS_NONE 1
63#define SLOTSTATUS_PRESENT 2
64#define SLOTSTATUS_RESET 4
65#define SLOTSTATUS_READY 8
66#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
67
68struct budget_ci {
69 struct budget budget;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -050070 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 struct tasklet_struct msp430_irq_tasklet;
72 struct tasklet_struct ciintf_irq_tasklet;
73 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -030074 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 struct dvb_ca_en50221 ca;
76 char ir_dev_name[50];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -070077 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -070078};
79
80/* from reading the following remotes:
81 Zenith Universal 7 / TV Mode 807 / VCR Mode 837
82 Hauppauge (from NOVA-CI-s box product)
83 i've taken a "middle of the road" approach and note the differences
84*/
85static u16 key_map[64] = {
86 /* 0x0X */
87 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
88 KEY_9,
89 KEY_ENTER,
90 KEY_RED,
91 KEY_POWER, /* RADIO on Hauppauge */
92 KEY_MUTE,
93 0,
94 KEY_A, /* TV on Hauppauge */
95 /* 0x1X */
96 KEY_VOLUMEUP, KEY_VOLUMEDOWN,
97 0, 0,
98 KEY_B,
99 0, 0, 0, 0, 0, 0, 0,
100 KEY_UP, KEY_DOWN,
101 KEY_OPTION, /* RESERVED on Hauppauge */
102 KEY_BREAK,
103 /* 0x2X */
104 KEY_CHANNELUP, KEY_CHANNELDOWN,
105 KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
106 0, KEY_RESTART, KEY_OK,
107 KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
108 0,
109 KEY_ENTER, /* VCR mode on Zenith */
110 KEY_PAUSE,
111 0,
112 KEY_RIGHT, KEY_LEFT,
113 0,
114 KEY_MENU, /* FULL SCREEN on Hauppauge */
115 0,
116 /* 0x3X */
117 KEY_SLOW,
118 KEY_PREVIOUS, /* VCR mode on Zenith */
119 KEY_REWIND,
120 0,
121 KEY_FASTFORWARD,
122 KEY_PLAY, KEY_STOP,
123 KEY_RECORD,
124 KEY_TUNER, /* TV/VCR on Zenith */
125 0,
126 KEY_C,
127 0,
128 KEY_EXIT,
129 KEY_POWER2,
130 KEY_TUNER, /* VCR mode on Zenith */
131 0,
132};
133
134static void msp430_ir_debounce(unsigned long data)
135{
136 struct input_dev *dev = (struct input_dev *) data;
137
138 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
139 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
140 return;
141 }
142
143 dev->rep[0] = 0;
144 dev->timer.expires = jiffies + HZ * 350 / 1000;
145 add_timer(&dev->timer);
146 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
147}
148
149static void msp430_ir_interrupt(unsigned long data)
150{
151 struct budget_ci *budget_ci = (struct budget_ci *) data;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500152 struct input_dev *dev = budget_ci->input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 unsigned int code =
154 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
155
156 if (code & 0x40) {
157 code &= 0x3f;
158
159 if (timer_pending(&dev->timer)) {
160 if (code == dev->repeat_key) {
161 ++dev->rep[0];
162 return;
163 }
164 del_timer(&dev->timer);
165 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
166 }
167
168 if (!key_map[code]) {
169 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
170 return;
171 }
172
173 /* initialize debounce and repeat */
174 dev->repeat_key = code;
175 /* Zenith remote _always_ sends 2 sequences */
176 dev->rep[0] = ~0;
177 /* 350 milliseconds */
178 dev->timer.expires = jiffies + HZ * 350 / 1000;
179 /* MAKE */
180 input_event(dev, EV_KEY, key_map[code], !0);
181 add_timer(&dev->timer);
182 }
183}
184
185static int msp430_ir_init(struct budget_ci *budget_ci)
186{
187 struct saa7146_dev *saa = budget_ci->budget.dev;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500188 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 int i;
190
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500191 budget_ci->input_dev = input_dev = input_allocate_device();
192 if (!input_dev)
193 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
195 sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500197 input_dev->name = budget_ci->ir_dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500199 set_bit(EV_KEY, input_dev->evbit);
200 for (i = 0; i < ARRAY_SIZE(key_map); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 if (key_map[i])
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500202 set_bit(key_map[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500204 input_register_device(budget_ci->input_dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500206 input_dev->timer.function = msp430_ir_debounce;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
210
211 return 0;
212}
213
214static void msp430_ir_deinit(struct budget_ci *budget_ci)
215{
216 struct saa7146_dev *saa = budget_ci->budget.dev;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500217 struct input_dev *dev = budget_ci->input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
219 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
220 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
221
222 if (del_timer(&dev->timer))
223 input_event(dev, EV_KEY, key_map[dev->repeat_key], !!0);
224
225 input_unregister_device(dev);
226}
227
228static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
229{
230 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
231
232 if (slot != 0)
233 return -EINVAL;
234
235 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
236 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
237}
238
239static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
240{
241 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
242
243 if (slot != 0)
244 return -EINVAL;
245
246 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
247 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
248}
249
250static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
251{
252 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
253
254 if (slot != 0)
255 return -EINVAL;
256
257 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
258 DEBIADDR_IO | (address & 3), 1, 1, 0);
259}
260
261static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
262{
263 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
264
265 if (slot != 0)
266 return -EINVAL;
267
268 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
269 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
270}
271
272static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
273{
274 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
275 struct saa7146_dev *saa = budget_ci->budget.dev;
276
277 if (slot != 0)
278 return -EINVAL;
279
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300280 if (budget_ci->ci_irq) {
281 // trigger on RISING edge during reset so we know when READY is re-asserted
282 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
283 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284 budget_ci->slot_status = SLOTSTATUS_RESET;
285 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
286 msleep(1);
287 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
288 CICONTROL_RESET, 1, 0);
289
290 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
291 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
292 return 0;
293}
294
295static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
296{
297 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
298 struct saa7146_dev *saa = budget_ci->budget.dev;
299
300 if (slot != 0)
301 return -EINVAL;
302
303 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
304 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
305 return 0;
306}
307
308static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
309{
310 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
311 struct saa7146_dev *saa = budget_ci->budget.dev;
312 int tmp;
313
314 if (slot != 0)
315 return -EINVAL;
316
317 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
318
319 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
320 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
321 tmp | CICONTROL_ENABLETS, 1, 0);
322
323 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
324 return 0;
325}
326
327static void ciintf_interrupt(unsigned long data)
328{
329 struct budget_ci *budget_ci = (struct budget_ci *) data;
330 struct saa7146_dev *saa = budget_ci->budget.dev;
331 unsigned int flags;
332
333 // ensure we don't get spurious IRQs during initialisation
334 if (!budget_ci->budget.ci_present)
335 return;
336
337 // read the CAM status
338 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
339 if (flags & CICONTROL_CAMDETECT) {
340
341 // GPIO should be set to trigger on falling edge if a CAM is present
342 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
343
344 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
345 // CAM insertion IRQ
346 budget_ci->slot_status = SLOTSTATUS_PRESENT;
347 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
348 DVB_CA_EN50221_CAMCHANGE_INSERTED);
349
350 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
351 // CAM ready (reset completed)
352 budget_ci->slot_status = SLOTSTATUS_READY;
353 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
354
355 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
356 // FR/DA IRQ
357 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
358 }
359 } else {
360
361 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
362 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
363 // the CAM might not actually be ready yet.
364 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
365
366 // generate a CAM removal IRQ if we haven't already
367 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
368 // CAM removal IRQ
369 budget_ci->slot_status = SLOTSTATUS_NONE;
370 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
371 DVB_CA_EN50221_CAMCHANGE_REMOVED);
372 }
373 }
374}
375
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300376static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
377{
378 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
379 unsigned int flags;
380
381 // ensure we don't get spurious IRQs during initialisation
382 if (!budget_ci->budget.ci_present)
383 return -EINVAL;
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 // mark it as present if it wasn't before
389 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
390 budget_ci->slot_status = SLOTSTATUS_PRESENT;
391 }
392
393 // during a RESET, we check if we can read from IO memory to see when CAM is ready
394 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
395 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
396 budget_ci->slot_status = SLOTSTATUS_READY;
397 }
398 }
399 } else {
400 budget_ci->slot_status = SLOTSTATUS_NONE;
401 }
402
403 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
404 if (budget_ci->slot_status & SLOTSTATUS_READY) {
405 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
406 }
407 return DVB_CA_EN50221_POLL_CAM_PRESENT;
408 }
409
410 return 0;
411}
412
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413static int ciintf_init(struct budget_ci *budget_ci)
414{
415 struct saa7146_dev *saa = budget_ci->budget.dev;
416 int flags;
417 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300418 int ci_version;
419 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420
421 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
422
423 // enable DEBI pins
424 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
425
426 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300427 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
428 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 result = -ENODEV;
430 goto error;
431 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300432
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 // determine whether a CAM is present or not
434 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
435 budget_ci->slot_status = SLOTSTATUS_NONE;
436 if (flags & CICONTROL_CAMDETECT)
437 budget_ci->slot_status = SLOTSTATUS_PRESENT;
438
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300439 // version 0xa2 of the CI firmware doesn't generate interrupts
440 if (ci_version == 0xa2) {
441 ca_flags = 0;
442 budget_ci->ci_irq = 0;
443 } else {
444 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
445 DVB_CA_EN50221_FLAG_IRQ_FR |
446 DVB_CA_EN50221_FLAG_IRQ_DA;
447 budget_ci->ci_irq = 1;
448 }
449
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 // register CI interface
451 budget_ci->ca.owner = THIS_MODULE;
452 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
453 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
454 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
455 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
456 budget_ci->ca.slot_reset = ciintf_slot_reset;
457 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
458 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300459 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700461 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300463 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 printk("budget_ci: CI interface detected, but initialisation failed.\n");
465 goto error;
466 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300467
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300469 if (budget_ci->ci_irq) {
470 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
471 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
472 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
473 } else {
474 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
475 }
476 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300478
479 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
481 CICONTROL_RESET, 1, 0);
482
483 // success!
484 printk("budget_ci: CI interface initialised\n");
485 budget_ci->budget.ci_present = 1;
486
487 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300488 if (budget_ci->ci_irq) {
489 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
490 if (budget_ci->slot_status != SLOTSTATUS_NONE)
491 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
492 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495 return 0;
496
497error:
498 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
499 return result;
500}
501
502static void ciintf_deinit(struct budget_ci *budget_ci)
503{
504 struct saa7146_dev *saa = budget_ci->budget.dev;
505
506 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300507 if (budget_ci->ci_irq) {
508 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
509 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
510 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
511 }
512
513 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700514 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
515 msleep(1);
516 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
517 CICONTROL_RESET, 1, 0);
518
519 // disable TS data stream to CI interface
520 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
521
522 // release the CA device
523 dvb_ca_en50221_release(&budget_ci->ca);
524
525 // disable DEBI pins
526 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
527}
528
529static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
530{
531 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
532
533 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
534
535 if (*isr & MASK_06)
536 tasklet_schedule(&budget_ci->msp430_irq_tasklet);
537
538 if (*isr & MASK_10)
539 ttpci_budget_irq10_handler(dev, isr);
540
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300541 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
543}
544
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545static u8 philips_su1278_tt_inittab[] = {
546 0x01, 0x0f,
547 0x02, 0x30,
548 0x03, 0x00,
549 0x04, 0x5b,
550 0x05, 0x85,
551 0x06, 0x02,
552 0x07, 0x00,
553 0x08, 0x02,
554 0x09, 0x00,
555 0x0C, 0x01,
556 0x0D, 0x81,
557 0x0E, 0x44,
558 0x0f, 0x14,
559 0x10, 0x3c,
560 0x11, 0x84,
561 0x12, 0xda,
562 0x13, 0x97,
563 0x14, 0x95,
564 0x15, 0xc9,
565 0x16, 0x19,
566 0x17, 0x8c,
567 0x18, 0x59,
568 0x19, 0xf8,
569 0x1a, 0xfe,
570 0x1c, 0x7f,
571 0x1d, 0x00,
572 0x1e, 0x00,
573 0x1f, 0x50,
574 0x20, 0x00,
575 0x21, 0x00,
576 0x22, 0x00,
577 0x23, 0x00,
578 0x28, 0x00,
579 0x29, 0x28,
580 0x2a, 0x14,
581 0x2b, 0x0f,
582 0x2c, 0x09,
583 0x2d, 0x09,
584 0x31, 0x1f,
585 0x32, 0x19,
586 0x33, 0xfc,
587 0x34, 0x93,
588 0xff, 0xff
589};
590
591static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
592{
593 stv0299_writereg(fe, 0x0e, 0x44);
594 if (srate >= 10000000) {
595 stv0299_writereg(fe, 0x13, 0x97);
596 stv0299_writereg(fe, 0x14, 0x95);
597 stv0299_writereg(fe, 0x15, 0xc9);
598 stv0299_writereg(fe, 0x17, 0x8c);
599 stv0299_writereg(fe, 0x1a, 0xfe);
600 stv0299_writereg(fe, 0x1c, 0x7f);
601 stv0299_writereg(fe, 0x2d, 0x09);
602 } else {
603 stv0299_writereg(fe, 0x13, 0x99);
604 stv0299_writereg(fe, 0x14, 0x8d);
605 stv0299_writereg(fe, 0x15, 0xce);
606 stv0299_writereg(fe, 0x17, 0x43);
607 stv0299_writereg(fe, 0x1a, 0x1d);
608 stv0299_writereg(fe, 0x1c, 0x12);
609 stv0299_writereg(fe, 0x2d, 0x05);
610 }
611 stv0299_writereg(fe, 0x0e, 0x23);
612 stv0299_writereg(fe, 0x0f, 0x94);
613 stv0299_writereg(fe, 0x10, 0x39);
614 stv0299_writereg(fe, 0x15, 0xc9);
615
616 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
617 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
618 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
619
620 return 0;
621}
622
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300623static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
624 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700625{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300626 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627 u32 div;
628 u8 buf[4];
629 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
630
631 if ((params->frequency < 950000) || (params->frequency > 2150000))
632 return -EINVAL;
633
634 div = (params->frequency + (500 - 1)) / 500; // round correctly
635 buf[0] = (div >> 8) & 0x7f;
636 buf[1] = div & 0xff;
637 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
638 buf[3] = 0x20;
639
640 if (params->u.qpsk.symbol_rate < 4000000)
641 buf[3] |= 1;
642
643 if (params->frequency < 1250000)
644 buf[3] |= 0;
645 else if (params->frequency < 1550000)
646 buf[3] |= 0x40;
647 else if (params->frequency < 2050000)
648 buf[3] |= 0x80;
649 else if (params->frequency < 2150000)
650 buf[3] |= 0xC0;
651
Patrick Boettcherdea74862006-05-14 05:01:31 -0300652 if (fe->ops.i2c_gate_ctrl)
653 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300654 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 return -EIO;
656 return 0;
657}
658
659static struct stv0299_config philips_su1278_tt_config = {
660
661 .demod_address = 0x68,
662 .inittab = philips_su1278_tt_inittab,
663 .mclk = 64000000UL,
664 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 .skip_reinit = 1,
666 .lock_output = STV0229_LOCKOUTPUT_1,
667 .volt13_op0_op1 = STV0299_VOLT13_OP1,
668 .min_delay_ms = 50,
669 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670};
671
672
673
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300674static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
677 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
678 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700679 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 sizeof(td1316_init) };
681
682 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300683 if (fe->ops.i2c_gate_ctrl)
684 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
686 return -EIO;
687 msleep(1);
688
689 // disable the mc44BC374c (do not check for errors)
690 tuner_msg.addr = 0x65;
691 tuner_msg.buf = disable_mc44BC374c;
692 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300693 if (fe->ops.i2c_gate_ctrl)
694 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300696 if (fe->ops.i2c_gate_ctrl)
697 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
699 }
700
701 return 0;
702}
703
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300704static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705{
706 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
707 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700708 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 -0700709 int tuner_frequency = 0;
710 u8 band, cp, filter;
711
712 // determine charge pump
713 tuner_frequency = params->frequency + 36130000;
714 if (tuner_frequency < 87000000)
715 return -EINVAL;
716 else if (tuner_frequency < 130000000)
717 cp = 3;
718 else if (tuner_frequency < 160000000)
719 cp = 5;
720 else if (tuner_frequency < 200000000)
721 cp = 6;
722 else if (tuner_frequency < 290000000)
723 cp = 3;
724 else if (tuner_frequency < 420000000)
725 cp = 5;
726 else if (tuner_frequency < 480000000)
727 cp = 6;
728 else if (tuner_frequency < 620000000)
729 cp = 3;
730 else if (tuner_frequency < 830000000)
731 cp = 5;
732 else if (tuner_frequency < 895000000)
733 cp = 7;
734 else
735 return -EINVAL;
736
737 // determine band
738 if (params->frequency < 49000000)
739 return -EINVAL;
740 else if (params->frequency < 159000000)
741 band = 1;
742 else if (params->frequency < 444000000)
743 band = 2;
744 else if (params->frequency < 861000000)
745 band = 4;
746 else
747 return -EINVAL;
748
749 // setup PLL filter and TDA9889
750 switch (params->u.ofdm.bandwidth) {
751 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300752 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 filter = 0;
754 break;
755
756 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300757 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 filter = 0;
759 break;
760
761 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300762 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 filter = 1;
764 break;
765
766 default:
767 return -EINVAL;
768 }
769
770 // calculate divisor
771 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
772 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
773
774 // setup tuner buffer
775 tuner_buf[0] = tuner_frequency >> 8;
776 tuner_buf[1] = tuner_frequency & 0xff;
777 tuner_buf[2] = 0xca;
778 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
779
Patrick Boettcherdea74862006-05-14 05:01:31 -0300780 if (fe->ops.i2c_gate_ctrl)
781 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
783 return -EIO;
784
785 msleep(1);
786 return 0;
787}
788
789static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
790 const struct firmware **fw, char *name)
791{
792 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
793
794 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
795}
796
797static struct tda1004x_config philips_tdm1316l_config = {
798
799 .demod_address = 0x8,
800 .invert = 0,
801 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700802 .xtal_freq = TDA10046_XTAL_4M,
803 .agc_config = TDA10046_AGC_DEFAULT,
804 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 .request_firmware = philips_tdm1316l_request_firmware,
806};
807
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300808static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700809{
810 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
811 u8 tuner_buf[5];
812 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
813 .flags = 0,
814 .buf = tuner_buf,
815 .len = sizeof(tuner_buf) };
816 int tuner_frequency = 0;
817 u8 band, cp, filter;
818
819 // determine charge pump
820 tuner_frequency = params->frequency + 36125000;
821 if (tuner_frequency < 87000000)
822 return -EINVAL;
823 else if (tuner_frequency < 130000000) {
824 cp = 3;
825 band = 1;
826 } else if (tuner_frequency < 160000000) {
827 cp = 5;
828 band = 1;
829 } else if (tuner_frequency < 200000000) {
830 cp = 6;
831 band = 1;
832 } else if (tuner_frequency < 290000000) {
833 cp = 3;
834 band = 2;
835 } else if (tuner_frequency < 420000000) {
836 cp = 5;
837 band = 2;
838 } else if (tuner_frequency < 480000000) {
839 cp = 6;
840 band = 2;
841 } else if (tuner_frequency < 620000000) {
842 cp = 3;
843 band = 4;
844 } else if (tuner_frequency < 830000000) {
845 cp = 5;
846 band = 4;
847 } else if (tuner_frequency < 895000000) {
848 cp = 7;
849 band = 4;
850 } else
851 return -EINVAL;
852
853 // assume PLL filter should always be 8MHz for the moment.
854 filter = 1;
855
856 // calculate divisor
857 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
858
859 // setup tuner buffer
860 tuner_buf[0] = tuner_frequency >> 8;
861 tuner_buf[1] = tuner_frequency & 0xff;
862 tuner_buf[2] = 0xc8;
863 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
864 tuner_buf[4] = 0x80;
865
Patrick Boettcherdea74862006-05-14 05:01:31 -0300866 if (fe->ops.i2c_gate_ctrl)
867 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700868 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
869 return -EIO;
870
871 msleep(50);
872
Patrick Boettcherdea74862006-05-14 05:01:31 -0300873 if (fe->ops.i2c_gate_ctrl)
874 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700875 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
876 return -EIO;
877
878 msleep(1);
879
880 return 0;
881}
882
883static u8 dvbc_philips_tdm1316l_inittab[] = {
884 0x80, 0x01,
885 0x80, 0x00,
886 0x81, 0x01,
887 0x81, 0x00,
888 0x00, 0x09,
889 0x01, 0x69,
890 0x03, 0x00,
891 0x04, 0x00,
892 0x07, 0x00,
893 0x08, 0x00,
894 0x20, 0x00,
895 0x21, 0x40,
896 0x22, 0x00,
897 0x23, 0x00,
898 0x24, 0x40,
899 0x25, 0x88,
900 0x30, 0xff,
901 0x31, 0x00,
902 0x32, 0xff,
903 0x33, 0x00,
904 0x34, 0x50,
905 0x35, 0x7f,
906 0x36, 0x00,
907 0x37, 0x20,
908 0x38, 0x00,
909 0x40, 0x1c,
910 0x41, 0xff,
911 0x42, 0x29,
912 0x43, 0x20,
913 0x44, 0xff,
914 0x45, 0x00,
915 0x46, 0x00,
916 0x49, 0x04,
917 0x4a, 0x00,
918 0x4b, 0x7b,
919 0x52, 0x30,
920 0x55, 0xae,
921 0x56, 0x47,
922 0x57, 0xe1,
923 0x58, 0x3a,
924 0x5a, 0x1e,
925 0x5b, 0x34,
926 0x60, 0x00,
927 0x63, 0x00,
928 0x64, 0x00,
929 0x65, 0x00,
930 0x66, 0x00,
931 0x67, 0x00,
932 0x68, 0x00,
933 0x69, 0x00,
934 0x6a, 0x02,
935 0x6b, 0x00,
936 0x70, 0xff,
937 0x71, 0x00,
938 0x72, 0x00,
939 0x73, 0x00,
940 0x74, 0x0c,
941 0x80, 0x00,
942 0x81, 0x00,
943 0x82, 0x00,
944 0x83, 0x00,
945 0x84, 0x04,
946 0x85, 0x80,
947 0x86, 0x24,
948 0x87, 0x78,
949 0x88, 0x10,
950 0x89, 0x00,
951 0x90, 0x01,
952 0x91, 0x01,
953 0xa0, 0x04,
954 0xa1, 0x00,
955 0xa2, 0x00,
956 0xb0, 0x91,
957 0xb1, 0x0b,
958 0xc0, 0x53,
959 0xc1, 0x70,
960 0xc2, 0x12,
961 0xd0, 0x00,
962 0xd1, 0x00,
963 0xd2, 0x00,
964 0xd3, 0x00,
965 0xd4, 0x00,
966 0xd5, 0x00,
967 0xde, 0x00,
968 0xdf, 0x00,
969 0x61, 0x38,
970 0x62, 0x0a,
971 0x53, 0x13,
972 0x59, 0x08,
973 0xff, 0xff,
974};
975
976static struct stv0297_config dvbc_philips_tdm1316l_config = {
977 .demod_address = 0x1c,
978 .inittab = dvbc_philips_tdm1316l_inittab,
979 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -0300980 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700981};
982
983
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
985
986static void frontend_init(struct budget_ci *budget_ci)
987{
988 switch (budget_ci->budget.dev->pci->subsystem_device) {
989 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
990 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300991 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300993 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300994 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 break;
996 }
997 break;
998
999 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1000 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001001 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001003 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004 break;
1005 }
1006 break;
1007
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001008 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1009 budget_ci->tuner_pll_address = 0x61;
1010 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001011 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001012 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001013 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001014 break;
1015 }
1016 break;
1017
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001019 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001021 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001023 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1024 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025 break;
1026 }
1027 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001028
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001029 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001030 budget_ci->tuner_pll_address = 0x60;
1031 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001032 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001033 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001034 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1035 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001036 break;
1037 }
1038 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001039
1040 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001041 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001042 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001043 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001044 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1045
Patrick Boettcherdea74862006-05-14 05:01:31 -03001046 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001047 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 -03001048 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Patrick Boettcherdea74862006-05-14 05:01:31 -03001049 if (budget_ci->budget.dvb_frontend->ops.release)
1050 budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001051 budget_ci->budget.dvb_frontend = NULL;
1052 }
1053 }
1054
1055 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 }
1057
1058 if (budget_ci->budget.dvb_frontend == NULL) {
1059 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1060 budget_ci->budget.dev->pci->vendor,
1061 budget_ci->budget.dev->pci->device,
1062 budget_ci->budget.dev->pci->subsystem_vendor,
1063 budget_ci->budget.dev->pci->subsystem_device);
1064 } else {
1065 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001066 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001068 dvb_detach(budget_ci->budget.dvb_frontend->ops.release_sec, budget_ci->budget.dvb_frontend);
1069 dvb_detach(budget_ci->budget.dvb_frontend->ops.tuner_ops.release, budget_ci->budget.dvb_frontend);
1070 dvb_detach(budget_ci->budget.dvb_frontend->ops.release, budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 budget_ci->budget.dvb_frontend = NULL;
1072 }
1073 }
1074}
1075
1076static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1077{
1078 struct budget_ci *budget_ci;
1079 int err;
1080
1081 if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
1082 return -ENOMEM;
1083
1084 dprintk(2, "budget_ci: %p\n", budget_ci);
1085
1086 budget_ci->budget.ci_present = 0;
1087
1088 dev->ext_priv = budget_ci;
1089
1090 if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
1091 kfree(budget_ci);
1092 return err;
1093 }
1094
1095 tasklet_init(&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
1096 (unsigned long) budget_ci);
1097
1098 msp430_ir_init(budget_ci);
1099
1100 ciintf_init(budget_ci);
1101
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001102 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 frontend_init(budget_ci);
1104
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001105 ttpci_budget_init_hooks(&budget_ci->budget);
1106
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 return 0;
1108}
1109
1110static int budget_ci_detach(struct saa7146_dev *dev)
1111{
1112 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1113 struct saa7146_dev *saa = budget_ci->budget.dev;
1114 int err;
1115
1116 if (budget_ci->budget.ci_present)
1117 ciintf_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001118 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001120 dvb_detach(budget_ci->budget.dvb_frontend->ops.release_sec, budget_ci->budget.dvb_frontend);
1121 dvb_detach(budget_ci->budget.dvb_frontend->ops.tuner_ops.release, budget_ci->budget.dvb_frontend);
1122 dvb_detach(budget_ci->budget.dvb_frontend->ops.release, budget_ci->budget.dvb_frontend);
1123 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 err = ttpci_budget_deinit(&budget_ci->budget);
1125
1126 tasklet_kill(&budget_ci->msp430_irq_tasklet);
1127
1128 msp430_ir_deinit(budget_ci);
1129
1130 // disable frontend and CI interface
1131 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1132
1133 kfree(budget_ci);
1134
1135 return err;
1136}
1137
1138static struct saa7146_extension budget_extension;
1139
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001140MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1142MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001143MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001144MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
1146static struct pci_device_id pci_tbl[] = {
1147 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1148 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001149 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001151 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001152 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 {
1154 .vendor = 0,
1155 }
1156};
1157
1158MODULE_DEVICE_TABLE(pci, pci_tbl);
1159
1160static struct saa7146_extension budget_extension = {
1161 .name = "budget_ci dvb\0",
Oliver Endriss69459f32005-12-01 00:51:48 -08001162 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163
1164 .module = THIS_MODULE,
1165 .pci_tbl = &pci_tbl[0],
1166 .attach = budget_ci_attach,
1167 .detach = budget_ci_detach,
1168
1169 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1170 .irq_func = budget_ci_irq,
1171};
1172
1173static int __init budget_ci_init(void)
1174{
1175 return saa7146_register_extension(&budget_extension);
1176}
1177
1178static void __exit budget_ci_exit(void)
1179{
1180 saa7146_unregister_extension(&budget_extension);
1181}
1182
1183module_init(budget_ci_init);
1184module_exit(budget_ci_exit);
1185
1186MODULE_LICENSE("GPL");
1187MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1188MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1189 "budget PCI DVB cards w/ CI-module produced by "
1190 "Siemens, Technotrend, Hauppauge");