blob: ea4257653318a04d2025c77bdecde276a1f06d9b [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 Hardemanb5471a22006-12-02 21:16:05 -020095static int ir_debug = 0;
96module_param(ir_debug, int, 0644);
97MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
98
David Hardemandd2f3982006-12-02 21:16:05 -020099struct budget_ci_ir {
100 struct input_dev *dev;
101 struct tasklet_struct msp430_irq_tasklet;
102 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -0200103 char phys[32];
David Hardeman2520fff2006-12-02 21:16:05 -0200104 struct ir_input_state state;
David Hardeman64741b72006-12-02 21:16:05 -0200105 int rc5_device;
David Hardemandd2f3982006-12-02 21:16:05 -0200106};
107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108struct budget_ci {
109 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 struct tasklet_struct ciintf_irq_tasklet;
111 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300112 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -0200114 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700115 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116};
117
David Hardeman2520fff2006-12-02 21:16:05 -0200118static void msp430_ir_keyup(unsigned long data)
119{
120 struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
121 ir_input_nokey(ir->dev, &ir->state);
122}
123
124static void msp430_ir_interrupt(unsigned long data)
125{
126 struct budget_ci *budget_ci = (struct budget_ci *) data;
127 struct input_dev *dev = budget_ci->ir.dev;
128 static int bounces = 0;
David Hardeman64741b72006-12-02 21:16:05 -0200129 int device;
130 int toggle;
131 static int prev_toggle = -1;
132 static u32 ir_key;
David Hardeman2520fff2006-12-02 21:16:05 -0200133 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
134
David Hardeman64741b72006-12-02 21:16:05 -0200135 /*
136 * The msp430 chip can generate two different bytes, command and device
137 *
138 * type1: X1CCCCCC, C = command bits (0 - 63)
139 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
140 *
141 * More than one command byte may be generated before the device byte
142 * Only when we have both, a correct keypress is generated
143 */
144
145 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200146 if (command & 0x40) {
David Hardemanb5471a22006-12-02 21:16:05 -0200147 if (ir_debug)
148 printk("budget_ci: received command byte 0x%02x\n", command);
David Hardeman2520fff2006-12-02 21:16:05 -0200149 ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200150 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200151 }
David Hardeman64741b72006-12-02 21:16:05 -0200152
153 /* It's a RC5 device byte */
David Hardemanb5471a22006-12-02 21:16:05 -0200154 if (ir_debug)
155 printk("budget_ci: received device byte 0x%02x\n", command);
David Hardeman64741b72006-12-02 21:16:05 -0200156 device = command & 0x1f;
157 toggle = command & 0x20;
158
159 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device)
160 return;
161
David Hardeman64741b72006-12-02 21:16:05 -0200162 /* Ignore repeated key sequences if requested */
David Hardeman59236d42006-12-02 21:16:06 -0200163 if (toggle == prev_toggle && ir_key == dev->repeat_key &&
164 bounces > 0 && timer_pending(&dev->timer)) {
165 if (ir_debug)
166 printk("budget_ci: debounce logic ignored IR command\n");
David Hardeman64741b72006-12-02 21:16:05 -0200167 bounces--;
168 return;
169 }
David Hardeman59236d42006-12-02 21:16:06 -0200170 prev_toggle = toggle;
David Hardeman64741b72006-12-02 21:16:05 -0200171
David Hardeman59236d42006-12-02 21:16:06 -0200172 /* Are we still waiting for a keyup event? */
173 if (del_timer(&dev->timer))
174 ir_input_nokey(dev, &budget_ci->ir.state);
175
176 /* Generate keypress */
177 if (ir_debug)
178 printk("budget_ci: generating keypress 0x%02x\n", ir_key);
179 ir_input_keydown(dev, &budget_ci->ir.state, ir_key, (ir_key & (command << 8)));
180
181 /* Do we want to delay the keyup event? */
182 if (debounce) {
David Hardeman64741b72006-12-02 21:16:05 -0200183 bounces = debounce;
David Hardeman59236d42006-12-02 21:16:06 -0200184 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT));
185 } else {
186 ir_input_nokey(dev, &budget_ci->ir.state);
187 }
David Hardeman2520fff2006-12-02 21:16:05 -0200188}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190static int msp430_ir_init(struct budget_ci *budget_ci)
191{
192 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200193 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200194 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
David Hardemandd2f3982006-12-02 21:16:05 -0200196 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200197 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200198 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200199 error = -ENOMEM;
200 goto out1;
201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
David Hardemandd2f3982006-12-02 21:16:05 -0200203 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
204 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200205 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
206 "pci-%s/ir0", pci_name(saa->pci));
207
David Hardemandd2f3982006-12-02 21:16:05 -0200208 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
David Hardeman5cc8ae02006-12-02 21:16:05 -0200210 input_dev->phys = budget_ci->ir.phys;
211 input_dev->id.bustype = BUS_PCI;
212 input_dev->id.version = 1;
213 if (saa->pci->subsystem_vendor) {
214 input_dev->id.vendor = saa->pci->subsystem_vendor;
215 input_dev->id.product = saa->pci->subsystem_device;
216 } else {
217 input_dev->id.vendor = saa->pci->vendor;
218 input_dev->id.product = saa->pci->device;
219 }
David Hardeman5cc8ae02006-12-02 21:16:05 -0200220 input_dev->cdev.dev = &saa->pci->dev;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200221
David Hardeman64741b72006-12-02 21:16:05 -0200222 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200223 switch (budget_ci->budget.dev->pci->subsystem_device) {
224 case 0x100c:
225 case 0x100f:
David Hardeman2520fff2006-12-02 21:16:05 -0200226 case 0x1011:
227 case 0x1012:
228 case 0x1017:
229 /* The hauppauge keymap is a superset of these remotes */
230 ir_input_init(input_dev, &budget_ci->ir.state,
231 IR_TYPE_RC5, ir_codes_hauppauge_new);
David Hardeman64741b72006-12-02 21:16:05 -0200232
233 if (rc5_device < 0)
234 budget_ci->ir.rc5_device = 0x1f;
235 else
236 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200237 break;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300238 case 0x1010:
239 /* for the Technotrend 1500 bundled remote */
240 ir_input_init(input_dev, &budget_ci->ir.state,
241 IR_TYPE_RC5, ir_codes_tt_1500);
242
243 if (rc5_device < 0)
244 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
245 else
246 budget_ci->ir.rc5_device = rc5_device;
247 break;
David Hardeman2520fff2006-12-02 21:16:05 -0200248 default:
249 /* unknown remote */
250 ir_input_init(input_dev, &budget_ci->ir.state,
251 IR_TYPE_RC5, ir_codes_budget_ci_old);
David Hardeman64741b72006-12-02 21:16:05 -0200252
253 if (rc5_device < 0)
254 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
255 else
256 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200257 break;
258 }
259
David Hardeman59236d42006-12-02 21:16:06 -0200260 /* initialise the key-up debounce timeout handler */
David Hardeman2520fff2006-12-02 21:16:05 -0200261 input_dev->timer.function = msp430_ir_keyup;
262 input_dev->timer.data = (unsigned long) &budget_ci->ir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263
David Hardeman8cc532e2006-12-02 21:16:05 -0200264 error = input_register_device(input_dev);
265 if (error) {
266 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
267 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
David Hardeman8cc532e2006-12-02 21:16:05 -0200270 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
271 (unsigned long) budget_ci);
272
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300273 SAA7146_IER_ENABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
275
276 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200277
278out2:
279 input_free_device(input_dev);
280out1:
281 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282}
283
284static void msp430_ir_deinit(struct budget_ci *budget_ci)
285{
286 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200287 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300289 SAA7146_IER_DISABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200291 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300293 if (del_timer(&dev->timer)) {
David Hardeman2520fff2006-12-02 21:16:05 -0200294 ir_input_nokey(dev, &budget_ci->ir.state);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300295 input_sync(dev);
296 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
298 input_unregister_device(dev);
299}
300
301static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
302{
303 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
304
305 if (slot != 0)
306 return -EINVAL;
307
308 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
309 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
310}
311
312static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
313{
314 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
315
316 if (slot != 0)
317 return -EINVAL;
318
319 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
320 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
321}
322
323static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
324{
325 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
326
327 if (slot != 0)
328 return -EINVAL;
329
330 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
331 DEBIADDR_IO | (address & 3), 1, 1, 0);
332}
333
334static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
335{
336 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
337
338 if (slot != 0)
339 return -EINVAL;
340
341 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
342 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
343}
344
345static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
346{
347 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
348 struct saa7146_dev *saa = budget_ci->budget.dev;
349
350 if (slot != 0)
351 return -EINVAL;
352
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300353 if (budget_ci->ci_irq) {
354 // trigger on RISING edge during reset so we know when READY is re-asserted
355 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 budget_ci->slot_status = SLOTSTATUS_RESET;
358 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
359 msleep(1);
360 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
361 CICONTROL_RESET, 1, 0);
362
363 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
364 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
365 return 0;
366}
367
368static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
369{
370 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
371 struct saa7146_dev *saa = budget_ci->budget.dev;
372
373 if (slot != 0)
374 return -EINVAL;
375
376 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
377 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
378 return 0;
379}
380
381static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
382{
383 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
384 struct saa7146_dev *saa = budget_ci->budget.dev;
385 int tmp;
386
387 if (slot != 0)
388 return -EINVAL;
389
390 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
391
392 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
393 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
394 tmp | CICONTROL_ENABLETS, 1, 0);
395
396 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
397 return 0;
398}
399
400static void ciintf_interrupt(unsigned long data)
401{
402 struct budget_ci *budget_ci = (struct budget_ci *) data;
403 struct saa7146_dev *saa = budget_ci->budget.dev;
404 unsigned int flags;
405
406 // ensure we don't get spurious IRQs during initialisation
407 if (!budget_ci->budget.ci_present)
408 return;
409
410 // read the CAM status
411 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
412 if (flags & CICONTROL_CAMDETECT) {
413
414 // GPIO should be set to trigger on falling edge if a CAM is present
415 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
416
417 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
418 // CAM insertion IRQ
419 budget_ci->slot_status = SLOTSTATUS_PRESENT;
420 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
421 DVB_CA_EN50221_CAMCHANGE_INSERTED);
422
423 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
424 // CAM ready (reset completed)
425 budget_ci->slot_status = SLOTSTATUS_READY;
426 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
427
428 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
429 // FR/DA IRQ
430 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
431 }
432 } else {
433
434 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
435 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
436 // the CAM might not actually be ready yet.
437 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
438
439 // generate a CAM removal IRQ if we haven't already
440 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
441 // CAM removal IRQ
442 budget_ci->slot_status = SLOTSTATUS_NONE;
443 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
444 DVB_CA_EN50221_CAMCHANGE_REMOVED);
445 }
446 }
447}
448
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300449static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
450{
451 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
452 unsigned int flags;
453
454 // ensure we don't get spurious IRQs during initialisation
455 if (!budget_ci->budget.ci_present)
456 return -EINVAL;
457
458 // read the CAM status
459 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
460 if (flags & CICONTROL_CAMDETECT) {
461 // mark it as present if it wasn't before
462 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
463 budget_ci->slot_status = SLOTSTATUS_PRESENT;
464 }
465
466 // during a RESET, we check if we can read from IO memory to see when CAM is ready
467 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
468 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
469 budget_ci->slot_status = SLOTSTATUS_READY;
470 }
471 }
472 } else {
473 budget_ci->slot_status = SLOTSTATUS_NONE;
474 }
475
476 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
477 if (budget_ci->slot_status & SLOTSTATUS_READY) {
478 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
479 }
480 return DVB_CA_EN50221_POLL_CAM_PRESENT;
481 }
482
483 return 0;
484}
485
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486static int ciintf_init(struct budget_ci *budget_ci)
487{
488 struct saa7146_dev *saa = budget_ci->budget.dev;
489 int flags;
490 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300491 int ci_version;
492 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
494 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
495
496 // enable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300497 saa7146_write(saa, MC1, MASK_27 | MASK_11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300500 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
501 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 result = -ENODEV;
503 goto error;
504 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 // determine whether a CAM is present or not
507 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
508 budget_ci->slot_status = SLOTSTATUS_NONE;
509 if (flags & CICONTROL_CAMDETECT)
510 budget_ci->slot_status = SLOTSTATUS_PRESENT;
511
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300512 // version 0xa2 of the CI firmware doesn't generate interrupts
513 if (ci_version == 0xa2) {
514 ca_flags = 0;
515 budget_ci->ci_irq = 0;
516 } else {
517 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
518 DVB_CA_EN50221_FLAG_IRQ_FR |
519 DVB_CA_EN50221_FLAG_IRQ_DA;
520 budget_ci->ci_irq = 1;
521 }
522
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 // register CI interface
524 budget_ci->ca.owner = THIS_MODULE;
525 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
526 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
527 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
528 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
529 budget_ci->ca.slot_reset = ciintf_slot_reset;
530 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
531 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300532 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700534 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300536 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 printk("budget_ci: CI interface detected, but initialisation failed.\n");
538 goto error;
539 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300540
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300542 if (budget_ci->ci_irq) {
543 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
544 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
545 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
546 } else {
547 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
548 }
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300549 SAA7146_IER_ENABLE(saa, MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300551
552 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
554 CICONTROL_RESET, 1, 0);
555
556 // success!
557 printk("budget_ci: CI interface initialised\n");
558 budget_ci->budget.ci_present = 1;
559
560 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300561 if (budget_ci->ci_irq) {
562 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
563 if (budget_ci->slot_status != SLOTSTATUS_NONE)
564 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
565 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
566 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
568 return 0;
569
570error:
Hartmut Birr2a893de2006-12-03 21:08:08 -0300571 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572 return result;
573}
574
575static void ciintf_deinit(struct budget_ci *budget_ci)
576{
577 struct saa7146_dev *saa = budget_ci->budget.dev;
578
579 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300580 if (budget_ci->ci_irq) {
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300581 SAA7146_IER_DISABLE(saa, MASK_03);
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300582 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
583 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
584 }
585
586 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
588 msleep(1);
589 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
590 CICONTROL_RESET, 1, 0);
591
592 // disable TS data stream to CI interface
593 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
594
595 // release the CA device
596 dvb_ca_en50221_release(&budget_ci->ca);
597
598 // disable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300599 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600}
601
602static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
603{
604 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
605
606 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
607
608 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200609 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610
611 if (*isr & MASK_10)
612 ttpci_budget_irq10_handler(dev, isr);
613
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300614 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
616}
617
Linus Torvalds1da177e2005-04-16 15:20:36 -0700618static u8 philips_su1278_tt_inittab[] = {
619 0x01, 0x0f,
620 0x02, 0x30,
621 0x03, 0x00,
622 0x04, 0x5b,
623 0x05, 0x85,
624 0x06, 0x02,
625 0x07, 0x00,
626 0x08, 0x02,
627 0x09, 0x00,
628 0x0C, 0x01,
629 0x0D, 0x81,
630 0x0E, 0x44,
631 0x0f, 0x14,
632 0x10, 0x3c,
633 0x11, 0x84,
634 0x12, 0xda,
635 0x13, 0x97,
636 0x14, 0x95,
637 0x15, 0xc9,
638 0x16, 0x19,
639 0x17, 0x8c,
640 0x18, 0x59,
641 0x19, 0xf8,
642 0x1a, 0xfe,
643 0x1c, 0x7f,
644 0x1d, 0x00,
645 0x1e, 0x00,
646 0x1f, 0x50,
647 0x20, 0x00,
648 0x21, 0x00,
649 0x22, 0x00,
650 0x23, 0x00,
651 0x28, 0x00,
652 0x29, 0x28,
653 0x2a, 0x14,
654 0x2b, 0x0f,
655 0x2c, 0x09,
656 0x2d, 0x09,
657 0x31, 0x1f,
658 0x32, 0x19,
659 0x33, 0xfc,
660 0x34, 0x93,
661 0xff, 0xff
662};
663
664static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
665{
666 stv0299_writereg(fe, 0x0e, 0x44);
667 if (srate >= 10000000) {
668 stv0299_writereg(fe, 0x13, 0x97);
669 stv0299_writereg(fe, 0x14, 0x95);
670 stv0299_writereg(fe, 0x15, 0xc9);
671 stv0299_writereg(fe, 0x17, 0x8c);
672 stv0299_writereg(fe, 0x1a, 0xfe);
673 stv0299_writereg(fe, 0x1c, 0x7f);
674 stv0299_writereg(fe, 0x2d, 0x09);
675 } else {
676 stv0299_writereg(fe, 0x13, 0x99);
677 stv0299_writereg(fe, 0x14, 0x8d);
678 stv0299_writereg(fe, 0x15, 0xce);
679 stv0299_writereg(fe, 0x17, 0x43);
680 stv0299_writereg(fe, 0x1a, 0x1d);
681 stv0299_writereg(fe, 0x1c, 0x12);
682 stv0299_writereg(fe, 0x2d, 0x05);
683 }
684 stv0299_writereg(fe, 0x0e, 0x23);
685 stv0299_writereg(fe, 0x0f, 0x94);
686 stv0299_writereg(fe, 0x10, 0x39);
687 stv0299_writereg(fe, 0x15, 0xc9);
688
689 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
690 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
691 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
692
693 return 0;
694}
695
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300696static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
697 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300699 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 u32 div;
701 u8 buf[4];
702 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
703
704 if ((params->frequency < 950000) || (params->frequency > 2150000))
705 return -EINVAL;
706
707 div = (params->frequency + (500 - 1)) / 500; // round correctly
708 buf[0] = (div >> 8) & 0x7f;
709 buf[1] = div & 0xff;
710 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
711 buf[3] = 0x20;
712
713 if (params->u.qpsk.symbol_rate < 4000000)
714 buf[3] |= 1;
715
716 if (params->frequency < 1250000)
717 buf[3] |= 0;
718 else if (params->frequency < 1550000)
719 buf[3] |= 0x40;
720 else if (params->frequency < 2050000)
721 buf[3] |= 0x80;
722 else if (params->frequency < 2150000)
723 buf[3] |= 0xC0;
724
Patrick Boettcherdea74862006-05-14 05:01:31 -0300725 if (fe->ops.i2c_gate_ctrl)
726 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300727 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 return -EIO;
729 return 0;
730}
731
732static struct stv0299_config philips_su1278_tt_config = {
733
734 .demod_address = 0x68,
735 .inittab = philips_su1278_tt_inittab,
736 .mclk = 64000000UL,
737 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 .skip_reinit = 1,
739 .lock_output = STV0229_LOCKOUTPUT_1,
740 .volt13_op0_op1 = STV0299_VOLT13_OP1,
741 .min_delay_ms = 50,
742 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743};
744
745
746
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300747static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748{
749 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
750 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
751 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700752 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 sizeof(td1316_init) };
754
755 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300756 if (fe->ops.i2c_gate_ctrl)
757 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
759 return -EIO;
760 msleep(1);
761
762 // disable the mc44BC374c (do not check for errors)
763 tuner_msg.addr = 0x65;
764 tuner_msg.buf = disable_mc44BC374c;
765 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300766 if (fe->ops.i2c_gate_ctrl)
767 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300769 if (fe->ops.i2c_gate_ctrl)
770 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
772 }
773
774 return 0;
775}
776
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300777static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778{
779 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
780 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700781 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 -0700782 int tuner_frequency = 0;
783 u8 band, cp, filter;
784
785 // determine charge pump
786 tuner_frequency = params->frequency + 36130000;
787 if (tuner_frequency < 87000000)
788 return -EINVAL;
789 else if (tuner_frequency < 130000000)
790 cp = 3;
791 else if (tuner_frequency < 160000000)
792 cp = 5;
793 else if (tuner_frequency < 200000000)
794 cp = 6;
795 else if (tuner_frequency < 290000000)
796 cp = 3;
797 else if (tuner_frequency < 420000000)
798 cp = 5;
799 else if (tuner_frequency < 480000000)
800 cp = 6;
801 else if (tuner_frequency < 620000000)
802 cp = 3;
803 else if (tuner_frequency < 830000000)
804 cp = 5;
805 else if (tuner_frequency < 895000000)
806 cp = 7;
807 else
808 return -EINVAL;
809
810 // determine band
811 if (params->frequency < 49000000)
812 return -EINVAL;
813 else if (params->frequency < 159000000)
814 band = 1;
815 else if (params->frequency < 444000000)
816 band = 2;
817 else if (params->frequency < 861000000)
818 band = 4;
819 else
820 return -EINVAL;
821
822 // setup PLL filter and TDA9889
823 switch (params->u.ofdm.bandwidth) {
824 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300825 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 filter = 0;
827 break;
828
829 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300830 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 filter = 0;
832 break;
833
834 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300835 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836 filter = 1;
837 break;
838
839 default:
840 return -EINVAL;
841 }
842
843 // calculate divisor
844 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
845 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
846
847 // setup tuner buffer
848 tuner_buf[0] = tuner_frequency >> 8;
849 tuner_buf[1] = tuner_frequency & 0xff;
850 tuner_buf[2] = 0xca;
851 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
852
Patrick Boettcherdea74862006-05-14 05:01:31 -0300853 if (fe->ops.i2c_gate_ctrl)
854 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
856 return -EIO;
857
858 msleep(1);
859 return 0;
860}
861
862static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
863 const struct firmware **fw, char *name)
864{
865 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
866
867 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
868}
869
870static struct tda1004x_config philips_tdm1316l_config = {
871
872 .demod_address = 0x8,
873 .invert = 0,
874 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700875 .xtal_freq = TDA10046_XTAL_4M,
876 .agc_config = TDA10046_AGC_DEFAULT,
877 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 .request_firmware = philips_tdm1316l_request_firmware,
879};
880
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300881static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700882{
883 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
884 u8 tuner_buf[5];
885 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
886 .flags = 0,
887 .buf = tuner_buf,
888 .len = sizeof(tuner_buf) };
889 int tuner_frequency = 0;
890 u8 band, cp, filter;
891
892 // determine charge pump
893 tuner_frequency = params->frequency + 36125000;
894 if (tuner_frequency < 87000000)
895 return -EINVAL;
896 else if (tuner_frequency < 130000000) {
897 cp = 3;
898 band = 1;
899 } else if (tuner_frequency < 160000000) {
900 cp = 5;
901 band = 1;
902 } else if (tuner_frequency < 200000000) {
903 cp = 6;
Thomas Kaiser9abec612006-11-22 18:15:19 -0300904 band = 2;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700905 } else if (tuner_frequency < 290000000) {
906 cp = 3;
907 band = 2;
908 } else if (tuner_frequency < 420000000) {
909 cp = 5;
910 band = 2;
911 } else if (tuner_frequency < 480000000) {
912 cp = 6;
913 band = 2;
914 } else if (tuner_frequency < 620000000) {
915 cp = 3;
916 band = 4;
917 } else if (tuner_frequency < 830000000) {
918 cp = 5;
919 band = 4;
920 } else if (tuner_frequency < 895000000) {
921 cp = 7;
922 band = 4;
923 } else
924 return -EINVAL;
925
926 // assume PLL filter should always be 8MHz for the moment.
927 filter = 1;
928
929 // calculate divisor
930 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
931
932 // setup tuner buffer
933 tuner_buf[0] = tuner_frequency >> 8;
934 tuner_buf[1] = tuner_frequency & 0xff;
935 tuner_buf[2] = 0xc8;
936 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
937 tuner_buf[4] = 0x80;
938
Patrick Boettcherdea74862006-05-14 05:01:31 -0300939 if (fe->ops.i2c_gate_ctrl)
940 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700941 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
942 return -EIO;
943
944 msleep(50);
945
Patrick Boettcherdea74862006-05-14 05:01:31 -0300946 if (fe->ops.i2c_gate_ctrl)
947 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700948 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
949 return -EIO;
950
951 msleep(1);
952
953 return 0;
954}
955
956static u8 dvbc_philips_tdm1316l_inittab[] = {
957 0x80, 0x01,
958 0x80, 0x00,
959 0x81, 0x01,
960 0x81, 0x00,
961 0x00, 0x09,
962 0x01, 0x69,
963 0x03, 0x00,
964 0x04, 0x00,
965 0x07, 0x00,
966 0x08, 0x00,
967 0x20, 0x00,
968 0x21, 0x40,
969 0x22, 0x00,
970 0x23, 0x00,
971 0x24, 0x40,
972 0x25, 0x88,
973 0x30, 0xff,
974 0x31, 0x00,
975 0x32, 0xff,
976 0x33, 0x00,
977 0x34, 0x50,
978 0x35, 0x7f,
979 0x36, 0x00,
980 0x37, 0x20,
981 0x38, 0x00,
982 0x40, 0x1c,
983 0x41, 0xff,
984 0x42, 0x29,
985 0x43, 0x20,
986 0x44, 0xff,
987 0x45, 0x00,
988 0x46, 0x00,
989 0x49, 0x04,
990 0x4a, 0x00,
991 0x4b, 0x7b,
992 0x52, 0x30,
993 0x55, 0xae,
994 0x56, 0x47,
995 0x57, 0xe1,
996 0x58, 0x3a,
997 0x5a, 0x1e,
998 0x5b, 0x34,
999 0x60, 0x00,
1000 0x63, 0x00,
1001 0x64, 0x00,
1002 0x65, 0x00,
1003 0x66, 0x00,
1004 0x67, 0x00,
1005 0x68, 0x00,
1006 0x69, 0x00,
1007 0x6a, 0x02,
1008 0x6b, 0x00,
1009 0x70, 0xff,
1010 0x71, 0x00,
1011 0x72, 0x00,
1012 0x73, 0x00,
1013 0x74, 0x0c,
1014 0x80, 0x00,
1015 0x81, 0x00,
1016 0x82, 0x00,
1017 0x83, 0x00,
1018 0x84, 0x04,
1019 0x85, 0x80,
1020 0x86, 0x24,
1021 0x87, 0x78,
1022 0x88, 0x10,
1023 0x89, 0x00,
1024 0x90, 0x01,
1025 0x91, 0x01,
1026 0xa0, 0x04,
1027 0xa1, 0x00,
1028 0xa2, 0x00,
1029 0xb0, 0x91,
1030 0xb1, 0x0b,
1031 0xc0, 0x53,
1032 0xc1, 0x70,
1033 0xc2, 0x12,
1034 0xd0, 0x00,
1035 0xd1, 0x00,
1036 0xd2, 0x00,
1037 0xd3, 0x00,
1038 0xd4, 0x00,
1039 0xd5, 0x00,
1040 0xde, 0x00,
1041 0xdf, 0x00,
1042 0x61, 0x38,
1043 0x62, 0x0a,
1044 0x53, 0x13,
1045 0x59, 0x08,
1046 0xff, 0xff,
1047};
1048
1049static struct stv0297_config dvbc_philips_tdm1316l_config = {
1050 .demod_address = 0x1c,
1051 .inittab = dvbc_philips_tdm1316l_inittab,
1052 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001053 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001054};
1055
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
1058
1059static void frontend_init(struct budget_ci *budget_ci)
1060{
1061 switch (budget_ci->budget.dev->pci->subsystem_device) {
1062 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1063 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001064 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001066 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001067 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 break;
1069 }
1070 break;
1071
1072 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1073 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001074 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001076 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077 break;
1078 }
1079 break;
1080
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001081 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1082 budget_ci->tuner_pll_address = 0x61;
1083 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001084 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001085 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001086 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001087 break;
1088 }
1089 break;
1090
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001092 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001094 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001096 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1097 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098 break;
1099 }
1100 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001101
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001102 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001103 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001104 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001105 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001106 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001107 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001108 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1109 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001110 break;
1111 }
1112 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001113
1114 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001115 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001116 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001117 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001118 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1119
Patrick Boettcherdea74862006-05-14 05:01:31 -03001120 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001121 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 -03001122 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001123 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001124 budget_ci->budget.dvb_frontend = NULL;
1125 }
1126 }
1127
1128 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 }
1130
1131 if (budget_ci->budget.dvb_frontend == NULL) {
1132 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1133 budget_ci->budget.dev->pci->vendor,
1134 budget_ci->budget.dev->pci->device,
1135 budget_ci->budget.dev->pci->subsystem_vendor,
1136 budget_ci->budget.dev->pci->subsystem_device);
1137 } else {
1138 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001139 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001141 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 budget_ci->budget.dvb_frontend = NULL;
1143 }
1144 }
1145}
1146
1147static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1148{
1149 struct budget_ci *budget_ci;
1150 int err;
1151
David Hardemanee579bc2006-12-02 21:16:05 -02001152 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001153 if (!budget_ci) {
1154 err = -ENOMEM;
1155 goto out1;
1156 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001157
1158 dprintk(2, "budget_ci: %p\n", budget_ci);
1159
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 dev->ext_priv = budget_ci;
1161
David Hardeman8cc532e2006-12-02 21:16:05 -02001162 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1163 if (err)
1164 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
David Hardeman8cc532e2006-12-02 21:16:05 -02001166 err = msp430_ir_init(budget_ci);
1167 if (err)
1168 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169
1170 ciintf_init(budget_ci);
1171
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001172 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 frontend_init(budget_ci);
1174
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001175 ttpci_budget_init_hooks(&budget_ci->budget);
1176
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001178
1179out3:
1180 ttpci_budget_deinit(&budget_ci->budget);
1181out2:
1182 kfree(budget_ci);
1183out1:
1184 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185}
1186
1187static int budget_ci_detach(struct saa7146_dev *dev)
1188{
1189 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1190 struct saa7146_dev *saa = budget_ci->budget.dev;
1191 int err;
1192
1193 if (budget_ci->budget.ci_present)
1194 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001195 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001196 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001198 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 err = ttpci_budget_deinit(&budget_ci->budget);
1201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 // disable frontend and CI interface
1203 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1204
1205 kfree(budget_ci);
1206
1207 return err;
1208}
1209
1210static struct saa7146_extension budget_extension;
1211
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001212MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1214MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001215MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001216MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217
1218static struct pci_device_id pci_tbl[] = {
1219 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1220 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001221 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001223 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001224 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 {
1226 .vendor = 0,
1227 }
1228};
1229
1230MODULE_DEVICE_TABLE(pci, pci_tbl);
1231
1232static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001233 .name = "budget_ci dvb",
Oliver Endriss00c4cc62006-11-01 13:09:51 -03001234 .flags = SAA7146_USE_I2C_IRQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001235
1236 .module = THIS_MODULE,
1237 .pci_tbl = &pci_tbl[0],
1238 .attach = budget_ci_attach,
1239 .detach = budget_ci_detach,
1240
1241 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1242 .irq_func = budget_ci_irq,
1243};
1244
1245static int __init budget_ci_init(void)
1246{
1247 return saa7146_register_extension(&budget_extension);
1248}
1249
1250static void __exit budget_ci_exit(void)
1251{
1252 saa7146_unregister_extension(&budget_extension);
1253}
1254
1255module_init(budget_ci_init);
1256module_exit(budget_ci_exit);
1257
1258MODULE_LICENSE("GPL");
1259MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1260MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1261 "budget PCI DVB cards w/ CI-module produced by "
1262 "Siemens, Technotrend, Hauppauge");