blob: bf8b4934cb7ca756728932494ef152beba4b6e53 [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 *
Mauro Carvalho Chehabaf86ce72011-01-24 12:18:48 -030029 * the project's page is at http://www.linuxtv.org/
Linus Torvalds1da177e2005-04-16 15:20:36 -070030 */
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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/spinlock.h>
Mauro Carvalho Chehab6bda9642010-11-17 13:28:38 -030037#include <media/rc-core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
Trent Piepho68277092007-01-30 23:25:46 -030039#include "budget.h"
40
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include "dvb_ca_en50221.h"
42#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070043#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include "tda1004x.h"
Marko Schluessler9e0dc662008-10-23 18:16:40 -030045#include "stb0899_drv.h"
46#include "stb0899_reg.h"
Manu Abraham8be969b2008-01-25 18:20:48 -030047#include "stb0899_cfg.h"
Marko Schluessler9e0dc662008-10-23 18:16:40 -030048#include "stb6100.h"
Manu Abraham8be969b2008-01-25 18:20:48 -030049#include "stb6100_cfg.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030050#include "lnbp21.h"
51#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030052#include "bsru6.h"
Sigmund Augdal11417da2008-06-15 17:25:46 -030053#include "tda1002x.h"
54#include "tda827x.h"
Oliver Endriss574312d2011-03-29 17:37:00 -030055#include "bsbe1-d01a.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Mauro Carvalho Chehab727e6252010-03-12 21:18:14 -030057#define MODULE_NAME "budget_ci"
58
David Härdemanecba77f2006-10-27 20:56:51 -030059/*
60 * Regarding DEBIADDR_IR:
61 * Some CI modules hang if random addresses are read.
62 * Using address 0x4000 for the IR read means that we
63 * use the same address as for CI version, which should
64 * be a safe default.
65 */
66#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070067#define DEBIADDR_CICONTROL 0x0000
68#define DEBIADDR_CIVERSION 0x4000
69#define DEBIADDR_IO 0x1000
70#define DEBIADDR_ATTR 0x3000
71
72#define CICONTROL_RESET 0x01
73#define CICONTROL_ENABLETS 0x02
74#define CICONTROL_CAMDETECT 0x08
75
76#define DEBICICTL 0x00420000
77#define DEBICICAM 0x02420000
78
79#define SLOTSTATUS_NONE 1
80#define SLOTSTATUS_PRESENT 2
81#define SLOTSTATUS_RESET 4
82#define SLOTSTATUS_READY 8
83#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
84
David Hardeman64741b72006-12-02 21:16:05 -020085/* RC5 device wildcard */
86#define IR_DEVICE_ANY 255
87
David Hardeman64741b72006-12-02 21:16:05 -020088static int rc5_device = -1;
89module_param(rc5_device, int, 0644);
90MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
91
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030092static int ir_debug;
David Hardemanb5471a22006-12-02 21:16:05 -020093module_param(ir_debug, int, 0644);
94MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
95
Janne Grunau26dc4d02008-09-21 20:50:11 -030096DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
97
David Hardemandd2f3982006-12-02 21:16:05 -020098struct budget_ci_ir {
David Härdemand8b4b582010-10-29 16:08:23 -030099 struct rc_dev *dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200100 struct tasklet_struct msp430_irq_tasklet;
101 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -0200102 char phys[32];
David Hardeman64741b72006-12-02 21:16:05 -0200103 int rc5_device;
David Härdeman145859c2007-04-27 12:31:22 -0300104 u32 ir_key;
105 bool have_command;
Mauro Carvalho Chehabaf86ce72011-01-24 12:18:48 -0300106 bool full_rc5; /* Outputs a full RC5 code */
David Hardemandd2f3982006-12-02 21:16:05 -0200107};
108
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109struct budget_ci {
110 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 struct tasklet_struct ciintf_irq_tasklet;
112 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300113 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -0200115 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700116 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117};
118
David Hardeman2520fff2006-12-02 21:16:05 -0200119static void msp430_ir_interrupt(unsigned long data)
120{
121 struct budget_ci *budget_ci = (struct budget_ci *) data;
David Härdemand8b4b582010-10-29 16:08:23 -0300122 struct rc_dev *dev = budget_ci->ir.dev;
David Hardeman2520fff2006-12-02 21:16:05 -0200123 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
124
David Hardeman64741b72006-12-02 21:16:05 -0200125 /*
126 * The msp430 chip can generate two different bytes, command and device
127 *
128 * type1: X1CCCCCC, C = command bits (0 - 63)
129 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
130 *
David Härdeman59327a42007-02-13 09:39:58 -0300131 * Each signal from the remote control can generate one or more command
132 * bytes and one or more device bytes. For the repeated bytes, the
133 * highest bit (X) is set. The first command byte is always generated
134 * before the first device byte. Other than that, no specific order
David Härdeman145859c2007-04-27 12:31:22 -0300135 * seems to apply. To make life interesting, bytes can also be lost.
David Härdeman59327a42007-02-13 09:39:58 -0300136 *
137 * Only when we have a command and device byte, a keypress is
138 * generated.
David Hardeman64741b72006-12-02 21:16:05 -0200139 */
140
David Härdeman59327a42007-02-13 09:39:58 -0300141 if (ir_debug)
142 printk("budget_ci: received byte 0x%02x\n", command);
143
David Härdeman145859c2007-04-27 12:31:22 -0300144 /* Remove repeat bit, we use every command */
145 command = command & 0x7f;
David Härdeman59327a42007-02-13 09:39:58 -0300146
David Hardeman64741b72006-12-02 21:16:05 -0200147 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200148 if (command & 0x40) {
David Härdeman145859c2007-04-27 12:31:22 -0300149 budget_ci->ir.have_command = true;
150 budget_ci->ir.ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200151 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200152 }
David Hardeman64741b72006-12-02 21:16:05 -0200153
154 /* It's a RC5 device byte */
David Härdeman145859c2007-04-27 12:31:22 -0300155 if (!budget_ci->ir.have_command)
David Härdeman59327a42007-02-13 09:39:58 -0300156 return;
David Härdeman145859c2007-04-27 12:31:22 -0300157 budget_ci->ir.have_command = false;
David Hardeman64741b72006-12-02 21:16:05 -0200158
David Härdeman145859c2007-04-27 12:31:22 -0300159 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
160 budget_ci->ir.rc5_device != (command & 0x1f))
David Hardeman64741b72006-12-02 21:16:05 -0200161 return;
162
Mauro Carvalho Chehabaf86ce72011-01-24 12:18:48 -0300163 if (budget_ci->ir.full_rc5) {
164 rc_keydown(dev,
165 budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key,
166 (command & 0x20) ? 1 : 0);
167 return;
168 }
169
170 /* FIXME: We should generate complete scancodes for all devices */
Mauro Carvalho Chehabca866742010-11-17 13:53:11 -0300171 rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
David Hardeman2520fff2006-12-02 21:16:05 -0200172}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174static int msp430_ir_init(struct budget_ci *budget_ci)
175{
176 struct saa7146_dev *saa = budget_ci->budget.dev;
David Härdemand8b4b582010-10-29 16:08:23 -0300177 struct rc_dev *dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200178 int error;
Mauro Carvalho Chehab579e7d62009-12-11 11:20:59 -0300179
David Härdemand8b4b582010-10-29 16:08:23 -0300180 dev = rc_allocate_device();
181 if (!dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200182 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
Mauro Carvalho Chehab579e7d62009-12-11 11:20:59 -0300183 return -ENOMEM;
David Hardeman8cc532e2006-12-02 21:16:05 -0200184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185
David Hardemandd2f3982006-12-02 21:16:05 -0200186 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
187 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200188 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
189 "pci-%s/ir0", pci_name(saa->pci));
190
David Härdemand8b4b582010-10-29 16:08:23 -0300191 dev->driver_name = MODULE_NAME;
192 dev->input_name = budget_ci->ir.name;
193 dev->input_phys = budget_ci->ir.phys;
194 dev->input_id.bustype = BUS_PCI;
195 dev->input_id.version = 1;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200196 if (saa->pci->subsystem_vendor) {
David Härdemand8b4b582010-10-29 16:08:23 -0300197 dev->input_id.vendor = saa->pci->subsystem_vendor;
198 dev->input_id.product = saa->pci->subsystem_device;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200199 } else {
David Härdemand8b4b582010-10-29 16:08:23 -0300200 dev->input_id.vendor = saa->pci->vendor;
201 dev->input_id.product = saa->pci->device;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200202 }
David Härdemand8b4b582010-10-29 16:08:23 -0300203 dev->dev.parent = &saa->pci->dev;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200204
Mauro Carvalho Chehab579e7d62009-12-11 11:20:59 -0300205 if (rc5_device < 0)
206 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
207 else
208 budget_ci->ir.rc5_device = rc5_device;
209
David Hardeman64741b72006-12-02 21:16:05 -0200210 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200211 switch (budget_ci->budget.dev->pci->subsystem_device) {
212 case 0x100c:
213 case 0x100f:
David Hardeman2520fff2006-12-02 21:16:05 -0200214 case 0x1011:
215 case 0x1012:
David Hardeman2520fff2006-12-02 21:16:05 -0200216 /* The hauppauge keymap is a superset of these remotes */
Mauro Carvalho Chehabaf86ce72011-01-24 12:18:48 -0300217 dev->map_name = RC_MAP_HAUPPAUGE;
218 budget_ci->ir.full_rc5 = true;
David Hardeman64741b72006-12-02 21:16:05 -0200219
220 if (rc5_device < 0)
221 budget_ci->ir.rc5_device = 0x1f;
David Hardeman2520fff2006-12-02 21:16:05 -0200222 break;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300223 case 0x1010:
Oliver Endrissf64899c2007-09-17 22:17:12 -0300224 case 0x1017:
Hermann Gaustererf137f9d2010-05-18 04:26:17 -0300225 case 0x1019:
Oliver Endrissbbfc4c22008-06-19 23:36:45 -0300226 case 0x101a:
Oliver Endriss574312d2011-03-29 17:37:00 -0300227 case 0x101b:
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300228 /* for the Technotrend 1500 bundled remote */
David Härdemand8b4b582010-10-29 16:08:23 -0300229 dev->map_name = RC_MAP_TT_1500;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300230 break;
David Hardeman2520fff2006-12-02 21:16:05 -0200231 default:
232 /* unknown remote */
David Härdemand8b4b582010-10-29 16:08:23 -0300233 dev->map_name = RC_MAP_BUDGET_CI_OLD;
David Hardeman2520fff2006-12-02 21:16:05 -0200234 break;
235 }
Mauro Carvalho Chehab5183c132011-12-17 09:03:29 -0200236 if (!budget_ci->ir.full_rc5)
237 dev->scanmask = 0xff;
David Hardeman2520fff2006-12-02 21:16:05 -0200238
David Härdemand8b4b582010-10-29 16:08:23 -0300239 error = rc_register_device(dev);
David Hardeman8cc532e2006-12-02 21:16:05 -0200240 if (error) {
241 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
David Härdemand8b4b582010-10-29 16:08:23 -0300242 rc_free_device(dev);
Mauro Carvalho Chehab579e7d62009-12-11 11:20:59 -0300243 return error;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300244 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
David Härdemand8b4b582010-10-29 16:08:23 -0300246 budget_ci->ir.dev = dev;
David Härdeman145859c2007-04-27 12:31:22 -0300247
David Hardeman8cc532e2006-12-02 21:16:05 -0200248 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
249 (unsigned long) budget_ci);
250
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300251 SAA7146_IER_ENABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
253
254 return 0;
255}
256
257static void msp430_ir_deinit(struct budget_ci *budget_ci)
258{
259 struct saa7146_dev *saa = budget_ci->budget.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300261 SAA7146_IER_DISABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200263 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
David Härdemand8b4b582010-10-29 16:08:23 -0300265 rc_unregister_device(budget_ci->ir.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266}
267
268static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
269{
270 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
271
272 if (slot != 0)
273 return -EINVAL;
274
275 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
276 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
277}
278
279static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
280{
281 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
282
283 if (slot != 0)
284 return -EINVAL;
285
286 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
287 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
288}
289
290static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
291{
292 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
293
294 if (slot != 0)
295 return -EINVAL;
296
297 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
298 DEBIADDR_IO | (address & 3), 1, 1, 0);
299}
300
301static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
302{
303 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
304
305 if (slot != 0)
306 return -EINVAL;
307
308 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
309 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
310}
311
312static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
313{
314 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
315 struct saa7146_dev *saa = budget_ci->budget.dev;
316
317 if (slot != 0)
318 return -EINVAL;
319
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300320 if (budget_ci->ci_irq) {
321 // trigger on RISING edge during reset so we know when READY is re-asserted
322 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
323 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 budget_ci->slot_status = SLOTSTATUS_RESET;
325 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
326 msleep(1);
327 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
328 CICONTROL_RESET, 1, 0);
329
330 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
331 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
332 return 0;
333}
334
335static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
336{
337 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
338 struct saa7146_dev *saa = budget_ci->budget.dev;
339
340 if (slot != 0)
341 return -EINVAL;
342
343 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
344 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
345 return 0;
346}
347
348static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
349{
350 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
351 struct saa7146_dev *saa = budget_ci->budget.dev;
352 int tmp;
353
354 if (slot != 0)
355 return -EINVAL;
356
357 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
358
359 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
360 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
361 tmp | CICONTROL_ENABLETS, 1, 0);
362
363 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
364 return 0;
365}
366
367static void ciintf_interrupt(unsigned long data)
368{
369 struct budget_ci *budget_ci = (struct budget_ci *) data;
370 struct saa7146_dev *saa = budget_ci->budget.dev;
371 unsigned int flags;
372
373 // ensure we don't get spurious IRQs during initialisation
374 if (!budget_ci->budget.ci_present)
375 return;
376
377 // read the CAM status
378 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
379 if (flags & CICONTROL_CAMDETECT) {
380
381 // GPIO should be set to trigger on falling edge if a CAM is present
382 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
383
384 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
385 // CAM insertion IRQ
386 budget_ci->slot_status = SLOTSTATUS_PRESENT;
387 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
388 DVB_CA_EN50221_CAMCHANGE_INSERTED);
389
390 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
391 // CAM ready (reset completed)
392 budget_ci->slot_status = SLOTSTATUS_READY;
393 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
394
395 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
396 // FR/DA IRQ
397 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
398 }
399 } else {
400
401 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
402 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
403 // the CAM might not actually be ready yet.
404 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
405
406 // generate a CAM removal IRQ if we haven't already
407 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
408 // CAM removal IRQ
409 budget_ci->slot_status = SLOTSTATUS_NONE;
410 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
411 DVB_CA_EN50221_CAMCHANGE_REMOVED);
412 }
413 }
414}
415
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300416static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
417{
418 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
419 unsigned int flags;
420
421 // ensure we don't get spurious IRQs during initialisation
422 if (!budget_ci->budget.ci_present)
423 return -EINVAL;
424
425 // read the CAM status
426 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
427 if (flags & CICONTROL_CAMDETECT) {
428 // mark it as present if it wasn't before
429 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
430 budget_ci->slot_status = SLOTSTATUS_PRESENT;
431 }
432
433 // during a RESET, we check if we can read from IO memory to see when CAM is ready
434 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
435 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
436 budget_ci->slot_status = SLOTSTATUS_READY;
437 }
438 }
439 } else {
440 budget_ci->slot_status = SLOTSTATUS_NONE;
441 }
442
443 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
444 if (budget_ci->slot_status & SLOTSTATUS_READY) {
445 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
446 }
447 return DVB_CA_EN50221_POLL_CAM_PRESENT;
448 }
449
450 return 0;
451}
452
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453static int ciintf_init(struct budget_ci *budget_ci)
454{
455 struct saa7146_dev *saa = budget_ci->budget.dev;
456 int flags;
457 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300458 int ci_version;
459 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460
461 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
462
463 // enable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300464 saa7146_write(saa, MC1, MASK_27 | MASK_11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300467 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
468 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 result = -ENODEV;
470 goto error;
471 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300472
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 // determine whether a CAM is present or not
474 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
475 budget_ci->slot_status = SLOTSTATUS_NONE;
476 if (flags & CICONTROL_CAMDETECT)
477 budget_ci->slot_status = SLOTSTATUS_PRESENT;
478
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300479 // version 0xa2 of the CI firmware doesn't generate interrupts
480 if (ci_version == 0xa2) {
481 ca_flags = 0;
482 budget_ci->ci_irq = 0;
483 } else {
484 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
485 DVB_CA_EN50221_FLAG_IRQ_FR |
486 DVB_CA_EN50221_FLAG_IRQ_DA;
487 budget_ci->ci_irq = 1;
488 }
489
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 // register CI interface
491 budget_ci->ca.owner = THIS_MODULE;
492 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
493 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
494 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
495 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
496 budget_ci->ca.slot_reset = ciintf_slot_reset;
497 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
498 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300499 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700501 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300503 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 printk("budget_ci: CI interface detected, but initialisation failed.\n");
505 goto error;
506 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300509 if (budget_ci->ci_irq) {
510 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
511 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
512 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
513 } else {
514 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
515 }
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300516 SAA7146_IER_ENABLE(saa, MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300518
519 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
521 CICONTROL_RESET, 1, 0);
522
523 // success!
524 printk("budget_ci: CI interface initialised\n");
525 budget_ci->budget.ci_present = 1;
526
527 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300528 if (budget_ci->ci_irq) {
529 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
530 if (budget_ci->slot_status != SLOTSTATUS_NONE)
531 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
532 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
533 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
535 return 0;
536
537error:
Hartmut Birr2a893de2006-12-03 21:08:08 -0300538 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 return result;
540}
541
542static void ciintf_deinit(struct budget_ci *budget_ci)
543{
544 struct saa7146_dev *saa = budget_ci->budget.dev;
545
546 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300547 if (budget_ci->ci_irq) {
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300548 SAA7146_IER_DISABLE(saa, MASK_03);
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300549 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
550 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
551 }
552
553 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
555 msleep(1);
556 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
557 CICONTROL_RESET, 1, 0);
558
559 // disable TS data stream to CI interface
560 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
561
562 // release the CA device
563 dvb_ca_en50221_release(&budget_ci->ca);
564
565 // disable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300566 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567}
568
569static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
570{
571 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
572
573 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
574
575 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200576 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700577
578 if (*isr & MASK_10)
579 ttpci_budget_irq10_handler(dev, isr);
580
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300581 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
583}
584
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585static u8 philips_su1278_tt_inittab[] = {
586 0x01, 0x0f,
587 0x02, 0x30,
588 0x03, 0x00,
589 0x04, 0x5b,
590 0x05, 0x85,
591 0x06, 0x02,
592 0x07, 0x00,
593 0x08, 0x02,
594 0x09, 0x00,
595 0x0C, 0x01,
596 0x0D, 0x81,
597 0x0E, 0x44,
598 0x0f, 0x14,
599 0x10, 0x3c,
600 0x11, 0x84,
601 0x12, 0xda,
602 0x13, 0x97,
603 0x14, 0x95,
604 0x15, 0xc9,
605 0x16, 0x19,
606 0x17, 0x8c,
607 0x18, 0x59,
608 0x19, 0xf8,
609 0x1a, 0xfe,
610 0x1c, 0x7f,
611 0x1d, 0x00,
612 0x1e, 0x00,
613 0x1f, 0x50,
614 0x20, 0x00,
615 0x21, 0x00,
616 0x22, 0x00,
617 0x23, 0x00,
618 0x28, 0x00,
619 0x29, 0x28,
620 0x2a, 0x14,
621 0x2b, 0x0f,
622 0x2c, 0x09,
623 0x2d, 0x09,
624 0x31, 0x1f,
625 0x32, 0x19,
626 0x33, 0xfc,
627 0x34, 0x93,
628 0xff, 0xff
629};
630
631static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
632{
633 stv0299_writereg(fe, 0x0e, 0x44);
634 if (srate >= 10000000) {
635 stv0299_writereg(fe, 0x13, 0x97);
636 stv0299_writereg(fe, 0x14, 0x95);
637 stv0299_writereg(fe, 0x15, 0xc9);
638 stv0299_writereg(fe, 0x17, 0x8c);
639 stv0299_writereg(fe, 0x1a, 0xfe);
640 stv0299_writereg(fe, 0x1c, 0x7f);
641 stv0299_writereg(fe, 0x2d, 0x09);
642 } else {
643 stv0299_writereg(fe, 0x13, 0x99);
644 stv0299_writereg(fe, 0x14, 0x8d);
645 stv0299_writereg(fe, 0x15, 0xce);
646 stv0299_writereg(fe, 0x17, 0x43);
647 stv0299_writereg(fe, 0x1a, 0x1d);
648 stv0299_writereg(fe, 0x1c, 0x12);
649 stv0299_writereg(fe, 0x2d, 0x05);
650 }
651 stv0299_writereg(fe, 0x0e, 0x23);
652 stv0299_writereg(fe, 0x0f, 0x94);
653 stv0299_writereg(fe, 0x10, 0x39);
654 stv0299_writereg(fe, 0x15, 0xc9);
655
656 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
657 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
658 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
659
660 return 0;
661}
662
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300663static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
664 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665{
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300666 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300667 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668 u32 div;
669 u8 buf[4];
670 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
671
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300672 if ((p->frequency < 950000) || (p->frequency > 2150000))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 return -EINVAL;
674
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300675 div = (p->frequency + (500 - 1)) / 500; /* round correctly */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 buf[0] = (div >> 8) & 0x7f;
677 buf[1] = div & 0xff;
678 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
679 buf[3] = 0x20;
680
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300681 if (p->symbol_rate < 4000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 buf[3] |= 1;
683
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300684 if (p->frequency < 1250000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685 buf[3] |= 0;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300686 else if (p->frequency < 1550000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 buf[3] |= 0x40;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300688 else if (p->frequency < 2050000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 buf[3] |= 0x80;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300690 else if (p->frequency < 2150000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700691 buf[3] |= 0xC0;
692
Patrick Boettcherdea74862006-05-14 05:01:31 -0300693 if (fe->ops.i2c_gate_ctrl)
694 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300695 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696 return -EIO;
697 return 0;
698}
699
700static struct stv0299_config philips_su1278_tt_config = {
701
702 .demod_address = 0x68,
703 .inittab = philips_su1278_tt_inittab,
704 .mclk = 64000000UL,
705 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 .skip_reinit = 1,
Oliver Endrissda2c7f62008-04-20 22:13:37 -0300707 .lock_output = STV0299_LOCKOUTPUT_1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 .volt13_op0_op1 = STV0299_VOLT13_OP1,
709 .min_delay_ms = 50,
710 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711};
712
713
714
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300715static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
717 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
718 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
719 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700720 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721 sizeof(td1316_init) };
722
723 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300724 if (fe->ops.i2c_gate_ctrl)
725 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
727 return -EIO;
728 msleep(1);
729
730 // disable the mc44BC374c (do not check for errors)
731 tuner_msg.addr = 0x65;
732 tuner_msg.buf = disable_mc44BC374c;
733 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300734 if (fe->ops.i2c_gate_ctrl)
735 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300737 if (fe->ops.i2c_gate_ctrl)
738 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
740 }
741
742 return 0;
743}
744
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300745static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300747 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700748 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
749 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700750 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 -0700751 int tuner_frequency = 0;
752 u8 band, cp, filter;
753
754 // determine charge pump
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300755 tuner_frequency = p->frequency + 36130000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 if (tuner_frequency < 87000000)
757 return -EINVAL;
758 else if (tuner_frequency < 130000000)
759 cp = 3;
760 else if (tuner_frequency < 160000000)
761 cp = 5;
762 else if (tuner_frequency < 200000000)
763 cp = 6;
764 else if (tuner_frequency < 290000000)
765 cp = 3;
766 else if (tuner_frequency < 420000000)
767 cp = 5;
768 else if (tuner_frequency < 480000000)
769 cp = 6;
770 else if (tuner_frequency < 620000000)
771 cp = 3;
772 else if (tuner_frequency < 830000000)
773 cp = 5;
774 else if (tuner_frequency < 895000000)
775 cp = 7;
776 else
777 return -EINVAL;
778
779 // determine band
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300780 if (p->frequency < 49000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781 return -EINVAL;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300782 else if (p->frequency < 159000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 band = 1;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300784 else if (p->frequency < 444000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785 band = 2;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300786 else if (p->frequency < 861000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787 band = 4;
788 else
789 return -EINVAL;
790
791 // setup PLL filter and TDA9889
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300792 switch (p->bandwidth_hz) {
793 case 6000000:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300794 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795 filter = 0;
796 break;
797
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300798 case 7000000:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300799 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800 filter = 0;
801 break;
802
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300803 case 8000000:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300804 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805 filter = 1;
806 break;
807
808 default:
809 return -EINVAL;
810 }
811
812 // calculate divisor
813 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300814 tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700815
816 // setup tuner buffer
817 tuner_buf[0] = tuner_frequency >> 8;
818 tuner_buf[1] = tuner_frequency & 0xff;
819 tuner_buf[2] = 0xca;
820 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
821
Patrick Boettcherdea74862006-05-14 05:01:31 -0300822 if (fe->ops.i2c_gate_ctrl)
823 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
825 return -EIO;
826
827 msleep(1);
828 return 0;
829}
830
831static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
832 const struct firmware **fw, char *name)
833{
834 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
835
836 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
837}
838
839static struct tda1004x_config philips_tdm1316l_config = {
840
841 .demod_address = 0x8,
842 .invert = 0,
843 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700844 .xtal_freq = TDA10046_XTAL_4M,
845 .agc_config = TDA10046_AGC_DEFAULT,
846 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700847 .request_firmware = philips_tdm1316l_request_firmware,
848};
849
Oliver Endriss6c914492007-02-02 19:12:53 -0300850static struct tda1004x_config philips_tdm1316l_config_invert = {
851
852 .demod_address = 0x8,
853 .invert = 1,
854 .invert_oclk = 0,
855 .xtal_freq = TDA10046_XTAL_4M,
856 .agc_config = TDA10046_AGC_DEFAULT,
857 .if_freq = TDA10046_FREQ_3617,
858 .request_firmware = philips_tdm1316l_request_firmware,
859};
860
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300861static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700862{
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300863 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700864 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
865 u8 tuner_buf[5];
866 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
867 .flags = 0,
868 .buf = tuner_buf,
869 .len = sizeof(tuner_buf) };
870 int tuner_frequency = 0;
871 u8 band, cp, filter;
872
873 // determine charge pump
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300874 tuner_frequency = p->frequency + 36125000;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700875 if (tuner_frequency < 87000000)
876 return -EINVAL;
877 else if (tuner_frequency < 130000000) {
878 cp = 3;
879 band = 1;
880 } else if (tuner_frequency < 160000000) {
881 cp = 5;
882 band = 1;
883 } else if (tuner_frequency < 200000000) {
884 cp = 6;
Oliver Endriss910a7b62007-05-03 13:16:12 -0300885 band = 1;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700886 } else if (tuner_frequency < 290000000) {
887 cp = 3;
888 band = 2;
889 } else if (tuner_frequency < 420000000) {
890 cp = 5;
891 band = 2;
892 } else if (tuner_frequency < 480000000) {
893 cp = 6;
894 band = 2;
895 } else if (tuner_frequency < 620000000) {
896 cp = 3;
897 band = 4;
898 } else if (tuner_frequency < 830000000) {
899 cp = 5;
900 band = 4;
901 } else if (tuner_frequency < 895000000) {
902 cp = 7;
903 band = 4;
904 } else
905 return -EINVAL;
906
907 // assume PLL filter should always be 8MHz for the moment.
908 filter = 1;
909
910 // calculate divisor
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300911 tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700912
913 // setup tuner buffer
914 tuner_buf[0] = tuner_frequency >> 8;
915 tuner_buf[1] = tuner_frequency & 0xff;
916 tuner_buf[2] = 0xc8;
917 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
918 tuner_buf[4] = 0x80;
919
Patrick Boettcherdea74862006-05-14 05:01:31 -0300920 if (fe->ops.i2c_gate_ctrl)
921 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700922 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
923 return -EIO;
924
925 msleep(50);
926
Patrick Boettcherdea74862006-05-14 05:01:31 -0300927 if (fe->ops.i2c_gate_ctrl)
928 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700929 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
930 return -EIO;
931
932 msleep(1);
933
934 return 0;
935}
936
937static u8 dvbc_philips_tdm1316l_inittab[] = {
938 0x80, 0x01,
939 0x80, 0x00,
940 0x81, 0x01,
941 0x81, 0x00,
942 0x00, 0x09,
943 0x01, 0x69,
944 0x03, 0x00,
945 0x04, 0x00,
946 0x07, 0x00,
947 0x08, 0x00,
948 0x20, 0x00,
949 0x21, 0x40,
950 0x22, 0x00,
951 0x23, 0x00,
952 0x24, 0x40,
953 0x25, 0x88,
954 0x30, 0xff,
955 0x31, 0x00,
956 0x32, 0xff,
957 0x33, 0x00,
958 0x34, 0x50,
959 0x35, 0x7f,
960 0x36, 0x00,
961 0x37, 0x20,
962 0x38, 0x00,
963 0x40, 0x1c,
964 0x41, 0xff,
965 0x42, 0x29,
966 0x43, 0x20,
967 0x44, 0xff,
968 0x45, 0x00,
969 0x46, 0x00,
970 0x49, 0x04,
971 0x4a, 0x00,
972 0x4b, 0x7b,
973 0x52, 0x30,
974 0x55, 0xae,
975 0x56, 0x47,
976 0x57, 0xe1,
977 0x58, 0x3a,
978 0x5a, 0x1e,
979 0x5b, 0x34,
980 0x60, 0x00,
981 0x63, 0x00,
982 0x64, 0x00,
983 0x65, 0x00,
984 0x66, 0x00,
985 0x67, 0x00,
986 0x68, 0x00,
987 0x69, 0x00,
988 0x6a, 0x02,
989 0x6b, 0x00,
990 0x70, 0xff,
991 0x71, 0x00,
992 0x72, 0x00,
993 0x73, 0x00,
994 0x74, 0x0c,
995 0x80, 0x00,
996 0x81, 0x00,
997 0x82, 0x00,
998 0x83, 0x00,
999 0x84, 0x04,
1000 0x85, 0x80,
1001 0x86, 0x24,
1002 0x87, 0x78,
1003 0x88, 0x10,
1004 0x89, 0x00,
1005 0x90, 0x01,
1006 0x91, 0x01,
1007 0xa0, 0x04,
1008 0xa1, 0x00,
1009 0xa2, 0x00,
1010 0xb0, 0x91,
1011 0xb1, 0x0b,
1012 0xc0, 0x53,
1013 0xc1, 0x70,
1014 0xc2, 0x12,
1015 0xd0, 0x00,
1016 0xd1, 0x00,
1017 0xd2, 0x00,
1018 0xd3, 0x00,
1019 0xd4, 0x00,
1020 0xd5, 0x00,
1021 0xde, 0x00,
1022 0xdf, 0x00,
1023 0x61, 0x38,
1024 0x62, 0x0a,
1025 0x53, 0x13,
1026 0x59, 0x08,
1027 0xff, 0xff,
1028};
1029
1030static struct stv0297_config dvbc_philips_tdm1316l_config = {
1031 .demod_address = 0x1c,
1032 .inittab = dvbc_philips_tdm1316l_inittab,
1033 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001034 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001035};
1036
Sigmund Augdal11417da2008-06-15 17:25:46 -03001037static struct tda10023_config tda10023_config = {
1038 .demod_address = 0xc,
1039 .invert = 0,
1040 .xtal = 16000000,
1041 .pll_m = 11,
1042 .pll_p = 3,
1043 .pll_n = 1,
1044 .deltaf = 0xa511,
1045};
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001046
klaas de waalcf47d872009-03-25 17:53:02 -03001047static struct tda827x_config tda827x_config = {
1048 .config = 0,
1049};
1050
Manu Abrahama55bc842008-10-23 18:32:50 -03001051/* TT S2-3200 DVB-S (STB0899) Inittab */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001052static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001054 { STB0899_DEV_ID , 0x81 },
1055 { STB0899_DISCNTRL1 , 0x32 },
1056 { STB0899_DISCNTRL2 , 0x80 },
1057 { STB0899_DISRX_ST0 , 0x04 },
1058 { STB0899_DISRX_ST1 , 0x00 },
1059 { STB0899_DISPARITY , 0x00 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001060 { STB0899_DISSTATUS , 0x20 },
1061 { STB0899_DISF22 , 0x8c },
1062 { STB0899_DISF22RX , 0x9a },
Manu Abrahamef3052b2008-10-23 18:45:17 -03001063 { STB0899_SYSREG , 0x0b },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001064 { STB0899_ACRPRESC , 0x11 },
1065 { STB0899_ACRDIV1 , 0x0a },
1066 { STB0899_ACRDIV2 , 0x05 },
1067 { STB0899_DACR1 , 0x00 },
1068 { STB0899_DACR2 , 0x00 },
1069 { STB0899_OUTCFG , 0x00 },
1070 { STB0899_MODECFG , 0x00 },
1071 { STB0899_IRQSTATUS_3 , 0x30 },
1072 { STB0899_IRQSTATUS_2 , 0x00 },
1073 { STB0899_IRQSTATUS_1 , 0x00 },
1074 { STB0899_IRQSTATUS_0 , 0x00 },
1075 { STB0899_IRQMSK_3 , 0xf3 },
1076 { STB0899_IRQMSK_2 , 0xfc },
1077 { STB0899_IRQMSK_1 , 0xff },
1078 { STB0899_IRQMSK_0 , 0xff },
1079 { STB0899_IRQCFG , 0x00 },
1080 { STB0899_I2CCFG , 0x88 },
Manu Abraham40e8ce32008-02-03 19:37:02 -03001081 { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001082 { STB0899_IOPVALUE5 , 0x00 },
1083 { STB0899_IOPVALUE4 , 0x20 },
1084 { STB0899_IOPVALUE3 , 0xc9 },
1085 { STB0899_IOPVALUE2 , 0x90 },
1086 { STB0899_IOPVALUE1 , 0x40 },
1087 { STB0899_IOPVALUE0 , 0x00 },
1088 { STB0899_GPIO00CFG , 0x82 },
1089 { STB0899_GPIO01CFG , 0x82 },
1090 { STB0899_GPIO02CFG , 0x82 },
1091 { STB0899_GPIO03CFG , 0x82 },
1092 { STB0899_GPIO04CFG , 0x82 },
1093 { STB0899_GPIO05CFG , 0x82 },
1094 { STB0899_GPIO06CFG , 0x82 },
1095 { STB0899_GPIO07CFG , 0x82 },
1096 { STB0899_GPIO08CFG , 0x82 },
1097 { STB0899_GPIO09CFG , 0x82 },
1098 { STB0899_GPIO10CFG , 0x82 },
1099 { STB0899_GPIO11CFG , 0x82 },
1100 { STB0899_GPIO12CFG , 0x82 },
1101 { STB0899_GPIO13CFG , 0x82 },
1102 { STB0899_GPIO14CFG , 0x82 },
1103 { STB0899_GPIO15CFG , 0x82 },
1104 { STB0899_GPIO16CFG , 0x82 },
1105 { STB0899_GPIO17CFG , 0x82 },
1106 { STB0899_GPIO18CFG , 0x82 },
1107 { STB0899_GPIO19CFG , 0x82 },
1108 { STB0899_GPIO20CFG , 0x82 },
1109 { STB0899_SDATCFG , 0xb8 },
1110 { STB0899_SCLTCFG , 0xba },
Manu Abrahama55bc842008-10-23 18:32:50 -03001111 { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */
1112 { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
1113 { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001114 { STB0899_DIRCLKCFG , 0x82 },
1115 { STB0899_CLKOUT27CFG , 0x7e },
1116 { STB0899_STDBYCFG , 0x82 },
1117 { STB0899_CS0CFG , 0x82 },
1118 { STB0899_CS1CFG , 0x82 },
1119 { STB0899_DISEQCOCFG , 0x20 },
1120 { STB0899_GPIO32CFG , 0x82 },
1121 { STB0899_GPIO33CFG , 0x82 },
1122 { STB0899_GPIO34CFG , 0x82 },
1123 { STB0899_GPIO35CFG , 0x82 },
1124 { STB0899_GPIO36CFG , 0x82 },
1125 { STB0899_GPIO37CFG , 0x82 },
1126 { STB0899_GPIO38CFG , 0x82 },
1127 { STB0899_GPIO39CFG , 0x82 },
Manu Abrahamf2e52cd2007-11-19 16:44:47 -03001128 { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
Manu Abrahama55bc842008-10-23 18:32:50 -03001129 { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001130 { STB0899_FILTCTRL , 0x00 },
1131 { STB0899_SYSCTRL , 0x00 },
1132 { STB0899_STOPCLK1 , 0x20 },
1133 { STB0899_STOPCLK2 , 0x00 },
1134 { STB0899_INTBUFSTATUS , 0x00 },
1135 { STB0899_INTBUFCTRL , 0x0a },
1136 { 0xffff , 0xff },
1137};
1138
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001139static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
1140 { STB0899_DEMOD , 0x00 },
1141 { STB0899_RCOMPC , 0xc9 },
1142 { STB0899_AGC1CN , 0x41 },
1143 { STB0899_AGC1REF , 0x10 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001144 { STB0899_RTC , 0x7a },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001145 { STB0899_TMGCFG , 0x4e },
1146 { STB0899_AGC2REF , 0x34 },
1147 { STB0899_TLSR , 0x84 },
1148 { STB0899_CFD , 0xc7 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001149 { STB0899_ACLC , 0x87 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001150 { STB0899_BCLC , 0x94 },
1151 { STB0899_EQON , 0x41 },
1152 { STB0899_LDT , 0xdd },
1153 { STB0899_LDT2 , 0xc9 },
1154 { STB0899_EQUALREF , 0xb4 },
1155 { STB0899_TMGRAMP , 0x10 },
1156 { STB0899_TMGTHD , 0x30 },
1157 { STB0899_IDCCOMP , 0xfb },
1158 { STB0899_QDCCOMP , 0x03 },
1159 { STB0899_POWERI , 0x3b },
1160 { STB0899_POWERQ , 0x3d },
1161 { STB0899_RCOMP , 0x81 },
1162 { STB0899_AGCIQIN , 0x80 },
1163 { STB0899_AGC2I1 , 0x04 },
1164 { STB0899_AGC2I2 , 0xf5 },
1165 { STB0899_TLIR , 0x25 },
1166 { STB0899_RTF , 0x80 },
1167 { STB0899_DSTATUS , 0x00 },
1168 { STB0899_LDI , 0xca },
1169 { STB0899_CFRM , 0xf1 },
1170 { STB0899_CFRL , 0xf3 },
1171 { STB0899_NIRM , 0x2a },
1172 { STB0899_NIRL , 0x05 },
1173 { STB0899_ISYMB , 0x17 },
1174 { STB0899_QSYMB , 0xfa },
1175 { STB0899_SFRH , 0x2f },
1176 { STB0899_SFRM , 0x68 },
1177 { STB0899_SFRL , 0x40 },
1178 { STB0899_SFRUPH , 0x2f },
1179 { STB0899_SFRUPM , 0x68 },
1180 { STB0899_SFRUPL , 0x40 },
1181 { STB0899_EQUAI1 , 0xfd },
1182 { STB0899_EQUAQ1 , 0x04 },
1183 { STB0899_EQUAI2 , 0x0f },
1184 { STB0899_EQUAQ2 , 0xff },
1185 { STB0899_EQUAI3 , 0xdf },
1186 { STB0899_EQUAQ3 , 0xfa },
1187 { STB0899_EQUAI4 , 0x37 },
1188 { STB0899_EQUAQ4 , 0x0d },
1189 { STB0899_EQUAI5 , 0xbd },
1190 { STB0899_EQUAQ5 , 0xf7 },
1191 { STB0899_DSTATUS2 , 0x00 },
1192 { STB0899_VSTATUS , 0x00 },
1193 { STB0899_VERROR , 0xff },
1194 { STB0899_IQSWAP , 0x2a },
1195 { STB0899_ECNT1M , 0x00 },
1196 { STB0899_ECNT1L , 0x00 },
1197 { STB0899_ECNT2M , 0x00 },
1198 { STB0899_ECNT2L , 0x00 },
1199 { STB0899_ECNT3M , 0x00 },
1200 { STB0899_ECNT3L , 0x00 },
1201 { STB0899_FECAUTO1 , 0x06 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001202 { STB0899_FECM , 0x01 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001203 { STB0899_VTH12 , 0xf0 },
1204 { STB0899_VTH23 , 0xa0 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001205 { STB0899_VTH34 , 0x78 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001206 { STB0899_VTH56 , 0x4e },
1207 { STB0899_VTH67 , 0x48 },
1208 { STB0899_VTH78 , 0x38 },
1209 { STB0899_PRVIT , 0xff },
1210 { STB0899_VITSYNC , 0x19 },
Manu Abrahama55bc842008-10-23 18:32:50 -03001211 { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001212 { STB0899_TSULC , 0x42 },
1213 { STB0899_RSLLC , 0x40 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001214 { STB0899_TSLPL , 0x12 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001215 { STB0899_TSCFGH , 0x0c },
1216 { STB0899_TSCFGM , 0x00 },
1217 { STB0899_TSCFGL , 0x0c },
Manu Abrahamc1426df2009-11-13 18:51:39 -03001218 { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001219 { STB0899_RSSYNCDEL , 0x00 },
1220 { STB0899_TSINHDELH , 0x02 },
1221 { STB0899_TSINHDELM , 0x00 },
1222 { STB0899_TSINHDELL , 0x00 },
1223 { STB0899_TSLLSTKM , 0x00 },
1224 { STB0899_TSLLSTKL , 0x00 },
1225 { STB0899_TSULSTKM , 0x00 },
1226 { STB0899_TSULSTKL , 0xab },
1227 { STB0899_PCKLENUL , 0x00 },
1228 { STB0899_PCKLENLL , 0xcc },
1229 { STB0899_RSPCKLEN , 0xcc },
1230 { STB0899_TSSTATUS , 0x80 },
1231 { STB0899_ERRCTRL1 , 0xb6 },
1232 { STB0899_ERRCTRL2 , 0x96 },
1233 { STB0899_ERRCTRL3 , 0x89 },
1234 { STB0899_DMONMSK1 , 0x27 },
1235 { STB0899_DMONMSK0 , 0x03 },
1236 { STB0899_DEMAPVIT , 0x5c },
1237 { STB0899_PLPARM , 0x1f },
1238 { STB0899_PDELCTRL , 0x48 },
1239 { STB0899_PDELCTRL2 , 0x00 },
1240 { STB0899_BBHCTRL1 , 0x00 },
1241 { STB0899_BBHCTRL2 , 0x00 },
1242 { STB0899_HYSTTHRESH , 0x77 },
1243 { STB0899_MATCSTM , 0x00 },
1244 { STB0899_MATCSTL , 0x00 },
1245 { STB0899_UPLCSTM , 0x00 },
1246 { STB0899_UPLCSTL , 0x00 },
1247 { STB0899_DFLCSTM , 0x00 },
1248 { STB0899_DFLCSTL , 0x00 },
1249 { STB0899_SYNCCST , 0x00 },
1250 { STB0899_SYNCDCSTM , 0x00 },
1251 { STB0899_SYNCDCSTL , 0x00 },
1252 { STB0899_ISI_ENTRY , 0x00 },
1253 { STB0899_ISI_BIT_EN , 0x00 },
1254 { STB0899_MATSTRM , 0x00 },
1255 { STB0899_MATSTRL , 0x00 },
1256 { STB0899_UPLSTRM , 0x00 },
1257 { STB0899_UPLSTRL , 0x00 },
1258 { STB0899_DFLSTRM , 0x00 },
1259 { STB0899_DFLSTRL , 0x00 },
1260 { STB0899_SYNCSTR , 0x00 },
1261 { STB0899_SYNCDSTRM , 0x00 },
1262 { STB0899_SYNCDSTRL , 0x00 },
1263 { STB0899_CFGPDELSTATUS1 , 0x10 },
1264 { STB0899_CFGPDELSTATUS2 , 0x00 },
1265 { STB0899_BBFERRORM , 0x00 },
1266 { STB0899_BBFERRORL , 0x00 },
1267 { STB0899_UPKTERRORM , 0x00 },
1268 { STB0899_UPKTERRORL , 0x00 },
1269 { 0xffff , 0xff },
1270};
1271
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001272static struct stb0899_config tt3200_config = {
1273 .init_dev = tt3200_stb0899_s1_init_1,
Manu Abraham8be969b2008-01-25 18:20:48 -03001274 .init_s2_demod = stb0899_s2_init_2,
Manu Abrahama55bc842008-10-23 18:32:50 -03001275 .init_s1_demod = tt3200_stb0899_s1_init_3,
Manu Abraham8be969b2008-01-25 18:20:48 -03001276 .init_s2_fec = stb0899_s2_init_4,
1277 .init_tst = stb0899_s1_init_5,
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001278
Manu Abraham043a68b2008-01-18 14:15:17 -03001279 .postproc = NULL,
1280
Manu Abrahama55bc842008-10-23 18:32:50 -03001281 .demod_address = 0x68,
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001282
1283 .xtal_freq = 27000000,
Manu Abrahame99d00c2007-09-25 17:48:59 -03001284 .inversion = IQ_SWAP_ON, /* 1 */
Manu Abrahama55bc842008-10-23 18:32:50 -03001285
Manu Abrahamb91a7cb2008-03-04 19:19:58 -03001286 .lo_clk = 76500000,
1287 .hi_clk = 99000000,
1288
Manu Abraham8be969b2008-01-25 18:20:48 -03001289 .esno_ave = STB0899_DVBS2_ESNO_AVE,
1290 .esno_quant = STB0899_DVBS2_ESNO_QUANT,
1291 .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
1292 .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
1293 .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
1294 .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
1295 .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
1296 .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
1297 .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
Manu Abrahama55bc842008-10-23 18:32:50 -03001298
Manu Abraham8be969b2008-01-25 18:20:48 -03001299 .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
1300 .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
1301 .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
1302 .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
Manu Abrahama55bc842008-10-23 18:32:50 -03001303
1304 .tuner_get_frequency = stb6100_get_frequency,
1305 .tuner_set_frequency = stb6100_set_frequency,
1306 .tuner_set_bandwidth = stb6100_set_bandwidth,
1307 .tuner_get_bandwidth = stb6100_get_bandwidth,
Manu Abraham043a68b2008-01-18 14:15:17 -03001308 .tuner_set_rfsiggain = NULL
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001309};
1310
Mauro Carvalho Chehabffbc5f82009-01-05 01:34:20 -03001311static struct stb6100_config tt3200_stb6100_config = {
Manu Abrahamc14eaed2007-10-04 16:52:51 -03001312 .tuner_address = 0x60,
1313 .refclock = 27000000,
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001314};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001315
1316static void frontend_init(struct budget_ci *budget_ci)
1317{
1318 switch (budget_ci->budget.dev->pci->subsystem_device) {
1319 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1320 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001321 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001323 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001324 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 break;
1326 }
1327 break;
1328
1329 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1330 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001331 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001332 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001333 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 break;
1335 }
1336 break;
1337
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001338 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1339 budget_ci->tuner_pll_address = 0x61;
1340 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001341 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001342 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001343 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001344 break;
1345 }
1346 break;
1347
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001349 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001351 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001353 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1354 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001355 break;
1356 }
1357 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001358
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001359 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001360 budget_ci->tuner_pll_address = 0x60;
1361 budget_ci->budget.dvb_frontend =
Oliver Endriss6c914492007-02-02 19:12:53 -03001362 dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001363 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001364 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1365 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001366 break;
1367 }
1368 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001369
1370 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001371 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001372 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001373 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001374 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1375
Patrick Boettcherdea74862006-05-14 05:01:31 -03001376 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001377 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 -03001378 printk("%s: No LNBP21 found!\n", __func__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001379 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001380 budget_ci->budget.dvb_frontend = NULL;
1381 }
1382 }
Sigmund Augdal11417da2008-06-15 17:25:46 -03001383 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001384
Sigmund Augdal11417da2008-06-15 17:25:46 -03001385 case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
1386 budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
1387 if (budget_ci->budget.dvb_frontend) {
klaas de waalcf47d872009-03-25 17:53:02 -03001388 if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) {
Sigmund Augdal11417da2008-06-15 17:25:46 -03001389 printk(KERN_ERR "%s: No tda827x found!\n", __func__);
1390 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1391 budget_ci->budget.dvb_frontend = NULL;
1392 }
1393 }
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001394 break;
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001395
Oliver Endriss574312d2011-03-29 17:37:00 -03001396 case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */
1397 budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap);
1398 if (budget_ci->budget.dvb_frontend) {
1399 if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) {
1400 if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
1401 printk(KERN_ERR "%s: No LNBP21 found!\n", __func__);
1402 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1403 budget_ci->budget.dvb_frontend = NULL;
1404 }
1405 } else {
1406 printk(KERN_ERR "%s: No STB6000 found!\n", __func__);
1407 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1408 budget_ci->budget.dvb_frontend = NULL;
1409 }
1410 }
1411 break;
1412
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001413 case 0x1019: // TT S2-3200 PCI
Manu Abraham6efb0ff2007-10-15 12:08:20 -03001414 /*
1415 * NOTE! on some STB0899 versions, the internal PLL takes a longer time
1416 * to settle, aka LOCK. On the older revisions of the chip, we don't see
1417 * this, as a result on the newer chips the entire clock tree, will not
1418 * be stable after a freshly POWER 'ed up situation.
1419 * In this case, we should RESET the STB0899 (Active LOW) and wait for
1420 * PLL stabilization.
1421 *
1422 * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is
1423 * connected to the SAA7146 GPIO, GPIO2, Pin 142
1424 */
1425 /* Reset Demodulator */
Manu Abraham0867f572007-10-15 13:07:16 -03001426 saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO);
Manu Abraham6efb0ff2007-10-15 12:08:20 -03001427 /* Wait for everything to die */
1428 msleep(50);
1429 /* Pull it up out of Reset state */
Manu Abraham0867f572007-10-15 13:07:16 -03001430 saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI);
Manu Abraham6efb0ff2007-10-15 12:08:20 -03001431 /* Wait for PLL to stabilize */
1432 msleep(250);
1433 /*
1434 * PLL state should be stable now. Ideally, we should check
1435 * for PLL LOCK status. But well, never mind!
1436 */
Manu Abrahamae9902d2007-10-08 18:51:54 -03001437 budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap);
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001438 if (budget_ci->budget.dvb_frontend) {
Manu Abrahamae9902d2007-10-08 18:51:54 -03001439 if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) {
1440 if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
Harvey Harrison9b4778f2009-01-07 14:42:41 -08001441 printk("%s: No LNBP21 found!\n", __func__);
Manu Abrahamae9902d2007-10-08 18:51:54 -03001442 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001443 budget_ci->budget.dvb_frontend = NULL;
1444 }
1445 } else {
Manu Abrahamae9902d2007-10-08 18:51:54 -03001446 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1447 budget_ci->budget.dvb_frontend = NULL;
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001448 }
1449 }
1450 break;
1451
Linus Torvalds1da177e2005-04-16 15:20:36 -07001452 }
1453
1454 if (budget_ci->budget.dvb_frontend == NULL) {
Bjorn Helgaas29e66a62008-09-04 17:24:51 -03001455 printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001456 budget_ci->budget.dev->pci->vendor,
1457 budget_ci->budget.dev->pci->device,
1458 budget_ci->budget.dev->pci->subsystem_vendor,
1459 budget_ci->budget.dev->pci->subsystem_device);
1460 } else {
1461 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001462 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001463 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001464 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 budget_ci->budget.dvb_frontend = NULL;
1466 }
1467 }
1468}
1469
1470static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1471{
1472 struct budget_ci *budget_ci;
1473 int err;
1474
David Hardemanee579bc2006-12-02 21:16:05 -02001475 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001476 if (!budget_ci) {
1477 err = -ENOMEM;
1478 goto out1;
1479 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480
1481 dprintk(2, "budget_ci: %p\n", budget_ci);
1482
Linus Torvalds1da177e2005-04-16 15:20:36 -07001483 dev->ext_priv = budget_ci;
1484
Janne Grunau26dc4d02008-09-21 20:50:11 -03001485 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE,
1486 adapter_nr);
David Hardeman8cc532e2006-12-02 21:16:05 -02001487 if (err)
1488 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
David Hardeman8cc532e2006-12-02 21:16:05 -02001490 err = msp430_ir_init(budget_ci);
1491 if (err)
1492 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493
1494 ciintf_init(budget_ci);
1495
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001496 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 frontend_init(budget_ci);
1498
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001499 ttpci_budget_init_hooks(&budget_ci->budget);
1500
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001502
1503out3:
1504 ttpci_budget_deinit(&budget_ci->budget);
1505out2:
1506 kfree(budget_ci);
1507out1:
1508 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509}
1510
1511static int budget_ci_detach(struct saa7146_dev *dev)
1512{
1513 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1514 struct saa7146_dev *saa = budget_ci->budget.dev;
1515 int err;
1516
1517 if (budget_ci->budget.ci_present)
1518 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001519 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001520 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001522 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001523 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 err = ttpci_budget_deinit(&budget_ci->budget);
1525
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526 // disable frontend and CI interface
1527 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1528
1529 kfree(budget_ci);
1530
1531 return err;
1532}
1533
1534static struct saa7146_extension budget_extension;
1535
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001536MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001537MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1538MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001539MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001540MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Sigmund Augdal11417da2008-06-15 17:25:46 -03001541MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001542MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
Oliver Endriss574312d2011-03-29 17:37:00 -03001543MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
1545static struct pci_device_id pci_tbl[] = {
1546 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1547 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001548 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001550 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001551 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Sigmund Augdal11417da2008-06-15 17:25:46 -03001552 MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001553 MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
Oliver Endriss574312d2011-03-29 17:37:00 -03001554 MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555 {
1556 .vendor = 0,
1557 }
1558};
1559
1560MODULE_DEVICE_TABLE(pci, pci_tbl);
1561
1562static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001563 .name = "budget_ci dvb",
Oliver Endriss00c4cc62006-11-01 13:09:51 -03001564 .flags = SAA7146_USE_I2C_IRQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001565
1566 .module = THIS_MODULE,
1567 .pci_tbl = &pci_tbl[0],
1568 .attach = budget_ci_attach,
1569 .detach = budget_ci_detach,
1570
1571 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1572 .irq_func = budget_ci_irq,
1573};
1574
1575static int __init budget_ci_init(void)
1576{
1577 return saa7146_register_extension(&budget_extension);
1578}
1579
1580static void __exit budget_ci_exit(void)
1581{
1582 saa7146_unregister_extension(&budget_extension);
1583}
1584
1585module_init(budget_ci_init);
1586module_exit(budget_ci_exit);
1587
1588MODULE_LICENSE("GPL");
1589MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1590MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1591 "budget PCI DVB cards w/ CI-module produced by "
1592 "Siemens, Technotrend, Hauppauge");