blob: 060e7c7853266f9a2ae6fd514748a6e10b67182c [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"
Sigmund Augdal11417da2008-06-15 17:25:46 -030049#include "tda1002x.h"
50#include "tda827x.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
David Härdemanecba77f2006-10-27 20:56:51 -030052/*
53 * Regarding DEBIADDR_IR:
54 * Some CI modules hang if random addresses are read.
55 * Using address 0x4000 for the IR read means that we
56 * use the same address as for CI version, which should
57 * be a safe default.
58 */
59#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define DEBIADDR_CICONTROL 0x0000
61#define DEBIADDR_CIVERSION 0x4000
62#define DEBIADDR_IO 0x1000
63#define DEBIADDR_ATTR 0x3000
64
65#define CICONTROL_RESET 0x01
66#define CICONTROL_ENABLETS 0x02
67#define CICONTROL_CAMDETECT 0x08
68
69#define DEBICICTL 0x00420000
70#define DEBICICAM 0x02420000
71
72#define SLOTSTATUS_NONE 1
73#define SLOTSTATUS_PRESENT 2
74#define SLOTSTATUS_RESET 4
75#define SLOTSTATUS_READY 8
76#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
77
David Härdeman145859c2007-04-27 12:31:22 -030078/*
79 * Milliseconds during which a key is regarded as pressed.
80 * If an identical command arrives within this time, the timer will start over.
David Hardeman2520fff2006-12-02 21:16:05 -020081 */
David Härdeman145859c2007-04-27 12:31:22 -030082#define IR_KEYPRESS_TIMEOUT 250
David Hardeman2520fff2006-12-02 21:16:05 -020083
David Hardeman64741b72006-12-02 21:16:05 -020084/* RC5 device wildcard */
85#define IR_DEVICE_ANY 255
86
David Hardeman64741b72006-12-02 21:16:05 -020087static int rc5_device = -1;
88module_param(rc5_device, int, 0644);
89MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
90
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030091static int ir_debug;
David Hardemanb5471a22006-12-02 21:16:05 -020092module_param(ir_debug, int, 0644);
93MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
94
David Hardemandd2f3982006-12-02 21:16:05 -020095struct budget_ci_ir {
96 struct input_dev *dev;
97 struct tasklet_struct msp430_irq_tasklet;
David Härdeman145859c2007-04-27 12:31:22 -030098 struct timer_list timer_keyup;
David Hardemandd2f3982006-12-02 21:16:05 -020099 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -0200100 char phys[32];
David Hardeman2520fff2006-12-02 21:16:05 -0200101 struct ir_input_state state;
David Hardeman64741b72006-12-02 21:16:05 -0200102 int rc5_device;
David Härdeman145859c2007-04-27 12:31:22 -0300103 u32 last_raw;
104 u32 ir_key;
105 bool have_command;
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;
David Hardeman2520fff2006-12-02 21:16:05 -0200128 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
David Härdeman145859c2007-04-27 12:31:22 -0300129 u32 raw;
David Hardeman2520fff2006-12-02 21:16:05 -0200130
David Hardeman64741b72006-12-02 21:16:05 -0200131 /*
132 * The msp430 chip can generate two different bytes, command and device
133 *
134 * type1: X1CCCCCC, C = command bits (0 - 63)
135 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
136 *
David Härdeman59327a42007-02-13 09:39:58 -0300137 * Each signal from the remote control can generate one or more command
138 * bytes and one or more device bytes. For the repeated bytes, the
139 * highest bit (X) is set. The first command byte is always generated
140 * before the first device byte. Other than that, no specific order
David Härdeman145859c2007-04-27 12:31:22 -0300141 * seems to apply. To make life interesting, bytes can also be lost.
David Härdeman59327a42007-02-13 09:39:58 -0300142 *
143 * Only when we have a command and device byte, a keypress is
144 * generated.
David Hardeman64741b72006-12-02 21:16:05 -0200145 */
146
David Härdeman59327a42007-02-13 09:39:58 -0300147 if (ir_debug)
148 printk("budget_ci: received byte 0x%02x\n", command);
149
David Härdeman145859c2007-04-27 12:31:22 -0300150 /* Remove repeat bit, we use every command */
151 command = command & 0x7f;
David Härdeman59327a42007-02-13 09:39:58 -0300152
David Hardeman64741b72006-12-02 21:16:05 -0200153 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200154 if (command & 0x40) {
David Härdeman145859c2007-04-27 12:31:22 -0300155 budget_ci->ir.have_command = true;
156 budget_ci->ir.ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200157 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200158 }
David Hardeman64741b72006-12-02 21:16:05 -0200159
160 /* It's a RC5 device byte */
David Härdeman145859c2007-04-27 12:31:22 -0300161 if (!budget_ci->ir.have_command)
David Härdeman59327a42007-02-13 09:39:58 -0300162 return;
David Härdeman145859c2007-04-27 12:31:22 -0300163 budget_ci->ir.have_command = false;
David Hardeman64741b72006-12-02 21:16:05 -0200164
David Härdeman145859c2007-04-27 12:31:22 -0300165 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
166 budget_ci->ir.rc5_device != (command & 0x1f))
David Hardeman64741b72006-12-02 21:16:05 -0200167 return;
168
David Härdeman145859c2007-04-27 12:31:22 -0300169 /* Is this a repeated key sequence? (same device, command, toggle) */
170 raw = budget_ci->ir.ir_key | (command << 8);
171 if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) {
David Hardeman59236d42006-12-02 21:16:06 -0200172 ir_input_nokey(dev, &budget_ci->ir.state);
David Härdeman145859c2007-04-27 12:31:22 -0300173 ir_input_keydown(dev, &budget_ci->ir.state,
174 budget_ci->ir.ir_key, raw);
175 budget_ci->ir.last_raw = raw;
David Hardeman59236d42006-12-02 21:16:06 -0200176 }
David Härdeman145859c2007-04-27 12:31:22 -0300177
178 mod_timer(&budget_ci->ir.timer_keyup, jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT));
David Hardeman2520fff2006-12-02 21:16:05 -0200179}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static int msp430_ir_init(struct budget_ci *budget_ci)
182{
183 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200184 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200185 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
David Hardemandd2f3982006-12-02 21:16:05 -0200187 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200188 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200189 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200190 error = -ENOMEM;
191 goto out1;
192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
David Hardemandd2f3982006-12-02 21:16:05 -0200194 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
195 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200196 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
197 "pci-%s/ir0", pci_name(saa->pci));
198
David Hardemandd2f3982006-12-02 21:16:05 -0200199 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
David Hardeman5cc8ae02006-12-02 21:16:05 -0200201 input_dev->phys = budget_ci->ir.phys;
202 input_dev->id.bustype = BUS_PCI;
203 input_dev->id.version = 1;
204 if (saa->pci->subsystem_vendor) {
205 input_dev->id.vendor = saa->pci->subsystem_vendor;
206 input_dev->id.product = saa->pci->subsystem_device;
207 } else {
208 input_dev->id.vendor = saa->pci->vendor;
209 input_dev->id.product = saa->pci->device;
210 }
Dmitry Torokhov2c8a3a32007-07-16 09:28:15 -0300211 input_dev->dev.parent = &saa->pci->dev;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200212
David Hardeman64741b72006-12-02 21:16:05 -0200213 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200214 switch (budget_ci->budget.dev->pci->subsystem_device) {
215 case 0x100c:
216 case 0x100f:
David Hardeman2520fff2006-12-02 21:16:05 -0200217 case 0x1011:
218 case 0x1012:
David Hardeman2520fff2006-12-02 21:16:05 -0200219 /* The hauppauge keymap is a superset of these remotes */
220 ir_input_init(input_dev, &budget_ci->ir.state,
221 IR_TYPE_RC5, ir_codes_hauppauge_new);
David Hardeman64741b72006-12-02 21:16:05 -0200222
223 if (rc5_device < 0)
224 budget_ci->ir.rc5_device = 0x1f;
225 else
226 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200227 break;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300228 case 0x1010:
Oliver Endrissf64899c2007-09-17 22:17:12 -0300229 case 0x1017:
Oliver Endrissbbfc4c22008-06-19 23:36:45 -0300230 case 0x101a:
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300231 /* for the Technotrend 1500 bundled remote */
232 ir_input_init(input_dev, &budget_ci->ir.state,
233 IR_TYPE_RC5, ir_codes_tt_1500);
234
235 if (rc5_device < 0)
236 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
237 else
238 budget_ci->ir.rc5_device = rc5_device;
239 break;
David Hardeman2520fff2006-12-02 21:16:05 -0200240 default:
241 /* unknown remote */
242 ir_input_init(input_dev, &budget_ci->ir.state,
243 IR_TYPE_RC5, ir_codes_budget_ci_old);
David Hardeman64741b72006-12-02 21:16:05 -0200244
245 if (rc5_device < 0)
246 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
247 else
248 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200249 break;
250 }
251
David Härdeman145859c2007-04-27 12:31:22 -0300252 /* initialise the key-up timeout handler */
253 init_timer(&budget_ci->ir.timer_keyup);
254 budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
255 budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
256 budget_ci->ir.last_raw = 0xffff; /* An impossible value */
David Hardeman8cc532e2006-12-02 21:16:05 -0200257 error = input_register_device(input_dev);
258 if (error) {
259 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
260 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
David Härdeman145859c2007-04-27 12:31:22 -0300263 /* note: these must be after input_register_device */
264 input_dev->rep[REP_DELAY] = 400;
265 input_dev->rep[REP_PERIOD] = 250;
266
David Hardeman8cc532e2006-12-02 21:16:05 -0200267 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
268 (unsigned long) budget_ci);
269
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300270 SAA7146_IER_ENABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
272
273 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200274
275out2:
276 input_free_device(input_dev);
277out1:
278 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
281static void msp430_ir_deinit(struct budget_ci *budget_ci)
282{
283 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200284 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300286 SAA7146_IER_DISABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200288 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289
David Härdeman145859c2007-04-27 12:31:22 -0300290 del_timer_sync(&dev->timer);
291 ir_input_nokey(dev, &budget_ci->ir.state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
293 input_unregister_device(dev);
294}
295
296static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
297{
298 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
299
300 if (slot != 0)
301 return -EINVAL;
302
303 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
304 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
305}
306
307static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
308{
309 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
310
311 if (slot != 0)
312 return -EINVAL;
313
314 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
315 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
316}
317
318static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
319{
320 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
321
322 if (slot != 0)
323 return -EINVAL;
324
325 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
326 DEBIADDR_IO | (address & 3), 1, 1, 0);
327}
328
329static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
330{
331 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
332
333 if (slot != 0)
334 return -EINVAL;
335
336 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
337 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
338}
339
340static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
341{
342 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
343 struct saa7146_dev *saa = budget_ci->budget.dev;
344
345 if (slot != 0)
346 return -EINVAL;
347
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300348 if (budget_ci->ci_irq) {
349 // trigger on RISING edge during reset so we know when READY is re-asserted
350 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352 budget_ci->slot_status = SLOTSTATUS_RESET;
353 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
354 msleep(1);
355 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
356 CICONTROL_RESET, 1, 0);
357
358 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
359 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
360 return 0;
361}
362
363static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
364{
365 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
366 struct saa7146_dev *saa = budget_ci->budget.dev;
367
368 if (slot != 0)
369 return -EINVAL;
370
371 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
372 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
373 return 0;
374}
375
376static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
377{
378 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
379 struct saa7146_dev *saa = budget_ci->budget.dev;
380 int tmp;
381
382 if (slot != 0)
383 return -EINVAL;
384
385 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
386
387 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
388 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
389 tmp | CICONTROL_ENABLETS, 1, 0);
390
391 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
392 return 0;
393}
394
395static void ciintf_interrupt(unsigned long data)
396{
397 struct budget_ci *budget_ci = (struct budget_ci *) data;
398 struct saa7146_dev *saa = budget_ci->budget.dev;
399 unsigned int flags;
400
401 // ensure we don't get spurious IRQs during initialisation
402 if (!budget_ci->budget.ci_present)
403 return;
404
405 // read the CAM status
406 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
407 if (flags & CICONTROL_CAMDETECT) {
408
409 // GPIO should be set to trigger on falling edge if a CAM is present
410 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
411
412 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
413 // CAM insertion IRQ
414 budget_ci->slot_status = SLOTSTATUS_PRESENT;
415 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
416 DVB_CA_EN50221_CAMCHANGE_INSERTED);
417
418 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
419 // CAM ready (reset completed)
420 budget_ci->slot_status = SLOTSTATUS_READY;
421 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
422
423 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
424 // FR/DA IRQ
425 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
426 }
427 } else {
428
429 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
430 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
431 // the CAM might not actually be ready yet.
432 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
433
434 // generate a CAM removal IRQ if we haven't already
435 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
436 // CAM removal IRQ
437 budget_ci->slot_status = SLOTSTATUS_NONE;
438 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
439 DVB_CA_EN50221_CAMCHANGE_REMOVED);
440 }
441 }
442}
443
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300444static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
445{
446 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
447 unsigned int flags;
448
449 // ensure we don't get spurious IRQs during initialisation
450 if (!budget_ci->budget.ci_present)
451 return -EINVAL;
452
453 // read the CAM status
454 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
455 if (flags & CICONTROL_CAMDETECT) {
456 // mark it as present if it wasn't before
457 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
458 budget_ci->slot_status = SLOTSTATUS_PRESENT;
459 }
460
461 // during a RESET, we check if we can read from IO memory to see when CAM is ready
462 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
463 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
464 budget_ci->slot_status = SLOTSTATUS_READY;
465 }
466 }
467 } else {
468 budget_ci->slot_status = SLOTSTATUS_NONE;
469 }
470
471 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
472 if (budget_ci->slot_status & SLOTSTATUS_READY) {
473 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
474 }
475 return DVB_CA_EN50221_POLL_CAM_PRESENT;
476 }
477
478 return 0;
479}
480
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481static int ciintf_init(struct budget_ci *budget_ci)
482{
483 struct saa7146_dev *saa = budget_ci->budget.dev;
484 int flags;
485 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300486 int ci_version;
487 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488
489 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
490
491 // enable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300492 saa7146_write(saa, MC1, MASK_27 | MASK_11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493
494 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300495 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
496 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 result = -ENODEV;
498 goto error;
499 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300500
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 // determine whether a CAM is present or not
502 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
503 budget_ci->slot_status = SLOTSTATUS_NONE;
504 if (flags & CICONTROL_CAMDETECT)
505 budget_ci->slot_status = SLOTSTATUS_PRESENT;
506
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300507 // version 0xa2 of the CI firmware doesn't generate interrupts
508 if (ci_version == 0xa2) {
509 ca_flags = 0;
510 budget_ci->ci_irq = 0;
511 } else {
512 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
513 DVB_CA_EN50221_FLAG_IRQ_FR |
514 DVB_CA_EN50221_FLAG_IRQ_DA;
515 budget_ci->ci_irq = 1;
516 }
517
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 // register CI interface
519 budget_ci->ca.owner = THIS_MODULE;
520 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
521 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
522 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
523 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
524 budget_ci->ca.slot_reset = ciintf_slot_reset;
525 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
526 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300527 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700529 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300531 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 printk("budget_ci: CI interface detected, but initialisation failed.\n");
533 goto error;
534 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300535
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300537 if (budget_ci->ci_irq) {
538 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
539 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
540 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
541 } else {
542 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
543 }
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300544 SAA7146_IER_ENABLE(saa, MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300546
547 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
549 CICONTROL_RESET, 1, 0);
550
551 // success!
552 printk("budget_ci: CI interface initialised\n");
553 budget_ci->budget.ci_present = 1;
554
555 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300556 if (budget_ci->ci_irq) {
557 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
558 if (budget_ci->slot_status != SLOTSTATUS_NONE)
559 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
560 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
561 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 return 0;
564
565error:
Hartmut Birr2a893de2006-12-03 21:08:08 -0300566 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567 return result;
568}
569
570static void ciintf_deinit(struct budget_ci *budget_ci)
571{
572 struct saa7146_dev *saa = budget_ci->budget.dev;
573
574 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300575 if (budget_ci->ci_irq) {
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300576 SAA7146_IER_DISABLE(saa, MASK_03);
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300577 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
578 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
579 }
580
581 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
583 msleep(1);
584 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
585 CICONTROL_RESET, 1, 0);
586
587 // disable TS data stream to CI interface
588 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
589
590 // release the CA device
591 dvb_ca_en50221_release(&budget_ci->ca);
592
593 // disable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300594 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595}
596
597static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
598{
599 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
600
601 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
602
603 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200604 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605
606 if (*isr & MASK_10)
607 ttpci_budget_irq10_handler(dev, isr);
608
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300609 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700610 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
611}
612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613static u8 philips_su1278_tt_inittab[] = {
614 0x01, 0x0f,
615 0x02, 0x30,
616 0x03, 0x00,
617 0x04, 0x5b,
618 0x05, 0x85,
619 0x06, 0x02,
620 0x07, 0x00,
621 0x08, 0x02,
622 0x09, 0x00,
623 0x0C, 0x01,
624 0x0D, 0x81,
625 0x0E, 0x44,
626 0x0f, 0x14,
627 0x10, 0x3c,
628 0x11, 0x84,
629 0x12, 0xda,
630 0x13, 0x97,
631 0x14, 0x95,
632 0x15, 0xc9,
633 0x16, 0x19,
634 0x17, 0x8c,
635 0x18, 0x59,
636 0x19, 0xf8,
637 0x1a, 0xfe,
638 0x1c, 0x7f,
639 0x1d, 0x00,
640 0x1e, 0x00,
641 0x1f, 0x50,
642 0x20, 0x00,
643 0x21, 0x00,
644 0x22, 0x00,
645 0x23, 0x00,
646 0x28, 0x00,
647 0x29, 0x28,
648 0x2a, 0x14,
649 0x2b, 0x0f,
650 0x2c, 0x09,
651 0x2d, 0x09,
652 0x31, 0x1f,
653 0x32, 0x19,
654 0x33, 0xfc,
655 0x34, 0x93,
656 0xff, 0xff
657};
658
659static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
660{
661 stv0299_writereg(fe, 0x0e, 0x44);
662 if (srate >= 10000000) {
663 stv0299_writereg(fe, 0x13, 0x97);
664 stv0299_writereg(fe, 0x14, 0x95);
665 stv0299_writereg(fe, 0x15, 0xc9);
666 stv0299_writereg(fe, 0x17, 0x8c);
667 stv0299_writereg(fe, 0x1a, 0xfe);
668 stv0299_writereg(fe, 0x1c, 0x7f);
669 stv0299_writereg(fe, 0x2d, 0x09);
670 } else {
671 stv0299_writereg(fe, 0x13, 0x99);
672 stv0299_writereg(fe, 0x14, 0x8d);
673 stv0299_writereg(fe, 0x15, 0xce);
674 stv0299_writereg(fe, 0x17, 0x43);
675 stv0299_writereg(fe, 0x1a, 0x1d);
676 stv0299_writereg(fe, 0x1c, 0x12);
677 stv0299_writereg(fe, 0x2d, 0x05);
678 }
679 stv0299_writereg(fe, 0x0e, 0x23);
680 stv0299_writereg(fe, 0x0f, 0x94);
681 stv0299_writereg(fe, 0x10, 0x39);
682 stv0299_writereg(fe, 0x15, 0xc9);
683
684 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
685 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
686 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
687
688 return 0;
689}
690
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300691static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
692 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300694 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695 u32 div;
696 u8 buf[4];
697 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
698
699 if ((params->frequency < 950000) || (params->frequency > 2150000))
700 return -EINVAL;
701
702 div = (params->frequency + (500 - 1)) / 500; // round correctly
703 buf[0] = (div >> 8) & 0x7f;
704 buf[1] = div & 0xff;
705 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
706 buf[3] = 0x20;
707
708 if (params->u.qpsk.symbol_rate < 4000000)
709 buf[3] |= 1;
710
711 if (params->frequency < 1250000)
712 buf[3] |= 0;
713 else if (params->frequency < 1550000)
714 buf[3] |= 0x40;
715 else if (params->frequency < 2050000)
716 buf[3] |= 0x80;
717 else if (params->frequency < 2150000)
718 buf[3] |= 0xC0;
719
Patrick Boettcherdea74862006-05-14 05:01:31 -0300720 if (fe->ops.i2c_gate_ctrl)
721 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300722 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 return -EIO;
724 return 0;
725}
726
727static struct stv0299_config philips_su1278_tt_config = {
728
729 .demod_address = 0x68,
730 .inittab = philips_su1278_tt_inittab,
731 .mclk = 64000000UL,
732 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 .skip_reinit = 1,
Oliver Endrissda2c7f62008-04-20 22:13:37 -0300734 .lock_output = STV0299_LOCKOUTPUT_1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 .volt13_op0_op1 = STV0299_VOLT13_OP1,
736 .min_delay_ms = 50,
737 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738};
739
740
741
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300742static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
744 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
745 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
746 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700747 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 sizeof(td1316_init) };
749
750 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300751 if (fe->ops.i2c_gate_ctrl)
752 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
754 return -EIO;
755 msleep(1);
756
757 // disable the mc44BC374c (do not check for errors)
758 tuner_msg.addr = 0x65;
759 tuner_msg.buf = disable_mc44BC374c;
760 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300761 if (fe->ops.i2c_gate_ctrl)
762 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300764 if (fe->ops.i2c_gate_ctrl)
765 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
767 }
768
769 return 0;
770}
771
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300772static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773{
774 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
775 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700776 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 -0700777 int tuner_frequency = 0;
778 u8 band, cp, filter;
779
780 // determine charge pump
781 tuner_frequency = params->frequency + 36130000;
782 if (tuner_frequency < 87000000)
783 return -EINVAL;
784 else if (tuner_frequency < 130000000)
785 cp = 3;
786 else if (tuner_frequency < 160000000)
787 cp = 5;
788 else if (tuner_frequency < 200000000)
789 cp = 6;
790 else if (tuner_frequency < 290000000)
791 cp = 3;
792 else if (tuner_frequency < 420000000)
793 cp = 5;
794 else if (tuner_frequency < 480000000)
795 cp = 6;
796 else if (tuner_frequency < 620000000)
797 cp = 3;
798 else if (tuner_frequency < 830000000)
799 cp = 5;
800 else if (tuner_frequency < 895000000)
801 cp = 7;
802 else
803 return -EINVAL;
804
805 // determine band
806 if (params->frequency < 49000000)
807 return -EINVAL;
808 else if (params->frequency < 159000000)
809 band = 1;
810 else if (params->frequency < 444000000)
811 band = 2;
812 else if (params->frequency < 861000000)
813 band = 4;
814 else
815 return -EINVAL;
816
817 // setup PLL filter and TDA9889
818 switch (params->u.ofdm.bandwidth) {
819 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300820 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 filter = 0;
822 break;
823
824 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300825 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 filter = 0;
827 break;
828
829 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300830 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 filter = 1;
832 break;
833
834 default:
835 return -EINVAL;
836 }
837
838 // calculate divisor
839 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
840 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
841
842 // setup tuner buffer
843 tuner_buf[0] = tuner_frequency >> 8;
844 tuner_buf[1] = tuner_frequency & 0xff;
845 tuner_buf[2] = 0xca;
846 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
847
Patrick Boettcherdea74862006-05-14 05:01:31 -0300848 if (fe->ops.i2c_gate_ctrl)
849 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
851 return -EIO;
852
853 msleep(1);
854 return 0;
855}
856
857static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
858 const struct firmware **fw, char *name)
859{
860 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
861
862 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
863}
864
865static struct tda1004x_config philips_tdm1316l_config = {
866
867 .demod_address = 0x8,
868 .invert = 0,
869 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700870 .xtal_freq = TDA10046_XTAL_4M,
871 .agc_config = TDA10046_AGC_DEFAULT,
872 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 .request_firmware = philips_tdm1316l_request_firmware,
874};
875
Oliver Endriss6c914492007-02-02 19:12:53 -0300876static struct tda1004x_config philips_tdm1316l_config_invert = {
877
878 .demod_address = 0x8,
879 .invert = 1,
880 .invert_oclk = 0,
881 .xtal_freq = TDA10046_XTAL_4M,
882 .agc_config = TDA10046_AGC_DEFAULT,
883 .if_freq = TDA10046_FREQ_3617,
884 .request_firmware = philips_tdm1316l_request_firmware,
885};
886
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300887static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700888{
889 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
890 u8 tuner_buf[5];
891 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
892 .flags = 0,
893 .buf = tuner_buf,
894 .len = sizeof(tuner_buf) };
895 int tuner_frequency = 0;
896 u8 band, cp, filter;
897
898 // determine charge pump
899 tuner_frequency = params->frequency + 36125000;
900 if (tuner_frequency < 87000000)
901 return -EINVAL;
902 else if (tuner_frequency < 130000000) {
903 cp = 3;
904 band = 1;
905 } else if (tuner_frequency < 160000000) {
906 cp = 5;
907 band = 1;
908 } else if (tuner_frequency < 200000000) {
909 cp = 6;
Oliver Endriss910a7b62007-05-03 13:16:12 -0300910 band = 1;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700911 } else if (tuner_frequency < 290000000) {
912 cp = 3;
913 band = 2;
914 } else if (tuner_frequency < 420000000) {
915 cp = 5;
916 band = 2;
917 } else if (tuner_frequency < 480000000) {
918 cp = 6;
919 band = 2;
920 } else if (tuner_frequency < 620000000) {
921 cp = 3;
922 band = 4;
923 } else if (tuner_frequency < 830000000) {
924 cp = 5;
925 band = 4;
926 } else if (tuner_frequency < 895000000) {
927 cp = 7;
928 band = 4;
929 } else
930 return -EINVAL;
931
932 // assume PLL filter should always be 8MHz for the moment.
933 filter = 1;
934
935 // calculate divisor
936 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
937
938 // setup tuner buffer
939 tuner_buf[0] = tuner_frequency >> 8;
940 tuner_buf[1] = tuner_frequency & 0xff;
941 tuner_buf[2] = 0xc8;
942 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
943 tuner_buf[4] = 0x80;
944
Patrick Boettcherdea74862006-05-14 05:01:31 -0300945 if (fe->ops.i2c_gate_ctrl)
946 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700947 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
948 return -EIO;
949
950 msleep(50);
951
Patrick Boettcherdea74862006-05-14 05:01:31 -0300952 if (fe->ops.i2c_gate_ctrl)
953 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700954 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
955 return -EIO;
956
957 msleep(1);
958
959 return 0;
960}
961
962static u8 dvbc_philips_tdm1316l_inittab[] = {
963 0x80, 0x01,
964 0x80, 0x00,
965 0x81, 0x01,
966 0x81, 0x00,
967 0x00, 0x09,
968 0x01, 0x69,
969 0x03, 0x00,
970 0x04, 0x00,
971 0x07, 0x00,
972 0x08, 0x00,
973 0x20, 0x00,
974 0x21, 0x40,
975 0x22, 0x00,
976 0x23, 0x00,
977 0x24, 0x40,
978 0x25, 0x88,
979 0x30, 0xff,
980 0x31, 0x00,
981 0x32, 0xff,
982 0x33, 0x00,
983 0x34, 0x50,
984 0x35, 0x7f,
985 0x36, 0x00,
986 0x37, 0x20,
987 0x38, 0x00,
988 0x40, 0x1c,
989 0x41, 0xff,
990 0x42, 0x29,
991 0x43, 0x20,
992 0x44, 0xff,
993 0x45, 0x00,
994 0x46, 0x00,
995 0x49, 0x04,
996 0x4a, 0x00,
997 0x4b, 0x7b,
998 0x52, 0x30,
999 0x55, 0xae,
1000 0x56, 0x47,
1001 0x57, 0xe1,
1002 0x58, 0x3a,
1003 0x5a, 0x1e,
1004 0x5b, 0x34,
1005 0x60, 0x00,
1006 0x63, 0x00,
1007 0x64, 0x00,
1008 0x65, 0x00,
1009 0x66, 0x00,
1010 0x67, 0x00,
1011 0x68, 0x00,
1012 0x69, 0x00,
1013 0x6a, 0x02,
1014 0x6b, 0x00,
1015 0x70, 0xff,
1016 0x71, 0x00,
1017 0x72, 0x00,
1018 0x73, 0x00,
1019 0x74, 0x0c,
1020 0x80, 0x00,
1021 0x81, 0x00,
1022 0x82, 0x00,
1023 0x83, 0x00,
1024 0x84, 0x04,
1025 0x85, 0x80,
1026 0x86, 0x24,
1027 0x87, 0x78,
1028 0x88, 0x10,
1029 0x89, 0x00,
1030 0x90, 0x01,
1031 0x91, 0x01,
1032 0xa0, 0x04,
1033 0xa1, 0x00,
1034 0xa2, 0x00,
1035 0xb0, 0x91,
1036 0xb1, 0x0b,
1037 0xc0, 0x53,
1038 0xc1, 0x70,
1039 0xc2, 0x12,
1040 0xd0, 0x00,
1041 0xd1, 0x00,
1042 0xd2, 0x00,
1043 0xd3, 0x00,
1044 0xd4, 0x00,
1045 0xd5, 0x00,
1046 0xde, 0x00,
1047 0xdf, 0x00,
1048 0x61, 0x38,
1049 0x62, 0x0a,
1050 0x53, 0x13,
1051 0x59, 0x08,
1052 0xff, 0xff,
1053};
1054
1055static struct stv0297_config dvbc_philips_tdm1316l_config = {
1056 .demod_address = 0x1c,
1057 .inittab = dvbc_philips_tdm1316l_inittab,
1058 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001059 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001060};
1061
Sigmund Augdal11417da2008-06-15 17:25:46 -03001062static struct tda10023_config tda10023_config = {
1063 .demod_address = 0xc,
1064 .invert = 0,
1065 .xtal = 16000000,
1066 .pll_m = 11,
1067 .pll_p = 3,
1068 .pll_n = 1,
1069 .deltaf = 0xa511,
1070};
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001071
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
1073
1074static void frontend_init(struct budget_ci *budget_ci)
1075{
1076 switch (budget_ci->budget.dev->pci->subsystem_device) {
1077 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1078 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001079 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001081 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001082 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 break;
1084 }
1085 break;
1086
1087 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1088 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001089 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001091 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 break;
1093 }
1094 break;
1095
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001096 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1097 budget_ci->tuner_pll_address = 0x61;
1098 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001099 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001100 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001101 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001102 break;
1103 }
1104 break;
1105
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001107 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001109 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001111 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1112 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 break;
1114 }
1115 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001116
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001117 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001118 budget_ci->tuner_pll_address = 0x60;
1119 budget_ci->budget.dvb_frontend =
Oliver Endriss6c914492007-02-02 19:12:53 -03001120 dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001121 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001122 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1123 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001124 break;
1125 }
1126 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001127
1128 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001129 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001130 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001131 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001132 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1133
Patrick Boettcherdea74862006-05-14 05:01:31 -03001134 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001135 if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) {
Harvey Harrison3ca7fc82008-04-08 23:20:00 -03001136 printk("%s: No LNBP21 found!\n", __func__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001137 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001138 budget_ci->budget.dvb_frontend = NULL;
1139 }
1140 }
Sigmund Augdal11417da2008-06-15 17:25:46 -03001141 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001142
Sigmund Augdal11417da2008-06-15 17:25:46 -03001143 case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
1144 budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
1145 if (budget_ci->budget.dvb_frontend) {
1146 if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
1147 printk(KERN_ERR "%s: No tda827x found!\n", __func__);
1148 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1149 budget_ci->budget.dvb_frontend = NULL;
1150 }
1151 }
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001152 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 }
1154
1155 if (budget_ci->budget.dvb_frontend == NULL) {
1156 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1157 budget_ci->budget.dev->pci->vendor,
1158 budget_ci->budget.dev->pci->device,
1159 budget_ci->budget.dev->pci->subsystem_vendor,
1160 budget_ci->budget.dev->pci->subsystem_device);
1161 } else {
1162 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001163 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001164 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001165 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 budget_ci->budget.dvb_frontend = NULL;
1167 }
1168 }
1169}
1170
1171static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1172{
1173 struct budget_ci *budget_ci;
1174 int err;
1175
David Hardemanee579bc2006-12-02 21:16:05 -02001176 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001177 if (!budget_ci) {
1178 err = -ENOMEM;
1179 goto out1;
1180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001181
1182 dprintk(2, "budget_ci: %p\n", budget_ci);
1183
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 dev->ext_priv = budget_ci;
1185
David Hardeman8cc532e2006-12-02 21:16:05 -02001186 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1187 if (err)
1188 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189
David Hardeman8cc532e2006-12-02 21:16:05 -02001190 err = msp430_ir_init(budget_ci);
1191 if (err)
1192 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193
1194 ciintf_init(budget_ci);
1195
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001196 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 frontend_init(budget_ci);
1198
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001199 ttpci_budget_init_hooks(&budget_ci->budget);
1200
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001202
1203out3:
1204 ttpci_budget_deinit(&budget_ci->budget);
1205out2:
1206 kfree(budget_ci);
1207out1:
1208 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209}
1210
1211static int budget_ci_detach(struct saa7146_dev *dev)
1212{
1213 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1214 struct saa7146_dev *saa = budget_ci->budget.dev;
1215 int err;
1216
1217 if (budget_ci->budget.ci_present)
1218 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001219 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001220 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001222 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001223 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 err = ttpci_budget_deinit(&budget_ci->budget);
1225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 // disable frontend and CI interface
1227 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1228
1229 kfree(budget_ci);
1230
1231 return err;
1232}
1233
1234static struct saa7146_extension budget_extension;
1235
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001236MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1238MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001239MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001240MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Sigmund Augdal11417da2008-06-15 17:25:46 -03001241MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
1243static struct pci_device_id pci_tbl[] = {
1244 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1245 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001246 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001248 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001249 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Sigmund Augdal11417da2008-06-15 17:25:46 -03001250 MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 {
1252 .vendor = 0,
1253 }
1254};
1255
1256MODULE_DEVICE_TABLE(pci, pci_tbl);
1257
1258static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001259 .name = "budget_ci dvb",
Oliver Endriss00c4cc62006-11-01 13:09:51 -03001260 .flags = SAA7146_USE_I2C_IRQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261
1262 .module = THIS_MODULE,
1263 .pci_tbl = &pci_tbl[0],
1264 .attach = budget_ci_attach,
1265 .detach = budget_ci_detach,
1266
1267 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1268 .irq_func = budget_ci_irq,
1269};
1270
1271static int __init budget_ci_init(void)
1272{
1273 return saa7146_register_extension(&budget_extension);
1274}
1275
1276static void __exit budget_ci_exit(void)
1277{
1278 saa7146_unregister_extension(&budget_extension);
1279}
1280
1281module_init(budget_ci_init);
1282module_exit(budget_ci_exit);
1283
1284MODULE_LICENSE("GPL");
1285MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1286MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1287 "budget PCI DVB cards w/ CI-module produced by "
1288 "Siemens, Technotrend, Hauppauge");