blob: 25d0dfc1f58538c2faa666ffc5c94867c0d5f33a [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
75struct budget_ci {
76 struct budget budget;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -050077 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 struct tasklet_struct msp430_irq_tasklet;
79 struct tasklet_struct ciintf_irq_tasklet;
80 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -030081 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 struct dvb_ca_en50221 ca;
83 char ir_dev_name[50];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -070084 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -070085};
86
87/* from reading the following remotes:
88 Zenith Universal 7 / TV Mode 807 / VCR Mode 837
89 Hauppauge (from NOVA-CI-s box product)
90 i've taken a "middle of the road" approach and note the differences
91*/
92static u16 key_map[64] = {
93 /* 0x0X */
94 KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8,
95 KEY_9,
96 KEY_ENTER,
97 KEY_RED,
98 KEY_POWER, /* RADIO on Hauppauge */
99 KEY_MUTE,
100 0,
101 KEY_A, /* TV on Hauppauge */
102 /* 0x1X */
103 KEY_VOLUMEUP, KEY_VOLUMEDOWN,
104 0, 0,
105 KEY_B,
106 0, 0, 0, 0, 0, 0, 0,
107 KEY_UP, KEY_DOWN,
108 KEY_OPTION, /* RESERVED on Hauppauge */
109 KEY_BREAK,
110 /* 0x2X */
111 KEY_CHANNELUP, KEY_CHANNELDOWN,
112 KEY_PREVIOUS, /* Prev. Ch on Zenith, SOURCE on Hauppauge */
113 0, KEY_RESTART, KEY_OK,
114 KEY_CYCLEWINDOWS, /* MINIMIZE on Hauppauge */
115 0,
116 KEY_ENTER, /* VCR mode on Zenith */
117 KEY_PAUSE,
118 0,
119 KEY_RIGHT, KEY_LEFT,
120 0,
121 KEY_MENU, /* FULL SCREEN on Hauppauge */
122 0,
123 /* 0x3X */
124 KEY_SLOW,
125 KEY_PREVIOUS, /* VCR mode on Zenith */
126 KEY_REWIND,
127 0,
128 KEY_FASTFORWARD,
129 KEY_PLAY, KEY_STOP,
130 KEY_RECORD,
131 KEY_TUNER, /* TV/VCR on Zenith */
132 0,
133 KEY_C,
134 0,
135 KEY_EXIT,
136 KEY_POWER2,
137 KEY_TUNER, /* VCR mode on Zenith */
138 0,
139};
140
141static void msp430_ir_debounce(unsigned long data)
142{
143 struct input_dev *dev = (struct input_dev *) data;
144
145 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300146 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
147 } else {
148 dev->rep[0] = 0;
149 dev->timer.expires = jiffies + HZ * 350 / 1000;
150 add_timer(&dev->timer);
151 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 }
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300153 input_sync(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154}
155
156static void msp430_ir_interrupt(unsigned long data)
157{
158 struct budget_ci *budget_ci = (struct budget_ci *) data;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500159 struct input_dev *dev = budget_ci->input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 unsigned int code =
161 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
162
163 if (code & 0x40) {
164 code &= 0x3f;
165
166 if (timer_pending(&dev->timer)) {
167 if (code == dev->repeat_key) {
168 ++dev->rep[0];
169 return;
170 }
171 del_timer(&dev->timer);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300172 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 }
174
175 if (!key_map[code]) {
176 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
177 return;
178 }
179
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300180 input_event(dev, EV_KEY, key_map[code], 1);
181 input_sync(dev);
182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 /* initialize debounce and repeat */
184 dev->repeat_key = code;
185 /* Zenith remote _always_ sends 2 sequences */
186 dev->rep[0] = ~0;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300187 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(350));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 }
189}
190
191static int msp430_ir_init(struct budget_ci *budget_ci)
192{
193 struct saa7146_dev *saa = budget_ci->budget.dev;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500194 struct input_dev *input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 int i;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300196 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300198 input_dev = input_allocate_device();
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500199 if (!input_dev)
200 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 sprintf(budget_ci->ir_dev_name, "Budget-CI dvb ir receiver %s", saa->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500204 input_dev->name = budget_ci->ir_dev_name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500206 set_bit(EV_KEY, input_dev->evbit);
207 for (i = 0; i < ARRAY_SIZE(key_map); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 if (key_map[i])
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500209 set_bit(key_map[i], input_dev->keybit);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300211 err = input_register_device(input_dev);
212 if (err) {
213 input_free_device(input_dev);
214 return err;
215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500217 input_dev->timer.function = msp430_ir_debounce;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300219 budget_ci->input_dev = input_dev;
220
Linus Torvalds1da177e2005-04-16 15:20:36 -0700221 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
223
224 return 0;
225}
226
227static void msp430_ir_deinit(struct budget_ci *budget_ci)
228{
229 struct saa7146_dev *saa = budget_ci->budget.dev;
Dmitry Torokhovb7df3912005-09-15 02:01:53 -0500230 struct input_dev *dev = budget_ci->input_dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231
232 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
233 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
234
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300235 if (del_timer(&dev->timer)) {
236 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
237 input_sync(dev);
238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240 input_unregister_device(dev);
241}
242
243static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
244{
245 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
246
247 if (slot != 0)
248 return -EINVAL;
249
250 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
251 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
252}
253
254static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
255{
256 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
257
258 if (slot != 0)
259 return -EINVAL;
260
261 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
262 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
263}
264
265static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
266{
267 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
268
269 if (slot != 0)
270 return -EINVAL;
271
272 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
273 DEBIADDR_IO | (address & 3), 1, 1, 0);
274}
275
276static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
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_debiwrite(&budget_ci->budget, DEBICICAM,
284 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
285}
286
287static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
288{
289 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
290 struct saa7146_dev *saa = budget_ci->budget.dev;
291
292 if (slot != 0)
293 return -EINVAL;
294
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300295 if (budget_ci->ci_irq) {
296 // trigger on RISING edge during reset so we know when READY is re-asserted
297 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 budget_ci->slot_status = SLOTSTATUS_RESET;
300 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
301 msleep(1);
302 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
303 CICONTROL_RESET, 1, 0);
304
305 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
306 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
307 return 0;
308}
309
310static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
311{
312 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
313 struct saa7146_dev *saa = budget_ci->budget.dev;
314
315 if (slot != 0)
316 return -EINVAL;
317
318 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
319 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
320 return 0;
321}
322
323static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
324{
325 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
326 struct saa7146_dev *saa = budget_ci->budget.dev;
327 int tmp;
328
329 if (slot != 0)
330 return -EINVAL;
331
332 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
333
334 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
335 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
336 tmp | CICONTROL_ENABLETS, 1, 0);
337
338 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
339 return 0;
340}
341
342static void ciintf_interrupt(unsigned long data)
343{
344 struct budget_ci *budget_ci = (struct budget_ci *) data;
345 struct saa7146_dev *saa = budget_ci->budget.dev;
346 unsigned int flags;
347
348 // ensure we don't get spurious IRQs during initialisation
349 if (!budget_ci->budget.ci_present)
350 return;
351
352 // read the CAM status
353 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
354 if (flags & CICONTROL_CAMDETECT) {
355
356 // GPIO should be set to trigger on falling edge if a CAM is present
357 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
358
359 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
360 // CAM insertion IRQ
361 budget_ci->slot_status = SLOTSTATUS_PRESENT;
362 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
363 DVB_CA_EN50221_CAMCHANGE_INSERTED);
364
365 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
366 // CAM ready (reset completed)
367 budget_ci->slot_status = SLOTSTATUS_READY;
368 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
369
370 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
371 // FR/DA IRQ
372 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
373 }
374 } else {
375
376 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
377 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
378 // the CAM might not actually be ready yet.
379 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
380
381 // generate a CAM removal IRQ if we haven't already
382 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
383 // CAM removal IRQ
384 budget_ci->slot_status = SLOTSTATUS_NONE;
385 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
386 DVB_CA_EN50221_CAMCHANGE_REMOVED);
387 }
388 }
389}
390
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300391static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
392{
393 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
394 unsigned int flags;
395
396 // ensure we don't get spurious IRQs during initialisation
397 if (!budget_ci->budget.ci_present)
398 return -EINVAL;
399
400 // read the CAM status
401 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
402 if (flags & CICONTROL_CAMDETECT) {
403 // mark it as present if it wasn't before
404 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
405 budget_ci->slot_status = SLOTSTATUS_PRESENT;
406 }
407
408 // during a RESET, we check if we can read from IO memory to see when CAM is ready
409 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
410 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
411 budget_ci->slot_status = SLOTSTATUS_READY;
412 }
413 }
414 } else {
415 budget_ci->slot_status = SLOTSTATUS_NONE;
416 }
417
418 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
419 if (budget_ci->slot_status & SLOTSTATUS_READY) {
420 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
421 }
422 return DVB_CA_EN50221_POLL_CAM_PRESENT;
423 }
424
425 return 0;
426}
427
Linus Torvalds1da177e2005-04-16 15:20:36 -0700428static int ciintf_init(struct budget_ci *budget_ci)
429{
430 struct saa7146_dev *saa = budget_ci->budget.dev;
431 int flags;
432 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300433 int ci_version;
434 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435
436 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
437
438 // enable DEBI pins
439 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
440
441 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300442 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
443 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 result = -ENODEV;
445 goto error;
446 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300447
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 // determine whether a CAM is present or not
449 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
450 budget_ci->slot_status = SLOTSTATUS_NONE;
451 if (flags & CICONTROL_CAMDETECT)
452 budget_ci->slot_status = SLOTSTATUS_PRESENT;
453
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300454 // version 0xa2 of the CI firmware doesn't generate interrupts
455 if (ci_version == 0xa2) {
456 ca_flags = 0;
457 budget_ci->ci_irq = 0;
458 } else {
459 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
460 DVB_CA_EN50221_FLAG_IRQ_FR |
461 DVB_CA_EN50221_FLAG_IRQ_DA;
462 budget_ci->ci_irq = 1;
463 }
464
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465 // register CI interface
466 budget_ci->ca.owner = THIS_MODULE;
467 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
468 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
469 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
470 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
471 budget_ci->ca.slot_reset = ciintf_slot_reset;
472 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
473 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300474 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700475 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700476 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300478 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479 printk("budget_ci: CI interface detected, but initialisation failed.\n");
480 goto error;
481 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300484 if (budget_ci->ci_irq) {
485 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
486 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
487 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
488 } else {
489 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
490 }
491 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300493
494 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
496 CICONTROL_RESET, 1, 0);
497
498 // success!
499 printk("budget_ci: CI interface initialised\n");
500 budget_ci->budget.ci_present = 1;
501
502 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300503 if (budget_ci->ci_irq) {
504 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
505 if (budget_ci->slot_status != SLOTSTATUS_NONE)
506 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
507 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
508 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 return 0;
511
512error:
513 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
514 return result;
515}
516
517static void ciintf_deinit(struct budget_ci *budget_ci)
518{
519 struct saa7146_dev *saa = budget_ci->budget.dev;
520
521 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300522 if (budget_ci->ci_irq) {
523 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
524 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
525 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
526 }
527
528 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
530 msleep(1);
531 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
532 CICONTROL_RESET, 1, 0);
533
534 // disable TS data stream to CI interface
535 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
536
537 // release the CA device
538 dvb_ca_en50221_release(&budget_ci->ca);
539
540 // disable DEBI pins
541 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
542}
543
544static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
545{
546 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
547
548 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
549
550 if (*isr & MASK_06)
551 tasklet_schedule(&budget_ci->msp430_irq_tasklet);
552
553 if (*isr & MASK_10)
554 ttpci_budget_irq10_handler(dev, isr);
555
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300556 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
558}
559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560static u8 philips_su1278_tt_inittab[] = {
561 0x01, 0x0f,
562 0x02, 0x30,
563 0x03, 0x00,
564 0x04, 0x5b,
565 0x05, 0x85,
566 0x06, 0x02,
567 0x07, 0x00,
568 0x08, 0x02,
569 0x09, 0x00,
570 0x0C, 0x01,
571 0x0D, 0x81,
572 0x0E, 0x44,
573 0x0f, 0x14,
574 0x10, 0x3c,
575 0x11, 0x84,
576 0x12, 0xda,
577 0x13, 0x97,
578 0x14, 0x95,
579 0x15, 0xc9,
580 0x16, 0x19,
581 0x17, 0x8c,
582 0x18, 0x59,
583 0x19, 0xf8,
584 0x1a, 0xfe,
585 0x1c, 0x7f,
586 0x1d, 0x00,
587 0x1e, 0x00,
588 0x1f, 0x50,
589 0x20, 0x00,
590 0x21, 0x00,
591 0x22, 0x00,
592 0x23, 0x00,
593 0x28, 0x00,
594 0x29, 0x28,
595 0x2a, 0x14,
596 0x2b, 0x0f,
597 0x2c, 0x09,
598 0x2d, 0x09,
599 0x31, 0x1f,
600 0x32, 0x19,
601 0x33, 0xfc,
602 0x34, 0x93,
603 0xff, 0xff
604};
605
606static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
607{
608 stv0299_writereg(fe, 0x0e, 0x44);
609 if (srate >= 10000000) {
610 stv0299_writereg(fe, 0x13, 0x97);
611 stv0299_writereg(fe, 0x14, 0x95);
612 stv0299_writereg(fe, 0x15, 0xc9);
613 stv0299_writereg(fe, 0x17, 0x8c);
614 stv0299_writereg(fe, 0x1a, 0xfe);
615 stv0299_writereg(fe, 0x1c, 0x7f);
616 stv0299_writereg(fe, 0x2d, 0x09);
617 } else {
618 stv0299_writereg(fe, 0x13, 0x99);
619 stv0299_writereg(fe, 0x14, 0x8d);
620 stv0299_writereg(fe, 0x15, 0xce);
621 stv0299_writereg(fe, 0x17, 0x43);
622 stv0299_writereg(fe, 0x1a, 0x1d);
623 stv0299_writereg(fe, 0x1c, 0x12);
624 stv0299_writereg(fe, 0x2d, 0x05);
625 }
626 stv0299_writereg(fe, 0x0e, 0x23);
627 stv0299_writereg(fe, 0x0f, 0x94);
628 stv0299_writereg(fe, 0x10, 0x39);
629 stv0299_writereg(fe, 0x15, 0xc9);
630
631 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
632 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
633 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
634
635 return 0;
636}
637
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300638static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
639 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300641 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642 u32 div;
643 u8 buf[4];
644 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
645
646 if ((params->frequency < 950000) || (params->frequency > 2150000))
647 return -EINVAL;
648
649 div = (params->frequency + (500 - 1)) / 500; // round correctly
650 buf[0] = (div >> 8) & 0x7f;
651 buf[1] = div & 0xff;
652 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
653 buf[3] = 0x20;
654
655 if (params->u.qpsk.symbol_rate < 4000000)
656 buf[3] |= 1;
657
658 if (params->frequency < 1250000)
659 buf[3] |= 0;
660 else if (params->frequency < 1550000)
661 buf[3] |= 0x40;
662 else if (params->frequency < 2050000)
663 buf[3] |= 0x80;
664 else if (params->frequency < 2150000)
665 buf[3] |= 0xC0;
666
Patrick Boettcherdea74862006-05-14 05:01:31 -0300667 if (fe->ops.i2c_gate_ctrl)
668 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300669 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 return -EIO;
671 return 0;
672}
673
674static struct stv0299_config philips_su1278_tt_config = {
675
676 .demod_address = 0x68,
677 .inittab = philips_su1278_tt_inittab,
678 .mclk = 64000000UL,
679 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 .skip_reinit = 1,
681 .lock_output = STV0229_LOCKOUTPUT_1,
682 .volt13_op0_op1 = STV0299_VOLT13_OP1,
683 .min_delay_ms = 50,
684 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685};
686
687
688
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300689static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
691 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
692 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
693 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700694 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 sizeof(td1316_init) };
696
697 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300698 if (fe->ops.i2c_gate_ctrl)
699 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
701 return -EIO;
702 msleep(1);
703
704 // disable the mc44BC374c (do not check for errors)
705 tuner_msg.addr = 0x65;
706 tuner_msg.buf = disable_mc44BC374c;
707 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300708 if (fe->ops.i2c_gate_ctrl)
709 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300711 if (fe->ops.i2c_gate_ctrl)
712 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
714 }
715
716 return 0;
717}
718
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300719static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720{
721 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
722 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700723 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 -0700724 int tuner_frequency = 0;
725 u8 band, cp, filter;
726
727 // determine charge pump
728 tuner_frequency = params->frequency + 36130000;
729 if (tuner_frequency < 87000000)
730 return -EINVAL;
731 else if (tuner_frequency < 130000000)
732 cp = 3;
733 else if (tuner_frequency < 160000000)
734 cp = 5;
735 else if (tuner_frequency < 200000000)
736 cp = 6;
737 else if (tuner_frequency < 290000000)
738 cp = 3;
739 else if (tuner_frequency < 420000000)
740 cp = 5;
741 else if (tuner_frequency < 480000000)
742 cp = 6;
743 else if (tuner_frequency < 620000000)
744 cp = 3;
745 else if (tuner_frequency < 830000000)
746 cp = 5;
747 else if (tuner_frequency < 895000000)
748 cp = 7;
749 else
750 return -EINVAL;
751
752 // determine band
753 if (params->frequency < 49000000)
754 return -EINVAL;
755 else if (params->frequency < 159000000)
756 band = 1;
757 else if (params->frequency < 444000000)
758 band = 2;
759 else if (params->frequency < 861000000)
760 band = 4;
761 else
762 return -EINVAL;
763
764 // setup PLL filter and TDA9889
765 switch (params->u.ofdm.bandwidth) {
766 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300767 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 filter = 0;
769 break;
770
771 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300772 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 filter = 0;
774 break;
775
776 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300777 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 filter = 1;
779 break;
780
781 default:
782 return -EINVAL;
783 }
784
785 // calculate divisor
786 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
787 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
788
789 // setup tuner buffer
790 tuner_buf[0] = tuner_frequency >> 8;
791 tuner_buf[1] = tuner_frequency & 0xff;
792 tuner_buf[2] = 0xca;
793 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
794
Patrick Boettcherdea74862006-05-14 05:01:31 -0300795 if (fe->ops.i2c_gate_ctrl)
796 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
798 return -EIO;
799
800 msleep(1);
801 return 0;
802}
803
804static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
805 const struct firmware **fw, char *name)
806{
807 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
808
809 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
810}
811
812static struct tda1004x_config philips_tdm1316l_config = {
813
814 .demod_address = 0x8,
815 .invert = 0,
816 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700817 .xtal_freq = TDA10046_XTAL_4M,
818 .agc_config = TDA10046_AGC_DEFAULT,
819 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 .request_firmware = philips_tdm1316l_request_firmware,
821};
822
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300823static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700824{
825 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
826 u8 tuner_buf[5];
827 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
828 .flags = 0,
829 .buf = tuner_buf,
830 .len = sizeof(tuner_buf) };
831 int tuner_frequency = 0;
832 u8 band, cp, filter;
833
834 // determine charge pump
835 tuner_frequency = params->frequency + 36125000;
836 if (tuner_frequency < 87000000)
837 return -EINVAL;
838 else if (tuner_frequency < 130000000) {
839 cp = 3;
840 band = 1;
841 } else if (tuner_frequency < 160000000) {
842 cp = 5;
843 band = 1;
844 } else if (tuner_frequency < 200000000) {
845 cp = 6;
846 band = 1;
847 } else if (tuner_frequency < 290000000) {
848 cp = 3;
849 band = 2;
850 } else if (tuner_frequency < 420000000) {
851 cp = 5;
852 band = 2;
853 } else if (tuner_frequency < 480000000) {
854 cp = 6;
855 band = 2;
856 } else if (tuner_frequency < 620000000) {
857 cp = 3;
858 band = 4;
859 } else if (tuner_frequency < 830000000) {
860 cp = 5;
861 band = 4;
862 } else if (tuner_frequency < 895000000) {
863 cp = 7;
864 band = 4;
865 } else
866 return -EINVAL;
867
868 // assume PLL filter should always be 8MHz for the moment.
869 filter = 1;
870
871 // calculate divisor
872 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
873
874 // setup tuner buffer
875 tuner_buf[0] = tuner_frequency >> 8;
876 tuner_buf[1] = tuner_frequency & 0xff;
877 tuner_buf[2] = 0xc8;
878 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
879 tuner_buf[4] = 0x80;
880
Patrick Boettcherdea74862006-05-14 05:01:31 -0300881 if (fe->ops.i2c_gate_ctrl)
882 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700883 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
884 return -EIO;
885
886 msleep(50);
887
Patrick Boettcherdea74862006-05-14 05:01:31 -0300888 if (fe->ops.i2c_gate_ctrl)
889 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700890 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
891 return -EIO;
892
893 msleep(1);
894
895 return 0;
896}
897
898static u8 dvbc_philips_tdm1316l_inittab[] = {
899 0x80, 0x01,
900 0x80, 0x00,
901 0x81, 0x01,
902 0x81, 0x00,
903 0x00, 0x09,
904 0x01, 0x69,
905 0x03, 0x00,
906 0x04, 0x00,
907 0x07, 0x00,
908 0x08, 0x00,
909 0x20, 0x00,
910 0x21, 0x40,
911 0x22, 0x00,
912 0x23, 0x00,
913 0x24, 0x40,
914 0x25, 0x88,
915 0x30, 0xff,
916 0x31, 0x00,
917 0x32, 0xff,
918 0x33, 0x00,
919 0x34, 0x50,
920 0x35, 0x7f,
921 0x36, 0x00,
922 0x37, 0x20,
923 0x38, 0x00,
924 0x40, 0x1c,
925 0x41, 0xff,
926 0x42, 0x29,
927 0x43, 0x20,
928 0x44, 0xff,
929 0x45, 0x00,
930 0x46, 0x00,
931 0x49, 0x04,
932 0x4a, 0x00,
933 0x4b, 0x7b,
934 0x52, 0x30,
935 0x55, 0xae,
936 0x56, 0x47,
937 0x57, 0xe1,
938 0x58, 0x3a,
939 0x5a, 0x1e,
940 0x5b, 0x34,
941 0x60, 0x00,
942 0x63, 0x00,
943 0x64, 0x00,
944 0x65, 0x00,
945 0x66, 0x00,
946 0x67, 0x00,
947 0x68, 0x00,
948 0x69, 0x00,
949 0x6a, 0x02,
950 0x6b, 0x00,
951 0x70, 0xff,
952 0x71, 0x00,
953 0x72, 0x00,
954 0x73, 0x00,
955 0x74, 0x0c,
956 0x80, 0x00,
957 0x81, 0x00,
958 0x82, 0x00,
959 0x83, 0x00,
960 0x84, 0x04,
961 0x85, 0x80,
962 0x86, 0x24,
963 0x87, 0x78,
964 0x88, 0x10,
965 0x89, 0x00,
966 0x90, 0x01,
967 0x91, 0x01,
968 0xa0, 0x04,
969 0xa1, 0x00,
970 0xa2, 0x00,
971 0xb0, 0x91,
972 0xb1, 0x0b,
973 0xc0, 0x53,
974 0xc1, 0x70,
975 0xc2, 0x12,
976 0xd0, 0x00,
977 0xd1, 0x00,
978 0xd2, 0x00,
979 0xd3, 0x00,
980 0xd4, 0x00,
981 0xd5, 0x00,
982 0xde, 0x00,
983 0xdf, 0x00,
984 0x61, 0x38,
985 0x62, 0x0a,
986 0x53, 0x13,
987 0x59, 0x08,
988 0xff, 0xff,
989};
990
991static struct stv0297_config dvbc_philips_tdm1316l_config = {
992 .demod_address = 0x1c,
993 .inittab = dvbc_philips_tdm1316l_inittab,
994 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -0300995 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700996};
997
998
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999
1000
1001static void frontend_init(struct budget_ci *budget_ci)
1002{
1003 switch (budget_ci->budget.dev->pci->subsystem_device) {
1004 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1005 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001006 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001008 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001009 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 break;
1011 }
1012 break;
1013
1014 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1015 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001016 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001018 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 break;
1020 }
1021 break;
1022
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001023 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1024 budget_ci->tuner_pll_address = 0x61;
1025 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001026 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001027 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001028 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001029 break;
1030 }
1031 break;
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001034 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001036 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001038 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1039 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040 break;
1041 }
1042 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001043
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001044 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001045 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001046 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001047 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001048 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001049 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001050 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1051 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001052 break;
1053 }
1054 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001055
1056 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001057 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001058 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001059 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001060 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1061
Patrick Boettcherdea74862006-05-14 05:01:31 -03001062 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001063 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 -03001064 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001065 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001066 budget_ci->budget.dvb_frontend = NULL;
1067 }
1068 }
1069
1070 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 }
1072
1073 if (budget_ci->budget.dvb_frontend == NULL) {
1074 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1075 budget_ci->budget.dev->pci->vendor,
1076 budget_ci->budget.dev->pci->device,
1077 budget_ci->budget.dev->pci->subsystem_vendor,
1078 budget_ci->budget.dev->pci->subsystem_device);
1079 } else {
1080 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001081 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001083 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 budget_ci->budget.dvb_frontend = NULL;
1085 }
1086 }
1087}
1088
1089static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1090{
1091 struct budget_ci *budget_ci;
1092 int err;
1093
1094 if (!(budget_ci = kmalloc(sizeof(struct budget_ci), GFP_KERNEL)))
1095 return -ENOMEM;
1096
1097 dprintk(2, "budget_ci: %p\n", budget_ci);
1098
1099 budget_ci->budget.ci_present = 0;
1100
1101 dev->ext_priv = budget_ci;
1102
1103 if ((err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE))) {
1104 kfree(budget_ci);
1105 return err;
1106 }
1107
1108 tasklet_init(&budget_ci->msp430_irq_tasklet, msp430_ir_interrupt,
1109 (unsigned long) budget_ci);
1110
1111 msp430_ir_init(budget_ci);
1112
1113 ciintf_init(budget_ci);
1114
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001115 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 frontend_init(budget_ci);
1117
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001118 ttpci_budget_init_hooks(&budget_ci->budget);
1119
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 return 0;
1121}
1122
1123static int budget_ci_detach(struct saa7146_dev *dev)
1124{
1125 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1126 struct saa7146_dev *saa = budget_ci->budget.dev;
1127 int err;
1128
1129 if (budget_ci->budget.ci_present)
1130 ciintf_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001131 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001133 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 err = ttpci_budget_deinit(&budget_ci->budget);
1136
1137 tasklet_kill(&budget_ci->msp430_irq_tasklet);
1138
1139 msp430_ir_deinit(budget_ci);
1140
1141 // disable frontend and CI interface
1142 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1143
1144 kfree(budget_ci);
1145
1146 return err;
1147}
1148
1149static struct saa7146_extension budget_extension;
1150
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001151MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1153MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001154MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001155MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
1157static struct pci_device_id pci_tbl[] = {
1158 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1159 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001160 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001162 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001163 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 {
1165 .vendor = 0,
1166 }
1167};
1168
1169MODULE_DEVICE_TABLE(pci, pci_tbl);
1170
1171static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001172 .name = "budget_ci dvb",
Oliver Endriss69459f3d2005-12-01 00:51:48 -08001173 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174
1175 .module = THIS_MODULE,
1176 .pci_tbl = &pci_tbl[0],
1177 .attach = budget_ci_attach,
1178 .detach = budget_ci_detach,
1179
1180 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1181 .irq_func = budget_ci_irq,
1182};
1183
1184static int __init budget_ci_init(void)
1185{
1186 return saa7146_register_extension(&budget_extension);
1187}
1188
1189static void __exit budget_ci_exit(void)
1190{
1191 saa7146_unregister_extension(&budget_extension);
1192}
1193
1194module_init(budget_ci_init);
1195module_exit(budget_ci_exit);
1196
1197MODULE_LICENSE("GPL");
1198MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1199MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1200 "budget PCI DVB cards w/ CI-module produced by "
1201 "Siemens, Technotrend, Hauppauge");