blob: 464feaf1a9ad2401afbeeb686b0996b36765aa5d [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
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/module.h>
33#include <linux/errno.h>
34#include <linux/slab.h>
35#include <linux/interrupt.h>
36#include <linux/input.h>
37#include <linux/spinlock.h>
David Hardeman2520fff2006-12-02 21:16:05 -020038#include <media/ir-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Trent Piepho68277092007-01-30 23:25:46 -030040#include "budget.h"
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#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 Härdeman59327a42007-02-13 09:39:58 -0300133 static int state = 0;
David Hardeman2520fff2006-12-02 21:16:05 -0200134 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
135
David Hardeman64741b72006-12-02 21:16:05 -0200136 /*
137 * The msp430 chip can generate two different bytes, command and device
138 *
139 * type1: X1CCCCCC, C = command bits (0 - 63)
140 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
141 *
David Härdeman59327a42007-02-13 09:39:58 -0300142 * Each signal from the remote control can generate one or more command
143 * bytes and one or more device bytes. For the repeated bytes, the
144 * highest bit (X) is set. The first command byte is always generated
145 * before the first device byte. Other than that, no specific order
146 * seems to apply.
147 *
148 * Only when we have a command and device byte, a keypress is
149 * generated.
David Hardeman64741b72006-12-02 21:16:05 -0200150 */
151
David Härdeman59327a42007-02-13 09:39:58 -0300152 if (ir_debug)
153 printk("budget_ci: received byte 0x%02x\n", command);
154
155 /* Is this a repeated byte? */
156 if (command & 0x80)
157 return;
158
David Hardeman64741b72006-12-02 21:16:05 -0200159 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200160 if (command & 0x40) {
David Härdeman59327a42007-02-13 09:39:58 -0300161 state = 1;
David Hardeman2520fff2006-12-02 21:16:05 -0200162 ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200163 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200164 }
David Hardeman64741b72006-12-02 21:16:05 -0200165
166 /* It's a RC5 device byte */
David Härdeman59327a42007-02-13 09:39:58 -0300167 if (!state)
168 return;
169 state = 0;
David Hardeman64741b72006-12-02 21:16:05 -0200170 device = command & 0x1f;
171 toggle = command & 0x20;
172
173 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device)
174 return;
175
David Hardeman64741b72006-12-02 21:16:05 -0200176 /* Ignore repeated key sequences if requested */
David Hardeman59236d42006-12-02 21:16:06 -0200177 if (toggle == prev_toggle && ir_key == dev->repeat_key &&
178 bounces > 0 && timer_pending(&dev->timer)) {
179 if (ir_debug)
180 printk("budget_ci: debounce logic ignored IR command\n");
David Hardeman64741b72006-12-02 21:16:05 -0200181 bounces--;
182 return;
183 }
David Hardeman59236d42006-12-02 21:16:06 -0200184 prev_toggle = toggle;
David Hardeman64741b72006-12-02 21:16:05 -0200185
David Hardeman59236d42006-12-02 21:16:06 -0200186 /* Are we still waiting for a keyup event? */
187 if (del_timer(&dev->timer))
188 ir_input_nokey(dev, &budget_ci->ir.state);
189
190 /* Generate keypress */
191 if (ir_debug)
192 printk("budget_ci: generating keypress 0x%02x\n", ir_key);
193 ir_input_keydown(dev, &budget_ci->ir.state, ir_key, (ir_key & (command << 8)));
194
195 /* Do we want to delay the keyup event? */
196 if (debounce) {
David Hardeman64741b72006-12-02 21:16:05 -0200197 bounces = debounce;
David Hardeman59236d42006-12-02 21:16:06 -0200198 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT));
199 } else {
200 ir_input_nokey(dev, &budget_ci->ir.state);
201 }
David Hardeman2520fff2006-12-02 21:16:05 -0200202}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204static int msp430_ir_init(struct budget_ci *budget_ci)
205{
206 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200207 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200208 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
David Hardemandd2f3982006-12-02 21:16:05 -0200210 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200211 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200212 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200213 error = -ENOMEM;
214 goto out1;
215 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216
David Hardemandd2f3982006-12-02 21:16:05 -0200217 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
218 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200219 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
220 "pci-%s/ir0", pci_name(saa->pci));
221
David Hardemandd2f3982006-12-02 21:16:05 -0200222 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223
David Hardeman5cc8ae02006-12-02 21:16:05 -0200224 input_dev->phys = budget_ci->ir.phys;
225 input_dev->id.bustype = BUS_PCI;
226 input_dev->id.version = 1;
227 if (saa->pci->subsystem_vendor) {
228 input_dev->id.vendor = saa->pci->subsystem_vendor;
229 input_dev->id.product = saa->pci->subsystem_device;
230 } else {
231 input_dev->id.vendor = saa->pci->vendor;
232 input_dev->id.product = saa->pci->device;
233 }
David Hardeman5cc8ae02006-12-02 21:16:05 -0200234 input_dev->cdev.dev = &saa->pci->dev;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200235
David Hardeman64741b72006-12-02 21:16:05 -0200236 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200237 switch (budget_ci->budget.dev->pci->subsystem_device) {
238 case 0x100c:
239 case 0x100f:
David Hardeman2520fff2006-12-02 21:16:05 -0200240 case 0x1011:
241 case 0x1012:
242 case 0x1017:
243 /* The hauppauge keymap is a superset of these remotes */
244 ir_input_init(input_dev, &budget_ci->ir.state,
245 IR_TYPE_RC5, ir_codes_hauppauge_new);
David Hardeman64741b72006-12-02 21:16:05 -0200246
247 if (rc5_device < 0)
248 budget_ci->ir.rc5_device = 0x1f;
249 else
250 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200251 break;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300252 case 0x1010:
253 /* for the Technotrend 1500 bundled remote */
254 ir_input_init(input_dev, &budget_ci->ir.state,
255 IR_TYPE_RC5, ir_codes_tt_1500);
256
257 if (rc5_device < 0)
258 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
259 else
260 budget_ci->ir.rc5_device = rc5_device;
261 break;
David Hardeman2520fff2006-12-02 21:16:05 -0200262 default:
263 /* unknown remote */
264 ir_input_init(input_dev, &budget_ci->ir.state,
265 IR_TYPE_RC5, ir_codes_budget_ci_old);
David Hardeman64741b72006-12-02 21:16:05 -0200266
267 if (rc5_device < 0)
268 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
269 else
270 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200271 break;
272 }
273
David Hardeman59236d42006-12-02 21:16:06 -0200274 /* initialise the key-up debounce timeout handler */
David Hardeman2520fff2006-12-02 21:16:05 -0200275 input_dev->timer.function = msp430_ir_keyup;
276 input_dev->timer.data = (unsigned long) &budget_ci->ir;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
David Hardeman8cc532e2006-12-02 21:16:05 -0200278 error = input_register_device(input_dev);
279 if (error) {
280 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
281 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300282 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283
David Hardeman8cc532e2006-12-02 21:16:05 -0200284 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
285 (unsigned long) budget_ci);
286
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300287 SAA7146_IER_ENABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
289
290 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200291
292out2:
293 input_free_device(input_dev);
294out1:
295 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296}
297
298static void msp430_ir_deinit(struct budget_ci *budget_ci)
299{
300 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200301 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300303 SAA7146_IER_DISABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200305 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300307 if (del_timer(&dev->timer)) {
David Hardeman2520fff2006-12-02 21:16:05 -0200308 ir_input_nokey(dev, &budget_ci->ir.state);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300309 input_sync(dev);
310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
312 input_unregister_device(dev);
313}
314
315static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
316{
317 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
318
319 if (slot != 0)
320 return -EINVAL;
321
322 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
323 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
324}
325
326static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
327{
328 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
329
330 if (slot != 0)
331 return -EINVAL;
332
333 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
334 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
335}
336
337static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
338{
339 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
340
341 if (slot != 0)
342 return -EINVAL;
343
344 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
345 DEBIADDR_IO | (address & 3), 1, 1, 0);
346}
347
348static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
349{
350 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
351
352 if (slot != 0)
353 return -EINVAL;
354
355 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
356 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
357}
358
359static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
360{
361 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
362 struct saa7146_dev *saa = budget_ci->budget.dev;
363
364 if (slot != 0)
365 return -EINVAL;
366
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300367 if (budget_ci->ci_irq) {
368 // trigger on RISING edge during reset so we know when READY is re-asserted
369 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
370 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371 budget_ci->slot_status = SLOTSTATUS_RESET;
372 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
373 msleep(1);
374 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
375 CICONTROL_RESET, 1, 0);
376
377 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
378 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
379 return 0;
380}
381
382static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
383{
384 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
385 struct saa7146_dev *saa = budget_ci->budget.dev;
386
387 if (slot != 0)
388 return -EINVAL;
389
390 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
391 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
392 return 0;
393}
394
395static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
396{
397 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
398 struct saa7146_dev *saa = budget_ci->budget.dev;
399 int tmp;
400
401 if (slot != 0)
402 return -EINVAL;
403
404 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
405
406 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
407 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
408 tmp | CICONTROL_ENABLETS, 1, 0);
409
410 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
411 return 0;
412}
413
414static void ciintf_interrupt(unsigned long data)
415{
416 struct budget_ci *budget_ci = (struct budget_ci *) data;
417 struct saa7146_dev *saa = budget_ci->budget.dev;
418 unsigned int flags;
419
420 // ensure we don't get spurious IRQs during initialisation
421 if (!budget_ci->budget.ci_present)
422 return;
423
424 // read the CAM status
425 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
426 if (flags & CICONTROL_CAMDETECT) {
427
428 // GPIO should be set to trigger on falling edge if a CAM is present
429 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
430
431 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
432 // CAM insertion IRQ
433 budget_ci->slot_status = SLOTSTATUS_PRESENT;
434 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
435 DVB_CA_EN50221_CAMCHANGE_INSERTED);
436
437 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
438 // CAM ready (reset completed)
439 budget_ci->slot_status = SLOTSTATUS_READY;
440 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
441
442 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
443 // FR/DA IRQ
444 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
445 }
446 } else {
447
448 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
449 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
450 // the CAM might not actually be ready yet.
451 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
452
453 // generate a CAM removal IRQ if we haven't already
454 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
455 // CAM removal IRQ
456 budget_ci->slot_status = SLOTSTATUS_NONE;
457 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
458 DVB_CA_EN50221_CAMCHANGE_REMOVED);
459 }
460 }
461}
462
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300463static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
464{
465 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
466 unsigned int flags;
467
468 // ensure we don't get spurious IRQs during initialisation
469 if (!budget_ci->budget.ci_present)
470 return -EINVAL;
471
472 // read the CAM status
473 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
474 if (flags & CICONTROL_CAMDETECT) {
475 // mark it as present if it wasn't before
476 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
477 budget_ci->slot_status = SLOTSTATUS_PRESENT;
478 }
479
480 // during a RESET, we check if we can read from IO memory to see when CAM is ready
481 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
482 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
483 budget_ci->slot_status = SLOTSTATUS_READY;
484 }
485 }
486 } else {
487 budget_ci->slot_status = SLOTSTATUS_NONE;
488 }
489
490 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
491 if (budget_ci->slot_status & SLOTSTATUS_READY) {
492 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
493 }
494 return DVB_CA_EN50221_POLL_CAM_PRESENT;
495 }
496
497 return 0;
498}
499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500static int ciintf_init(struct budget_ci *budget_ci)
501{
502 struct saa7146_dev *saa = budget_ci->budget.dev;
503 int flags;
504 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300505 int ci_version;
506 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507
508 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
509
510 // enable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300511 saa7146_write(saa, MC1, MASK_27 | MASK_11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512
513 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300514 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
515 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 result = -ENODEV;
517 goto error;
518 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 // determine whether a CAM is present or not
521 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
522 budget_ci->slot_status = SLOTSTATUS_NONE;
523 if (flags & CICONTROL_CAMDETECT)
524 budget_ci->slot_status = SLOTSTATUS_PRESENT;
525
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300526 // version 0xa2 of the CI firmware doesn't generate interrupts
527 if (ci_version == 0xa2) {
528 ca_flags = 0;
529 budget_ci->ci_irq = 0;
530 } else {
531 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
532 DVB_CA_EN50221_FLAG_IRQ_FR |
533 DVB_CA_EN50221_FLAG_IRQ_DA;
534 budget_ci->ci_irq = 1;
535 }
536
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 // register CI interface
538 budget_ci->ca.owner = THIS_MODULE;
539 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
540 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
541 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
542 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
543 budget_ci->ca.slot_reset = ciintf_slot_reset;
544 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
545 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300546 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700548 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700549 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300550 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 printk("budget_ci: CI interface detected, but initialisation failed.\n");
552 goto error;
553 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300556 if (budget_ci->ci_irq) {
557 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
558 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
559 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
560 } else {
561 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
562 }
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300563 SAA7146_IER_ENABLE(saa, MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300565
566 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
568 CICONTROL_RESET, 1, 0);
569
570 // success!
571 printk("budget_ci: CI interface initialised\n");
572 budget_ci->budget.ci_present = 1;
573
574 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300575 if (budget_ci->ci_irq) {
576 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
577 if (budget_ci->slot_status != SLOTSTATUS_NONE)
578 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
579 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
580 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581
582 return 0;
583
584error:
Hartmut Birr2a893de2006-12-03 21:08:08 -0300585 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586 return result;
587}
588
589static void ciintf_deinit(struct budget_ci *budget_ci)
590{
591 struct saa7146_dev *saa = budget_ci->budget.dev;
592
593 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300594 if (budget_ci->ci_irq) {
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300595 SAA7146_IER_DISABLE(saa, MASK_03);
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300596 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
597 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
598 }
599
600 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
602 msleep(1);
603 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
604 CICONTROL_RESET, 1, 0);
605
606 // disable TS data stream to CI interface
607 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
608
609 // release the CA device
610 dvb_ca_en50221_release(&budget_ci->ca);
611
612 // disable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300613 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614}
615
616static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
617{
618 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
619
620 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
621
622 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200623 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624
625 if (*isr & MASK_10)
626 ttpci_budget_irq10_handler(dev, isr);
627
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300628 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
630}
631
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632static u8 philips_su1278_tt_inittab[] = {
633 0x01, 0x0f,
634 0x02, 0x30,
635 0x03, 0x00,
636 0x04, 0x5b,
637 0x05, 0x85,
638 0x06, 0x02,
639 0x07, 0x00,
640 0x08, 0x02,
641 0x09, 0x00,
642 0x0C, 0x01,
643 0x0D, 0x81,
644 0x0E, 0x44,
645 0x0f, 0x14,
646 0x10, 0x3c,
647 0x11, 0x84,
648 0x12, 0xda,
649 0x13, 0x97,
650 0x14, 0x95,
651 0x15, 0xc9,
652 0x16, 0x19,
653 0x17, 0x8c,
654 0x18, 0x59,
655 0x19, 0xf8,
656 0x1a, 0xfe,
657 0x1c, 0x7f,
658 0x1d, 0x00,
659 0x1e, 0x00,
660 0x1f, 0x50,
661 0x20, 0x00,
662 0x21, 0x00,
663 0x22, 0x00,
664 0x23, 0x00,
665 0x28, 0x00,
666 0x29, 0x28,
667 0x2a, 0x14,
668 0x2b, 0x0f,
669 0x2c, 0x09,
670 0x2d, 0x09,
671 0x31, 0x1f,
672 0x32, 0x19,
673 0x33, 0xfc,
674 0x34, 0x93,
675 0xff, 0xff
676};
677
678static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
679{
680 stv0299_writereg(fe, 0x0e, 0x44);
681 if (srate >= 10000000) {
682 stv0299_writereg(fe, 0x13, 0x97);
683 stv0299_writereg(fe, 0x14, 0x95);
684 stv0299_writereg(fe, 0x15, 0xc9);
685 stv0299_writereg(fe, 0x17, 0x8c);
686 stv0299_writereg(fe, 0x1a, 0xfe);
687 stv0299_writereg(fe, 0x1c, 0x7f);
688 stv0299_writereg(fe, 0x2d, 0x09);
689 } else {
690 stv0299_writereg(fe, 0x13, 0x99);
691 stv0299_writereg(fe, 0x14, 0x8d);
692 stv0299_writereg(fe, 0x15, 0xce);
693 stv0299_writereg(fe, 0x17, 0x43);
694 stv0299_writereg(fe, 0x1a, 0x1d);
695 stv0299_writereg(fe, 0x1c, 0x12);
696 stv0299_writereg(fe, 0x2d, 0x05);
697 }
698 stv0299_writereg(fe, 0x0e, 0x23);
699 stv0299_writereg(fe, 0x0f, 0x94);
700 stv0299_writereg(fe, 0x10, 0x39);
701 stv0299_writereg(fe, 0x15, 0xc9);
702
703 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
704 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
705 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
706
707 return 0;
708}
709
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300710static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
711 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300713 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 u32 div;
715 u8 buf[4];
716 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
717
718 if ((params->frequency < 950000) || (params->frequency > 2150000))
719 return -EINVAL;
720
721 div = (params->frequency + (500 - 1)) / 500; // round correctly
722 buf[0] = (div >> 8) & 0x7f;
723 buf[1] = div & 0xff;
724 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
725 buf[3] = 0x20;
726
727 if (params->u.qpsk.symbol_rate < 4000000)
728 buf[3] |= 1;
729
730 if (params->frequency < 1250000)
731 buf[3] |= 0;
732 else if (params->frequency < 1550000)
733 buf[3] |= 0x40;
734 else if (params->frequency < 2050000)
735 buf[3] |= 0x80;
736 else if (params->frequency < 2150000)
737 buf[3] |= 0xC0;
738
Patrick Boettcherdea74862006-05-14 05:01:31 -0300739 if (fe->ops.i2c_gate_ctrl)
740 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300741 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 return -EIO;
743 return 0;
744}
745
746static struct stv0299_config philips_su1278_tt_config = {
747
748 .demod_address = 0x68,
749 .inittab = philips_su1278_tt_inittab,
750 .mclk = 64000000UL,
751 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 .skip_reinit = 1,
753 .lock_output = STV0229_LOCKOUTPUT_1,
754 .volt13_op0_op1 = STV0299_VOLT13_OP1,
755 .min_delay_ms = 50,
756 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700757};
758
759
760
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300761static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762{
763 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
764 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
765 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700766 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767 sizeof(td1316_init) };
768
769 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300770 if (fe->ops.i2c_gate_ctrl)
771 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
773 return -EIO;
774 msleep(1);
775
776 // disable the mc44BC374c (do not check for errors)
777 tuner_msg.addr = 0x65;
778 tuner_msg.buf = disable_mc44BC374c;
779 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300780 if (fe->ops.i2c_gate_ctrl)
781 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300783 if (fe->ops.i2c_gate_ctrl)
784 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
786 }
787
788 return 0;
789}
790
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300791static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792{
793 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
794 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700795 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 -0700796 int tuner_frequency = 0;
797 u8 band, cp, filter;
798
799 // determine charge pump
800 tuner_frequency = params->frequency + 36130000;
801 if (tuner_frequency < 87000000)
802 return -EINVAL;
803 else if (tuner_frequency < 130000000)
804 cp = 3;
805 else if (tuner_frequency < 160000000)
806 cp = 5;
807 else if (tuner_frequency < 200000000)
808 cp = 6;
809 else if (tuner_frequency < 290000000)
810 cp = 3;
811 else if (tuner_frequency < 420000000)
812 cp = 5;
813 else if (tuner_frequency < 480000000)
814 cp = 6;
815 else if (tuner_frequency < 620000000)
816 cp = 3;
817 else if (tuner_frequency < 830000000)
818 cp = 5;
819 else if (tuner_frequency < 895000000)
820 cp = 7;
821 else
822 return -EINVAL;
823
824 // determine band
825 if (params->frequency < 49000000)
826 return -EINVAL;
827 else if (params->frequency < 159000000)
828 band = 1;
829 else if (params->frequency < 444000000)
830 band = 2;
831 else if (params->frequency < 861000000)
832 band = 4;
833 else
834 return -EINVAL;
835
836 // setup PLL filter and TDA9889
837 switch (params->u.ofdm.bandwidth) {
838 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300839 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840 filter = 0;
841 break;
842
843 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300844 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 filter = 0;
846 break;
847
848 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300849 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 filter = 1;
851 break;
852
853 default:
854 return -EINVAL;
855 }
856
857 // calculate divisor
858 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
859 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
860
861 // setup tuner buffer
862 tuner_buf[0] = tuner_frequency >> 8;
863 tuner_buf[1] = tuner_frequency & 0xff;
864 tuner_buf[2] = 0xca;
865 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
866
Patrick Boettcherdea74862006-05-14 05:01:31 -0300867 if (fe->ops.i2c_gate_ctrl)
868 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
870 return -EIO;
871
872 msleep(1);
873 return 0;
874}
875
876static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
877 const struct firmware **fw, char *name)
878{
879 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
880
881 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
882}
883
884static struct tda1004x_config philips_tdm1316l_config = {
885
886 .demod_address = 0x8,
887 .invert = 0,
888 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700889 .xtal_freq = TDA10046_XTAL_4M,
890 .agc_config = TDA10046_AGC_DEFAULT,
891 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 .request_firmware = philips_tdm1316l_request_firmware,
893};
894
Oliver Endriss6c914492007-02-02 19:12:53 -0300895static struct tda1004x_config philips_tdm1316l_config_invert = {
896
897 .demod_address = 0x8,
898 .invert = 1,
899 .invert_oclk = 0,
900 .xtal_freq = TDA10046_XTAL_4M,
901 .agc_config = TDA10046_AGC_DEFAULT,
902 .if_freq = TDA10046_FREQ_3617,
903 .request_firmware = philips_tdm1316l_request_firmware,
904};
905
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300906static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700907{
908 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
909 u8 tuner_buf[5];
910 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
911 .flags = 0,
912 .buf = tuner_buf,
913 .len = sizeof(tuner_buf) };
914 int tuner_frequency = 0;
915 u8 band, cp, filter;
916
917 // determine charge pump
918 tuner_frequency = params->frequency + 36125000;
919 if (tuner_frequency < 87000000)
920 return -EINVAL;
921 else if (tuner_frequency < 130000000) {
922 cp = 3;
923 band = 1;
924 } else if (tuner_frequency < 160000000) {
925 cp = 5;
926 band = 1;
927 } else if (tuner_frequency < 200000000) {
928 cp = 6;
Thomas Kaiser9abec612006-11-22 18:15:19 -0300929 band = 2;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700930 } else if (tuner_frequency < 290000000) {
931 cp = 3;
932 band = 2;
933 } else if (tuner_frequency < 420000000) {
934 cp = 5;
935 band = 2;
936 } else if (tuner_frequency < 480000000) {
937 cp = 6;
938 band = 2;
939 } else if (tuner_frequency < 620000000) {
940 cp = 3;
941 band = 4;
942 } else if (tuner_frequency < 830000000) {
943 cp = 5;
944 band = 4;
945 } else if (tuner_frequency < 895000000) {
946 cp = 7;
947 band = 4;
948 } else
949 return -EINVAL;
950
951 // assume PLL filter should always be 8MHz for the moment.
952 filter = 1;
953
954 // calculate divisor
955 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
956
957 // setup tuner buffer
958 tuner_buf[0] = tuner_frequency >> 8;
959 tuner_buf[1] = tuner_frequency & 0xff;
960 tuner_buf[2] = 0xc8;
961 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
962 tuner_buf[4] = 0x80;
963
Patrick Boettcherdea74862006-05-14 05:01:31 -0300964 if (fe->ops.i2c_gate_ctrl)
965 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700966 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
967 return -EIO;
968
969 msleep(50);
970
Patrick Boettcherdea74862006-05-14 05:01:31 -0300971 if (fe->ops.i2c_gate_ctrl)
972 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700973 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
974 return -EIO;
975
976 msleep(1);
977
978 return 0;
979}
980
981static u8 dvbc_philips_tdm1316l_inittab[] = {
982 0x80, 0x01,
983 0x80, 0x00,
984 0x81, 0x01,
985 0x81, 0x00,
986 0x00, 0x09,
987 0x01, 0x69,
988 0x03, 0x00,
989 0x04, 0x00,
990 0x07, 0x00,
991 0x08, 0x00,
992 0x20, 0x00,
993 0x21, 0x40,
994 0x22, 0x00,
995 0x23, 0x00,
996 0x24, 0x40,
997 0x25, 0x88,
998 0x30, 0xff,
999 0x31, 0x00,
1000 0x32, 0xff,
1001 0x33, 0x00,
1002 0x34, 0x50,
1003 0x35, 0x7f,
1004 0x36, 0x00,
1005 0x37, 0x20,
1006 0x38, 0x00,
1007 0x40, 0x1c,
1008 0x41, 0xff,
1009 0x42, 0x29,
1010 0x43, 0x20,
1011 0x44, 0xff,
1012 0x45, 0x00,
1013 0x46, 0x00,
1014 0x49, 0x04,
1015 0x4a, 0x00,
1016 0x4b, 0x7b,
1017 0x52, 0x30,
1018 0x55, 0xae,
1019 0x56, 0x47,
1020 0x57, 0xe1,
1021 0x58, 0x3a,
1022 0x5a, 0x1e,
1023 0x5b, 0x34,
1024 0x60, 0x00,
1025 0x63, 0x00,
1026 0x64, 0x00,
1027 0x65, 0x00,
1028 0x66, 0x00,
1029 0x67, 0x00,
1030 0x68, 0x00,
1031 0x69, 0x00,
1032 0x6a, 0x02,
1033 0x6b, 0x00,
1034 0x70, 0xff,
1035 0x71, 0x00,
1036 0x72, 0x00,
1037 0x73, 0x00,
1038 0x74, 0x0c,
1039 0x80, 0x00,
1040 0x81, 0x00,
1041 0x82, 0x00,
1042 0x83, 0x00,
1043 0x84, 0x04,
1044 0x85, 0x80,
1045 0x86, 0x24,
1046 0x87, 0x78,
1047 0x88, 0x10,
1048 0x89, 0x00,
1049 0x90, 0x01,
1050 0x91, 0x01,
1051 0xa0, 0x04,
1052 0xa1, 0x00,
1053 0xa2, 0x00,
1054 0xb0, 0x91,
1055 0xb1, 0x0b,
1056 0xc0, 0x53,
1057 0xc1, 0x70,
1058 0xc2, 0x12,
1059 0xd0, 0x00,
1060 0xd1, 0x00,
1061 0xd2, 0x00,
1062 0xd3, 0x00,
1063 0xd4, 0x00,
1064 0xd5, 0x00,
1065 0xde, 0x00,
1066 0xdf, 0x00,
1067 0x61, 0x38,
1068 0x62, 0x0a,
1069 0x53, 0x13,
1070 0x59, 0x08,
1071 0xff, 0xff,
1072};
1073
1074static struct stv0297_config dvbc_philips_tdm1316l_config = {
1075 .demod_address = 0x1c,
1076 .inittab = dvbc_philips_tdm1316l_inittab,
1077 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001078 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001079};
1080
1081
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083
1084static void frontend_init(struct budget_ci *budget_ci)
1085{
1086 switch (budget_ci->budget.dev->pci->subsystem_device) {
1087 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1088 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001089 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001091 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001092 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 break;
1094 }
1095 break;
1096
1097 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1098 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001099 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001101 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 break;
1103 }
1104 break;
1105
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001106 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1107 budget_ci->tuner_pll_address = 0x61;
1108 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001109 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -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 = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001112 break;
1113 }
1114 break;
1115
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001117 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001119 dvb_attach(tda10045_attach, &philips_tdm1316l_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.init = philips_tdm1316l_tuner_init;
1122 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123 break;
1124 }
1125 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001126
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001127 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001128 budget_ci->tuner_pll_address = 0x60;
1129 budget_ci->budget.dvb_frontend =
Oliver Endriss6c914492007-02-02 19:12:53 -03001130 dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001131 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001132 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1133 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001134 break;
1135 }
1136 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001137
1138 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001139 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001140 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001141 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001142 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1143
Patrick Boettcherdea74862006-05-14 05:01:31 -03001144 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001145 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 -03001146 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001147 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001148 budget_ci->budget.dvb_frontend = NULL;
1149 }
1150 }
1151
1152 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 }
1154
1155 if (budget_ci->budget.dvb_frontend == NULL) {
1156 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1157 budget_ci->budget.dev->pci->vendor,
1158 budget_ci->budget.dev->pci->device,
1159 budget_ci->budget.dev->pci->subsystem_vendor,
1160 budget_ci->budget.dev->pci->subsystem_device);
1161 } else {
1162 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001163 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001165 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 budget_ci->budget.dvb_frontend = NULL;
1167 }
1168 }
1169}
1170
1171static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1172{
1173 struct budget_ci *budget_ci;
1174 int err;
1175
David Hardemanee579bc2006-12-02 21:16:05 -02001176 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001177 if (!budget_ci) {
1178 err = -ENOMEM;
1179 goto out1;
1180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182 dprintk(2, "budget_ci: %p\n", budget_ci);
1183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 dev->ext_priv = budget_ci;
1185
David Hardeman8cc532e2006-12-02 21:16:05 -02001186 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1187 if (err)
1188 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
David Hardeman8cc532e2006-12-02 21:16:05 -02001190 err = msp430_ir_init(budget_ci);
1191 if (err)
1192 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
1194 ciintf_init(budget_ci);
1195
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001196 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 frontend_init(budget_ci);
1198
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001199 ttpci_budget_init_hooks(&budget_ci->budget);
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001202
1203out3:
1204 ttpci_budget_deinit(&budget_ci->budget);
1205out2:
1206 kfree(budget_ci);
1207out1:
1208 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209}
1210
1211static int budget_ci_detach(struct saa7146_dev *dev)
1212{
1213 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1214 struct saa7146_dev *saa = budget_ci->budget.dev;
1215 int err;
1216
1217 if (budget_ci->budget.ci_present)
1218 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001219 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001220 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001222 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 err = ttpci_budget_deinit(&budget_ci->budget);
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 // disable frontend and CI interface
1227 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1228
1229 kfree(budget_ci);
1230
1231 return err;
1232}
1233
1234static struct saa7146_extension budget_extension;
1235
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001236MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1238MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001239MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001240MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
1242static struct pci_device_id pci_tbl[] = {
1243 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1244 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001245 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001247 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001248 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249 {
1250 .vendor = 0,
1251 }
1252};
1253
1254MODULE_DEVICE_TABLE(pci, pci_tbl);
1255
1256static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001257 .name = "budget_ci dvb",
Oliver Endriss00c4cc62006-11-01 13:09:51 -03001258 .flags = SAA7146_USE_I2C_IRQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260 .module = THIS_MODULE,
1261 .pci_tbl = &pci_tbl[0],
1262 .attach = budget_ci_attach,
1263 .detach = budget_ci_detach,
1264
1265 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1266 .irq_func = budget_ci_irq,
1267};
1268
1269static int __init budget_ci_init(void)
1270{
1271 return saa7146_register_extension(&budget_extension);
1272}
1273
1274static void __exit budget_ci_exit(void)
1275{
1276 saa7146_unregister_extension(&budget_extension);
1277}
1278
1279module_init(budget_ci_init);
1280module_exit(budget_ci_exit);
1281
1282MODULE_LICENSE("GPL");
1283MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1284MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1285 "budget PCI DVB cards w/ CI-module produced by "
1286 "Siemens, Technotrend, Hauppauge");