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.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
#include <linux/init.h>
21
#include <linux/module.h>
22
#include <linux/pci.h>
23
#include <linux/delay.h>
24
#include <linux/i2c.h>
25
#include <linux/usb.h>
26
#include <linux/slab.h>
27
#include <media/v4l2-common.h>
28
#include <media/tuner.h>
29
#include <media/tvaudio.h>
30
#include <media/i2c-addr.h>
31
#include <media/rc-map.h>
34
#include "tm6000-regs.h"
35
#include "tuner-xc2028.h"
38
#define TM6000_BOARD_UNKNOWN 0
39
#define TM5600_BOARD_GENERIC 1
40
#define TM6000_BOARD_GENERIC 2
41
#define TM6010_BOARD_GENERIC 3
42
#define TM5600_BOARD_10MOONS_UT821 4
43
#define TM5600_BOARD_10MOONS_UT330 5
44
#define TM6000_BOARD_ADSTECH_DUAL_TV 6
45
#define TM6000_BOARD_FREECOM_AND_SIMILAR 7
46
#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV 8
47
#define TM6010_BOARD_HAUPPAUGE_900H 9
48
#define TM6010_BOARD_BEHOLD_WANDER 10
49
#define TM6010_BOARD_BEHOLD_VOYAGER 11
50
#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE 12
51
#define TM6010_BOARD_TWINHAN_TU501 13
52
#define TM6010_BOARD_BEHOLD_WANDER_LITE 14
53
#define TM6010_BOARD_BEHOLD_VOYAGER_LITE 15
54
#define TM5600_BOARD_TERRATEC_GRABSTER 16
56
#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
57
(model == TM5600_BOARD_GENERIC) || \
58
(model == TM6000_BOARD_GENERIC) || \
59
(model == TM6010_BOARD_GENERIC))
61
#define TM6000_MAXBOARDS 16
62
static unsigned int card[] = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
64
module_param_array(card, int, NULL, 0444);
66
static unsigned long tm6000_devused;
71
char eename[16]; /* EEPROM name */
72
unsigned eename_size; /* size of EEPROM name */
73
unsigned eename_pos; /* Position where it appears at ROM */
75
struct tm6000_capabilities caps;
77
enum tm6000_devtype type; /* variant of the chipset */
78
int tuner_type; /* type of the tuner */
79
int tuner_addr; /* tuner address */
80
int demod_addr; /* demodulator address */
82
struct tm6000_gpio gpio;
84
struct tm6000_input vinput[3];
85
struct tm6000_input rinput;
90
static struct tm6000_board tm6000_boards[] = {
91
[TM6000_BOARD_UNKNOWN] = {
92
.name = "Unknown tm6000 video grabber",
98
.tuner_reset = TM6000_GPIO_1,
101
.type = TM6000_INPUT_TV,
102
.vmux = TM6000_VMUX_VIDEO_B,
103
.amux = TM6000_AMUX_ADC1,
105
.type = TM6000_INPUT_COMPOSITE1,
106
.vmux = TM6000_VMUX_VIDEO_A,
107
.amux = TM6000_AMUX_ADC2,
109
.type = TM6000_INPUT_SVIDEO,
110
.vmux = TM6000_VMUX_VIDEO_AB,
111
.amux = TM6000_AMUX_ADC2,
115
[TM5600_BOARD_GENERIC] = {
116
.name = "Generic tm5600 board",
118
.tuner_type = TUNER_XC2028,
119
.tuner_addr = 0xc2 >> 1,
125
.tuner_reset = TM6000_GPIO_1,
128
.type = TM6000_INPUT_TV,
129
.vmux = TM6000_VMUX_VIDEO_B,
130
.amux = TM6000_AMUX_ADC1,
132
.type = TM6000_INPUT_COMPOSITE1,
133
.vmux = TM6000_VMUX_VIDEO_A,
134
.amux = TM6000_AMUX_ADC2,
136
.type = TM6000_INPUT_SVIDEO,
137
.vmux = TM6000_VMUX_VIDEO_AB,
138
.amux = TM6000_AMUX_ADC2,
142
[TM6000_BOARD_GENERIC] = {
143
.name = "Generic tm6000 board",
144
.tuner_type = TUNER_XC2028,
145
.tuner_addr = 0xc2 >> 1,
151
.tuner_reset = TM6000_GPIO_1,
154
.type = TM6000_INPUT_TV,
155
.vmux = TM6000_VMUX_VIDEO_B,
156
.amux = TM6000_AMUX_ADC1,
158
.type = TM6000_INPUT_COMPOSITE1,
159
.vmux = TM6000_VMUX_VIDEO_A,
160
.amux = TM6000_AMUX_ADC2,
162
.type = TM6000_INPUT_SVIDEO,
163
.vmux = TM6000_VMUX_VIDEO_AB,
164
.amux = TM6000_AMUX_ADC2,
168
[TM6010_BOARD_GENERIC] = {
169
.name = "Generic tm6010 board",
171
.tuner_type = TUNER_XC2028,
172
.tuner_addr = 0xc2 >> 1,
173
.demod_addr = 0x1e >> 1,
182
.tuner_reset = TM6010_GPIO_2,
183
.tuner_on = TM6010_GPIO_3,
184
.demod_reset = TM6010_GPIO_1,
185
.demod_on = TM6010_GPIO_4,
186
.power_led = TM6010_GPIO_7,
187
.dvb_led = TM6010_GPIO_5,
191
.type = TM6000_INPUT_TV,
192
.vmux = TM6000_VMUX_VIDEO_B,
193
.amux = TM6000_AMUX_SIF1,
195
.type = TM6000_INPUT_COMPOSITE1,
196
.vmux = TM6000_VMUX_VIDEO_A,
197
.amux = TM6000_AMUX_ADC2,
199
.type = TM6000_INPUT_SVIDEO,
200
.vmux = TM6000_VMUX_VIDEO_AB,
201
.amux = TM6000_AMUX_ADC2,
205
[TM5600_BOARD_10MOONS_UT821] = {
206
.name = "10Moons UT 821",
207
.tuner_type = TUNER_XC2028,
208
.eename = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
212
.tuner_addr = 0xc2 >> 1,
218
.tuner_reset = TM6000_GPIO_1,
221
.type = TM6000_INPUT_TV,
222
.vmux = TM6000_VMUX_VIDEO_B,
223
.amux = TM6000_AMUX_ADC1,
225
.type = TM6000_INPUT_COMPOSITE1,
226
.vmux = TM6000_VMUX_VIDEO_A,
227
.amux = TM6000_AMUX_ADC2,
229
.type = TM6000_INPUT_SVIDEO,
230
.vmux = TM6000_VMUX_VIDEO_AB,
231
.amux = TM6000_AMUX_ADC2,
235
[TM5600_BOARD_10MOONS_UT330] = {
236
.name = "10Moons UT 330",
237
.tuner_type = TUNER_PHILIPS_FQ1216AME_MK4,
238
.tuner_addr = 0xc8 >> 1,
246
.type = TM6000_INPUT_TV,
247
.vmux = TM6000_VMUX_VIDEO_B,
248
.amux = TM6000_AMUX_ADC1,
250
.type = TM6000_INPUT_COMPOSITE1,
251
.vmux = TM6000_VMUX_VIDEO_A,
252
.amux = TM6000_AMUX_ADC2,
254
.type = TM6000_INPUT_SVIDEO,
255
.vmux = TM6000_VMUX_VIDEO_AB,
256
.amux = TM6000_AMUX_ADC2,
260
[TM6000_BOARD_ADSTECH_DUAL_TV] = {
261
.name = "ADSTECH Dual TV USB",
262
.tuner_type = TUNER_XC2028,
263
.tuner_addr = 0xc8 >> 1,
272
.type = TM6000_INPUT_TV,
273
.vmux = TM6000_VMUX_VIDEO_B,
274
.amux = TM6000_AMUX_ADC1,
276
.type = TM6000_INPUT_COMPOSITE1,
277
.vmux = TM6000_VMUX_VIDEO_A,
278
.amux = TM6000_AMUX_ADC2,
280
.type = TM6000_INPUT_SVIDEO,
281
.vmux = TM6000_VMUX_VIDEO_AB,
282
.amux = TM6000_AMUX_ADC2,
286
[TM6000_BOARD_FREECOM_AND_SIMILAR] = {
287
.name = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
288
.tuner_type = TUNER_XC2028, /* has a XC3028 */
289
.tuner_addr = 0xc2 >> 1,
290
.demod_addr = 0x1e >> 1,
299
.tuner_reset = TM6000_GPIO_4,
302
.type = TM6000_INPUT_TV,
303
.vmux = TM6000_VMUX_VIDEO_B,
304
.amux = TM6000_AMUX_ADC1,
306
.type = TM6000_INPUT_COMPOSITE1,
307
.vmux = TM6000_VMUX_VIDEO_A,
308
.amux = TM6000_AMUX_ADC2,
310
.type = TM6000_INPUT_SVIDEO,
311
.vmux = TM6000_VMUX_VIDEO_AB,
312
.amux = TM6000_AMUX_ADC2,
316
[TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
317
.name = "ADSTECH Mini Dual TV USB",
318
.tuner_type = TUNER_XC2028, /* has a XC3028 */
319
.tuner_addr = 0xc8 >> 1,
320
.demod_addr = 0x1e >> 1,
328
.tuner_reset = TM6000_GPIO_4,
331
.type = TM6000_INPUT_TV,
332
.vmux = TM6000_VMUX_VIDEO_B,
333
.amux = TM6000_AMUX_ADC1,
335
.type = TM6000_INPUT_COMPOSITE1,
336
.vmux = TM6000_VMUX_VIDEO_A,
337
.amux = TM6000_AMUX_ADC2,
339
.type = TM6000_INPUT_SVIDEO,
340
.vmux = TM6000_VMUX_VIDEO_AB,
341
.amux = TM6000_AMUX_ADC2,
345
[TM6010_BOARD_HAUPPAUGE_900H] = {
346
.name = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
347
.eename = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
350
.tuner_type = TUNER_XC2028, /* has a XC3028 */
351
.tuner_addr = 0xc2 >> 1,
352
.demod_addr = 0x1e >> 1,
362
.tuner_reset = TM6010_GPIO_2,
363
.tuner_on = TM6010_GPIO_3,
364
.demod_reset = TM6010_GPIO_1,
365
.demod_on = TM6010_GPIO_4,
366
.power_led = TM6010_GPIO_7,
367
.dvb_led = TM6010_GPIO_5,
371
.type = TM6000_INPUT_TV,
372
.vmux = TM6000_VMUX_VIDEO_B,
373
.amux = TM6000_AMUX_SIF1,
375
.type = TM6000_INPUT_COMPOSITE1,
376
.vmux = TM6000_VMUX_VIDEO_A,
377
.amux = TM6000_AMUX_ADC2,
379
.type = TM6000_INPUT_SVIDEO,
380
.vmux = TM6000_VMUX_VIDEO_AB,
381
.amux = TM6000_AMUX_ADC2,
385
[TM6010_BOARD_BEHOLD_WANDER] = {
386
.name = "Beholder Wander DVB-T/TV/FM USB2.0",
387
.tuner_type = TUNER_XC5000,
388
.tuner_addr = 0xc2 >> 1,
389
.demod_addr = 0x1e >> 1,
400
.tuner_reset = TM6010_GPIO_0,
401
.demod_reset = TM6010_GPIO_1,
402
.power_led = TM6010_GPIO_6,
405
.type = TM6000_INPUT_TV,
406
.vmux = TM6000_VMUX_VIDEO_B,
407
.amux = TM6000_AMUX_SIF1,
409
.type = TM6000_INPUT_COMPOSITE1,
410
.vmux = TM6000_VMUX_VIDEO_A,
411
.amux = TM6000_AMUX_ADC2,
413
.type = TM6000_INPUT_SVIDEO,
414
.vmux = TM6000_VMUX_VIDEO_AB,
415
.amux = TM6000_AMUX_ADC2,
419
.type = TM6000_INPUT_RADIO,
420
.amux = TM6000_AMUX_ADC1,
423
[TM6010_BOARD_BEHOLD_VOYAGER] = {
424
.name = "Beholder Voyager TV/FM USB2.0",
425
.tuner_type = TUNER_XC5000,
426
.tuner_addr = 0xc2 >> 1,
437
.tuner_reset = TM6010_GPIO_0,
438
.power_led = TM6010_GPIO_6,
441
.type = TM6000_INPUT_TV,
442
.vmux = TM6000_VMUX_VIDEO_B,
443
.amux = TM6000_AMUX_SIF1,
445
.type = TM6000_INPUT_COMPOSITE1,
446
.vmux = TM6000_VMUX_VIDEO_A,
447
.amux = TM6000_AMUX_ADC2,
449
.type = TM6000_INPUT_SVIDEO,
450
.vmux = TM6000_VMUX_VIDEO_AB,
451
.amux = TM6000_AMUX_ADC2,
455
.type = TM6000_INPUT_RADIO,
456
.amux = TM6000_AMUX_ADC1,
459
[TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
460
.name = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
461
.tuner_type = TUNER_XC2028, /* has a XC3028 */
462
.tuner_addr = 0xc2 >> 1,
463
.demod_addr = 0x1e >> 1,
474
.tuner_reset = TM6010_GPIO_2,
475
.tuner_on = TM6010_GPIO_3,
476
.demod_reset = TM6010_GPIO_1,
477
.demod_on = TM6010_GPIO_4,
478
.power_led = TM6010_GPIO_7,
479
.dvb_led = TM6010_GPIO_5,
482
.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
484
.type = TM6000_INPUT_TV,
485
.vmux = TM6000_VMUX_VIDEO_B,
486
.amux = TM6000_AMUX_SIF1,
488
.type = TM6000_INPUT_COMPOSITE1,
489
.vmux = TM6000_VMUX_VIDEO_A,
490
.amux = TM6000_AMUX_ADC2,
492
.type = TM6000_INPUT_SVIDEO,
493
.vmux = TM6000_VMUX_VIDEO_AB,
494
.amux = TM6000_AMUX_ADC2,
498
.type = TM6000_INPUT_RADIO,
499
.amux = TM6000_AMUX_SIF1,
502
[TM5600_BOARD_TERRATEC_GRABSTER] = {
503
.name = "Terratec Grabster AV 150/250 MX",
505
.tuner_type = TUNER_ABSENT,
507
.type = TM6000_INPUT_TV,
508
.vmux = TM6000_VMUX_VIDEO_B,
509
.amux = TM6000_AMUX_ADC1,
511
.type = TM6000_INPUT_COMPOSITE1,
512
.vmux = TM6000_VMUX_VIDEO_A,
513
.amux = TM6000_AMUX_ADC2,
515
.type = TM6000_INPUT_SVIDEO,
516
.vmux = TM6000_VMUX_VIDEO_AB,
517
.amux = TM6000_AMUX_ADC2,
521
[TM6010_BOARD_TWINHAN_TU501] = {
522
.name = "Twinhan TU501(704D1)",
523
.tuner_type = TUNER_XC2028, /* has a XC3028 */
524
.tuner_addr = 0xc2 >> 1,
525
.demod_addr = 0x1e >> 1,
535
.tuner_reset = TM6010_GPIO_2,
536
.tuner_on = TM6010_GPIO_3,
537
.demod_reset = TM6010_GPIO_1,
538
.demod_on = TM6010_GPIO_4,
539
.power_led = TM6010_GPIO_7,
540
.dvb_led = TM6010_GPIO_5,
544
.type = TM6000_INPUT_TV,
545
.vmux = TM6000_VMUX_VIDEO_B,
546
.amux = TM6000_AMUX_SIF1,
548
.type = TM6000_INPUT_COMPOSITE1,
549
.vmux = TM6000_VMUX_VIDEO_A,
550
.amux = TM6000_AMUX_ADC2,
552
.type = TM6000_INPUT_SVIDEO,
553
.vmux = TM6000_VMUX_VIDEO_AB,
554
.amux = TM6000_AMUX_ADC2,
558
[TM6010_BOARD_BEHOLD_WANDER_LITE] = {
559
.name = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
560
.tuner_type = TUNER_XC5000,
561
.tuner_addr = 0xc2 >> 1,
562
.demod_addr = 0x1e >> 1,
573
.tuner_reset = TM6010_GPIO_0,
574
.demod_reset = TM6010_GPIO_1,
575
.power_led = TM6010_GPIO_6,
578
.type = TM6000_INPUT_TV,
579
.vmux = TM6000_VMUX_VIDEO_B,
580
.amux = TM6000_AMUX_SIF1,
584
.type = TM6000_INPUT_RADIO,
585
.amux = TM6000_AMUX_ADC1,
588
[TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
589
.name = "Beholder Voyager Lite TV/FM USB2.0",
590
.tuner_type = TUNER_XC5000,
591
.tuner_addr = 0xc2 >> 1,
602
.tuner_reset = TM6010_GPIO_0,
603
.power_led = TM6010_GPIO_6,
606
.type = TM6000_INPUT_TV,
607
.vmux = TM6000_VMUX_VIDEO_B,
608
.amux = TM6000_AMUX_SIF1,
612
.type = TM6000_INPUT_RADIO,
613
.amux = TM6000_AMUX_ADC1,
618
/* table of devices that work with this driver */
619
static struct usb_device_id tm6000_id_table[] = {
620
{ USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
621
{ USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
622
{ USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
623
{ USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
624
{ USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
625
{ USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
626
{ USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
627
{ USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
628
{ USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
629
{ USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
630
{ USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
631
{ USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
632
{ USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
633
{ USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
634
{ USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
635
{ USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
636
{ USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
637
{ USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
638
{ USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
639
{ USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
643
/* Control power led for show some activity */
644
void tm6000_flash_led(struct tm6000_core *dev, u8 state)
646
/* Power LED unconfigured */
647
if (!dev->gpio.power_led)
652
switch (dev->model) {
653
case TM6010_BOARD_HAUPPAUGE_900H:
654
case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
655
case TM6010_BOARD_TWINHAN_TU501:
656
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
657
dev->gpio.power_led, 0x00);
659
case TM6010_BOARD_BEHOLD_WANDER:
660
case TM6010_BOARD_BEHOLD_VOYAGER:
661
case TM6010_BOARD_BEHOLD_WANDER_LITE:
662
case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
663
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
664
dev->gpio.power_led, 0x01);
670
switch (dev->model) {
671
case TM6010_BOARD_HAUPPAUGE_900H:
672
case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
673
case TM6010_BOARD_TWINHAN_TU501:
674
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
675
dev->gpio.power_led, 0x01);
677
case TM6010_BOARD_BEHOLD_WANDER:
678
case TM6010_BOARD_BEHOLD_VOYAGER:
679
case TM6010_BOARD_BEHOLD_WANDER_LITE:
680
case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
681
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
682
dev->gpio.power_led, 0x00);
688
/* Tuner callback to provide the proper gpio changes needed for xc5000 */
689
int tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
692
struct tm6000_core *dev = ptr;
694
if (dev->tuner_type != TUNER_XC5000)
698
case XC5000_TUNER_RESET:
699
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
700
dev->gpio.tuner_reset, 0x01);
702
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
703
dev->gpio.tuner_reset, 0x00);
705
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
706
dev->gpio.tuner_reset, 0x01);
711
EXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
713
/* Tuner callback to provide the proper gpio changes needed for xc2028 */
715
int tm6000_tuner_callback(void *ptr, int component, int command, int arg)
718
struct tm6000_core *dev = ptr;
720
if (dev->tuner_type != TUNER_XC2028)
724
case XC2028_RESET_CLK:
725
tm6000_ir_wait(dev, 0);
727
tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
730
rc = tm6000_i2c_reset(dev, 10);
732
case XC2028_TUNER_RESET:
733
/* Reset codes during load firmware */
736
/* newer tuner can faster reset */
737
switch (dev->model) {
738
case TM5600_BOARD_10MOONS_UT821:
739
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
740
dev->gpio.tuner_reset, 0x01);
741
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
744
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
745
dev->gpio.tuner_reset, 0x00);
746
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
749
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
750
dev->gpio.tuner_reset, 0x01);
751
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
754
case TM6010_BOARD_HAUPPAUGE_900H:
755
case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
756
case TM6010_BOARD_TWINHAN_TU501:
757
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
758
dev->gpio.tuner_reset, 0x01);
760
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
761
dev->gpio.tuner_reset, 0x00);
763
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
764
dev->gpio.tuner_reset, 0x01);
768
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
769
dev->gpio.tuner_reset, 0x00);
771
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
772
dev->gpio.tuner_reset, 0x01);
777
tm6000_ir_wait(dev, 1);
780
tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
785
rc = tm6000_i2c_reset(dev, 100);
789
case XC2028_I2C_FLUSH:
790
tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
791
tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
796
EXPORT_SYMBOL_GPL(tm6000_tuner_callback);
798
int tm6000_cards_setup(struct tm6000_core *dev)
801
* Board-specific initialization sequence. Handles all GPIO
802
* initialization sequences that are board-specific.
803
* Up to now, all found devices use GPIO1 and GPIO4 at the same way.
804
* Probably, they're all based on some reference device. Due to that,
805
* there's a common routine at the end to handle those GPIO's. Devices
806
* that use different pinups or init sequences can just return at
807
* the board-specific session.
809
switch (dev->model) {
810
case TM6010_BOARD_HAUPPAUGE_900H:
811
case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
812
case TM6010_BOARD_TWINHAN_TU501:
813
case TM6010_BOARD_GENERIC:
814
/* Turn xceive 3028 on */
815
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
817
/* Turn zarlink zl10353 on */
818
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
820
/* Reset zarlink zl10353 */
821
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
823
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
825
/* Turn zarlink zl10353 off */
826
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
829
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
831
/* Power led on (blue) */
832
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
834
/* DVB led off (orange) */
835
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
837
/* Turn zarlink zl10353 on */
838
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
841
case TM6010_BOARD_BEHOLD_WANDER:
842
case TM6010_BOARD_BEHOLD_WANDER_LITE:
843
/* Power led on (blue) */
844
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
846
/* Reset zarlink zl10353 */
847
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
849
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
852
case TM6010_BOARD_BEHOLD_VOYAGER:
853
case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
854
/* Power led on (blue) */
855
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
863
* Default initialization. Most of the devices seem to use GPIO1
864
* and GPIO4.on the same way, so, this handles the common sequence
865
* used by most devices.
866
* If a device uses a different sequence or different GPIO pins for
867
* reset, just add the code at the board-specific part
870
if (dev->gpio.tuner_reset) {
874
for (i = 0; i < 2; i++) {
875
rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
876
dev->gpio.tuner_reset, 0x00);
878
printk(KERN_ERR "Error %i doing tuner reset\n", rc);
882
msleep(10); /* Just to be conservative */
883
rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
884
dev->gpio.tuner_reset, 0x01);
886
printk(KERN_ERR "Error %i doing tuner reset\n", rc);
891
printk(KERN_ERR "Tuner reset is not configured\n");
900
static void tm6000_config_tuner(struct tm6000_core *dev)
902
struct tuner_setup tun_setup;
904
/* Load tuner module */
905
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
906
"tuner", dev->tuner_addr, NULL);
908
memset(&tun_setup, 0, sizeof(tun_setup));
909
tun_setup.type = dev->tuner_type;
910
tun_setup.addr = dev->tuner_addr;
912
tun_setup.mode_mask = 0;
913
if (dev->caps.has_tuner)
914
tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
916
switch (dev->tuner_type) {
918
tun_setup.tuner_callback = tm6000_tuner_callback;
921
tun_setup.tuner_callback = tm6000_xc5000_callback;
925
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
927
switch (dev->tuner_type) {
929
struct v4l2_priv_tun_config xc2028_cfg;
930
struct xc2028_ctrl ctl;
932
memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
933
memset(&ctl, 0, sizeof(ctl));
935
ctl.demod = XC3028_FE_ZARLINK456;
937
xc2028_cfg.tuner = TUNER_XC2028;
938
xc2028_cfg.priv = &ctl;
940
switch (dev->model) {
941
case TM6010_BOARD_HAUPPAUGE_900H:
942
case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
943
case TM6010_BOARD_TWINHAN_TU501:
944
ctl.fname = "xc3028L-v36.fw";
947
if (dev->dev_type == TM6010)
948
ctl.fname = "xc3028-v27.fw";
950
ctl.fname = "xc3028-v24.fw";
953
printk(KERN_INFO "Setting firmware parameters for xc2028\n");
954
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
961
struct v4l2_priv_tun_config xc5000_cfg;
962
struct xc5000_config ctl = {
963
.i2c_address = dev->tuner_addr,
965
.radio_input = XC5000_RADIO_FM1_MONO,
968
xc5000_cfg.tuner = TUNER_XC5000;
969
xc5000_cfg.priv = &ctl;
971
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
976
printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
981
static int fill_board_specific_data(struct tm6000_core *dev)
985
dev->dev_type = tm6000_boards[dev->model].type;
986
dev->tuner_type = tm6000_boards[dev->model].tuner_type;
987
dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
989
dev->gpio = tm6000_boards[dev->model].gpio;
991
dev->ir_codes = tm6000_boards[dev->model].ir_codes;
993
dev->demod_addr = tm6000_boards[dev->model].demod_addr;
995
dev->caps = tm6000_boards[dev->model].caps;
997
dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
998
dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
999
dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
1000
dev->rinput = tm6000_boards[dev->model].rinput;
1002
/* setup per-model quirks */
1003
switch (dev->model) {
1004
case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
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
static int tm6000_init_dev(struct tm6000_core *dev)
1055
struct v4l2_frequency f;
1058
mutex_init(&dev->lock);
1059
mutex_lock(&dev->lock);
1061
if (!is_generic(dev->model)) {
1062
rc = fill_board_specific_data(dev);
1066
/* register i2c bus */
1067
rc = tm6000_i2c_register(dev);
1071
/* register i2c bus */
1072
rc = tm6000_i2c_register(dev);
1076
use_alternative_detection_method(dev);
1078
rc = fill_board_specific_data(dev);
1083
/* Default values for STD and resolutions */
1086
dev->norm = V4L2_STD_PAL_M;
1088
/* Configure tuner */
1089
tm6000_config_tuner(dev);
1091
/* Set video standard */
1092
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
1094
/* Set tuner frequency - also loads firmware on xc2028/xc3028 */
1096
f.type = V4L2_TUNER_ANALOG_TV;
1097
f.frequency = 3092; /* 193.25 MHz */
1098
dev->freq = f.frequency;
1099
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
1101
if (dev->caps.has_tda9874)
1102
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
1103
"tvaudio", I2C_ADDR_TDA9874, NULL);
1105
/* register and initialize V4L2 */
1106
rc = tm6000_v4l2_register(dev);
1110
tm6000_add_into_devlist(dev);
1111
tm6000_init_extension(dev);
1113
tm6000_ir_init(dev);
1115
mutex_unlock(&dev->lock);
1119
mutex_unlock(&dev->lock);
1123
/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
1124
#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
1126
static void get_max_endpoint(struct usb_device *udev,
1127
struct usb_host_interface *alt,
1129
struct usb_host_endpoint *curr_e,
1130
struct tm6000_endpoint *tm_ep)
1132
u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
1133
unsigned int size = tmp & 0x7ff;
1135
if (udev->speed == USB_SPEED_HIGH)
1136
size = size * hb_mult(tmp);
1138
if (size > tm_ep->maxsize) {
1139
tm_ep->endp = curr_e;
1140
tm_ep->maxsize = size;
1141
tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
1142
tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
1144
printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
1145
msgtype, curr_e->desc.bEndpointAddress,
1151
* tm6000_usb_probe()
1152
* checks for supported devices
1154
static int tm6000_usb_probe(struct usb_interface *interface,
1155
const struct usb_device_id *id)
1157
struct usb_device *usbdev;
1158
struct tm6000_core *dev = NULL;
1163
usbdev = usb_get_dev(interface_to_usbdev(interface));
1165
/* Selects the proper interface */
1166
rc = usb_set_interface(usbdev, 0, 1);
1170
/* Check to see next free device and mark as used */
1171
nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
1172
if (nr >= TM6000_MAXBOARDS) {
1173
printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
1174
usb_put_dev(usbdev);
1178
/* Create and initialize dev struct */
1179
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1181
printk(KERN_ERR "tm6000" ": out of memory!\n");
1182
usb_put_dev(usbdev);
1185
spin_lock_init(&dev->slock);
1186
mutex_init(&dev->usb_lock);
1188
/* Increment usage count */
1189
set_bit(nr, &tm6000_devused);
1190
snprintf(dev->name, 29, "tm6000 #%d", nr);
1192
dev->model = id->driver_info;
1193
if (card[nr] < ARRAY_SIZE(tm6000_boards))
1194
dev->model = card[nr];
1199
switch (usbdev->speed) {
1203
case USB_SPEED_UNKNOWN:
1204
case USB_SPEED_FULL:
1207
case USB_SPEED_HIGH:
1215
for (i = 0; i < interface->num_altsetting; i++) {
1218
for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
1219
struct usb_host_endpoint *e;
1222
e = &interface->altsetting[i].endpoint[ep];
1224
dir_out = ((e->desc.bEndpointAddress &
1225
USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
1227
printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
1229
interface->altsetting[i].desc.bInterfaceNumber,
1230
interface->altsetting[i].desc.bInterfaceClass);
1232
switch (e->desc.bmAttributes) {
1233
case USB_ENDPOINT_XFER_BULK:
1235
get_max_endpoint(usbdev,
1236
&interface->altsetting[i],
1240
get_max_endpoint(usbdev,
1241
&interface->altsetting[i],
1246
case USB_ENDPOINT_XFER_ISOC:
1248
get_max_endpoint(usbdev,
1249
&interface->altsetting[i],
1253
get_max_endpoint(usbdev,
1254
&interface->altsetting[i],
1259
case USB_ENDPOINT_XFER_INT:
1261
get_max_endpoint(usbdev,
1262
&interface->altsetting[i],
1266
get_max_endpoint(usbdev,
1267
&interface->altsetting[i],
1277
printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
1279
le16_to_cpu(dev->udev->descriptor.idVendor),
1280
le16_to_cpu(dev->udev->descriptor.idProduct),
1281
interface->altsetting->desc.bInterfaceNumber);
1283
/* check if the the device has the iso in endpoint at the correct place */
1284
if (!dev->isoc_in.endp) {
1285
printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
1291
/* save our data pointer in this interface device */
1292
usb_set_intfdata(interface, dev);
1294
printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
1296
rc = tm6000_init_dev(dev);
1303
printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
1305
clear_bit(nr, &tm6000_devused);
1306
usb_put_dev(usbdev);
1313
* tm6000_usb_disconnect()
1314
* called when the device gets diconencted
1315
* video device will be unregistered on v4l2_close in case it is still open
1317
static void tm6000_usb_disconnect(struct usb_interface *interface)
1319
struct tm6000_core *dev = usb_get_intfdata(interface);
1320
usb_set_intfdata(interface, NULL);
1325
printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
1327
tm6000_ir_fini(dev);
1329
if (dev->gpio.power_led) {
1330
switch (dev->model) {
1331
case TM6010_BOARD_HAUPPAUGE_900H:
1332
case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
1333
case TM6010_BOARD_TWINHAN_TU501:
1335
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1336
dev->gpio.power_led, 0x01);
1339
case TM6010_BOARD_BEHOLD_WANDER:
1340
case TM6010_BOARD_BEHOLD_VOYAGER:
1341
case TM6010_BOARD_BEHOLD_WANDER_LITE:
1342
case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
1344
tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
1345
dev->gpio.power_led, 0x00);
1350
tm6000_v4l2_unregister(dev);
1352
tm6000_i2c_unregister(dev);
1354
v4l2_device_unregister(&dev->v4l2_dev);
1356
dev->state |= DEV_DISCONNECTED;
1358
usb_put_dev(dev->udev);
1360
tm6000_close_extension(dev);
1361
tm6000_remove_from_devlist(dev);
1363
clear_bit(dev->devno, &tm6000_devused);
1367
static struct usb_driver tm6000_usb_driver = {
1369
.probe = tm6000_usb_probe,
1370
.disconnect = tm6000_usb_disconnect,
1371
.id_table = tm6000_id_table,
1374
static int __init tm6000_module_init(void)
1378
printk(KERN_INFO "tm6000" " v4l2 driver version %d.%d.%d loaded\n",
1379
(TM6000_VERSION >> 16) & 0xff,
1380
(TM6000_VERSION >> 8) & 0xff, TM6000_VERSION & 0xff);
1382
/* register this driver with the USB subsystem */
1383
result = usb_register(&tm6000_usb_driver);
1385
printk(KERN_ERR "tm6000"
1386
" usb_register failed. Error number %d.\n", result);
1391
static void __exit tm6000_module_exit(void)
1393
/* deregister at USB subsystem */
1394
usb_deregister(&tm6000_usb_driver);
1397
module_init(tm6000_module_init);
1398
module_exit(tm6000_module_exit);
1400
MODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
1401
MODULE_AUTHOR("Mauro Carvalho Chehab");
1402
MODULE_LICENSE("GPL");