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