1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * budget-ci.c: driver for the SAA7146 based Budget DVB cards |
4 | * |
5 | * Compiled from various sources by Michael Hunold <michael@mihu.de> |
6 | * |
7 | * msp430 IR support contributed by Jack Thomasson <jkt@Helius.COM> |
8 | * partially based on the Siemens DVB driver by Ralph+Marcus Metzler |
9 | * |
10 | * CI interface support (c) 2004 Andrew de Quincey <adq_dvb@lidskialf.net> |
11 | * |
12 | * the project's page is at https://linuxtv.org |
13 | */ |
14 | |
15 | #include <linux/module.h> |
16 | #include <linux/errno.h> |
17 | #include <linux/slab.h> |
18 | #include <linux/interrupt.h> |
19 | #include <linux/spinlock.h> |
20 | #include <media/rc-core.h> |
21 | |
22 | #include "budget.h" |
23 | |
24 | #include <media/dvb_ca_en50221.h> |
25 | #include "stv0299.h" |
26 | #include "stv0297.h" |
27 | #include "tda1004x.h" |
28 | #include "stb0899_drv.h" |
29 | #include "stb0899_reg.h" |
30 | #include "stb0899_cfg.h" |
31 | #include "stb6100.h" |
32 | #include "stb6100_cfg.h" |
33 | #include "lnbp21.h" |
34 | #include "bsbe1.h" |
35 | #include "bsru6.h" |
36 | #include "tda1002x.h" |
37 | #include "tda827x.h" |
38 | #include "bsbe1-d01a.h" |
39 | |
40 | #define MODULE_NAME "budget_ci" |
41 | |
42 | /* |
43 | * Regarding DEBIADDR_IR: |
44 | * Some CI modules hang if random addresses are read. |
45 | * Using address 0x4000 for the IR read means that we |
46 | * use the same address as for CI version, which should |
47 | * be a safe default. |
48 | */ |
49 | #define DEBIADDR_IR 0x4000 |
50 | #define DEBIADDR_CICONTROL 0x0000 |
51 | #define DEBIADDR_CIVERSION 0x4000 |
52 | #define DEBIADDR_IO 0x1000 |
53 | #define DEBIADDR_ATTR 0x3000 |
54 | |
55 | #define CICONTROL_RESET 0x01 |
56 | #define CICONTROL_ENABLETS 0x02 |
57 | #define CICONTROL_CAMDETECT 0x08 |
58 | |
59 | #define DEBICICTL 0x00420000 |
60 | #define DEBICICAM 0x02420000 |
61 | |
62 | #define SLOTSTATUS_NONE 1 |
63 | #define SLOTSTATUS_PRESENT 2 |
64 | #define SLOTSTATUS_RESET 4 |
65 | #define SLOTSTATUS_READY 8 |
66 | #define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) |
67 | |
68 | /* RC5 device wildcard */ |
69 | #define IR_DEVICE_ANY 255 |
70 | |
71 | static int rc5_device = -1; |
72 | module_param(rc5_device, int, 0644); |
73 | MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)" ); |
74 | |
75 | static int ir_debug; |
76 | module_param(ir_debug, int, 0644); |
77 | MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding" ); |
78 | |
79 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); |
80 | |
81 | struct budget_ci_ir { |
82 | struct rc_dev *dev; |
83 | struct tasklet_struct msp430_irq_tasklet; |
84 | char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ |
85 | char phys[32]; |
86 | int rc5_device; |
87 | u32 ir_key; |
88 | bool have_command; |
89 | bool full_rc5; /* Outputs a full RC5 code */ |
90 | }; |
91 | |
92 | struct budget_ci { |
93 | struct budget budget; |
94 | struct tasklet_struct ciintf_irq_tasklet; |
95 | int slot_status; |
96 | int ci_irq; |
97 | struct dvb_ca_en50221 ca; |
98 | struct budget_ci_ir ir; |
99 | u8 tuner_pll_address; /* used for philips_tdm1316l configs */ |
100 | }; |
101 | |
102 | static void msp430_ir_interrupt(struct tasklet_struct *t) |
103 | { |
104 | struct budget_ci_ir *ir = from_tasklet(ir, t, msp430_irq_tasklet); |
105 | struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir); |
106 | struct rc_dev *dev = budget_ci->ir.dev; |
107 | u32 command = ttpci_budget_debiread(budget: &budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, count: 2, uselocks: 1, nobusyloop: 0) >> 8; |
108 | |
109 | /* |
110 | * The msp430 chip can generate two different bytes, command and device |
111 | * |
112 | * type1: X1CCCCCC, C = command bits (0 - 63) |
113 | * type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit |
114 | * |
115 | * Each signal from the remote control can generate one or more command |
116 | * bytes and one or more device bytes. For the repeated bytes, the |
117 | * highest bit (X) is set. The first command byte is always generated |
118 | * before the first device byte. Other than that, no specific order |
119 | * seems to apply. To make life interesting, bytes can also be lost. |
120 | * |
121 | * Only when we have a command and device byte, a keypress is |
122 | * generated. |
123 | */ |
124 | |
125 | if (ir_debug) |
126 | printk("budget_ci: received byte 0x%02x\n" , command); |
127 | |
128 | /* Remove repeat bit, we use every command */ |
129 | command = command & 0x7f; |
130 | |
131 | /* Is this a RC5 command byte? */ |
132 | if (command & 0x40) { |
133 | budget_ci->ir.have_command = true; |
134 | budget_ci->ir.ir_key = command & 0x3f; |
135 | return; |
136 | } |
137 | |
138 | /* It's a RC5 device byte */ |
139 | if (!budget_ci->ir.have_command) |
140 | return; |
141 | budget_ci->ir.have_command = false; |
142 | |
143 | if (budget_ci->ir.rc5_device != IR_DEVICE_ANY && |
144 | budget_ci->ir.rc5_device != (command & 0x1f)) |
145 | return; |
146 | |
147 | if (budget_ci->ir.full_rc5) { |
148 | rc_keydown(dev, protocol: RC_PROTO_RC5, |
149 | RC_SCANCODE_RC5(budget_ci->ir.rc5_device, budget_ci->ir.ir_key), |
150 | toggle: !!(command & 0x20)); |
151 | return; |
152 | } |
153 | |
154 | /* FIXME: We should generate complete scancodes for all devices */ |
155 | rc_keydown(dev, protocol: RC_PROTO_UNKNOWN, scancode: budget_ci->ir.ir_key, |
156 | toggle: !!(command & 0x20)); |
157 | } |
158 | |
159 | static int msp430_ir_init(struct budget_ci *budget_ci) |
160 | { |
161 | struct saa7146_dev *saa = budget_ci->budget.dev; |
162 | struct rc_dev *dev; |
163 | int error; |
164 | |
165 | dev = rc_allocate_device(RC_DRIVER_SCANCODE); |
166 | if (!dev) { |
167 | printk(KERN_ERR "budget_ci: IR interface initialisation failed\n" ); |
168 | return -ENOMEM; |
169 | } |
170 | |
171 | snprintf(buf: budget_ci->ir.name, size: sizeof(budget_ci->ir.name), |
172 | fmt: "Budget-CI dvb ir receiver %s" , saa->name); |
173 | snprintf(buf: budget_ci->ir.phys, size: sizeof(budget_ci->ir.phys), |
174 | fmt: "pci-%s/ir0" , pci_name(pdev: saa->pci)); |
175 | |
176 | dev->driver_name = MODULE_NAME; |
177 | dev->device_name = budget_ci->ir.name; |
178 | dev->input_phys = budget_ci->ir.phys; |
179 | dev->input_id.bustype = BUS_PCI; |
180 | dev->input_id.version = 1; |
181 | if (saa->pci->subsystem_vendor) { |
182 | dev->input_id.vendor = saa->pci->subsystem_vendor; |
183 | dev->input_id.product = saa->pci->subsystem_device; |
184 | } else { |
185 | dev->input_id.vendor = saa->pci->vendor; |
186 | dev->input_id.product = saa->pci->device; |
187 | } |
188 | dev->dev.parent = &saa->pci->dev; |
189 | |
190 | if (rc5_device < 0) |
191 | budget_ci->ir.rc5_device = IR_DEVICE_ANY; |
192 | else |
193 | budget_ci->ir.rc5_device = rc5_device; |
194 | |
195 | /* Select keymap and address */ |
196 | switch (budget_ci->budget.dev->pci->subsystem_device) { |
197 | case 0x100c: |
198 | case 0x100f: |
199 | case 0x1011: |
200 | case 0x1012: |
201 | /* The hauppauge keymap is a superset of these remotes */ |
202 | dev->map_name = RC_MAP_HAUPPAUGE; |
203 | budget_ci->ir.full_rc5 = true; |
204 | |
205 | if (rc5_device < 0) |
206 | budget_ci->ir.rc5_device = 0x1f; |
207 | break; |
208 | case 0x1010: |
209 | case 0x1017: |
210 | case 0x1019: |
211 | case 0x101a: |
212 | case 0x101b: |
213 | /* for the Technotrend 1500 bundled remote */ |
214 | dev->map_name = RC_MAP_TT_1500; |
215 | break; |
216 | default: |
217 | /* unknown remote */ |
218 | dev->map_name = RC_MAP_BUDGET_CI_OLD; |
219 | break; |
220 | } |
221 | if (!budget_ci->ir.full_rc5) |
222 | dev->scancode_mask = 0xff; |
223 | |
224 | error = rc_register_device(dev); |
225 | if (error) { |
226 | printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n" , error); |
227 | rc_free_device(dev); |
228 | return error; |
229 | } |
230 | |
231 | budget_ci->ir.dev = dev; |
232 | |
233 | tasklet_setup(t: &budget_ci->ir.msp430_irq_tasklet, callback: msp430_ir_interrupt); |
234 | |
235 | SAA7146_IER_ENABLE(x: saa, MASK_06); |
236 | saa7146_setgpio(dev: saa, port: 3, SAA7146_GPIO_IRQHI); |
237 | |
238 | return 0; |
239 | } |
240 | |
241 | static void msp430_ir_deinit(struct budget_ci *budget_ci) |
242 | { |
243 | struct saa7146_dev *saa = budget_ci->budget.dev; |
244 | |
245 | SAA7146_IER_DISABLE(x: saa, MASK_06); |
246 | saa7146_setgpio(dev: saa, port: 3, SAA7146_GPIO_INPUT); |
247 | tasklet_kill(t: &budget_ci->ir.msp430_irq_tasklet); |
248 | |
249 | rc_unregister_device(dev: budget_ci->ir.dev); |
250 | } |
251 | |
252 | static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address) |
253 | { |
254 | struct budget_ci *budget_ci = ca->data; |
255 | |
256 | if (slot != 0) |
257 | return -EINVAL; |
258 | |
259 | return ttpci_budget_debiread(budget: &budget_ci->budget, DEBICICAM, |
260 | DEBIADDR_ATTR | (address & 0xfff), count: 1, uselocks: 1, nobusyloop: 0); |
261 | } |
262 | |
263 | static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address, u8 value) |
264 | { |
265 | struct budget_ci *budget_ci = ca->data; |
266 | |
267 | if (slot != 0) |
268 | return -EINVAL; |
269 | |
270 | return ttpci_budget_debiwrite(budget: &budget_ci->budget, DEBICICAM, |
271 | DEBIADDR_ATTR | (address & 0xfff), count: 1, value, uselocks: 1, nobusyloop: 0); |
272 | } |
273 | |
274 | static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address) |
275 | { |
276 | struct budget_ci *budget_ci = ca->data; |
277 | |
278 | if (slot != 0) |
279 | return -EINVAL; |
280 | |
281 | return ttpci_budget_debiread(budget: &budget_ci->budget, DEBICICAM, |
282 | DEBIADDR_IO | (address & 3), count: 1, uselocks: 1, nobusyloop: 0); |
283 | } |
284 | |
285 | static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 address, u8 value) |
286 | { |
287 | struct budget_ci *budget_ci = ca->data; |
288 | |
289 | if (slot != 0) |
290 | return -EINVAL; |
291 | |
292 | return ttpci_budget_debiwrite(budget: &budget_ci->budget, DEBICICAM, |
293 | DEBIADDR_IO | (address & 3), count: 1, value, uselocks: 1, nobusyloop: 0); |
294 | } |
295 | |
296 | static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) |
297 | { |
298 | struct budget_ci *budget_ci = ca->data; |
299 | struct saa7146_dev *saa = budget_ci->budget.dev; |
300 | |
301 | if (slot != 0) |
302 | return -EINVAL; |
303 | |
304 | if (budget_ci->ci_irq) { |
305 | // trigger on RISING edge during reset so we know when READY is re-asserted |
306 | saa7146_setgpio(dev: saa, port: 0, SAA7146_GPIO_IRQHI); |
307 | } |
308 | budget_ci->slot_status = SLOTSTATUS_RESET; |
309 | ttpci_budget_debiwrite(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, value: 0, uselocks: 1, nobusyloop: 0); |
310 | msleep(msecs: 1); |
311 | ttpci_budget_debiwrite(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, |
312 | CICONTROL_RESET, uselocks: 1, nobusyloop: 0); |
313 | |
314 | saa7146_setgpio(dev: saa, port: 1, SAA7146_GPIO_OUTHI); |
315 | ttpci_budget_set_video_port(dev: saa, BUDGET_VIDEO_PORTB); |
316 | return 0; |
317 | } |
318 | |
319 | static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) |
320 | { |
321 | struct budget_ci *budget_ci = ca->data; |
322 | struct saa7146_dev *saa = budget_ci->budget.dev; |
323 | |
324 | if (slot != 0) |
325 | return -EINVAL; |
326 | |
327 | saa7146_setgpio(dev: saa, port: 1, SAA7146_GPIO_OUTHI); |
328 | ttpci_budget_set_video_port(dev: saa, BUDGET_VIDEO_PORTB); |
329 | return 0; |
330 | } |
331 | |
332 | static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) |
333 | { |
334 | struct budget_ci *budget_ci = ca->data; |
335 | struct saa7146_dev *saa = budget_ci->budget.dev; |
336 | int tmp; |
337 | |
338 | if (slot != 0) |
339 | return -EINVAL; |
340 | |
341 | saa7146_setgpio(dev: saa, port: 1, SAA7146_GPIO_OUTLO); |
342 | |
343 | tmp = ttpci_budget_debiread(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, uselocks: 1, nobusyloop: 0); |
344 | ttpci_budget_debiwrite(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, |
345 | value: tmp | CICONTROL_ENABLETS, uselocks: 1, nobusyloop: 0); |
346 | |
347 | ttpci_budget_set_video_port(dev: saa, BUDGET_VIDEO_PORTA); |
348 | return 0; |
349 | } |
350 | |
351 | static void ciintf_interrupt(struct tasklet_struct *t) |
352 | { |
353 | struct budget_ci *budget_ci = from_tasklet(budget_ci, t, |
354 | ciintf_irq_tasklet); |
355 | struct saa7146_dev *saa = budget_ci->budget.dev; |
356 | unsigned int flags; |
357 | |
358 | // ensure we don't get spurious IRQs during initialisation |
359 | if (!budget_ci->budget.ci_present) |
360 | return; |
361 | |
362 | // read the CAM status |
363 | flags = ttpci_budget_debiread(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, uselocks: 1, nobusyloop: 0); |
364 | if (flags & CICONTROL_CAMDETECT) { |
365 | |
366 | // GPIO should be set to trigger on falling edge if a CAM is present |
367 | saa7146_setgpio(dev: saa, port: 0, SAA7146_GPIO_IRQLO); |
368 | |
369 | if (budget_ci->slot_status & SLOTSTATUS_NONE) { |
370 | // CAM insertion IRQ |
371 | budget_ci->slot_status = SLOTSTATUS_PRESENT; |
372 | dvb_ca_en50221_camchange_irq(pubca: &budget_ci->ca, slot: 0, |
373 | DVB_CA_EN50221_CAMCHANGE_INSERTED); |
374 | |
375 | } else if (budget_ci->slot_status & SLOTSTATUS_RESET) { |
376 | // CAM ready (reset completed) |
377 | budget_ci->slot_status = SLOTSTATUS_READY; |
378 | dvb_ca_en50221_camready_irq(pubca: &budget_ci->ca, slot: 0); |
379 | |
380 | } else if (budget_ci->slot_status & SLOTSTATUS_READY) { |
381 | // FR/DA IRQ |
382 | dvb_ca_en50221_frda_irq(ca: &budget_ci->ca, slot: 0); |
383 | } |
384 | } else { |
385 | |
386 | // trigger on rising edge if a CAM is not present - when a CAM is inserted, we |
387 | // only want to get the IRQ when it sets READY. If we trigger on the falling edge, |
388 | // the CAM might not actually be ready yet. |
389 | saa7146_setgpio(dev: saa, port: 0, SAA7146_GPIO_IRQHI); |
390 | |
391 | // generate a CAM removal IRQ if we haven't already |
392 | if (budget_ci->slot_status & SLOTSTATUS_OCCUPIED) { |
393 | // CAM removal IRQ |
394 | budget_ci->slot_status = SLOTSTATUS_NONE; |
395 | dvb_ca_en50221_camchange_irq(pubca: &budget_ci->ca, slot: 0, |
396 | DVB_CA_EN50221_CAMCHANGE_REMOVED); |
397 | } |
398 | } |
399 | } |
400 | |
401 | static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) |
402 | { |
403 | struct budget_ci *budget_ci = ca->data; |
404 | unsigned int flags; |
405 | |
406 | // ensure we don't get spurious IRQs during initialisation |
407 | if (!budget_ci->budget.ci_present) |
408 | return -EINVAL; |
409 | |
410 | // read the CAM status |
411 | flags = ttpci_budget_debiread(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, uselocks: 1, nobusyloop: 0); |
412 | if (flags & CICONTROL_CAMDETECT) { |
413 | // mark it as present if it wasn't before |
414 | if (budget_ci->slot_status & SLOTSTATUS_NONE) { |
415 | budget_ci->slot_status = SLOTSTATUS_PRESENT; |
416 | } |
417 | |
418 | // during a RESET, we check if we can read from IO memory to see when CAM is ready |
419 | if (budget_ci->slot_status & SLOTSTATUS_RESET) { |
420 | if (ciintf_read_attribute_mem(ca, slot, address: 0) == 0x1d) { |
421 | budget_ci->slot_status = SLOTSTATUS_READY; |
422 | } |
423 | } |
424 | } else { |
425 | budget_ci->slot_status = SLOTSTATUS_NONE; |
426 | } |
427 | |
428 | if (budget_ci->slot_status != SLOTSTATUS_NONE) { |
429 | if (budget_ci->slot_status & SLOTSTATUS_READY) { |
430 | return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; |
431 | } |
432 | return DVB_CA_EN50221_POLL_CAM_PRESENT; |
433 | } |
434 | |
435 | return 0; |
436 | } |
437 | |
438 | static int ciintf_init(struct budget_ci *budget_ci) |
439 | { |
440 | struct saa7146_dev *saa = budget_ci->budget.dev; |
441 | int flags; |
442 | int result; |
443 | int ci_version; |
444 | int ca_flags; |
445 | |
446 | memset(&budget_ci->ca, 0, sizeof(struct dvb_ca_en50221)); |
447 | |
448 | // enable DEBI pins |
449 | saa7146_write(saa, MC1, MASK_27 | MASK_11); |
450 | |
451 | // test if it is there |
452 | ci_version = ttpci_budget_debiread(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CIVERSION, count: 1, uselocks: 1, nobusyloop: 0); |
453 | if ((ci_version & 0xa0) != 0xa0) { |
454 | result = -ENODEV; |
455 | goto error; |
456 | } |
457 | |
458 | // determine whether a CAM is present or not |
459 | flags = ttpci_budget_debiread(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, uselocks: 1, nobusyloop: 0); |
460 | budget_ci->slot_status = SLOTSTATUS_NONE; |
461 | if (flags & CICONTROL_CAMDETECT) |
462 | budget_ci->slot_status = SLOTSTATUS_PRESENT; |
463 | |
464 | // version 0xa2 of the CI firmware doesn't generate interrupts |
465 | if (ci_version == 0xa2) { |
466 | ca_flags = 0; |
467 | budget_ci->ci_irq = 0; |
468 | } else { |
469 | ca_flags = DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE | |
470 | DVB_CA_EN50221_FLAG_IRQ_FR | |
471 | DVB_CA_EN50221_FLAG_IRQ_DA; |
472 | budget_ci->ci_irq = 1; |
473 | } |
474 | |
475 | // register CI interface |
476 | budget_ci->ca.owner = THIS_MODULE; |
477 | budget_ci->ca.read_attribute_mem = ciintf_read_attribute_mem; |
478 | budget_ci->ca.write_attribute_mem = ciintf_write_attribute_mem; |
479 | budget_ci->ca.read_cam_control = ciintf_read_cam_control; |
480 | budget_ci->ca.write_cam_control = ciintf_write_cam_control; |
481 | budget_ci->ca.slot_reset = ciintf_slot_reset; |
482 | budget_ci->ca.slot_shutdown = ciintf_slot_shutdown; |
483 | budget_ci->ca.slot_ts_enable = ciintf_slot_ts_enable; |
484 | budget_ci->ca.poll_slot_status = ciintf_poll_slot_status; |
485 | budget_ci->ca.data = budget_ci; |
486 | if ((result = dvb_ca_en50221_init(dvb_adapter: &budget_ci->budget.dvb_adapter, |
487 | ca: &budget_ci->ca, |
488 | flags: ca_flags, slot_count: 1)) != 0) { |
489 | printk("budget_ci: CI interface detected, but initialisation failed.\n" ); |
490 | goto error; |
491 | } |
492 | |
493 | // Setup CI slot IRQ |
494 | if (budget_ci->ci_irq) { |
495 | tasklet_setup(t: &budget_ci->ciintf_irq_tasklet, callback: ciintf_interrupt); |
496 | if (budget_ci->slot_status != SLOTSTATUS_NONE) { |
497 | saa7146_setgpio(dev: saa, port: 0, SAA7146_GPIO_IRQLO); |
498 | } else { |
499 | saa7146_setgpio(dev: saa, port: 0, SAA7146_GPIO_IRQHI); |
500 | } |
501 | SAA7146_IER_ENABLE(x: saa, MASK_03); |
502 | } |
503 | |
504 | // enable interface |
505 | ttpci_budget_debiwrite(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, |
506 | CICONTROL_RESET, uselocks: 1, nobusyloop: 0); |
507 | |
508 | // success! |
509 | printk("budget_ci: CI interface initialised\n" ); |
510 | budget_ci->budget.ci_present = 1; |
511 | |
512 | // forge a fake CI IRQ so the CAM state is setup correctly |
513 | if (budget_ci->ci_irq) { |
514 | flags = DVB_CA_EN50221_CAMCHANGE_REMOVED; |
515 | if (budget_ci->slot_status != SLOTSTATUS_NONE) |
516 | flags = DVB_CA_EN50221_CAMCHANGE_INSERTED; |
517 | dvb_ca_en50221_camchange_irq(pubca: &budget_ci->ca, slot: 0, change_type: flags); |
518 | } |
519 | |
520 | return 0; |
521 | |
522 | error: |
523 | saa7146_write(saa, MC1, MASK_27); |
524 | return result; |
525 | } |
526 | |
527 | static void ciintf_deinit(struct budget_ci *budget_ci) |
528 | { |
529 | struct saa7146_dev *saa = budget_ci->budget.dev; |
530 | |
531 | // disable CI interrupts |
532 | if (budget_ci->ci_irq) { |
533 | SAA7146_IER_DISABLE(x: saa, MASK_03); |
534 | saa7146_setgpio(dev: saa, port: 0, SAA7146_GPIO_INPUT); |
535 | tasklet_kill(t: &budget_ci->ciintf_irq_tasklet); |
536 | } |
537 | |
538 | // reset interface |
539 | ttpci_budget_debiwrite(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, value: 0, uselocks: 1, nobusyloop: 0); |
540 | msleep(msecs: 1); |
541 | ttpci_budget_debiwrite(budget: &budget_ci->budget, DEBICICTL, DEBIADDR_CICONTROL, count: 1, |
542 | CICONTROL_RESET, uselocks: 1, nobusyloop: 0); |
543 | |
544 | // disable TS data stream to CI interface |
545 | saa7146_setgpio(dev: saa, port: 1, SAA7146_GPIO_INPUT); |
546 | |
547 | // release the CA device |
548 | dvb_ca_en50221_release(ca: &budget_ci->ca); |
549 | |
550 | // disable DEBI pins |
551 | saa7146_write(saa, MC1, MASK_27); |
552 | } |
553 | |
554 | static void budget_ci_irq(struct saa7146_dev *dev, u32 * isr) |
555 | { |
556 | struct budget_ci *budget_ci = dev->ext_priv; |
557 | |
558 | dprintk(8, "dev: %p, budget_ci: %p\n" , dev, budget_ci); |
559 | |
560 | if (*isr & MASK_06) |
561 | tasklet_schedule(t: &budget_ci->ir.msp430_irq_tasklet); |
562 | |
563 | if (*isr & MASK_10) |
564 | ttpci_budget_irq10_handler(dev, isr); |
565 | |
566 | if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) |
567 | tasklet_schedule(t: &budget_ci->ciintf_irq_tasklet); |
568 | } |
569 | |
570 | static u8 philips_su1278_tt_inittab[] = { |
571 | 0x01, 0x0f, |
572 | 0x02, 0x30, |
573 | 0x03, 0x00, |
574 | 0x04, 0x5b, |
575 | 0x05, 0x85, |
576 | 0x06, 0x02, |
577 | 0x07, 0x00, |
578 | 0x08, 0x02, |
579 | 0x09, 0x00, |
580 | 0x0C, 0x01, |
581 | 0x0D, 0x81, |
582 | 0x0E, 0x44, |
583 | 0x0f, 0x14, |
584 | 0x10, 0x3c, |
585 | 0x11, 0x84, |
586 | 0x12, 0xda, |
587 | 0x13, 0x97, |
588 | 0x14, 0x95, |
589 | 0x15, 0xc9, |
590 | 0x16, 0x19, |
591 | 0x17, 0x8c, |
592 | 0x18, 0x59, |
593 | 0x19, 0xf8, |
594 | 0x1a, 0xfe, |
595 | 0x1c, 0x7f, |
596 | 0x1d, 0x00, |
597 | 0x1e, 0x00, |
598 | 0x1f, 0x50, |
599 | 0x20, 0x00, |
600 | 0x21, 0x00, |
601 | 0x22, 0x00, |
602 | 0x23, 0x00, |
603 | 0x28, 0x00, |
604 | 0x29, 0x28, |
605 | 0x2a, 0x14, |
606 | 0x2b, 0x0f, |
607 | 0x2c, 0x09, |
608 | 0x2d, 0x09, |
609 | 0x31, 0x1f, |
610 | 0x32, 0x19, |
611 | 0x33, 0xfc, |
612 | 0x34, 0x93, |
613 | 0xff, 0xff |
614 | }; |
615 | |
616 | static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ratio) |
617 | { |
618 | stv0299_writereg(fe, 0x0e, 0x44); |
619 | if (srate >= 10000000) { |
620 | stv0299_writereg(fe, 0x13, 0x97); |
621 | stv0299_writereg(fe, 0x14, 0x95); |
622 | stv0299_writereg(fe, 0x15, 0xc9); |
623 | stv0299_writereg(fe, 0x17, 0x8c); |
624 | stv0299_writereg(fe, 0x1a, 0xfe); |
625 | stv0299_writereg(fe, 0x1c, 0x7f); |
626 | stv0299_writereg(fe, 0x2d, 0x09); |
627 | } else { |
628 | stv0299_writereg(fe, 0x13, 0x99); |
629 | stv0299_writereg(fe, 0x14, 0x8d); |
630 | stv0299_writereg(fe, 0x15, 0xce); |
631 | stv0299_writereg(fe, 0x17, 0x43); |
632 | stv0299_writereg(fe, 0x1a, 0x1d); |
633 | stv0299_writereg(fe, 0x1c, 0x12); |
634 | stv0299_writereg(fe, 0x2d, 0x05); |
635 | } |
636 | stv0299_writereg(fe, 0x0e, 0x23); |
637 | stv0299_writereg(fe, 0x0f, 0x94); |
638 | stv0299_writereg(fe, 0x10, 0x39); |
639 | stv0299_writereg(fe, 0x15, 0xc9); |
640 | |
641 | stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); |
642 | stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); |
643 | stv0299_writereg(fe, 0x21, (ratio) & 0xf0); |
644 | |
645 | return 0; |
646 | } |
647 | |
648 | static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe) |
649 | { |
650 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
651 | struct budget_ci *budget_ci = fe->dvb->priv; |
652 | u32 div; |
653 | u8 buf[4]; |
654 | struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; |
655 | |
656 | if ((p->frequency < 950000) || (p->frequency > 2150000)) |
657 | return -EINVAL; |
658 | |
659 | div = (p->frequency + (500 - 1)) / 500; /* round correctly */ |
660 | buf[0] = (div >> 8) & 0x7f; |
661 | buf[1] = div & 0xff; |
662 | buf[2] = 0x80 | ((div & 0x18000) >> 10) | 2; |
663 | buf[3] = 0x20; |
664 | |
665 | if (p->symbol_rate < 4000000) |
666 | buf[3] |= 1; |
667 | |
668 | if (p->frequency < 1250000) |
669 | buf[3] |= 0; |
670 | else if (p->frequency < 1550000) |
671 | buf[3] |= 0x40; |
672 | else if (p->frequency < 2050000) |
673 | buf[3] |= 0x80; |
674 | else if (p->frequency < 2150000) |
675 | buf[3] |= 0xC0; |
676 | |
677 | if (fe->ops.i2c_gate_ctrl) |
678 | fe->ops.i2c_gate_ctrl(fe, 1); |
679 | if (i2c_transfer(adap: &budget_ci->budget.i2c_adap, msgs: &msg, num: 1) != 1) |
680 | return -EIO; |
681 | return 0; |
682 | } |
683 | |
684 | static const struct stv0299_config philips_su1278_tt_config = { |
685 | |
686 | .demod_address = 0x68, |
687 | .inittab = philips_su1278_tt_inittab, |
688 | .mclk = 64000000UL, |
689 | .invert = 0, |
690 | .skip_reinit = 1, |
691 | .lock_output = STV0299_LOCKOUTPUT_1, |
692 | .volt13_op0_op1 = STV0299_VOLT13_OP1, |
693 | .min_delay_ms = 50, |
694 | .set_symbol_rate = philips_su1278_tt_set_symbol_rate, |
695 | }; |
696 | |
697 | |
698 | |
699 | static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) |
700 | { |
701 | struct budget_ci *budget_ci = fe->dvb->priv; |
702 | static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; |
703 | static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; |
704 | struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len = |
705 | sizeof(td1316_init) }; |
706 | |
707 | // setup PLL configuration |
708 | if (fe->ops.i2c_gate_ctrl) |
709 | fe->ops.i2c_gate_ctrl(fe, 1); |
710 | if (i2c_transfer(adap: &budget_ci->budget.i2c_adap, msgs: &tuner_msg, num: 1) != 1) |
711 | return -EIO; |
712 | msleep(msecs: 1); |
713 | |
714 | // disable the mc44BC374c (do not check for errors) |
715 | tuner_msg.addr = 0x65; |
716 | tuner_msg.buf = disable_mc44BC374c; |
717 | tuner_msg.len = sizeof(disable_mc44BC374c); |
718 | if (fe->ops.i2c_gate_ctrl) |
719 | fe->ops.i2c_gate_ctrl(fe, 1); |
720 | if (i2c_transfer(adap: &budget_ci->budget.i2c_adap, msgs: &tuner_msg, num: 1) != 1) { |
721 | if (fe->ops.i2c_gate_ctrl) |
722 | fe->ops.i2c_gate_ctrl(fe, 1); |
723 | i2c_transfer(adap: &budget_ci->budget.i2c_adap, msgs: &tuner_msg, num: 1); |
724 | } |
725 | |
726 | return 0; |
727 | } |
728 | |
729 | static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) |
730 | { |
731 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
732 | struct budget_ci *budget_ci = fe->dvb->priv; |
733 | u8 tuner_buf[4]; |
734 | struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) }; |
735 | int tuner_frequency = 0; |
736 | u8 band, cp, filter; |
737 | |
738 | // determine charge pump |
739 | tuner_frequency = p->frequency + 36130000; |
740 | if (tuner_frequency < 87000000) |
741 | return -EINVAL; |
742 | else if (tuner_frequency < 130000000) |
743 | cp = 3; |
744 | else if (tuner_frequency < 160000000) |
745 | cp = 5; |
746 | else if (tuner_frequency < 200000000) |
747 | cp = 6; |
748 | else if (tuner_frequency < 290000000) |
749 | cp = 3; |
750 | else if (tuner_frequency < 420000000) |
751 | cp = 5; |
752 | else if (tuner_frequency < 480000000) |
753 | cp = 6; |
754 | else if (tuner_frequency < 620000000) |
755 | cp = 3; |
756 | else if (tuner_frequency < 830000000) |
757 | cp = 5; |
758 | else if (tuner_frequency < 895000000) |
759 | cp = 7; |
760 | else |
761 | return -EINVAL; |
762 | |
763 | // determine band |
764 | if (p->frequency < 49000000) |
765 | return -EINVAL; |
766 | else if (p->frequency < 159000000) |
767 | band = 1; |
768 | else if (p->frequency < 444000000) |
769 | band = 2; |
770 | else if (p->frequency < 861000000) |
771 | band = 4; |
772 | else |
773 | return -EINVAL; |
774 | |
775 | // setup PLL filter and TDA9889 |
776 | switch (p->bandwidth_hz) { |
777 | case 6000000: |
778 | tda1004x_writereg(fe, 0x0C, 0x14); |
779 | filter = 0; |
780 | break; |
781 | |
782 | case 7000000: |
783 | tda1004x_writereg(fe, 0x0C, 0x80); |
784 | filter = 0; |
785 | break; |
786 | |
787 | case 8000000: |
788 | tda1004x_writereg(fe, 0x0C, 0x14); |
789 | filter = 1; |
790 | break; |
791 | |
792 | default: |
793 | return -EINVAL; |
794 | } |
795 | |
796 | // calculate divisor |
797 | // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) |
798 | tuner_frequency = (((p->frequency / 1000) * 6) + 217280) / 1000; |
799 | |
800 | // setup tuner buffer |
801 | tuner_buf[0] = tuner_frequency >> 8; |
802 | tuner_buf[1] = tuner_frequency & 0xff; |
803 | tuner_buf[2] = 0xca; |
804 | tuner_buf[3] = (cp << 5) | (filter << 3) | band; |
805 | |
806 | if (fe->ops.i2c_gate_ctrl) |
807 | fe->ops.i2c_gate_ctrl(fe, 1); |
808 | if (i2c_transfer(adap: &budget_ci->budget.i2c_adap, msgs: &tuner_msg, num: 1) != 1) |
809 | return -EIO; |
810 | |
811 | msleep(msecs: 1); |
812 | return 0; |
813 | } |
814 | |
815 | static int philips_tdm1316l_request_firmware(struct dvb_frontend *fe, |
816 | const struct firmware **fw, char *name) |
817 | { |
818 | struct budget_ci *budget_ci = fe->dvb->priv; |
819 | |
820 | return request_firmware(fw, name, &budget_ci->budget.dev->pci->dev); |
821 | } |
822 | |
823 | static struct tda1004x_config philips_tdm1316l_config = { |
824 | |
825 | .demod_address = 0x8, |
826 | .invert = 0, |
827 | .invert_oclk = 0, |
828 | .xtal_freq = TDA10046_XTAL_4M, |
829 | .agc_config = TDA10046_AGC_DEFAULT, |
830 | .if_freq = TDA10046_FREQ_3617, |
831 | .request_firmware = philips_tdm1316l_request_firmware, |
832 | }; |
833 | |
834 | static struct tda1004x_config philips_tdm1316l_config_invert = { |
835 | |
836 | .demod_address = 0x8, |
837 | .invert = 1, |
838 | .invert_oclk = 0, |
839 | .xtal_freq = TDA10046_XTAL_4M, |
840 | .agc_config = TDA10046_AGC_DEFAULT, |
841 | .if_freq = TDA10046_FREQ_3617, |
842 | .request_firmware = philips_tdm1316l_request_firmware, |
843 | }; |
844 | |
845 | static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe) |
846 | { |
847 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
848 | struct budget_ci *budget_ci = fe->dvb->priv; |
849 | u8 tuner_buf[5]; |
850 | struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address, |
851 | .flags = 0, |
852 | .buf = tuner_buf, |
853 | .len = sizeof(tuner_buf) }; |
854 | int tuner_frequency = 0; |
855 | u8 band, cp, filter; |
856 | |
857 | // determine charge pump |
858 | tuner_frequency = p->frequency + 36125000; |
859 | if (tuner_frequency < 87000000) |
860 | return -EINVAL; |
861 | else if (tuner_frequency < 130000000) { |
862 | cp = 3; |
863 | band = 1; |
864 | } else if (tuner_frequency < 160000000) { |
865 | cp = 5; |
866 | band = 1; |
867 | } else if (tuner_frequency < 200000000) { |
868 | cp = 6; |
869 | band = 1; |
870 | } else if (tuner_frequency < 290000000) { |
871 | cp = 3; |
872 | band = 2; |
873 | } else if (tuner_frequency < 420000000) { |
874 | cp = 5; |
875 | band = 2; |
876 | } else if (tuner_frequency < 480000000) { |
877 | cp = 6; |
878 | band = 2; |
879 | } else if (tuner_frequency < 620000000) { |
880 | cp = 3; |
881 | band = 4; |
882 | } else if (tuner_frequency < 830000000) { |
883 | cp = 5; |
884 | band = 4; |
885 | } else if (tuner_frequency < 895000000) { |
886 | cp = 7; |
887 | band = 4; |
888 | } else |
889 | return -EINVAL; |
890 | |
891 | // assume PLL filter should always be 8MHz for the moment. |
892 | filter = 1; |
893 | |
894 | // calculate divisor |
895 | tuner_frequency = (p->frequency + 36125000 + (62500/2)) / 62500; |
896 | |
897 | // setup tuner buffer |
898 | tuner_buf[0] = tuner_frequency >> 8; |
899 | tuner_buf[1] = tuner_frequency & 0xff; |
900 | tuner_buf[2] = 0xc8; |
901 | tuner_buf[3] = (cp << 5) | (filter << 3) | band; |
902 | tuner_buf[4] = 0x80; |
903 | |
904 | if (fe->ops.i2c_gate_ctrl) |
905 | fe->ops.i2c_gate_ctrl(fe, 1); |
906 | if (i2c_transfer(adap: &budget_ci->budget.i2c_adap, msgs: &tuner_msg, num: 1) != 1) |
907 | return -EIO; |
908 | |
909 | msleep(msecs: 50); |
910 | |
911 | if (fe->ops.i2c_gate_ctrl) |
912 | fe->ops.i2c_gate_ctrl(fe, 1); |
913 | if (i2c_transfer(adap: &budget_ci->budget.i2c_adap, msgs: &tuner_msg, num: 1) != 1) |
914 | return -EIO; |
915 | |
916 | msleep(msecs: 1); |
917 | |
918 | return 0; |
919 | } |
920 | |
921 | static u8 dvbc_philips_tdm1316l_inittab[] = { |
922 | 0x80, 0x01, |
923 | 0x80, 0x00, |
924 | 0x81, 0x01, |
925 | 0x81, 0x00, |
926 | 0x00, 0x09, |
927 | 0x01, 0x69, |
928 | 0x03, 0x00, |
929 | 0x04, 0x00, |
930 | 0x07, 0x00, |
931 | 0x08, 0x00, |
932 | 0x20, 0x00, |
933 | 0x21, 0x40, |
934 | 0x22, 0x00, |
935 | 0x23, 0x00, |
936 | 0x24, 0x40, |
937 | 0x25, 0x88, |
938 | 0x30, 0xff, |
939 | 0x31, 0x00, |
940 | 0x32, 0xff, |
941 | 0x33, 0x00, |
942 | 0x34, 0x50, |
943 | 0x35, 0x7f, |
944 | 0x36, 0x00, |
945 | 0x37, 0x20, |
946 | 0x38, 0x00, |
947 | 0x40, 0x1c, |
948 | 0x41, 0xff, |
949 | 0x42, 0x29, |
950 | 0x43, 0x20, |
951 | 0x44, 0xff, |
952 | 0x45, 0x00, |
953 | 0x46, 0x00, |
954 | 0x49, 0x04, |
955 | 0x4a, 0x00, |
956 | 0x4b, 0x7b, |
957 | 0x52, 0x30, |
958 | 0x55, 0xae, |
959 | 0x56, 0x47, |
960 | 0x57, 0xe1, |
961 | 0x58, 0x3a, |
962 | 0x5a, 0x1e, |
963 | 0x5b, 0x34, |
964 | 0x60, 0x00, |
965 | 0x63, 0x00, |
966 | 0x64, 0x00, |
967 | 0x65, 0x00, |
968 | 0x66, 0x00, |
969 | 0x67, 0x00, |
970 | 0x68, 0x00, |
971 | 0x69, 0x00, |
972 | 0x6a, 0x02, |
973 | 0x6b, 0x00, |
974 | 0x70, 0xff, |
975 | 0x71, 0x00, |
976 | 0x72, 0x00, |
977 | 0x73, 0x00, |
978 | 0x74, 0x0c, |
979 | 0x80, 0x00, |
980 | 0x81, 0x00, |
981 | 0x82, 0x00, |
982 | 0x83, 0x00, |
983 | 0x84, 0x04, |
984 | 0x85, 0x80, |
985 | 0x86, 0x24, |
986 | 0x87, 0x78, |
987 | 0x88, 0x10, |
988 | 0x89, 0x00, |
989 | 0x90, 0x01, |
990 | 0x91, 0x01, |
991 | 0xa0, 0x04, |
992 | 0xa1, 0x00, |
993 | 0xa2, 0x00, |
994 | 0xb0, 0x91, |
995 | 0xb1, 0x0b, |
996 | 0xc0, 0x53, |
997 | 0xc1, 0x70, |
998 | 0xc2, 0x12, |
999 | 0xd0, 0x00, |
1000 | 0xd1, 0x00, |
1001 | 0xd2, 0x00, |
1002 | 0xd3, 0x00, |
1003 | 0xd4, 0x00, |
1004 | 0xd5, 0x00, |
1005 | 0xde, 0x00, |
1006 | 0xdf, 0x00, |
1007 | 0x61, 0x38, |
1008 | 0x62, 0x0a, |
1009 | 0x53, 0x13, |
1010 | 0x59, 0x08, |
1011 | 0xff, 0xff, |
1012 | }; |
1013 | |
1014 | static struct stv0297_config dvbc_philips_tdm1316l_config = { |
1015 | .demod_address = 0x1c, |
1016 | .inittab = dvbc_philips_tdm1316l_inittab, |
1017 | .invert = 0, |
1018 | .stop_during_read = 1, |
1019 | }; |
1020 | |
1021 | static struct tda10023_config tda10023_config = { |
1022 | .demod_address = 0xc, |
1023 | .invert = 0, |
1024 | .xtal = 16000000, |
1025 | .pll_m = 11, |
1026 | .pll_p = 3, |
1027 | .pll_n = 1, |
1028 | .deltaf = 0xa511, |
1029 | }; |
1030 | |
1031 | static struct tda827x_config tda827x_config = { |
1032 | .config = 0, |
1033 | }; |
1034 | |
1035 | /* TT S2-3200 DVB-S (STB0899) Inittab */ |
1036 | static const struct stb0899_s1_reg tt3200_stb0899_s1_init_1[] = { |
1037 | |
1038 | { STB0899_DEV_ID , 0x81 }, |
1039 | { STB0899_DISCNTRL1 , 0x32 }, |
1040 | { STB0899_DISCNTRL2 , 0x80 }, |
1041 | { STB0899_DISRX_ST0 , 0x04 }, |
1042 | { STB0899_DISRX_ST1 , 0x00 }, |
1043 | { STB0899_DISPARITY , 0x00 }, |
1044 | { STB0899_DISSTATUS , 0x20 }, |
1045 | { STB0899_DISF22 , 0x8c }, |
1046 | { STB0899_DISF22RX , 0x9a }, |
1047 | { STB0899_SYSREG , 0x0b }, |
1048 | { STB0899_ACRPRESC , 0x11 }, |
1049 | { STB0899_ACRDIV1 , 0x0a }, |
1050 | { STB0899_ACRDIV2 , 0x05 }, |
1051 | { STB0899_DACR1 , 0x00 }, |
1052 | { STB0899_DACR2 , 0x00 }, |
1053 | { STB0899_OUTCFG , 0x00 }, |
1054 | { STB0899_MODECFG , 0x00 }, |
1055 | { STB0899_IRQSTATUS_3 , 0x30 }, |
1056 | { STB0899_IRQSTATUS_2 , 0x00 }, |
1057 | { STB0899_IRQSTATUS_1 , 0x00 }, |
1058 | { STB0899_IRQSTATUS_0 , 0x00 }, |
1059 | { STB0899_IRQMSK_3 , 0xf3 }, |
1060 | { STB0899_IRQMSK_2 , 0xfc }, |
1061 | { STB0899_IRQMSK_1 , 0xff }, |
1062 | { STB0899_IRQMSK_0 , 0xff }, |
1063 | { STB0899_IRQCFG , 0x00 }, |
1064 | { STB0899_I2CCFG , 0x88 }, |
1065 | { STB0899_I2CRPT , 0x48 }, /* 12k Pullup, Repeater=16, Stop=disabled */ |
1066 | { STB0899_IOPVALUE5 , 0x00 }, |
1067 | { STB0899_IOPVALUE4 , 0x20 }, |
1068 | { STB0899_IOPVALUE3 , 0xc9 }, |
1069 | { STB0899_IOPVALUE2 , 0x90 }, |
1070 | { STB0899_IOPVALUE1 , 0x40 }, |
1071 | { STB0899_IOPVALUE0 , 0x00 }, |
1072 | { STB0899_GPIO00CFG , 0x82 }, |
1073 | { STB0899_GPIO01CFG , 0x82 }, |
1074 | { STB0899_GPIO02CFG , 0x82 }, |
1075 | { STB0899_GPIO03CFG , 0x82 }, |
1076 | { STB0899_GPIO04CFG , 0x82 }, |
1077 | { STB0899_GPIO05CFG , 0x82 }, |
1078 | { STB0899_GPIO06CFG , 0x82 }, |
1079 | { STB0899_GPIO07CFG , 0x82 }, |
1080 | { STB0899_GPIO08CFG , 0x82 }, |
1081 | { STB0899_GPIO09CFG , 0x82 }, |
1082 | { STB0899_GPIO10CFG , 0x82 }, |
1083 | { STB0899_GPIO11CFG , 0x82 }, |
1084 | { STB0899_GPIO12CFG , 0x82 }, |
1085 | { STB0899_GPIO13CFG , 0x82 }, |
1086 | { STB0899_GPIO14CFG , 0x82 }, |
1087 | { STB0899_GPIO15CFG , 0x82 }, |
1088 | { STB0899_GPIO16CFG , 0x82 }, |
1089 | { STB0899_GPIO17CFG , 0x82 }, |
1090 | { STB0899_GPIO18CFG , 0x82 }, |
1091 | { STB0899_GPIO19CFG , 0x82 }, |
1092 | { STB0899_GPIO20CFG , 0x82 }, |
1093 | { STB0899_SDATCFG , 0xb8 }, |
1094 | { STB0899_SCLTCFG , 0xba }, |
1095 | { STB0899_AGCRFCFG , 0x1c }, /* 0x11 */ |
1096 | { STB0899_GPIO22 , 0x82 }, /* AGCBB2CFG */ |
1097 | { STB0899_GPIO21 , 0x91 }, /* AGCBB1CFG */ |
1098 | { STB0899_DIRCLKCFG , 0x82 }, |
1099 | { STB0899_CLKOUT27CFG , 0x7e }, |
1100 | { STB0899_STDBYCFG , 0x82 }, |
1101 | { STB0899_CS0CFG , 0x82 }, |
1102 | { STB0899_CS1CFG , 0x82 }, |
1103 | { STB0899_DISEQCOCFG , 0x20 }, |
1104 | { STB0899_GPIO32CFG , 0x82 }, |
1105 | { STB0899_GPIO33CFG , 0x82 }, |
1106 | { STB0899_GPIO34CFG , 0x82 }, |
1107 | { STB0899_GPIO35CFG , 0x82 }, |
1108 | { STB0899_GPIO36CFG , 0x82 }, |
1109 | { STB0899_GPIO37CFG , 0x82 }, |
1110 | { STB0899_GPIO38CFG , 0x82 }, |
1111 | { STB0899_GPIO39CFG , 0x82 }, |
1112 | { STB0899_NCOARSE , 0x15 }, /* 0x15 = 27 Mhz Clock, F/3 = 198MHz, F/6 = 99MHz */ |
1113 | { STB0899_SYNTCTRL , 0x02 }, /* 0x00 = CLK from CLKI, 0x02 = CLK from XTALI */ |
1114 | { STB0899_FILTCTRL , 0x00 }, |
1115 | { STB0899_SYSCTRL , 0x00 }, |
1116 | { STB0899_STOPCLK1 , 0x20 }, |
1117 | { STB0899_STOPCLK2 , 0x00 }, |
1118 | { STB0899_INTBUFSTATUS , 0x00 }, |
1119 | { STB0899_INTBUFCTRL , 0x0a }, |
1120 | { 0xffff , 0xff }, |
1121 | }; |
1122 | |
1123 | static const struct stb0899_s1_reg tt3200_stb0899_s1_init_3[] = { |
1124 | { STB0899_DEMOD , 0x00 }, |
1125 | { STB0899_RCOMPC , 0xc9 }, |
1126 | { STB0899_AGC1CN , 0x41 }, |
1127 | { STB0899_AGC1REF , 0x10 }, |
1128 | { STB0899_RTC , 0x7a }, |
1129 | { STB0899_TMGCFG , 0x4e }, |
1130 | { STB0899_AGC2REF , 0x34 }, |
1131 | { STB0899_TLSR , 0x84 }, |
1132 | { STB0899_CFD , 0xc7 }, |
1133 | { STB0899_ACLC , 0x87 }, |
1134 | { STB0899_BCLC , 0x94 }, |
1135 | { STB0899_EQON , 0x41 }, |
1136 | { STB0899_LDT , 0xdd }, |
1137 | { STB0899_LDT2 , 0xc9 }, |
1138 | { STB0899_EQUALREF , 0xb4 }, |
1139 | { STB0899_TMGRAMP , 0x10 }, |
1140 | { STB0899_TMGTHD , 0x30 }, |
1141 | { STB0899_IDCCOMP , 0xfb }, |
1142 | { STB0899_QDCCOMP , 0x03 }, |
1143 | { STB0899_POWERI , 0x3b }, |
1144 | { STB0899_POWERQ , 0x3d }, |
1145 | { STB0899_RCOMP , 0x81 }, |
1146 | { STB0899_AGCIQIN , 0x80 }, |
1147 | { STB0899_AGC2I1 , 0x04 }, |
1148 | { STB0899_AGC2I2 , 0xf5 }, |
1149 | { STB0899_TLIR , 0x25 }, |
1150 | { STB0899_RTF , 0x80 }, |
1151 | { STB0899_DSTATUS , 0x00 }, |
1152 | { STB0899_LDI , 0xca }, |
1153 | { STB0899_CFRM , 0xf1 }, |
1154 | { STB0899_CFRL , 0xf3 }, |
1155 | { STB0899_NIRM , 0x2a }, |
1156 | { STB0899_NIRL , 0x05 }, |
1157 | { STB0899_ISYMB , 0x17 }, |
1158 | { STB0899_QSYMB , 0xfa }, |
1159 | { STB0899_SFRH , 0x2f }, |
1160 | { STB0899_SFRM , 0x68 }, |
1161 | { STB0899_SFRL , 0x40 }, |
1162 | { STB0899_SFRUPH , 0x2f }, |
1163 | { STB0899_SFRUPM , 0x68 }, |
1164 | { STB0899_SFRUPL , 0x40 }, |
1165 | { STB0899_EQUAI1 , 0xfd }, |
1166 | { STB0899_EQUAQ1 , 0x04 }, |
1167 | { STB0899_EQUAI2 , 0x0f }, |
1168 | { STB0899_EQUAQ2 , 0xff }, |
1169 | { STB0899_EQUAI3 , 0xdf }, |
1170 | { STB0899_EQUAQ3 , 0xfa }, |
1171 | { STB0899_EQUAI4 , 0x37 }, |
1172 | { STB0899_EQUAQ4 , 0x0d }, |
1173 | { STB0899_EQUAI5 , 0xbd }, |
1174 | { STB0899_EQUAQ5 , 0xf7 }, |
1175 | { STB0899_DSTATUS2 , 0x00 }, |
1176 | { STB0899_VSTATUS , 0x00 }, |
1177 | { STB0899_VERROR , 0xff }, |
1178 | { STB0899_IQSWAP , 0x2a }, |
1179 | { STB0899_ECNT1M , 0x00 }, |
1180 | { STB0899_ECNT1L , 0x00 }, |
1181 | { STB0899_ECNT2M , 0x00 }, |
1182 | { STB0899_ECNT2L , 0x00 }, |
1183 | { STB0899_ECNT3M , 0x00 }, |
1184 | { STB0899_ECNT3L , 0x00 }, |
1185 | { STB0899_FECAUTO1 , 0x06 }, |
1186 | { STB0899_FECM , 0x01 }, |
1187 | { STB0899_VTH12 , 0xf0 }, |
1188 | { STB0899_VTH23 , 0xa0 }, |
1189 | { STB0899_VTH34 , 0x78 }, |
1190 | { STB0899_VTH56 , 0x4e }, |
1191 | { STB0899_VTH67 , 0x48 }, |
1192 | { STB0899_VTH78 , 0x38 }, |
1193 | { STB0899_PRVIT , 0xff }, |
1194 | { STB0899_VITSYNC , 0x19 }, |
1195 | { STB0899_RSULC , 0xb1 }, /* DVB = 0xb1, DSS = 0xa1 */ |
1196 | { STB0899_TSULC , 0x42 }, |
1197 | { STB0899_RSLLC , 0x40 }, |
1198 | { STB0899_TSLPL , 0x12 }, |
1199 | { STB0899_TSCFGH , 0x0c }, |
1200 | { STB0899_TSCFGM , 0x00 }, |
1201 | { STB0899_TSCFGL , 0x0c }, |
1202 | { STB0899_TSOUT , 0x4d }, /* 0x0d for CAM */ |
1203 | { STB0899_RSSYNCDEL , 0x00 }, |
1204 | { STB0899_TSINHDELH , 0x02 }, |
1205 | { STB0899_TSINHDELM , 0x00 }, |
1206 | { STB0899_TSINHDELL , 0x00 }, |
1207 | { STB0899_TSLLSTKM , 0x00 }, |
1208 | { STB0899_TSLLSTKL , 0x00 }, |
1209 | { STB0899_TSULSTKM , 0x00 }, |
1210 | { STB0899_TSULSTKL , 0xab }, |
1211 | { STB0899_PCKLENUL , 0x00 }, |
1212 | { STB0899_PCKLENLL , 0xcc }, |
1213 | { STB0899_RSPCKLEN , 0xcc }, |
1214 | { STB0899_TSSTATUS , 0x80 }, |
1215 | { STB0899_ERRCTRL1 , 0xb6 }, |
1216 | { STB0899_ERRCTRL2 , 0x96 }, |
1217 | { STB0899_ERRCTRL3 , 0x89 }, |
1218 | { STB0899_DMONMSK1 , 0x27 }, |
1219 | { STB0899_DMONMSK0 , 0x03 }, |
1220 | { STB0899_DEMAPVIT , 0x5c }, |
1221 | { STB0899_PLPARM , 0x1f }, |
1222 | { STB0899_PDELCTRL , 0x48 }, |
1223 | { STB0899_PDELCTRL2 , 0x00 }, |
1224 | { STB0899_BBHCTRL1 , 0x00 }, |
1225 | { STB0899_BBHCTRL2 , 0x00 }, |
1226 | { STB0899_HYSTTHRESH , 0x77 }, |
1227 | { STB0899_MATCSTM , 0x00 }, |
1228 | { STB0899_MATCSTL , 0x00 }, |
1229 | { STB0899_UPLCSTM , 0x00 }, |
1230 | { STB0899_UPLCSTL , 0x00 }, |
1231 | { STB0899_DFLCSTM , 0x00 }, |
1232 | { STB0899_DFLCSTL , 0x00 }, |
1233 | { STB0899_SYNCCST , 0x00 }, |
1234 | { STB0899_SYNCDCSTM , 0x00 }, |
1235 | { STB0899_SYNCDCSTL , 0x00 }, |
1236 | { STB0899_ISI_ENTRY , 0x00 }, |
1237 | { STB0899_ISI_BIT_EN , 0x00 }, |
1238 | { STB0899_MATSTRM , 0x00 }, |
1239 | { STB0899_MATSTRL , 0x00 }, |
1240 | { STB0899_UPLSTRM , 0x00 }, |
1241 | { STB0899_UPLSTRL , 0x00 }, |
1242 | { STB0899_DFLSTRM , 0x00 }, |
1243 | { STB0899_DFLSTRL , 0x00 }, |
1244 | { STB0899_SYNCSTR , 0x00 }, |
1245 | { STB0899_SYNCDSTRM , 0x00 }, |
1246 | { STB0899_SYNCDSTRL , 0x00 }, |
1247 | { STB0899_CFGPDELSTATUS1 , 0x10 }, |
1248 | { STB0899_CFGPDELSTATUS2 , 0x00 }, |
1249 | { STB0899_BBFERRORM , 0x00 }, |
1250 | { STB0899_BBFERRORL , 0x00 }, |
1251 | { STB0899_UPKTERRORM , 0x00 }, |
1252 | { STB0899_UPKTERRORL , 0x00 }, |
1253 | { 0xffff , 0xff }, |
1254 | }; |
1255 | |
1256 | static struct stb0899_config tt3200_config = { |
1257 | .init_dev = tt3200_stb0899_s1_init_1, |
1258 | .init_s2_demod = stb0899_s2_init_2, |
1259 | .init_s1_demod = tt3200_stb0899_s1_init_3, |
1260 | .init_s2_fec = stb0899_s2_init_4, |
1261 | .init_tst = stb0899_s1_init_5, |
1262 | |
1263 | .postproc = NULL, |
1264 | |
1265 | .demod_address = 0x68, |
1266 | |
1267 | .xtal_freq = 27000000, |
1268 | .inversion = IQ_SWAP_ON, |
1269 | |
1270 | .lo_clk = 76500000, |
1271 | .hi_clk = 99000000, |
1272 | |
1273 | .esno_ave = STB0899_DVBS2_ESNO_AVE, |
1274 | .esno_quant = STB0899_DVBS2_ESNO_QUANT, |
1275 | .avframes_coarse = STB0899_DVBS2_AVFRAMES_COARSE, |
1276 | .avframes_fine = STB0899_DVBS2_AVFRAMES_FINE, |
1277 | .miss_threshold = STB0899_DVBS2_MISS_THRESHOLD, |
1278 | .uwp_threshold_acq = STB0899_DVBS2_UWP_THRESHOLD_ACQ, |
1279 | .uwp_threshold_track = STB0899_DVBS2_UWP_THRESHOLD_TRACK, |
1280 | .uwp_threshold_sof = STB0899_DVBS2_UWP_THRESHOLD_SOF, |
1281 | .sof_search_timeout = STB0899_DVBS2_SOF_SEARCH_TIMEOUT, |
1282 | |
1283 | .btr_nco_bits = STB0899_DVBS2_BTR_NCO_BITS, |
1284 | .btr_gain_shift_offset = STB0899_DVBS2_BTR_GAIN_SHIFT_OFFSET, |
1285 | .crl_nco_bits = STB0899_DVBS2_CRL_NCO_BITS, |
1286 | .ldpc_max_iter = STB0899_DVBS2_LDPC_MAX_ITER, |
1287 | |
1288 | .tuner_get_frequency = stb6100_get_frequency, |
1289 | .tuner_set_frequency = stb6100_set_frequency, |
1290 | .tuner_set_bandwidth = stb6100_set_bandwidth, |
1291 | .tuner_get_bandwidth = stb6100_get_bandwidth, |
1292 | .tuner_set_rfsiggain = NULL |
1293 | }; |
1294 | |
1295 | static struct stb6100_config tt3200_stb6100_config = { |
1296 | .tuner_address = 0x60, |
1297 | .refclock = 27000000, |
1298 | }; |
1299 | |
1300 | static void frontend_init(struct budget_ci *budget_ci) |
1301 | { |
1302 | switch (budget_ci->budget.dev->pci->subsystem_device) { |
1303 | case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059)) |
1304 | budget_ci->budget.dvb_frontend = |
1305 | dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap); |
1306 | if (budget_ci->budget.dvb_frontend) { |
1307 | budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; |
1308 | budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; |
1309 | break; |
1310 | } |
1311 | break; |
1312 | |
1313 | case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059)) |
1314 | budget_ci->budget.dvb_frontend = |
1315 | dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap); |
1316 | if (budget_ci->budget.dvb_frontend) { |
1317 | budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params; |
1318 | break; |
1319 | } |
1320 | break; |
1321 | |
1322 | case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt)) |
1323 | budget_ci->tuner_pll_address = 0x61; |
1324 | budget_ci->budget.dvb_frontend = |
1325 | dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); |
1326 | if (budget_ci->budget.dvb_frontend) { |
1327 | budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; |
1328 | break; |
1329 | } |
1330 | break; |
1331 | |
1332 | case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889) |
1333 | budget_ci->tuner_pll_address = 0x63; |
1334 | budget_ci->budget.dvb_frontend = |
1335 | dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap); |
1336 | if (budget_ci->budget.dvb_frontend) { |
1337 | budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; |
1338 | budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; |
1339 | break; |
1340 | } |
1341 | break; |
1342 | |
1343 | case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt)) |
1344 | budget_ci->tuner_pll_address = 0x60; |
1345 | budget_ci->budget.dvb_frontend = |
1346 | dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap); |
1347 | if (budget_ci->budget.dvb_frontend) { |
1348 | budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; |
1349 | budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; |
1350 | break; |
1351 | } |
1352 | break; |
1353 | |
1354 | case 0x1017: // TT S-1500 PCI |
1355 | budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap); |
1356 | if (budget_ci->budget.dvb_frontend) { |
1357 | budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; |
1358 | budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; |
1359 | |
1360 | budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; |
1361 | if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) { |
1362 | printk("%s: No LNBP21 found!\n" , __func__); |
1363 | dvb_frontend_detach(fe: budget_ci->budget.dvb_frontend); |
1364 | budget_ci->budget.dvb_frontend = NULL; |
1365 | } |
1366 | } |
1367 | break; |
1368 | |
1369 | case 0x101a: /* TT Budget-C-1501 (philips tda10023/philips tda8274A) */ |
1370 | budget_ci->budget.dvb_frontend = dvb_attach(tda10023_attach, &tda10023_config, &budget_ci->budget.i2c_adap, 0x48); |
1371 | if (budget_ci->budget.dvb_frontend) { |
1372 | if (dvb_attach(tda827x_attach, budget_ci->budget.dvb_frontend, 0x61, &budget_ci->budget.i2c_adap, &tda827x_config) == NULL) { |
1373 | printk(KERN_ERR "%s: No tda827x found!\n" , __func__); |
1374 | dvb_frontend_detach(fe: budget_ci->budget.dvb_frontend); |
1375 | budget_ci->budget.dvb_frontend = NULL; |
1376 | } |
1377 | } |
1378 | break; |
1379 | |
1380 | case 0x101b: /* TT S-1500B (BSBE1-D01A - STV0288/STB6000/LNBP21) */ |
1381 | budget_ci->budget.dvb_frontend = dvb_attach(stv0288_attach, &stv0288_bsbe1_d01a_config, &budget_ci->budget.i2c_adap); |
1382 | if (budget_ci->budget.dvb_frontend) { |
1383 | if (dvb_attach(stb6000_attach, budget_ci->budget.dvb_frontend, 0x63, &budget_ci->budget.i2c_adap)) { |
1384 | if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { |
1385 | printk(KERN_ERR "%s: No LNBP21 found!\n" , __func__); |
1386 | dvb_frontend_detach(fe: budget_ci->budget.dvb_frontend); |
1387 | budget_ci->budget.dvb_frontend = NULL; |
1388 | } |
1389 | } else { |
1390 | printk(KERN_ERR "%s: No STB6000 found!\n" , __func__); |
1391 | dvb_frontend_detach(fe: budget_ci->budget.dvb_frontend); |
1392 | budget_ci->budget.dvb_frontend = NULL; |
1393 | } |
1394 | } |
1395 | break; |
1396 | |
1397 | case 0x1019: // TT S2-3200 PCI |
1398 | /* |
1399 | * NOTE! on some STB0899 versions, the internal PLL takes a longer time |
1400 | * to settle, aka LOCK. On the older revisions of the chip, we don't see |
1401 | * this, as a result on the newer chips the entire clock tree, will not |
1402 | * be stable after a freshly POWER 'ed up situation. |
1403 | * In this case, we should RESET the STB0899 (Active LOW) and wait for |
1404 | * PLL stabilization. |
1405 | * |
1406 | * On the TT S2 3200 and clones, the STB0899 demodulator's RESETB is |
1407 | * connected to the SAA7146 GPIO, GPIO2, Pin 142 |
1408 | */ |
1409 | /* Reset Demodulator */ |
1410 | saa7146_setgpio(dev: budget_ci->budget.dev, port: 2, SAA7146_GPIO_OUTLO); |
1411 | /* Wait for everything to die */ |
1412 | msleep(msecs: 50); |
1413 | /* Pull it up out of Reset state */ |
1414 | saa7146_setgpio(dev: budget_ci->budget.dev, port: 2, SAA7146_GPIO_OUTHI); |
1415 | /* Wait for PLL to stabilize */ |
1416 | msleep(msecs: 250); |
1417 | /* |
1418 | * PLL state should be stable now. Ideally, we should check |
1419 | * for PLL LOCK status. But well, never mind! |
1420 | */ |
1421 | budget_ci->budget.dvb_frontend = dvb_attach(stb0899_attach, &tt3200_config, &budget_ci->budget.i2c_adap); |
1422 | if (budget_ci->budget.dvb_frontend) { |
1423 | if (dvb_attach(stb6100_attach, budget_ci->budget.dvb_frontend, &tt3200_stb6100_config, &budget_ci->budget.i2c_adap)) { |
1424 | if (!dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, 0, 0)) { |
1425 | printk("%s: No LNBP21 found!\n" , __func__); |
1426 | dvb_frontend_detach(fe: budget_ci->budget.dvb_frontend); |
1427 | budget_ci->budget.dvb_frontend = NULL; |
1428 | } |
1429 | } else { |
1430 | dvb_frontend_detach(fe: budget_ci->budget.dvb_frontend); |
1431 | budget_ci->budget.dvb_frontend = NULL; |
1432 | } |
1433 | } |
1434 | break; |
1435 | |
1436 | } |
1437 | |
1438 | if (budget_ci->budget.dvb_frontend == NULL) { |
1439 | printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n" , |
1440 | budget_ci->budget.dev->pci->vendor, |
1441 | budget_ci->budget.dev->pci->device, |
1442 | budget_ci->budget.dev->pci->subsystem_vendor, |
1443 | budget_ci->budget.dev->pci->subsystem_device); |
1444 | } else { |
1445 | if (dvb_register_frontend |
1446 | (dvb: &budget_ci->budget.dvb_adapter, fe: budget_ci->budget.dvb_frontend)) { |
1447 | printk("budget-ci: Frontend registration failed!\n" ); |
1448 | dvb_frontend_detach(fe: budget_ci->budget.dvb_frontend); |
1449 | budget_ci->budget.dvb_frontend = NULL; |
1450 | } |
1451 | } |
1452 | } |
1453 | |
1454 | static int budget_ci_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info) |
1455 | { |
1456 | struct budget_ci *budget_ci; |
1457 | int err; |
1458 | |
1459 | budget_ci = kzalloc(size: sizeof(struct budget_ci), GFP_KERNEL); |
1460 | if (!budget_ci) { |
1461 | err = -ENOMEM; |
1462 | goto out1; |
1463 | } |
1464 | |
1465 | dprintk(2, "budget_ci: %p\n" , budget_ci); |
1466 | |
1467 | dev->ext_priv = budget_ci; |
1468 | |
1469 | err = ttpci_budget_init(budget: &budget_ci->budget, dev, info, THIS_MODULE, |
1470 | adapter_nums: adapter_nr); |
1471 | if (err) |
1472 | goto out2; |
1473 | |
1474 | err = msp430_ir_init(budget_ci); |
1475 | if (err) |
1476 | goto out3; |
1477 | |
1478 | ciintf_init(budget_ci); |
1479 | |
1480 | budget_ci->budget.dvb_adapter.priv = budget_ci; |
1481 | frontend_init(budget_ci); |
1482 | |
1483 | ttpci_budget_init_hooks(budget: &budget_ci->budget); |
1484 | |
1485 | return 0; |
1486 | |
1487 | out3: |
1488 | ttpci_budget_deinit(budget: &budget_ci->budget); |
1489 | out2: |
1490 | kfree(objp: budget_ci); |
1491 | out1: |
1492 | return err; |
1493 | } |
1494 | |
1495 | static int budget_ci_detach(struct saa7146_dev *dev) |
1496 | { |
1497 | struct budget_ci *budget_ci = dev->ext_priv; |
1498 | struct saa7146_dev *saa = budget_ci->budget.dev; |
1499 | int err; |
1500 | |
1501 | if (budget_ci->budget.ci_present) |
1502 | ciintf_deinit(budget_ci); |
1503 | msp430_ir_deinit(budget_ci); |
1504 | if (budget_ci->budget.dvb_frontend) { |
1505 | dvb_unregister_frontend(fe: budget_ci->budget.dvb_frontend); |
1506 | dvb_frontend_detach(fe: budget_ci->budget.dvb_frontend); |
1507 | } |
1508 | err = ttpci_budget_deinit(budget: &budget_ci->budget); |
1509 | |
1510 | // disable frontend and CI interface |
1511 | saa7146_setgpio(dev: saa, port: 2, SAA7146_GPIO_INPUT); |
1512 | |
1513 | kfree(objp: budget_ci); |
1514 | |
1515 | return err; |
1516 | } |
1517 | |
1518 | static struct saa7146_extension budget_extension; |
1519 | |
1520 | MAKE_BUDGET_INFO(ttbs2, "TT-Budget/S-1500 PCI" , BUDGET_TT); |
1521 | MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI" , BUDGET_TT_HW_DISEQC); |
1522 | MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI" , BUDGET_TT); |
1523 | MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI" , BUDGET_TT); |
1524 | MAKE_BUDGET_INFO(ttbcci, "TT-Budget-C-CI PCI" , BUDGET_TT); |
1525 | MAKE_BUDGET_INFO(ttc1501, "TT-Budget C-1501 PCI" , BUDGET_TT); |
1526 | MAKE_BUDGET_INFO(tt3200, "TT-Budget S2-3200 PCI" , BUDGET_TT); |
1527 | MAKE_BUDGET_INFO(ttbs1500b, "TT-Budget S-1500B PCI" , BUDGET_TT); |
1528 | |
1529 | static const struct pci_device_id pci_tbl[] = { |
1530 | MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c), |
1531 | MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f), |
1532 | MAKE_EXTENSION_PCI(ttbcci, 0x13c2, 0x1010), |
1533 | MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011), |
1534 | MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012), |
1535 | MAKE_EXTENSION_PCI(ttbs2, 0x13c2, 0x1017), |
1536 | MAKE_EXTENSION_PCI(ttc1501, 0x13c2, 0x101a), |
1537 | MAKE_EXTENSION_PCI(tt3200, 0x13c2, 0x1019), |
1538 | MAKE_EXTENSION_PCI(ttbs1500b, 0x13c2, 0x101b), |
1539 | { |
1540 | .vendor = 0, |
1541 | } |
1542 | }; |
1543 | |
1544 | MODULE_DEVICE_TABLE(pci, pci_tbl); |
1545 | |
1546 | static struct saa7146_extension budget_extension = { |
1547 | .name = "budget_ci dvb" , |
1548 | .flags = SAA7146_USE_I2C_IRQ, |
1549 | |
1550 | .module = THIS_MODULE, |
1551 | .pci_tbl = &pci_tbl[0], |
1552 | .attach = budget_ci_attach, |
1553 | .detach = budget_ci_detach, |
1554 | |
1555 | .irq_mask = MASK_03 | MASK_06 | MASK_10, |
1556 | .irq_func = budget_ci_irq, |
1557 | }; |
1558 | |
1559 | static int __init budget_ci_init(void) |
1560 | { |
1561 | return saa7146_register_extension(&budget_extension); |
1562 | } |
1563 | |
1564 | static void __exit budget_ci_exit(void) |
1565 | { |
1566 | saa7146_unregister_extension(&budget_extension); |
1567 | } |
1568 | |
1569 | module_init(budget_ci_init); |
1570 | module_exit(budget_ci_exit); |
1571 | |
1572 | MODULE_LICENSE("GPL" ); |
1573 | MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others" ); |
1574 | MODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB cards w/ CI-module produced by Siemens, Technotrend, Hauppauge" ); |
1575 | |