blob: ebe8210b123d0c4195ba1bfb6554509471291f76 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * budget-ci.c: driver for the SAA7146 based Budget DVB cards
3 *
4 * Compiled from various sources by Michael Hunold <michael@mihu.de>
5 *
6 * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
7 * partially based on the Siemens DVB driver by Ralph+Marcus Metzler
8 *
9 * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
27 *
28 *
29 * the project's page is at http://www.linuxtv.org/dvb/
30 */
31
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/module.h>
33#include <linux/errno.h>
34#include <linux/slab.h>
35#include <linux/interrupt.h>
36#include <linux/input.h>
37#include <linux/spinlock.h>
David Hardeman2520fff2006-12-02 21:16:05 -020038#include <media/ir-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Trent Piepho68277092007-01-30 23:25:46 -030040#include "budget.h"
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "dvb_ca_en50221.h"
43#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070044#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "tda1004x.h"
Marko Schluessler9e0dc662008-10-23 18:16:40 -030046#include "stb0899_drv.h"
47#include "stb0899_reg.h"
Manu Abraham8be969b2008-01-25 18:20:48 -030048#include "stb0899_cfg.h"
Marko Schluessler9e0dc662008-10-23 18:16:40 -030049#include "stb6100.h"
Manu Abraham8be969b2008-01-25 18:20:48 -030050#include "stb6100_cfg.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030051#include "lnbp21.h"
52#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030053#include "bsru6.h"
Sigmund Augdal11417da2008-06-15 17:25:46 -030054#include "tda1002x.h"
55#include "tda827x.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
David Härdemanecba77f2006-10-27 20:56:51 -030057/*
58 * Regarding DEBIADDR_IR:
59 * Some CI modules hang if random addresses are read.
60 * Using address 0x4000 for the IR read means that we
61 * use the same address as for CI version, which should
62 * be a safe default.
63 */
64#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070065#define DEBIADDR_CICONTROL 0x0000
66#define DEBIADDR_CIVERSION 0x4000
67#define DEBIADDR_IO 0x1000
68#define DEBIADDR_ATTR 0x3000
69
70#define CICONTROL_RESET 0x01
71#define CICONTROL_ENABLETS 0x02
72#define CICONTROL_CAMDETECT 0x08
73
74#define DEBICICTL 0x00420000
75#define DEBICICAM 0x02420000
76
77#define SLOTSTATUS_NONE 1
78#define SLOTSTATUS_PRESENT 2
79#define SLOTSTATUS_RESET 4
80#define SLOTSTATUS_READY 8
81#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
82
David Härdeman145859c2007-04-27 12:31:22 -030083/*
84 * Milliseconds during which a key is regarded as pressed.
85 * If an identical command arrives within this time, the timer will start over.
David Hardeman2520fff2006-12-02 21:16:05 -020086 */
David Härdeman145859c2007-04-27 12:31:22 -030087#define IR_KEYPRESS_TIMEOUT 250
David Hardeman2520fff2006-12-02 21:16:05 -020088
David Hardeman64741b72006-12-02 21:16:05 -020089/* RC5 device wildcard */
90#define IR_DEVICE_ANY 255
91
David Hardeman64741b72006-12-02 21:16:05 -020092static int rc5_device = -1;
93module_param(rc5_device, int, 0644);
94MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
95
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030096static int ir_debug;
David Hardemanb5471a22006-12-02 21:16:05 -020097module_param(ir_debug, int, 0644);
98MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
99
Janne Grunau26dc4d02008-09-21 20:50:11 -0300100DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
101
David Hardemandd2f3982006-12-02 21:16:05 -0200102struct budget_ci_ir {
103 struct input_dev *dev;
104 struct tasklet_struct msp430_irq_tasklet;
David Härdeman145859c2007-04-27 12:31:22 -0300105 struct timer_list timer_keyup;
David Hardemandd2f3982006-12-02 21:16:05 -0200106 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -0200107 char phys[32];
David Hardeman2520fff2006-12-02 21:16:05 -0200108 struct ir_input_state state;
David Hardeman64741b72006-12-02 21:16:05 -0200109 int rc5_device;
David Härdeman145859c2007-04-27 12:31:22 -0300110 u32 last_raw;
111 u32 ir_key;
112 bool have_command;
David Hardemandd2f3982006-12-02 21:16:05 -0200113};
114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115struct budget_ci {
116 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 struct tasklet_struct ciintf_irq_tasklet;
118 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300119 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -0200121 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700122 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123};
124
David Hardeman2520fff2006-12-02 21:16:05 -0200125static void msp430_ir_keyup(unsigned long data)
126{
127 struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
128 ir_input_nokey(ir->dev, &ir->state);
129}
130
131static void msp430_ir_interrupt(unsigned long data)
132{
133 struct budget_ci *budget_ci = (struct budget_ci *) data;
134 struct input_dev *dev = budget_ci->ir.dev;
David Hardeman2520fff2006-12-02 21:16:05 -0200135 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
David Härdeman145859c2007-04-27 12:31:22 -0300136 u32 raw;
David Hardeman2520fff2006-12-02 21:16:05 -0200137
David Hardeman64741b72006-12-02 21:16:05 -0200138 /*
139 * The msp430 chip can generate two different bytes, command and device
140 *
141 * type1: X1CCCCCC, C = command bits (0 - 63)
142 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
143 *
David Härdeman59327a42007-02-13 09:39:58 -0300144 * Each signal from the remote control can generate one or more command
145 * bytes and one or more device bytes. For the repeated bytes, the
146 * highest bit (X) is set. The first command byte is always generated
147 * before the first device byte. Other than that, no specific order
David Härdeman145859c2007-04-27 12:31:22 -0300148 * seems to apply. To make life interesting, bytes can also be lost.
David Härdeman59327a42007-02-13 09:39:58 -0300149 *
150 * Only when we have a command and device byte, a keypress is
151 * generated.
David Hardeman64741b72006-12-02 21:16:05 -0200152 */
153
David Härdeman59327a42007-02-13 09:39:58 -0300154 if (ir_debug)
155 printk("budget_ci: received byte 0x%02x\n", command);
156
David Härdeman145859c2007-04-27 12:31:22 -0300157 /* Remove repeat bit, we use every command */
158 command = command & 0x7f;
David Härdeman59327a42007-02-13 09:39:58 -0300159
David Hardeman64741b72006-12-02 21:16:05 -0200160 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200161 if (command & 0x40) {
David Härdeman145859c2007-04-27 12:31:22 -0300162 budget_ci->ir.have_command = true;
163 budget_ci->ir.ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200164 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200165 }
David Hardeman64741b72006-12-02 21:16:05 -0200166
167 /* It's a RC5 device byte */
David Härdeman145859c2007-04-27 12:31:22 -0300168 if (!budget_ci->ir.have_command)
David Härdeman59327a42007-02-13 09:39:58 -0300169 return;
David Härdeman145859c2007-04-27 12:31:22 -0300170 budget_ci->ir.have_command = false;
David Hardeman64741b72006-12-02 21:16:05 -0200171
David Härdeman145859c2007-04-27 12:31:22 -0300172 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
173 budget_ci->ir.rc5_device != (command & 0x1f))
David Hardeman64741b72006-12-02 21:16:05 -0200174 return;
175
David Härdeman145859c2007-04-27 12:31:22 -0300176 /* Is this a repeated key sequence? (same device, command, toggle) */
177 raw = budget_ci->ir.ir_key | (command << 8);
178 if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) {
David Hardeman59236d42006-12-02 21:16:06 -0200179 ir_input_nokey(dev, &budget_ci->ir.state);
David Härdeman145859c2007-04-27 12:31:22 -0300180 ir_input_keydown(dev, &budget_ci->ir.state,
181 budget_ci->ir.ir_key, raw);
182 budget_ci->ir.last_raw = raw;
David Hardeman59236d42006-12-02 21:16:06 -0200183 }
David Härdeman145859c2007-04-27 12:31:22 -0300184
185 mod_timer(&budget_ci->ir.timer_keyup, jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT));
David Hardeman2520fff2006-12-02 21:16:05 -0200186}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188static int msp430_ir_init(struct budget_ci *budget_ci)
189{
190 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200191 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200192 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
David Hardemandd2f3982006-12-02 21:16:05 -0200194 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200195 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200196 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200197 error = -ENOMEM;
198 goto out1;
199 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
David Hardemandd2f3982006-12-02 21:16:05 -0200201 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
202 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200203 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
204 "pci-%s/ir0", pci_name(saa->pci));
205
David Hardemandd2f3982006-12-02 21:16:05 -0200206 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
David Hardeman5cc8ae02006-12-02 21:16:05 -0200208 input_dev->phys = budget_ci->ir.phys;
209 input_dev->id.bustype = BUS_PCI;
210 input_dev->id.version = 1;
211 if (saa->pci->subsystem_vendor) {
212 input_dev->id.vendor = saa->pci->subsystem_vendor;
213 input_dev->id.product = saa->pci->subsystem_device;
214 } else {
215 input_dev->id.vendor = saa->pci->vendor;
216 input_dev->id.product = saa->pci->device;
217 }
Dmitry Torokhov2c8a3a32007-07-16 09:28:15 -0300218 input_dev->dev.parent = &saa->pci->dev;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200219
David Hardeman64741b72006-12-02 21:16:05 -0200220 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200221 switch (budget_ci->budget.dev->pci->subsystem_device) {
222 case 0x100c:
223 case 0x100f:
David Hardeman2520fff2006-12-02 21:16:05 -0200224 case 0x1011:
225 case 0x1012:
David Hardeman2520fff2006-12-02 21:16:05 -0200226 /* The hauppauge keymap is a superset of these remotes */
227 ir_input_init(input_dev, &budget_ci->ir.state,
228 IR_TYPE_RC5, ir_codes_hauppauge_new);
David Hardeman64741b72006-12-02 21:16:05 -0200229
230 if (rc5_device < 0)
231 budget_ci->ir.rc5_device = 0x1f;
232 else
233 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200234 break;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300235 case 0x1010:
Oliver Endrissf64899c2007-09-17 22:17:12 -0300236 case 0x1017:
Oliver Endrissbbfc4c22008-06-19 23:36:45 -0300237 case 0x101a:
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300238 /* for the Technotrend 1500 bundled remote */
239 ir_input_init(input_dev, &budget_ci->ir.state,
240 IR_TYPE_RC5, ir_codes_tt_1500);
241
242 if (rc5_device < 0)
243 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
244 else
245 budget_ci->ir.rc5_device = rc5_device;
246 break;
David Hardeman2520fff2006-12-02 21:16:05 -0200247 default:
248 /* unknown remote */
249 ir_input_init(input_dev, &budget_ci->ir.state,
250 IR_TYPE_RC5, ir_codes_budget_ci_old);
David Hardeman64741b72006-12-02 21:16:05 -0200251
252 if (rc5_device < 0)
253 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
254 else
255 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200256 break;
257 }
258
David Härdeman145859c2007-04-27 12:31:22 -0300259 /* initialise the key-up timeout handler */
260 init_timer(&budget_ci->ir.timer_keyup);
261 budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
262 budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
263 budget_ci->ir.last_raw = 0xffff; /* An impossible value */
David Hardeman8cc532e2006-12-02 21:16:05 -0200264 error = input_register_device(input_dev);
265 if (error) {
266 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
267 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300268 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269
David Härdeman145859c2007-04-27 12:31:22 -0300270 /* note: these must be after input_register_device */
271 input_dev->rep[REP_DELAY] = 400;
272 input_dev->rep[REP_PERIOD] = 250;
273
David Hardeman8cc532e2006-12-02 21:16:05 -0200274 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
275 (unsigned long) budget_ci);
276
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300277 SAA7146_IER_ENABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
279
280 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200281
282out2:
283 input_free_device(input_dev);
284out1:
285 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286}
287
288static void msp430_ir_deinit(struct budget_ci *budget_ci)
289{
290 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200291 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300293 SAA7146_IER_DISABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200295 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296
David Härdeman145859c2007-04-27 12:31:22 -0300297 del_timer_sync(&dev->timer);
298 ir_input_nokey(dev, &budget_ci->ir.state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299
300 input_unregister_device(dev);
301}
302
303static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
304{
305 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
306
307 if (slot != 0)
308 return -EINVAL;
309
310 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
311 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
312}
313
314static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
315{
316 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
317
318 if (slot != 0)
319 return -EINVAL;
320
321 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
322 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
323}
324
325static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
326{
327 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
328
329 if (slot != 0)
330 return -EINVAL;
331
332 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
333 DEBIADDR_IO | (address & 3), 1, 1, 0);
334}
335
336static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
337{
338 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
339
340 if (slot != 0)
341 return -EINVAL;
342
343 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
344 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
345}
346
347static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
348{
349 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
350 struct saa7146_dev *saa = budget_ci->budget.dev;
351
352 if (slot != 0)
353 return -EINVAL;
354
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300355 if (budget_ci->ci_irq) {
356 // trigger on RISING edge during reset so we know when READY is re-asserted
357 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
358 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 budget_ci->slot_status = SLOTSTATUS_RESET;
360 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
361 msleep(1);
362 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
363 CICONTROL_RESET, 1, 0);
364
365 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
366 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
367 return 0;
368}
369
370static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
371{
372 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
373 struct saa7146_dev *saa = budget_ci->budget.dev;
374
375 if (slot != 0)
376 return -EINVAL;
377
378 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
379 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
380 return 0;
381}
382
383static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
384{
385 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
386 struct saa7146_dev *saa = budget_ci->budget.dev;
387 int tmp;
388
389 if (slot != 0)
390 return -EINVAL;
391
392 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
393
394 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
395 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
396 tmp | CICONTROL_ENABLETS, 1, 0);
397
398 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
399 return 0;
400}
401
402static void ciintf_interrupt(unsigned long data)
403{
404 struct budget_ci *budget_ci = (struct budget_ci *) data;
405 struct saa7146_dev *saa = budget_ci->budget.dev;
406 unsigned int flags;
407
408 // ensure we don't get spurious IRQs during initialisation
409 if (!budget_ci->budget.ci_present)
410 return;
411
412 // read the CAM status
413 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
414 if (flags & CICONTROL_CAMDETECT) {
415
416 // GPIO should be set to trigger on falling edge if a CAM is present
417 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
418
419 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
420 // CAM insertion IRQ
421 budget_ci->slot_status = SLOTSTATUS_PRESENT;
422 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
423 DVB_CA_EN50221_CAMCHANGE_INSERTED);
424
425 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
426 // CAM ready (reset completed)
427 budget_ci->slot_status = SLOTSTATUS_READY;
428 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
429
430 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
431 // FR/DA IRQ
432 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
433 }
434 } else {
435
436 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
437 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
438 // the CAM might not actually be ready yet.
439 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
440
441 // generate a CAM removal IRQ if we haven't already
442 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
443 // CAM removal IRQ
444 budget_ci->slot_status = SLOTSTATUS_NONE;
445 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
446 DVB_CA_EN50221_CAMCHANGE_REMOVED);
447 }
448 }
449}
450
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300451static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
452{
453 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
454 unsigned int flags;
455
456 // ensure we don't get spurious IRQs during initialisation
457 if (!budget_ci->budget.ci_present)
458 return -EINVAL;
459
460 // read the CAM status
461 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
462 if (flags & CICONTROL_CAMDETECT) {
463 // mark it as present if it wasn't before
464 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
465 budget_ci->slot_status = SLOTSTATUS_PRESENT;
466 }
467
468 // during a RESET, we check if we can read from IO memory to see when CAM is ready
469 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
470 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
471 budget_ci->slot_status = SLOTSTATUS_READY;
472 }
473 }
474 } else {
475 budget_ci->slot_status = SLOTSTATUS_NONE;
476 }
477
478 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
479 if (budget_ci->slot_status & SLOTSTATUS_READY) {
480 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
481 }
482 return DVB_CA_EN50221_POLL_CAM_PRESENT;
483 }
484
485 return 0;
486}
487
Linus Torvalds1da177e2005-04-16 15:20:36 -0700488static int ciintf_init(struct budget_ci *budget_ci)
489{
490 struct saa7146_dev *saa = budget_ci->budget.dev;
491 int flags;
492 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300493 int ci_version;
494 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
497
498 // enable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300499 saa7146_write(saa, MC1, MASK_27 | MASK_11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
501 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300502 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
503 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 result = -ENODEV;
505 goto error;
506 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300507
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508 // determine whether a CAM is present or not
509 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
510 budget_ci->slot_status = SLOTSTATUS_NONE;
511 if (flags & CICONTROL_CAMDETECT)
512 budget_ci->slot_status = SLOTSTATUS_PRESENT;
513
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300514 // version 0xa2 of the CI firmware doesn't generate interrupts
515 if (ci_version == 0xa2) {
516 ca_flags = 0;
517 budget_ci->ci_irq = 0;
518 } else {
519 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
520 DVB_CA_EN50221_FLAG_IRQ_FR |
521 DVB_CA_EN50221_FLAG_IRQ_DA;
522 budget_ci->ci_irq = 1;
523 }
524
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 // register CI interface
526 budget_ci->ca.owner = THIS_MODULE;
527 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
528 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
529 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
530 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
531 budget_ci->ca.slot_reset = ciintf_slot_reset;
532 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
533 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300534 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700536 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700537 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300538 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 printk("budget_ci: CI interface detected, but initialisation failed.\n");
540 goto error;
541 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300542
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300544 if (budget_ci->ci_irq) {
545 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
546 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
547 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
548 } else {
549 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
550 }
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300551 SAA7146_IER_ENABLE(saa, MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300553
554 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
556 CICONTROL_RESET, 1, 0);
557
558 // success!
559 printk("budget_ci: CI interface initialised\n");
560 budget_ci->budget.ci_present = 1;
561
562 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300563 if (budget_ci->ci_irq) {
564 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
565 if (budget_ci->slot_status != SLOTSTATUS_NONE)
566 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
567 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569
570 return 0;
571
572error:
Hartmut Birr2a893de2006-12-03 21:08:08 -0300573 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 return result;
575}
576
577static void ciintf_deinit(struct budget_ci *budget_ci)
578{
579 struct saa7146_dev *saa = budget_ci->budget.dev;
580
581 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300582 if (budget_ci->ci_irq) {
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300583 SAA7146_IER_DISABLE(saa, MASK_03);
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300584 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
585 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
586 }
587
588 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
590 msleep(1);
591 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
592 CICONTROL_RESET, 1, 0);
593
594 // disable TS data stream to CI interface
595 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
596
597 // release the CA device
598 dvb_ca_en50221_release(&budget_ci->ca);
599
600 // disable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300601 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602}
603
604static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
605{
606 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
607
608 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
609
610 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200611 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612
613 if (*isr & MASK_10)
614 ttpci_budget_irq10_handler(dev, isr);
615
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300616 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
618}
619
Linus Torvalds1da177e2005-04-16 15:20:36 -0700620static u8 philips_su1278_tt_inittab[] = {
621 0x01, 0x0f,
622 0x02, 0x30,
623 0x03, 0x00,
624 0x04, 0x5b,
625 0x05, 0x85,
626 0x06, 0x02,
627 0x07, 0x00,
628 0x08, 0x02,
629 0x09, 0x00,
630 0x0C, 0x01,
631 0x0D, 0x81,
632 0x0E, 0x44,
633 0x0f, 0x14,
634 0x10, 0x3c,
635 0x11, 0x84,
636 0x12, 0xda,
637 0x13, 0x97,
638 0x14, 0x95,
639 0x15, 0xc9,
640 0x16, 0x19,
641 0x17, 0x8c,
642 0x18, 0x59,
643 0x19, 0xf8,
644 0x1a, 0xfe,
645 0x1c, 0x7f,
646 0x1d, 0x00,
647 0x1e, 0x00,
648 0x1f, 0x50,
649 0x20, 0x00,
650 0x21, 0x00,
651 0x22, 0x00,
652 0x23, 0x00,
653 0x28, 0x00,
654 0x29, 0x28,
655 0x2a, 0x14,
656 0x2b, 0x0f,
657 0x2c, 0x09,
658 0x2d, 0x09,
659 0x31, 0x1f,
660 0x32, 0x19,
661 0x33, 0xfc,
662 0x34, 0x93,
663 0xff, 0xff
664};
665
666static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
667{
668 stv0299_writereg(fe, 0x0e, 0x44);
669 if (srate >= 10000000) {
670 stv0299_writereg(fe, 0x13, 0x97);
671 stv0299_writereg(fe, 0x14, 0x95);
672 stv0299_writereg(fe, 0x15, 0xc9);
673 stv0299_writereg(fe, 0x17, 0x8c);
674 stv0299_writereg(fe, 0x1a, 0xfe);
675 stv0299_writereg(fe, 0x1c, 0x7f);
676 stv0299_writereg(fe, 0x2d, 0x09);
677 } else {
678 stv0299_writereg(fe, 0x13, 0x99);
679 stv0299_writereg(fe, 0x14, 0x8d);
680 stv0299_writereg(fe, 0x15, 0xce);
681 stv0299_writereg(fe, 0x17, 0x43);
682 stv0299_writereg(fe, 0x1a, 0x1d);
683 stv0299_writereg(fe, 0x1c, 0x12);
684 stv0299_writereg(fe, 0x2d, 0x05);
685 }
686 stv0299_writereg(fe, 0x0e, 0x23);
687 stv0299_writereg(fe, 0x0f, 0x94);
688 stv0299_writereg(fe, 0x10, 0x39);
689 stv0299_writereg(fe, 0x15, 0xc9);
690
691 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
692 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
693 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
694
695 return 0;
696}
697
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300698static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
699 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300701 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 u32 div;
703 u8 buf[4];
704 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
705
706 if ((params->frequency < 950000) || (params->frequency > 2150000))
707 return -EINVAL;
708
709 div = (params->frequency + (500 - 1)) / 500; // round correctly
710 buf[0] = (div >> 8) & 0x7f;
711 buf[1] = div & 0xff;
712 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
713 buf[3] = 0x20;
714
715 if (params->u.qpsk.symbol_rate < 4000000)
716 buf[3] |= 1;
717
718 if (params->frequency < 1250000)
719 buf[3] |= 0;
720 else if (params->frequency < 1550000)
721 buf[3] |= 0x40;
722 else if (params->frequency < 2050000)
723 buf[3] |= 0x80;
724 else if (params->frequency < 2150000)
725 buf[3] |= 0xC0;
726
Patrick Boettcherdea74862006-05-14 05:01:31 -0300727 if (fe->ops.i2c_gate_ctrl)
728 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300729 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 return -EIO;
731 return 0;
732}
733
734static struct stv0299_config philips_su1278_tt_config = {
735
736 .demod_address = 0x68,
737 .inittab = philips_su1278_tt_inittab,
738 .mclk = 64000000UL,
739 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 .skip_reinit = 1,
Oliver Endrissda2c7f62008-04-20 22:13:37 -0300741 .lock_output = STV0299_LOCKOUTPUT_1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742 .volt13_op0_op1 = STV0299_VOLT13_OP1,
743 .min_delay_ms = 50,
744 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745};
746
747
748
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300749static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750{
751 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
752 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
753 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700754 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 sizeof(td1316_init) };
756
757 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300758 if (fe->ops.i2c_gate_ctrl)
759 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700760 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
761 return -EIO;
762 msleep(1);
763
764 // disable the mc44BC374c (do not check for errors)
765 tuner_msg.addr = 0x65;
766 tuner_msg.buf = disable_mc44BC374c;
767 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300768 if (fe->ops.i2c_gate_ctrl)
769 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300771 if (fe->ops.i2c_gate_ctrl)
772 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
774 }
775
776 return 0;
777}
778
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300779static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700780{
781 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
782 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700783 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 -0700784 int tuner_frequency = 0;
785 u8 band, cp, filter;
786
787 // determine charge pump
788 tuner_frequency = params->frequency + 36130000;
789 if (tuner_frequency < 87000000)
790 return -EINVAL;
791 else if (tuner_frequency < 130000000)
792 cp = 3;
793 else if (tuner_frequency < 160000000)
794 cp = 5;
795 else if (tuner_frequency < 200000000)
796 cp = 6;
797 else if (tuner_frequency < 290000000)
798 cp = 3;
799 else if (tuner_frequency < 420000000)
800 cp = 5;
801 else if (tuner_frequency < 480000000)
802 cp = 6;
803 else if (tuner_frequency < 620000000)
804 cp = 3;
805 else if (tuner_frequency < 830000000)
806 cp = 5;
807 else if (tuner_frequency < 895000000)
808 cp = 7;
809 else
810 return -EINVAL;
811
812 // determine band
813 if (params->frequency < 49000000)
814 return -EINVAL;
815 else if (params->frequency < 159000000)
816 band = 1;
817 else if (params->frequency < 444000000)
818 band = 2;
819 else if (params->frequency < 861000000)
820 band = 4;
821 else
822 return -EINVAL;
823
824 // setup PLL filter and TDA9889
825 switch (params->u.ofdm.bandwidth) {
826 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300827 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 filter = 0;
829 break;
830
831 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300832 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 filter = 0;
834 break;
835
836 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300837 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 filter = 1;
839 break;
840
841 default:
842 return -EINVAL;
843 }
844
845 // calculate divisor
846 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
847 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
848
849 // setup tuner buffer
850 tuner_buf[0] = tuner_frequency >> 8;
851 tuner_buf[1] = tuner_frequency & 0xff;
852 tuner_buf[2] = 0xca;
853 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
854
Patrick Boettcherdea74862006-05-14 05:01:31 -0300855 if (fe->ops.i2c_gate_ctrl)
856 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
858 return -EIO;
859
860 msleep(1);
861 return 0;
862}
863
864static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
865 const struct firmware **fw, char *name)
866{
867 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
868
869 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
870}
871
872static struct tda1004x_config philips_tdm1316l_config = {
873
874 .demod_address = 0x8,
875 .invert = 0,
876 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700877 .xtal_freq = TDA10046_XTAL_4M,
878 .agc_config = TDA10046_AGC_DEFAULT,
879 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 .request_firmware = philips_tdm1316l_request_firmware,
881};
882
Oliver Endriss6c914492007-02-02 19:12:53 -0300883static struct tda1004x_config philips_tdm1316l_config_invert = {
884
885 .demod_address = 0x8,
886 .invert = 1,
887 .invert_oclk = 0,
888 .xtal_freq = TDA10046_XTAL_4M,
889 .agc_config = TDA10046_AGC_DEFAULT,
890 .if_freq = TDA10046_FREQ_3617,
891 .request_firmware = philips_tdm1316l_request_firmware,
892};
893
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300894static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700895{
896 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
897 u8 tuner_buf[5];
898 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
899 .flags = 0,
900 .buf = tuner_buf,
901 .len = sizeof(tuner_buf) };
902 int tuner_frequency = 0;
903 u8 band, cp, filter;
904
905 // determine charge pump
906 tuner_frequency = params->frequency + 36125000;
907 if (tuner_frequency < 87000000)
908 return -EINVAL;
909 else if (tuner_frequency < 130000000) {
910 cp = 3;
911 band = 1;
912 } else if (tuner_frequency < 160000000) {
913 cp = 5;
914 band = 1;
915 } else if (tuner_frequency < 200000000) {
916 cp = 6;
Oliver Endriss910a7b62007-05-03 13:16:12 -0300917 band = 1;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700918 } else if (tuner_frequency < 290000000) {
919 cp = 3;
920 band = 2;
921 } else if (tuner_frequency < 420000000) {
922 cp = 5;
923 band = 2;
924 } else if (tuner_frequency < 480000000) {
925 cp = 6;
926 band = 2;
927 } else if (tuner_frequency < 620000000) {
928 cp = 3;
929 band = 4;
930 } else if (tuner_frequency < 830000000) {
931 cp = 5;
932 band = 4;
933 } else if (tuner_frequency < 895000000) {
934 cp = 7;
935 band = 4;
936 } else
937 return -EINVAL;
938
939 // assume PLL filter should always be 8MHz for the moment.
940 filter = 1;
941
942 // calculate divisor
943 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
944
945 // setup tuner buffer
946 tuner_buf[0] = tuner_frequency >> 8;
947 tuner_buf[1] = tuner_frequency & 0xff;
948 tuner_buf[2] = 0xc8;
949 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
950 tuner_buf[4] = 0x80;
951
Patrick Boettcherdea74862006-05-14 05:01:31 -0300952 if (fe->ops.i2c_gate_ctrl)
953 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700954 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
955 return -EIO;
956
957 msleep(50);
958
Patrick Boettcherdea74862006-05-14 05:01:31 -0300959 if (fe->ops.i2c_gate_ctrl)
960 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700961 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
962 return -EIO;
963
964 msleep(1);
965
966 return 0;
967}
968
969static u8 dvbc_philips_tdm1316l_inittab[] = {
970 0x80, 0x01,
971 0x80, 0x00,
972 0x81, 0x01,
973 0x81, 0x00,
974 0x00, 0x09,
975 0x01, 0x69,
976 0x03, 0x00,
977 0x04, 0x00,
978 0x07, 0x00,
979 0x08, 0x00,
980 0x20, 0x00,
981 0x21, 0x40,
982 0x22, 0x00,
983 0x23, 0x00,
984 0x24, 0x40,
985 0x25, 0x88,
986 0x30, 0xff,
987 0x31, 0x00,
988 0x32, 0xff,
989 0x33, 0x00,
990 0x34, 0x50,
991 0x35, 0x7f,
992 0x36, 0x00,
993 0x37, 0x20,
994 0x38, 0x00,
995 0x40, 0x1c,
996 0x41, 0xff,
997 0x42, 0x29,
998 0x43, 0x20,
999 0x44, 0xff,
1000 0x45, 0x00,
1001 0x46, 0x00,
1002 0x49, 0x04,
1003 0x4a, 0x00,
1004 0x4b, 0x7b,
1005 0x52, 0x30,
1006 0x55, 0xae,
1007 0x56, 0x47,
1008 0x57, 0xe1,
1009 0x58, 0x3a,
1010 0x5a, 0x1e,
1011 0x5b, 0x34,
1012 0x60, 0x00,
1013 0x63, 0x00,
1014 0x64, 0x00,
1015 0x65, 0x00,
1016 0x66, 0x00,
1017 0x67, 0x00,
1018 0x68, 0x00,
1019 0x69, 0x00,
1020 0x6a, 0x02,
1021 0x6b, 0x00,
1022 0x70, 0xff,
1023 0x71, 0x00,
1024 0x72, 0x00,
1025 0x73, 0x00,
1026 0x74, 0x0c,
1027 0x80, 0x00,
1028 0x81, 0x00,
1029 0x82, 0x00,
1030 0x83, 0x00,
1031 0x84, 0x04,
1032 0x85, 0x80,
1033 0x86, 0x24,
1034 0x87, 0x78,
1035 0x88, 0x10,
1036 0x89, 0x00,
1037 0x90, 0x01,
1038 0x91, 0x01,
1039 0xa0, 0x04,
1040 0xa1, 0x00,
1041 0xa2, 0x00,
1042 0xb0, 0x91,
1043 0xb1, 0x0b,
1044 0xc0, 0x53,
1045 0xc1, 0x70,
1046 0xc2, 0x12,
1047 0xd0, 0x00,
1048 0xd1, 0x00,
1049 0xd2, 0x00,
1050 0xd3, 0x00,
1051 0xd4, 0x00,
1052 0xd5, 0x00,
1053 0xde, 0x00,
1054 0xdf, 0x00,
1055 0x61, 0x38,
1056 0x62, 0x0a,
1057 0x53, 0x13,
1058 0x59, 0x08,
1059 0xff, 0xff,
1060};
1061
1062static struct stv0297_config dvbc_philips_tdm1316l_config = {
1063 .demod_address = 0x1c,
1064 .inittab = dvbc_philips_tdm1316l_inittab,
1065 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001066 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001067};
1068
Sigmund Augdal11417da2008-06-15 17:25:46 -03001069static struct tda10023_config tda10023_config = {
1070 .demod_address = 0xc,
1071 .invert = 0,
1072 .xtal = 16000000,
1073 .pll_m = 11,
1074 .pll_p = 3,
1075 .pll_n = 1,
1076 .deltaf = 0xa511,
1077};
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001078
Manu Abrahama55bc842008-10-23 18:32:50 -03001079/* TT S2-3200 DVB-S (STB0899) Inittab */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001080static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001082 { STB0899_DEV_ID , 0x81 },
1083 { STB0899_DISCNTRL1 , 0x32 },
1084 { STB0899_DISCNTRL2 , 0x80 },
1085 { STB0899_DISRX_ST0 , 0x04 },
1086 { STB0899_DISRX_ST1 , 0x00 },
1087 { STB0899_DISPARITY , 0x00 },
1088 { STB0899_DISFIFO , 0x00 },
1089 { STB0899_DISSTATUS , 0x20 },
1090 { STB0899_DISF22 , 0x8c },
1091 { STB0899_DISF22RX , 0x9a },
Manu Abrahamef3052b2008-10-23 18:45:17 -03001092 { STB0899_SYSREG , 0x0b },
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001093 { STB0899_ACRPRESC , 0x11 },
1094 { STB0899_ACRDIV1 , 0x0a },
1095 { STB0899_ACRDIV2 , 0x05 },
1096 { STB0899_DACR1 , 0x00 },
1097 { STB0899_DACR2 , 0x00 },
1098 { STB0899_OUTCFG , 0x00 },
1099 { STB0899_MODECFG , 0x00 },
1100 { STB0899_IRQSTATUS_3 , 0x30 },
1101 { STB0899_IRQSTATUS_2 , 0x00 },
1102 { STB0899_IRQSTATUS_1 , 0x00 },
1103 { STB0899_IRQSTATUS_0 , 0x00 },
1104 { STB0899_IRQMSK_3 , 0xf3 },
1105 { STB0899_IRQMSK_2 , 0xfc },
1106 { STB0899_IRQMSK_1 , 0xff },
1107 { STB0899_IRQMSK_0 , 0xff },
1108 { STB0899_IRQCFG , 0x00 },
1109 { STB0899_I2CCFG , 0x88 },
Manu Abraham40e8ce32008-02-03 19:37:02 -03001110 { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001111 { STB0899_IOPVALUE5 , 0x00 },
1112 { STB0899_IOPVALUE4 , 0x20 },
1113 { STB0899_IOPVALUE3 , 0xc9 },
1114 { STB0899_IOPVALUE2 , 0x90 },
1115 { STB0899_IOPVALUE1 , 0x40 },
1116 { STB0899_IOPVALUE0 , 0x00 },
1117 { STB0899_GPIO00CFG , 0x82 },
1118 { STB0899_GPIO01CFG , 0x82 },
1119 { STB0899_GPIO02CFG , 0x82 },
1120 { STB0899_GPIO03CFG , 0x82 },
1121 { STB0899_GPIO04CFG , 0x82 },
1122 { STB0899_GPIO05CFG , 0x82 },
1123 { STB0899_GPIO06CFG , 0x82 },
1124 { STB0899_GPIO07CFG , 0x82 },
1125 { STB0899_GPIO08CFG , 0x82 },
1126 { STB0899_GPIO09CFG , 0x82 },
1127 { STB0899_GPIO10CFG , 0x82 },
1128 { STB0899_GPIO11CFG , 0x82 },
1129 { STB0899_GPIO12CFG , 0x82 },
1130 { STB0899_GPIO13CFG , 0x82 },
1131 { STB0899_GPIO14CFG , 0x82 },
1132 { STB0899_GPIO15CFG , 0x82 },
1133 { STB0899_GPIO16CFG , 0x82 },
1134 { STB0899_GPIO17CFG , 0x82 },
1135 { STB0899_GPIO18CFG , 0x82 },
1136 { STB0899_GPIO19CFG , 0x82 },
1137 { STB0899_GPIO20CFG , 0x82 },
1138 { STB0899_SDATCFG , 0xb8 },
1139 { STB0899_SCLTCFG , 0xba },
Manu Abrahama55bc842008-10-23 18:32:50 -03001140 { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */
1141 { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */
1142 { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001143 { STB0899_DIRCLKCFG , 0x82 },
1144 { STB0899_CLKOUT27CFG , 0x7e },
1145 { STB0899_STDBYCFG , 0x82 },
1146 { STB0899_CS0CFG , 0x82 },
1147 { STB0899_CS1CFG , 0x82 },
1148 { STB0899_DISEQCOCFG , 0x20 },
1149 { STB0899_GPIO32CFG , 0x82 },
1150 { STB0899_GPIO33CFG , 0x82 },
1151 { STB0899_GPIO34CFG , 0x82 },
1152 { STB0899_GPIO35CFG , 0x82 },
1153 { STB0899_GPIO36CFG , 0x82 },
1154 { STB0899_GPIO37CFG , 0x82 },
1155 { STB0899_GPIO38CFG , 0x82 },
1156 { STB0899_GPIO39CFG , 0x82 },
Manu Abraham27a330d2007-11-19 16:44:47 -03001157 { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */
Manu Abrahama55bc842008-10-23 18:32:50 -03001158 { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001159 { STB0899_FILTCTRL , 0x00 },
1160 { STB0899_SYSCTRL , 0x00 },
1161 { STB0899_STOPCLK1 , 0x20 },
1162 { STB0899_STOPCLK2 , 0x00 },
1163 { STB0899_INTBUFSTATUS , 0x00 },
1164 { STB0899_INTBUFCTRL , 0x0a },
1165 { 0xffff , 0xff },
1166};
1167
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001168static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = {
1169 { STB0899_DEMOD , 0x00 },
1170 { STB0899_RCOMPC , 0xc9 },
1171 { STB0899_AGC1CN , 0x41 },
1172 { STB0899_AGC1REF , 0x10 },
1173 { STB0899_RTC , 0x7a },
1174 { STB0899_TMGCFG , 0x4e },
1175 { STB0899_AGC2REF , 0x34 },
1176 { STB0899_TLSR , 0x84 },
1177 { STB0899_CFD , 0xc7 },
1178 { STB0899_ACLC , 0x87 },
1179 { STB0899_BCLC , 0x94 },
1180 { STB0899_EQON , 0x41 },
1181 { STB0899_LDT , 0xdd },
1182 { STB0899_LDT2 , 0xc9 },
1183 { STB0899_EQUALREF , 0xb4 },
1184 { STB0899_TMGRAMP , 0x10 },
1185 { STB0899_TMGTHD , 0x30 },
1186 { STB0899_IDCCOMP , 0xfb },
1187 { STB0899_QDCCOMP , 0x03 },
1188 { STB0899_POWERI , 0x3b },
1189 { STB0899_POWERQ , 0x3d },
1190 { STB0899_RCOMP , 0x81 },
1191 { STB0899_AGCIQIN , 0x80 },
1192 { STB0899_AGC2I1 , 0x04 },
1193 { STB0899_AGC2I2 , 0xf5 },
1194 { STB0899_TLIR , 0x25 },
1195 { STB0899_RTF , 0x80 },
1196 { STB0899_DSTATUS , 0x00 },
1197 { STB0899_LDI , 0xca },
1198 { STB0899_CFRM , 0xf1 },
1199 { STB0899_CFRL , 0xf3 },
1200 { STB0899_NIRM , 0x2a },
1201 { STB0899_NIRL , 0x05 },
1202 { STB0899_ISYMB , 0x17 },
1203 { STB0899_QSYMB , 0xfa },
1204 { STB0899_SFRH , 0x2f },
1205 { STB0899_SFRM , 0x68 },
1206 { STB0899_SFRL , 0x40 },
1207 { STB0899_SFRUPH , 0x2f },
1208 { STB0899_SFRUPM , 0x68 },
1209 { STB0899_SFRUPL , 0x40 },
1210 { STB0899_EQUAI1 , 0xfd },
1211 { STB0899_EQUAQ1 , 0x04 },
1212 { STB0899_EQUAI2 , 0x0f },
1213 { STB0899_EQUAQ2 , 0xff },
1214 { STB0899_EQUAI3 , 0xdf },
1215 { STB0899_EQUAQ3 , 0xfa },
1216 { STB0899_EQUAI4 , 0x37 },
1217 { STB0899_EQUAQ4 , 0x0d },
1218 { STB0899_EQUAI5 , 0xbd },
1219 { STB0899_EQUAQ5 , 0xf7 },
1220 { STB0899_DSTATUS2 , 0x00 },
1221 { STB0899_VSTATUS , 0x00 },
1222 { STB0899_VERROR , 0xff },
1223 { STB0899_IQSWAP , 0x2a },
1224 { STB0899_ECNT1M , 0x00 },
1225 { STB0899_ECNT1L , 0x00 },
1226 { STB0899_ECNT2M , 0x00 },
1227 { STB0899_ECNT2L , 0x00 },
1228 { STB0899_ECNT3M , 0x00 },
1229 { STB0899_ECNT3L , 0x00 },
1230 { STB0899_FECAUTO1 , 0x06 },
1231 { STB0899_FECM , 0x01 },
1232 { STB0899_VTH12 , 0xf0 },
1233 { STB0899_VTH23 , 0xa0 },
1234 { STB0899_VTH34 , 0x78 },
1235 { STB0899_VTH56 , 0x4e },
1236 { STB0899_VTH67 , 0x48 },
1237 { STB0899_VTH78 , 0x38 },
1238 { STB0899_PRVIT , 0xff },
1239 { STB0899_VITSYNC , 0x19 },
Manu Abrahama55bc842008-10-23 18:32:50 -03001240 { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001241 { STB0899_TSULC , 0x42 },
1242 { STB0899_RSLLC , 0x40 },
1243 { STB0899_TSLPL , 0x12 },
1244 { STB0899_TSCFGH , 0x0c },
1245 { STB0899_TSCFGM , 0x00 },
1246 { STB0899_TSCFGL , 0x0c },
Manu Abraham6ea223c2007-09-24 19:58:24 -03001247 { STB0899_TSOUT , 0x0d }, /* 0x0d for CAM */
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001248 { STB0899_RSSYNCDEL , 0x00 },
1249 { STB0899_TSINHDELH , 0x02 },
1250 { STB0899_TSINHDELM , 0x00 },
1251 { STB0899_TSINHDELL , 0x00 },
1252 { STB0899_TSLLSTKM , 0x00 },
1253 { STB0899_TSLLSTKL , 0x00 },
1254 { STB0899_TSULSTKM , 0x00 },
1255 { STB0899_TSULSTKL , 0xab },
1256 { STB0899_PCKLENUL , 0x00 },
1257 { STB0899_PCKLENLL , 0xcc },
1258 { STB0899_RSPCKLEN , 0xcc },
1259 { STB0899_TSSTATUS , 0x80 },
1260 { STB0899_ERRCTRL1 , 0xb6 },
1261 { STB0899_ERRCTRL2 , 0x96 },
1262 { STB0899_ERRCTRL3 , 0x89 },
1263 { STB0899_DMONMSK1 , 0x27 },
1264 { STB0899_DMONMSK0 , 0x03 },
1265 { STB0899_DEMAPVIT , 0x5c },
1266 { STB0899_PLPARM , 0x1f },
1267 { STB0899_PDELCTRL , 0x48 },
1268 { STB0899_PDELCTRL2 , 0x00 },
1269 { STB0899_BBHCTRL1 , 0x00 },
1270 { STB0899_BBHCTRL2 , 0x00 },
1271 { STB0899_HYSTTHRESH , 0x77 },
1272 { STB0899_MATCSTM , 0x00 },
1273 { STB0899_MATCSTL , 0x00 },
1274 { STB0899_UPLCSTM , 0x00 },
1275 { STB0899_UPLCSTL , 0x00 },
1276 { STB0899_DFLCSTM , 0x00 },
1277 { STB0899_DFLCSTL , 0x00 },
1278 { STB0899_SYNCCST , 0x00 },
1279 { STB0899_SYNCDCSTM , 0x00 },
1280 { STB0899_SYNCDCSTL , 0x00 },
1281 { STB0899_ISI_ENTRY , 0x00 },
1282 { STB0899_ISI_BIT_EN , 0x00 },
1283 { STB0899_MATSTRM , 0x00 },
1284 { STB0899_MATSTRL , 0x00 },
1285 { STB0899_UPLSTRM , 0x00 },
1286 { STB0899_UPLSTRL , 0x00 },
1287 { STB0899_DFLSTRM , 0x00 },
1288 { STB0899_DFLSTRL , 0x00 },
1289 { STB0899_SYNCSTR , 0x00 },
1290 { STB0899_SYNCDSTRM , 0x00 },
1291 { STB0899_SYNCDSTRL , 0x00 },
1292 { STB0899_CFGPDELSTATUS1 , 0x10 },
1293 { STB0899_CFGPDELSTATUS2 , 0x00 },
1294 { STB0899_BBFERRORM , 0x00 },
1295 { STB0899_BBFERRORL , 0x00 },
1296 { STB0899_UPKTERRORM , 0x00 },
1297 { STB0899_UPKTERRORL , 0x00 },
1298 { 0xffff , 0xff },
1299};
1300
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001301static struct stb0899_config tt3200_config = {
1302 .init_dev = tt3200_stb0899_s1_init_1,
Manu Abraham8be969b2008-01-25 18:20:48 -03001303 .init_s2_demod = stb0899_s2_init_2,
Manu Abrahama55bc842008-10-23 18:32:50 -03001304 .init_s1_demod = tt3200_stb0899_s1_init_3,
Manu Abraham8be969b2008-01-25 18:20:48 -03001305 .init_s2_fec = stb0899_s2_init_4,
1306 .init_tst = stb0899_s1_init_5,
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001307
Manu Abraham043a68b2008-01-18 14:15:17 -03001308 .postproc = NULL,
1309
Manu Abrahama55bc842008-10-23 18:32:50 -03001310 .demod_address = 0x68,
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001311
1312 .xtal_freq = 27000000,
Manu Abrahame99d00c2007-09-25 17:48:59 -03001313 .inversion = IQ_SWAP_ON, /* 1 */
Manu Abrahama55bc842008-10-23 18:32:50 -03001314
Manu Abraham8be969b2008-01-25 18:20:48 -03001315 .esno_ave = STB0899_DVBS2_ESNO_AVE,
1316 .esno_quant = STB0899_DVBS2_ESNO_QUANT,
1317 .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE,
1318 .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE,
1319 .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD,
1320 .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ,
1321 .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK,
1322 .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF,
1323 .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT,
Manu Abrahama55bc842008-10-23 18:32:50 -03001324
Manu Abraham8be969b2008-01-25 18:20:48 -03001325 .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS,
1326 .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET,
1327 .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS,
1328 .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER,
Manu Abrahama55bc842008-10-23 18:32:50 -03001329
1330 .tuner_get_frequency = stb6100_get_frequency,
1331 .tuner_set_frequency = stb6100_set_frequency,
1332 .tuner_set_bandwidth = stb6100_set_bandwidth,
1333 .tuner_get_bandwidth = stb6100_get_bandwidth,
Manu Abraham043a68b2008-01-18 14:15:17 -03001334 .tuner_set_rfsiggain = NULL
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001335};
1336
1337struct stb6100_config tt3200_stb6100_config = {
Manu Abrahamc14eaed2007-10-04 16:52:51 -03001338 .tuner_address = 0x60,
1339 .refclock = 27000000,
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001340};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001341
1342static void frontend_init(struct budget_ci *budget_ci)
1343{
1344 switch (budget_ci->budget.dev->pci->subsystem_device) {
1345 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1346 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001347 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001348 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001349 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001350 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351 break;
1352 }
1353 break;
1354
1355 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1356 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001357 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001358 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001359 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001360 break;
1361 }
1362 break;
1363
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001364 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1365 budget_ci->tuner_pll_address = 0x61;
1366 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001367 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001368 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001369 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001370 break;
1371 }
1372 break;
1373
Linus Torvalds1da177e2005-04-16 15:20:36 -07001374 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001375 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001377 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001378 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001379 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1380 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381 break;
1382 }
1383 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001384
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001385 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001386 budget_ci->tuner_pll_address = 0x60;
1387 budget_ci->budget.dvb_frontend =
Oliver Endriss6c914492007-02-02 19:12:53 -03001388 dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001389 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001390 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1391 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001392 break;
1393 }
1394 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001395
1396 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001397 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001398 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001399 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001400 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1401
Patrick Boettcherdea74862006-05-14 05:01:31 -03001402 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001403 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 -03001404 printk("%s: No LNBP21 found!\n", __func__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001405 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001406 budget_ci->budget.dvb_frontend = NULL;
1407 }
1408 }
Sigmund Augdal11417da2008-06-15 17:25:46 -03001409 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001410
Sigmund Augdal11417da2008-06-15 17:25:46 -03001411 case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
1412 budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
1413 if (budget_ci->budget.dvb_frontend) {
1414 if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
1415 printk(KERN_ERR "%s: No tda827x found!\n", __func__);
1416 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1417 budget_ci->budget.dvb_frontend = NULL;
1418 }
1419 }
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001420 break;
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001421
1422 case 0x1019: // TT S2-3200 PCI
Manu Abraham6efb0ff2007-10-15 12:08:20 -03001423 /*
1424 * NOTE! on some STB0899 versions, the internal PLL takes a longer time
1425 * to settle, aka LOCK. On the older revisions of the chip, we don't see
1426 * this, as a result on the newer chips the entire clock tree, will not
1427 * be stable after a freshly POWER 'ed up situation.
1428 * In this case, we should RESET the STB0899 (Active LOW) and wait for
1429 * PLL stabilization.
1430 *
1431 * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is
1432 * connected to the SAA7146 GPIO, GPIO2, Pin 142
1433 */
1434 /* Reset Demodulator */
Manu Abraham0867f572007-10-15 13:07:16 -03001435 saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTLO);
Manu Abraham6efb0ff2007-10-15 12:08:20 -03001436 /* Wait for everything to die */
1437 msleep(50);
1438 /* Pull it up out of Reset state */
Manu Abraham0867f572007-10-15 13:07:16 -03001439 saa7146_setgpio(budget_ci->budget.dev, 2, SAA7146_GPIO_OUTHI);
Manu Abraham6efb0ff2007-10-15 12:08:20 -03001440 /* Wait for PLL to stabilize */
1441 msleep(250);
1442 /*
1443 * PLL state should be stable now. Ideally, we should check
1444 * for PLL LOCK status. But well, never mind!
1445 */
Manu Abrahamae9902d2007-10-08 18:51:54 -03001446 budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap);
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001447 if (budget_ci->budget.dvb_frontend) {
Manu Abrahamae9902d2007-10-08 18:51:54 -03001448 if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) {
1449 if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) {
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001450 printk("%s: No LNBP21 found!\n", __FUNCTION__);
Manu Abrahamae9902d2007-10-08 18:51:54 -03001451 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001452 budget_ci->budget.dvb_frontend = NULL;
1453 }
1454 } else {
Manu Abrahamae9902d2007-10-08 18:51:54 -03001455 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1456 budget_ci->budget.dvb_frontend = NULL;
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001457 }
1458 }
1459 break;
1460
Linus Torvalds1da177e2005-04-16 15:20:36 -07001461 }
1462
1463 if (budget_ci->budget.dvb_frontend == NULL) {
Bjorn Helgaas29e66a62008-09-04 17:24:51 -03001464 printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 budget_ci->budget.dev->pci->vendor,
1466 budget_ci->budget.dev->pci->device,
1467 budget_ci->budget.dev->pci->subsystem_vendor,
1468 budget_ci->budget.dev->pci->subsystem_device);
1469 } else {
1470 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001471 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001473 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 budget_ci->budget.dvb_frontend = NULL;
1475 }
1476 }
1477}
1478
1479static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1480{
1481 struct budget_ci *budget_ci;
1482 int err;
1483
David Hardemanee579bc2006-12-02 21:16:05 -02001484 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001485 if (!budget_ci) {
1486 err = -ENOMEM;
1487 goto out1;
1488 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489
1490 dprintk(2, "budget_ci: %p\n", budget_ci);
1491
Linus Torvalds1da177e2005-04-16 15:20:36 -07001492 dev->ext_priv = budget_ci;
1493
Janne Grunau26dc4d02008-09-21 20:50:11 -03001494 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE,
1495 adapter_nr);
David Hardeman8cc532e2006-12-02 21:16:05 -02001496 if (err)
1497 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
David Hardeman8cc532e2006-12-02 21:16:05 -02001499 err = msp430_ir_init(budget_ci);
1500 if (err)
1501 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502
1503 ciintf_init(budget_ci);
1504
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001505 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001506 frontend_init(budget_ci);
1507
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001508 ttpci_budget_init_hooks(&budget_ci->budget);
1509
Linus Torvalds1da177e2005-04-16 15:20:36 -07001510 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001511
1512out3:
1513 ttpci_budget_deinit(&budget_ci->budget);
1514out2:
1515 kfree(budget_ci);
1516out1:
1517 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518}
1519
1520static int budget_ci_detach(struct saa7146_dev *dev)
1521{
1522 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1523 struct saa7146_dev *saa = budget_ci->budget.dev;
1524 int err;
1525
1526 if (budget_ci->budget.ci_present)
1527 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001528 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001529 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001531 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001532 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533 err = ttpci_budget_deinit(&budget_ci->budget);
1534
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 // disable frontend and CI interface
1536 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1537
1538 kfree(budget_ci);
1539
1540 return err;
1541}
1542
1543static struct saa7146_extension budget_extension;
1544
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001545MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1547MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001548MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001549MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Sigmund Augdal11417da2008-06-15 17:25:46 -03001550MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001551MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
1553static struct pci_device_id pci_tbl[] = {
1554 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1555 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001556 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001557 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001558 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001559 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Sigmund Augdal11417da2008-06-15 17:25:46 -03001560 MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
Marko Schluessler9e0dc662008-10-23 18:16:40 -03001561 MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562 {
1563 .vendor = 0,
1564 }
1565};
1566
1567MODULE_DEVICE_TABLE(pci, pci_tbl);
1568
1569static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001570 .name = "budget_ci dvb",
Oliver Endriss00c4cc62006-11-01 13:09:51 -03001571 .flags = SAA7146_USE_I2C_IRQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
1573 .module = THIS_MODULE,
1574 .pci_tbl = &pci_tbl[0],
1575 .attach = budget_ci_attach,
1576 .detach = budget_ci_detach,
1577
1578 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1579 .irq_func = budget_ci_irq,
1580};
1581
1582static int __init budget_ci_init(void)
1583{
1584 return saa7146_register_extension(&budget_extension);
1585}
1586
1587static void __exit budget_ci_exit(void)
1588{
1589 saa7146_unregister_extension(&budget_extension);
1590}
1591
1592module_init(budget_ci_init);
1593module_exit(budget_ci_exit);
1594
1595MODULE_LICENSE("GPL");
1596MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1597MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1598 "budget PCI DVB cards w/ CI-module produced by "
1599 "Siemens, Technotrend, Hauppauge");