1 // SPDX-License-Identifier: GPL-2.0
2 // tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
4 // Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
6 #include <linux/init.h>
7 #include <linux/module.h>
9 #include <linux/delay.h>
10 #include <linux/i2c.h>
11 #include <linux/usb.h>
12 #include <linux/slab.h>
13 #include <media/v4l2-common.h>
14 #include <media/tuner.h>
15 #include <media/i2c/tvaudio.h>
16 #include <media/rc-map.h>
19 #include "tm6000-regs.h"
20 #include "tuner-xc2028.h"
23 #define TM6000_BOARD_UNKNOWN 0
24 #define TM5600_BOARD_GENERIC 1
25 #define TM6000_BOARD_GENERIC 2
26 #define TM6010_BOARD_GENERIC 3
27 #define TM5600_BOARD_10MOONS_UT821 4
28 #define TM5600_BOARD_10MOONS_UT330 5
29 #define TM6000_BOARD_ADSTECH_DUAL_TV 6
30 #define TM6000_BOARD_FREECOM_AND_SIMILAR 7
31 #define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8
32 #define TM6010_BOARD_HAUPPAUGE_900H 9
33 #define TM6010_BOARD_BEHOLD_WANDER 10
34 #define TM6010_BOARD_BEHOLD_VOYAGER 11
35 #define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12
36 #define TM6010_BOARD_TWINHAN_TU501 13
37 #define TM6010_BOARD_BEHOLD_WANDER_LITE 14
38 #define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15
39 #define TM5600_BOARD_TERRATEC_GRABSTER 16
41 #define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
42 (model == TM5600_BOARD_GENERIC) || \
43 (model == TM6000_BOARD_GENERIC) || \
44 (model == TM6010_BOARD_GENERIC))
46 #define TM6000_MAXBOARDS 16
47 static unsigned int card
[] = {[0 ... (TM6000_MAXBOARDS
- 1)] = UNSET
};
49 module_param_array(card
, int, NULL
, 0444);
51 static unsigned long tm6000_devused
;
56 char eename
[16]; /* EEPROM name */
57 unsigned eename_size
; /* size of EEPROM name */
58 unsigned eename_pos
; /* Position where it appears at ROM */
60 struct tm6000_capabilities caps
;
62 enum tm6000_devtype type
; /* variant of the chipset */
63 int tuner_type
; /* type of the tuner */
64 int tuner_addr
; /* tuner address */
65 int demod_addr
; /* demodulator address */
67 struct tm6000_gpio gpio
;
69 struct tm6000_input vinput
[3];
70 struct tm6000_input rinput
;
75 static struct tm6000_board tm6000_boards
[] = {
76 [TM6000_BOARD_UNKNOWN
] = {
77 .name
= "Unknown tm6000 video grabber",
83 .tuner_reset
= TM6000_GPIO_1
,
86 .type
= TM6000_INPUT_TV
,
87 .vmux
= TM6000_VMUX_VIDEO_B
,
88 .amux
= TM6000_AMUX_ADC1
,
90 .type
= TM6000_INPUT_COMPOSITE1
,
91 .vmux
= TM6000_VMUX_VIDEO_A
,
92 .amux
= TM6000_AMUX_ADC2
,
94 .type
= TM6000_INPUT_SVIDEO
,
95 .vmux
= TM6000_VMUX_VIDEO_AB
,
96 .amux
= TM6000_AMUX_ADC2
,
100 [TM5600_BOARD_GENERIC
] = {
101 .name
= "Generic tm5600 board",
103 .tuner_type
= TUNER_XC2028
,
104 .tuner_addr
= 0xc2 >> 1,
110 .tuner_reset
= TM6000_GPIO_1
,
113 .type
= TM6000_INPUT_TV
,
114 .vmux
= TM6000_VMUX_VIDEO_B
,
115 .amux
= TM6000_AMUX_ADC1
,
117 .type
= TM6000_INPUT_COMPOSITE1
,
118 .vmux
= TM6000_VMUX_VIDEO_A
,
119 .amux
= TM6000_AMUX_ADC2
,
121 .type
= TM6000_INPUT_SVIDEO
,
122 .vmux
= TM6000_VMUX_VIDEO_AB
,
123 .amux
= TM6000_AMUX_ADC2
,
127 [TM6000_BOARD_GENERIC
] = {
128 .name
= "Generic tm6000 board",
129 .tuner_type
= TUNER_XC2028
,
130 .tuner_addr
= 0xc2 >> 1,
136 .tuner_reset
= TM6000_GPIO_1
,
139 .type
= TM6000_INPUT_TV
,
140 .vmux
= TM6000_VMUX_VIDEO_B
,
141 .amux
= TM6000_AMUX_ADC1
,
143 .type
= TM6000_INPUT_COMPOSITE1
,
144 .vmux
= TM6000_VMUX_VIDEO_A
,
145 .amux
= TM6000_AMUX_ADC2
,
147 .type
= TM6000_INPUT_SVIDEO
,
148 .vmux
= TM6000_VMUX_VIDEO_AB
,
149 .amux
= TM6000_AMUX_ADC2
,
153 [TM6010_BOARD_GENERIC
] = {
154 .name
= "Generic tm6010 board",
156 .tuner_type
= TUNER_XC2028
,
157 .tuner_addr
= 0xc2 >> 1,
158 .demod_addr
= 0x1e >> 1,
167 .tuner_reset
= TM6010_GPIO_2
,
168 .tuner_on
= TM6010_GPIO_3
,
169 .demod_reset
= TM6010_GPIO_1
,
170 .demod_on
= TM6010_GPIO_4
,
171 .power_led
= TM6010_GPIO_7
,
172 .dvb_led
= TM6010_GPIO_5
,
176 .type
= TM6000_INPUT_TV
,
177 .vmux
= TM6000_VMUX_VIDEO_B
,
178 .amux
= TM6000_AMUX_SIF1
,
180 .type
= TM6000_INPUT_COMPOSITE1
,
181 .vmux
= TM6000_VMUX_VIDEO_A
,
182 .amux
= TM6000_AMUX_ADC2
,
184 .type
= TM6000_INPUT_SVIDEO
,
185 .vmux
= TM6000_VMUX_VIDEO_AB
,
186 .amux
= TM6000_AMUX_ADC2
,
190 [TM5600_BOARD_10MOONS_UT821
] = {
191 .name
= "10Moons UT 821",
192 .tuner_type
= TUNER_XC2028
,
193 .eename
= { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
197 .tuner_addr
= 0xc2 >> 1,
203 .tuner_reset
= TM6000_GPIO_1
,
206 .type
= TM6000_INPUT_TV
,
207 .vmux
= TM6000_VMUX_VIDEO_B
,
208 .amux
= TM6000_AMUX_ADC1
,
210 .type
= TM6000_INPUT_COMPOSITE1
,
211 .vmux
= TM6000_VMUX_VIDEO_A
,
212 .amux
= TM6000_AMUX_ADC2
,
214 .type
= TM6000_INPUT_SVIDEO
,
215 .vmux
= TM6000_VMUX_VIDEO_AB
,
216 .amux
= TM6000_AMUX_ADC2
,
220 [TM5600_BOARD_10MOONS_UT330
] = {
221 .name
= "10Moons UT 330",
222 .tuner_type
= TUNER_PHILIPS_FQ1216AME_MK4
,
223 .tuner_addr
= 0xc8 >> 1,
231 .type
= TM6000_INPUT_TV
,
232 .vmux
= TM6000_VMUX_VIDEO_B
,
233 .amux
= TM6000_AMUX_ADC1
,
235 .type
= TM6000_INPUT_COMPOSITE1
,
236 .vmux
= TM6000_VMUX_VIDEO_A
,
237 .amux
= TM6000_AMUX_ADC2
,
239 .type
= TM6000_INPUT_SVIDEO
,
240 .vmux
= TM6000_VMUX_VIDEO_AB
,
241 .amux
= TM6000_AMUX_ADC2
,
245 [TM6000_BOARD_ADSTECH_DUAL_TV
] = {
246 .name
= "ADSTECH Dual TV USB",
247 .tuner_type
= TUNER_XC2028
,
248 .tuner_addr
= 0xc8 >> 1,
257 .type
= TM6000_INPUT_TV
,
258 .vmux
= TM6000_VMUX_VIDEO_B
,
259 .amux
= TM6000_AMUX_ADC1
,
261 .type
= TM6000_INPUT_COMPOSITE1
,
262 .vmux
= TM6000_VMUX_VIDEO_A
,
263 .amux
= TM6000_AMUX_ADC2
,
265 .type
= TM6000_INPUT_SVIDEO
,
266 .vmux
= TM6000_VMUX_VIDEO_AB
,
267 .amux
= TM6000_AMUX_ADC2
,
271 [TM6000_BOARD_FREECOM_AND_SIMILAR
] = {
272 .name
= "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
273 .tuner_type
= TUNER_XC2028
, /* has a XC3028 */
274 .tuner_addr
= 0xc2 >> 1,
275 .demod_addr
= 0x1e >> 1,
284 .tuner_reset
= TM6000_GPIO_4
,
287 .type
= TM6000_INPUT_TV
,
288 .vmux
= TM6000_VMUX_VIDEO_B
,
289 .amux
= TM6000_AMUX_ADC1
,
291 .type
= TM6000_INPUT_COMPOSITE1
,
292 .vmux
= TM6000_VMUX_VIDEO_A
,
293 .amux
= TM6000_AMUX_ADC2
,
295 .type
= TM6000_INPUT_SVIDEO
,
296 .vmux
= TM6000_VMUX_VIDEO_AB
,
297 .amux
= TM6000_AMUX_ADC2
,
301 [TM6000_BOARD_ADSTECH_MINI_DUAL_TV
] = {
302 .name
= "ADSTECH Mini Dual TV USB",
303 .tuner_type
= TUNER_XC2028
, /* has a XC3028 */
304 .tuner_addr
= 0xc8 >> 1,
305 .demod_addr
= 0x1e >> 1,
313 .tuner_reset
= TM6000_GPIO_4
,
316 .type
= TM6000_INPUT_TV
,
317 .vmux
= TM6000_VMUX_VIDEO_B
,
318 .amux
= TM6000_AMUX_ADC1
,
320 .type
= TM6000_INPUT_COMPOSITE1
,
321 .vmux
= TM6000_VMUX_VIDEO_A
,
322 .amux
= TM6000_AMUX_ADC2
,
324 .type
= TM6000_INPUT_SVIDEO
,
325 .vmux
= TM6000_VMUX_VIDEO_AB
,
326 .amux
= TM6000_AMUX_ADC2
,
330 [TM6010_BOARD_HAUPPAUGE_900H
] = {
331 .name
= "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
332 .eename
= { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
335 .tuner_type
= TUNER_XC2028
, /* has a XC3028 */
336 .tuner_addr
= 0xc2 >> 1,
337 .demod_addr
= 0x1e >> 1,
339 .ir_codes
= RC_MAP_HAUPPAUGE
,
348 .tuner_reset
= TM6010_GPIO_2
,
349 .tuner_on
= TM6010_GPIO_3
,
350 .demod_reset
= TM6010_GPIO_1
,
351 .demod_on
= TM6010_GPIO_4
,
352 .power_led
= TM6010_GPIO_7
,
353 .dvb_led
= TM6010_GPIO_5
,
357 .type
= TM6000_INPUT_TV
,
358 .vmux
= TM6000_VMUX_VIDEO_B
,
359 .amux
= TM6000_AMUX_SIF1
,
361 .type
= TM6000_INPUT_COMPOSITE1
,
362 .vmux
= TM6000_VMUX_VIDEO_A
,
363 .amux
= TM6000_AMUX_ADC2
,
365 .type
= TM6000_INPUT_SVIDEO
,
366 .vmux
= TM6000_VMUX_VIDEO_AB
,
367 .amux
= TM6000_AMUX_ADC2
,
371 [TM6010_BOARD_BEHOLD_WANDER
] = {
372 .name
= "Beholder Wander DVB-T/TV/FM USB2.0",
373 .tuner_type
= TUNER_XC5000
,
374 .tuner_addr
= 0xc2 >> 1,
375 .demod_addr
= 0x1e >> 1,
386 .tuner_reset
= TM6010_GPIO_0
,
387 .demod_reset
= TM6010_GPIO_1
,
388 .power_led
= TM6010_GPIO_6
,
391 .type
= TM6000_INPUT_TV
,
392 .vmux
= TM6000_VMUX_VIDEO_B
,
393 .amux
= TM6000_AMUX_SIF1
,
395 .type
= TM6000_INPUT_COMPOSITE1
,
396 .vmux
= TM6000_VMUX_VIDEO_A
,
397 .amux
= TM6000_AMUX_ADC2
,
399 .type
= TM6000_INPUT_SVIDEO
,
400 .vmux
= TM6000_VMUX_VIDEO_AB
,
401 .amux
= TM6000_AMUX_ADC2
,
405 .type
= TM6000_INPUT_RADIO
,
406 .amux
= TM6000_AMUX_ADC1
,
409 [TM6010_BOARD_BEHOLD_VOYAGER
] = {
410 .name
= "Beholder Voyager TV/FM USB2.0",
411 .tuner_type
= TUNER_XC5000
,
412 .tuner_addr
= 0xc2 >> 1,
423 .tuner_reset
= TM6010_GPIO_0
,
424 .power_led
= TM6010_GPIO_6
,
427 .type
= TM6000_INPUT_TV
,
428 .vmux
= TM6000_VMUX_VIDEO_B
,
429 .amux
= TM6000_AMUX_SIF1
,
431 .type
= TM6000_INPUT_COMPOSITE1
,
432 .vmux
= TM6000_VMUX_VIDEO_A
,
433 .amux
= TM6000_AMUX_ADC2
,
435 .type
= TM6000_INPUT_SVIDEO
,
436 .vmux
= TM6000_VMUX_VIDEO_AB
,
437 .amux
= TM6000_AMUX_ADC2
,
441 .type
= TM6000_INPUT_RADIO
,
442 .amux
= TM6000_AMUX_ADC1
,
445 [TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
] = {
446 .name
= "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
447 .tuner_type
= TUNER_XC2028
, /* has a XC3028 */
448 .tuner_addr
= 0xc2 >> 1,
449 .demod_addr
= 0x1e >> 1,
460 .tuner_reset
= TM6010_GPIO_2
,
461 .tuner_on
= TM6010_GPIO_3
,
462 .demod_reset
= TM6010_GPIO_1
,
463 .demod_on
= TM6010_GPIO_4
,
464 .power_led
= TM6010_GPIO_7
,
465 .dvb_led
= TM6010_GPIO_5
,
468 .ir_codes
= RC_MAP_NEC_TERRATEC_CINERGY_XS
,
470 .type
= TM6000_INPUT_TV
,
471 .vmux
= TM6000_VMUX_VIDEO_B
,
472 .amux
= TM6000_AMUX_SIF1
,
474 .type
= TM6000_INPUT_COMPOSITE1
,
475 .vmux
= TM6000_VMUX_VIDEO_A
,
476 .amux
= TM6000_AMUX_ADC2
,
478 .type
= TM6000_INPUT_SVIDEO
,
479 .vmux
= TM6000_VMUX_VIDEO_AB
,
480 .amux
= TM6000_AMUX_ADC2
,
484 .type
= TM6000_INPUT_RADIO
,
485 .amux
= TM6000_AMUX_SIF1
,
488 [TM5600_BOARD_TERRATEC_GRABSTER
] = {
489 .name
= "Terratec Grabster AV 150/250 MX",
491 .tuner_type
= TUNER_ABSENT
,
493 .type
= TM6000_INPUT_TV
,
494 .vmux
= TM6000_VMUX_VIDEO_B
,
495 .amux
= TM6000_AMUX_ADC1
,
497 .type
= TM6000_INPUT_COMPOSITE1
,
498 .vmux
= TM6000_VMUX_VIDEO_A
,
499 .amux
= TM6000_AMUX_ADC2
,
501 .type
= TM6000_INPUT_SVIDEO
,
502 .vmux
= TM6000_VMUX_VIDEO_AB
,
503 .amux
= TM6000_AMUX_ADC2
,
507 [TM6010_BOARD_TWINHAN_TU501
] = {
508 .name
= "Twinhan TU501(704D1)",
509 .tuner_type
= TUNER_XC2028
, /* has a XC3028 */
510 .tuner_addr
= 0xc2 >> 1,
511 .demod_addr
= 0x1e >> 1,
521 .tuner_reset
= TM6010_GPIO_2
,
522 .tuner_on
= TM6010_GPIO_3
,
523 .demod_reset
= TM6010_GPIO_1
,
524 .demod_on
= TM6010_GPIO_4
,
525 .power_led
= TM6010_GPIO_7
,
526 .dvb_led
= TM6010_GPIO_5
,
530 .type
= TM6000_INPUT_TV
,
531 .vmux
= TM6000_VMUX_VIDEO_B
,
532 .amux
= TM6000_AMUX_SIF1
,
534 .type
= TM6000_INPUT_COMPOSITE1
,
535 .vmux
= TM6000_VMUX_VIDEO_A
,
536 .amux
= TM6000_AMUX_ADC2
,
538 .type
= TM6000_INPUT_SVIDEO
,
539 .vmux
= TM6000_VMUX_VIDEO_AB
,
540 .amux
= TM6000_AMUX_ADC2
,
544 [TM6010_BOARD_BEHOLD_WANDER_LITE
] = {
545 .name
= "Beholder Wander Lite DVB-T/TV/FM USB2.0",
546 .tuner_type
= TUNER_XC5000
,
547 .tuner_addr
= 0xc2 >> 1,
548 .demod_addr
= 0x1e >> 1,
559 .tuner_reset
= TM6010_GPIO_0
,
560 .demod_reset
= TM6010_GPIO_1
,
561 .power_led
= TM6010_GPIO_6
,
564 .type
= TM6000_INPUT_TV
,
565 .vmux
= TM6000_VMUX_VIDEO_B
,
566 .amux
= TM6000_AMUX_SIF1
,
570 .type
= TM6000_INPUT_RADIO
,
571 .amux
= TM6000_AMUX_ADC1
,
574 [TM6010_BOARD_BEHOLD_VOYAGER_LITE
] = {
575 .name
= "Beholder Voyager Lite TV/FM USB2.0",
576 .tuner_type
= TUNER_XC5000
,
577 .tuner_addr
= 0xc2 >> 1,
588 .tuner_reset
= TM6010_GPIO_0
,
589 .power_led
= TM6010_GPIO_6
,
592 .type
= TM6000_INPUT_TV
,
593 .vmux
= TM6000_VMUX_VIDEO_B
,
594 .amux
= TM6000_AMUX_SIF1
,
598 .type
= TM6000_INPUT_RADIO
,
599 .amux
= TM6000_AMUX_ADC1
,
604 /* table of devices that work with this driver */
605 static const struct usb_device_id tm6000_id_table
[] = {
606 { USB_DEVICE(0x6000, 0x0001), .driver_info
= TM5600_BOARD_GENERIC
},
607 { USB_DEVICE(0x6000, 0x0002), .driver_info
= TM6010_BOARD_GENERIC
},
608 { USB_DEVICE(0x06e1, 0xf332), .driver_info
= TM6000_BOARD_ADSTECH_DUAL_TV
},
609 { USB_DEVICE(0x14aa, 0x0620), .driver_info
= TM6000_BOARD_FREECOM_AND_SIMILAR
},
610 { USB_DEVICE(0x06e1, 0xb339), .driver_info
= TM6000_BOARD_ADSTECH_MINI_DUAL_TV
},
611 { USB_DEVICE(0x2040, 0x6600), .driver_info
= TM6010_BOARD_HAUPPAUGE_900H
},
612 { USB_DEVICE(0x2040, 0x6601), .driver_info
= TM6010_BOARD_HAUPPAUGE_900H
},
613 { USB_DEVICE(0x2040, 0x6610), .driver_info
= TM6010_BOARD_HAUPPAUGE_900H
},
614 { USB_DEVICE(0x2040, 0x6611), .driver_info
= TM6010_BOARD_HAUPPAUGE_900H
},
615 { USB_DEVICE(0x6000, 0xdec0), .driver_info
= TM6010_BOARD_BEHOLD_WANDER
},
616 { USB_DEVICE(0x6000, 0xdec1), .driver_info
= TM6010_BOARD_BEHOLD_VOYAGER
},
617 { USB_DEVICE(0x0ccd, 0x0086), .driver_info
= TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
},
618 { USB_DEVICE(0x0ccd, 0x00A5), .driver_info
= TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
},
619 { USB_DEVICE(0x0ccd, 0x0079), .driver_info
= TM5600_BOARD_TERRATEC_GRABSTER
},
620 { USB_DEVICE(0x13d3, 0x3240), .driver_info
= TM6010_BOARD_TWINHAN_TU501
},
621 { USB_DEVICE(0x13d3, 0x3241), .driver_info
= TM6010_BOARD_TWINHAN_TU501
},
622 { USB_DEVICE(0x13d3, 0x3243), .driver_info
= TM6010_BOARD_TWINHAN_TU501
},
623 { USB_DEVICE(0x13d3, 0x3264), .driver_info
= TM6010_BOARD_TWINHAN_TU501
},
624 { USB_DEVICE(0x6000, 0xdec2), .driver_info
= TM6010_BOARD_BEHOLD_WANDER_LITE
},
625 { USB_DEVICE(0x6000, 0xdec3), .driver_info
= TM6010_BOARD_BEHOLD_VOYAGER_LITE
},
628 MODULE_DEVICE_TABLE(usb
, tm6000_id_table
);
630 /* Control power led for show some activity */
631 void tm6000_flash_led(struct tm6000_core
*dev
, u8 state
)
633 /* Power LED unconfigured */
634 if (!dev
->gpio
.power_led
)
639 switch (dev
->model
) {
640 case TM6010_BOARD_HAUPPAUGE_900H
:
641 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
:
642 case TM6010_BOARD_TWINHAN_TU501
:
643 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
644 dev
->gpio
.power_led
, 0x00);
646 case TM6010_BOARD_BEHOLD_WANDER
:
647 case TM6010_BOARD_BEHOLD_VOYAGER
:
648 case TM6010_BOARD_BEHOLD_WANDER_LITE
:
649 case TM6010_BOARD_BEHOLD_VOYAGER_LITE
:
650 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
651 dev
->gpio
.power_led
, 0x01);
657 switch (dev
->model
) {
658 case TM6010_BOARD_HAUPPAUGE_900H
:
659 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
:
660 case TM6010_BOARD_TWINHAN_TU501
:
661 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
662 dev
->gpio
.power_led
, 0x01);
664 case TM6010_BOARD_BEHOLD_WANDER
:
665 case TM6010_BOARD_BEHOLD_VOYAGER
:
666 case TM6010_BOARD_BEHOLD_WANDER_LITE
:
667 case TM6010_BOARD_BEHOLD_VOYAGER_LITE
:
668 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
669 dev
->gpio
.power_led
, 0x00);
675 /* Tuner callback to provide the proper gpio changes needed for xc5000 */
676 int tm6000_xc5000_callback(void *ptr
, int component
, int command
, int arg
)
679 struct tm6000_core
*dev
= ptr
;
681 if (dev
->tuner_type
!= TUNER_XC5000
)
685 case XC5000_TUNER_RESET
:
686 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
687 dev
->gpio
.tuner_reset
, 0x01);
689 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
690 dev
->gpio
.tuner_reset
, 0x00);
692 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
693 dev
->gpio
.tuner_reset
, 0x01);
698 EXPORT_SYMBOL_GPL(tm6000_xc5000_callback
);
700 /* Tuner callback to provide the proper gpio changes needed for xc2028 */
702 int tm6000_tuner_callback(void *ptr
, int component
, int command
, int arg
)
705 struct tm6000_core
*dev
= ptr
;
707 if (dev
->tuner_type
!= TUNER_XC2028
)
711 case XC2028_RESET_CLK
:
712 tm6000_ir_wait(dev
, 0);
714 tm6000_set_reg(dev
, REQ_04_EN_DISABLE_MCU_INT
,
717 rc
= tm6000_i2c_reset(dev
, 10);
719 case XC2028_TUNER_RESET
:
720 /* Reset codes during load firmware */
723 /* newer tuner can faster reset */
724 switch (dev
->model
) {
725 case TM5600_BOARD_10MOONS_UT821
:
726 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
727 dev
->gpio
.tuner_reset
, 0x01);
728 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
731 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
732 dev
->gpio
.tuner_reset
, 0x00);
733 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
736 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
737 dev
->gpio
.tuner_reset
, 0x01);
738 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
741 case TM6010_BOARD_HAUPPAUGE_900H
:
742 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
:
743 case TM6010_BOARD_TWINHAN_TU501
:
744 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
745 dev
->gpio
.tuner_reset
, 0x01);
747 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
748 dev
->gpio
.tuner_reset
, 0x00);
750 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
751 dev
->gpio
.tuner_reset
, 0x01);
755 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
756 dev
->gpio
.tuner_reset
, 0x00);
758 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
759 dev
->gpio
.tuner_reset
, 0x01);
764 tm6000_ir_wait(dev
, 1);
767 tm6000_set_reg(dev
, REQ_04_EN_DISABLE_MCU_INT
,
772 rc
= tm6000_i2c_reset(dev
, 100);
776 case XC2028_I2C_FLUSH
:
777 tm6000_set_reg(dev
, REQ_50_SET_START
, 0, 0);
778 tm6000_set_reg(dev
, REQ_51_SET_STOP
, 0, 0);
783 EXPORT_SYMBOL_GPL(tm6000_tuner_callback
);
785 int tm6000_cards_setup(struct tm6000_core
*dev
)
788 * Board-specific initialization sequence. Handles all GPIO
789 * initialization sequences that are board-specific.
790 * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
791 * Probably, they're all based on some reference device. Due to that,
792 * there's a common routine at the end to handle those GPIO's. Devices
793 * that use different pinups or init sequences can just return at
794 * the board-specific session.
796 switch (dev
->model
) {
797 case TM6010_BOARD_HAUPPAUGE_900H
:
798 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
:
799 case TM6010_BOARD_TWINHAN_TU501
:
800 case TM6010_BOARD_GENERIC
:
801 /* Turn xceive 3028 on */
802 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.tuner_on
, 0x01);
804 /* Turn zarlink zl10353 on */
805 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.demod_on
, 0x00);
807 /* Reset zarlink zl10353 */
808 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.demod_reset
, 0x00);
810 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.demod_reset
, 0x01);
812 /* Turn zarlink zl10353 off */
813 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.demod_on
, 0x01);
816 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.ir
, 0x01);
818 /* Power led on (blue) */
819 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.power_led
, 0x00);
821 /* DVB led off (orange) */
822 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.dvb_led
, 0x01);
824 /* Turn zarlink zl10353 on */
825 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.demod_on
, 0x00);
828 case TM6010_BOARD_BEHOLD_WANDER
:
829 case TM6010_BOARD_BEHOLD_WANDER_LITE
:
830 /* Power led on (blue) */
831 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.power_led
, 0x01);
833 /* Reset zarlink zl10353 */
834 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.demod_reset
, 0x00);
836 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.demod_reset
, 0x01);
839 case TM6010_BOARD_BEHOLD_VOYAGER
:
840 case TM6010_BOARD_BEHOLD_VOYAGER_LITE
:
841 /* Power led on (blue) */
842 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
, dev
->gpio
.power_led
, 0x01);
850 * Default initialization. Most of the devices seem to use GPIO1
851 * and GPIO4.on the same way, so, this handles the common sequence
852 * used by most devices.
853 * If a device uses a different sequence or different GPIO pins for
854 * reset, just add the code at the board-specific part
857 if (dev
->gpio
.tuner_reset
) {
861 for (i
= 0; i
< 2; i
++) {
862 rc
= tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
863 dev
->gpio
.tuner_reset
, 0x00);
865 printk(KERN_ERR
"Error %i doing tuner reset\n", rc
);
869 msleep(10); /* Just to be conservative */
870 rc
= tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
871 dev
->gpio
.tuner_reset
, 0x01);
873 printk(KERN_ERR
"Error %i doing tuner reset\n", rc
);
878 printk(KERN_ERR
"Tuner reset is not configured\n");
887 static void tm6000_config_tuner(struct tm6000_core
*dev
)
889 struct tuner_setup tun_setup
;
891 /* Load tuner module */
892 v4l2_i2c_new_subdev(&dev
->v4l2_dev
, &dev
->i2c_adap
,
893 "tuner", dev
->tuner_addr
, NULL
);
895 memset(&tun_setup
, 0, sizeof(tun_setup
));
896 tun_setup
.type
= dev
->tuner_type
;
897 tun_setup
.addr
= dev
->tuner_addr
;
899 tun_setup
.mode_mask
= 0;
900 if (dev
->caps
.has_tuner
)
901 tun_setup
.mode_mask
|= (T_ANALOG_TV
| T_RADIO
);
903 switch (dev
->tuner_type
) {
905 tun_setup
.tuner_callback
= tm6000_tuner_callback
;
908 tun_setup
.tuner_callback
= tm6000_xc5000_callback
;
912 v4l2_device_call_all(&dev
->v4l2_dev
, 0, tuner
, s_type_addr
, &tun_setup
);
914 switch (dev
->tuner_type
) {
916 struct v4l2_priv_tun_config xc2028_cfg
;
917 struct xc2028_ctrl ctl
;
919 memset(&xc2028_cfg
, 0, sizeof(xc2028_cfg
));
920 memset(&ctl
, 0, sizeof(ctl
));
922 ctl
.demod
= XC3028_FE_ZARLINK456
;
924 xc2028_cfg
.tuner
= TUNER_XC2028
;
925 xc2028_cfg
.priv
= &ctl
;
927 switch (dev
->model
) {
928 case TM6010_BOARD_HAUPPAUGE_900H
:
929 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
:
930 case TM6010_BOARD_TWINHAN_TU501
:
932 ctl
.fname
= "xc3028L-v36.fw";
935 if (dev
->dev_type
== TM6010
)
936 ctl
.fname
= "xc3028-v27.fw";
938 ctl
.fname
= "xc3028-v24.fw";
941 printk(KERN_INFO
"Setting firmware parameters for xc2028\n");
942 v4l2_device_call_all(&dev
->v4l2_dev
, 0, tuner
, s_config
,
949 struct v4l2_priv_tun_config xc5000_cfg
;
950 struct xc5000_config ctl
= {
951 .i2c_address
= dev
->tuner_addr
,
953 .radio_input
= XC5000_RADIO_FM1_MONO
,
956 xc5000_cfg
.tuner
= TUNER_XC5000
;
957 xc5000_cfg
.priv
= &ctl
;
959 v4l2_device_call_all(&dev
->v4l2_dev
, 0, tuner
, s_config
,
964 printk(KERN_INFO
"Unknown tuner type. Tuner is not configured.\n");
969 static int fill_board_specific_data(struct tm6000_core
*dev
)
973 dev
->dev_type
= tm6000_boards
[dev
->model
].type
;
974 dev
->tuner_type
= tm6000_boards
[dev
->model
].tuner_type
;
975 dev
->tuner_addr
= tm6000_boards
[dev
->model
].tuner_addr
;
977 dev
->gpio
= tm6000_boards
[dev
->model
].gpio
;
979 dev
->ir_codes
= tm6000_boards
[dev
->model
].ir_codes
;
981 dev
->demod_addr
= tm6000_boards
[dev
->model
].demod_addr
;
983 dev
->caps
= tm6000_boards
[dev
->model
].caps
;
985 dev
->vinput
[0] = tm6000_boards
[dev
->model
].vinput
[0];
986 dev
->vinput
[1] = tm6000_boards
[dev
->model
].vinput
[1];
987 dev
->vinput
[2] = tm6000_boards
[dev
->model
].vinput
[2];
988 dev
->rinput
= tm6000_boards
[dev
->model
].rinput
;
990 /* setup per-model quirks */
991 switch (dev
->model
) {
992 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
:
993 case TM6010_BOARD_HAUPPAUGE_900H
:
994 dev
->quirks
|= TM6000_QUIRK_NO_USB_DELAY
;
1001 /* initialize hardware */
1002 rc
= tm6000_init(dev
);
1006 return v4l2_device_register(&dev
->udev
->dev
, &dev
->v4l2_dev
);
1010 static void use_alternative_detection_method(struct tm6000_core
*dev
)
1014 if (!dev
->eedata_size
)
1017 for (i
= 0; i
< ARRAY_SIZE(tm6000_boards
); i
++) {
1018 if (!tm6000_boards
[i
].eename_size
)
1020 if (dev
->eedata_size
< tm6000_boards
[i
].eename_pos
+
1021 tm6000_boards
[i
].eename_size
)
1024 if (!memcmp(&dev
->eedata
[tm6000_boards
[i
].eename_pos
],
1025 tm6000_boards
[i
].eename
,
1026 tm6000_boards
[i
].eename_size
)) {
1032 printk(KERN_INFO
"Device has eeprom but is currently unknown\n");
1038 printk(KERN_INFO
"Device identified via eeprom as %s (type = %d)\n",
1039 tm6000_boards
[model
].name
, model
);
1042 #if defined(CONFIG_MODULES) && defined(MODULE)
1043 static void request_module_async(struct work_struct
*work
)
1045 struct tm6000_core
*dev
= container_of(work
, struct tm6000_core
,
1048 request_module("tm6000-alsa");
1050 if (dev
->caps
.has_dvb
)
1051 request_module("tm6000-dvb");
1054 static void request_modules(struct tm6000_core
*dev
)
1056 INIT_WORK(&dev
->request_module_wk
, request_module_async
);
1057 schedule_work(&dev
->request_module_wk
);
1060 static void flush_request_modules(struct tm6000_core
*dev
)
1062 flush_work(&dev
->request_module_wk
);
1065 #define request_modules(dev)
1066 #define flush_request_modules(dev)
1067 #endif /* CONFIG_MODULES */
1069 static int tm6000_init_dev(struct tm6000_core
*dev
)
1071 struct v4l2_frequency f
;
1074 mutex_init(&dev
->lock
);
1075 mutex_lock(&dev
->lock
);
1077 if (!is_generic(dev
->model
)) {
1078 rc
= fill_board_specific_data(dev
);
1082 /* register i2c bus */
1083 rc
= tm6000_i2c_register(dev
);
1087 /* register i2c bus */
1088 rc
= tm6000_i2c_register(dev
);
1092 use_alternative_detection_method(dev
);
1094 rc
= fill_board_specific_data(dev
);
1099 /* Default values for STD and resolutions */
1102 dev
->norm
= V4L2_STD_NTSC_M
;
1104 /* Configure tuner */
1105 tm6000_config_tuner(dev
);
1107 /* Set video standard */
1108 v4l2_device_call_all(&dev
->v4l2_dev
, 0, video
, s_std
, dev
->norm
);
1110 /* Set tuner frequency - also loads firmware on xc2028/xc3028 */
1112 f
.type
= V4L2_TUNER_ANALOG_TV
;
1113 f
.frequency
= 3092; /* 193.25 MHz */
1114 dev
->freq
= f
.frequency
;
1115 v4l2_device_call_all(&dev
->v4l2_dev
, 0, tuner
, s_frequency
, &f
);
1117 if (dev
->caps
.has_tda9874
)
1118 v4l2_i2c_new_subdev(&dev
->v4l2_dev
, &dev
->i2c_adap
,
1119 "tvaudio", I2C_ADDR_TDA9874
, NULL
);
1121 /* register and initialize V4L2 */
1122 rc
= tm6000_v4l2_register(dev
);
1126 tm6000_add_into_devlist(dev
);
1127 tm6000_init_extension(dev
);
1129 tm6000_ir_init(dev
);
1131 request_modules(dev
);
1133 mutex_unlock(&dev
->lock
);
1137 mutex_unlock(&dev
->lock
);
1141 /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
1142 #define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
1144 static void get_max_endpoint(struct usb_device
*udev
,
1145 struct usb_host_interface
*alt
,
1147 struct usb_host_endpoint
*curr_e
,
1148 struct tm6000_endpoint
*tm_ep
)
1150 u16 tmp
= le16_to_cpu(curr_e
->desc
.wMaxPacketSize
);
1151 unsigned int size
= tmp
& 0x7ff;
1153 if (udev
->speed
== USB_SPEED_HIGH
)
1154 size
= size
* hb_mult(tmp
);
1156 if (size
> tm_ep
->maxsize
) {
1157 tm_ep
->endp
= curr_e
;
1158 tm_ep
->maxsize
= size
;
1159 tm_ep
->bInterfaceNumber
= alt
->desc
.bInterfaceNumber
;
1160 tm_ep
->bAlternateSetting
= alt
->desc
.bAlternateSetting
;
1162 printk(KERN_INFO
"tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
1163 msgtype
, curr_e
->desc
.bEndpointAddress
,
1169 * tm6000_usb_probe()
1170 * checks for supported devices
1172 static int tm6000_usb_probe(struct usb_interface
*interface
,
1173 const struct usb_device_id
*id
)
1175 struct usb_device
*usbdev
;
1176 struct tm6000_core
*dev
;
1181 usbdev
= usb_get_dev(interface_to_usbdev(interface
));
1183 /* Selects the proper interface */
1184 rc
= usb_set_interface(usbdev
, 0, 1);
1186 goto report_failure
;
1188 /* Check to see next free device and mark as used */
1189 nr
= find_first_zero_bit(&tm6000_devused
, TM6000_MAXBOARDS
);
1190 if (nr
>= TM6000_MAXBOARDS
) {
1191 printk(KERN_ERR
"tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS
);
1196 /* Create and initialize dev struct */
1197 dev
= kzalloc(sizeof(*dev
), GFP_KERNEL
);
1202 spin_lock_init(&dev
->slock
);
1203 mutex_init(&dev
->usb_lock
);
1205 /* Increment usage count */
1206 set_bit(nr
, &tm6000_devused
);
1207 snprintf(dev
->name
, 29, "tm6000 #%d", nr
);
1209 dev
->model
= id
->driver_info
;
1210 if (card
[nr
] < ARRAY_SIZE(tm6000_boards
))
1211 dev
->model
= card
[nr
];
1216 switch (usbdev
->speed
) {
1220 case USB_SPEED_UNKNOWN
:
1221 case USB_SPEED_FULL
:
1224 case USB_SPEED_HIGH
:
1232 for (i
= 0; i
< interface
->num_altsetting
; i
++) {
1235 for (ep
= 0; ep
< interface
->altsetting
[i
].desc
.bNumEndpoints
; ep
++) {
1236 struct usb_host_endpoint
*e
;
1239 e
= &interface
->altsetting
[i
].endpoint
[ep
];
1241 dir_out
= ((e
->desc
.bEndpointAddress
&
1242 USB_ENDPOINT_DIR_MASK
) == USB_DIR_OUT
);
1244 printk(KERN_INFO
"tm6000: alt %d, interface %i, class %i\n",
1246 interface
->altsetting
[i
].desc
.bInterfaceNumber
,
1247 interface
->altsetting
[i
].desc
.bInterfaceClass
);
1249 switch (e
->desc
.bmAttributes
) {
1250 case USB_ENDPOINT_XFER_BULK
:
1252 get_max_endpoint(usbdev
,
1253 &interface
->altsetting
[i
],
1257 get_max_endpoint(usbdev
,
1258 &interface
->altsetting
[i
],
1263 case USB_ENDPOINT_XFER_ISOC
:
1265 get_max_endpoint(usbdev
,
1266 &interface
->altsetting
[i
],
1270 get_max_endpoint(usbdev
,
1271 &interface
->altsetting
[i
],
1276 case USB_ENDPOINT_XFER_INT
:
1278 get_max_endpoint(usbdev
,
1279 &interface
->altsetting
[i
],
1283 get_max_endpoint(usbdev
,
1284 &interface
->altsetting
[i
],
1294 printk(KERN_INFO
"tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
1296 le16_to_cpu(dev
->udev
->descriptor
.idVendor
),
1297 le16_to_cpu(dev
->udev
->descriptor
.idProduct
),
1298 interface
->altsetting
->desc
.bInterfaceNumber
);
1300 /* check if the the device has the iso in endpoint at the correct place */
1301 if (!dev
->isoc_in
.endp
) {
1302 printk(KERN_ERR
"tm6000: probing error: no IN ISOC endpoint!\n");
1307 /* save our data pointer in this interface device */
1308 usb_set_intfdata(interface
, dev
);
1310 printk(KERN_INFO
"tm6000: Found %s\n", tm6000_boards
[dev
->model
].name
);
1312 rc
= tm6000_init_dev(dev
);
1321 printk(KERN_ERR
"tm6000: Error %d while registering\n", rc
);
1323 clear_bit(nr
, &tm6000_devused
);
1325 usb_put_dev(usbdev
);
1330 * tm6000_usb_disconnect()
1331 * called when the device gets diconencted
1332 * video device will be unregistered on v4l2_close in case it is still open
1334 static void tm6000_usb_disconnect(struct usb_interface
*interface
)
1336 struct tm6000_core
*dev
= usb_get_intfdata(interface
);
1337 usb_set_intfdata(interface
, NULL
);
1342 printk(KERN_INFO
"tm6000: disconnecting %s\n", dev
->name
);
1344 flush_request_modules(dev
);
1346 tm6000_ir_fini(dev
);
1348 if (dev
->gpio
.power_led
) {
1349 switch (dev
->model
) {
1350 case TM6010_BOARD_HAUPPAUGE_900H
:
1351 case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE
:
1352 case TM6010_BOARD_TWINHAN_TU501
:
1354 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
1355 dev
->gpio
.power_led
, 0x01);
1358 case TM6010_BOARD_BEHOLD_WANDER
:
1359 case TM6010_BOARD_BEHOLD_VOYAGER
:
1360 case TM6010_BOARD_BEHOLD_WANDER_LITE
:
1361 case TM6010_BOARD_BEHOLD_VOYAGER_LITE
:
1363 tm6000_set_reg(dev
, REQ_03_SET_GET_MCU_PIN
,
1364 dev
->gpio
.power_led
, 0x00);
1369 tm6000_v4l2_unregister(dev
);
1371 tm6000_i2c_unregister(dev
);
1373 v4l2_device_unregister(&dev
->v4l2_dev
);
1375 dev
->state
|= DEV_DISCONNECTED
;
1377 usb_put_dev(dev
->udev
);
1379 tm6000_close_extension(dev
);
1380 tm6000_remove_from_devlist(dev
);
1382 clear_bit(dev
->devno
, &tm6000_devused
);
1386 static struct usb_driver tm6000_usb_driver
= {
1388 .probe
= tm6000_usb_probe
,
1389 .disconnect
= tm6000_usb_disconnect
,
1390 .id_table
= tm6000_id_table
,
1393 module_usb_driver(tm6000_usb_driver
);
1395 MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
1396 MODULE_AUTHOR("Mauro Carvalho Chehab");
1397 MODULE_LICENSE("GPL v2");