blob: a68f5bf012598f9afe224631592547d0567e9386 [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
190static void msp430_ir_debounce(unsigned long data)
191{
192 struct input_dev *dev = (struct input_dev *) data;
193
194 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300195 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
196 } else {
197 dev->rep[0] = 0;
198 dev->timer.expires = jiffies + HZ * 350 / 1000;
199 add_timer(&dev->timer);
200 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 }
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300202 input_sync(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203}
204
205static void msp430_ir_interrupt(unsigned long data)
206{
207 struct budget_ci *budget_ci = (struct budget_ci *) data;
David Hardemandd2f3982006-12-02 21:16:05 -0200208 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 unsigned int code =
210 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
211
212 if (code & 0x40) {
213 code &= 0x3f;
214
215 if (timer_pending(&dev->timer)) {
216 if (code == dev->repeat_key) {
217 ++dev->rep[0];
218 return;
219 }
220 del_timer(&dev->timer);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300221 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222 }
223
224 if (!key_map[code]) {
225 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
226 return;
227 }
228
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300229 input_event(dev, EV_KEY, key_map[code], 1);
230 input_sync(dev);
231
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 /* initialize debounce and repeat */
233 dev->repeat_key = code;
234 /* Zenith remote _always_ sends 2 sequences */
235 dev->rep[0] = ~0;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300236 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(350));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 }
238}
239
240static int msp430_ir_init(struct budget_ci *budget_ci)
241{
242 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200243 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200244 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
David Hardemandd2f3982006-12-02 21:16:05 -0200246 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200247 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200248 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200249 error = -ENOMEM;
250 goto out1;
251 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252
David Hardemandd2f3982006-12-02 21:16:05 -0200253 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
254 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200255 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
256 "pci-%s/ir0", pci_name(saa->pci));
257
David Hardemandd2f3982006-12-02 21:16:05 -0200258 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259
David Hardeman5cc8ae02006-12-02 21:16:05 -0200260 input_dev->phys = budget_ci->ir.phys;
261 input_dev->id.bustype = BUS_PCI;
262 input_dev->id.version = 1;
263 if (saa->pci->subsystem_vendor) {
264 input_dev->id.vendor = saa->pci->subsystem_vendor;
265 input_dev->id.product = saa->pci->subsystem_device;
266 } else {
267 input_dev->id.vendor = saa->pci->vendor;
268 input_dev->id.product = saa->pci->device;
269 }
270# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
271 input_dev->cdev.dev = &saa->pci->dev;
272# else
273 input_dev->dev = &saa->pci->dev;
274# endif
275
David Hardeman64741b72006-12-02 21:16:05 -0200276 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200277 switch (budget_ci->budget.dev->pci->subsystem_device) {
278 case 0x100c:
279 case 0x100f:
280 case 0x1010:
281 case 0x1011:
282 case 0x1012:
283 case 0x1017:
284 /* The hauppauge keymap is a superset of these remotes */
285 ir_input_init(input_dev, &budget_ci->ir.state,
286 IR_TYPE_RC5, ir_codes_hauppauge_new);
David Hardeman64741b72006-12-02 21:16:05 -0200287
288 if (rc5_device < 0)
289 budget_ci->ir.rc5_device = 0x1f;
290 else
291 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200292 break;
293 default:
294 /* unknown remote */
295 ir_input_init(input_dev, &budget_ci->ir.state,
296 IR_TYPE_RC5, ir_codes_budget_ci_old);
David Hardeman64741b72006-12-02 21:16:05 -0200297
298 if (rc5_device < 0)
299 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
300 else
301 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200302 break;
303 }
304
David Hardeman59236d42006-12-02 21:16:06 -0200305 /* initialise the key-up debounce timeout handler */
David Hardeman2520fff2006-12-02 21:16:05 -0200306 input_dev->timer.function = msp430_ir_keyup;
307 input_dev->timer.data = (unsigned long) &budget_ci->ir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
David Hardeman8cc532e2006-12-02 21:16:05 -0200309 error = input_register_device(input_dev);
310 if (error) {
311 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
312 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300313 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314
David Hardeman8cc532e2006-12-02 21:16:05 -0200315 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
316 (unsigned long) budget_ci);
317
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
320
321 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200322
323out2:
324 input_free_device(input_dev);
325out1:
326 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700327}
328
329static void msp430_ir_deinit(struct budget_ci *budget_ci)
330{
331 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200332 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
334 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
335 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200336 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300338 if (del_timer(&dev->timer)) {
David Hardeman2520fff2006-12-02 21:16:05 -0200339 ir_input_nokey(dev, &budget_ci->ir.state);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300340 input_sync(dev);
341 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700342
343 input_unregister_device(dev);
344}
345
346static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
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_debiread(&budget_ci->budget, DEBICICAM,
354 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
355}
356
357static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
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_debiwrite(&budget_ci->budget, DEBICICAM,
365 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
366}
367
368static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
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_debiread(&budget_ci->budget, DEBICICAM,
376 DEBIADDR_IO | (address & 3), 1, 1, 0);
377}
378
379static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
380{
381 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
382
383 if (slot != 0)
384 return -EINVAL;
385
386 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
387 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
388}
389
390static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
391{
392 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
393 struct saa7146_dev *saa = budget_ci->budget.dev;
394
395 if (slot != 0)
396 return -EINVAL;
397
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300398 if (budget_ci->ci_irq) {
399 // trigger on RISING edge during reset so we know when READY is re-asserted
400 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402 budget_ci->slot_status = SLOTSTATUS_RESET;
403 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
404 msleep(1);
405 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
406 CICONTROL_RESET, 1, 0);
407
408 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
409 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
410 return 0;
411}
412
413static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
414{
415 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
416 struct saa7146_dev *saa = budget_ci->budget.dev;
417
418 if (slot != 0)
419 return -EINVAL;
420
421 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
422 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
423 return 0;
424}
425
426static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
427{
428 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
429 struct saa7146_dev *saa = budget_ci->budget.dev;
430 int tmp;
431
432 if (slot != 0)
433 return -EINVAL;
434
435 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
436
437 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
438 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
439 tmp | CICONTROL_ENABLETS, 1, 0);
440
441 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
442 return 0;
443}
444
445static void ciintf_interrupt(unsigned long data)
446{
447 struct budget_ci *budget_ci = (struct budget_ci *) data;
448 struct saa7146_dev *saa = budget_ci->budget.dev;
449 unsigned int flags;
450
451 // ensure we don't get spurious IRQs during initialisation
452 if (!budget_ci->budget.ci_present)
453 return;
454
455 // read the CAM status
456 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
457 if (flags & CICONTROL_CAMDETECT) {
458
459 // GPIO should be set to trigger on falling edge if a CAM is present
460 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
461
462 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
463 // CAM insertion IRQ
464 budget_ci->slot_status = SLOTSTATUS_PRESENT;
465 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
466 DVB_CA_EN50221_CAMCHANGE_INSERTED);
467
468 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
469 // CAM ready (reset completed)
470 budget_ci->slot_status = SLOTSTATUS_READY;
471 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
472
473 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
474 // FR/DA IRQ
475 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
476 }
477 } else {
478
479 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
480 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
481 // the CAM might not actually be ready yet.
482 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
483
484 // generate a CAM removal IRQ if we haven't already
485 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
486 // CAM removal IRQ
487 budget_ci->slot_status = SLOTSTATUS_NONE;
488 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
489 DVB_CA_EN50221_CAMCHANGE_REMOVED);
490 }
491 }
492}
493
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300494static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
495{
496 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
497 unsigned int flags;
498
499 // ensure we don't get spurious IRQs during initialisation
500 if (!budget_ci->budget.ci_present)
501 return -EINVAL;
502
503 // read the CAM status
504 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
505 if (flags & CICONTROL_CAMDETECT) {
506 // mark it as present if it wasn't before
507 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
508 budget_ci->slot_status = SLOTSTATUS_PRESENT;
509 }
510
511 // during a RESET, we check if we can read from IO memory to see when CAM is ready
512 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
513 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
514 budget_ci->slot_status = SLOTSTATUS_READY;
515 }
516 }
517 } else {
518 budget_ci->slot_status = SLOTSTATUS_NONE;
519 }
520
521 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
522 if (budget_ci->slot_status & SLOTSTATUS_READY) {
523 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
524 }
525 return DVB_CA_EN50221_POLL_CAM_PRESENT;
526 }
527
528 return 0;
529}
530
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531static int ciintf_init(struct budget_ci *budget_ci)
532{
533 struct saa7146_dev *saa = budget_ci->budget.dev;
534 int flags;
535 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300536 int ci_version;
537 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
540
541 // enable DEBI pins
542 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
543
544 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300545 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
546 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 result = -ENODEV;
548 goto error;
549 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 // determine whether a CAM is present or not
552 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
553 budget_ci->slot_status = SLOTSTATUS_NONE;
554 if (flags & CICONTROL_CAMDETECT)
555 budget_ci->slot_status = SLOTSTATUS_PRESENT;
556
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300557 // version 0xa2 of the CI firmware doesn't generate interrupts
558 if (ci_version == 0xa2) {
559 ca_flags = 0;
560 budget_ci->ci_irq = 0;
561 } else {
562 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
563 DVB_CA_EN50221_FLAG_IRQ_FR |
564 DVB_CA_EN50221_FLAG_IRQ_DA;
565 budget_ci->ci_irq = 1;
566 }
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 // register CI interface
569 budget_ci->ca.owner = THIS_MODULE;
570 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
571 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
572 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
573 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
574 budget_ci->ca.slot_reset = ciintf_slot_reset;
575 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
576 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300577 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700579 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300581 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 printk("budget_ci: CI interface detected, but initialisation failed.\n");
583 goto error;
584 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300585
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300587 if (budget_ci->ci_irq) {
588 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
589 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
590 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
591 } else {
592 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
593 }
594 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300596
597 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
599 CICONTROL_RESET, 1, 0);
600
601 // success!
602 printk("budget_ci: CI interface initialised\n");
603 budget_ci->budget.ci_present = 1;
604
605 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300606 if (budget_ci->ci_irq) {
607 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
608 if (budget_ci->slot_status != SLOTSTATUS_NONE)
609 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
610 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
611 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 return 0;
614
615error:
616 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
617 return result;
618}
619
620static void ciintf_deinit(struct budget_ci *budget_ci)
621{
622 struct saa7146_dev *saa = budget_ci->budget.dev;
623
624 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300625 if (budget_ci->ci_irq) {
626 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
627 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
628 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
629 }
630
631 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
633 msleep(1);
634 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
635 CICONTROL_RESET, 1, 0);
636
637 // disable TS data stream to CI interface
638 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
639
640 // release the CA device
641 dvb_ca_en50221_release(&budget_ci->ca);
642
643 // disable DEBI pins
644 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
645}
646
647static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
648{
649 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
650
651 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
652
653 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200654 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 if (*isr & MASK_10)
657 ttpci_budget_irq10_handler(dev, isr);
658
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300659 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
661}
662
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663static u8 philips_su1278_tt_inittab[] = {
664 0x01, 0x0f,
665 0x02, 0x30,
666 0x03, 0x00,
667 0x04, 0x5b,
668 0x05, 0x85,
669 0x06, 0x02,
670 0x07, 0x00,
671 0x08, 0x02,
672 0x09, 0x00,
673 0x0C, 0x01,
674 0x0D, 0x81,
675 0x0E, 0x44,
676 0x0f, 0x14,
677 0x10, 0x3c,
678 0x11, 0x84,
679 0x12, 0xda,
680 0x13, 0x97,
681 0x14, 0x95,
682 0x15, 0xc9,
683 0x16, 0x19,
684 0x17, 0x8c,
685 0x18, 0x59,
686 0x19, 0xf8,
687 0x1a, 0xfe,
688 0x1c, 0x7f,
689 0x1d, 0x00,
690 0x1e, 0x00,
691 0x1f, 0x50,
692 0x20, 0x00,
693 0x21, 0x00,
694 0x22, 0x00,
695 0x23, 0x00,
696 0x28, 0x00,
697 0x29, 0x28,
698 0x2a, 0x14,
699 0x2b, 0x0f,
700 0x2c, 0x09,
701 0x2d, 0x09,
702 0x31, 0x1f,
703 0x32, 0x19,
704 0x33, 0xfc,
705 0x34, 0x93,
706 0xff, 0xff
707};
708
709static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
710{
711 stv0299_writereg(fe, 0x0e, 0x44);
712 if (srate >= 10000000) {
713 stv0299_writereg(fe, 0x13, 0x97);
714 stv0299_writereg(fe, 0x14, 0x95);
715 stv0299_writereg(fe, 0x15, 0xc9);
716 stv0299_writereg(fe, 0x17, 0x8c);
717 stv0299_writereg(fe, 0x1a, 0xfe);
718 stv0299_writereg(fe, 0x1c, 0x7f);
719 stv0299_writereg(fe, 0x2d, 0x09);
720 } else {
721 stv0299_writereg(fe, 0x13, 0x99);
722 stv0299_writereg(fe, 0x14, 0x8d);
723 stv0299_writereg(fe, 0x15, 0xce);
724 stv0299_writereg(fe, 0x17, 0x43);
725 stv0299_writereg(fe, 0x1a, 0x1d);
726 stv0299_writereg(fe, 0x1c, 0x12);
727 stv0299_writereg(fe, 0x2d, 0x05);
728 }
729 stv0299_writereg(fe, 0x0e, 0x23);
730 stv0299_writereg(fe, 0x0f, 0x94);
731 stv0299_writereg(fe, 0x10, 0x39);
732 stv0299_writereg(fe, 0x15, 0xc9);
733
734 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
735 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
736 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
737
738 return 0;
739}
740
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300741static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
742 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300744 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 u32 div;
746 u8 buf[4];
747 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
748
749 if ((params->frequency < 950000) || (params->frequency > 2150000))
750 return -EINVAL;
751
752 div = (params->frequency + (500 - 1)) / 500; // round correctly
753 buf[0] = (div >> 8) & 0x7f;
754 buf[1] = div & 0xff;
755 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
756 buf[3] = 0x20;
757
758 if (params->u.qpsk.symbol_rate < 4000000)
759 buf[3] |= 1;
760
761 if (params->frequency < 1250000)
762 buf[3] |= 0;
763 else if (params->frequency < 1550000)
764 buf[3] |= 0x40;
765 else if (params->frequency < 2050000)
766 buf[3] |= 0x80;
767 else if (params->frequency < 2150000)
768 buf[3] |= 0xC0;
769
Patrick Boettcherdea74862006-05-14 05:01:31 -0300770 if (fe->ops.i2c_gate_ctrl)
771 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300772 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 return -EIO;
774 return 0;
775}
776
777static struct stv0299_config philips_su1278_tt_config = {
778
779 .demod_address = 0x68,
780 .inittab = philips_su1278_tt_inittab,
781 .mclk = 64000000UL,
782 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 .skip_reinit = 1,
784 .lock_output = STV0229_LOCKOUTPUT_1,
785 .volt13_op0_op1 = STV0299_VOLT13_OP1,
786 .min_delay_ms = 50,
787 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700788};
789
790
791
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300792static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793{
794 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
795 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
796 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700797 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 sizeof(td1316_init) };
799
800 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300801 if (fe->ops.i2c_gate_ctrl)
802 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700803 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
804 return -EIO;
805 msleep(1);
806
807 // disable the mc44BC374c (do not check for errors)
808 tuner_msg.addr = 0x65;
809 tuner_msg.buf = disable_mc44BC374c;
810 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300811 if (fe->ops.i2c_gate_ctrl)
812 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300814 if (fe->ops.i2c_gate_ctrl)
815 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
817 }
818
819 return 0;
820}
821
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300822static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823{
824 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
825 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700826 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 -0700827 int tuner_frequency = 0;
828 u8 band, cp, filter;
829
830 // determine charge pump
831 tuner_frequency = params->frequency + 36130000;
832 if (tuner_frequency < 87000000)
833 return -EINVAL;
834 else if (tuner_frequency < 130000000)
835 cp = 3;
836 else if (tuner_frequency < 160000000)
837 cp = 5;
838 else if (tuner_frequency < 200000000)
839 cp = 6;
840 else if (tuner_frequency < 290000000)
841 cp = 3;
842 else if (tuner_frequency < 420000000)
843 cp = 5;
844 else if (tuner_frequency < 480000000)
845 cp = 6;
846 else if (tuner_frequency < 620000000)
847 cp = 3;
848 else if (tuner_frequency < 830000000)
849 cp = 5;
850 else if (tuner_frequency < 895000000)
851 cp = 7;
852 else
853 return -EINVAL;
854
855 // determine band
856 if (params->frequency < 49000000)
857 return -EINVAL;
858 else if (params->frequency < 159000000)
859 band = 1;
860 else if (params->frequency < 444000000)
861 band = 2;
862 else if (params->frequency < 861000000)
863 band = 4;
864 else
865 return -EINVAL;
866
867 // setup PLL filter and TDA9889
868 switch (params->u.ofdm.bandwidth) {
869 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300870 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871 filter = 0;
872 break;
873
874 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300875 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 filter = 0;
877 break;
878
879 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300880 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 filter = 1;
882 break;
883
884 default:
885 return -EINVAL;
886 }
887
888 // calculate divisor
889 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
890 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
891
892 // setup tuner buffer
893 tuner_buf[0] = tuner_frequency >> 8;
894 tuner_buf[1] = tuner_frequency & 0xff;
895 tuner_buf[2] = 0xca;
896 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
897
Patrick Boettcherdea74862006-05-14 05:01:31 -0300898 if (fe->ops.i2c_gate_ctrl)
899 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
901 return -EIO;
902
903 msleep(1);
904 return 0;
905}
906
907static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
908 const struct firmware **fw, char *name)
909{
910 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
911
912 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
913}
914
915static struct tda1004x_config philips_tdm1316l_config = {
916
917 .demod_address = 0x8,
918 .invert = 0,
919 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700920 .xtal_freq = TDA10046_XTAL_4M,
921 .agc_config = TDA10046_AGC_DEFAULT,
922 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 .request_firmware = philips_tdm1316l_request_firmware,
924};
925
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300926static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700927{
928 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
929 u8 tuner_buf[5];
930 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
931 .flags = 0,
932 .buf = tuner_buf,
933 .len = sizeof(tuner_buf) };
934 int tuner_frequency = 0;
935 u8 band, cp, filter;
936
937 // determine charge pump
938 tuner_frequency = params->frequency + 36125000;
939 if (tuner_frequency < 87000000)
940 return -EINVAL;
941 else if (tuner_frequency < 130000000) {
942 cp = 3;
943 band = 1;
944 } else if (tuner_frequency < 160000000) {
945 cp = 5;
946 band = 1;
947 } else if (tuner_frequency < 200000000) {
948 cp = 6;
Thomas Kaiser9abec612006-11-22 18:15:19 -0300949 band = 2;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700950 } else if (tuner_frequency < 290000000) {
951 cp = 3;
952 band = 2;
953 } else if (tuner_frequency < 420000000) {
954 cp = 5;
955 band = 2;
956 } else if (tuner_frequency < 480000000) {
957 cp = 6;
958 band = 2;
959 } else if (tuner_frequency < 620000000) {
960 cp = 3;
961 band = 4;
962 } else if (tuner_frequency < 830000000) {
963 cp = 5;
964 band = 4;
965 } else if (tuner_frequency < 895000000) {
966 cp = 7;
967 band = 4;
968 } else
969 return -EINVAL;
970
971 // assume PLL filter should always be 8MHz for the moment.
972 filter = 1;
973
974 // calculate divisor
975 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
976
977 // setup tuner buffer
978 tuner_buf[0] = tuner_frequency >> 8;
979 tuner_buf[1] = tuner_frequency & 0xff;
980 tuner_buf[2] = 0xc8;
981 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
982 tuner_buf[4] = 0x80;
983
Patrick Boettcherdea74862006-05-14 05:01:31 -0300984 if (fe->ops.i2c_gate_ctrl)
985 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700986 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
987 return -EIO;
988
989 msleep(50);
990
Patrick Boettcherdea74862006-05-14 05:01:31 -0300991 if (fe->ops.i2c_gate_ctrl)
992 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700993 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
994 return -EIO;
995
996 msleep(1);
997
998 return 0;
999}
1000
1001static u8 dvbc_philips_tdm1316l_inittab[] = {
1002 0x80, 0x01,
1003 0x80, 0x00,
1004 0x81, 0x01,
1005 0x81, 0x00,
1006 0x00, 0x09,
1007 0x01, 0x69,
1008 0x03, 0x00,
1009 0x04, 0x00,
1010 0x07, 0x00,
1011 0x08, 0x00,
1012 0x20, 0x00,
1013 0x21, 0x40,
1014 0x22, 0x00,
1015 0x23, 0x00,
1016 0x24, 0x40,
1017 0x25, 0x88,
1018 0x30, 0xff,
1019 0x31, 0x00,
1020 0x32, 0xff,
1021 0x33, 0x00,
1022 0x34, 0x50,
1023 0x35, 0x7f,
1024 0x36, 0x00,
1025 0x37, 0x20,
1026 0x38, 0x00,
1027 0x40, 0x1c,
1028 0x41, 0xff,
1029 0x42, 0x29,
1030 0x43, 0x20,
1031 0x44, 0xff,
1032 0x45, 0x00,
1033 0x46, 0x00,
1034 0x49, 0x04,
1035 0x4a, 0x00,
1036 0x4b, 0x7b,
1037 0x52, 0x30,
1038 0x55, 0xae,
1039 0x56, 0x47,
1040 0x57, 0xe1,
1041 0x58, 0x3a,
1042 0x5a, 0x1e,
1043 0x5b, 0x34,
1044 0x60, 0x00,
1045 0x63, 0x00,
1046 0x64, 0x00,
1047 0x65, 0x00,
1048 0x66, 0x00,
1049 0x67, 0x00,
1050 0x68, 0x00,
1051 0x69, 0x00,
1052 0x6a, 0x02,
1053 0x6b, 0x00,
1054 0x70, 0xff,
1055 0x71, 0x00,
1056 0x72, 0x00,
1057 0x73, 0x00,
1058 0x74, 0x0c,
1059 0x80, 0x00,
1060 0x81, 0x00,
1061 0x82, 0x00,
1062 0x83, 0x00,
1063 0x84, 0x04,
1064 0x85, 0x80,
1065 0x86, 0x24,
1066 0x87, 0x78,
1067 0x88, 0x10,
1068 0x89, 0x00,
1069 0x90, 0x01,
1070 0x91, 0x01,
1071 0xa0, 0x04,
1072 0xa1, 0x00,
1073 0xa2, 0x00,
1074 0xb0, 0x91,
1075 0xb1, 0x0b,
1076 0xc0, 0x53,
1077 0xc1, 0x70,
1078 0xc2, 0x12,
1079 0xd0, 0x00,
1080 0xd1, 0x00,
1081 0xd2, 0x00,
1082 0xd3, 0x00,
1083 0xd4, 0x00,
1084 0xd5, 0x00,
1085 0xde, 0x00,
1086 0xdf, 0x00,
1087 0x61, 0x38,
1088 0x62, 0x0a,
1089 0x53, 0x13,
1090 0x59, 0x08,
1091 0xff, 0xff,
1092};
1093
1094static struct stv0297_config dvbc_philips_tdm1316l_config = {
1095 .demod_address = 0x1c,
1096 .inittab = dvbc_philips_tdm1316l_inittab,
1097 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001098 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001099};
1100
1101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
1103
1104static void frontend_init(struct budget_ci *budget_ci)
1105{
1106 switch (budget_ci->budget.dev->pci->subsystem_device) {
1107 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1108 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001109 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001111 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001112 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 break;
1114 }
1115 break;
1116
1117 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1118 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001119 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001121 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122 break;
1123 }
1124 break;
1125
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001126 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1127 budget_ci->tuner_pll_address = 0x61;
1128 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001129 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001130 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001131 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001132 break;
1133 }
1134 break;
1135
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001137 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001139 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001141 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1142 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143 break;
1144 }
1145 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001146
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001147 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001148 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001149 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001150 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001151 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001152 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001153 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1154 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001155 break;
1156 }
1157 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001158
1159 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001160 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001161 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001162 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001163 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1164
Patrick Boettcherdea74862006-05-14 05:01:31 -03001165 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001166 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 -03001167 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001168 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001169 budget_ci->budget.dvb_frontend = NULL;
1170 }
1171 }
1172
1173 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 }
1175
1176 if (budget_ci->budget.dvb_frontend == NULL) {
1177 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1178 budget_ci->budget.dev->pci->vendor,
1179 budget_ci->budget.dev->pci->device,
1180 budget_ci->budget.dev->pci->subsystem_vendor,
1181 budget_ci->budget.dev->pci->subsystem_device);
1182 } else {
1183 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001184 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001186 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 budget_ci->budget.dvb_frontend = NULL;
1188 }
1189 }
1190}
1191
1192static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1193{
1194 struct budget_ci *budget_ci;
1195 int err;
1196
David Hardemanee579bc2006-12-02 21:16:05 -02001197 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001198 if (!budget_ci) {
1199 err = -ENOMEM;
1200 goto out1;
1201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202
1203 dprintk(2, "budget_ci: %p\n", budget_ci);
1204
Linus Torvalds1da177e2005-04-16 15:20:36 -07001205 dev->ext_priv = budget_ci;
1206
David Hardeman8cc532e2006-12-02 21:16:05 -02001207 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1208 if (err)
1209 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
David Hardeman8cc532e2006-12-02 21:16:05 -02001211 err = msp430_ir_init(budget_ci);
1212 if (err)
1213 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214
1215 ciintf_init(budget_ci);
1216
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001217 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 frontend_init(budget_ci);
1219
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001220 ttpci_budget_init_hooks(&budget_ci->budget);
1221
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001223
1224out3:
1225 ttpci_budget_deinit(&budget_ci->budget);
1226out2:
1227 kfree(budget_ci);
1228out1:
1229 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001230}
1231
1232static int budget_ci_detach(struct saa7146_dev *dev)
1233{
1234 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1235 struct saa7146_dev *saa = budget_ci->budget.dev;
1236 int err;
1237
1238 if (budget_ci->budget.ci_present)
1239 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001240 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001241 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001243 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 err = ttpci_budget_deinit(&budget_ci->budget);
1246
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 // disable frontend and CI interface
1248 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1249
1250 kfree(budget_ci);
1251
1252 return err;
1253}
1254
1255static struct saa7146_extension budget_extension;
1256
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001257MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1259MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001260MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001261MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001262
1263static struct pci_device_id pci_tbl[] = {
1264 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1265 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001266 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001268 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001269 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 {
1271 .vendor = 0,
1272 }
1273};
1274
1275MODULE_DEVICE_TABLE(pci, pci_tbl);
1276
1277static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001278 .name = "budget_ci dvb",
Oliver Endriss69459f3d2005-12-01 00:51:48 -08001279 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
1281 .module = THIS_MODULE,
1282 .pci_tbl = &pci_tbl[0],
1283 .attach = budget_ci_attach,
1284 .detach = budget_ci_detach,
1285
1286 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1287 .irq_func = budget_ci_irq,
1288};
1289
1290static int __init budget_ci_init(void)
1291{
1292 return saa7146_register_extension(&budget_extension);
1293}
1294
1295static void __exit budget_ci_exit(void)
1296{
1297 saa7146_unregister_extension(&budget_extension);
1298}
1299
1300module_init(budget_ci_init);
1301module_exit(budget_ci_exit);
1302
1303MODULE_LICENSE("GPL");
1304MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1305MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1306 "budget PCI DVB cards w/ CI-module produced by "
1307 "Siemens, Technotrend, Hauppauge");