blob: f67ed118f273076c3df88bd33cf5e9436a8d49cc [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 *
Sakari Ailusbcb63312016-10-28 09:31:20 -020022 * To obtain the license, point your browser to
23 * http://www.gnu.org/copyleft/gpl.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 *
25 *
Mauro Carvalho Chehab991ce922015-12-04 10:38:59 -020026 * the project's page is at https://linuxtv.org
Linus Torvalds1da177e2005-04-16 15:20:36 -070027 */
28
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30#include <linux/errno.h>
31#include <linux/slab.h>
32#include <linux/interrupt.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/spinlock.h>
Mauro Carvalho Chehab6bda9642010-11-17 13:28:38 -030034#include <media/rc-core.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Trent Piepho68277092007-01-30 23:25:46 -030036#include "budget.h"
37
Mauro Carvalho Chehabfada1932017-12-28 13:03:51 -050038#include <media/dvb_ca_en50221.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070040#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include "tda1004x.h"
Marko Schluessler9e0dc662008-10-23 18:16:40 -030042#include "stb0899_drv.h"
43#include "stb0899_reg.h"
Manu Abraham8be969b2008-01-25 18:20:48 -030044#include "stb0899_cfg.h"
Marko Schluessler9e0dc662008-10-23 18:16:40 -030045#include "stb6100.h"
Manu Abraham8be969b2008-01-25 18:20:48 -030046#include "stb6100_cfg.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030047#include "lnbp21.h"
48#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030049#include "bsru6.h"
Sigmund Augdal11417da2008-06-15 17:25:46 -030050#include "tda1002x.h"
51#include "tda827x.h"
Oliver Endriss574312d2011-03-29 17:37:00 -030052#include "bsbe1-d01a.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Mauro Carvalho Chehab727e6252010-03-12 21:18:14 -030054#define MODULE_NAME "budget_ci"
55
David Härdemanecba77f2006-10-27 20:56:51 -030056/*
57 * Regarding DEBIADDR_IR:
58 * Some CI modules hang if random addresses are read.
59 * Using address 0x4000 for the IR read means that we
60 * use the same address as for CI version, which should
61 * be a safe default.
62 */
63#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070064#define DEBIADDR_CICONTROL 0x0000
65#define DEBIADDR_CIVERSION 0x4000
66#define DEBIADDR_IO 0x1000
67#define DEBIADDR_ATTR 0x3000
68
69#define CICONTROL_RESET 0x01
70#define CICONTROL_ENABLETS 0x02
71#define CICONTROL_CAMDETECT 0x08
72
73#define DEBICICTL 0x00420000
74#define DEBICICAM 0x02420000
75
76#define SLOTSTATUS_NONE 1
77#define SLOTSTATUS_PRESENT 2
78#define SLOTSTATUS_RESET 4
79#define SLOTSTATUS_READY 8
80#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
81
David Hardeman64741b72006-12-02 21:16:05 -020082/* RC5 device wildcard */
83#define IR_DEVICE_ANY 255
84
David Hardeman64741b72006-12-02 21:16:05 -020085static int rc5_device = -1;
86module_param(rc5_device, int, 0644);
87MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
88
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030089static int ir_debug;
David Hardemanb5471a22006-12-02 21:16:05 -020090module_param(ir_debug, int, 0644);
91MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
92
Janne Grunau26dc4d02008-09-21 20:50:11 -030093DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
94
David Hardemandd2f3982006-12-02 21:16:05 -020095struct budget_ci_ir {
David Härdemand8b4b582010-10-29 16:08:23 -030096 struct rc_dev *dev;
David Hardemandd2f3982006-12-02 21:16:05 -020097 struct tasklet_struct msp430_irq_tasklet;
98 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -020099 char phys[32];
David Hardeman64741b72006-12-02 21:16:05 -0200100 int rc5_device;
David Härdeman145859c2007-04-27 12:31:22 -0300101 u32 ir_key;
102 bool have_command;
Mauro Carvalho Chehabaf86ce72011-01-24 12:18:48 -0300103 bool full_rc5; /* Outputs a full RC5 code */
David Hardemandd2f3982006-12-02 21:16:05 -0200104};
105
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106struct budget_ci {
107 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 struct tasklet_struct ciintf_irq_tasklet;
109 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300110 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -0200112 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700113 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114};
115
David Hardeman2520fff2006-12-02 21:16:05 -0200116static void msp430_ir_interrupt(unsigned long data)
117{
118 struct budget_ci *budget_ci = (struct budget_ci *) data;
David Härdemand8b4b582010-10-29 16:08:23 -0300119 struct rc_dev *dev = budget_ci->ir.dev;
David Hardeman2520fff2006-12-02 21:16:05 -0200120 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
121
David Hardeman64741b72006-12-02 21:16:05 -0200122 /*
123 * The msp430 chip can generate two different bytes, command and device
124 *
125 * type1: X1CCCCCC, C = command bits (0 - 63)
126 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
127 *
David Härdeman59327a42007-02-13 09:39:58 -0300128 * Each signal from the remote control can generate one or more command
129 * bytes and one or more device bytes. For the repeated bytes, the
130 * highest bit (X) is set. The first command byte is always generated
131 * before the first device byte. Other than that, no specific order
David Härdeman145859c2007-04-27 12:31:22 -0300132 * seems to apply. To make life interesting, bytes can also be lost.
David Härdeman59327a42007-02-13 09:39:58 -0300133 *
134 * Only when we have a command and device byte, a keypress is
135 * generated.
David Hardeman64741b72006-12-02 21:16:05 -0200136 */
137
David Härdeman59327a42007-02-13 09:39:58 -0300138 if (ir_debug)
139 printk("budget_ci: received byte 0x%02x\n", command);
140
David Härdeman145859c2007-04-27 12:31:22 -0300141 /* Remove repeat bit, we use every command */
142 command = command & 0x7f;
David Härdeman59327a42007-02-13 09:39:58 -0300143
David Hardeman64741b72006-12-02 21:16:05 -0200144 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200145 if (command & 0x40) {
David Härdeman145859c2007-04-27 12:31:22 -0300146 budget_ci->ir.have_command = true;
147 budget_ci->ir.ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200148 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200149 }
David Hardeman64741b72006-12-02 21:16:05 -0200150
151 /* It's a RC5 device byte */
David Härdeman145859c2007-04-27 12:31:22 -0300152 if (!budget_ci->ir.have_command)
David Härdeman59327a42007-02-13 09:39:58 -0300153 return;
David Härdeman145859c2007-04-27 12:31:22 -0300154 budget_ci->ir.have_command = false;
David Hardeman64741b72006-12-02 21:16:05 -0200155
David Härdeman145859c2007-04-27 12:31:22 -0300156 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
157 budget_ci->ir.rc5_device != (command & 0x1f))
David Hardeman64741b72006-12-02 21:16:05 -0200158 return;
159
Mauro Carvalho Chehabaf86ce72011-01-24 12:18:48 -0300160 if (budget_ci->ir.full_rc5) {
Sean Young6d741bf2017-08-07 16:20:58 -0400161 rc_keydown(dev, RC_PROTO_RC5,
David Härdeman120703f2014-04-03 20:31:30 -0300162 RC_SCANCODE_RC5(budget_ci->ir.rc5_device, budget_ci->ir.ir_key),
163 !!(command & 0x20));
Mauro Carvalho Chehabaf86ce72011-01-24 12:18:48 -0300164 return;
165 }
166
167 /* FIXME: We should generate complete scancodes for all devices */
Sean Young6d741bf2017-08-07 16:20:58 -0400168 rc_keydown(dev, RC_PROTO_UNKNOWN, budget_ci->ir.ir_key,
169 !!(command & 0x20));
David Hardeman2520fff2006-12-02 21:16:05 -0200170}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172static int msp430_ir_init(struct budget_ci *budget_ci)
173{
174 struct saa7146_dev *saa = budget_ci->budget.dev;
David Härdemand8b4b582010-10-29 16:08:23 -0300175 struct rc_dev *dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200176 int error;
Mauro Carvalho Chehab579e7d62009-12-11 11:20:59 -0300177
Andi Shyti0f7499f2016-12-16 06:50:58 -0200178 dev = rc_allocate_device(RC_DRIVER_SCANCODE);
David Härdemand8b4b582010-10-29 16:08:23 -0300179 if (!dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200180 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
Mauro Carvalho Chehab579e7d62009-12-11 11:20:59 -0300181 return -ENOMEM;
David Hardeman8cc532e2006-12-02 21:16:05 -0200182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
David Hardemandd2f3982006-12-02 21:16:05 -0200184 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
185 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200186 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
187 "pci-%s/ir0", pci_name(saa->pci));
188
David Härdemand8b4b582010-10-29 16:08:23 -0300189 dev->driver_name = MODULE_NAME;
Sean Young518f4b22017-07-01 12:13:19 -0400190 dev->device_name = budget_ci->ir.name;
David Härdemand8b4b582010-10-29 16:08:23 -0300191 dev->input_phys = budget_ci->ir.phys;
192 dev->input_id.bustype = BUS_PCI;
193 dev->input_id.version = 1;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200194 if (saa->pci->subsystem_vendor) {
David Härdemand8b4b582010-10-29 16:08:23 -0300195 dev->input_id.vendor = saa->pci->subsystem_vendor;
196 dev->input_id.product = saa->pci->subsystem_device;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200197 } else {
David Härdemand8b4b582010-10-29 16:08:23 -0300198 dev->input_id.vendor = saa->pci->vendor;
199 dev->input_id.product = saa->pci->device;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200200 }
David Härdemand8b4b582010-10-29 16:08:23 -0300201 dev->dev.parent = &saa->pci->dev;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200202
Mauro Carvalho Chehab579e7d62009-12-11 11:20:59 -0300203 if (rc5_device < 0)
204 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
205 else
206 budget_ci->ir.rc5_device = rc5_device;
207
David Hardeman64741b72006-12-02 21:16:05 -0200208 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200209 switch (budget_ci->budget.dev->pci->subsystem_device) {
210 case 0x100c:
211 case 0x100f:
David Hardeman2520fff2006-12-02 21:16:05 -0200212 case 0x1011:
213 case 0x1012:
David Hardeman2520fff2006-12-02 21:16:05 -0200214 /* The hauppauge keymap is a superset of these remotes */
Mauro Carvalho Chehabaf86ce72011-01-24 12:18:48 -0300215 dev->map_name = RC_MAP_HAUPPAUGE;
216 budget_ci->ir.full_rc5 = true;
David Hardeman64741b72006-12-02 21:16:05 -0200217
218 if (rc5_device < 0)
219 budget_ci->ir.rc5_device = 0x1f;
David Hardeman2520fff2006-12-02 21:16:05 -0200220 break;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300221 case 0x1010:
Oliver Endrissf64899c2007-09-17 22:17:12 -0300222 case 0x1017:
Hermann Gaustererf137f9d2010-05-18 04:26:17 -0300223 case 0x1019:
Oliver Endrissbbfc4c22008-06-19 23:36:45 -0300224 case 0x101a:
Oliver Endriss574312d2011-03-29 17:37:00 -0300225 case 0x101b:
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300226 /* for the Technotrend 1500 bundled remote */
David Härdemand8b4b582010-10-29 16:08:23 -0300227 dev->map_name = RC_MAP_TT_1500;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300228 break;
David Hardeman2520fff2006-12-02 21:16:05 -0200229 default:
230 /* unknown remote */
David Härdemand8b4b582010-10-29 16:08:23 -0300231 dev->map_name = RC_MAP_BUDGET_CI_OLD;
David Hardeman2520fff2006-12-02 21:16:05 -0200232 break;
233 }
Mauro Carvalho Chehab5183c132011-12-17 09:03:29 -0200234 if (!budget_ci->ir.full_rc5)
David Härdeman9d2f1d32014-04-03 20:32:26 -0300235 dev->scancode_mask = 0xff;
David Hardeman2520fff2006-12-02 21:16:05 -0200236
David Härdemand8b4b582010-10-29 16:08:23 -0300237 error = rc_register_device(dev);
David Hardeman8cc532e2006-12-02 21:16:05 -0200238 if (error) {
239 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
David Härdemand8b4b582010-10-29 16:08:23 -0300240 rc_free_device(dev);
Mauro Carvalho Chehab579e7d62009-12-11 11:20:59 -0300241 return error;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
David Härdemand8b4b582010-10-29 16:08:23 -0300244 budget_ci->ir.dev = dev;
David Härdeman145859c2007-04-27 12:31:22 -0300245
David Hardeman8cc532e2006-12-02 21:16:05 -0200246 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
247 (unsigned long) budget_ci);
248
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300249 SAA7146_IER_ENABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
251
252 return 0;
253}
254
255static void msp430_ir_deinit(struct budget_ci *budget_ci)
256{
257 struct saa7146_dev *saa = budget_ci->budget.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300259 SAA7146_IER_DISABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200261 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
David Härdemand8b4b582010-10-29 16:08:23 -0300263 rc_unregister_device(budget_ci->ir.dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264}
265
266static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
267{
268 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
269
270 if (slot != 0)
271 return -EINVAL;
272
273 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
274 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
275}
276
277static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
278{
279 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
280
281 if (slot != 0)
282 return -EINVAL;
283
284 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
285 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
286}
287
288static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
289{
290 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
291
292 if (slot != 0)
293 return -EINVAL;
294
295 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
296 DEBIADDR_IO | (address & 3), 1, 1, 0);
297}
298
299static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
300{
301 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
302
303 if (slot != 0)
304 return -EINVAL;
305
306 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
307 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
308}
309
310static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
311{
312 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
313 struct saa7146_dev *saa = budget_ci->budget.dev;
314
315 if (slot != 0)
316 return -EINVAL;
317
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300318 if (budget_ci->ci_irq) {
319 // trigger on RISING edge during reset so we know when READY is re-asserted
320 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
321 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322 budget_ci->slot_status = SLOTSTATUS_RESET;
323 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
324 msleep(1);
325 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
326 CICONTROL_RESET, 1, 0);
327
328 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
329 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
330 return 0;
331}
332
333static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
334{
335 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
336 struct saa7146_dev *saa = budget_ci->budget.dev;
337
338 if (slot != 0)
339 return -EINVAL;
340
341 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
342 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
343 return 0;
344}
345
346static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
347{
348 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
349 struct saa7146_dev *saa = budget_ci->budget.dev;
350 int tmp;
351
352 if (slot != 0)
353 return -EINVAL;
354
355 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
356
357 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
358 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
359 tmp | CICONTROL_ENABLETS, 1, 0);
360
361 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
362 return 0;
363}
364
365static void ciintf_interrupt(unsigned long data)
366{
367 struct budget_ci *budget_ci = (struct budget_ci *) data;
368 struct saa7146_dev *saa = budget_ci->budget.dev;
369 unsigned int flags;
370
371 // ensure we don't get spurious IRQs during initialisation
372 if (!budget_ci->budget.ci_present)
373 return;
374
375 // read the CAM status
376 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
377 if (flags & CICONTROL_CAMDETECT) {
378
379 // GPIO should be set to trigger on falling edge if a CAM is present
380 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
381
382 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
383 // CAM insertion IRQ
384 budget_ci->slot_status = SLOTSTATUS_PRESENT;
385 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
386 DVB_CA_EN50221_CAMCHANGE_INSERTED);
387
388 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
389 // CAM ready (reset completed)
390 budget_ci->slot_status = SLOTSTATUS_READY;
391 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
392
393 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
394 // FR/DA IRQ
395 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
396 }
397 } else {
398
399 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
400 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
401 // the CAM might not actually be ready yet.
402 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
403
404 // generate a CAM removal IRQ if we haven't already
405 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
406 // CAM removal IRQ
407 budget_ci->slot_status = SLOTSTATUS_NONE;
408 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
409 DVB_CA_EN50221_CAMCHANGE_REMOVED);
410 }
411 }
412}
413
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300414static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
415{
416 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
417 unsigned int flags;
418
419 // ensure we don't get spurious IRQs during initialisation
420 if (!budget_ci->budget.ci_present)
421 return -EINVAL;
422
423 // read the CAM status
424 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
425 if (flags & CICONTROL_CAMDETECT) {
426 // mark it as present if it wasn't before
427 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
428 budget_ci->slot_status = SLOTSTATUS_PRESENT;
429 }
430
431 // during a RESET, we check if we can read from IO memory to see when CAM is ready
432 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
433 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
434 budget_ci->slot_status = SLOTSTATUS_READY;
435 }
436 }
437 } else {
438 budget_ci->slot_status = SLOTSTATUS_NONE;
439 }
440
441 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
442 if (budget_ci->slot_status & SLOTSTATUS_READY) {
443 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
444 }
445 return DVB_CA_EN50221_POLL_CAM_PRESENT;
446 }
447
448 return 0;
449}
450
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451static int ciintf_init(struct budget_ci *budget_ci)
452{
453 struct saa7146_dev *saa = budget_ci->budget.dev;
454 int flags;
455 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300456 int ci_version;
457 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458
459 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
460
461 // enable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300462 saa7146_write(saa, MC1, MASK_27 | MASK_11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700463
464 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300465 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
466 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 result = -ENODEV;
468 goto error;
469 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 // determine whether a CAM is present or not
472 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
473 budget_ci->slot_status = SLOTSTATUS_NONE;
474 if (flags & CICONTROL_CAMDETECT)
475 budget_ci->slot_status = SLOTSTATUS_PRESENT;
476
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300477 // version 0xa2 of the CI firmware doesn't generate interrupts
478 if (ci_version == 0xa2) {
479 ca_flags = 0;
480 budget_ci->ci_irq = 0;
481 } else {
482 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
483 DVB_CA_EN50221_FLAG_IRQ_FR |
484 DVB_CA_EN50221_FLAG_IRQ_DA;
485 budget_ci->ci_irq = 1;
486 }
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488 // register CI interface
489 budget_ci->ca.owner = THIS_MODULE;
490 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
491 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
492 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
493 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
494 budget_ci->ca.slot_reset = ciintf_slot_reset;
495 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
496 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300497 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700499 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300501 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 printk("budget_ci: CI interface detected, but initialisation failed.\n");
503 goto error;
504 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300505
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300507 if (budget_ci->ci_irq) {
508 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
509 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
510 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
511 } else {
512 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
513 }
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300514 SAA7146_IER_ENABLE(saa, MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300516
517 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
519 CICONTROL_RESET, 1, 0);
520
521 // success!
522 printk("budget_ci: CI interface initialised\n");
523 budget_ci->budget.ci_present = 1;
524
525 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300526 if (budget_ci->ci_irq) {
527 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
528 if (budget_ci->slot_status != SLOTSTATUS_NONE)
529 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
530 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
531 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533 return 0;
534
535error:
Hartmut Birr2a893de2006-12-03 21:08:08 -0300536 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 return result;
538}
539
540static void ciintf_deinit(struct budget_ci *budget_ci)
541{
542 struct saa7146_dev *saa = budget_ci->budget.dev;
543
544 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300545 if (budget_ci->ci_irq) {
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300546 SAA7146_IER_DISABLE(saa, MASK_03);
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300547 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
548 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
549 }
550
551 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
553 msleep(1);
554 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
555 CICONTROL_RESET, 1, 0);
556
557 // disable TS data stream to CI interface
558 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
559
560 // release the CA device
561 dvb_ca_en50221_release(&budget_ci->ca);
562
563 // disable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300564 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565}
566
567static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
568{
569 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
570
571 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
572
573 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200574 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 if (*isr & MASK_10)
577 ttpci_budget_irq10_handler(dev, isr);
578
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300579 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
581}
582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583static u8 philips_su1278_tt_inittab[] = {
584 0x01, 0x0f,
585 0x02, 0x30,
586 0x03, 0x00,
587 0x04, 0x5b,
588 0x05, 0x85,
589 0x06, 0x02,
590 0x07, 0x00,
591 0x08, 0x02,
592 0x09, 0x00,
593 0x0C, 0x01,
594 0x0D, 0x81,
595 0x0E, 0x44,
596 0x0f, 0x14,
597 0x10, 0x3c,
598 0x11, 0x84,
599 0x12, 0xda,
600 0x13, 0x97,
601 0x14, 0x95,
602 0x15, 0xc9,
603 0x16, 0x19,
604 0x17, 0x8c,
605 0x18, 0x59,
606 0x19, 0xf8,
607 0x1a, 0xfe,
608 0x1c, 0x7f,
609 0x1d, 0x00,
610 0x1e, 0x00,
611 0x1f, 0x50,
612 0x20, 0x00,
613 0x21, 0x00,
614 0x22, 0x00,
615 0x23, 0x00,
616 0x28, 0x00,
617 0x29, 0x28,
618 0x2a, 0x14,
619 0x2b, 0x0f,
620 0x2c, 0x09,
621 0x2d, 0x09,
622 0x31, 0x1f,
623 0x32, 0x19,
624 0x33, 0xfc,
625 0x34, 0x93,
626 0xff, 0xff
627};
628
629static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
630{
631 stv0299_writereg(fe, 0x0e, 0x44);
632 if (srate >= 10000000) {
633 stv0299_writereg(fe, 0x13, 0x97);
634 stv0299_writereg(fe, 0x14, 0x95);
635 stv0299_writereg(fe, 0x15, 0xc9);
636 stv0299_writereg(fe, 0x17, 0x8c);
637 stv0299_writereg(fe, 0x1a, 0xfe);
638 stv0299_writereg(fe, 0x1c, 0x7f);
639 stv0299_writereg(fe, 0x2d, 0x09);
640 } else {
641 stv0299_writereg(fe, 0x13, 0x99);
642 stv0299_writereg(fe, 0x14, 0x8d);
643 stv0299_writereg(fe, 0x15, 0xce);
644 stv0299_writereg(fe, 0x17, 0x43);
645 stv0299_writereg(fe, 0x1a, 0x1d);
646 stv0299_writereg(fe, 0x1c, 0x12);
647 stv0299_writereg(fe, 0x2d, 0x05);
648 }
649 stv0299_writereg(fe, 0x0e, 0x23);
650 stv0299_writereg(fe, 0x0f, 0x94);
651 stv0299_writereg(fe, 0x10, 0x39);
652 stv0299_writereg(fe, 0x15, 0xc9);
653
654 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
655 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
656 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
657
658 return 0;
659}
660
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300661static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662{
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300663 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300664 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 u32 div;
666 u8 buf[4];
667 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
668
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300669 if ((p->frequency < 950000) || (p->frequency > 2150000))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 return -EINVAL;
671
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300672 div = (p->frequency + (500 - 1)) / 500; /* round correctly */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 buf[0] = (div >> 8) & 0x7f;
674 buf[1] = div & 0xff;
675 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
676 buf[3] = 0x20;
677
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300678 if (p->symbol_rate < 4000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 buf[3] |= 1;
680
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300681 if (p->frequency < 1250000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 buf[3] |= 0;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300683 else if (p->frequency < 1550000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 buf[3] |= 0x40;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300685 else if (p->frequency < 2050000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 buf[3] |= 0x80;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300687 else if (p->frequency < 2150000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688 buf[3] |= 0xC0;
689
Patrick Boettcherdea74862006-05-14 05:01:31 -0300690 if (fe->ops.i2c_gate_ctrl)
691 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300692 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return -EIO;
694 return 0;
695}
696
Bhumika Goyal650497f2017-02-19 15:04:41 -0300697static const struct stv0299_config philips_su1278_tt_config = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 .demod_address = 0x68,
700 .inittab = philips_su1278_tt_inittab,
701 .mclk = 64000000UL,
702 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 .skip_reinit = 1,
Oliver Endrissda2c7f62008-04-20 22:13:37 -0300704 .lock_output = STV0299_LOCKOUTPUT_1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 .volt13_op0_op1 = STV0299_VOLT13_OP1,
706 .min_delay_ms = 50,
707 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708};
709
710
711
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300712static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713{
714 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
715 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
716 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700717 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 sizeof(td1316_init) };
719
720 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300721 if (fe->ops.i2c_gate_ctrl)
722 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700723 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
724 return -EIO;
725 msleep(1);
726
727 // disable the mc44BC374c (do not check for errors)
728 tuner_msg.addr = 0x65;
729 tuner_msg.buf = disable_mc44BC374c;
730 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300731 if (fe->ops.i2c_gate_ctrl)
732 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
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 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
737 }
738
739 return 0;
740}
741
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300742static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743{
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300744 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
746 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700747 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 -0700748 int tuner_frequency = 0;
749 u8 band, cp, filter;
750
751 // determine charge pump
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300752 tuner_frequency = p->frequency + 36130000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753 if (tuner_frequency < 87000000)
754 return -EINVAL;
755 else if (tuner_frequency < 130000000)
756 cp = 3;
757 else if (tuner_frequency < 160000000)
758 cp = 5;
759 else if (tuner_frequency < 200000000)
760 cp = 6;
761 else if (tuner_frequency < 290000000)
762 cp = 3;
763 else if (tuner_frequency < 420000000)
764 cp = 5;
765 else if (tuner_frequency < 480000000)
766 cp = 6;
767 else if (tuner_frequency < 620000000)
768 cp = 3;
769 else if (tuner_frequency < 830000000)
770 cp = 5;
771 else if (tuner_frequency < 895000000)
772 cp = 7;
773 else
774 return -EINVAL;
775
776 // determine band
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300777 if (p->frequency < 49000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700778 return -EINVAL;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300779 else if (p->frequency < 159000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780 band = 1;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300781 else if (p->frequency < 444000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 band = 2;
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300783 else if (p->frequency < 861000000)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 band = 4;
785 else
786 return -EINVAL;
787
788 // setup PLL filter and TDA9889
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300789 switch (p->bandwidth_hz) {
790 case 6000000:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300791 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700792 filter = 0;
793 break;
794
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300795 case 7000000:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300796 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797 filter = 0;
798 break;
799
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300800 case 8000000:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300801 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700802 filter = 1;
803 break;
804
805 default:
806 return -EINVAL;
807 }
808
809 // calculate divisor
810 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300811 tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812
813 // setup tuner buffer
814 tuner_buf[0] = tuner_frequency >> 8;
815 tuner_buf[1] = tuner_frequency & 0xff;
816 tuner_buf[2] = 0xca;
817 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
818
Patrick Boettcherdea74862006-05-14 05:01:31 -0300819 if (fe->ops.i2c_gate_ctrl)
820 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
822 return -EIO;
823
824 msleep(1);
825 return 0;
826}
827
828static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
829 const struct firmware **fw, char *name)
830{
831 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
832
833 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
834}
835
836static struct tda1004x_config philips_tdm1316l_config = {
837
838 .demod_address = 0x8,
839 .invert = 0,
840 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700841 .xtal_freq = TDA10046_XTAL_4M,
842 .agc_config = TDA10046_AGC_DEFAULT,
843 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 .request_firmware = philips_tdm1316l_request_firmware,
845};
846
Oliver Endriss6c914492007-02-02 19:12:53 -0300847static struct tda1004x_config philips_tdm1316l_config_invert = {
848
849 .demod_address = 0x8,
850 .invert = 1,
851 .invert_oclk = 0,
852 .xtal_freq = TDA10046_XTAL_4M,
853 .agc_config = TDA10046_AGC_DEFAULT,
854 .if_freq = TDA10046_FREQ_3617,
855 .request_firmware = philips_tdm1316l_request_firmware,
856};
857
Mauro Carvalho Chehab14d24d12011-12-24 12:24:33 -0300858static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700859{
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300860 struct dtv_frontend_properties *p = &fe->dtv_property_cache;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700861 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
862 u8 tuner_buf[5];
863 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
864 .flags = 0,
865 .buf = tuner_buf,
866 .len = sizeof(tuner_buf) };
867 int tuner_frequency = 0;
868 u8 band, cp, filter;
869
870 // determine charge pump
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300871 tuner_frequency = p->frequency + 36125000;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700872 if (tuner_frequency < 87000000)
873 return -EINVAL;
874 else if (tuner_frequency < 130000000) {
875 cp = 3;
876 band = 1;
877 } else if (tuner_frequency < 160000000) {
878 cp = 5;
879 band = 1;
880 } else if (tuner_frequency < 200000000) {
881 cp = 6;
Oliver Endriss910a7b62007-05-03 13:16:12 -0300882 band = 1;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700883 } else if (tuner_frequency < 290000000) {
884 cp = 3;
885 band = 2;
886 } else if (tuner_frequency < 420000000) {
887 cp = 5;
888 band = 2;
889 } else if (tuner_frequency < 480000000) {
890 cp = 6;
891 band = 2;
892 } else if (tuner_frequency < 620000000) {
893 cp = 3;
894 band = 4;
895 } else if (tuner_frequency < 830000000) {
896 cp = 5;
897 band = 4;
898 } else if (tuner_frequency < 895000000) {
899 cp = 7;
900 band = 4;
901 } else
902 return -EINVAL;
903
904 // assume PLL filter should always be 8MHz for the moment.
905 filter = 1;
906
907 // calculate divisor
Mauro Carvalho Chehab9b544642011-12-23 08:04:27 -0300908 tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700909
910 // setup tuner buffer
911 tuner_buf[0] = tuner_frequency >> 8;
912 tuner_buf[1] = tuner_frequency & 0xff;
913 tuner_buf[2] = 0xc8;
914 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
915 tuner_buf[4] = 0x80;
916
Patrick Boettcherdea74862006-05-14 05:01:31 -0300917 if (fe->ops.i2c_gate_ctrl)
918 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700919 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
920 return -EIO;
921
922 msleep(50);
923
Patrick Boettcherdea74862006-05-14 05:01:31 -0300924 if (fe->ops.i2c_gate_ctrl)
925 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700926 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
927 return -EIO;
928
929 msleep(1);
930
931 return 0;
932}
933
934static u8 dvbc_philips_tdm1316l_inittab[] = {
935 0x80, 0x01,
936 0x80, 0x00,
937 0x81, 0x01,
938 0x81, 0x00,
939 0x00, 0x09,
940 0x01, 0x69,
941 0x03, 0x00,
942 0x04, 0x00,
943 0x07, 0x00,
944 0x08, 0x00,
945 0x20, 0x00,
946 0x21, 0x40,
947 0x22, 0x00,
948 0x23, 0x00,
949 0x24, 0x40,
950 0x25, 0x88,
951 0x30, 0xff,
952 0x31, 0x00,
953 0x32, 0xff,
954 0x33, 0x00,
955 0x34, 0x50,
956 0x35, 0x7f,
957 0x36, 0x00,
958 0x37, 0x20,
959 0x38, 0x00,
960 0x40, 0x1c,
961 0x41, 0xff,
962 0x42, 0x29,
963 0x43, 0x20,
964 0x44, 0xff,
965 0x45, 0x00,
966 0x46, 0x00,
967 0x49, 0x04,
968 0x4a, 0x00,
969 0x4b, 0x7b,
970 0x52, 0x30,
971 0x55, 0xae,
972 0x56, 0x47,
973 0x57, 0xe1,
974 0x58, 0x3a,
975 0x5a, 0x1e,
976 0x5b, 0x34,
977 0x60, 0x00,
978 0x63, 0x00,
979 0x64, 0x00,
980 0x65, 0x00,
981 0x66, 0x00,
982 0x67, 0x00,
983 0x68, 0x00,
984 0x69, 0x00,
985 0x6a, 0x02,
986 0x6b, 0x00,
987 0x70, 0xff,
988 0x71, 0x00,
989 0x72, 0x00,
990 0x73, 0x00,
991 0x74, 0x0c,
992 0x80, 0x00,
993 0x81, 0x00,
994 0x82, 0x00,
995 0x83, 0x00,
996 0x84, 0x04,
997 0x85, 0x80,
998 0x86, 0x24,
999 0x87, 0x78,
1000 0x88, 0x10,
1001 0x89, 0x00,
1002 0x90, 0x01,
1003 0x91, 0x01,
1004 0xa0, 0x04,
1005 0xa1, 0x00,
1006 0xa2, 0x00,
1007 0xb0, 0x91,
1008 0xb1, 0x0b,
1009 0xc0, 0x53,
1010 0xc1, 0x70,
1011 0xc2, 0x12,
1012 0xd0, 0x00,
1013 0xd1, 0x00,
1014 0xd2, 0x00,
1015 0xd3, 0x00,
1016 0xd4, 0x00,
1017 0xd5, 0x00,
1018 0xde, 0x00,
1019 0xdf, 0x00,
1020 0x61, 0x38,
1021 0x62, 0x0a,
1022 0x53, 0x13,
1023 0x59, 0x08,
1024 0xff, 0xff,
1025};
1026
1027static struct stv0297_config dvbc_philips_tdm1316l_config = {
1028 .demod_address = 0x1c,
1029 .inittab = dvbc_philips_tdm1316l_inittab,
1030 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001031 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001032};
1033
Sigmund Augdal11417da2008-06-15 17:25:46 -03001034static struct tda10023_config tda10023_config = {
1035 .demod_address = 0xc,
1036 .invert = 0,
1037 .xtal = 16000000,
1038 .pll_m = 11,
1039 .pll_p = 3,
1040 .pll_n = 1,
1041 .deltaf = 0xa511,
1042};
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001043
klaas de waalcf47d872009-03-25 17:53:02 -03001044static struct tda827x_config tda827x_config = {
1045 .config = 0,
1046};
1047
Manu Abrahama55bc842008-10-23 18:32:50 -03001048/* TT S2-3200 DVB-S (STB0899) Inittab */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001049static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001051 { STB0899_DEV_ID , 0x81 },
1052 { STB0899_DISCNTRL1 , 0x32 },
1053 { STB0899_DISCNTRL2 , 0x80 },
1054 { STB0899_DISRX_ST0 , 0x04 },
1055 { STB0899_DISRX_ST1 , 0x00 },
1056 { STB0899_DISPARITY , 0x00 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001057 { STB0899_DISSTATUS , 0x20 },
1058 { STB0899_DISF22 , 0x8c },
1059 { STB0899_DISF22RX , 0x9a },
Manu Abrahamef3052b2008-10-23 18:45:17 -03001060 { STB0899_SYSREG , 0x0b },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001061 { STB0899_ACRPRESC , 0x11 },
1062 { STB0899_ACRDIV1 , 0x0a },
1063 { STB0899_ACRDIV2 , 0x05 },
1064 { STB0899_DACR1 , 0x00 },
1065 { STB0899_DACR2 , 0x00 },
1066 { STB0899_OUTCFG , 0x00 },
1067 { STB0899_MODECFG , 0x00 },
1068 { STB0899_IRQSTATUS_3 , 0x30 },
1069 { STB0899_IRQSTATUS_2 , 0x00 },
1070 { STB0899_IRQSTATUS_1 , 0x00 },
1071 { STB0899_IRQSTATUS_0 , 0x00 },
1072 { STB0899_IRQMSK_3 , 0xf3 },
1073 { STB0899_IRQMSK_2 , 0xfc },
1074 { STB0899_IRQMSK_1 , 0xff },
1075 { STB0899_IRQMSK_0 , 0xff },
1076 { STB0899_IRQCFG , 0x00 },
1077 { STB0899_I2CCFG , 0x88 },
Manu Abraham40e8ce32008-02-03 19:37:02 -03001078 { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001079 { STB0899_IOPVALUE5 , 0x00 },
1080 { STB0899_IOPVALUE4 , 0x20 },
1081 { STB0899_IOPVALUE3 , 0xc9 },
1082 { STB0899_IOPVALUE2 , 0x90 },
1083 { STB0899_IOPVALUE1 , 0x40 },
1084 { STB0899_IOPVALUE0 , 0x00 },
1085 { STB0899_GPIO00CFG , 0x82 },
1086 { STB0899_GPIO01CFG , 0x82 },
1087 { STB0899_GPIO02CFG , 0x82 },
1088 { STB0899_GPIO03CFG , 0x82 },
1089 { STB0899_GPIO04CFG , 0x82 },
1090 { STB0899_GPIO05CFG , 0x82 },
1091 { STB0899_GPIO06CFG , 0x82 },
1092 { STB0899_GPIO07CFG , 0x82 },
1093 { STB0899_GPIO08CFG , 0x82 },
1094 { STB0899_GPIO09CFG , 0x82 },
1095 { STB0899_GPIO10CFG , 0x82 },
1096 { STB0899_GPIO11CFG , 0x82 },
1097 { STB0899_GPIO12CFG , 0x82 },
1098 { STB0899_GPIO13CFG , 0x82 },
1099 { STB0899_GPIO14CFG , 0x82 },
1100 { STB0899_GPIO15CFG , 0x82 },
1101 { STB0899_GPIO16CFG , 0x82 },
1102 { STB0899_GPIO17CFG , 0x82 },
1103 { STB0899_GPIO18CFG , 0x82 },
1104 { STB0899_GPIO19CFG , 0x82 },
1105 { STB0899_GPIO20CFG , 0x82 },
1106 { STB0899_SDATCFG , 0xb8 },
1107 { STB0899_SCLTCFG , 0xba },
Manu Abrahama55bc842008-10-23 18:32:50 -03001108 { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */
1109 { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
1110 { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001111 { STB0899_DIRCLKCFG , 0x82 },
1112 { STB0899_CLKOUT27CFG , 0x7e },
1113 { STB0899_STDBYCFG , 0x82 },
1114 { STB0899_CS0CFG , 0x82 },
1115 { STB0899_CS1CFG , 0x82 },
1116 { STB0899_DISEQCOCFG , 0x20 },
1117 { STB0899_GPIO32CFG , 0x82 },
1118 { STB0899_GPIO33CFG , 0x82 },
1119 { STB0899_GPIO34CFG , 0x82 },
1120 { STB0899_GPIO35CFG , 0x82 },
1121 { STB0899_GPIO36CFG , 0x82 },
1122 { STB0899_GPIO37CFG , 0x82 },
1123 { STB0899_GPIO38CFG , 0x82 },
1124 { STB0899_GPIO39CFG , 0x82 },
Manu Abrahamf2e52cd2007-11-19 16:44:47 -03001125 { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
Manu Abrahama55bc842008-10-23 18:32:50 -03001126 { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001127 { STB0899_FILTCTRL , 0x00 },
1128 { STB0899_SYSCTRL , 0x00 },
1129 { STB0899_STOPCLK1 , 0x20 },
1130 { STB0899_STOPCLK2 , 0x00 },
1131 { STB0899_INTBUFSTATUS , 0x00 },
1132 { STB0899_INTBUFCTRL , 0x0a },
1133 { 0xffff , 0xff },
1134};
1135
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001136static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
1137 { STB0899_DEMOD , 0x00 },
1138 { STB0899_RCOMPC , 0xc9 },
1139 { STB0899_AGC1CN , 0x41 },
1140 { STB0899_AGC1REF , 0x10 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001141 { STB0899_RTC , 0x7a },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001142 { STB0899_TMGCFG , 0x4e },
1143 { STB0899_AGC2REF , 0x34 },
1144 { STB0899_TLSR , 0x84 },
1145 { STB0899_CFD , 0xc7 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001146 { STB0899_ACLC , 0x87 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001147 { STB0899_BCLC , 0x94 },
1148 { STB0899_EQON , 0x41 },
1149 { STB0899_LDT , 0xdd },
1150 { STB0899_LDT2 , 0xc9 },
1151 { STB0899_EQUALREF , 0xb4 },
1152 { STB0899_TMGRAMP , 0x10 },
1153 { STB0899_TMGTHD , 0x30 },
1154 { STB0899_IDCCOMP , 0xfb },
1155 { STB0899_QDCCOMP , 0x03 },
1156 { STB0899_POWERI , 0x3b },
1157 { STB0899_POWERQ , 0x3d },
1158 { STB0899_RCOMP , 0x81 },
1159 { STB0899_AGCIQIN , 0x80 },
1160 { STB0899_AGC2I1 , 0x04 },
1161 { STB0899_AGC2I2 , 0xf5 },
1162 { STB0899_TLIR , 0x25 },
1163 { STB0899_RTF , 0x80 },
1164 { STB0899_DSTATUS , 0x00 },
1165 { STB0899_LDI , 0xca },
1166 { STB0899_CFRM , 0xf1 },
1167 { STB0899_CFRL , 0xf3 },
1168 { STB0899_NIRM , 0x2a },
1169 { STB0899_NIRL , 0x05 },
1170 { STB0899_ISYMB , 0x17 },
1171 { STB0899_QSYMB , 0xfa },
1172 { STB0899_SFRH , 0x2f },
1173 { STB0899_SFRM , 0x68 },
1174 { STB0899_SFRL , 0x40 },
1175 { STB0899_SFRUPH , 0x2f },
1176 { STB0899_SFRUPM , 0x68 },
1177 { STB0899_SFRUPL , 0x40 },
1178 { STB0899_EQUAI1 , 0xfd },
1179 { STB0899_EQUAQ1 , 0x04 },
1180 { STB0899_EQUAI2 , 0x0f },
1181 { STB0899_EQUAQ2 , 0xff },
1182 { STB0899_EQUAI3 , 0xdf },
1183 { STB0899_EQUAQ3 , 0xfa },
1184 { STB0899_EQUAI4 , 0x37 },
1185 { STB0899_EQUAQ4 , 0x0d },
1186 { STB0899_EQUAI5 , 0xbd },
1187 { STB0899_EQUAQ5 , 0xf7 },
1188 { STB0899_DSTATUS2 , 0x00 },
1189 { STB0899_VSTATUS , 0x00 },
1190 { STB0899_VERROR , 0xff },
1191 { STB0899_IQSWAP , 0x2a },
1192 { STB0899_ECNT1M , 0x00 },
1193 { STB0899_ECNT1L , 0x00 },
1194 { STB0899_ECNT2M , 0x00 },
1195 { STB0899_ECNT2L , 0x00 },
1196 { STB0899_ECNT3M , 0x00 },
1197 { STB0899_ECNT3L , 0x00 },
1198 { STB0899_FECAUTO1 , 0x06 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001199 { STB0899_FECM , 0x01 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001200 { STB0899_VTH12 , 0xf0 },
1201 { STB0899_VTH23 , 0xa0 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001202 { STB0899_VTH34 , 0x78 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001203 { STB0899_VTH56 , 0x4e },
1204 { STB0899_VTH67 , 0x48 },
1205 { STB0899_VTH78 , 0x38 },
1206 { STB0899_PRVIT , 0xff },
1207 { STB0899_VITSYNC , 0x19 },
Manu Abrahama55bc842008-10-23 18:32:50 -03001208 { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001209 { STB0899_TSULC , 0x42 },
1210 { STB0899_RSLLC , 0x40 },
Mauro Carvalho Chehabf34253d2008-11-10 18:56:20 -03001211 { STB0899_TSLPL , 0x12 },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001212 { STB0899_TSCFGH , 0x0c },
1213 { STB0899_TSCFGM , 0x00 },
1214 { STB0899_TSCFGL , 0x0c },
Manu Abrahamc1426df2009-11-13 18:51:39 -03001215 { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001216 { STB0899_RSSYNCDEL , 0x00 },
1217 { STB0899_TSINHDELH , 0x02 },
1218 { STB0899_TSINHDELM , 0x00 },
1219 { STB0899_TSINHDELL , 0x00 },
1220 { STB0899_TSLLSTKM , 0x00 },
1221 { STB0899_TSLLSTKL , 0x00 },
1222 { STB0899_TSULSTKM , 0x00 },
1223 { STB0899_TSULSTKL , 0xab },
1224 { STB0899_PCKLENUL , 0x00 },
1225 { STB0899_PCKLENLL , 0xcc },
1226 { STB0899_RSPCKLEN , 0xcc },
1227 { STB0899_TSSTATUS , 0x80 },
1228 { STB0899_ERRCTRL1 , 0xb6 },
1229 { STB0899_ERRCTRL2 , 0x96 },
1230 { STB0899_ERRCTRL3 , 0x89 },
1231 { STB0899_DMONMSK1 , 0x27 },
1232 { STB0899_DMONMSK0 , 0x03 },
1233 { STB0899_DEMAPVIT , 0x5c },
1234 { STB0899_PLPARM , 0x1f },
1235 { STB0899_PDELCTRL , 0x48 },
1236 { STB0899_PDELCTRL2 , 0x00 },
1237 { STB0899_BBHCTRL1 , 0x00 },
1238 { STB0899_BBHCTRL2 , 0x00 },
1239 { STB0899_HYSTTHRESH , 0x77 },
1240 { STB0899_MATCSTM , 0x00 },
1241 { STB0899_MATCSTL , 0x00 },
1242 { STB0899_UPLCSTM , 0x00 },
1243 { STB0899_UPLCSTL , 0x00 },
1244 { STB0899_DFLCSTM , 0x00 },
1245 { STB0899_DFLCSTL , 0x00 },
1246 { STB0899_SYNCCST , 0x00 },
1247 { STB0899_SYNCDCSTM , 0x00 },
1248 { STB0899_SYNCDCSTL , 0x00 },
1249 { STB0899_ISI_ENTRY , 0x00 },
1250 { STB0899_ISI_BIT_EN , 0x00 },
1251 { STB0899_MATSTRM , 0x00 },
1252 { STB0899_MATSTRL , 0x00 },
1253 { STB0899_UPLSTRM , 0x00 },
1254 { STB0899_UPLSTRL , 0x00 },
1255 { STB0899_DFLSTRM , 0x00 },
1256 { STB0899_DFLSTRL , 0x00 },
1257 { STB0899_SYNCSTR , 0x00 },
1258 { STB0899_SYNCDSTRM , 0x00 },
1259 { STB0899_SYNCDSTRL , 0x00 },
1260 { STB0899_CFGPDELSTATUS1 , 0x10 },
1261 { STB0899_CFGPDELSTATUS2 , 0x00 },
1262 { STB0899_BBFERRORM , 0x00 },
1263 { STB0899_BBFERRORL , 0x00 },
1264 { STB0899_UPKTERRORM , 0x00 },
1265 { STB0899_UPKTERRORL , 0x00 },
1266 { 0xffff , 0xff },
1267};
1268
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001269static struct stb0899_config tt3200_config = {
1270 .init_dev = tt3200_stb0899_s1_init_1,
Manu Abraham8be969b2008-01-25 18:20:48 -03001271 .init_s2_demod = stb0899_s2_init_2,
Manu Abrahama55bc842008-10-23 18:32:50 -03001272 .init_s1_demod = tt3200_stb0899_s1_init_3,
Manu Abraham8be969b2008-01-25 18:20:48 -03001273 .init_s2_fec = stb0899_s2_init_4,
1274 .init_tst = stb0899_s1_init_5,
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001275
Manu Abraham043a68b2008-01-18 14:15:17 -03001276 .postproc = NULL,
1277
Manu Abrahama55bc842008-10-23 18:32:50 -03001278 .demod_address = 0x68,
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001279
1280 .xtal_freq = 27000000,
Reinhard Nissl07356472013-05-08 17:54:57 -03001281 .inversion = IQ_SWAP_ON,
Manu Abrahama55bc842008-10-23 18:32:50 -03001282
Manu Abrahamb91a7cb2008-03-04 19:19:58 -03001283 .lo_clk = 76500000,
1284 .hi_clk = 99000000,
1285
Manu Abraham8be969b2008-01-25 18:20:48 -03001286 .esno_ave = STB0899_DVBS2_ESNO_AVE,
1287 .esno_quant = STB0899_DVBS2_ESNO_QUANT,
1288 .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
1289 .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
1290 .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
1291 .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
1292 .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
1293 .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
1294 .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
Manu Abrahama55bc842008-10-23 18:32:50 -03001295
Manu Abraham8be969b2008-01-25 18:20:48 -03001296 .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
1297 .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
1298 .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
1299 .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
Manu Abrahama55bc842008-10-23 18:32:50 -03001300
1301 .tuner_get_frequency = stb6100_get_frequency,
1302 .tuner_set_frequency = stb6100_set_frequency,
1303 .tuner_set_bandwidth = stb6100_set_bandwidth,
1304 .tuner_get_bandwidth = stb6100_get_bandwidth,
Manu Abraham043a68b2008-01-18 14:15:17 -03001305 .tuner_set_rfsiggain = NULL
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001306};
1307
Mauro Carvalho Chehabffbc5f82009-01-05 01:34:20 -03001308static struct stb6100_config tt3200_stb6100_config = {
Manu Abrahamc14eaed2007-10-04 16:52:51 -03001309 .tuner_address = 0x60,
1310 .refclock = 27000000,
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001311};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001312
1313static void frontend_init(struct budget_ci *budget_ci)
1314{
1315 switch (budget_ci->budget.dev->pci->subsystem_device) {
1316 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1317 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001318 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001320 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001321 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322 break;
1323 }
1324 break;
1325
1326 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1327 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001328 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001329 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001330 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001331 break;
1332 }
1333 break;
1334
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001335 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1336 budget_ci->tuner_pll_address = 0x61;
1337 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001338 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001339 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001340 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001341 break;
1342 }
1343 break;
1344
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001346 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001348 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001350 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1351 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 break;
1353 }
1354 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001355
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001356 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001357 budget_ci->tuner_pll_address = 0x60;
1358 budget_ci->budget.dvb_frontend =
Oliver Endriss6c914492007-02-02 19:12:53 -03001359 dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001360 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001361 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1362 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001363 break;
1364 }
1365 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001366
1367 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001368 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001369 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001370 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001371 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1372
Patrick Boettcherdea74862006-05-14 05:01:31 -03001373 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001374 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 -03001375 printk("%s: No LNBP21 found!\n", __func__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001376 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001377 budget_ci->budget.dvb_frontend = NULL;
1378 }
1379 }
Sigmund Augdal11417da2008-06-15 17:25:46 -03001380 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001381
Sigmund Augdal11417da2008-06-15 17:25:46 -03001382 case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
1383 budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
1384 if (budget_ci->budget.dvb_frontend) {
klaas de waalcf47d872009-03-25 17:53:02 -03001385 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 -03001386 printk(KERN_ERR "%s: No tda827x found!\n", __func__);
1387 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1388 budget_ci->budget.dvb_frontend = NULL;
1389 }
1390 }
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001391 break;
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001392
Oliver Endriss574312d2011-03-29 17:37:00 -03001393 case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */
1394 budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap);
1395 if (budget_ci->budget.dvb_frontend) {
1396 if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) {
1397 if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
1398 printk(KERN_ERR "%s: No LNBP21 found!\n", __func__);
1399 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1400 budget_ci->budget.dvb_frontend = NULL;
1401 }
1402 } else {
1403 printk(KERN_ERR "%s: No STB6000 found!\n", __func__);
1404 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1405 budget_ci->budget.dvb_frontend = NULL;
1406 }
1407 }
1408 break;
1409
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001410 case 0x1019: // TT S2-3200 PCI
Manu Abraham6efb0ff2007-10-15 12:08:20 -03001411 /*
1412 * NOTE! on some STB0899 versions, the internal PLL takes a longer time
1413 * to settle, aka LOCK. On the older revisions of the chip, we don't see
1414 * this, as a result on the newer chips the entire clock tree, will not
1415 * be stable after a freshly POWER 'ed up situation.
1416 * In this case, we should RESET the STB0899 (Active LOW) and wait for
1417 * PLL stabilization.
1418 *
1419 * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is
1420 * connected to the SAA7146 GPIO, GPIO2, Pin 142
1421 */
1422 /* Reset Demodulator */
Manu Abraham0867f572007-10-15 13:07:16 -03001423 saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO);
Manu Abraham6efb0ff2007-10-15 12:08:20 -03001424 /* Wait for everything to die */
1425 msleep(50);
1426 /* Pull it up out of Reset state */
Manu Abraham0867f572007-10-15 13:07:16 -03001427 saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI);
Manu Abraham6efb0ff2007-10-15 12:08:20 -03001428 /* Wait for PLL to stabilize */
1429 msleep(250);
1430 /*
1431 * PLL state should be stable now. Ideally, we should check
1432 * for PLL LOCK status. But well, never mind!
1433 */
Manu Abrahamae9902d2007-10-08 18:51:54 -03001434 budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap);
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001435 if (budget_ci->budget.dvb_frontend) {
Manu Abrahamae9902d2007-10-08 18:51:54 -03001436 if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) {
1437 if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
Harvey Harrison9b4778f2009-01-07 14:42:41 -08001438 printk("%s: No LNBP21 found!\n", __func__);
Manu Abrahamae9902d2007-10-08 18:51:54 -03001439 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001440 budget_ci->budget.dvb_frontend = NULL;
1441 }
1442 } else {
Manu Abrahamae9902d2007-10-08 18:51:54 -03001443 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1444 budget_ci->budget.dvb_frontend = NULL;
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001445 }
1446 }
1447 break;
1448
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 }
1450
1451 if (budget_ci->budget.dvb_frontend == NULL) {
Bjorn Helgaas29e66a62008-09-04 17:24:51 -03001452 printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 budget_ci->budget.dev->pci->vendor,
1454 budget_ci->budget.dev->pci->device,
1455 budget_ci->budget.dev->pci->subsystem_vendor,
1456 budget_ci->budget.dev->pci->subsystem_device);
1457 } else {
1458 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001459 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001461 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 budget_ci->budget.dvb_frontend = NULL;
1463 }
1464 }
1465}
1466
1467static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1468{
1469 struct budget_ci *budget_ci;
1470 int err;
1471
David Hardemanee579bc2006-12-02 21:16:05 -02001472 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001473 if (!budget_ci) {
1474 err = -ENOMEM;
1475 goto out1;
1476 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477
1478 dprintk(2, "budget_ci: %p\n", budget_ci);
1479
Linus Torvalds1da177e2005-04-16 15:20:36 -07001480 dev->ext_priv = budget_ci;
1481
Janne Grunau26dc4d02008-09-21 20:50:11 -03001482 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE,
1483 adapter_nr);
David Hardeman8cc532e2006-12-02 21:16:05 -02001484 if (err)
1485 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
David Hardeman8cc532e2006-12-02 21:16:05 -02001487 err = msp430_ir_init(budget_ci);
1488 if (err)
1489 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
1491 ciintf_init(budget_ci);
1492
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001493 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494 frontend_init(budget_ci);
1495
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001496 ttpci_budget_init_hooks(&budget_ci->budget);
1497
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001499
1500out3:
1501 ttpci_budget_deinit(&budget_ci->budget);
1502out2:
1503 kfree(budget_ci);
1504out1:
1505 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506}
1507
1508static int budget_ci_detach(struct saa7146_dev *dev)
1509{
1510 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1511 struct saa7146_dev *saa = budget_ci->budget.dev;
1512 int err;
1513
1514 if (budget_ci->budget.ci_present)
1515 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001516 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001517 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001519 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001520 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001521 err = ttpci_budget_deinit(&budget_ci->budget);
1522
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 // disable frontend and CI interface
1524 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1525
1526 kfree(budget_ci);
1527
1528 return err;
1529}
1530
1531static struct saa7146_extension budget_extension;
1532
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001533MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001534MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1535MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001536MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001537MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Sigmund Augdal11417da2008-06-15 17:25:46 -03001538MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001539MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
Oliver Endriss574312d2011-03-29 17:37:00 -03001540MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541
Arvind Yadav110cb3c2017-08-02 13:14:52 -04001542static const struct pci_device_id pci_tbl[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1544 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001545 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001547 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001548 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Sigmund Augdal11417da2008-06-15 17:25:46 -03001549 MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001550 MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
Oliver Endriss574312d2011-03-29 17:37:00 -03001551 MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 {
1553 .vendor = 0,
1554 }
1555};
1556
1557MODULE_DEVICE_TABLE(pci, pci_tbl);
1558
1559static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001560 .name = "budget_ci dvb",
Oliver Endriss00c4cc62006-11-01 13:09:51 -03001561 .flags = SAA7146_USE_I2C_IRQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562
1563 .module = THIS_MODULE,
1564 .pci_tbl = &pci_tbl[0],
1565 .attach = budget_ci_attach,
1566 .detach = budget_ci_detach,
1567
1568 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1569 .irq_func = budget_ci_irq,
1570};
1571
1572static int __init budget_ci_init(void)
1573{
1574 return saa7146_register_extension(&budget_extension);
1575}
1576
1577static void __exit budget_ci_exit(void)
1578{
1579 saa7146_unregister_extension(&budget_extension);
1580}
1581
1582module_init(budget_ci_init);
1583module_exit(budget_ci_exit);
1584
1585MODULE_LICENSE("GPL");
1586MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
Mauro Carvalho Chehab008e6ff2016-10-18 17:44:07 -02001587MODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB cards w/ CI-module produced by Siemens, Technotrend, Hauppauge");