blob: 374100316dc350c0627e3842fb29e6f6cb1bacb2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * budget-ci.c: driver for the SAA7146 based Budget DVB cards
3 *
4 * Compiled from various sources by Michael Hunold <michael@mihu.de>
5 *
6 * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM>
7 * partially based on the Siemens DVB driver by Ralph+Marcus Metzler
8 *
9 * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net>
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
27 *
28 *
29 * the project's page is at http://www.linuxtv.org/dvb/
30 */
31
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/module.h>
33#include <linux/errno.h>
34#include <linux/slab.h>
35#include <linux/interrupt.h>
36#include <linux/input.h>
37#include <linux/spinlock.h>
David Hardeman2520fff2006-12-02 21:16:05 -020038#include <media/ir-common.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Trent Piepho68277092007-01-30 23:25:46 -030040#include "budget.h"
41
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include "dvb_ca_en50221.h"
43#include "stv0299.h"
Andrew de Quinceydc27a162005-09-09 13:03:07 -070044#include "stv0297.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include "tda1004x.h"
Perceval Anichini8cc2e372006-02-28 09:52:44 -030046#include "lnbp21.h"
47#include "bsbe1.h"
Perceval Anichini265366e2006-03-16 11:22:47 -030048#include "bsru6.h"
Sigmund Augdal11417da2008-06-15 17:25:46 -030049#include "tda1002x.h"
50#include "tda827x.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
David Härdemanecba77f2006-10-27 20:56:51 -030052/*
53 * Regarding DEBIADDR_IR:
54 * Some CI modules hang if random addresses are read.
55 * Using address 0x4000 for the IR read means that we
56 * use the same address as for CI version, which should
57 * be a safe default.
58 */
59#define DEBIADDR_IR 0x4000
Linus Torvalds1da177e2005-04-16 15:20:36 -070060#define DEBIADDR_CICONTROL 0x0000
61#define DEBIADDR_CIVERSION 0x4000
62#define DEBIADDR_IO 0x1000
63#define DEBIADDR_ATTR 0x3000
64
65#define CICONTROL_RESET 0x01
66#define CICONTROL_ENABLETS 0x02
67#define CICONTROL_CAMDETECT 0x08
68
69#define DEBICICTL 0x00420000
70#define DEBICICAM 0x02420000
71
72#define SLOTSTATUS_NONE 1
73#define SLOTSTATUS_PRESENT 2
74#define SLOTSTATUS_RESET 4
75#define SLOTSTATUS_READY 8
76#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
77
David Härdeman145859c2007-04-27 12:31:22 -030078/*
79 * Milliseconds during which a key is regarded as pressed.
80 * If an identical command arrives within this time, the timer will start over.
David Hardeman2520fff2006-12-02 21:16:05 -020081 */
David Härdeman145859c2007-04-27 12:31:22 -030082#define IR_KEYPRESS_TIMEOUT 250
David Hardeman2520fff2006-12-02 21:16:05 -020083
David Hardeman64741b72006-12-02 21:16:05 -020084/* RC5 device wildcard */
85#define IR_DEVICE_ANY 255
86
David Hardeman64741b72006-12-02 21:16:05 -020087static int rc5_device = -1;
88module_param(rc5_device, int, 0644);
89MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
90
Douglas Schilling Landgrafff699e62008-04-22 14:41:48 -030091static int ir_debug;
David Hardemanb5471a22006-12-02 21:16:05 -020092module_param(ir_debug, int, 0644);
93MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
94
David Hardemandd2f3982006-12-02 21:16:05 -020095struct budget_ci_ir {
96 struct input_dev *dev;
97 struct tasklet_struct msp430_irq_tasklet;
David Härdeman145859c2007-04-27 12:31:22 -030098 struct timer_list timer_keyup;
David Hardemandd2f3982006-12-02 21:16:05 -020099 char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
David Hardeman5cc8ae02006-12-02 21:16:05 -0200100 char phys[32];
David Hardeman2520fff2006-12-02 21:16:05 -0200101 struct ir_input_state state;
David Hardeman64741b72006-12-02 21:16:05 -0200102 int rc5_device;
David Härdeman145859c2007-04-27 12:31:22 -0300103 u32 last_raw;
104 u32 ir_key;
105 bool have_command;
David Hardemandd2f3982006-12-02 21:16:05 -0200106};
107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108struct budget_ci {
109 struct budget budget;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110 struct tasklet_struct ciintf_irq_tasklet;
111 int slot_status;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300112 int ci_irq;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 struct dvb_ca_en50221 ca;
David Hardemandd2f3982006-12-02 21:16:05 -0200114 struct budget_ci_ir ir;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700115 u8 tuner_pll_address; /* used for philips_tdm1316l configs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116};
117
David Hardeman2520fff2006-12-02 21:16:05 -0200118static void msp430_ir_keyup(unsigned long data)
119{
120 struct budget_ci_ir *ir = (struct budget_ci_ir *) data;
121 ir_input_nokey(ir->dev, &ir->state);
122}
123
124static void msp430_ir_interrupt(unsigned long data)
125{
126 struct budget_ci *budget_ci = (struct budget_ci *) data;
127 struct input_dev *dev = budget_ci->ir.dev;
David Hardeman2520fff2006-12-02 21:16:05 -0200128 u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
David Härdeman145859c2007-04-27 12:31:22 -0300129 u32 raw;
David Hardeman2520fff2006-12-02 21:16:05 -0200130
David Hardeman64741b72006-12-02 21:16:05 -0200131 /*
132 * The msp430 chip can generate two different bytes, command and device
133 *
134 * type1: X1CCCCCC, C = command bits (0 - 63)
135 * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
136 *
David Härdeman59327a42007-02-13 09:39:58 -0300137 * Each signal from the remote control can generate one or more command
138 * bytes and one or more device bytes. For the repeated bytes, the
139 * highest bit (X) is set. The first command byte is always generated
140 * before the first device byte. Other than that, no specific order
David Härdeman145859c2007-04-27 12:31:22 -0300141 * seems to apply. To make life interesting, bytes can also be lost.
David Härdeman59327a42007-02-13 09:39:58 -0300142 *
143 * Only when we have a command and device byte, a keypress is
144 * generated.
David Hardeman64741b72006-12-02 21:16:05 -0200145 */
146
David Härdeman59327a42007-02-13 09:39:58 -0300147 if (ir_debug)
148 printk("budget_ci: received byte 0x%02x\n", command);
149
David Härdeman145859c2007-04-27 12:31:22 -0300150 /* Remove repeat bit, we use every command */
151 command = command & 0x7f;
David Härdeman59327a42007-02-13 09:39:58 -0300152
David Hardeman64741b72006-12-02 21:16:05 -0200153 /* Is this a RC5 command byte? */
David Hardeman2520fff2006-12-02 21:16:05 -0200154 if (command & 0x40) {
David Härdeman145859c2007-04-27 12:31:22 -0300155 budget_ci->ir.have_command = true;
156 budget_ci->ir.ir_key = command & 0x3f;
David Hardeman64741b72006-12-02 21:16:05 -0200157 return;
David Hardeman2520fff2006-12-02 21:16:05 -0200158 }
David Hardeman64741b72006-12-02 21:16:05 -0200159
160 /* It's a RC5 device byte */
David Härdeman145859c2007-04-27 12:31:22 -0300161 if (!budget_ci->ir.have_command)
David Härdeman59327a42007-02-13 09:39:58 -0300162 return;
David Härdeman145859c2007-04-27 12:31:22 -0300163 budget_ci->ir.have_command = false;
David Hardeman64741b72006-12-02 21:16:05 -0200164
David Härdeman145859c2007-04-27 12:31:22 -0300165 if (budget_ci->ir.rc5_device != IR_DEVICE_ANY &&
166 budget_ci->ir.rc5_device != (command & 0x1f))
David Hardeman64741b72006-12-02 21:16:05 -0200167 return;
168
David Härdeman145859c2007-04-27 12:31:22 -0300169 /* Is this a repeated key sequence? (same device, command, toggle) */
170 raw = budget_ci->ir.ir_key | (command << 8);
171 if (budget_ci->ir.last_raw != raw || !timer_pending(&budget_ci->ir.timer_keyup)) {
David Hardeman59236d42006-12-02 21:16:06 -0200172 ir_input_nokey(dev, &budget_ci->ir.state);
David Härdeman145859c2007-04-27 12:31:22 -0300173 ir_input_keydown(dev, &budget_ci->ir.state,
174 budget_ci->ir.ir_key, raw);
175 budget_ci->ir.last_raw = raw;
David Hardeman59236d42006-12-02 21:16:06 -0200176 }
David Härdeman145859c2007-04-27 12:31:22 -0300177
178 mod_timer(&budget_ci->ir.timer_keyup, jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT));
David Hardeman2520fff2006-12-02 21:16:05 -0200179}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181static int msp430_ir_init(struct budget_ci *budget_ci)
182{
183 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200184 struct input_dev *input_dev = budget_ci->ir.dev;
David Hardeman8cc532e2006-12-02 21:16:05 -0200185 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186
David Hardemandd2f3982006-12-02 21:16:05 -0200187 budget_ci->ir.dev = input_dev = input_allocate_device();
David Hardeman8cc532e2006-12-02 21:16:05 -0200188 if (!input_dev) {
David Hardemanee579bc2006-12-02 21:16:05 -0200189 printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
David Hardeman8cc532e2006-12-02 21:16:05 -0200190 error = -ENOMEM;
191 goto out1;
192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193
David Hardemandd2f3982006-12-02 21:16:05 -0200194 snprintf(budget_ci->ir.name, sizeof(budget_ci->ir.name),
195 "Budget-CI dvb ir receiver %s", saa->name);
David Hardeman5cc8ae02006-12-02 21:16:05 -0200196 snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
197 "pci-%s/ir0", pci_name(saa->pci));
198
David Hardemandd2f3982006-12-02 21:16:05 -0200199 input_dev->name = budget_ci->ir.name;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
David Hardeman5cc8ae02006-12-02 21:16:05 -0200201 input_dev->phys = budget_ci->ir.phys;
202 input_dev->id.bustype = BUS_PCI;
203 input_dev->id.version = 1;
204 if (saa->pci->subsystem_vendor) {
205 input_dev->id.vendor = saa->pci->subsystem_vendor;
206 input_dev->id.product = saa->pci->subsystem_device;
207 } else {
208 input_dev->id.vendor = saa->pci->vendor;
209 input_dev->id.product = saa->pci->device;
210 }
Dmitry Torokhov2c8a3a32007-07-16 09:28:15 -0300211 input_dev->dev.parent = &saa->pci->dev;
David Hardeman5cc8ae02006-12-02 21:16:05 -0200212
David Hardeman64741b72006-12-02 21:16:05 -0200213 /* Select keymap and address */
David Hardeman2520fff2006-12-02 21:16:05 -0200214 switch (budget_ci->budget.dev->pci->subsystem_device) {
215 case 0x100c:
216 case 0x100f:
David Hardeman2520fff2006-12-02 21:16:05 -0200217 case 0x1011:
218 case 0x1012:
David Hardeman2520fff2006-12-02 21:16:05 -0200219 /* The hauppauge keymap is a superset of these remotes */
220 ir_input_init(input_dev, &budget_ci->ir.state,
221 IR_TYPE_RC5, ir_codes_hauppauge_new);
David Hardeman64741b72006-12-02 21:16:05 -0200222
223 if (rc5_device < 0)
224 budget_ci->ir.rc5_device = 0x1f;
225 else
226 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200227 break;
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300228 case 0x1010:
Oliver Endrissf64899c2007-09-17 22:17:12 -0300229 case 0x1017:
Ville-Pekka Vainioae1942c2007-01-12 14:06:21 -0300230 /* for the Technotrend 1500 bundled remote */
231 ir_input_init(input_dev, &budget_ci->ir.state,
232 IR_TYPE_RC5, ir_codes_tt_1500);
233
234 if (rc5_device < 0)
235 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
236 else
237 budget_ci->ir.rc5_device = rc5_device;
238 break;
David Hardeman2520fff2006-12-02 21:16:05 -0200239 default:
240 /* unknown remote */
241 ir_input_init(input_dev, &budget_ci->ir.state,
242 IR_TYPE_RC5, ir_codes_budget_ci_old);
David Hardeman64741b72006-12-02 21:16:05 -0200243
244 if (rc5_device < 0)
245 budget_ci->ir.rc5_device = IR_DEVICE_ANY;
246 else
247 budget_ci->ir.rc5_device = rc5_device;
David Hardeman2520fff2006-12-02 21:16:05 -0200248 break;
249 }
250
David Härdeman145859c2007-04-27 12:31:22 -0300251 /* initialise the key-up timeout handler */
252 init_timer(&budget_ci->ir.timer_keyup);
253 budget_ci->ir.timer_keyup.function = msp430_ir_keyup;
254 budget_ci->ir.timer_keyup.data = (unsigned long) &budget_ci->ir;
255 budget_ci->ir.last_raw = 0xffff; /* An impossible value */
David Hardeman8cc532e2006-12-02 21:16:05 -0200256 error = input_register_device(input_dev);
257 if (error) {
258 printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
259 goto out2;
Dmitry Torokhovb07b4782006-11-20 10:23:04 -0300260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
David Härdeman145859c2007-04-27 12:31:22 -0300262 /* note: these must be after input_register_device */
263 input_dev->rep[REP_DELAY] = 400;
264 input_dev->rep[REP_PERIOD] = 250;
265
David Hardeman8cc532e2006-12-02 21:16:05 -0200266 tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
267 (unsigned long) budget_ci);
268
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300269 SAA7146_IER_ENABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
271
272 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -0200273
274out2:
275 input_free_device(input_dev);
276out1:
277 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278}
279
280static void msp430_ir_deinit(struct budget_ci *budget_ci)
281{
282 struct saa7146_dev *saa = budget_ci->budget.dev;
David Hardemandd2f3982006-12-02 21:16:05 -0200283 struct input_dev *dev = budget_ci->ir.dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700284
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300285 SAA7146_IER_DISABLE(saa, MASK_06);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286 saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
David Hardeman8cc532e2006-12-02 21:16:05 -0200287 tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288
David Härdeman145859c2007-04-27 12:31:22 -0300289 del_timer_sync(&dev->timer);
290 ir_input_nokey(dev, &budget_ci->ir.state);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291
292 input_unregister_device(dev);
293}
294
295static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
296{
297 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
298
299 if (slot != 0)
300 return -EINVAL;
301
302 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
303 DEBIADDR_ATTR | (address & 0xfff), 1, 1, 0);
304}
305
306static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value)
307{
308 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
309
310 if (slot != 0)
311 return -EINVAL;
312
313 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
314 DEBIADDR_ATTR | (address & 0xfff), 1, value, 1, 0);
315}
316
317static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address)
318{
319 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
320
321 if (slot != 0)
322 return -EINVAL;
323
324 return ttpci_budget_debiread(&budget_ci->budget, DEBICICAM,
325 DEBIADDR_IO | (address & 3), 1, 1, 0);
326}
327
328static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value)
329{
330 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
331
332 if (slot != 0)
333 return -EINVAL;
334
335 return ttpci_budget_debiwrite(&budget_ci->budget, DEBICICAM,
336 DEBIADDR_IO | (address & 3), 1, value, 1, 0);
337}
338
339static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
340{
341 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
342 struct saa7146_dev *saa = budget_ci->budget.dev;
343
344 if (slot != 0)
345 return -EINVAL;
346
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300347 if (budget_ci->ci_irq) {
348 // trigger on RISING edge during reset so we know when READY is re-asserted
349 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
350 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351 budget_ci->slot_status = SLOTSTATUS_RESET;
352 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
353 msleep(1);
354 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
355 CICONTROL_RESET, 1, 0);
356
357 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
358 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
359 return 0;
360}
361
362static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
363{
364 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
365 struct saa7146_dev *saa = budget_ci->budget.dev;
366
367 if (slot != 0)
368 return -EINVAL;
369
370 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTHI);
371 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
372 return 0;
373}
374
375static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
376{
377 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
378 struct saa7146_dev *saa = budget_ci->budget.dev;
379 int tmp;
380
381 if (slot != 0)
382 return -EINVAL;
383
384 saa7146_setgpio(saa, 1, SAA7146_GPIO_OUTLO);
385
386 tmp = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
387 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
388 tmp | CICONTROL_ENABLETS, 1, 0);
389
390 ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
391 return 0;
392}
393
394static void ciintf_interrupt(unsigned long data)
395{
396 struct budget_ci *budget_ci = (struct budget_ci *) data;
397 struct saa7146_dev *saa = budget_ci->budget.dev;
398 unsigned int flags;
399
400 // ensure we don't get spurious IRQs during initialisation
401 if (!budget_ci->budget.ci_present)
402 return;
403
404 // read the CAM status
405 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
406 if (flags & CICONTROL_CAMDETECT) {
407
408 // GPIO should be set to trigger on falling edge if a CAM is present
409 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
410
411 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
412 // CAM insertion IRQ
413 budget_ci->slot_status = SLOTSTATUS_PRESENT;
414 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
415 DVB_CA_EN50221_CAMCHANGE_INSERTED);
416
417 } else if (budget_ci->slot_status & SLOTSTATUS_RESET) {
418 // CAM ready (reset completed)
419 budget_ci->slot_status = SLOTSTATUS_READY;
420 dvb_ca_en50221_camready_irq(&budget_ci->ca, 0);
421
422 } else if (budget_ci->slot_status & SLOTSTATUS_READY) {
423 // FR/DA IRQ
424 dvb_ca_en50221_frda_irq(&budget_ci->ca, 0);
425 }
426 } else {
427
428 // trigger on rising edge if a CAM is not present - when a CAM is inserted, we
429 // only want to get the IRQ when it sets READY. If we trigger on the falling edge,
430 // the CAM might not actually be ready yet.
431 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
432
433 // generate a CAM removal IRQ if we haven't already
434 if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) {
435 // CAM removal IRQ
436 budget_ci->slot_status = SLOTSTATUS_NONE;
437 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0,
438 DVB_CA_EN50221_CAMCHANGE_REMOVED);
439 }
440 }
441}
442
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300443static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open)
444{
445 struct budget_ci *budget_ci = (struct budget_ci *) ca->data;
446 unsigned int flags;
447
448 // ensure we don't get spurious IRQs during initialisation
449 if (!budget_ci->budget.ci_present)
450 return -EINVAL;
451
452 // read the CAM status
453 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
454 if (flags & CICONTROL_CAMDETECT) {
455 // mark it as present if it wasn't before
456 if (budget_ci->slot_status & SLOTSTATUS_NONE) {
457 budget_ci->slot_status = SLOTSTATUS_PRESENT;
458 }
459
460 // during a RESET, we check if we can read from IO memory to see when CAM is ready
461 if (budget_ci->slot_status & SLOTSTATUS_RESET) {
462 if (ciintf_read_attribute_mem(ca, slot, 0) == 0x1d) {
463 budget_ci->slot_status = SLOTSTATUS_READY;
464 }
465 }
466 } else {
467 budget_ci->slot_status = SLOTSTATUS_NONE;
468 }
469
470 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
471 if (budget_ci->slot_status & SLOTSTATUS_READY) {
472 return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
473 }
474 return DVB_CA_EN50221_POLL_CAM_PRESENT;
475 }
476
477 return 0;
478}
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480static int ciintf_init(struct budget_ci *budget_ci)
481{
482 struct saa7146_dev *saa = budget_ci->budget.dev;
483 int flags;
484 int result;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300485 int ci_version;
486 int ca_flags;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487
488 memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221));
489
490 // enable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300491 saa7146_write(saa, MC1, MASK_27 | MASK_11);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493 // test if it is there
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300494 ci_version = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, 1, 1, 0);
495 if ((ci_version & 0xa0) != 0xa0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 result = -ENODEV;
497 goto error;
498 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300499
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 // determine whether a CAM is present or not
501 flags = ttpci_budget_debiread(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 1, 0);
502 budget_ci->slot_status = SLOTSTATUS_NONE;
503 if (flags & CICONTROL_CAMDETECT)
504 budget_ci->slot_status = SLOTSTATUS_PRESENT;
505
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300506 // version 0xa2 of the CI firmware doesn't generate interrupts
507 if (ci_version == 0xa2) {
508 ca_flags = 0;
509 budget_ci->ci_irq = 0;
510 } else {
511 ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE |
512 DVB_CA_EN50221_FLAG_IRQ_FR |
513 DVB_CA_EN50221_FLAG_IRQ_DA;
514 budget_ci->ci_irq = 1;
515 }
516
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517 // register CI interface
518 budget_ci->ca.owner = THIS_MODULE;
519 budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem;
520 budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem;
521 budget_ci->ca.read_cam_control = ciintf_read_cam_control;
522 budget_ci->ca.write_cam_control = ciintf_write_cam_control;
523 budget_ci->ca.slot_reset = ciintf_slot_reset;
524 budget_ci->ca.slot_shutdown = ciintf_slot_shutdown;
525 budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable;
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300526 budget_ci->ca.poll_slot_status = ciintf_poll_slot_status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 budget_ci->ca.data = budget_ci;
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -0700528 if ((result = dvb_ca_en50221_init(&budget_ci->budget.dvb_adapter,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 &budget_ci->ca,
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300530 ca_flags, 1)) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 printk("budget_ci: CI interface detected, but initialisation failed.\n");
532 goto error;
533 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300534
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 // Setup CI slot IRQ
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300536 if (budget_ci->ci_irq) {
537 tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
538 if (budget_ci->slot_status != SLOTSTATUS_NONE) {
539 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
540 } else {
541 saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQHI);
542 }
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300543 SAA7146_IER_ENABLE(saa, MASK_03);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 }
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300545
546 // enable interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
548 CICONTROL_RESET, 1, 0);
549
550 // success!
551 printk("budget_ci: CI interface initialised\n");
552 budget_ci->budget.ci_present = 1;
553
554 // forge a fake CI IRQ so the CAM state is setup correctly
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300555 if (budget_ci->ci_irq) {
556 flags = DVB_CA_EN50221_CAMCHANGE_REMOVED;
557 if (budget_ci->slot_status != SLOTSTATUS_NONE)
558 flags = DVB_CA_EN50221_CAMCHANGE_INSERTED;
559 dvb_ca_en50221_camchange_irq(&budget_ci->ca, 0, flags);
560 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 return 0;
563
564error:
Hartmut Birr2a893de2006-12-03 21:08:08 -0300565 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566 return result;
567}
568
569static void ciintf_deinit(struct budget_ci *budget_ci)
570{
571 struct saa7146_dev *saa = budget_ci->budget.dev;
572
573 // disable CI interrupts
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300574 if (budget_ci->ci_irq) {
Hartmut Birr97a2cf02006-12-03 10:49:47 -0300575 SAA7146_IER_DISABLE(saa, MASK_03);
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300576 saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
577 tasklet_kill(&budget_ci->ciintf_irq_tasklet);
578 }
579
580 // reset interface
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1, 0, 1, 0);
582 msleep(1);
583 ttpci_budget_debiwrite(&budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, 1,
584 CICONTROL_RESET, 1, 0);
585
586 // disable TS data stream to CI interface
587 saa7146_setgpio(saa, 1, SAA7146_GPIO_INPUT);
588
589 // release the CA device
590 dvb_ca_en50221_release(&budget_ci->ca);
591
592 // disable DEBI pins
Hartmut Birr2a893de2006-12-03 21:08:08 -0300593 saa7146_write(saa, MC1, MASK_27);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594}
595
596static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr)
597{
598 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
599
600 dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
601
602 if (*isr & MASK_06)
David Hardemandd2f3982006-12-02 21:16:05 -0200603 tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
605 if (*isr & MASK_10)
606 ttpci_budget_irq10_handler(dev, isr);
607
Andrew de Quincey96b194c2006-04-05 14:09:45 -0300608 if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
610}
611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612static u8 philips_su1278_tt_inittab[] = {
613 0x01, 0x0f,
614 0x02, 0x30,
615 0x03, 0x00,
616 0x04, 0x5b,
617 0x05, 0x85,
618 0x06, 0x02,
619 0x07, 0x00,
620 0x08, 0x02,
621 0x09, 0x00,
622 0x0C, 0x01,
623 0x0D, 0x81,
624 0x0E, 0x44,
625 0x0f, 0x14,
626 0x10, 0x3c,
627 0x11, 0x84,
628 0x12, 0xda,
629 0x13, 0x97,
630 0x14, 0x95,
631 0x15, 0xc9,
632 0x16, 0x19,
633 0x17, 0x8c,
634 0x18, 0x59,
635 0x19, 0xf8,
636 0x1a, 0xfe,
637 0x1c, 0x7f,
638 0x1d, 0x00,
639 0x1e, 0x00,
640 0x1f, 0x50,
641 0x20, 0x00,
642 0x21, 0x00,
643 0x22, 0x00,
644 0x23, 0x00,
645 0x28, 0x00,
646 0x29, 0x28,
647 0x2a, 0x14,
648 0x2b, 0x0f,
649 0x2c, 0x09,
650 0x2d, 0x09,
651 0x31, 0x1f,
652 0x32, 0x19,
653 0x33, 0xfc,
654 0x34, 0x93,
655 0xff, 0xff
656};
657
658static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio)
659{
660 stv0299_writereg(fe, 0x0e, 0x44);
661 if (srate >= 10000000) {
662 stv0299_writereg(fe, 0x13, 0x97);
663 stv0299_writereg(fe, 0x14, 0x95);
664 stv0299_writereg(fe, 0x15, 0xc9);
665 stv0299_writereg(fe, 0x17, 0x8c);
666 stv0299_writereg(fe, 0x1a, 0xfe);
667 stv0299_writereg(fe, 0x1c, 0x7f);
668 stv0299_writereg(fe, 0x2d, 0x09);
669 } else {
670 stv0299_writereg(fe, 0x13, 0x99);
671 stv0299_writereg(fe, 0x14, 0x8d);
672 stv0299_writereg(fe, 0x15, 0xce);
673 stv0299_writereg(fe, 0x17, 0x43);
674 stv0299_writereg(fe, 0x1a, 0x1d);
675 stv0299_writereg(fe, 0x1c, 0x12);
676 stv0299_writereg(fe, 0x2d, 0x05);
677 }
678 stv0299_writereg(fe, 0x0e, 0x23);
679 stv0299_writereg(fe, 0x0f, 0x94);
680 stv0299_writereg(fe, 0x10, 0x39);
681 stv0299_writereg(fe, 0x15, 0xc9);
682
683 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
684 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
685 stv0299_writereg(fe, 0x21, (ratio) & 0xf0);
686
687 return 0;
688}
689
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300690static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
691 struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692{
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300693 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 u32 div;
695 u8 buf[4];
696 struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
697
698 if ((params->frequency < 950000) || (params->frequency > 2150000))
699 return -EINVAL;
700
701 div = (params->frequency + (500 - 1)) / 500; // round correctly
702 buf[0] = (div >> 8) & 0x7f;
703 buf[1] = div & 0xff;
704 buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2;
705 buf[3] = 0x20;
706
707 if (params->u.qpsk.symbol_rate < 4000000)
708 buf[3] |= 1;
709
710 if (params->frequency < 1250000)
711 buf[3] |= 0;
712 else if (params->frequency < 1550000)
713 buf[3] |= 0x40;
714 else if (params->frequency < 2050000)
715 buf[3] |= 0x80;
716 else if (params->frequency < 2150000)
717 buf[3] |= 0xC0;
718
Patrick Boettcherdea74862006-05-14 05:01:31 -0300719 if (fe->ops.i2c_gate_ctrl)
720 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300721 if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return -EIO;
723 return 0;
724}
725
726static struct stv0299_config philips_su1278_tt_config = {
727
728 .demod_address = 0x68,
729 .inittab = philips_su1278_tt_inittab,
730 .mclk = 64000000UL,
731 .invert = 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 .skip_reinit = 1,
Oliver Endrissda2c7f62008-04-20 22:13:37 -0300733 .lock_output = STV0299_LOCKOUTPUT_1,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 .volt13_op0_op1 = STV0299_VOLT13_OP1,
735 .min_delay_ms = 50,
736 .set_symbol_rate = philips_su1278_tt_set_symbol_rate,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737};
738
739
740
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300741static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742{
743 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
744 static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
745 static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700746 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 sizeof(td1316_init) };
748
749 // setup PLL configuration
Patrick Boettcherdea74862006-05-14 05:01:31 -0300750 if (fe->ops.i2c_gate_ctrl)
751 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
753 return -EIO;
754 msleep(1);
755
756 // disable the mc44BC374c (do not check for errors)
757 tuner_msg.addr = 0x65;
758 tuner_msg.buf = disable_mc44BC374c;
759 tuner_msg.len = sizeof(disable_mc44BC374c);
Patrick Boettcherdea74862006-05-14 05:01:31 -0300760 if (fe->ops.i2c_gate_ctrl)
761 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
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 i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
766 }
767
768 return 0;
769}
770
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300771static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772{
773 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
774 u8 tuner_buf[4];
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -0700775 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 -0700776 int tuner_frequency = 0;
777 u8 band, cp, filter;
778
779 // determine charge pump
780 tuner_frequency = params->frequency + 36130000;
781 if (tuner_frequency < 87000000)
782 return -EINVAL;
783 else if (tuner_frequency < 130000000)
784 cp = 3;
785 else if (tuner_frequency < 160000000)
786 cp = 5;
787 else if (tuner_frequency < 200000000)
788 cp = 6;
789 else if (tuner_frequency < 290000000)
790 cp = 3;
791 else if (tuner_frequency < 420000000)
792 cp = 5;
793 else if (tuner_frequency < 480000000)
794 cp = 6;
795 else if (tuner_frequency < 620000000)
796 cp = 3;
797 else if (tuner_frequency < 830000000)
798 cp = 5;
799 else if (tuner_frequency < 895000000)
800 cp = 7;
801 else
802 return -EINVAL;
803
804 // determine band
805 if (params->frequency < 49000000)
806 return -EINVAL;
807 else if (params->frequency < 159000000)
808 band = 1;
809 else if (params->frequency < 444000000)
810 band = 2;
811 else if (params->frequency < 861000000)
812 band = 4;
813 else
814 return -EINVAL;
815
816 // setup PLL filter and TDA9889
817 switch (params->u.ofdm.bandwidth) {
818 case BANDWIDTH_6_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300819 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820 filter = 0;
821 break;
822
823 case BANDWIDTH_7_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300824 tda1004x_writereg(fe, 0x0C, 0x80);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 filter = 0;
826 break;
827
828 case BANDWIDTH_8_MHZ:
Andrew de Quinceyc10d14d2006-08-08 09:10:08 -0300829 tda1004x_writereg(fe, 0x0C, 0x14);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830 filter = 1;
831 break;
832
833 default:
834 return -EINVAL;
835 }
836
837 // calculate divisor
838 // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
839 tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
840
841 // setup tuner buffer
842 tuner_buf[0] = tuner_frequency >> 8;
843 tuner_buf[1] = tuner_frequency & 0xff;
844 tuner_buf[2] = 0xca;
845 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
846
Patrick Boettcherdea74862006-05-14 05:01:31 -0300847 if (fe->ops.i2c_gate_ctrl)
848 fe->ops.i2c_gate_ctrl(fe, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
850 return -EIO;
851
852 msleep(1);
853 return 0;
854}
855
856static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe,
857 const struct firmware **fw, char *name)
858{
859 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
860
861 return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev);
862}
863
864static struct tda1004x_config philips_tdm1316l_config = {
865
866 .demod_address = 0x8,
867 .invert = 0,
868 .invert_oclk = 0,
Hartmut Hackmannecb60de2005-07-07 17:57:40 -0700869 .xtal_freq = TDA10046_XTAL_4M,
870 .agc_config = TDA10046_AGC_DEFAULT,
871 .if_freq = TDA10046_FREQ_3617,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 .request_firmware = philips_tdm1316l_request_firmware,
873};
874
Oliver Endriss6c914492007-02-02 19:12:53 -0300875static struct tda1004x_config philips_tdm1316l_config_invert = {
876
877 .demod_address = 0x8,
878 .invert = 1,
879 .invert_oclk = 0,
880 .xtal_freq = TDA10046_XTAL_4M,
881 .agc_config = TDA10046_AGC_DEFAULT,
882 .if_freq = TDA10046_FREQ_3617,
883 .request_firmware = philips_tdm1316l_request_firmware,
884};
885
Andrew de Quincey0f591d42006-04-18 17:47:11 -0300886static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700887{
888 struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
889 u8 tuner_buf[5];
890 struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,
891 .flags = 0,
892 .buf = tuner_buf,
893 .len = sizeof(tuner_buf) };
894 int tuner_frequency = 0;
895 u8 band, cp, filter;
896
897 // determine charge pump
898 tuner_frequency = params->frequency + 36125000;
899 if (tuner_frequency < 87000000)
900 return -EINVAL;
901 else if (tuner_frequency < 130000000) {
902 cp = 3;
903 band = 1;
904 } else if (tuner_frequency < 160000000) {
905 cp = 5;
906 band = 1;
907 } else if (tuner_frequency < 200000000) {
908 cp = 6;
Oliver Endriss910a7b62007-05-03 13:16:12 -0300909 band = 1;
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700910 } else if (tuner_frequency < 290000000) {
911 cp = 3;
912 band = 2;
913 } else if (tuner_frequency < 420000000) {
914 cp = 5;
915 band = 2;
916 } else if (tuner_frequency < 480000000) {
917 cp = 6;
918 band = 2;
919 } else if (tuner_frequency < 620000000) {
920 cp = 3;
921 band = 4;
922 } else if (tuner_frequency < 830000000) {
923 cp = 5;
924 band = 4;
925 } else if (tuner_frequency < 895000000) {
926 cp = 7;
927 band = 4;
928 } else
929 return -EINVAL;
930
931 // assume PLL filter should always be 8MHz for the moment.
932 filter = 1;
933
934 // calculate divisor
935 tuner_frequency = (params->frequency + 36125000 + (62500/2)) / 62500;
936
937 // setup tuner buffer
938 tuner_buf[0] = tuner_frequency >> 8;
939 tuner_buf[1] = tuner_frequency & 0xff;
940 tuner_buf[2] = 0xc8;
941 tuner_buf[3] = (cp << 5) | (filter << 3) | band;
942 tuner_buf[4] = 0x80;
943
Patrick Boettcherdea74862006-05-14 05:01:31 -0300944 if (fe->ops.i2c_gate_ctrl)
945 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700946 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
947 return -EIO;
948
949 msleep(50);
950
Patrick Boettcherdea74862006-05-14 05:01:31 -0300951 if (fe->ops.i2c_gate_ctrl)
952 fe->ops.i2c_gate_ctrl(fe, 1);
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700953 if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
954 return -EIO;
955
956 msleep(1);
957
958 return 0;
959}
960
961static u8 dvbc_philips_tdm1316l_inittab[] = {
962 0x80, 0x01,
963 0x80, 0x00,
964 0x81, 0x01,
965 0x81, 0x00,
966 0x00, 0x09,
967 0x01, 0x69,
968 0x03, 0x00,
969 0x04, 0x00,
970 0x07, 0x00,
971 0x08, 0x00,
972 0x20, 0x00,
973 0x21, 0x40,
974 0x22, 0x00,
975 0x23, 0x00,
976 0x24, 0x40,
977 0x25, 0x88,
978 0x30, 0xff,
979 0x31, 0x00,
980 0x32, 0xff,
981 0x33, 0x00,
982 0x34, 0x50,
983 0x35, 0x7f,
984 0x36, 0x00,
985 0x37, 0x20,
986 0x38, 0x00,
987 0x40, 0x1c,
988 0x41, 0xff,
989 0x42, 0x29,
990 0x43, 0x20,
991 0x44, 0xff,
992 0x45, 0x00,
993 0x46, 0x00,
994 0x49, 0x04,
995 0x4a, 0x00,
996 0x4b, 0x7b,
997 0x52, 0x30,
998 0x55, 0xae,
999 0x56, 0x47,
1000 0x57, 0xe1,
1001 0x58, 0x3a,
1002 0x5a, 0x1e,
1003 0x5b, 0x34,
1004 0x60, 0x00,
1005 0x63, 0x00,
1006 0x64, 0x00,
1007 0x65, 0x00,
1008 0x66, 0x00,
1009 0x67, 0x00,
1010 0x68, 0x00,
1011 0x69, 0x00,
1012 0x6a, 0x02,
1013 0x6b, 0x00,
1014 0x70, 0xff,
1015 0x71, 0x00,
1016 0x72, 0x00,
1017 0x73, 0x00,
1018 0x74, 0x0c,
1019 0x80, 0x00,
1020 0x81, 0x00,
1021 0x82, 0x00,
1022 0x83, 0x00,
1023 0x84, 0x04,
1024 0x85, 0x80,
1025 0x86, 0x24,
1026 0x87, 0x78,
1027 0x88, 0x10,
1028 0x89, 0x00,
1029 0x90, 0x01,
1030 0x91, 0x01,
1031 0xa0, 0x04,
1032 0xa1, 0x00,
1033 0xa2, 0x00,
1034 0xb0, 0x91,
1035 0xb1, 0x0b,
1036 0xc0, 0x53,
1037 0xc1, 0x70,
1038 0xc2, 0x12,
1039 0xd0, 0x00,
1040 0xd1, 0x00,
1041 0xd2, 0x00,
1042 0xd3, 0x00,
1043 0xd4, 0x00,
1044 0xd5, 0x00,
1045 0xde, 0x00,
1046 0xdf, 0x00,
1047 0x61, 0x38,
1048 0x62, 0x0a,
1049 0x53, 0x13,
1050 0x59, 0x08,
1051 0xff, 0xff,
1052};
1053
1054static struct stv0297_config dvbc_philips_tdm1316l_config = {
1055 .demod_address = 0x1c,
1056 .inittab = dvbc_philips_tdm1316l_inittab,
1057 .invert = 0,
Thomas Kaiserb8d4c232006-04-27 21:45:20 -03001058 .stop_during_read = 1,
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001059};
1060
Sigmund Augdal11417da2008-06-15 17:25:46 -03001061static struct tda10023_config tda10023_config = {
1062 .demod_address = 0xc,
1063 .invert = 0,
1064 .xtal = 16000000,
1065 .pll_m = 11,
1066 .pll_p = 3,
1067 .pll_n = 1,
1068 .deltaf = 0xa511,
1069};
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001070
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071
1072
1073static void frontend_init(struct budget_ci *budget_ci)
1074{
1075 switch (budget_ci->budget.dev->pci->subsystem_device) {
1076 case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
1077 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001078 dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001080 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001081 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082 break;
1083 }
1084 break;
1085
1086 case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
1087 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001088 dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001090 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 break;
1092 }
1093 break;
1094
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001095 case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
1096 budget_ci->tuner_pll_address = 0x61;
1097 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001098 dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001099 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001100 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001101 break;
1102 }
1103 break;
1104
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001106 budget_ci->tuner_pll_address = 0x63;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 budget_ci->budget.dvb_frontend =
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001108 dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001110 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1111 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 break;
1113 }
1114 break;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001115
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001116 case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001117 budget_ci->tuner_pll_address = 0x60;
1118 budget_ci->budget.dvb_frontend =
Oliver Endriss6c914492007-02-02 19:12:53 -03001119 dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001120 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001121 budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
1122 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001123 break;
1124 }
1125 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001126
1127 case 0x1017: // TT S-1500 PCI
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001128 budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001129 if (budget_ci->budget.dvb_frontend) {
Patrick Boettcherdea74862006-05-14 05:01:31 -03001130 budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
Andrew de Quincey0f591d42006-04-18 17:47:11 -03001131 budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
1132
Patrick Boettcherdea74862006-05-14 05:01:31 -03001133 budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001134 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 -03001135 printk("%s: No LNBP21 found!\n", __func__);
Andrew de Quincey2b100e72006-08-08 09:10:11 -03001136 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001137 budget_ci->budget.dvb_frontend = NULL;
1138 }
1139 }
Sigmund Augdal11417da2008-06-15 17:25:46 -03001140 break;
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001141
Sigmund Augdal11417da2008-06-15 17:25:46 -03001142 case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */
1143 budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48);
1144 if (budget_ci->budget.dvb_frontend) {
1145 if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, NULL) == NULL) {
1146 printk(KERN_ERR "%s: No tda827x found!\n", __func__);
1147 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
1148 budget_ci->budget.dvb_frontend = NULL;
1149 }
1150 }
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001151 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153
1154 if (budget_ci->budget.dvb_frontend == NULL) {
1155 printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
1156 budget_ci->budget.dev->pci->vendor,
1157 budget_ci->budget.dev->pci->device,
1158 budget_ci->budget.dev->pci->subsystem_vendor,
1159 budget_ci->budget.dev->pci->subsystem_device);
1160 } else {
1161 if (dvb_register_frontend
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001162 (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 printk("budget-ci: Frontend registration failed!\n");
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001164 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165 budget_ci->budget.dvb_frontend = NULL;
1166 }
1167 }
1168}
1169
1170static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)
1171{
1172 struct budget_ci *budget_ci;
1173 int err;
1174
David Hardemanee579bc2006-12-02 21:16:05 -02001175 budget_ci = kzalloc(sizeof(struct budget_ci), GFP_KERNEL);
David Hardeman8cc532e2006-12-02 21:16:05 -02001176 if (!budget_ci) {
1177 err = -ENOMEM;
1178 goto out1;
1179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
1181 dprintk(2, "budget_ci: %p\n", budget_ci);
1182
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183 dev->ext_priv = budget_ci;
1184
David Hardeman8cc532e2006-12-02 21:16:05 -02001185 err = ttpci_budget_init(&budget_ci->budget, dev, info, THIS_MODULE);
1186 if (err)
1187 goto out2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188
David Hardeman8cc532e2006-12-02 21:16:05 -02001189 err = msp430_ir_init(budget_ci);
1190 if (err)
1191 goto out3;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192
1193 ciintf_init(budget_ci);
1194
Johannes Stezenbachfdc53a62005-05-16 21:54:39 -07001195 budget_ci->budget.dvb_adapter.priv = budget_ci;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 frontend_init(budget_ci);
1197
Oliver Endriss32e4c3a2006-07-18 22:55:23 -03001198 ttpci_budget_init_hooks(&budget_ci->budget);
1199
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 return 0;
David Hardeman8cc532e2006-12-02 21:16:05 -02001201
1202out3:
1203 ttpci_budget_deinit(&budget_ci->budget);
1204out2:
1205 kfree(budget_ci);
1206out1:
1207 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208}
1209
1210static int budget_ci_detach(struct saa7146_dev *dev)
1211{
1212 struct budget_ci *budget_ci = (struct budget_ci *) dev->ext_priv;
1213 struct saa7146_dev *saa = budget_ci->budget.dev;
1214 int err;
1215
1216 if (budget_ci->budget.ci_present)
1217 ciintf_deinit(budget_ci);
David Hardeman8cc532e2006-12-02 21:16:05 -02001218 msp430_ir_deinit(budget_ci);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001219 if (budget_ci->budget.dvb_frontend) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -03001221 dvb_frontend_detach(budget_ci->budget.dvb_frontend);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -03001222 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 err = ttpci_budget_deinit(&budget_ci->budget);
1224
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225 // disable frontend and CI interface
1226 saa7146_setgpio(saa, 2, SAA7146_GPIO_INPUT);
1227
1228 kfree(budget_ci);
1229
1230 return err;
1231}
1232
1233static struct saa7146_extension budget_extension;
1234
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001235MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
1237MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001238MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001239MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI", BUDGET_TT);
Sigmund Augdal11417da2008-06-15 17:25:46 -03001240MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI", BUDGET_TT);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241
1242static struct pci_device_id pci_tbl[] = {
1243 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
1244 MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
Andrew de Quinceydc27a162005-09-09 13:03:07 -07001245 MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001246 MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
Andrew de Quinceydd2bbb12005-07-07 17:57:54 -07001247 MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
Perceval Anichini8cc2e372006-02-28 09:52:44 -03001248 MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017),
Sigmund Augdal11417da2008-06-15 17:25:46 -03001249 MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250 {
1251 .vendor = 0,
1252 }
1253};
1254
1255MODULE_DEVICE_TABLE(pci, pci_tbl);
1256
1257static struct saa7146_extension budget_extension = {
Dave Jones0e367a12006-08-07 13:18:56 -03001258 .name = "budget_ci dvb",
Oliver Endriss00c4cc62006-11-01 13:09:51 -03001259 .flags = SAA7146_USE_I2C_IRQ,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260
1261 .module = THIS_MODULE,
1262 .pci_tbl = &pci_tbl[0],
1263 .attach = budget_ci_attach,
1264 .detach = budget_ci_detach,
1265
1266 .irq_mask = MASK_03 | MASK_06 | MASK_10,
1267 .irq_func = budget_ci_irq,
1268};
1269
1270static int __init budget_ci_init(void)
1271{
1272 return saa7146_register_extension(&budget_extension);
1273}
1274
1275static void __exit budget_ci_exit(void)
1276{
1277 saa7146_unregister_extension(&budget_extension);
1278}
1279
1280module_init(budget_ci_init);
1281module_exit(budget_ci_exit);
1282
1283MODULE_LICENSE("GPL");
1284MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others");
1285MODULE_DESCRIPTION("driver for the SAA7146 based so-called "
1286 "budget PCI DVB cards w/ CI-module produced by "
1287 "Siemens, Technotrend, Hauppauge");