blob: 2a3707c87942355ea4a7c3f21b72881de6db76f0 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * budget-ci.c: driver for the SAA7146 based Budget DVB cards
3 *
4 * Compiled from various sources by Michael Hunold <michael@mihu.de>
5 *
6 * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
7 * partially based on the Siemens DVB driver by Ralph+Marcus Metzler
8 *
9 * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
27 *
28 *
29 * the project's page is at http://www.linuxtv.org/dvb/
30 */
31
32#include "budget.h"
33
34#include <linux/module.h>
35#include <linux/errno.h>
36#include <linux/slab.h>
37#include <linux/interrupt.h>
38#include <linux/input.h>
39#include <linux/spinlock.h>
David Hardeman2520fff2006-12-02 21:16:05 -020040#include <media/ir-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42#include "dvb_ca_en50221.h"
43#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070044#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "tda1004x.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030046#include "lnbp21.h"
47#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030048#include "bsru6.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
David Härdemanecba77f2006-10-27 20:56:51 -030050/*
51 * Regarding DEBIADDR_IR:
52 * Some CI modules hang if random addresses are read.
53 * Using address 0x4000 for the IR read means that we
54 * use the same address as for CI version, which should
55 * be a safe default.
56 */
57#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070058#define DEBIADDR_CICONTROL 0x0000
59#define DEBIADDR_CIVERSION 0x4000
60#define DEBIADDR_IO 0x1000
61#define DEBIADDR_ATTR 0x3000
62
63#define CICONTROL_RESET 0x01
64#define CICONTROL_ENABLETS 0x02
65#define CICONTROL_CAMDETECT 0x08
66
67#define DEBICICTL 0x00420000
68#define DEBICICAM 0x02420000
69
70#define SLOTSTATUS_NONE 1
71#define SLOTSTATUS_PRESENT 2
72#define SLOTSTATUS_RESET 4
73#define SLOTSTATUS_READY 8
74#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
75
David Hardeman2520fff2006-12-02 21:16:05 -020076/* Milliseconds during which key presses are regarded as key repeat and during
77 * which the debounce logic is active
78 */
79#define IR_REPEAT_TIMEOUT 350
80
David Hardeman64741b72006-12-02 21:16:05 -020081/* RC5 device wildcard */
82#define IR_DEVICE_ANY 255
83
David Hardeman2520fff2006-12-02 21:16:05 -020084/* Some remotes sends multiple sequences per keypress (e.g. Zenith sends two),
85 * this setting allows the superflous sequences to be ignored
86 */
87static int debounce = 0;
88module_param(debounce, int, 0644);
89MODULE_PARM_DESC(debounce, "ignore repeated IR sequences (default: 0 = ignore no sequences)");
90
David Hardeman64741b72006-12-02 21:16:05 -020091static int rc5_device = -1;
92module_param(rc5_device, int, 0644);
93MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
94
David Hardemanb5471a22006-12-02 21:16:05 -020095static int ir_debug = 0;
96module_param(ir_debug, int, 0644);
97MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
98
David Hardemandd2f3982006-12-02 21:16:05 -020099struct budget_ci_ir {
100 struct input_dev *dev;
101 struct tasklet_struct msp430_irq_tasklet;
102 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -0200103 char phys[32];
David Hardeman2520fff2006-12-02 21:16:05 -0200104 struct ir_input_state state;
David Hardeman64741b72006-12-02 21:16:05 -0200105 int rc5_device;
David Hardemandd2f3982006-12-02 21:16:05 -0200106};
107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108struct budget_ci {
109 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 struct tasklet_struct ciintf_irq_tasklet;
111 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300112 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -0200114 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700115 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116};
117
David Hardeman2520fff2006-12-02 21:16:05 -0200118static void msp430_ir_keyup(unsigned long data)
119{
120 struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
121 ir_input_nokey(ir->dev, &ir->state);
122}
123
124static void msp430_ir_interrupt(unsigned long data)
125{
126 struct budget_ci *budget_ci = (struct budget_ci *) data;
127 struct input_dev *dev = budget_ci->ir.dev;
128 static int bounces = 0;
David Hardeman64741b72006-12-02 21:16:05 -0200129 int device;
130 int toggle;
131 static int prev_toggle = -1;
132 static u32 ir_key;
David Hardeman2520fff2006-12-02 21:16:05 -0200133 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
134
David Hardeman64741b72006-12-02 21:16:05 -0200135 /*
136 * The msp430 chip can generate two different bytes, command and device
137 *
138 * type1: X1CCCCCC, C = command bits (0 - 63)
139 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
140 *
141 * More than one command byte may be generated before the device byte
142 * Only when we have both, a correct keypress is generated
143 */
144
145 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200146 if (command & 0x40) {
David Hardemanb5471a22006-12-02 21:16:05 -0200147 if (ir_debug)
148 printk("budget_ci: received command byte 0x%02x\n", command);
David Hardeman2520fff2006-12-02 21:16:05 -0200149 ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200150 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200151 }
David Hardeman64741b72006-12-02 21:16:05 -0200152
153 /* It's a RC5 device byte */
David Hardemanb5471a22006-12-02 21:16:05 -0200154 if (ir_debug)
155 printk("budget_ci: received device byte 0x%02x\n", command);
David Hardeman64741b72006-12-02 21:16:05 -0200156 device = command & 0x1f;
157 toggle = command & 0x20;
158
159 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && budget_ci->ir.rc5_device != device)
160 return;
161
162 /* Are we still waiting for a keyup event while this is a new key? */
163 if ((ir_key != dev->repeat_key || toggle != prev_toggle) && del_timer(&dev->timer))
164 ir_input_nokey(dev, &budget_ci->ir.state);
165
166 prev_toggle = toggle;
167
168 /* Ignore repeated key sequences if requested */
169 if (ir_key == dev->repeat_key && bounces > 0 && timer_pending(&dev->timer)) {
170 bounces--;
171 return;
172 }
173
174 /* New keypress? */
175 if (!timer_pending(&dev->timer))
176 bounces = debounce;
177
178 /* Prepare a keyup event sometime in the future */
179 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(IR_REPEAT_TIMEOUT));
180
181 /* Generate a new or repeated keypress */
182 ir_input_keydown(dev, &budget_ci->ir.state, ir_key, ((device << 8) | command));
David Hardeman2520fff2006-12-02 21:16:05 -0200183}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184
185static void msp430_ir_debounce(unsigned long data)
186{
187 struct input_dev *dev = (struct input_dev *) data;
188
189 if (dev->rep[0] == 0 || dev->rep[0] == ~0) {
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300190 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
191 } else {
192 dev->rep[0] = 0;
193 dev->timer.expires = jiffies + HZ * 350 / 1000;
194 add_timer(&dev->timer);
195 input_event(dev, EV_KEY, key_map[dev->repeat_key], 2); /* REPEAT */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 }
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300197 input_sync(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198}
199
200static void msp430_ir_interrupt(unsigned long data)
201{
202 struct budget_ci *budget_ci = (struct budget_ci *) data;
David Hardemandd2f3982006-12-02 21:16:05 -0200203 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 unsigned int code =
205 ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
206
207 if (code & 0x40) {
208 code &= 0x3f;
209
210 if (timer_pending(&dev->timer)) {
211 if (code == dev->repeat_key) {
212 ++dev->rep[0];
213 return;
214 }
215 del_timer(&dev->timer);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300216 input_event(dev, EV_KEY, key_map[dev->repeat_key], 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 }
218
219 if (!key_map[code]) {
220 printk("DVB (%s): no key for %02x!\n", __FUNCTION__, code);
221 return;
222 }
223
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300224 input_event(dev, EV_KEY, key_map[code], 1);
225 input_sync(dev);
226
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 /* initialize debounce and repeat */
228 dev->repeat_key = code;
229 /* Zenith remote _always_ sends 2 sequences */
230 dev->rep[0] = ~0;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300231 mod_timer(&dev->timer, jiffies + msecs_to_jiffies(350));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232 }
233}
234
235static int msp430_ir_init(struct budget_ci *budget_ci)
236{
237 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200238 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200239 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
David Hardemandd2f3982006-12-02 21:16:05 -0200241 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200242 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200243 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200244 error = -ENOMEM;
245 goto out1;
246 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247
David Hardemandd2f3982006-12-02 21:16:05 -0200248 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
249 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200250 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
251 "pci-%s/ir0", pci_name(saa->pci));
252
David Hardemandd2f3982006-12-02 21:16:05 -0200253 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
David Hardeman5cc8ae02006-12-02 21:16:05 -0200255 input_dev->phys = budget_ci->ir.phys;
256 input_dev->id.bustype = BUS_PCI;
257 input_dev->id.version = 1;
258 if (saa->pci->subsystem_vendor) {
259 input_dev->id.vendor = saa->pci->subsystem_vendor;
260 input_dev->id.product = saa->pci->subsystem_device;
261 } else {
262 input_dev->id.vendor = saa->pci->vendor;
263 input_dev->id.product = saa->pci->device;
264 }
265# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
266 input_dev->cdev.dev = &saa->pci->dev;
267# else
268 input_dev->dev = &saa->pci->dev;
269# endif
270
David Hardeman64741b72006-12-02 21:16:05 -0200271 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200272 switch (budget_ci->budget.dev->pci->subsystem_device) {
273 case 0x100c:
274 case 0x100f:
275 case 0x1010:
276 case 0x1011:
277 case 0x1012:
278 case 0x1017:
279 /* The hauppauge keymap is a superset of these remotes */
280 ir_input_init(input_dev, &budget_ci->ir.state,
281 IR_TYPE_RC5, ir_codes_hauppauge_new);
David Hardeman64741b72006-12-02 21:16:05 -0200282
283 if (rc5_device < 0)
284 budget_ci->ir.rc5_device = 0x1f;
285 else
286 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200287 break;
288 default:
289 /* unknown remote */
290 ir_input_init(input_dev, &budget_ci->ir.state,
291 IR_TYPE_RC5, ir_codes_budget_ci_old);
David Hardeman64741b72006-12-02 21:16:05 -0200292
293 if (rc5_device < 0)
294 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
295 else
296 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200297 break;
298 }
299
300 /* initialise the key-up timeout handler */
301 input_dev->timer.function = msp430_ir_keyup;
302 input_dev->timer.data = (unsigned long) &budget_ci->ir;
303 input_dev->rep[REP_DELAY] = 1;
304 input_dev->rep[REP_PERIOD] = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
David Hardeman8cc532e2006-12-02 21:16:05 -0200306 error = input_register_device(input_dev);
307 if (error) {
308 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
309 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300310 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311
David Hardeman8cc532e2006-12-02 21:16:05 -0200312 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
313 (unsigned long) budget_ci);
314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
317
318 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200319
320out2:
321 input_free_device(input_dev);
322out1:
323 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324}
325
326static void msp430_ir_deinit(struct budget_ci *budget_ci)
327{
328 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200329 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_06);
332 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200333 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300335 if (del_timer(&dev->timer)) {
David Hardeman2520fff2006-12-02 21:16:05 -0200336 ir_input_nokey(dev, &budget_ci->ir.state);
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300337 input_sync(dev);
338 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
340 input_unregister_device(dev);
341}
342
343static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
344{
345 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
346
347 if (slot != 0)
348 return -EINVAL;
349
350 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
351 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
352}
353
354static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
355{
356 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
357
358 if (slot != 0)
359 return -EINVAL;
360
361 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
362 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
363}
364
365static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
366{
367 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
368
369 if (slot != 0)
370 return -EINVAL;
371
372 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
373 DEBIADDR_IO | (address & 3), 1, 1, 0);
374}
375
376static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
377{
378 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
379
380 if (slot != 0)
381 return -EINVAL;
382
383 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
384 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
385}
386
387static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
388{
389 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
390 struct saa7146_dev *saa = budget_ci->budget.dev;
391
392 if (slot != 0)
393 return -EINVAL;
394
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300395 if (budget_ci->ci_irq) {
396 // trigger on RISING edge during reset so we know when READY is re-asserted
397 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
398 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 budget_ci->slot_status = SLOTSTATUS_RESET;
400 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
401 msleep(1);
402 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
403 CICONTROL_RESET, 1, 0);
404
405 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
406 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
407 return 0;
408}
409
410static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
411{
412 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
413 struct saa7146_dev *saa = budget_ci->budget.dev;
414
415 if (slot != 0)
416 return -EINVAL;
417
418 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
419 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
420 return 0;
421}
422
423static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
424{
425 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
426 struct saa7146_dev *saa = budget_ci->budget.dev;
427 int tmp;
428
429 if (slot != 0)
430 return -EINVAL;
431
432 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
433
434 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
435 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
436 tmp | CICONTROL_ENABLETS, 1, 0);
437
438 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
439 return 0;
440}
441
442static void ciintf_interrupt(unsigned long data)
443{
444 struct budget_ci *budget_ci = (struct budget_ci *) data;
445 struct saa7146_dev *saa = budget_ci->budget.dev;
446 unsigned int flags;
447
448 // ensure we don't get spurious IRQs during initialisation
449 if (!budget_ci->budget.ci_present)
450 return;
451
452 // read the CAM status
453 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
454 if (flags & CICONTROL_CAMDETECT) {
455
456 // GPIO should be set to trigger on falling edge if a CAM is present
457 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
458
459 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
460 // CAM insertion IRQ
461 budget_ci->slot_status = SLOTSTATUS_PRESENT;
462 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
463 DVB_CA_EN50221_CAMCHANGE_INSERTED);
464
465 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
466 // CAM ready (reset completed)
467 budget_ci->slot_status = SLOTSTATUS_READY;
468 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
469
470 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
471 // FR/DA IRQ
472 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
473 }
474 } else {
475
476 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
477 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
478 // the CAM might not actually be ready yet.
479 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
480
481 // generate a CAM removal IRQ if we haven't already
482 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
483 // CAM removal IRQ
484 budget_ci->slot_status = SLOTSTATUS_NONE;
485 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
486 DVB_CA_EN50221_CAMCHANGE_REMOVED);
487 }
488 }
489}
490
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300491static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
492{
493 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
494 unsigned int flags;
495
496 // ensure we don't get spurious IRQs during initialisation
497 if (!budget_ci->budget.ci_present)
498 return -EINVAL;
499
500 // read the CAM status
501 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
502 if (flags & CICONTROL_CAMDETECT) {
503 // mark it as present if it wasn't before
504 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
505 budget_ci->slot_status = SLOTSTATUS_PRESENT;
506 }
507
508 // during a RESET, we check if we can read from IO memory to see when CAM is ready
509 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
510 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
511 budget_ci->slot_status = SLOTSTATUS_READY;
512 }
513 }
514 } else {
515 budget_ci->slot_status = SLOTSTATUS_NONE;
516 }
517
518 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
519 if (budget_ci->slot_status & SLOTSTATUS_READY) {
520 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
521 }
522 return DVB_CA_EN50221_POLL_CAM_PRESENT;
523 }
524
525 return 0;
526}
527
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528static int ciintf_init(struct budget_ci *budget_ci)
529{
530 struct saa7146_dev *saa = budget_ci->budget.dev;
531 int flags;
532 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300533 int ci_version;
534 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535
536 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
537
538 // enable DEBI pins
539 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16) | 0x800);
540
541 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300542 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
543 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 result = -ENODEV;
545 goto error;
546 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300547
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 // determine whether a CAM is present or not
549 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
550 budget_ci->slot_status = SLOTSTATUS_NONE;
551 if (flags & CICONTROL_CAMDETECT)
552 budget_ci->slot_status = SLOTSTATUS_PRESENT;
553
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300554 // version 0xa2 of the CI firmware doesn't generate interrupts
555 if (ci_version == 0xa2) {
556 ca_flags = 0;
557 budget_ci->ci_irq = 0;
558 } else {
559 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
560 DVB_CA_EN50221_FLAG_IRQ_FR |
561 DVB_CA_EN50221_FLAG_IRQ_DA;
562 budget_ci->ci_irq = 1;
563 }
564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 // register CI interface
566 budget_ci->ca.owner = THIS_MODULE;
567 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
568 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
569 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
570 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
571 budget_ci->ca.slot_reset = ciintf_slot_reset;
572 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
573 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300574 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700576 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300578 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 printk("budget_ci: CI interface detected, but initialisation failed.\n");
580 goto error;
581 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300584 if (budget_ci->ci_irq) {
585 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
586 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
587 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
588 } else {
589 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
590 }
591 saa7146_write(saa, IER, saa7146_read(saa, IER) | MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300593
594 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
596 CICONTROL_RESET, 1, 0);
597
598 // success!
599 printk("budget_ci: CI interface initialised\n");
600 budget_ci->budget.ci_present = 1;
601
602 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300603 if (budget_ci->ci_irq) {
604 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
605 if (budget_ci->slot_status != SLOTSTATUS_NONE)
606 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
607 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
608 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609
610 return 0;
611
612error:
613 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
614 return result;
615}
616
617static void ciintf_deinit(struct budget_ci *budget_ci)
618{
619 struct saa7146_dev *saa = budget_ci->budget.dev;
620
621 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300622 if (budget_ci->ci_irq) {
623 saa7146_write(saa, IER, saa7146_read(saa, IER) & ~MASK_03);
624 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
625 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
626 }
627
628 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
630 msleep(1);
631 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
632 CICONTROL_RESET, 1, 0);
633
634 // disable TS data stream to CI interface
635 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
636
637 // release the CA device
638 dvb_ca_en50221_release(&budget_ci->ca);
639
640 // disable DEBI pins
641 saa7146_write(saa, MC1, saa7146_read(saa, MC1) | (0x800 << 16));
642}
643
644static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
645{
646 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
647
648 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
649
650 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200651 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 if (*isr & MASK_10)
654 ttpci_budget_irq10_handler(dev, isr);
655
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300656 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
658}
659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660static u8 philips_su1278_tt_inittab[] = {
661 0x01, 0x0f,
662 0x02, 0x30,
663 0x03, 0x00,
664 0x04, 0x5b,
665 0x05, 0x85,
666 0x06, 0x02,
667 0x07, 0x00,
668 0x08, 0x02,
669 0x09, 0x00,
670 0x0C, 0x01,
671 0x0D, 0x81,
672 0x0E, 0x44,
673 0x0f, 0x14,
674 0x10, 0x3c,
675 0x11, 0x84,
676 0x12, 0xda,
677 0x13, 0x97,
678 0x14, 0x95,
679 0x15, 0xc9,
680 0x16, 0x19,
681 0x17, 0x8c,
682 0x18, 0x59,
683 0x19, 0xf8,
684 0x1a, 0xfe,
685 0x1c, 0x7f,
686 0x1d, 0x00,
687 0x1e, 0x00,
688 0x1f, 0x50,
689 0x20, 0x00,
690 0x21, 0x00,
691 0x22, 0x00,
692 0x23, 0x00,
693 0x28, 0x00,
694 0x29, 0x28,
695 0x2a, 0x14,
696 0x2b, 0x0f,
697 0x2c, 0x09,
698 0x2d, 0x09,
699 0x31, 0x1f,
700 0x32, 0x19,
701 0x33, 0xfc,
702 0x34, 0x93,
703 0xff, 0xff
704};
705
706static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
707{
708 stv0299_writereg(fe, 0x0e, 0x44);
709 if (srate >= 10000000) {
710 stv0299_writereg(fe, 0x13, 0x97);
711 stv0299_writereg(fe, 0x14, 0x95);
712 stv0299_writereg(fe, 0x15, 0xc9);
713 stv0299_writereg(fe, 0x17, 0x8c);
714 stv0299_writereg(fe, 0x1a, 0xfe);
715 stv0299_writereg(fe, 0x1c, 0x7f);
716 stv0299_writereg(fe, 0x2d, 0x09);
717 } else {
718 stv0299_writereg(fe, 0x13, 0x99);
719 stv0299_writereg(fe, 0x14, 0x8d);
720 stv0299_writereg(fe, 0x15, 0xce);
721 stv0299_writereg(fe, 0x17, 0x43);
722 stv0299_writereg(fe, 0x1a, 0x1d);
723 stv0299_writereg(fe, 0x1c, 0x12);
724 stv0299_writereg(fe, 0x2d, 0x05);
725 }
726 stv0299_writereg(fe, 0x0e, 0x23);
727 stv0299_writereg(fe, 0x0f, 0x94);
728 stv0299_writereg(fe, 0x10, 0x39);
729 stv0299_writereg(fe, 0x15, 0xc9);
730
731 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
732 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
733 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
734
735 return 0;
736}
737
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300738static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
739 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300741 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 u32 div;
743 u8 buf[4];
744 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
745
746 if ((params->frequency < 950000) || (params->frequency > 2150000))
747 return -EINVAL;
748
749 div = (params->frequency + (500 - 1)) / 500; // round correctly
750 buf[0] = (div >> 8) & 0x7f;
751 buf[1] = div & 0xff;
752 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
753 buf[3] = 0x20;
754
755 if (params->u.qpsk.symbol_rate < 4000000)
756 buf[3] |= 1;
757
758 if (params->frequency < 1250000)
759 buf[3] |= 0;
760 else if (params->frequency < 1550000)
761 buf[3] |= 0x40;
762 else if (params->frequency < 2050000)
763 buf[3] |= 0x80;
764 else if (params->frequency < 2150000)
765 buf[3] |= 0xC0;
766
Patrick Boettcherdea74862006-05-14 05:01:31 -0300767 if (fe->ops.i2c_gate_ctrl)
768 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300769 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 return -EIO;
771 return 0;
772}
773
774static struct stv0299_config philips_su1278_tt_config = {
775
776 .demod_address = 0x68,
777 .inittab = philips_su1278_tt_inittab,
778 .mclk = 64000000UL,
779 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 .skip_reinit = 1,
781 .lock_output = STV0229_LOCKOUTPUT_1,
782 .volt13_op0_op1 = STV0299_VOLT13_OP1,
783 .min_delay_ms = 50,
784 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785};
786
787
788
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300789static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790{
791 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
792 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
793 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700794 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 sizeof(td1316_init) };
796
797 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300798 if (fe->ops.i2c_gate_ctrl)
799 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
801 return -EIO;
802 msleep(1);
803
804 // disable the mc44BC374c (do not check for errors)
805 tuner_msg.addr = 0x65;
806 tuner_msg.buf = disable_mc44BC374c;
807 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300808 if (fe->ops.i2c_gate_ctrl)
809 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300811 if (fe->ops.i2c_gate_ctrl)
812 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
814 }
815
816 return 0;
817}
818
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300819static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
821 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
822 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700823 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 -0700824 int tuner_frequency = 0;
825 u8 band, cp, filter;
826
827 // determine charge pump
828 tuner_frequency = params->frequency + 36130000;
829 if (tuner_frequency < 87000000)
830 return -EINVAL;
831 else if (tuner_frequency < 130000000)
832 cp = 3;
833 else if (tuner_frequency < 160000000)
834 cp = 5;
835 else if (tuner_frequency < 200000000)
836 cp = 6;
837 else if (tuner_frequency < 290000000)
838 cp = 3;
839 else if (tuner_frequency < 420000000)
840 cp = 5;
841 else if (tuner_frequency < 480000000)
842 cp = 6;
843 else if (tuner_frequency < 620000000)
844 cp = 3;
845 else if (tuner_frequency < 830000000)
846 cp = 5;
847 else if (tuner_frequency < 895000000)
848 cp = 7;
849 else
850 return -EINVAL;
851
852 // determine band
853 if (params->frequency < 49000000)
854 return -EINVAL;
855 else if (params->frequency < 159000000)
856 band = 1;
857 else if (params->frequency < 444000000)
858 band = 2;
859 else if (params->frequency < 861000000)
860 band = 4;
861 else
862 return -EINVAL;
863
864 // setup PLL filter and TDA9889
865 switch (params->u.ofdm.bandwidth) {
866 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300867 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 filter = 0;
869 break;
870
871 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300872 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 filter = 0;
874 break;
875
876 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300877 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 filter = 1;
879 break;
880
881 default:
882 return -EINVAL;
883 }
884
885 // calculate divisor
886 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
887 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
888
889 // setup tuner buffer
890 tuner_buf[0] = tuner_frequency >> 8;
891 tuner_buf[1] = tuner_frequency & 0xff;
892 tuner_buf[2] = 0xca;
893 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
894
Patrick Boettcherdea74862006-05-14 05:01:31 -0300895 if (fe->ops.i2c_gate_ctrl)
896 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
898 return -EIO;
899
900 msleep(1);
901 return 0;
902}
903
904static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
905 const struct firmware **fw, char *name)
906{
907 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
908
909 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
910}
911
912static struct tda1004x_config philips_tdm1316l_config = {
913
914 .demod_address = 0x8,
915 .invert = 0,
916 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700917 .xtal_freq = TDA10046_XTAL_4M,
918 .agc_config = TDA10046_AGC_DEFAULT,
919 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 .request_firmware = philips_tdm1316l_request_firmware,
921};
922
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300923static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700924{
925 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
926 u8 tuner_buf[5];
927 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
928 .flags = 0,
929 .buf = tuner_buf,
930 .len = sizeof(tuner_buf) };
931 int tuner_frequency = 0;
932 u8 band, cp, filter;
933
934 // determine charge pump
935 tuner_frequency = params->frequency + 36125000;
936 if (tuner_frequency < 87000000)
937 return -EINVAL;
938 else if (tuner_frequency < 130000000) {
939 cp = 3;
940 band = 1;
941 } else if (tuner_frequency < 160000000) {
942 cp = 5;
943 band = 1;
944 } else if (tuner_frequency < 200000000) {
945 cp = 6;
946 band = 1;
947 } else if (tuner_frequency < 290000000) {
948 cp = 3;
949 band = 2;
950 } else if (tuner_frequency < 420000000) {
951 cp = 5;
952 band = 2;
953 } else if (tuner_frequency < 480000000) {
954 cp = 6;
955 band = 2;
956 } else if (tuner_frequency < 620000000) {
957 cp = 3;
958 band = 4;
959 } else if (tuner_frequency < 830000000) {
960 cp = 5;
961 band = 4;
962 } else if (tuner_frequency < 895000000) {
963 cp = 7;
964 band = 4;
965 } else
966 return -EINVAL;
967
968 // assume PLL filter should always be 8MHz for the moment.
969 filter = 1;
970
971 // calculate divisor
972 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
973
974 // setup tuner buffer
975 tuner_buf[0] = tuner_frequency >> 8;
976 tuner_buf[1] = tuner_frequency & 0xff;
977 tuner_buf[2] = 0xc8;
978 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
979 tuner_buf[4] = 0x80;
980
Patrick Boettcherdea74862006-05-14 05:01:31 -0300981 if (fe->ops.i2c_gate_ctrl)
982 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700983 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
984 return -EIO;
985
986 msleep(50);
987
Patrick Boettcherdea74862006-05-14 05:01:31 -0300988 if (fe->ops.i2c_gate_ctrl)
989 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700990 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
991 return -EIO;
992
993 msleep(1);
994
995 return 0;
996}
997
998static u8 dvbc_philips_tdm1316l_inittab[] = {
999 0x80, 0x01,
1000 0x80, 0x00,
1001 0x81, 0x01,
1002 0x81, 0x00,
1003 0x00, 0x09,
1004 0x01, 0x69,
1005 0x03, 0x00,
1006 0x04, 0x00,
1007 0x07, 0x00,
1008 0x08, 0x00,
1009 0x20, 0x00,
1010 0x21, 0x40,
1011 0x22, 0x00,
1012 0x23, 0x00,
1013 0x24, 0x40,
1014 0x25, 0x88,
1015 0x30, 0xff,
1016 0x31, 0x00,
1017 0x32, 0xff,
1018 0x33, 0x00,
1019 0x34, 0x50,
1020 0x35, 0x7f,
1021 0x36, 0x00,
1022 0x37, 0x20,
1023 0x38, 0x00,
1024 0x40, 0x1c,
1025 0x41, 0xff,
1026 0x42, 0x29,
1027 0x43, 0x20,
1028 0x44, 0xff,
1029 0x45, 0x00,
1030 0x46, 0x00,
1031 0x49, 0x04,
1032 0x4a, 0x00,
1033 0x4b, 0x7b,
1034 0x52, 0x30,
1035 0x55, 0xae,
1036 0x56, 0x47,
1037 0x57, 0xe1,
1038 0x58, 0x3a,
1039 0x5a, 0x1e,
1040 0x5b, 0x34,
1041 0x60, 0x00,
1042 0x63, 0x00,
1043 0x64, 0x00,
1044 0x65, 0x00,
1045 0x66, 0x00,
1046 0x67, 0x00,
1047 0x68, 0x00,
1048 0x69, 0x00,
1049 0x6a, 0x02,
1050 0x6b, 0x00,
1051 0x70, 0xff,
1052 0x71, 0x00,
1053 0x72, 0x00,
1054 0x73, 0x00,
1055 0x74, 0x0c,
1056 0x80, 0x00,
1057 0x81, 0x00,
1058 0x82, 0x00,
1059 0x83, 0x00,
1060 0x84, 0x04,
1061 0x85, 0x80,
1062 0x86, 0x24,
1063 0x87, 0x78,
1064 0x88, 0x10,
1065 0x89, 0x00,
1066 0x90, 0x01,
1067 0x91, 0x01,
1068 0xa0, 0x04,
1069 0xa1, 0x00,
1070 0xa2, 0x00,
1071 0xb0, 0x91,
1072 0xb1, 0x0b,
1073 0xc0, 0x53,
1074 0xc1, 0x70,
1075 0xc2, 0x12,
1076 0xd0, 0x00,
1077 0xd1, 0x00,
1078 0xd2, 0x00,
1079 0xd3, 0x00,
1080 0xd4, 0x00,
1081 0xd5, 0x00,
1082 0xde, 0x00,
1083 0xdf, 0x00,
1084 0x61, 0x38,
1085 0x62, 0x0a,
1086 0x53, 0x13,
1087 0x59, 0x08,
1088 0xff, 0xff,
1089};
1090
1091static struct stv0297_config dvbc_philips_tdm1316l_config = {
1092 .demod_address = 0x1c,
1093 .inittab = dvbc_philips_tdm1316l_inittab,
1094 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001095 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001096};
1097
1098
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099
1100
1101static void frontend_init(struct budget_ci *budget_ci)
1102{
1103 switch (budget_ci->budget.dev->pci->subsystem_device) {
1104 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1105 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001106 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001108 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001109 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 break;
1111 }
1112 break;
1113
1114 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1115 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001116 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001118 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001119 break;
1120 }
1121 break;
1122
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001123 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1124 budget_ci->tuner_pll_address = 0x61;
1125 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001126 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001127 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001128 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001129 break;
1130 }
1131 break;
1132
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001134 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001136 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001138 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1139 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140 break;
1141 }
1142 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001143
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001144 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001145 budget_ci->tuner_pll_address = 0x60;
Raymond Mantchala9e741b72006-10-30 23:20:50 -03001146 philips_tdm1316l_config.invert = 1;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001147 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001148 dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001149 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001150 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1151 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001152 break;
1153 }
1154 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001155
1156 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001157 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001158 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001159 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001160 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1161
Patrick Boettcherdea74862006-05-14 05:01:31 -03001162 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001163 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 -03001164 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001165 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001166 budget_ci->budget.dvb_frontend = NULL;
1167 }
1168 }
1169
1170 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 }
1172
1173 if (budget_ci->budget.dvb_frontend == NULL) {
1174 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1175 budget_ci->budget.dev->pci->vendor,
1176 budget_ci->budget.dev->pci->device,
1177 budget_ci->budget.dev->pci->subsystem_vendor,
1178 budget_ci->budget.dev->pci->subsystem_device);
1179 } else {
1180 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001181 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001182 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001183 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 budget_ci->budget.dvb_frontend = NULL;
1185 }
1186 }
1187}
1188
1189static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1190{
1191 struct budget_ci *budget_ci;
1192 int err;
1193
David Hardemanee579bc2006-12-02 21:16:05 -02001194 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001195 if (!budget_ci) {
1196 err = -ENOMEM;
1197 goto out1;
1198 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199
1200 dprintk(2, "budget_ci: %p\n", budget_ci);
1201
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 dev->ext_priv = budget_ci;
1203
David Hardeman8cc532e2006-12-02 21:16:05 -02001204 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1205 if (err)
1206 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207
David Hardeman8cc532e2006-12-02 21:16:05 -02001208 err = msp430_ir_init(budget_ci);
1209 if (err)
1210 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001211
1212 ciintf_init(budget_ci);
1213
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001214 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 frontend_init(budget_ci);
1216
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001217 ttpci_budget_init_hooks(&budget_ci->budget);
1218
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001220
1221out3:
1222 ttpci_budget_deinit(&budget_ci->budget);
1223out2:
1224 kfree(budget_ci);
1225out1:
1226 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227}
1228
1229static int budget_ci_detach(struct saa7146_dev *dev)
1230{
1231 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1232 struct saa7146_dev *saa = budget_ci->budget.dev;
1233 int err;
1234
1235 if (budget_ci->budget.ci_present)
1236 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001237 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001238 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001240 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001241 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 err = ttpci_budget_deinit(&budget_ci->budget);
1243
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 // disable frontend and CI interface
1245 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1246
1247 kfree(budget_ci);
1248
1249 return err;
1250}
1251
1252static struct saa7146_extension budget_extension;
1253
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001254MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1256MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001257MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001258MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259
1260static struct pci_device_id pci_tbl[] = {
1261 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1262 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001263 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001265 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001266 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 {
1268 .vendor = 0,
1269 }
1270};
1271
1272MODULE_DEVICE_TABLE(pci, pci_tbl);
1273
1274static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001275 .name = "budget_ci dvb",
Oliver Endriss69459f32005-12-01 00:51:48 -08001276 .flags = SAA7146_I2C_SHORT_DELAY,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277
1278 .module = THIS_MODULE,
1279 .pci_tbl = &pci_tbl[0],
1280 .attach = budget_ci_attach,
1281 .detach = budget_ci_detach,
1282
1283 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1284 .irq_func = budget_ci_irq,
1285};
1286
1287static int __init budget_ci_init(void)
1288{
1289 return saa7146_register_extension(&budget_extension);
1290}
1291
1292static void __exit budget_ci_exit(void)
1293{
1294 saa7146_unregister_extension(&budget_extension);
1295}
1296
1297module_init(budget_ci_init);
1298module_exit(budget_ci_exit);
1299
1300MODULE_LICENSE("GPL");
1301MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1302MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1303 "budget PCI DVB cards w/ CI-module produced by "
1304 "Siemens, Technotrend, Hauppauge");