2 * tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
4 * Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation version 2
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <linux/init.h>
17 #include <linux/module.h>
18 #include <linux/pci.h>
19 #include <linux/delay.h>
20 #include <linux/i2c.h>
21 #include <linux/usb.h>
22 #include <linux/slab.h>
23 #include <media/v4l2-common.h>
24 #include <media/tuner.h>
25 #include <media/i2c/tvaudio.h>
26 #include <media/i2c-addr.h>
27 #include <media/rc-map.h>
30 #include "tm6000-regs.h"
31 #include "tuner-xc2028.h"
34 #define TM6000_BOARD_UNKNOWN 0
35 #define TM5600_BOARD_GENERIC 1
36 #define TM6000_BOARD_GENERIC 2
37 #define TM6010_BOARD_GENERIC 3
38 #define TM5600_BOARD_10MOONS_UT821 4
39 #define TM5600_BOARD_10MOONS_UT330 5
40 #define TM6000_BOARD_ADSTECH_DUAL_TV 6
41 #define TM6000_BOARD_FREECOM_AND_SIMILAR 7
42 #define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8
43 #define TM6010_BOARD_HAUPPAUGE_900H 9
44 #define TM6010_BOARD_BEHOLD_WANDER 10
45 #define TM6010_BOARD_BEHOLD_VOYAGER 11
46 #define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12
47 #define TM6010_BOARD_TWINHAN_TU501 13
48 #define TM6010_BOARD_BEHOLD_WANDER_LITE 14
49 #define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15
50 #define TM5600_BOARD_TERRATEC_GRABSTER 16
52 #define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
53 (model == TM5600_BOARD_GENERIC) || \
54 (model == TM6000_BOARD_GENERIC) || \
55 (model == TM6010_BOARD_GENERIC))
57 #define TM6000_MAXBOARDS 16
58 static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
60 module_param_array(card, int, NULL, 0444);
62 static unsigned long tm6000_devused;
67 char eename[16]; /* EEPROM name */
68 unsigned eename_size; /* size of EEPROM name */
69 unsigned eename_pos; /* Position where it appears at ROM */
71 struct tm6000_capabilities caps;
73 enum tm6000_devtype type; /* variant of the chipset */
74 int tuner_type; /* type of the tuner */
75 int tuner_addr; /* tuner address */
76 int demod_addr; /* demodulator address */
78 struct tm6000_gpio gpio;
80 struct tm6000_input vinput[3];
81 struct tm6000_input rinput;
86 static struct tm6000_board tm6000_boards[] = {
87 [TM6000_BOARD_UNKNOWN] = {
88 .name = "Unknown tm6000 video grabber",
94 .tuner_reset = TM6000_GPIO_1,
97 .type = TM6000_INPUT_TV,
98 .vmux = TM6000_VMUX_VIDEO_B,
99 .amux = TM6000_AMUX_ADC1,
101 .type = TM6000_INPUT_COMPOSITE1,
102 .vmux = TM6000_VMUX_VIDEO_A,
103 .amux = TM6000_AMUX_ADC2,
105 .type = TM6000_INPUT_SVIDEO,
106 .vmux = TM6000_VMUX_VIDEO_AB,
107 .amux = TM6000_AMUX_ADC2,
111 [TM5600_BOARD_GENERIC] = {
112 .name = "Generic tm5600 board",
114 .tuner_type = TUNER_XC2028,
115 .tuner_addr = 0xc2 >> 1,
121 .tuner_reset = TM6000_GPIO_1,
124 .type = TM6000_INPUT_TV,
125 .vmux = TM6000_VMUX_VIDEO_B,
126 .amux = TM6000_AMUX_ADC1,
128 .type = TM6000_INPUT_COMPOSITE1,
129 .vmux = TM6000_VMUX_VIDEO_A,
130 .amux = TM6000_AMUX_ADC2,
132 .type = TM6000_INPUT_SVIDEO,
133 .vmux = TM6000_VMUX_VIDEO_AB,
134 .amux = TM6000_AMUX_ADC2,
138 [TM6000_BOARD_GENERIC] = {
139 .name = "Generic tm6000 board",
140 .tuner_type = TUNER_XC2028,
141 .tuner_addr = 0xc2 >> 1,
147 .tuner_reset = TM6000_GPIO_1,
150 .type = TM6000_INPUT_TV,
151 .vmux = TM6000_VMUX_VIDEO_B,
152 .amux = TM6000_AMUX_ADC1,
154 .type = TM6000_INPUT_COMPOSITE1,
155 .vmux = TM6000_VMUX_VIDEO_A,
156 .amux = TM6000_AMUX_ADC2,
158 .type = TM6000_INPUT_SVIDEO,
159 .vmux = TM6000_VMUX_VIDEO_AB,
160 .amux = TM6000_AMUX_ADC2,
164 [TM6010_BOARD_GENERIC] = {
165 .name = "Generic tm6010 board",
167 .tuner_type = TUNER_XC2028,
168 .tuner_addr = 0xc2 >> 1,
169 .demod_addr = 0x1e >> 1,
178 .tuner_reset = TM6010_GPIO_2,
179 .tuner_on = TM6010_GPIO_3,
180 .demod_reset = TM6010_GPIO_1,
181 .demod_on = TM6010_GPIO_4,
182 .power_led = TM6010_GPIO_7,
183 .dvb_led = TM6010_GPIO_5,
187 .type = TM6000_INPUT_TV,
188 .vmux = TM6000_VMUX_VIDEO_B,
189 .amux = TM6000_AMUX_SIF1,
191 .type = TM6000_INPUT_COMPOSITE1,
192 .vmux = TM6000_VMUX_VIDEO_A,
193 .amux = TM6000_AMUX_ADC2,
195 .type = TM6000_INPUT_SVIDEO,
196 .vmux = TM6000_VMUX_VIDEO_AB,
197 .amux = TM6000_AMUX_ADC2,
201 [TM5600_BOARD_10MOONS_UT821] = {
202 .name = "10Moons UT 821",
203 .tuner_type = TUNER_XC2028,
204 .eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
208 .tuner_addr = 0xc2 >> 1,
214 .tuner_reset = TM6000_GPIO_1,
217 .type = TM6000_INPUT_TV,
218 .vmux = TM6000_VMUX_VIDEO_B,
219 .amux = TM6000_AMUX_ADC1,
221 .type = TM6000_INPUT_COMPOSITE1,
222 .vmux = TM6000_VMUX_VIDEO_A,
223 .amux = TM6000_AMUX_ADC2,
225 .type = TM6000_INPUT_SVIDEO,
226 .vmux = TM6000_VMUX_VIDEO_AB,
227 .amux = TM6000_AMUX_ADC2,
231 [TM5600_BOARD_10MOONS_UT330] = {
232 .name = "10Moons UT 330",
233 .tuner_type = TUNER_PHILIPS_FQ1216AME_MK4,
234 .tuner_addr = 0xc8 >> 1,
242 .type = TM6000_INPUT_TV,
243 .vmux = TM6000_VMUX_VIDEO_B,
244 .amux = TM6000_AMUX_ADC1,
246 .type = TM6000_INPUT_COMPOSITE1,
247 .vmux = TM6000_VMUX_VIDEO_A,
248 .amux = TM6000_AMUX_ADC2,
250 .type = TM6000_INPUT_SVIDEO,
251 .vmux = TM6000_VMUX_VIDEO_AB,
252 .amux = TM6000_AMUX_ADC2,
256 [TM6000_BOARD_ADSTECH_DUAL_TV] = {
257 .name = "ADSTECH Dual TV USB",
258 .tuner_type = TUNER_XC2028,
259 .tuner_addr = 0xc8 >> 1,
268 .type = TM6000_INPUT_TV,
269 .vmux = TM6000_VMUX_VIDEO_B,
270 .amux = TM6000_AMUX_ADC1,
272 .type = TM6000_INPUT_COMPOSITE1,
273 .vmux = TM6000_VMUX_VIDEO_A,
274 .amux = TM6000_AMUX_ADC2,
276 .type = TM6000_INPUT_SVIDEO,
277 .vmux = TM6000_VMUX_VIDEO_AB,
278 .amux = TM6000_AMUX_ADC2,
282 [TM6000_BOARD_FREECOM_AND_SIMILAR] = {
283 .name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
284 .tuner_type = TUNER_XC2028, /* has a XC3028 */
285 .tuner_addr = 0xc2 >> 1,
286 .demod_addr = 0x1e >> 1,
295 .tuner_reset = TM6000_GPIO_4,
298 .type = TM6000_INPUT_TV,
299 .vmux = TM6000_VMUX_VIDEO_B,
300 .amux = TM6000_AMUX_ADC1,
302 .type = TM6000_INPUT_COMPOSITE1,
303 .vmux = TM6000_VMUX_VIDEO_A,
304 .amux = TM6000_AMUX_ADC2,
306 .type = TM6000_INPUT_SVIDEO,
307 .vmux = TM6000_VMUX_VIDEO_AB,
308 .amux = TM6000_AMUX_ADC2,
312 [TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
313 .name = "ADSTECH Mini Dual TV USB",
314 .tuner_type = TUNER_XC2028, /* has a XC3028 */
315 .tuner_addr = 0xc8 >> 1,
316 .demod_addr = 0x1e >> 1,
324 .tuner_reset = TM6000_GPIO_4,
327 .type = TM6000_INPUT_TV,
328 .vmux = TM6000_VMUX_VIDEO_B,
329 .amux = TM6000_AMUX_ADC1,
331 .type = TM6000_INPUT_COMPOSITE1,
332 .vmux = TM6000_VMUX_VIDEO_A,
333 .amux = TM6000_AMUX_ADC2,
335 .type = TM6000_INPUT_SVIDEO,
336 .vmux = TM6000_VMUX_VIDEO_AB,
337 .amux = TM6000_AMUX_ADC2,
341 [TM6010_BOARD_HAUPPAUGE_900H] = {
342 .name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
343 .eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
346 .tuner_type = TUNER_XC2028, /* has a XC3028 */
347 .tuner_addr = 0xc2 >> 1,
348 .demod_addr = 0x1e >> 1,
350 .ir_codes = RC_MAP_HAUPPAUGE,
359 .tuner_reset = TM6010_GPIO_2,
360 .tuner_on = TM6010_GPIO_3,
361 .demod_reset = TM6010_GPIO_1,
362 .demod_on = TM6010_GPIO_4,
363 .power_led = TM6010_GPIO_7,
364 .dvb_led = TM6010_GPIO_5,
368 .type = TM6000_INPUT_TV,
369 .vmux = TM6000_VMUX_VIDEO_B,
370 .amux = TM6000_AMUX_SIF1,
372 .type = TM6000_INPUT_COMPOSITE1,
373 .vmux = TM6000_VMUX_VIDEO_A,
374 .amux = TM6000_AMUX_ADC2,
376 .type = TM6000_INPUT_SVIDEO,
377 .vmux = TM6000_VMUX_VIDEO_AB,
378 .amux = TM6000_AMUX_ADC2,
382 [TM6010_BOARD_BEHOLD_WANDER] = {
383 .name = "Beholder Wander DVB-T/TV/FM USB2.0",
384 .tuner_type = TUNER_XC5000,
385 .tuner_addr = 0xc2 >> 1,
386 .demod_addr = 0x1e >> 1,
397 .tuner_reset = TM6010_GPIO_0,
398 .demod_reset = TM6010_GPIO_1,
399 .power_led = TM6010_GPIO_6,
402 .type = TM6000_INPUT_TV,
403 .vmux = TM6000_VMUX_VIDEO_B,
404 .amux = TM6000_AMUX_SIF1,
406 .type = TM6000_INPUT_COMPOSITE1,
407 .vmux = TM6000_VMUX_VIDEO_A,
408 .amux = TM6000_AMUX_ADC2,
410 .type = TM6000_INPUT_SVIDEO,
411 .vmux = TM6000_VMUX_VIDEO_AB,
412 .amux = TM6000_AMUX_ADC2,
416 .type = TM6000_INPUT_RADIO,
417 .amux = TM6000_AMUX_ADC1,
420 [TM6010_BOARD_BEHOLD_VOYAGER] = {
421 .name = "Beholder Voyager TV/FM USB2.0",
422 .tuner_type = TUNER_XC5000,
423 .tuner_addr = 0xc2 >> 1,
434 .tuner_reset = TM6010_GPIO_0,
435 .power_led = TM6010_GPIO_6,
438 .type = TM6000_INPUT_TV,
439 .vmux = TM6000_VMUX_VIDEO_B,
440 .amux = TM6000_AMUX_SIF1,
442 .type = TM6000_INPUT_COMPOSITE1,
443 .vmux = TM6000_VMUX_VIDEO_A,
444 .amux = TM6000_AMUX_ADC2,
446 .type = TM6000_INPUT_SVIDEO,
447 .vmux = TM6000_VMUX_VIDEO_AB,
448 .amux = TM6000_AMUX_ADC2,
452 .type = TM6000_INPUT_RADIO,
453 .amux = TM6000_AMUX_ADC1,
456 [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
457 .name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
458 .tuner_type = TUNER_XC2028, /* has a XC3028 */
459 .tuner_addr = 0xc2 >> 1,
460 .demod_addr = 0x1e >> 1,
471 .tuner_reset = TM6010_GPIO_2,
472 .tuner_on = TM6010_GPIO_3,
473 .demod_reset = TM6010_GPIO_1,
474 .demod_on = TM6010_GPIO_4,
475 .power_led = TM6010_GPIO_7,
476 .dvb_led = TM6010_GPIO_5,
479 .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
481 .type = TM6000_INPUT_TV,
482 .vmux = TM6000_VMUX_VIDEO_B,
483 .amux = TM6000_AMUX_SIF1,
485 .type = TM6000_INPUT_COMPOSITE1,
486 .vmux = TM6000_VMUX_VIDEO_A,
487 .amux = TM6000_AMUX_ADC2,
489 .type = TM6000_INPUT_SVIDEO,
490 .vmux = TM6000_VMUX_VIDEO_AB,
491 .amux = TM6000_AMUX_ADC2,
495 .type = TM6000_INPUT_RADIO,
496 .amux = TM6000_AMUX_SIF1,
499 [TM5600_BOARD_TERRATEC_GRABSTER] = {
500 .name = "Terratec Grabster AV 150/250 MX",
502 .tuner_type = TUNER_ABSENT,
504 .type = TM6000_INPUT_TV,
505 .vmux = TM6000_VMUX_VIDEO_B,
506 .amux = TM6000_AMUX_ADC1,
508 .type = TM6000_INPUT_COMPOSITE1,
509 .vmux = TM6000_VMUX_VIDEO_A,
510 .amux = TM6000_AMUX_ADC2,
512 .type = TM6000_INPUT_SVIDEO,
513 .vmux = TM6000_VMUX_VIDEO_AB,
514 .amux = TM6000_AMUX_ADC2,
518 [TM6010_BOARD_TWINHAN_TU501] = {
519 .name = "Twinhan TU501(704D1)",
520 .tuner_type = TUNER_XC2028, /* has a XC3028 */
521 .tuner_addr = 0xc2 >> 1,
522 .demod_addr = 0x1e >> 1,
532 .tuner_reset = TM6010_GPIO_2,
533 .tuner_on = TM6010_GPIO_3,
534 .demod_reset = TM6010_GPIO_1,
535 .demod_on = TM6010_GPIO_4,
536 .power_led = TM6010_GPIO_7,
537 .dvb_led = TM6010_GPIO_5,
541 .type = TM6000_INPUT_TV,
542 .vmux = TM6000_VMUX_VIDEO_B,
543 .amux = TM6000_AMUX_SIF1,
545 .type = TM6000_INPUT_COMPOSITE1,
546 .vmux = TM6000_VMUX_VIDEO_A,
547 .amux = TM6000_AMUX_ADC2,
549 .type = TM6000_INPUT_SVIDEO,
550 .vmux = TM6000_VMUX_VIDEO_AB,
551 .amux = TM6000_AMUX_ADC2,
555 [TM6010_BOARD_BEHOLD_WANDER_LITE] = {
556 .name = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
557 .tuner_type = TUNER_XC5000,
558 .tuner_addr = 0xc2 >> 1,
559 .demod_addr = 0x1e >> 1,
570 .tuner_reset = TM6010_GPIO_0,
571 .demod_reset = TM6010_GPIO_1,
572 .power_led = TM6010_GPIO_6,
575 .type = TM6000_INPUT_TV,
576 .vmux = TM6000_VMUX_VIDEO_B,
577 .amux = TM6000_AMUX_SIF1,
581 .type = TM6000_INPUT_RADIO,
582 .amux = TM6000_AMUX_ADC1,
585 [TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
586 .name = "Beholder Voyager Lite TV/FM USB2.0",
587 .tuner_type = TUNER_XC5000,
588 .tuner_addr = 0xc2 >> 1,
599 .tuner_reset = TM6010_GPIO_0,
600 .power_led = TM6010_GPIO_6,
603 .type = TM6000_INPUT_TV,
604 .vmux = TM6000_VMUX_VIDEO_B,
605 .amux = TM6000_AMUX_SIF1,
609 .type = TM6000_INPUT_RADIO,
610 .amux = TM6000_AMUX_ADC1,
615 /* table of devices that work with this driver */
616 static const struct usb_device_id tm6000_id_table[] = {
617 { USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
618 { USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
619 { USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
620 { USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
621 { USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
622 { USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
623 { USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
624 { USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
625 { USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
626 { USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
627 { USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
628 { USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
629 { USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
630 { USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
631 { USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
632 { USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
633 { USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
634 { USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
635 { USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
636 { USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
639 MODULE_DEVICE_TABLE(usb, tm6000_id_table);
641 /* Control power led for show some activity */
642 void tm6000_flash_led(struct tm6000_core *dev, u8 state)
644 /* Power LED unconfigured */
645 if (!dev->gpio.power_led)
650 switch (dev->model) {
651 case TM6010_BOARD_HAUPPAUGE_900H:
652 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
653 case TM6010_BOARD_TWINHAN_TU501:
654 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
655 dev->gpio.power_led, 0x00);
657 case TM6010_BOARD_BEHOLD_WANDER:
658 case TM6010_BOARD_BEHOLD_VOYAGER:
659 case TM6010_BOARD_BEHOLD_WANDER_LITE:
660 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
661 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
662 dev->gpio.power_led, 0x01);
668 switch (dev->model) {
669 case TM6010_BOARD_HAUPPAUGE_900H:
670 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
671 case TM6010_BOARD_TWINHAN_TU501:
672 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
673 dev->gpio.power_led, 0x01);
675 case TM6010_BOARD_BEHOLD_WANDER:
676 case TM6010_BOARD_BEHOLD_VOYAGER:
677 case TM6010_BOARD_BEHOLD_WANDER_LITE:
678 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
679 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
680 dev->gpio.power_led, 0x00);
686 /* Tuner callback to provide the proper gpio changes needed for xc5000 */
687 int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
690 struct tm6000_core *dev = ptr;
692 if (dev->tuner_type != TUNER_XC5000)
696 case XC5000_TUNER_RESET:
697 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
698 dev->gpio.tuner_reset, 0x01);
700 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
701 dev->gpio.tuner_reset, 0x00);
703 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
704 dev->gpio.tuner_reset, 0x01);
709 EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
711 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
713 int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
716 struct tm6000_core *dev = ptr;
718 if (dev->tuner_type != TUNER_XC2028)
722 case XC2028_RESET_CLK:
723 tm6000_ir_wait(dev, 0);
725 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
728 rc = tm6000_i2c_reset(dev, 10);
730 case XC2028_TUNER_RESET:
731 /* Reset codes during load firmware */
734 /* newer tuner can faster reset */
735 switch (dev->model) {
736 case TM5600_BOARD_10MOONS_UT821:
737 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
738 dev->gpio.tuner_reset, 0x01);
739 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
742 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
743 dev->gpio.tuner_reset, 0x00);
744 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
747 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
748 dev->gpio.tuner_reset, 0x01);
749 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
752 case TM6010_BOARD_HAUPPAUGE_900H:
753 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
754 case TM6010_BOARD_TWINHAN_TU501:
755 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
756 dev->gpio.tuner_reset, 0x01);
758 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
759 dev->gpio.tuner_reset, 0x00);
761 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
762 dev->gpio.tuner_reset, 0x01);
766 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
767 dev->gpio.tuner_reset, 0x00);
769 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
770 dev->gpio.tuner_reset, 0x01);
775 tm6000_ir_wait(dev, 1);
778 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
783 rc = tm6000_i2c_reset(dev, 100);
787 case XC2028_I2C_FLUSH:
788 tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
789 tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
794 EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
796 int tm6000_cards_setup(struct tm6000_core *dev)
799 * Board-specific initialization sequence. Handles all GPIO
800 * initialization sequences that are board-specific.
801 * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
802 * Probably, they're all based on some reference device. Due to that,
803 * there's a common routine at the end to handle those GPIO's. Devices
804 * that use different pinups or init sequences can just return at
805 * the board-specific session.
807 switch (dev->model) {
808 case TM6010_BOARD_HAUPPAUGE_900H:
809 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
810 case TM6010_BOARD_TWINHAN_TU501:
811 case TM6010_BOARD_GENERIC:
812 /* Turn xceive 3028 on */
813 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
815 /* Turn zarlink zl10353 on */
816 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
818 /* Reset zarlink zl10353 */
819 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
821 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
823 /* Turn zarlink zl10353 off */
824 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
827 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
829 /* Power led on (blue) */
830 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
832 /* DVB led off (orange) */
833 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
835 /* Turn zarlink zl10353 on */
836 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
839 case TM6010_BOARD_BEHOLD_WANDER:
840 case TM6010_BOARD_BEHOLD_WANDER_LITE:
841 /* Power led on (blue) */
842 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
844 /* Reset zarlink zl10353 */
845 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
847 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
850 case TM6010_BOARD_BEHOLD_VOYAGER:
851 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
852 /* Power led on (blue) */
853 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
861 * Default initialization. Most of the devices seem to use GPIO1
862 * and GPIO4.on the same way, so, this handles the common sequence
863 * used by most devices.
864 * If a device uses a different sequence or different GPIO pins for
865 * reset, just add the code at the board-specific part
868 if (dev->gpio.tuner_reset) {
872 for (i = 0; i < 2; i++) {
873 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
874 dev->gpio.tuner_reset, 0x00);
876 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
880 msleep(10); /* Just to be conservative */
881 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
882 dev->gpio.tuner_reset, 0x01);
884 printk(KERN_ERR "Error %i doing tuner reset\n", rc);
889 printk(KERN_ERR "Tuner reset is not configured\n");
898 static void tm6000_config_tuner(struct tm6000_core *dev)
900 struct tuner_setup tun_setup;
902 /* Load tuner module */
903 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
904 "tuner", dev->tuner_addr, NULL);
906 memset(&tun_setup, 0, sizeof(tun_setup));
907 tun_setup.type = dev->tuner_type;
908 tun_setup.addr = dev->tuner_addr;
910 tun_setup.mode_mask = 0;
911 if (dev->caps.has_tuner)
912 tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
914 switch (dev->tuner_type) {
916 tun_setup.tuner_callback = tm6000_tuner_callback;
919 tun_setup.tuner_callback = tm6000_xc5000_callback;
923 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
925 switch (dev->tuner_type) {
927 struct v4l2_priv_tun_config xc2028_cfg;
928 struct xc2028_ctrl ctl;
930 memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
931 memset(&ctl, 0, sizeof(ctl));
933 ctl.demod = XC3028_FE_ZARLINK456;
935 xc2028_cfg.tuner = TUNER_XC2028;
936 xc2028_cfg.priv = &ctl;
938 switch (dev->model) {
939 case TM6010_BOARD_HAUPPAUGE_900H:
940 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
941 case TM6010_BOARD_TWINHAN_TU501:
943 ctl.fname = "/*(DEBLOBBED)*/";
946 if (dev->dev_type == TM6010)
947 ctl.fname = "/*(DEBLOBBED)*/";
949 ctl.fname = "/*(DEBLOBBED)*/";
952 printk(KERN_INFO "Setting firmware parameters for xc2028\n");
953 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
960 struct v4l2_priv_tun_config xc5000_cfg;
961 struct xc5000_config ctl = {
962 .i2c_address = dev->tuner_addr,
964 .radio_input = XC5000_RADIO_FM1_MONO,
967 xc5000_cfg.tuner = TUNER_XC5000;
968 xc5000_cfg.priv = &ctl;
970 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
975 printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
980 static int fill_board_specific_data(struct tm6000_core *dev)
984 dev->dev_type = tm6000_boards[dev->model].type;
985 dev->tuner_type = tm6000_boards[dev->model].tuner_type;
986 dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
988 dev->gpio = tm6000_boards[dev->model].gpio;
990 dev->ir_codes = tm6000_boards[dev->model].ir_codes;
992 dev->demod_addr = tm6000_boards[dev->model].demod_addr;
994 dev->caps = tm6000_boards[dev->model].caps;
996 dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
997 dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
998 dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
999 dev->rinput = tm6000_boards[dev->model].rinput;
1001 /* setup per-model quirks */
1002 switch (dev->model) {
1003 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1004 case TM6010_BOARD_HAUPPAUGE_900H:
1005 dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
1012 /* initialize hardware */
1013 rc = tm6000_init(dev);
1017 return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
1021 static void use_alternative_detection_method(struct tm6000_core *dev)
1025 if (!dev->eedata_size)
1028 for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
1029 if (!tm6000_boards[i].eename_size)
1031 if (dev->eedata_size < tm6000_boards[i].eename_pos +
1032 tm6000_boards[i].eename_size)
1035 if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
1036 tm6000_boards[i].eename,
1037 tm6000_boards[i].eename_size)) {
1043 printk(KERN_INFO "Device has eeprom but is currently unknown\n");
1049 printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
1050 tm6000_boards[model].name, model);
1053 #if defined(CONFIG_MODULES) && defined(MODULE)
1054 static void request_module_async(struct work_struct *work)
1056 struct tm6000_core *dev = container_of(work, struct tm6000_core,
1059 request_module("tm6000-alsa");
1061 if (dev->caps.has_dvb)
1062 request_module("tm6000-dvb");
1065 static void request_modules(struct tm6000_core *dev)
1067 INIT_WORK(&dev->request_module_wk, request_module_async);
1068 schedule_work(&dev->request_module_wk);
1071 static void flush_request_modules(struct tm6000_core *dev)
1073 flush_work(&dev->request_module_wk);
1076 #define request_modules(dev)
1077 #define flush_request_modules(dev)
1078 #endif /* CONFIG_MODULES */
1080 static int tm6000_init_dev(struct tm6000_core *dev)
1082 struct v4l2_frequency f;
1085 mutex_init(&dev->lock);
1086 mutex_lock(&dev->lock);
1088 if (!is_generic(dev->model)) {
1089 rc = fill_board_specific_data(dev);
1093 /* register i2c bus */
1094 rc = tm6000_i2c_register(dev);
1098 /* register i2c bus */
1099 rc = tm6000_i2c_register(dev);
1103 use_alternative_detection_method(dev);
1105 rc = fill_board_specific_data(dev);
1110 /* Default values for STD and resolutions */
1113 dev->norm = V4L2_STD_NTSC_M;
1115 /* Configure tuner */
1116 tm6000_config_tuner(dev);
1118 /* Set video standard */
1119 v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
1121 /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
1123 f.type = V4L2_TUNER_ANALOG_TV;
1124 f.frequency = 3092; /* 193.25 MHz */
1125 dev->freq = f.frequency;
1126 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
1128 if (dev->caps.has_tda9874)
1129 v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
1130 "tvaudio", I2C_ADDR_TDA9874, NULL);
1132 /* register and initialize V4L2 */
1133 rc = tm6000_v4l2_register(dev);
1137 tm6000_add_into_devlist(dev);
1138 tm6000_init_extension(dev);
1140 tm6000_ir_init(dev);
1142 request_modules(dev);
1144 mutex_unlock(&dev->lock);
1148 mutex_unlock(&dev->lock);
1152 /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
1153 #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
1155 static void get_max_endpoint(struct usb_device *udev,
1156 struct usb_host_interface *alt,
1158 struct usb_host_endpoint *curr_e,
1159 struct tm6000_endpoint *tm_ep)
1161 u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
1162 unsigned int size = tmp & 0x7ff;
1164 if (udev->speed == USB_SPEED_HIGH)
1165 size = size * hb_mult(tmp);
1167 if (size > tm_ep->maxsize) {
1168 tm_ep->endp = curr_e;
1169 tm_ep->maxsize = size;
1170 tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
1171 tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
1173 printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
1174 msgtype, curr_e->desc.bEndpointAddress,
1180 * tm6000_usb_probe()
1181 * checks for supported devices
1183 static int tm6000_usb_probe(struct usb_interface *interface,
1184 const struct usb_device_id *id)
1186 struct usb_device *usbdev;
1187 struct tm6000_core *dev = NULL;
1192 usbdev = usb_get_dev(interface_to_usbdev(interface));
1194 /* Selects the proper interface */
1195 rc = usb_set_interface(usbdev, 0, 1);
1199 /* Check to see next free device and mark as used */
1200 nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
1201 if (nr >= TM6000_MAXBOARDS) {
1202 printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
1203 usb_put_dev(usbdev);
1207 /* Create and initialize dev struct */
1208 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1210 printk(KERN_ERR "tm6000" ": out of memory!\n");
1211 usb_put_dev(usbdev);
1214 spin_lock_init(&dev->slock);
1215 mutex_init(&dev->usb_lock);
1217 /* Increment usage count */
1218 set_bit(nr, &tm6000_devused);
1219 snprintf(dev->name, 29, "tm6000 #%d", nr);
1221 dev->model = id->driver_info;
1222 if (card[nr] < ARRAY_SIZE(tm6000_boards))
1223 dev->model = card[nr];
1228 switch (usbdev->speed) {
1232 case USB_SPEED_UNKNOWN:
1233 case USB_SPEED_FULL:
1236 case USB_SPEED_HIGH:
1244 for (i = 0; i < interface->num_altsetting; i++) {
1247 for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
1248 struct usb_host_endpoint *e;
1251 e = &interface->altsetting[i].endpoint[ep];
1253 dir_out = ((e->desc.bEndpointAddress &
1254 USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
1256 printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
1258 interface->altsetting[i].desc.bInterfaceNumber,
1259 interface->altsetting[i].desc.bInterfaceClass);
1261 switch (e->desc.bmAttributes) {
1262 case USB_ENDPOINT_XFER_BULK:
1264 get_max_endpoint(usbdev,
1265 &interface->altsetting[i],
1269 get_max_endpoint(usbdev,
1270 &interface->altsetting[i],
1275 case USB_ENDPOINT_XFER_ISOC:
1277 get_max_endpoint(usbdev,
1278 &interface->altsetting[i],
1282 get_max_endpoint(usbdev,
1283 &interface->altsetting[i],
1288 case USB_ENDPOINT_XFER_INT:
1290 get_max_endpoint(usbdev,
1291 &interface->altsetting[i],
1295 get_max_endpoint(usbdev,
1296 &interface->altsetting[i],
1306 printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
1308 le16_to_cpu(dev->udev->descriptor.idVendor),
1309 le16_to_cpu(dev->udev->descriptor.idProduct),
1310 interface->altsetting->desc.bInterfaceNumber);
1312 /* check if the the device has the iso in endpoint at the correct place */
1313 if (!dev->isoc_in.endp) {
1314 printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
1320 /* save our data pointer in this interface device */
1321 usb_set_intfdata(interface, dev);
1323 printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
1325 rc = tm6000_init_dev(dev);
1332 printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
1334 clear_bit(nr, &tm6000_devused);
1335 usb_put_dev(usbdev);
1342 * tm6000_usb_disconnect()
1343 * called when the device gets diconencted
1344 * video device will be unregistered on v4l2_close in case it is still open
1346 static void tm6000_usb_disconnect(struct usb_interface *interface)
1348 struct tm6000_core *dev = usb_get_intfdata(interface);
1349 usb_set_intfdata(interface, NULL);
1354 printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
1356 flush_request_modules(dev);
1358 tm6000_ir_fini(dev);
1360 if (dev->gpio.power_led) {
1361 switch (dev->model) {
1362 case TM6010_BOARD_HAUPPAUGE_900H:
1363 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1364 case TM6010_BOARD_TWINHAN_TU501:
1366 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1367 dev->gpio.power_led, 0x01);
1370 case TM6010_BOARD_BEHOLD_WANDER:
1371 case TM6010_BOARD_BEHOLD_VOYAGER:
1372 case TM6010_BOARD_BEHOLD_WANDER_LITE:
1373 case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
1375 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1376 dev->gpio.power_led, 0x00);
1381 tm6000_v4l2_unregister(dev);
1383 tm6000_i2c_unregister(dev);
1385 v4l2_device_unregister(&dev->v4l2_dev);
1387 dev->state |= DEV_DISCONNECTED;
1389 usb_put_dev(dev->udev);
1391 tm6000_close_extension(dev);
1392 tm6000_remove_from_devlist(dev);
1394 clear_bit(dev->devno, &tm6000_devused);
1398 static struct usb_driver tm6000_usb_driver = {
1400 .probe = tm6000_usb_probe,
1401 .disconnect = tm6000_usb_disconnect,
1402 .id_table = tm6000_id_table,
1405 module_usb_driver(tm6000_usb_driver);
1407 MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
1408 MODULE_AUTHOR("Mauro Carvalho Chehab");
1409 MODULE_LICENSE("GPL");