blob: 0a5aad45435d2c0bb37209b8fb2341513f38e21e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * budget-ci.c: driver for the SAA7146 based Budget DVB cards
3 *
4 * Compiled from various sources by Michael Hunold <michael@mihu.de>
5 *
6 * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
7 * partially based on the Siemens DVB driver by Ralph+Marcus Metzler
8 *
9 * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
27 *
28 *
29 * the project's page is at http://www.linuxtv.org/dvb/
30 */
31
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/module.h>
33#include <linux/errno.h>
34#include <linux/slab.h>
35#include <linux/interrupt.h>
36#include <linux/input.h>
37#include <linux/spinlock.h>
David Hardeman2520fff2006-12-02 21:16:05 -020038#include <media/ir-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Trent Piepho68277092007-01-30 23:25:46 -030040#include "budget.h"
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "dvb_ca_en50221.h"
43#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070044#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "tda1004x.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030046#include "lnbp21.h"
47#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030048#include "bsru6.h"
Sigmund Augdal11417da2008-06-15 17:25:46 -030049#include "tda1002x.h"
50#include "tda827x.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
David Härdemanecba77f2006-10-27 20:56:51 -030052/*
53 * Regarding DEBIADDR_IR:
54 * Some CI modules hang if random addresses are read.
55 * Using address 0x4000 for the IR read means that we
56 * use the same address as for CI version, which should
57 * be a safe default.
58 */
59#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define DEBIADDR_CICONTROL 0x0000
61#define DEBIADDR_CIVERSION 0x4000
62#define DEBIADDR_IO 0x1000
63#define DEBIADDR_ATTR 0x3000
64
65#define CICONTROL_RESET 0x01
66#define CICONTROL_ENABLETS 0x02
67#define CICONTROL_CAMDETECT 0x08
68
69#define DEBICICTL 0x00420000
70#define DEBICICAM 0x02420000
71
72#define SLOTSTATUS_NONE 1
73#define SLOTSTATUS_PRESENT 2
74#define SLOTSTATUS_RESET 4
75#define SLOTSTATUS_READY 8
76#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
77
David Härdeman145859c2007-04-27 12:31:22 -030078/*
79 * Milliseconds during which a key is regarded as pressed.
80 * If an identical command arrives within this time, the timer will start over.
David Hardeman2520fff2006-12-02 21:16:05 -020081 */
David Härdeman145859c2007-04-27 12:31:22 -030082#define IR_KEYPRESS_TIMEOUT 250
David Hardeman2520fff2006-12-02 21:16:05 -020083
David Hardeman64741b72006-12-02 21:16:05 -020084/* RC5 device wildcard */
85#define IR_DEVICE_ANY 255
86
David Hardeman64741b72006-12-02 21:16:05 -020087static int rc5_device = -1;
88module_param(rc5_device, int, 0644);
89MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
90
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030091static int ir_debug;
David Hardemanb5471a22006-12-02 21:16:05 -020092module_param(ir_debug, int, 0644);
93MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
94
Janne Grunau26dc4d02008-09-21 20:50:11 -030095DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
96
David Hardemandd2f3982006-12-02 21:16:05 -020097struct budget_ci_ir {
98 struct input_dev *dev;
99 struct tasklet_struct msp430_irq_tasklet;
David Härdeman145859c2007-04-27 12:31:22 -0300100 struct timer_list timer_keyup;
David Hardemandd2f3982006-12-02 21:16:05 -0200101 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -0200102 char phys[32];
David Hardeman2520fff2006-12-02 21:16:05 -0200103 struct ir_input_state state;
David Hardeman64741b72006-12-02 21:16:05 -0200104 int rc5_device;
David Härdeman145859c2007-04-27 12:31:22 -0300105 u32 last_raw;
106 u32 ir_key;
107 bool have_command;
David Hardemandd2f3982006-12-02 21:16:05 -0200108};
109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110struct budget_ci {
111 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 struct tasklet_struct ciintf_irq_tasklet;
113 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300114 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -0200116 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700117 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118};
119
David Hardeman2520fff2006-12-02 21:16:05 -0200120static void msp430_ir_keyup(unsigned long data)
121{
122 struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
123 ir_input_nokey(ir->dev, &ir->state);
124}
125
126static void msp430_ir_interrupt(unsigned long data)
127{
128 struct budget_ci *budget_ci = (struct budget_ci *) data;
129 struct input_dev *dev = budget_ci->ir.dev;
David Hardeman2520fff2006-12-02 21:16:05 -0200130 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
David Härdeman145859c2007-04-27 12:31:22 -0300131 u32 raw;
David Hardeman2520fff2006-12-02 21:16:05 -0200132
David Hardeman64741b72006-12-02 21:16:05 -0200133 /*
134 * The msp430 chip can generate two different bytes, command and device
135 *
136 * type1: X1CCCCCC, C = command bits (0 - 63)
137 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
138 *
David Härdeman59327a42007-02-13 09:39:58 -0300139 * Each signal from the remote control can generate one or more command
140 * bytes and one or more device bytes. For the repeated bytes, the
141 * highest bit (X) is set. The first command byte is always generated
142 * before the first device byte. Other than that, no specific order
David Härdeman145859c2007-04-27 12:31:22 -0300143 * seems to apply. To make life interesting, bytes can also be lost.
David Härdeman59327a42007-02-13 09:39:58 -0300144 *
145 * Only when we have a command and device byte, a keypress is
146 * generated.
David Hardeman64741b72006-12-02 21:16:05 -0200147 */
148
David Härdeman59327a42007-02-13 09:39:58 -0300149 if (ir_debug)
150 printk("budget_ci: received byte 0x%02x\n", command);
151
David Härdeman145859c2007-04-27 12:31:22 -0300152 /* Remove repeat bit, we use every command */
153 command = command & 0x7f;
David Härdeman59327a42007-02-13 09:39:58 -0300154
David Hardeman64741b72006-12-02 21:16:05 -0200155 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200156 if (command & 0x40) {
David Härdeman145859c2007-04-27 12:31:22 -0300157 budget_ci->ir.have_command = true;
158 budget_ci->ir.ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200159 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200160 }
David Hardeman64741b72006-12-02 21:16:05 -0200161
162 /* It's a RC5 device byte */
David Härdeman145859c2007-04-27 12:31:22 -0300163 if (!budget_ci->ir.have_command)
David Härdeman59327a42007-02-13 09:39:58 -0300164 return;
David Härdeman145859c2007-04-27 12:31:22 -0300165 budget_ci->ir.have_command = false;
David Hardeman64741b72006-12-02 21:16:05 -0200166
David Härdeman145859c2007-04-27 12:31:22 -0300167 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
168 budget_ci->ir.rc5_device != (command & 0x1f))
David Hardeman64741b72006-12-02 21:16:05 -0200169 return;
170
David Härdeman145859c2007-04-27 12:31:22 -0300171 /* Is this a repeated key sequence? (same device, command, toggle) */
172 raw = budget_ci->ir.ir_key | (command << 8);
173 if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) {
David Hardeman59236d42006-12-02 21:16:06 -0200174 ir_input_nokey(dev, &budget_ci->ir.state);
David Härdeman145859c2007-04-27 12:31:22 -0300175 ir_input_keydown(dev, &budget_ci->ir.state,
176 budget_ci->ir.ir_key, raw);
177 budget_ci->ir.last_raw = raw;
David Hardeman59236d42006-12-02 21:16:06 -0200178 }
David Härdeman145859c2007-04-27 12:31:22 -0300179
180 mod_timer(&budget_ci->ir.timer_keyup, jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT));
David Hardeman2520fff2006-12-02 21:16:05 -0200181}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183static int msp430_ir_init(struct budget_ci *budget_ci)
184{
185 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200186 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200187 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188
David Hardemandd2f3982006-12-02 21:16:05 -0200189 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200190 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200191 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200192 error = -ENOMEM;
193 goto out1;
194 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
David Hardemandd2f3982006-12-02 21:16:05 -0200196 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
197 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200198 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
199 "pci-%s/ir0", pci_name(saa->pci));
200
David Hardemandd2f3982006-12-02 21:16:05 -0200201 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202
David Hardeman5cc8ae02006-12-02 21:16:05 -0200203 input_dev->phys = budget_ci->ir.phys;
204 input_dev->id.bustype = BUS_PCI;
205 input_dev->id.version = 1;
206 if (saa->pci->subsystem_vendor) {
207 input_dev->id.vendor = saa->pci->subsystem_vendor;
208 input_dev->id.product = saa->pci->subsystem_device;
209 } else {
210 input_dev->id.vendor = saa->pci->vendor;
211 input_dev->id.product = saa->pci->device;
212 }
Dmitry Torokhov2c8a3a32007-07-16 09:28:15 -0300213 input_dev->dev.parent = &saa->pci->dev;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200214
David Hardeman64741b72006-12-02 21:16:05 -0200215 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200216 switch (budget_ci->budget.dev->pci->subsystem_device) {
217 case 0x100c:
218 case 0x100f:
David Hardeman2520fff2006-12-02 21:16:05 -0200219 case 0x1011:
220 case 0x1012:
David Hardeman2520fff2006-12-02 21:16:05 -0200221 /* The hauppauge keymap is a superset of these remotes */
222 ir_input_init(input_dev, &budget_ci->ir.state,
223 IR_TYPE_RC5, ir_codes_hauppauge_new);
David Hardeman64741b72006-12-02 21:16:05 -0200224
225 if (rc5_device < 0)
226 budget_ci->ir.rc5_device = 0x1f;
227 else
228 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200229 break;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300230 case 0x1010:
Oliver Endrissf64899c2007-09-17 22:17:12 -0300231 case 0x1017:
Oliver Endrissbbfc4c22008-06-19 23:36:45 -0300232 case 0x101a:
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300233 /* for the Technotrend 1500 bundled remote */
234 ir_input_init(input_dev, &budget_ci->ir.state,
235 IR_TYPE_RC5, ir_codes_tt_1500);
236
237 if (rc5_device < 0)
238 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
239 else
240 budget_ci->ir.rc5_device = rc5_device;
241 break;
David Hardeman2520fff2006-12-02 21:16:05 -0200242 default:
243 /* unknown remote */
244 ir_input_init(input_dev, &budget_ci->ir.state,
245 IR_TYPE_RC5, ir_codes_budget_ci_old);
David Hardeman64741b72006-12-02 21:16:05 -0200246
247 if (rc5_device < 0)
248 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
249 else
250 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200251 break;
252 }
253
David Härdeman145859c2007-04-27 12:31:22 -0300254 /* initialise the key-up timeout handler */
255 init_timer(&budget_ci->ir.timer_keyup);
256 budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
257 budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
258 budget_ci->ir.last_raw = 0xffff; /* An impossible value */
David Hardeman8cc532e2006-12-02 21:16:05 -0200259 error = input_register_device(input_dev);
260 if (error) {
261 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
262 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
David Härdeman145859c2007-04-27 12:31:22 -0300265 /* note: these must be after input_register_device */
266 input_dev->rep[REP_DELAY] = 400;
267 input_dev->rep[REP_PERIOD] = 250;
268
David Hardeman8cc532e2006-12-02 21:16:05 -0200269 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
270 (unsigned long) budget_ci);
271
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300272 SAA7146_IER_ENABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
274
275 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200276
277out2:
278 input_free_device(input_dev);
279out1:
280 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281}
282
283static void msp430_ir_deinit(struct budget_ci *budget_ci)
284{
285 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200286 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300288 SAA7146_IER_DISABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700289 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200290 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
David Härdeman145859c2007-04-27 12:31:22 -0300292 del_timer_sync(&dev->timer);
293 ir_input_nokey(dev, &budget_ci->ir.state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294
295 input_unregister_device(dev);
296}
297
298static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
299{
300 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
301
302 if (slot != 0)
303 return -EINVAL;
304
305 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
306 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
307}
308
309static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
310{
311 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
312
313 if (slot != 0)
314 return -EINVAL;
315
316 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
317 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
318}
319
320static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
321{
322 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
323
324 if (slot != 0)
325 return -EINVAL;
326
327 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
328 DEBIADDR_IO | (address & 3), 1, 1, 0);
329}
330
331static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
332{
333 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
334
335 if (slot != 0)
336 return -EINVAL;
337
338 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
339 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
340}
341
342static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
343{
344 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
345 struct saa7146_dev *saa = budget_ci->budget.dev;
346
347 if (slot != 0)
348 return -EINVAL;
349
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300350 if (budget_ci->ci_irq) {
351 // trigger on RISING edge during reset so we know when READY is re-asserted
352 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
353 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 budget_ci->slot_status = SLOTSTATUS_RESET;
355 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
356 msleep(1);
357 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
358 CICONTROL_RESET, 1, 0);
359
360 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
361 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
362 return 0;
363}
364
365static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
366{
367 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
368 struct saa7146_dev *saa = budget_ci->budget.dev;
369
370 if (slot != 0)
371 return -EINVAL;
372
373 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
374 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
375 return 0;
376}
377
378static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
379{
380 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
381 struct saa7146_dev *saa = budget_ci->budget.dev;
382 int tmp;
383
384 if (slot != 0)
385 return -EINVAL;
386
387 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
388
389 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
390 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
391 tmp | CICONTROL_ENABLETS, 1, 0);
392
393 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
394 return 0;
395}
396
397static void ciintf_interrupt(unsigned long data)
398{
399 struct budget_ci *budget_ci = (struct budget_ci *) data;
400 struct saa7146_dev *saa = budget_ci->budget.dev;
401 unsigned int flags;
402
403 // ensure we don't get spurious IRQs during initialisation
404 if (!budget_ci->budget.ci_present)
405 return;
406
407 // read the CAM status
408 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
409 if (flags & CICONTROL_CAMDETECT) {
410
411 // GPIO should be set to trigger on falling edge if a CAM is present
412 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
413
414 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
415 // CAM insertion IRQ
416 budget_ci->slot_status = SLOTSTATUS_PRESENT;
417 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
418 DVB_CA_EN50221_CAMCHANGE_INSERTED);
419
420 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
421 // CAM ready (reset completed)
422 budget_ci->slot_status = SLOTSTATUS_READY;
423 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
424
425 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
426 // FR/DA IRQ
427 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
428 }
429 } else {
430
431 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
432 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
433 // the CAM might not actually be ready yet.
434 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
435
436 // generate a CAM removal IRQ if we haven't already
437 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
438 // CAM removal IRQ
439 budget_ci->slot_status = SLOTSTATUS_NONE;
440 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
441 DVB_CA_EN50221_CAMCHANGE_REMOVED);
442 }
443 }
444}
445
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300446static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
447{
448 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
449 unsigned int flags;
450
451 // ensure we don't get spurious IRQs during initialisation
452 if (!budget_ci->budget.ci_present)
453 return -EINVAL;
454
455 // read the CAM status
456 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
457 if (flags & CICONTROL_CAMDETECT) {
458 // mark it as present if it wasn't before
459 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
460 budget_ci->slot_status = SLOTSTATUS_PRESENT;
461 }
462
463 // during a RESET, we check if we can read from IO memory to see when CAM is ready
464 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
465 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
466 budget_ci->slot_status = SLOTSTATUS_READY;
467 }
468 }
469 } else {
470 budget_ci->slot_status = SLOTSTATUS_NONE;
471 }
472
473 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
474 if (budget_ci->slot_status & SLOTSTATUS_READY) {
475 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
476 }
477 return DVB_CA_EN50221_POLL_CAM_PRESENT;
478 }
479
480 return 0;
481}
482
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483static int ciintf_init(struct budget_ci *budget_ci)
484{
485 struct saa7146_dev *saa = budget_ci->budget.dev;
486 int flags;
487 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300488 int ci_version;
489 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490
491 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
492
493 // enable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300494 saa7146_write(saa, MC1, MASK_27 | MASK_11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495
496 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300497 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
498 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 result = -ENODEV;
500 goto error;
501 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300502
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 // determine whether a CAM is present or not
504 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
505 budget_ci->slot_status = SLOTSTATUS_NONE;
506 if (flags & CICONTROL_CAMDETECT)
507 budget_ci->slot_status = SLOTSTATUS_PRESENT;
508
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300509 // version 0xa2 of the CI firmware doesn't generate interrupts
510 if (ci_version == 0xa2) {
511 ca_flags = 0;
512 budget_ci->ci_irq = 0;
513 } else {
514 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
515 DVB_CA_EN50221_FLAG_IRQ_FR |
516 DVB_CA_EN50221_FLAG_IRQ_DA;
517 budget_ci->ci_irq = 1;
518 }
519
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 // register CI interface
521 budget_ci->ca.owner = THIS_MODULE;
522 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
523 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
524 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
525 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
526 budget_ci->ca.slot_reset = ciintf_slot_reset;
527 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
528 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300529 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700531 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300533 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534 printk("budget_ci: CI interface detected, but initialisation failed.\n");
535 goto error;
536 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300537
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300539 if (budget_ci->ci_irq) {
540 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
541 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
542 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
543 } else {
544 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
545 }
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300546 SAA7146_IER_ENABLE(saa, MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300548
549 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
551 CICONTROL_RESET, 1, 0);
552
553 // success!
554 printk("budget_ci: CI interface initialised\n");
555 budget_ci->budget.ci_present = 1;
556
557 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300558 if (budget_ci->ci_irq) {
559 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
560 if (budget_ci->slot_status != SLOTSTATUS_NONE)
561 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
562 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
563 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564
565 return 0;
566
567error:
Hartmut Birr2a893de2006-12-03 21:08:08 -0300568 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 return result;
570}
571
572static void ciintf_deinit(struct budget_ci *budget_ci)
573{
574 struct saa7146_dev *saa = budget_ci->budget.dev;
575
576 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300577 if (budget_ci->ci_irq) {
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300578 SAA7146_IER_DISABLE(saa, MASK_03);
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300579 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
580 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
581 }
582
583 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
585 msleep(1);
586 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
587 CICONTROL_RESET, 1, 0);
588
589 // disable TS data stream to CI interface
590 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
591
592 // release the CA device
593 dvb_ca_en50221_release(&budget_ci->ca);
594
595 // disable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300596 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597}
598
599static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
600{
601 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
602
603 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
604
605 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200606 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 if (*isr & MASK_10)
609 ttpci_budget_irq10_handler(dev, isr);
610
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300611 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
613}
614
Linus Torvalds1da177e2005-04-16 15:20:36 -0700615static u8 philips_su1278_tt_inittab[] = {
616 0x01, 0x0f,
617 0x02, 0x30,
618 0x03, 0x00,
619 0x04, 0x5b,
620 0x05, 0x85,
621 0x06, 0x02,
622 0x07, 0x00,
623 0x08, 0x02,
624 0x09, 0x00,
625 0x0C, 0x01,
626 0x0D, 0x81,
627 0x0E, 0x44,
628 0x0f, 0x14,
629 0x10, 0x3c,
630 0x11, 0x84,
631 0x12, 0xda,
632 0x13, 0x97,
633 0x14, 0x95,
634 0x15, 0xc9,
635 0x16, 0x19,
636 0x17, 0x8c,
637 0x18, 0x59,
638 0x19, 0xf8,
639 0x1a, 0xfe,
640 0x1c, 0x7f,
641 0x1d, 0x00,
642 0x1e, 0x00,
643 0x1f, 0x50,
644 0x20, 0x00,
645 0x21, 0x00,
646 0x22, 0x00,
647 0x23, 0x00,
648 0x28, 0x00,
649 0x29, 0x28,
650 0x2a, 0x14,
651 0x2b, 0x0f,
652 0x2c, 0x09,
653 0x2d, 0x09,
654 0x31, 0x1f,
655 0x32, 0x19,
656 0x33, 0xfc,
657 0x34, 0x93,
658 0xff, 0xff
659};
660
661static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
662{
663 stv0299_writereg(fe, 0x0e, 0x44);
664 if (srate >= 10000000) {
665 stv0299_writereg(fe, 0x13, 0x97);
666 stv0299_writereg(fe, 0x14, 0x95);
667 stv0299_writereg(fe, 0x15, 0xc9);
668 stv0299_writereg(fe, 0x17, 0x8c);
669 stv0299_writereg(fe, 0x1a, 0xfe);
670 stv0299_writereg(fe, 0x1c, 0x7f);
671 stv0299_writereg(fe, 0x2d, 0x09);
672 } else {
673 stv0299_writereg(fe, 0x13, 0x99);
674 stv0299_writereg(fe, 0x14, 0x8d);
675 stv0299_writereg(fe, 0x15, 0xce);
676 stv0299_writereg(fe, 0x17, 0x43);
677 stv0299_writereg(fe, 0x1a, 0x1d);
678 stv0299_writereg(fe, 0x1c, 0x12);
679 stv0299_writereg(fe, 0x2d, 0x05);
680 }
681 stv0299_writereg(fe, 0x0e, 0x23);
682 stv0299_writereg(fe, 0x0f, 0x94);
683 stv0299_writereg(fe, 0x10, 0x39);
684 stv0299_writereg(fe, 0x15, 0xc9);
685
686 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
687 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
688 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
689
690 return 0;
691}
692
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300693static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
694 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300696 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 u32 div;
698 u8 buf[4];
699 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
700
701 if ((params->frequency < 950000) || (params->frequency > 2150000))
702 return -EINVAL;
703
704 div = (params->frequency + (500 - 1)) / 500; // round correctly
705 buf[0] = (div >> 8) & 0x7f;
706 buf[1] = div & 0xff;
707 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
708 buf[3] = 0x20;
709
710 if (params->u.qpsk.symbol_rate < 4000000)
711 buf[3] |= 1;
712
713 if (params->frequency < 1250000)
714 buf[3] |= 0;
715 else if (params->frequency < 1550000)
716 buf[3] |= 0x40;
717 else if (params->frequency < 2050000)
718 buf[3] |= 0x80;
719 else if (params->frequency < 2150000)
720 buf[3] |= 0xC0;
721
Patrick Boettcherdea74862006-05-14 05:01:31 -0300722 if (fe->ops.i2c_gate_ctrl)
723 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300724 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 return -EIO;
726 return 0;
727}
728
729static struct stv0299_config philips_su1278_tt_config = {
730
731 .demod_address = 0x68,
732 .inittab = philips_su1278_tt_inittab,
733 .mclk = 64000000UL,
734 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 .skip_reinit = 1,
Oliver Endrissda2c7f62008-04-20 22:13:37 -0300736 .lock_output = STV0299_LOCKOUTPUT_1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 .volt13_op0_op1 = STV0299_VOLT13_OP1,
738 .min_delay_ms = 50,
739 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740};
741
742
743
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300744static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745{
746 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
747 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
748 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700749 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 sizeof(td1316_init) };
751
752 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300753 if (fe->ops.i2c_gate_ctrl)
754 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700755 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
756 return -EIO;
757 msleep(1);
758
759 // disable the mc44BC374c (do not check for errors)
760 tuner_msg.addr = 0x65;
761 tuner_msg.buf = disable_mc44BC374c;
762 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300763 if (fe->ops.i2c_gate_ctrl)
764 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700765 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
Patrick Boettcherdea74862006-05-14 05:01:31 -0300766 if (fe->ops.i2c_gate_ctrl)
767 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
769 }
770
771 return 0;
772}
773
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300774static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775{
776 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
777 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700778 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 -0700779 int tuner_frequency = 0;
780 u8 band, cp, filter;
781
782 // determine charge pump
783 tuner_frequency = params->frequency + 36130000;
784 if (tuner_frequency < 87000000)
785 return -EINVAL;
786 else if (tuner_frequency < 130000000)
787 cp = 3;
788 else if (tuner_frequency < 160000000)
789 cp = 5;
790 else if (tuner_frequency < 200000000)
791 cp = 6;
792 else if (tuner_frequency < 290000000)
793 cp = 3;
794 else if (tuner_frequency < 420000000)
795 cp = 5;
796 else if (tuner_frequency < 480000000)
797 cp = 6;
798 else if (tuner_frequency < 620000000)
799 cp = 3;
800 else if (tuner_frequency < 830000000)
801 cp = 5;
802 else if (tuner_frequency < 895000000)
803 cp = 7;
804 else
805 return -EINVAL;
806
807 // determine band
808 if (params->frequency < 49000000)
809 return -EINVAL;
810 else if (params->frequency < 159000000)
811 band = 1;
812 else if (params->frequency < 444000000)
813 band = 2;
814 else if (params->frequency < 861000000)
815 band = 4;
816 else
817 return -EINVAL;
818
819 // setup PLL filter and TDA9889
820 switch (params->u.ofdm.bandwidth) {
821 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300822 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 filter = 0;
824 break;
825
826 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300827 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 filter = 0;
829 break;
830
831 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300832 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 filter = 1;
834 break;
835
836 default:
837 return -EINVAL;
838 }
839
840 // calculate divisor
841 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
842 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
843
844 // setup tuner buffer
845 tuner_buf[0] = tuner_frequency >> 8;
846 tuner_buf[1] = tuner_frequency & 0xff;
847 tuner_buf[2] = 0xca;
848 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
849
Patrick Boettcherdea74862006-05-14 05:01:31 -0300850 if (fe->ops.i2c_gate_ctrl)
851 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
853 return -EIO;
854
855 msleep(1);
856 return 0;
857}
858
859static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
860 const struct firmware **fw, char *name)
861{
862 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
863
864 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
865}
866
867static struct tda1004x_config philips_tdm1316l_config = {
868
869 .demod_address = 0x8,
870 .invert = 0,
871 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700872 .xtal_freq = TDA10046_XTAL_4M,
873 .agc_config = TDA10046_AGC_DEFAULT,
874 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 .request_firmware = philips_tdm1316l_request_firmware,
876};
877
Oliver Endriss6c914492007-02-02 19:12:53 -0300878static struct tda1004x_config philips_tdm1316l_config_invert = {
879
880 .demod_address = 0x8,
881 .invert = 1,
882 .invert_oclk = 0,
883 .xtal_freq = TDA10046_XTAL_4M,
884 .agc_config = TDA10046_AGC_DEFAULT,
885 .if_freq = TDA10046_FREQ_3617,
886 .request_firmware = philips_tdm1316l_request_firmware,
887};
888
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300889static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700890{
891 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
892 u8 tuner_buf[5];
893 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
894 .flags = 0,
895 .buf = tuner_buf,
896 .len = sizeof(tuner_buf) };
897 int tuner_frequency = 0;
898 u8 band, cp, filter;
899
900 // determine charge pump
901 tuner_frequency = params->frequency + 36125000;
902 if (tuner_frequency < 87000000)
903 return -EINVAL;
904 else if (tuner_frequency < 130000000) {
905 cp = 3;
906 band = 1;
907 } else if (tuner_frequency < 160000000) {
908 cp = 5;
909 band = 1;
910 } else if (tuner_frequency < 200000000) {
911 cp = 6;
Oliver Endriss910a7b62007-05-03 13:16:12 -0300912 band = 1;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700913 } else if (tuner_frequency < 290000000) {
914 cp = 3;
915 band = 2;
916 } else if (tuner_frequency < 420000000) {
917 cp = 5;
918 band = 2;
919 } else if (tuner_frequency < 480000000) {
920 cp = 6;
921 band = 2;
922 } else if (tuner_frequency < 620000000) {
923 cp = 3;
924 band = 4;
925 } else if (tuner_frequency < 830000000) {
926 cp = 5;
927 band = 4;
928 } else if (tuner_frequency < 895000000) {
929 cp = 7;
930 band = 4;
931 } else
932 return -EINVAL;
933
934 // assume PLL filter should always be 8MHz for the moment.
935 filter = 1;
936
937 // calculate divisor
938 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
939
940 // setup tuner buffer
941 tuner_buf[0] = tuner_frequency >> 8;
942 tuner_buf[1] = tuner_frequency & 0xff;
943 tuner_buf[2] = 0xc8;
944 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
945 tuner_buf[4] = 0x80;
946
Patrick Boettcherdea74862006-05-14 05:01:31 -0300947 if (fe->ops.i2c_gate_ctrl)
948 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700949 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
950 return -EIO;
951
952 msleep(50);
953
Patrick Boettcherdea74862006-05-14 05:01:31 -0300954 if (fe->ops.i2c_gate_ctrl)
955 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700956 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
957 return -EIO;
958
959 msleep(1);
960
961 return 0;
962}
963
964static u8 dvbc_philips_tdm1316l_inittab[] = {
965 0x80, 0x01,
966 0x80, 0x00,
967 0x81, 0x01,
968 0x81, 0x00,
969 0x00, 0x09,
970 0x01, 0x69,
971 0x03, 0x00,
972 0x04, 0x00,
973 0x07, 0x00,
974 0x08, 0x00,
975 0x20, 0x00,
976 0x21, 0x40,
977 0x22, 0x00,
978 0x23, 0x00,
979 0x24, 0x40,
980 0x25, 0x88,
981 0x30, 0xff,
982 0x31, 0x00,
983 0x32, 0xff,
984 0x33, 0x00,
985 0x34, 0x50,
986 0x35, 0x7f,
987 0x36, 0x00,
988 0x37, 0x20,
989 0x38, 0x00,
990 0x40, 0x1c,
991 0x41, 0xff,
992 0x42, 0x29,
993 0x43, 0x20,
994 0x44, 0xff,
995 0x45, 0x00,
996 0x46, 0x00,
997 0x49, 0x04,
998 0x4a, 0x00,
999 0x4b, 0x7b,
1000 0x52, 0x30,
1001 0x55, 0xae,
1002 0x56, 0x47,
1003 0x57, 0xe1,
1004 0x58, 0x3a,
1005 0x5a, 0x1e,
1006 0x5b, 0x34,
1007 0x60, 0x00,
1008 0x63, 0x00,
1009 0x64, 0x00,
1010 0x65, 0x00,
1011 0x66, 0x00,
1012 0x67, 0x00,
1013 0x68, 0x00,
1014 0x69, 0x00,
1015 0x6a, 0x02,
1016 0x6b, 0x00,
1017 0x70, 0xff,
1018 0x71, 0x00,
1019 0x72, 0x00,
1020 0x73, 0x00,
1021 0x74, 0x0c,
1022 0x80, 0x00,
1023 0x81, 0x00,
1024 0x82, 0x00,
1025 0x83, 0x00,
1026 0x84, 0x04,
1027 0x85, 0x80,
1028 0x86, 0x24,
1029 0x87, 0x78,
1030 0x88, 0x10,
1031 0x89, 0x00,
1032 0x90, 0x01,
1033 0x91, 0x01,
1034 0xa0, 0x04,
1035 0xa1, 0x00,
1036 0xa2, 0x00,
1037 0xb0, 0x91,
1038 0xb1, 0x0b,
1039 0xc0, 0x53,
1040 0xc1, 0x70,
1041 0xc2, 0x12,
1042 0xd0, 0x00,
1043 0xd1, 0x00,
1044 0xd2, 0x00,
1045 0xd3, 0x00,
1046 0xd4, 0x00,
1047 0xd5, 0x00,
1048 0xde, 0x00,
1049 0xdf, 0x00,
1050 0x61, 0x38,
1051 0x62, 0x0a,
1052 0x53, 0x13,
1053 0x59, 0x08,
1054 0xff, 0xff,
1055};
1056
1057static struct stv0297_config dvbc_philips_tdm1316l_config = {
1058 .demod_address = 0x1c,
1059 .inittab = dvbc_philips_tdm1316l_inittab,
1060 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001061 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001062};
1063
Sigmund Augdal11417da2008-06-15 17:25:46 -03001064static struct tda10023_config tda10023_config = {
1065 .demod_address = 0xc,
1066 .invert = 0,
1067 .xtal = 16000000,
1068 .pll_m = 11,
1069 .pll_p = 3,
1070 .pll_n = 1,
1071 .deltaf = 0xa511,
1072};
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
1075
1076static void frontend_init(struct budget_ci *budget_ci)
1077{
1078 switch (budget_ci->budget.dev->pci->subsystem_device) {
1079 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1080 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001081 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001083 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001084 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 break;
1086 }
1087 break;
1088
1089 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1090 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001091 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001093 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 break;
1095 }
1096 break;
1097
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001098 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1099 budget_ci->tuner_pll_address = 0x61;
1100 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001101 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001102 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001103 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001104 break;
1105 }
1106 break;
1107
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001109 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001111 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001113 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1114 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 break;
1116 }
1117 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001118
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001119 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001120 budget_ci->tuner_pll_address = 0x60;
1121 budget_ci->budget.dvb_frontend =
Oliver Endriss6c914492007-02-02 19:12:53 -03001122 dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001123 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001124 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1125 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001126 break;
1127 }
1128 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001129
1130 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001131 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001132 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001133 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001134 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1135
Patrick Boettcherdea74862006-05-14 05:01:31 -03001136 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001137 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 -03001138 printk("%s: No LNBP21 found!\n", __func__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001139 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001140 budget_ci->budget.dvb_frontend = NULL;
1141 }
1142 }
Sigmund Augdal11417da2008-06-15 17:25:46 -03001143 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001144
Sigmund Augdal11417da2008-06-15 17:25:46 -03001145 case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
1146 budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
1147 if (budget_ci->budget.dvb_frontend) {
1148 if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
1149 printk(KERN_ERR "%s: No tda827x found!\n", __func__);
1150 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1151 budget_ci->budget.dvb_frontend = NULL;
1152 }
1153 }
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001154 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155 }
1156
1157 if (budget_ci->budget.dvb_frontend == NULL) {
Bjorn Helgaas29e66a62008-09-04 17:24:51 -03001158 printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 budget_ci->budget.dev->pci->vendor,
1160 budget_ci->budget.dev->pci->device,
1161 budget_ci->budget.dev->pci->subsystem_vendor,
1162 budget_ci->budget.dev->pci->subsystem_device);
1163 } else {
1164 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001165 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001167 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001168 budget_ci->budget.dvb_frontend = NULL;
1169 }
1170 }
1171}
1172
1173static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1174{
1175 struct budget_ci *budget_ci;
1176 int err;
1177
David Hardemanee579bc2006-12-02 21:16:05 -02001178 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001179 if (!budget_ci) {
1180 err = -ENOMEM;
1181 goto out1;
1182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183
1184 dprintk(2, "budget_ci: %p\n", budget_ci);
1185
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 dev->ext_priv = budget_ci;
1187
Janne Grunau26dc4d02008-09-21 20:50:11 -03001188 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE,
1189 adapter_nr);
David Hardeman8cc532e2006-12-02 21:16:05 -02001190 if (err)
1191 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
David Hardeman8cc532e2006-12-02 21:16:05 -02001193 err = msp430_ir_init(budget_ci);
1194 if (err)
1195 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
1197 ciintf_init(budget_ci);
1198
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001199 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 frontend_init(budget_ci);
1201
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001202 ttpci_budget_init_hooks(&budget_ci->budget);
1203
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001205
1206out3:
1207 ttpci_budget_deinit(&budget_ci->budget);
1208out2:
1209 kfree(budget_ci);
1210out1:
1211 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001212}
1213
1214static int budget_ci_detach(struct saa7146_dev *dev)
1215{
1216 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1217 struct saa7146_dev *saa = budget_ci->budget.dev;
1218 int err;
1219
1220 if (budget_ci->budget.ci_present)
1221 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001222 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001223 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001225 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001226 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227 err = ttpci_budget_deinit(&budget_ci->budget);
1228
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229 // disable frontend and CI interface
1230 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1231
1232 kfree(budget_ci);
1233
1234 return err;
1235}
1236
1237static struct saa7146_extension budget_extension;
1238
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001239MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1241MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001242MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001243MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Sigmund Augdal11417da2008-06-15 17:25:46 -03001244MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
1246static struct pci_device_id pci_tbl[] = {
1247 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1248 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001249 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001251 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001252 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Sigmund Augdal11417da2008-06-15 17:25:46 -03001253 MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 {
1255 .vendor = 0,
1256 }
1257};
1258
1259MODULE_DEVICE_TABLE(pci, pci_tbl);
1260
1261static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001262 .name = "budget_ci dvb",
Oliver Endriss00c4cc62006-11-01 13:09:51 -03001263 .flags = SAA7146_USE_I2C_IRQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001264
1265 .module = THIS_MODULE,
1266 .pci_tbl = &pci_tbl[0],
1267 .attach = budget_ci_attach,
1268 .detach = budget_ci_detach,
1269
1270 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1271 .irq_func = budget_ci_irq,
1272};
1273
1274static int __init budget_ci_init(void)
1275{
1276 return saa7146_register_extension(&budget_extension);
1277}
1278
1279static void __exit budget_ci_exit(void)
1280{
1281 saa7146_unregister_extension(&budget_extension);
1282}
1283
1284module_init(budget_ci_init);
1285module_exit(budget_ci_exit);
1286
1287MODULE_LICENSE("GPL");
1288MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1289MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1290 "budget PCI DVB cards w/ CI-module produced by "
1291 "Siemens, Technotrend, Hauppauge");