blob: 76d3b6694bce56f3d9989289289aca64fa12099a [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>
David Hardeman2520fff2006-12-02 21:16:05 -020040#include <media/ir-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#include "dvb_ca_en50221.h"
43#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070044#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "tda1004x.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030046#include "lnbp21.h"
47#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030048#include "bsru6.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
David Härdemanecba77f2006-10-27 20:56:51 -030050/*
51 * Regarding DEBIADDR_IR:
52 * Some CI modules hang if random addresses are read.
53 * Using address 0x4000 for the IR read means that we
54 * use the same address as for CI version, which should
55 * be a safe default.
56 */
57#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#define DEBIADDR_CICONTROL 0x0000
59#define DEBIADDR_CIVERSION 0x4000
60#define DEBIADDR_IO 0x1000
61#define DEBIADDR_ATTR 0x3000
62
63#define CICONTROL_RESET 0x01
64#define CICONTROL_ENABLETS 0x02
65#define CICONTROL_CAMDETECT 0x08
66
67#define DEBICICTL 0x00420000
68#define DEBICICAM 0x02420000
69
70#define SLOTSTATUS_NONE 1
71#define SLOTSTATUS_PRESENT 2
72#define SLOTSTATUS_RESET 4
73#define SLOTSTATUS_READY 8
74#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
75
David Hardeman2520fff2006-12-02 21:16:05 -020076/* Milliseconds during which key presses are regarded as key repeat and during
77 * which the debounce logic is active
78 */
79#define IR_REPEAT_TIMEOUT 350
80
David Hardeman64741b72006-12-02 21:16:05 -020081/* RC5 device wildcard */
82#define IR_DEVICE_ANY 255
83
David Hardeman2520fff2006-12-02 21:16:05 -020084/* Some remotes sends multiple sequences per keypress (e.g. Zenith sends two),
85 * this setting allows the superflous sequences to be ignored
86 */
87static int debounce = 0;
88module_param(debounce, int, 0644);
89MODULE_PARM_DESC(debounce, "ignore repeated IR sequences (default: 0 = ignore no sequences)");
90
David Hardeman64741b72006-12-02 21:16:05 -020091static int rc5_device = -1;
92module_param(rc5_device, int, 0644);
93MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
94
David Hardemandd2f3982006-12-02 21:16:05 -020095struct budget_ci_ir {
96 struct input_dev *dev;
97 struct tasklet_struct msp430_irq_tasklet;
98 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -020099 char phys[32];
David Hardeman2520fff2006-12-02 21:16:05 -0200100 struct ir_input_state state;
David Hardeman64741b72006-12-02 21:16:05 -0200101 int rc5_device;
David Hardemandd2f3982006-12-02 21:16:05 -0200102};
103
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104struct budget_ci {
105 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 struct tasklet_struct ciintf_irq_tasklet;
107 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300108 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -0200110 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700111 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112};
113
David Hardeman2520fff2006-12-02 21:16:05 -0200114static void msp430_ir_keyup(unsigned long data)
115{
116 struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
117 ir_input_nokey(ir->dev, &ir->state);
118}
119
120static void msp430_ir_interrupt(unsigned long data)
121{
122 struct budget_ci *budget_ci = (struct budget_ci *) data;
123 struct input_dev *dev = budget_ci->ir.dev;
124 static int bounces = 0;
David Hardeman64741b72006-12-02 21:16:05 -0200125 int device;
126 int toggle;
127 static int prev_toggle = -1;
128 static u32 ir_key;
David Hardeman2520fff2006-12-02 21:16:05 -0200129 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
130
David Hardeman64741b72006-12-02 21:16:05 -0200131 /*
132 * The msp430 chip can generate two different bytes, command and device
133 *
134 * type1: X1CCCCCC, C = command bits (0 - 63)
135 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
136 *
137 * More than one command byte may be generated before the device byte
138 * Only when we have both, a correct keypress is generated
139 */
140
141 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200142 if (command & 0x40) {
143 ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200144 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200145 }
David Hardeman64741b72006-12-02 21:16:05 -0200146
147 /* It's a RC5 device byte */
148 device = command & 0x1f;
149 toggle = command & 0x20;
150
151 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device)
152 return;
153
154 /* Are we still waiting for a keyup event while this is a new key? */
155 if ((ir_key != dev->repeat_key || toggle != prev_toggle) && del_timer(&dev->timer))
156 ir_input_nokey(dev, &budget_ci->ir.state);
157
158 prev_toggle = toggle;
159
160 /* Ignore repeated key sequences if requested */
161 if (ir_key == dev->repeat_key && bounces > 0 && timer_pending(&dev->timer)) {
162 bounces--;
163 return;
164 }
165
166 /* New keypress? */
167 if (!timer_pending(&dev->timer))
168 bounces = debounce;
169
170 /* Prepare a keyup event sometime in the future */
171 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT));
172
173 /* Generate a new or repeated keypress */
174 ir_input_keydown(dev, &budget_ci->ir.state, ir_key, ((device << 8) | command));
David Hardeman2520fff2006-12-02 21:16:05 -0200175}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
177static void msp430_ir_debounce(unsigned long data)
178{
179 struct input_dev *dev = (struct input_dev *) data;
180
181 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300182 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
183 } else {
184 dev->rep[0] = 0;
185 dev->timer.expires = jiffies + HZ * 350 / 1000;
186 add_timer(&dev->timer);
187 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 }
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300189 input_sync(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190}
191
192static void msp430_ir_interrupt(unsigned long data)
193{
194 struct budget_ci *budget_ci = (struct budget_ci *) data;
David Hardemandd2f3982006-12-02 21:16:05 -0200195 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 unsigned int code =
197 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
198
199 if (code & 0x40) {
200 code &= 0x3f;
201
202 if (timer_pending(&dev->timer)) {
203 if (code == dev->repeat_key) {
204 ++dev->rep[0];
205 return;
206 }
207 del_timer(&dev->timer);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300208 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 }
210
211 if (!key_map[code]) {
212 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
213 return;
214 }
215
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300216 input_event(dev, EV_KEY, key_map[code], 1);
217 input_sync(dev);
218
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 /* initialize debounce and repeat */
220 dev->repeat_key = code;
221 /* Zenith remote _always_ sends 2 sequences */
222 dev->rep[0] = ~0;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300223 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(350));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 }
225}
226
227static int msp430_ir_init(struct budget_ci *budget_ci)
228{
229 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200230 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200231 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
David Hardemandd2f3982006-12-02 21:16:05 -0200233 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200234 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200235 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200236 error = -ENOMEM;
237 goto out1;
238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
David Hardemandd2f3982006-12-02 21:16:05 -0200240 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
241 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200242 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
243 "pci-%s/ir0", pci_name(saa->pci));
244
David Hardemandd2f3982006-12-02 21:16:05 -0200245 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
David Hardeman5cc8ae02006-12-02 21:16:05 -0200247 input_dev->phys = budget_ci->ir.phys;
248 input_dev->id.bustype = BUS_PCI;
249 input_dev->id.version = 1;
250 if (saa->pci->subsystem_vendor) {
251 input_dev->id.vendor = saa->pci->subsystem_vendor;
252 input_dev->id.product = saa->pci->subsystem_device;
253 } else {
254 input_dev->id.vendor = saa->pci->vendor;
255 input_dev->id.product = saa->pci->device;
256 }
257# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
258 input_dev->cdev.dev = &saa->pci->dev;
259# else
260 input_dev->dev = &saa->pci->dev;
261# endif
262
David Hardeman64741b72006-12-02 21:16:05 -0200263 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200264 switch (budget_ci->budget.dev->pci->subsystem_device) {
265 case 0x100c:
266 case 0x100f:
267 case 0x1010:
268 case 0x1011:
269 case 0x1012:
270 case 0x1017:
271 /* The hauppauge keymap is a superset of these remotes */
272 ir_input_init(input_dev, &budget_ci->ir.state,
273 IR_TYPE_RC5, ir_codes_hauppauge_new);
David Hardeman64741b72006-12-02 21:16:05 -0200274
275 if (rc5_device < 0)
276 budget_ci->ir.rc5_device = 0x1f;
277 else
278 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200279 break;
280 default:
281 /* unknown remote */
282 ir_input_init(input_dev, &budget_ci->ir.state,
283 IR_TYPE_RC5, ir_codes_budget_ci_old);
David Hardeman64741b72006-12-02 21:16:05 -0200284
285 if (rc5_device < 0)
286 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
287 else
288 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200289 break;
290 }
291
292 /* initialise the key-up timeout handler */
293 input_dev->timer.function = msp430_ir_keyup;
294 input_dev->timer.data = (unsigned long) &budget_ci->ir;
295 input_dev->rep[REP_DELAY] = 1;
296 input_dev->rep[REP_PERIOD] = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
David Hardeman8cc532e2006-12-02 21:16:05 -0200298 error = input_register_device(input_dev);
299 if (error) {
300 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
301 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
David Hardeman8cc532e2006-12-02 21:16:05 -0200304 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
305 (unsigned long) budget_ci);
306
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
309
310 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200311
312out2:
313 input_free_device(input_dev);
314out1:
315 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316}
317
318static void msp430_ir_deinit(struct budget_ci *budget_ci)
319{
320 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200321 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322
323 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
324 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200325 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300327 if (del_timer(&dev->timer)) {
David Hardeman2520fff2006-12-02 21:16:05 -0200328 ir_input_nokey(dev, &budget_ci->ir.state);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300329 input_sync(dev);
330 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331
332 input_unregister_device(dev);
333}
334
335static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
336{
337 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
338
339 if (slot != 0)
340 return -EINVAL;
341
342 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
343 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
344}
345
346static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
347{
348 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
349
350 if (slot != 0)
351 return -EINVAL;
352
353 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
354 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
355}
356
357static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
358{
359 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
360
361 if (slot != 0)
362 return -EINVAL;
363
364 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
365 DEBIADDR_IO | (address & 3), 1, 1, 0);
366}
367
368static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
369{
370 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
371
372 if (slot != 0)
373 return -EINVAL;
374
375 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
376 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
377}
378
379static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
380{
381 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
382 struct saa7146_dev *saa = budget_ci->budget.dev;
383
384 if (slot != 0)
385 return -EINVAL;
386
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300387 if (budget_ci->ci_irq) {
388 // trigger on RISING edge during reset so we know when READY is re-asserted
389 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
390 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 budget_ci->slot_status = SLOTSTATUS_RESET;
392 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
393 msleep(1);
394 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
395 CICONTROL_RESET, 1, 0);
396
397 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
398 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
399 return 0;
400}
401
402static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
403{
404 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
405 struct saa7146_dev *saa = budget_ci->budget.dev;
406
407 if (slot != 0)
408 return -EINVAL;
409
410 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
411 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
412 return 0;
413}
414
415static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
416{
417 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
418 struct saa7146_dev *saa = budget_ci->budget.dev;
419 int tmp;
420
421 if (slot != 0)
422 return -EINVAL;
423
424 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
425
426 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
427 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
428 tmp | CICONTROL_ENABLETS, 1, 0);
429
430 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
431 return 0;
432}
433
434static void ciintf_interrupt(unsigned long data)
435{
436 struct budget_ci *budget_ci = (struct budget_ci *) data;
437 struct saa7146_dev *saa = budget_ci->budget.dev;
438 unsigned int flags;
439
440 // ensure we don't get spurious IRQs during initialisation
441 if (!budget_ci->budget.ci_present)
442 return;
443
444 // read the CAM status
445 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
446 if (flags & CICONTROL_CAMDETECT) {
447
448 // GPIO should be set to trigger on falling edge if a CAM is present
449 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
450
451 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
452 // CAM insertion IRQ
453 budget_ci->slot_status = SLOTSTATUS_PRESENT;
454 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
455 DVB_CA_EN50221_CAMCHANGE_INSERTED);
456
457 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
458 // CAM ready (reset completed)
459 budget_ci->slot_status = SLOTSTATUS_READY;
460 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
461
462 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
463 // FR/DA IRQ
464 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
465 }
466 } else {
467
468 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
469 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
470 // the CAM might not actually be ready yet.
471 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
472
473 // generate a CAM removal IRQ if we haven't already
474 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
475 // CAM removal IRQ
476 budget_ci->slot_status = SLOTSTATUS_NONE;
477 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
478 DVB_CA_EN50221_CAMCHANGE_REMOVED);
479 }
480 }
481}
482
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300483static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
484{
485 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
486 unsigned int flags;
487
488 // ensure we don't get spurious IRQs during initialisation
489 if (!budget_ci->budget.ci_present)
490 return -EINVAL;
491
492 // read the CAM status
493 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
494 if (flags & CICONTROL_CAMDETECT) {
495 // mark it as present if it wasn't before
496 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
497 budget_ci->slot_status = SLOTSTATUS_PRESENT;
498 }
499
500 // during a RESET, we check if we can read from IO memory to see when CAM is ready
501 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
502 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
503 budget_ci->slot_status = SLOTSTATUS_READY;
504 }
505 }
506 } else {
507 budget_ci->slot_status = SLOTSTATUS_NONE;
508 }
509
510 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
511 if (budget_ci->slot_status & SLOTSTATUS_READY) {
512 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
513 }
514 return DVB_CA_EN50221_POLL_CAM_PRESENT;
515 }
516
517 return 0;
518}
519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520static int ciintf_init(struct budget_ci *budget_ci)
521{
522 struct saa7146_dev *saa = budget_ci->budget.dev;
523 int flags;
524 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300525 int ci_version;
526 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
528 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
529
530 // enable DEBI pins
531 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
532
533 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300534 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
535 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 result = -ENODEV;
537 goto error;
538 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300539
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 // determine whether a CAM is present or not
541 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
542 budget_ci->slot_status = SLOTSTATUS_NONE;
543 if (flags & CICONTROL_CAMDETECT)
544 budget_ci->slot_status = SLOTSTATUS_PRESENT;
545
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300546 // version 0xa2 of the CI firmware doesn't generate interrupts
547 if (ci_version == 0xa2) {
548 ca_flags = 0;
549 budget_ci->ci_irq = 0;
550 } else {
551 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
552 DVB_CA_EN50221_FLAG_IRQ_FR |
553 DVB_CA_EN50221_FLAG_IRQ_DA;
554 budget_ci->ci_irq = 1;
555 }
556
Linus Torvalds1da177e2005-04-16 15:20:36 -0700557 // register CI interface
558 budget_ci->ca.owner = THIS_MODULE;
559 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
560 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
561 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
562 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
563 budget_ci->ca.slot_reset = ciintf_slot_reset;
564 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
565 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300566 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700568 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300570 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 printk("budget_ci: CI interface detected, but initialisation failed.\n");
572 goto error;
573 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300576 if (budget_ci->ci_irq) {
577 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
578 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
579 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
580 } else {
581 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
582 }
583 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300585
586 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
588 CICONTROL_RESET, 1, 0);
589
590 // success!
591 printk("budget_ci: CI interface initialised\n");
592 budget_ci->budget.ci_present = 1;
593
594 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300595 if (budget_ci->ci_irq) {
596 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
597 if (budget_ci->slot_status != SLOTSTATUS_NONE)
598 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
599 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
600 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
602 return 0;
603
604error:
605 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
606 return result;
607}
608
609static void ciintf_deinit(struct budget_ci *budget_ci)
610{
611 struct saa7146_dev *saa = budget_ci->budget.dev;
612
613 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300614 if (budget_ci->ci_irq) {
615 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
616 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
617 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
618 }
619
620 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
622 msleep(1);
623 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
624 CICONTROL_RESET, 1, 0);
625
626 // disable TS data stream to CI interface
627 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
628
629 // release the CA device
630 dvb_ca_en50221_release(&budget_ci->ca);
631
632 // disable DEBI pins
633 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
634}
635
636static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
637{
638 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
639
640 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
641
642 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200643 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
645 if (*isr & MASK_10)
646 ttpci_budget_irq10_handler(dev, isr);
647
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300648 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
650}
651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652static u8 philips_su1278_tt_inittab[] = {
653 0x01, 0x0f,
654 0x02, 0x30,
655 0x03, 0x00,
656 0x04, 0x5b,
657 0x05, 0x85,
658 0x06, 0x02,
659 0x07, 0x00,
660 0x08, 0x02,
661 0x09, 0x00,
662 0x0C, 0x01,
663 0x0D, 0x81,
664 0x0E, 0x44,
665 0x0f, 0x14,
666 0x10, 0x3c,
667 0x11, 0x84,
668 0x12, 0xda,
669 0x13, 0x97,
670 0x14, 0x95,
671 0x15, 0xc9,
672 0x16, 0x19,
673 0x17, 0x8c,
674 0x18, 0x59,
675 0x19, 0xf8,
676 0x1a, 0xfe,
677 0x1c, 0x7f,
678 0x1d, 0x00,
679 0x1e, 0x00,
680 0x1f, 0x50,
681 0x20, 0x00,
682 0x21, 0x00,
683 0x22, 0x00,
684 0x23, 0x00,
685 0x28, 0x00,
686 0x29, 0x28,
687 0x2a, 0x14,
688 0x2b, 0x0f,
689 0x2c, 0x09,
690 0x2d, 0x09,
691 0x31, 0x1f,
692 0x32, 0x19,
693 0x33, 0xfc,
694 0x34, 0x93,
695 0xff, 0xff
696};
697
698static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
699{
700 stv0299_writereg(fe, 0x0e, 0x44);
701 if (srate >= 10000000) {
702 stv0299_writereg(fe, 0x13, 0x97);
703 stv0299_writereg(fe, 0x14, 0x95);
704 stv0299_writereg(fe, 0x15, 0xc9);
705 stv0299_writereg(fe, 0x17, 0x8c);
706 stv0299_writereg(fe, 0x1a, 0xfe);
707 stv0299_writereg(fe, 0x1c, 0x7f);
708 stv0299_writereg(fe, 0x2d, 0x09);
709 } else {
710 stv0299_writereg(fe, 0x13, 0x99);
711 stv0299_writereg(fe, 0x14, 0x8d);
712 stv0299_writereg(fe, 0x15, 0xce);
713 stv0299_writereg(fe, 0x17, 0x43);
714 stv0299_writereg(fe, 0x1a, 0x1d);
715 stv0299_writereg(fe, 0x1c, 0x12);
716 stv0299_writereg(fe, 0x2d, 0x05);
717 }
718 stv0299_writereg(fe, 0x0e, 0x23);
719 stv0299_writereg(fe, 0x0f, 0x94);
720 stv0299_writereg(fe, 0x10, 0x39);
721 stv0299_writereg(fe, 0x15, 0xc9);
722
723 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
724 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
725 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
726
727 return 0;
728}
729
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300730static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
731 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300733 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 u32 div;
735 u8 buf[4];
736 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
737
738 if ((params->frequency < 950000) || (params->frequency > 2150000))
739 return -EINVAL;
740
741 div = (params->frequency + (500 - 1)) / 500; // round correctly
742 buf[0] = (div >> 8) & 0x7f;
743 buf[1] = div & 0xff;
744 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
745 buf[3] = 0x20;
746
747 if (params->u.qpsk.symbol_rate < 4000000)
748 buf[3] |= 1;
749
750 if (params->frequency < 1250000)
751 buf[3] |= 0;
752 else if (params->frequency < 1550000)
753 buf[3] |= 0x40;
754 else if (params->frequency < 2050000)
755 buf[3] |= 0x80;
756 else if (params->frequency < 2150000)
757 buf[3] |= 0xC0;
758
Patrick Boettcherdea74862006-05-14 05:01:31 -0300759 if (fe->ops.i2c_gate_ctrl)
760 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300761 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 return -EIO;
763 return 0;
764}
765
766static struct stv0299_config philips_su1278_tt_config = {
767
768 .demod_address = 0x68,
769 .inittab = philips_su1278_tt_inittab,
770 .mclk = 64000000UL,
771 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 .skip_reinit = 1,
773 .lock_output = STV0229_LOCKOUTPUT_1,
774 .volt13_op0_op1 = STV0299_VOLT13_OP1,
775 .min_delay_ms = 50,
776 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777};
778
779
780
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300781static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782{
783 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
784 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
785 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700786 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 sizeof(td1316_init) };
788
789 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300790 if (fe->ops.i2c_gate_ctrl)
791 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
793 return -EIO;
794 msleep(1);
795
796 // disable the mc44BC374c (do not check for errors)
797 tuner_msg.addr = 0x65;
798 tuner_msg.buf = disable_mc44BC374c;
799 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300800 if (fe->ops.i2c_gate_ctrl)
801 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300803 if (fe->ops.i2c_gate_ctrl)
804 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
806 }
807
808 return 0;
809}
810
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300811static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812{
813 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
814 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700815 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 -0700816 int tuner_frequency = 0;
817 u8 band, cp, filter;
818
819 // determine charge pump
820 tuner_frequency = params->frequency + 36130000;
821 if (tuner_frequency < 87000000)
822 return -EINVAL;
823 else if (tuner_frequency < 130000000)
824 cp = 3;
825 else if (tuner_frequency < 160000000)
826 cp = 5;
827 else if (tuner_frequency < 200000000)
828 cp = 6;
829 else if (tuner_frequency < 290000000)
830 cp = 3;
831 else if (tuner_frequency < 420000000)
832 cp = 5;
833 else if (tuner_frequency < 480000000)
834 cp = 6;
835 else if (tuner_frequency < 620000000)
836 cp = 3;
837 else if (tuner_frequency < 830000000)
838 cp = 5;
839 else if (tuner_frequency < 895000000)
840 cp = 7;
841 else
842 return -EINVAL;
843
844 // determine band
845 if (params->frequency < 49000000)
846 return -EINVAL;
847 else if (params->frequency < 159000000)
848 band = 1;
849 else if (params->frequency < 444000000)
850 band = 2;
851 else if (params->frequency < 861000000)
852 band = 4;
853 else
854 return -EINVAL;
855
856 // setup PLL filter and TDA9889
857 switch (params->u.ofdm.bandwidth) {
858 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300859 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 filter = 0;
861 break;
862
863 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300864 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 filter = 0;
866 break;
867
868 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300869 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700870 filter = 1;
871 break;
872
873 default:
874 return -EINVAL;
875 }
876
877 // calculate divisor
878 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
879 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
880
881 // setup tuner buffer
882 tuner_buf[0] = tuner_frequency >> 8;
883 tuner_buf[1] = tuner_frequency & 0xff;
884 tuner_buf[2] = 0xca;
885 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
886
Patrick Boettcherdea74862006-05-14 05:01:31 -0300887 if (fe->ops.i2c_gate_ctrl)
888 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
890 return -EIO;
891
892 msleep(1);
893 return 0;
894}
895
896static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
897 const struct firmware **fw, char *name)
898{
899 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
900
901 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
902}
903
904static struct tda1004x_config philips_tdm1316l_config = {
905
906 .demod_address = 0x8,
907 .invert = 0,
908 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700909 .xtal_freq = TDA10046_XTAL_4M,
910 .agc_config = TDA10046_AGC_DEFAULT,
911 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 .request_firmware = philips_tdm1316l_request_firmware,
913};
914
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300915static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700916{
917 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
918 u8 tuner_buf[5];
919 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
920 .flags = 0,
921 .buf = tuner_buf,
922 .len = sizeof(tuner_buf) };
923 int tuner_frequency = 0;
924 u8 band, cp, filter;
925
926 // determine charge pump
927 tuner_frequency = params->frequency + 36125000;
928 if (tuner_frequency < 87000000)
929 return -EINVAL;
930 else if (tuner_frequency < 130000000) {
931 cp = 3;
932 band = 1;
933 } else if (tuner_frequency < 160000000) {
934 cp = 5;
935 band = 1;
936 } else if (tuner_frequency < 200000000) {
937 cp = 6;
938 band = 1;
939 } else if (tuner_frequency < 290000000) {
940 cp = 3;
941 band = 2;
942 } else if (tuner_frequency < 420000000) {
943 cp = 5;
944 band = 2;
945 } else if (tuner_frequency < 480000000) {
946 cp = 6;
947 band = 2;
948 } else if (tuner_frequency < 620000000) {
949 cp = 3;
950 band = 4;
951 } else if (tuner_frequency < 830000000) {
952 cp = 5;
953 band = 4;
954 } else if (tuner_frequency < 895000000) {
955 cp = 7;
956 band = 4;
957 } else
958 return -EINVAL;
959
960 // assume PLL filter should always be 8MHz for the moment.
961 filter = 1;
962
963 // calculate divisor
964 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
965
966 // setup tuner buffer
967 tuner_buf[0] = tuner_frequency >> 8;
968 tuner_buf[1] = tuner_frequency & 0xff;
969 tuner_buf[2] = 0xc8;
970 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
971 tuner_buf[4] = 0x80;
972
Patrick Boettcherdea74862006-05-14 05:01:31 -0300973 if (fe->ops.i2c_gate_ctrl)
974 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700975 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
976 return -EIO;
977
978 msleep(50);
979
Patrick Boettcherdea74862006-05-14 05:01:31 -0300980 if (fe->ops.i2c_gate_ctrl)
981 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700982 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
983 return -EIO;
984
985 msleep(1);
986
987 return 0;
988}
989
990static u8 dvbc_philips_tdm1316l_inittab[] = {
991 0x80, 0x01,
992 0x80, 0x00,
993 0x81, 0x01,
994 0x81, 0x00,
995 0x00, 0x09,
996 0x01, 0x69,
997 0x03, 0x00,
998 0x04, 0x00,
999 0x07, 0x00,
1000 0x08, 0x00,
1001 0x20, 0x00,
1002 0x21, 0x40,
1003 0x22, 0x00,
1004 0x23, 0x00,
1005 0x24, 0x40,
1006 0x25, 0x88,
1007 0x30, 0xff,
1008 0x31, 0x00,
1009 0x32, 0xff,
1010 0x33, 0x00,
1011 0x34, 0x50,
1012 0x35, 0x7f,
1013 0x36, 0x00,
1014 0x37, 0x20,
1015 0x38, 0x00,
1016 0x40, 0x1c,
1017 0x41, 0xff,
1018 0x42, 0x29,
1019 0x43, 0x20,
1020 0x44, 0xff,
1021 0x45, 0x00,
1022 0x46, 0x00,
1023 0x49, 0x04,
1024 0x4a, 0x00,
1025 0x4b, 0x7b,
1026 0x52, 0x30,
1027 0x55, 0xae,
1028 0x56, 0x47,
1029 0x57, 0xe1,
1030 0x58, 0x3a,
1031 0x5a, 0x1e,
1032 0x5b, 0x34,
1033 0x60, 0x00,
1034 0x63, 0x00,
1035 0x64, 0x00,
1036 0x65, 0x00,
1037 0x66, 0x00,
1038 0x67, 0x00,
1039 0x68, 0x00,
1040 0x69, 0x00,
1041 0x6a, 0x02,
1042 0x6b, 0x00,
1043 0x70, 0xff,
1044 0x71, 0x00,
1045 0x72, 0x00,
1046 0x73, 0x00,
1047 0x74, 0x0c,
1048 0x80, 0x00,
1049 0x81, 0x00,
1050 0x82, 0x00,
1051 0x83, 0x00,
1052 0x84, 0x04,
1053 0x85, 0x80,
1054 0x86, 0x24,
1055 0x87, 0x78,
1056 0x88, 0x10,
1057 0x89, 0x00,
1058 0x90, 0x01,
1059 0x91, 0x01,
1060 0xa0, 0x04,
1061 0xa1, 0x00,
1062 0xa2, 0x00,
1063 0xb0, 0x91,
1064 0xb1, 0x0b,
1065 0xc0, 0x53,
1066 0xc1, 0x70,
1067 0xc2, 0x12,
1068 0xd0, 0x00,
1069 0xd1, 0x00,
1070 0xd2, 0x00,
1071 0xd3, 0x00,
1072 0xd4, 0x00,
1073 0xd5, 0x00,
1074 0xde, 0x00,
1075 0xdf, 0x00,
1076 0x61, 0x38,
1077 0x62, 0x0a,
1078 0x53, 0x13,
1079 0x59, 0x08,
1080 0xff, 0xff,
1081};
1082
1083static struct stv0297_config dvbc_philips_tdm1316l_config = {
1084 .demod_address = 0x1c,
1085 .inittab = dvbc_philips_tdm1316l_inittab,
1086 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001087 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001088};
1089
1090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091
1092
1093static void frontend_init(struct budget_ci *budget_ci)
1094{
1095 switch (budget_ci->budget.dev->pci->subsystem_device) {
1096 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1097 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001098 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001100 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001101 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 break;
1103 }
1104 break;
1105
1106 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1107 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001108 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001110 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 break;
1112 }
1113 break;
1114
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001115 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1116 budget_ci->tuner_pll_address = 0x61;
1117 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001118 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001119 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001120 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001121 break;
1122 }
1123 break;
1124
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001126 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001128 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001130 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1131 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 break;
1133 }
1134 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001135
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001136 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001137 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001138 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001139 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001140 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001141 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001142 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1143 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001144 break;
1145 }
1146 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001147
1148 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001149 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001150 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001151 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001152 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1153
Patrick Boettcherdea74862006-05-14 05:01:31 -03001154 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001155 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 -03001156 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001157 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001158 budget_ci->budget.dvb_frontend = NULL;
1159 }
1160 }
1161
1162 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 }
1164
1165 if (budget_ci->budget.dvb_frontend == NULL) {
1166 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1167 budget_ci->budget.dev->pci->vendor,
1168 budget_ci->budget.dev->pci->device,
1169 budget_ci->budget.dev->pci->subsystem_vendor,
1170 budget_ci->budget.dev->pci->subsystem_device);
1171 } else {
1172 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001173 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001175 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 budget_ci->budget.dvb_frontend = NULL;
1177 }
1178 }
1179}
1180
1181static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1182{
1183 struct budget_ci *budget_ci;
1184 int err;
1185
David Hardemanee579bc2006-12-02 21:16:05 -02001186 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001187 if (!budget_ci) {
1188 err = -ENOMEM;
1189 goto out1;
1190 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001191
1192 dprintk(2, "budget_ci: %p\n", budget_ci);
1193
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 dev->ext_priv = budget_ci;
1195
David Hardeman8cc532e2006-12-02 21:16:05 -02001196 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1197 if (err)
1198 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
David Hardeman8cc532e2006-12-02 21:16:05 -02001200 err = msp430_ir_init(budget_ci);
1201 if (err)
1202 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001203
1204 ciintf_init(budget_ci);
1205
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001206 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 frontend_init(budget_ci);
1208
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001209 ttpci_budget_init_hooks(&budget_ci->budget);
1210
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001212
1213out3:
1214 ttpci_budget_deinit(&budget_ci->budget);
1215out2:
1216 kfree(budget_ci);
1217out1:
1218 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219}
1220
1221static int budget_ci_detach(struct saa7146_dev *dev)
1222{
1223 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1224 struct saa7146_dev *saa = budget_ci->budget.dev;
1225 int err;
1226
1227 if (budget_ci->budget.ci_present)
1228 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001229 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001230 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001232 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234 err = ttpci_budget_deinit(&budget_ci->budget);
1235
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236 // disable frontend and CI interface
1237 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1238
1239 kfree(budget_ci);
1240
1241 return err;
1242}
1243
1244static struct saa7146_extension budget_extension;
1245
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001246MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1248MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001249MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001250MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251
1252static struct pci_device_id pci_tbl[] = {
1253 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1254 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001255 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001257 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001258 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 {
1260 .vendor = 0,
1261 }
1262};
1263
1264MODULE_DEVICE_TABLE(pci, pci_tbl);
1265
1266static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001267 .name = "budget_ci dvb",
Oliver Endriss69459f32005-12-01 00:51:48 -08001268 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001269
1270 .module = THIS_MODULE,
1271 .pci_tbl = &pci_tbl[0],
1272 .attach = budget_ci_attach,
1273 .detach = budget_ci_detach,
1274
1275 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1276 .irq_func = budget_ci_irq,
1277};
1278
1279static int __init budget_ci_init(void)
1280{
1281 return saa7146_register_extension(&budget_extension);
1282}
1283
1284static void __exit budget_ci_exit(void)
1285{
1286 saa7146_unregister_extension(&budget_extension);
1287}
1288
1289module_init(budget_ci_init);
1290module_exit(budget_ci_exit);
1291
1292MODULE_LICENSE("GPL");
1293MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1294MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1295 "budget PCI DVB cards w/ CI-module produced by "
1296 "Siemens, Technotrend, Hauppauge");