18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci// tm6000-cards.c - driver for TM5600/TM6000/TM6010 USB video capture devices
38c2ecf20Sopenharmony_ci//
48c2ecf20Sopenharmony_ci// Copyright (c) 2006-2007 Mauro Carvalho Chehab <mchehab@kernel.org>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/init.h>
78c2ecf20Sopenharmony_ci#include <linux/module.h>
88c2ecf20Sopenharmony_ci#include <linux/pci.h>
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/i2c.h>
118c2ecf20Sopenharmony_ci#include <linux/usb.h>
128c2ecf20Sopenharmony_ci#include <linux/slab.h>
138c2ecf20Sopenharmony_ci#include <media/v4l2-common.h>
148c2ecf20Sopenharmony_ci#include <media/tuner.h>
158c2ecf20Sopenharmony_ci#include <media/i2c/tvaudio.h>
168c2ecf20Sopenharmony_ci#include <media/rc-map.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "tm6000.h"
198c2ecf20Sopenharmony_ci#include "tm6000-regs.h"
208c2ecf20Sopenharmony_ci#include "tuner-xc2028.h"
218c2ecf20Sopenharmony_ci#include "xc5000.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define TM6000_BOARD_UNKNOWN			0
248c2ecf20Sopenharmony_ci#define TM5600_BOARD_GENERIC			1
258c2ecf20Sopenharmony_ci#define TM6000_BOARD_GENERIC			2
268c2ecf20Sopenharmony_ci#define TM6010_BOARD_GENERIC			3
278c2ecf20Sopenharmony_ci#define TM5600_BOARD_10MOONS_UT821		4
288c2ecf20Sopenharmony_ci#define TM5600_BOARD_10MOONS_UT330		5
298c2ecf20Sopenharmony_ci#define TM6000_BOARD_ADSTECH_DUAL_TV		6
308c2ecf20Sopenharmony_ci#define TM6000_BOARD_FREECOM_AND_SIMILAR	7
318c2ecf20Sopenharmony_ci#define TM6000_BOARD_ADSTECH_MINI_DUAL_TV	8
328c2ecf20Sopenharmony_ci#define TM6010_BOARD_HAUPPAUGE_900H		9
338c2ecf20Sopenharmony_ci#define TM6010_BOARD_BEHOLD_WANDER		10
348c2ecf20Sopenharmony_ci#define TM6010_BOARD_BEHOLD_VOYAGER		11
358c2ecf20Sopenharmony_ci#define TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE	12
368c2ecf20Sopenharmony_ci#define TM6010_BOARD_TWINHAN_TU501		13
378c2ecf20Sopenharmony_ci#define TM6010_BOARD_BEHOLD_WANDER_LITE		14
388c2ecf20Sopenharmony_ci#define TM6010_BOARD_BEHOLD_VOYAGER_LITE	15
398c2ecf20Sopenharmony_ci#define TM5600_BOARD_TERRATEC_GRABSTER		16
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define is_generic(model) ((model == TM6000_BOARD_UNKNOWN) || \
428c2ecf20Sopenharmony_ci			   (model == TM5600_BOARD_GENERIC) || \
438c2ecf20Sopenharmony_ci			   (model == TM6000_BOARD_GENERIC) || \
448c2ecf20Sopenharmony_ci			   (model == TM6010_BOARD_GENERIC))
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define TM6000_MAXBOARDS        16
478c2ecf20Sopenharmony_cistatic unsigned int card[]     = {[0 ... (TM6000_MAXBOARDS - 1)] = UNSET };
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cimodule_param_array(card,  int, NULL, 0444);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic unsigned long tm6000_devused;
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistruct tm6000_board {
558c2ecf20Sopenharmony_ci	char            *name;
568c2ecf20Sopenharmony_ci	char		eename[16];		/* EEPROM name */
578c2ecf20Sopenharmony_ci	unsigned	eename_size;		/* size of EEPROM name */
588c2ecf20Sopenharmony_ci	unsigned	eename_pos;		/* Position where it appears at ROM */
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	struct tm6000_capabilities caps;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	enum		tm6000_devtype type;	/* variant of the chipset */
638c2ecf20Sopenharmony_ci	int             tuner_type;     /* type of the tuner */
648c2ecf20Sopenharmony_ci	int             tuner_addr;     /* tuner address */
658c2ecf20Sopenharmony_ci	int             demod_addr;     /* demodulator address */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	struct tm6000_gpio gpio;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	struct tm6000_input	vinput[3];
708c2ecf20Sopenharmony_ci	struct tm6000_input	rinput;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	char		*ir_codes;
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic struct tm6000_board tm6000_boards[] = {
768c2ecf20Sopenharmony_ci	[TM6000_BOARD_UNKNOWN] = {
778c2ecf20Sopenharmony_ci		.name         = "Unknown tm6000 video grabber",
788c2ecf20Sopenharmony_ci		.caps = {
798c2ecf20Sopenharmony_ci			.has_tuner	= 1,
808c2ecf20Sopenharmony_ci			.has_eeprom	= 1,
818c2ecf20Sopenharmony_ci		},
828c2ecf20Sopenharmony_ci		.gpio = {
838c2ecf20Sopenharmony_ci			.tuner_reset	= TM6000_GPIO_1,
848c2ecf20Sopenharmony_ci		},
858c2ecf20Sopenharmony_ci		.vinput = { {
868c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
878c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
888c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
898c2ecf20Sopenharmony_ci			}, {
908c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
918c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
928c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
938c2ecf20Sopenharmony_ci			}, {
948c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
958c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
968c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
978c2ecf20Sopenharmony_ci			},
988c2ecf20Sopenharmony_ci		},
998c2ecf20Sopenharmony_ci	},
1008c2ecf20Sopenharmony_ci	[TM5600_BOARD_GENERIC] = {
1018c2ecf20Sopenharmony_ci		.name         = "Generic tm5600 board",
1028c2ecf20Sopenharmony_ci		.type         = TM5600,
1038c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028,
1048c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
1058c2ecf20Sopenharmony_ci		.caps = {
1068c2ecf20Sopenharmony_ci			.has_tuner	= 1,
1078c2ecf20Sopenharmony_ci			.has_eeprom	= 1,
1088c2ecf20Sopenharmony_ci		},
1098c2ecf20Sopenharmony_ci		.gpio = {
1108c2ecf20Sopenharmony_ci			.tuner_reset	= TM6000_GPIO_1,
1118c2ecf20Sopenharmony_ci		},
1128c2ecf20Sopenharmony_ci		.vinput = { {
1138c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
1148c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
1158c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
1168c2ecf20Sopenharmony_ci			}, {
1178c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
1188c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
1198c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
1208c2ecf20Sopenharmony_ci			}, {
1218c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
1228c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
1238c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
1248c2ecf20Sopenharmony_ci			},
1258c2ecf20Sopenharmony_ci		},
1268c2ecf20Sopenharmony_ci	},
1278c2ecf20Sopenharmony_ci	[TM6000_BOARD_GENERIC] = {
1288c2ecf20Sopenharmony_ci		.name         = "Generic tm6000 board",
1298c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028,
1308c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
1318c2ecf20Sopenharmony_ci		.caps = {
1328c2ecf20Sopenharmony_ci			.has_tuner	= 1,
1338c2ecf20Sopenharmony_ci			.has_eeprom	= 1,
1348c2ecf20Sopenharmony_ci		},
1358c2ecf20Sopenharmony_ci		.gpio = {
1368c2ecf20Sopenharmony_ci			.tuner_reset	= TM6000_GPIO_1,
1378c2ecf20Sopenharmony_ci		},
1388c2ecf20Sopenharmony_ci		.vinput = { {
1398c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
1408c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
1418c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
1428c2ecf20Sopenharmony_ci			}, {
1438c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
1448c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
1458c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
1468c2ecf20Sopenharmony_ci			}, {
1478c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
1488c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
1498c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
1508c2ecf20Sopenharmony_ci			},
1518c2ecf20Sopenharmony_ci		},
1528c2ecf20Sopenharmony_ci	},
1538c2ecf20Sopenharmony_ci	[TM6010_BOARD_GENERIC] = {
1548c2ecf20Sopenharmony_ci		.name         = "Generic tm6010 board",
1558c2ecf20Sopenharmony_ci		.type         = TM6010,
1568c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028,
1578c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
1588c2ecf20Sopenharmony_ci		.demod_addr   = 0x1e >> 1,
1598c2ecf20Sopenharmony_ci		.caps = {
1608c2ecf20Sopenharmony_ci			.has_tuner	= 1,
1618c2ecf20Sopenharmony_ci			.has_dvb	= 1,
1628c2ecf20Sopenharmony_ci			.has_zl10353	= 1,
1638c2ecf20Sopenharmony_ci			.has_eeprom	= 1,
1648c2ecf20Sopenharmony_ci			.has_remote	= 1,
1658c2ecf20Sopenharmony_ci		},
1668c2ecf20Sopenharmony_ci		.gpio = {
1678c2ecf20Sopenharmony_ci			.tuner_reset	= TM6010_GPIO_2,
1688c2ecf20Sopenharmony_ci			.tuner_on	= TM6010_GPIO_3,
1698c2ecf20Sopenharmony_ci			.demod_reset	= TM6010_GPIO_1,
1708c2ecf20Sopenharmony_ci			.demod_on	= TM6010_GPIO_4,
1718c2ecf20Sopenharmony_ci			.power_led	= TM6010_GPIO_7,
1728c2ecf20Sopenharmony_ci			.dvb_led	= TM6010_GPIO_5,
1738c2ecf20Sopenharmony_ci			.ir		= TM6010_GPIO_0,
1748c2ecf20Sopenharmony_ci		},
1758c2ecf20Sopenharmony_ci		.vinput = { {
1768c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
1778c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
1788c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_SIF1,
1798c2ecf20Sopenharmony_ci			}, {
1808c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
1818c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
1828c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
1838c2ecf20Sopenharmony_ci			}, {
1848c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
1858c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
1868c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
1878c2ecf20Sopenharmony_ci			},
1888c2ecf20Sopenharmony_ci		},
1898c2ecf20Sopenharmony_ci	},
1908c2ecf20Sopenharmony_ci	[TM5600_BOARD_10MOONS_UT821] = {
1918c2ecf20Sopenharmony_ci		.name         = "10Moons UT 821",
1928c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028,
1938c2ecf20Sopenharmony_ci		.eename       = { '1', '0', 'M', 'O', 'O', 'N', 'S', '5', '6', '0', '0', 0xff, 0x45, 0x5b},
1948c2ecf20Sopenharmony_ci		.eename_size  = 14,
1958c2ecf20Sopenharmony_ci		.eename_pos   = 0x14,
1968c2ecf20Sopenharmony_ci		.type         = TM5600,
1978c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
1988c2ecf20Sopenharmony_ci		.caps = {
1998c2ecf20Sopenharmony_ci			.has_tuner    = 1,
2008c2ecf20Sopenharmony_ci			.has_eeprom   = 1,
2018c2ecf20Sopenharmony_ci		},
2028c2ecf20Sopenharmony_ci		.gpio = {
2038c2ecf20Sopenharmony_ci			.tuner_reset	= TM6000_GPIO_1,
2048c2ecf20Sopenharmony_ci		},
2058c2ecf20Sopenharmony_ci		.vinput = { {
2068c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
2078c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
2088c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
2098c2ecf20Sopenharmony_ci			}, {
2108c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
2118c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
2128c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
2138c2ecf20Sopenharmony_ci			}, {
2148c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
2158c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
2168c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
2178c2ecf20Sopenharmony_ci			},
2188c2ecf20Sopenharmony_ci		},
2198c2ecf20Sopenharmony_ci	},
2208c2ecf20Sopenharmony_ci	[TM5600_BOARD_10MOONS_UT330] = {
2218c2ecf20Sopenharmony_ci		.name         = "10Moons UT 330",
2228c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_PHILIPS_FQ1216AME_MK4,
2238c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc8 >> 1,
2248c2ecf20Sopenharmony_ci		.caps = {
2258c2ecf20Sopenharmony_ci			.has_tuner    = 1,
2268c2ecf20Sopenharmony_ci			.has_dvb      = 0,
2278c2ecf20Sopenharmony_ci			.has_zl10353  = 0,
2288c2ecf20Sopenharmony_ci			.has_eeprom   = 1,
2298c2ecf20Sopenharmony_ci		},
2308c2ecf20Sopenharmony_ci		.vinput = { {
2318c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
2328c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
2338c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
2348c2ecf20Sopenharmony_ci			}, {
2358c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
2368c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
2378c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
2388c2ecf20Sopenharmony_ci			}, {
2398c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
2408c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
2418c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
2428c2ecf20Sopenharmony_ci			},
2438c2ecf20Sopenharmony_ci		},
2448c2ecf20Sopenharmony_ci	},
2458c2ecf20Sopenharmony_ci	[TM6000_BOARD_ADSTECH_DUAL_TV] = {
2468c2ecf20Sopenharmony_ci		.name         = "ADSTECH Dual TV USB",
2478c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028,
2488c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc8 >> 1,
2498c2ecf20Sopenharmony_ci		.caps = {
2508c2ecf20Sopenharmony_ci			.has_tuner    = 1,
2518c2ecf20Sopenharmony_ci			.has_tda9874  = 1,
2528c2ecf20Sopenharmony_ci			.has_dvb      = 1,
2538c2ecf20Sopenharmony_ci			.has_zl10353  = 1,
2548c2ecf20Sopenharmony_ci			.has_eeprom   = 1,
2558c2ecf20Sopenharmony_ci		},
2568c2ecf20Sopenharmony_ci		.vinput = { {
2578c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
2588c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
2598c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
2608c2ecf20Sopenharmony_ci			}, {
2618c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
2628c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
2638c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
2648c2ecf20Sopenharmony_ci			}, {
2658c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
2668c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
2678c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
2688c2ecf20Sopenharmony_ci			},
2698c2ecf20Sopenharmony_ci		},
2708c2ecf20Sopenharmony_ci	},
2718c2ecf20Sopenharmony_ci	[TM6000_BOARD_FREECOM_AND_SIMILAR] = {
2728c2ecf20Sopenharmony_ci		.name         = "Freecom Hybrid Stick / Moka DVB-T Receiver Dual",
2738c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
2748c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
2758c2ecf20Sopenharmony_ci		.demod_addr   = 0x1e >> 1,
2768c2ecf20Sopenharmony_ci		.caps = {
2778c2ecf20Sopenharmony_ci			.has_tuner    = 1,
2788c2ecf20Sopenharmony_ci			.has_dvb      = 1,
2798c2ecf20Sopenharmony_ci			.has_zl10353  = 1,
2808c2ecf20Sopenharmony_ci			.has_eeprom   = 0,
2818c2ecf20Sopenharmony_ci			.has_remote   = 1,
2828c2ecf20Sopenharmony_ci		},
2838c2ecf20Sopenharmony_ci		.gpio = {
2848c2ecf20Sopenharmony_ci			.tuner_reset	= TM6000_GPIO_4,
2858c2ecf20Sopenharmony_ci		},
2868c2ecf20Sopenharmony_ci		.vinput = { {
2878c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
2888c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
2898c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
2908c2ecf20Sopenharmony_ci			}, {
2918c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
2928c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
2938c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
2948c2ecf20Sopenharmony_ci			}, {
2958c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
2968c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
2978c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
2988c2ecf20Sopenharmony_ci			},
2998c2ecf20Sopenharmony_ci		},
3008c2ecf20Sopenharmony_ci	},
3018c2ecf20Sopenharmony_ci	[TM6000_BOARD_ADSTECH_MINI_DUAL_TV] = {
3028c2ecf20Sopenharmony_ci		.name         = "ADSTECH Mini Dual TV USB",
3038c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
3048c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc8 >> 1,
3058c2ecf20Sopenharmony_ci		.demod_addr   = 0x1e >> 1,
3068c2ecf20Sopenharmony_ci		.caps = {
3078c2ecf20Sopenharmony_ci			.has_tuner    = 1,
3088c2ecf20Sopenharmony_ci			.has_dvb      = 1,
3098c2ecf20Sopenharmony_ci			.has_zl10353  = 1,
3108c2ecf20Sopenharmony_ci			.has_eeprom   = 0,
3118c2ecf20Sopenharmony_ci		},
3128c2ecf20Sopenharmony_ci		.gpio = {
3138c2ecf20Sopenharmony_ci			.tuner_reset	= TM6000_GPIO_4,
3148c2ecf20Sopenharmony_ci		},
3158c2ecf20Sopenharmony_ci		.vinput = { {
3168c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
3178c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
3188c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
3198c2ecf20Sopenharmony_ci			}, {
3208c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
3218c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
3228c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
3238c2ecf20Sopenharmony_ci			}, {
3248c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
3258c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
3268c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
3278c2ecf20Sopenharmony_ci			},
3288c2ecf20Sopenharmony_ci		},
3298c2ecf20Sopenharmony_ci	},
3308c2ecf20Sopenharmony_ci	[TM6010_BOARD_HAUPPAUGE_900H] = {
3318c2ecf20Sopenharmony_ci		.name         = "Hauppauge WinTV HVR-900H / WinTV USB2-Stick",
3328c2ecf20Sopenharmony_ci		.eename       = { 'H', 0, 'V', 0, 'R', 0, '9', 0, '0', 0, '0', 0, 'H', 0 },
3338c2ecf20Sopenharmony_ci		.eename_size  = 14,
3348c2ecf20Sopenharmony_ci		.eename_pos   = 0x42,
3358c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
3368c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
3378c2ecf20Sopenharmony_ci		.demod_addr   = 0x1e >> 1,
3388c2ecf20Sopenharmony_ci		.type         = TM6010,
3398c2ecf20Sopenharmony_ci		.ir_codes = RC_MAP_HAUPPAUGE,
3408c2ecf20Sopenharmony_ci		.caps = {
3418c2ecf20Sopenharmony_ci			.has_tuner    = 1,
3428c2ecf20Sopenharmony_ci			.has_dvb      = 1,
3438c2ecf20Sopenharmony_ci			.has_zl10353  = 1,
3448c2ecf20Sopenharmony_ci			.has_eeprom   = 1,
3458c2ecf20Sopenharmony_ci			.has_remote   = 1,
3468c2ecf20Sopenharmony_ci		},
3478c2ecf20Sopenharmony_ci		.gpio = {
3488c2ecf20Sopenharmony_ci			.tuner_reset	= TM6010_GPIO_2,
3498c2ecf20Sopenharmony_ci			.tuner_on	= TM6010_GPIO_3,
3508c2ecf20Sopenharmony_ci			.demod_reset	= TM6010_GPIO_1,
3518c2ecf20Sopenharmony_ci			.demod_on	= TM6010_GPIO_4,
3528c2ecf20Sopenharmony_ci			.power_led	= TM6010_GPIO_7,
3538c2ecf20Sopenharmony_ci			.dvb_led	= TM6010_GPIO_5,
3548c2ecf20Sopenharmony_ci			.ir		= TM6010_GPIO_0,
3558c2ecf20Sopenharmony_ci		},
3568c2ecf20Sopenharmony_ci		.vinput = { {
3578c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
3588c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
3598c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_SIF1,
3608c2ecf20Sopenharmony_ci			}, {
3618c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
3628c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
3638c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
3648c2ecf20Sopenharmony_ci			}, {
3658c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
3668c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
3678c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
3688c2ecf20Sopenharmony_ci			},
3698c2ecf20Sopenharmony_ci		},
3708c2ecf20Sopenharmony_ci	},
3718c2ecf20Sopenharmony_ci	[TM6010_BOARD_BEHOLD_WANDER] = {
3728c2ecf20Sopenharmony_ci		.name         = "Beholder Wander DVB-T/TV/FM USB2.0",
3738c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC5000,
3748c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
3758c2ecf20Sopenharmony_ci		.demod_addr   = 0x1e >> 1,
3768c2ecf20Sopenharmony_ci		.type         = TM6010,
3778c2ecf20Sopenharmony_ci		.caps = {
3788c2ecf20Sopenharmony_ci			.has_tuner      = 1,
3798c2ecf20Sopenharmony_ci			.has_dvb        = 1,
3808c2ecf20Sopenharmony_ci			.has_zl10353    = 1,
3818c2ecf20Sopenharmony_ci			.has_eeprom     = 1,
3828c2ecf20Sopenharmony_ci			.has_remote     = 1,
3838c2ecf20Sopenharmony_ci			.has_radio	= 1,
3848c2ecf20Sopenharmony_ci		},
3858c2ecf20Sopenharmony_ci		.gpio = {
3868c2ecf20Sopenharmony_ci			.tuner_reset	= TM6010_GPIO_0,
3878c2ecf20Sopenharmony_ci			.demod_reset	= TM6010_GPIO_1,
3888c2ecf20Sopenharmony_ci			.power_led	= TM6010_GPIO_6,
3898c2ecf20Sopenharmony_ci		},
3908c2ecf20Sopenharmony_ci		.vinput = { {
3918c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
3928c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
3938c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_SIF1,
3948c2ecf20Sopenharmony_ci			}, {
3958c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
3968c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
3978c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
3988c2ecf20Sopenharmony_ci			}, {
3998c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
4008c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
4018c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
4028c2ecf20Sopenharmony_ci			},
4038c2ecf20Sopenharmony_ci		},
4048c2ecf20Sopenharmony_ci		.rinput = {
4058c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_RADIO,
4068c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
4078c2ecf20Sopenharmony_ci		},
4088c2ecf20Sopenharmony_ci	},
4098c2ecf20Sopenharmony_ci	[TM6010_BOARD_BEHOLD_VOYAGER] = {
4108c2ecf20Sopenharmony_ci		.name         = "Beholder Voyager TV/FM USB2.0",
4118c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC5000,
4128c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
4138c2ecf20Sopenharmony_ci		.type         = TM6010,
4148c2ecf20Sopenharmony_ci		.caps = {
4158c2ecf20Sopenharmony_ci			.has_tuner      = 1,
4168c2ecf20Sopenharmony_ci			.has_dvb        = 0,
4178c2ecf20Sopenharmony_ci			.has_zl10353    = 0,
4188c2ecf20Sopenharmony_ci			.has_eeprom     = 1,
4198c2ecf20Sopenharmony_ci			.has_remote     = 1,
4208c2ecf20Sopenharmony_ci			.has_radio	= 1,
4218c2ecf20Sopenharmony_ci		},
4228c2ecf20Sopenharmony_ci		.gpio = {
4238c2ecf20Sopenharmony_ci			.tuner_reset	= TM6010_GPIO_0,
4248c2ecf20Sopenharmony_ci			.power_led	= TM6010_GPIO_6,
4258c2ecf20Sopenharmony_ci		},
4268c2ecf20Sopenharmony_ci		.vinput = { {
4278c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
4288c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
4298c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_SIF1,
4308c2ecf20Sopenharmony_ci			}, {
4318c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
4328c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
4338c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
4348c2ecf20Sopenharmony_ci			}, {
4358c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
4368c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
4378c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
4388c2ecf20Sopenharmony_ci			},
4398c2ecf20Sopenharmony_ci		},
4408c2ecf20Sopenharmony_ci		.rinput = {
4418c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_RADIO,
4428c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
4438c2ecf20Sopenharmony_ci		},
4448c2ecf20Sopenharmony_ci	},
4458c2ecf20Sopenharmony_ci	[TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE] = {
4468c2ecf20Sopenharmony_ci		.name         = "Terratec Cinergy Hybrid XE / Cinergy Hybrid-Stick",
4478c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
4488c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
4498c2ecf20Sopenharmony_ci		.demod_addr   = 0x1e >> 1,
4508c2ecf20Sopenharmony_ci		.type         = TM6010,
4518c2ecf20Sopenharmony_ci		.caps = {
4528c2ecf20Sopenharmony_ci			.has_tuner    = 1,
4538c2ecf20Sopenharmony_ci			.has_dvb      = 1,
4548c2ecf20Sopenharmony_ci			.has_zl10353  = 1,
4558c2ecf20Sopenharmony_ci			.has_eeprom   = 1,
4568c2ecf20Sopenharmony_ci			.has_remote   = 1,
4578c2ecf20Sopenharmony_ci			.has_radio    = 1,
4588c2ecf20Sopenharmony_ci		},
4598c2ecf20Sopenharmony_ci		.gpio = {
4608c2ecf20Sopenharmony_ci			.tuner_reset	= TM6010_GPIO_2,
4618c2ecf20Sopenharmony_ci			.tuner_on	= TM6010_GPIO_3,
4628c2ecf20Sopenharmony_ci			.demod_reset	= TM6010_GPIO_1,
4638c2ecf20Sopenharmony_ci			.demod_on	= TM6010_GPIO_4,
4648c2ecf20Sopenharmony_ci			.power_led	= TM6010_GPIO_7,
4658c2ecf20Sopenharmony_ci			.dvb_led	= TM6010_GPIO_5,
4668c2ecf20Sopenharmony_ci			.ir		= TM6010_GPIO_0,
4678c2ecf20Sopenharmony_ci		},
4688c2ecf20Sopenharmony_ci		.ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS,
4698c2ecf20Sopenharmony_ci		.vinput = { {
4708c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
4718c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
4728c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_SIF1,
4738c2ecf20Sopenharmony_ci			}, {
4748c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
4758c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
4768c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
4778c2ecf20Sopenharmony_ci			}, {
4788c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
4798c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
4808c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
4818c2ecf20Sopenharmony_ci			},
4828c2ecf20Sopenharmony_ci		},
4838c2ecf20Sopenharmony_ci		.rinput = {
4848c2ecf20Sopenharmony_ci			.type = TM6000_INPUT_RADIO,
4858c2ecf20Sopenharmony_ci			.amux = TM6000_AMUX_SIF1,
4868c2ecf20Sopenharmony_ci		},
4878c2ecf20Sopenharmony_ci	},
4888c2ecf20Sopenharmony_ci	[TM5600_BOARD_TERRATEC_GRABSTER] = {
4898c2ecf20Sopenharmony_ci		.name         = "Terratec Grabster AV 150/250 MX",
4908c2ecf20Sopenharmony_ci		.type         = TM5600,
4918c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_ABSENT,
4928c2ecf20Sopenharmony_ci		.vinput = { {
4938c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
4948c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
4958c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
4968c2ecf20Sopenharmony_ci			}, {
4978c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
4988c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
4998c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
5008c2ecf20Sopenharmony_ci			}, {
5018c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
5028c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
5038c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
5048c2ecf20Sopenharmony_ci			},
5058c2ecf20Sopenharmony_ci		},
5068c2ecf20Sopenharmony_ci	},
5078c2ecf20Sopenharmony_ci	[TM6010_BOARD_TWINHAN_TU501] = {
5088c2ecf20Sopenharmony_ci		.name         = "Twinhan TU501(704D1)",
5098c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC2028, /* has a XC3028 */
5108c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
5118c2ecf20Sopenharmony_ci		.demod_addr   = 0x1e >> 1,
5128c2ecf20Sopenharmony_ci		.type         = TM6010,
5138c2ecf20Sopenharmony_ci		.caps = {
5148c2ecf20Sopenharmony_ci			.has_tuner    = 1,
5158c2ecf20Sopenharmony_ci			.has_dvb      = 1,
5168c2ecf20Sopenharmony_ci			.has_zl10353  = 1,
5178c2ecf20Sopenharmony_ci			.has_eeprom   = 1,
5188c2ecf20Sopenharmony_ci			.has_remote   = 1,
5198c2ecf20Sopenharmony_ci		},
5208c2ecf20Sopenharmony_ci		.gpio = {
5218c2ecf20Sopenharmony_ci			.tuner_reset	= TM6010_GPIO_2,
5228c2ecf20Sopenharmony_ci			.tuner_on	= TM6010_GPIO_3,
5238c2ecf20Sopenharmony_ci			.demod_reset	= TM6010_GPIO_1,
5248c2ecf20Sopenharmony_ci			.demod_on	= TM6010_GPIO_4,
5258c2ecf20Sopenharmony_ci			.power_led	= TM6010_GPIO_7,
5268c2ecf20Sopenharmony_ci			.dvb_led	= TM6010_GPIO_5,
5278c2ecf20Sopenharmony_ci			.ir		= TM6010_GPIO_0,
5288c2ecf20Sopenharmony_ci		},
5298c2ecf20Sopenharmony_ci		.vinput = { {
5308c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
5318c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
5328c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_SIF1,
5338c2ecf20Sopenharmony_ci			}, {
5348c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_COMPOSITE1,
5358c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_A,
5368c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
5378c2ecf20Sopenharmony_ci			}, {
5388c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_SVIDEO,
5398c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_AB,
5408c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC2,
5418c2ecf20Sopenharmony_ci			},
5428c2ecf20Sopenharmony_ci		},
5438c2ecf20Sopenharmony_ci	},
5448c2ecf20Sopenharmony_ci	[TM6010_BOARD_BEHOLD_WANDER_LITE] = {
5458c2ecf20Sopenharmony_ci		.name         = "Beholder Wander Lite DVB-T/TV/FM USB2.0",
5468c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC5000,
5478c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
5488c2ecf20Sopenharmony_ci		.demod_addr   = 0x1e >> 1,
5498c2ecf20Sopenharmony_ci		.type         = TM6010,
5508c2ecf20Sopenharmony_ci		.caps = {
5518c2ecf20Sopenharmony_ci			.has_tuner      = 1,
5528c2ecf20Sopenharmony_ci			.has_dvb        = 1,
5538c2ecf20Sopenharmony_ci			.has_zl10353    = 1,
5548c2ecf20Sopenharmony_ci			.has_eeprom     = 1,
5558c2ecf20Sopenharmony_ci			.has_remote     = 0,
5568c2ecf20Sopenharmony_ci			.has_radio	= 1,
5578c2ecf20Sopenharmony_ci		},
5588c2ecf20Sopenharmony_ci		.gpio = {
5598c2ecf20Sopenharmony_ci			.tuner_reset	= TM6010_GPIO_0,
5608c2ecf20Sopenharmony_ci			.demod_reset	= TM6010_GPIO_1,
5618c2ecf20Sopenharmony_ci			.power_led	= TM6010_GPIO_6,
5628c2ecf20Sopenharmony_ci		},
5638c2ecf20Sopenharmony_ci		.vinput = { {
5648c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
5658c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
5668c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_SIF1,
5678c2ecf20Sopenharmony_ci			},
5688c2ecf20Sopenharmony_ci		},
5698c2ecf20Sopenharmony_ci		.rinput = {
5708c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_RADIO,
5718c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
5728c2ecf20Sopenharmony_ci		},
5738c2ecf20Sopenharmony_ci	},
5748c2ecf20Sopenharmony_ci	[TM6010_BOARD_BEHOLD_VOYAGER_LITE] = {
5758c2ecf20Sopenharmony_ci		.name         = "Beholder Voyager Lite TV/FM USB2.0",
5768c2ecf20Sopenharmony_ci		.tuner_type   = TUNER_XC5000,
5778c2ecf20Sopenharmony_ci		.tuner_addr   = 0xc2 >> 1,
5788c2ecf20Sopenharmony_ci		.type         = TM6010,
5798c2ecf20Sopenharmony_ci		.caps = {
5808c2ecf20Sopenharmony_ci			.has_tuner      = 1,
5818c2ecf20Sopenharmony_ci			.has_dvb        = 0,
5828c2ecf20Sopenharmony_ci			.has_zl10353    = 0,
5838c2ecf20Sopenharmony_ci			.has_eeprom     = 1,
5848c2ecf20Sopenharmony_ci			.has_remote     = 0,
5858c2ecf20Sopenharmony_ci			.has_radio	= 1,
5868c2ecf20Sopenharmony_ci		},
5878c2ecf20Sopenharmony_ci		.gpio = {
5888c2ecf20Sopenharmony_ci			.tuner_reset	= TM6010_GPIO_0,
5898c2ecf20Sopenharmony_ci			.power_led	= TM6010_GPIO_6,
5908c2ecf20Sopenharmony_ci		},
5918c2ecf20Sopenharmony_ci		.vinput = { {
5928c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_TV,
5938c2ecf20Sopenharmony_ci			.vmux	= TM6000_VMUX_VIDEO_B,
5948c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_SIF1,
5958c2ecf20Sopenharmony_ci			},
5968c2ecf20Sopenharmony_ci		},
5978c2ecf20Sopenharmony_ci		.rinput = {
5988c2ecf20Sopenharmony_ci			.type	= TM6000_INPUT_RADIO,
5998c2ecf20Sopenharmony_ci			.amux	= TM6000_AMUX_ADC1,
6008c2ecf20Sopenharmony_ci		},
6018c2ecf20Sopenharmony_ci	},
6028c2ecf20Sopenharmony_ci};
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci/* table of devices that work with this driver */
6058c2ecf20Sopenharmony_cistatic const struct usb_device_id tm6000_id_table[] = {
6068c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x6000, 0x0001), .driver_info = TM5600_BOARD_GENERIC },
6078c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x6000, 0x0002), .driver_info = TM6010_BOARD_GENERIC },
6088c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x06e1, 0xf332), .driver_info = TM6000_BOARD_ADSTECH_DUAL_TV },
6098c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x14aa, 0x0620), .driver_info = TM6000_BOARD_FREECOM_AND_SIMILAR },
6108c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x06e1, 0xb339), .driver_info = TM6000_BOARD_ADSTECH_MINI_DUAL_TV },
6118c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x2040, 0x6600), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
6128c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x2040, 0x6601), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
6138c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x2040, 0x6610), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
6148c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x2040, 0x6611), .driver_info = TM6010_BOARD_HAUPPAUGE_900H },
6158c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x6000, 0xdec0), .driver_info = TM6010_BOARD_BEHOLD_WANDER },
6168c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x6000, 0xdec1), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER },
6178c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x0ccd, 0x0086), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
6188c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x0ccd, 0x00A5), .driver_info = TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE },
6198c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x0ccd, 0x0079), .driver_info = TM5600_BOARD_TERRATEC_GRABSTER },
6208c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x13d3, 0x3240), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
6218c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x13d3, 0x3241), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
6228c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x13d3, 0x3243), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
6238c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x13d3, 0x3264), .driver_info = TM6010_BOARD_TWINHAN_TU501 },
6248c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x6000, 0xdec2), .driver_info = TM6010_BOARD_BEHOLD_WANDER_LITE },
6258c2ecf20Sopenharmony_ci	{ USB_DEVICE(0x6000, 0xdec3), .driver_info = TM6010_BOARD_BEHOLD_VOYAGER_LITE },
6268c2ecf20Sopenharmony_ci	{ }
6278c2ecf20Sopenharmony_ci};
6288c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, tm6000_id_table);
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_ci/* Control power led for show some activity */
6318c2ecf20Sopenharmony_civoid tm6000_flash_led(struct tm6000_core *dev, u8 state)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	/* Power LED unconfigured */
6348c2ecf20Sopenharmony_ci	if (!dev->gpio.power_led)
6358c2ecf20Sopenharmony_ci		return;
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci	/* ON Power LED */
6388c2ecf20Sopenharmony_ci	if (state) {
6398c2ecf20Sopenharmony_ci		switch (dev->model) {
6408c2ecf20Sopenharmony_ci		case TM6010_BOARD_HAUPPAUGE_900H:
6418c2ecf20Sopenharmony_ci		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
6428c2ecf20Sopenharmony_ci		case TM6010_BOARD_TWINHAN_TU501:
6438c2ecf20Sopenharmony_ci			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
6448c2ecf20Sopenharmony_ci				dev->gpio.power_led, 0x00);
6458c2ecf20Sopenharmony_ci			break;
6468c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_WANDER:
6478c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_VOYAGER:
6488c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_WANDER_LITE:
6498c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
6508c2ecf20Sopenharmony_ci			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
6518c2ecf20Sopenharmony_ci				dev->gpio.power_led, 0x01);
6528c2ecf20Sopenharmony_ci			break;
6538c2ecf20Sopenharmony_ci		}
6548c2ecf20Sopenharmony_ci	}
6558c2ecf20Sopenharmony_ci	/* OFF Power LED */
6568c2ecf20Sopenharmony_ci	else {
6578c2ecf20Sopenharmony_ci		switch (dev->model) {
6588c2ecf20Sopenharmony_ci		case TM6010_BOARD_HAUPPAUGE_900H:
6598c2ecf20Sopenharmony_ci		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
6608c2ecf20Sopenharmony_ci		case TM6010_BOARD_TWINHAN_TU501:
6618c2ecf20Sopenharmony_ci			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
6628c2ecf20Sopenharmony_ci				dev->gpio.power_led, 0x01);
6638c2ecf20Sopenharmony_ci			break;
6648c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_WANDER:
6658c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_VOYAGER:
6668c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_WANDER_LITE:
6678c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
6688c2ecf20Sopenharmony_ci			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
6698c2ecf20Sopenharmony_ci				dev->gpio.power_led, 0x00);
6708c2ecf20Sopenharmony_ci			break;
6718c2ecf20Sopenharmony_ci		}
6728c2ecf20Sopenharmony_ci	}
6738c2ecf20Sopenharmony_ci}
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci/* Tuner callback to provide the proper gpio changes needed for xc5000 */
6768c2ecf20Sopenharmony_ciint tm6000_xc5000_callback(void *ptr, int component, int command, int arg)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	int rc = 0;
6798c2ecf20Sopenharmony_ci	struct tm6000_core *dev = ptr;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	if (dev->tuner_type != TUNER_XC5000)
6828c2ecf20Sopenharmony_ci		return 0;
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	switch (command) {
6858c2ecf20Sopenharmony_ci	case XC5000_TUNER_RESET:
6868c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
6878c2ecf20Sopenharmony_ci			       dev->gpio.tuner_reset, 0x01);
6888c2ecf20Sopenharmony_ci		msleep(15);
6898c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
6908c2ecf20Sopenharmony_ci			       dev->gpio.tuner_reset, 0x00);
6918c2ecf20Sopenharmony_ci		msleep(15);
6928c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
6938c2ecf20Sopenharmony_ci			       dev->gpio.tuner_reset, 0x01);
6948c2ecf20Sopenharmony_ci		break;
6958c2ecf20Sopenharmony_ci	}
6968c2ecf20Sopenharmony_ci	return rc;
6978c2ecf20Sopenharmony_ci}
6988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tm6000_xc5000_callback);
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci/* Tuner callback to provide the proper gpio changes needed for xc2028 */
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ciint tm6000_tuner_callback(void *ptr, int component, int command, int arg)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	int rc = 0;
7058c2ecf20Sopenharmony_ci	struct tm6000_core *dev = ptr;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	if (dev->tuner_type != TUNER_XC2028)
7088c2ecf20Sopenharmony_ci		return 0;
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	switch (command) {
7118c2ecf20Sopenharmony_ci	case XC2028_RESET_CLK:
7128c2ecf20Sopenharmony_ci		tm6000_ir_wait(dev, 0);
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
7158c2ecf20Sopenharmony_ci					0x02, arg);
7168c2ecf20Sopenharmony_ci		msleep(10);
7178c2ecf20Sopenharmony_ci		rc = tm6000_i2c_reset(dev, 10);
7188c2ecf20Sopenharmony_ci		break;
7198c2ecf20Sopenharmony_ci	case XC2028_TUNER_RESET:
7208c2ecf20Sopenharmony_ci		/* Reset codes during load firmware */
7218c2ecf20Sopenharmony_ci		switch (arg) {
7228c2ecf20Sopenharmony_ci		case 0:
7238c2ecf20Sopenharmony_ci			/* newer tuner can faster reset */
7248c2ecf20Sopenharmony_ci			switch (dev->model) {
7258c2ecf20Sopenharmony_ci			case TM5600_BOARD_10MOONS_UT821:
7268c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7278c2ecf20Sopenharmony_ci					       dev->gpio.tuner_reset, 0x01);
7288c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7298c2ecf20Sopenharmony_ci					       0x300, 0x01);
7308c2ecf20Sopenharmony_ci				msleep(10);
7318c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7328c2ecf20Sopenharmony_ci					       dev->gpio.tuner_reset, 0x00);
7338c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7348c2ecf20Sopenharmony_ci					       0x300, 0x00);
7358c2ecf20Sopenharmony_ci				msleep(10);
7368c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7378c2ecf20Sopenharmony_ci					       dev->gpio.tuner_reset, 0x01);
7388c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7398c2ecf20Sopenharmony_ci					       0x300, 0x01);
7408c2ecf20Sopenharmony_ci				break;
7418c2ecf20Sopenharmony_ci			case TM6010_BOARD_HAUPPAUGE_900H:
7428c2ecf20Sopenharmony_ci			case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
7438c2ecf20Sopenharmony_ci			case TM6010_BOARD_TWINHAN_TU501:
7448c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7458c2ecf20Sopenharmony_ci					       dev->gpio.tuner_reset, 0x01);
7468c2ecf20Sopenharmony_ci				msleep(60);
7478c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7488c2ecf20Sopenharmony_ci					       dev->gpio.tuner_reset, 0x00);
7498c2ecf20Sopenharmony_ci				msleep(75);
7508c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7518c2ecf20Sopenharmony_ci					       dev->gpio.tuner_reset, 0x01);
7528c2ecf20Sopenharmony_ci				msleep(60);
7538c2ecf20Sopenharmony_ci				break;
7548c2ecf20Sopenharmony_ci			default:
7558c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7568c2ecf20Sopenharmony_ci					       dev->gpio.tuner_reset, 0x00);
7578c2ecf20Sopenharmony_ci				msleep(130);
7588c2ecf20Sopenharmony_ci				tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
7598c2ecf20Sopenharmony_ci					       dev->gpio.tuner_reset, 0x01);
7608c2ecf20Sopenharmony_ci				msleep(130);
7618c2ecf20Sopenharmony_ci				break;
7628c2ecf20Sopenharmony_ci			}
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci			tm6000_ir_wait(dev, 1);
7658c2ecf20Sopenharmony_ci			break;
7668c2ecf20Sopenharmony_ci		case 1:
7678c2ecf20Sopenharmony_ci			tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT,
7688c2ecf20Sopenharmony_ci						0x02, 0x01);
7698c2ecf20Sopenharmony_ci			msleep(10);
7708c2ecf20Sopenharmony_ci			break;
7718c2ecf20Sopenharmony_ci		case 2:
7728c2ecf20Sopenharmony_ci			rc = tm6000_i2c_reset(dev, 100);
7738c2ecf20Sopenharmony_ci			break;
7748c2ecf20Sopenharmony_ci		}
7758c2ecf20Sopenharmony_ci		break;
7768c2ecf20Sopenharmony_ci	case XC2028_I2C_FLUSH:
7778c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_50_SET_START, 0, 0);
7788c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_51_SET_STOP, 0, 0);
7798c2ecf20Sopenharmony_ci		break;
7808c2ecf20Sopenharmony_ci	}
7818c2ecf20Sopenharmony_ci	return rc;
7828c2ecf20Sopenharmony_ci}
7838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(tm6000_tuner_callback);
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ciint tm6000_cards_setup(struct tm6000_core *dev)
7868c2ecf20Sopenharmony_ci{
7878c2ecf20Sopenharmony_ci	/*
7888c2ecf20Sopenharmony_ci	 * Board-specific initialization sequence. Handles all GPIO
7898c2ecf20Sopenharmony_ci	 * initialization sequences that are board-specific.
7908c2ecf20Sopenharmony_ci	 * Up to now, all found devices use GPIO1 and GPIO4 at the same way.
7918c2ecf20Sopenharmony_ci	 * Probably, they're all based on some reference device. Due to that,
7928c2ecf20Sopenharmony_ci	 * there's a common routine at the end to handle those GPIO's. Devices
7938c2ecf20Sopenharmony_ci	 * that use different pinups or init sequences can just return at
7948c2ecf20Sopenharmony_ci	 * the board-specific session.
7958c2ecf20Sopenharmony_ci	 */
7968c2ecf20Sopenharmony_ci	switch (dev->model) {
7978c2ecf20Sopenharmony_ci	case TM6010_BOARD_HAUPPAUGE_900H:
7988c2ecf20Sopenharmony_ci	case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
7998c2ecf20Sopenharmony_ci	case TM6010_BOARD_TWINHAN_TU501:
8008c2ecf20Sopenharmony_ci	case TM6010_BOARD_GENERIC:
8018c2ecf20Sopenharmony_ci		/* Turn xceive 3028 on */
8028c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.tuner_on, 0x01);
8038c2ecf20Sopenharmony_ci		msleep(15);
8048c2ecf20Sopenharmony_ci		/* Turn zarlink zl10353 on */
8058c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
8068c2ecf20Sopenharmony_ci		msleep(15);
8078c2ecf20Sopenharmony_ci		/* Reset zarlink zl10353 */
8088c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
8098c2ecf20Sopenharmony_ci		msleep(50);
8108c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
8118c2ecf20Sopenharmony_ci		msleep(15);
8128c2ecf20Sopenharmony_ci		/* Turn zarlink zl10353 off */
8138c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x01);
8148c2ecf20Sopenharmony_ci		msleep(15);
8158c2ecf20Sopenharmony_ci		/* ir ? */
8168c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.ir, 0x01);
8178c2ecf20Sopenharmony_ci		msleep(15);
8188c2ecf20Sopenharmony_ci		/* Power led on (blue) */
8198c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x00);
8208c2ecf20Sopenharmony_ci		msleep(15);
8218c2ecf20Sopenharmony_ci		/* DVB led off (orange) */
8228c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.dvb_led, 0x01);
8238c2ecf20Sopenharmony_ci		msleep(15);
8248c2ecf20Sopenharmony_ci		/* Turn zarlink zl10353 on */
8258c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_on, 0x00);
8268c2ecf20Sopenharmony_ci		msleep(15);
8278c2ecf20Sopenharmony_ci		break;
8288c2ecf20Sopenharmony_ci	case TM6010_BOARD_BEHOLD_WANDER:
8298c2ecf20Sopenharmony_ci	case TM6010_BOARD_BEHOLD_WANDER_LITE:
8308c2ecf20Sopenharmony_ci		/* Power led on (blue) */
8318c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
8328c2ecf20Sopenharmony_ci		msleep(15);
8338c2ecf20Sopenharmony_ci		/* Reset zarlink zl10353 */
8348c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x00);
8358c2ecf20Sopenharmony_ci		msleep(50);
8368c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.demod_reset, 0x01);
8378c2ecf20Sopenharmony_ci		msleep(15);
8388c2ecf20Sopenharmony_ci		break;
8398c2ecf20Sopenharmony_ci	case TM6010_BOARD_BEHOLD_VOYAGER:
8408c2ecf20Sopenharmony_ci	case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
8418c2ecf20Sopenharmony_ci		/* Power led on (blue) */
8428c2ecf20Sopenharmony_ci		tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, dev->gpio.power_led, 0x01);
8438c2ecf20Sopenharmony_ci		msleep(15);
8448c2ecf20Sopenharmony_ci		break;
8458c2ecf20Sopenharmony_ci	default:
8468c2ecf20Sopenharmony_ci		break;
8478c2ecf20Sopenharmony_ci	}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	/*
8508c2ecf20Sopenharmony_ci	 * Default initialization. Most of the devices seem to use GPIO1
8518c2ecf20Sopenharmony_ci	 * and GPIO4.on the same way, so, this handles the common sequence
8528c2ecf20Sopenharmony_ci	 * used by most devices.
8538c2ecf20Sopenharmony_ci	 * If a device uses a different sequence or different GPIO pins for
8548c2ecf20Sopenharmony_ci	 * reset, just add the code at the board-specific part
8558c2ecf20Sopenharmony_ci	 */
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	if (dev->gpio.tuner_reset) {
8588c2ecf20Sopenharmony_ci		int rc;
8598c2ecf20Sopenharmony_ci		int i;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci		for (i = 0; i < 2; i++) {
8628c2ecf20Sopenharmony_ci			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
8638c2ecf20Sopenharmony_ci						dev->gpio.tuner_reset, 0x00);
8648c2ecf20Sopenharmony_ci			if (rc < 0) {
8658c2ecf20Sopenharmony_ci				printk(KERN_ERR "Error %i doing tuner reset\n", rc);
8668c2ecf20Sopenharmony_ci				return rc;
8678c2ecf20Sopenharmony_ci			}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci			msleep(10); /* Just to be conservative */
8708c2ecf20Sopenharmony_ci			rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
8718c2ecf20Sopenharmony_ci						dev->gpio.tuner_reset, 0x01);
8728c2ecf20Sopenharmony_ci			if (rc < 0) {
8738c2ecf20Sopenharmony_ci				printk(KERN_ERR "Error %i doing tuner reset\n", rc);
8748c2ecf20Sopenharmony_ci				return rc;
8758c2ecf20Sopenharmony_ci			}
8768c2ecf20Sopenharmony_ci		}
8778c2ecf20Sopenharmony_ci	} else {
8788c2ecf20Sopenharmony_ci		printk(KERN_ERR "Tuner reset is not configured\n");
8798c2ecf20Sopenharmony_ci		return -1;
8808c2ecf20Sopenharmony_ci	}
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	msleep(50);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	return 0;
8858c2ecf20Sopenharmony_ci};
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_cistatic void tm6000_config_tuner(struct tm6000_core *dev)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	struct tuner_setup tun_setup;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	/* Load tuner module */
8928c2ecf20Sopenharmony_ci	v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
8938c2ecf20Sopenharmony_ci		"tuner", dev->tuner_addr, NULL);
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	memset(&tun_setup, 0, sizeof(tun_setup));
8968c2ecf20Sopenharmony_ci	tun_setup.type = dev->tuner_type;
8978c2ecf20Sopenharmony_ci	tun_setup.addr = dev->tuner_addr;
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	tun_setup.mode_mask = 0;
9008c2ecf20Sopenharmony_ci	if (dev->caps.has_tuner)
9018c2ecf20Sopenharmony_ci		tun_setup.mode_mask |= (T_ANALOG_TV | T_RADIO);
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	switch (dev->tuner_type) {
9048c2ecf20Sopenharmony_ci	case TUNER_XC2028:
9058c2ecf20Sopenharmony_ci		tun_setup.tuner_callback = tm6000_tuner_callback;
9068c2ecf20Sopenharmony_ci		break;
9078c2ecf20Sopenharmony_ci	case TUNER_XC5000:
9088c2ecf20Sopenharmony_ci		tun_setup.tuner_callback = tm6000_xc5000_callback;
9098c2ecf20Sopenharmony_ci		break;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	switch (dev->tuner_type) {
9158c2ecf20Sopenharmony_ci	case TUNER_XC2028: {
9168c2ecf20Sopenharmony_ci		struct v4l2_priv_tun_config xc2028_cfg;
9178c2ecf20Sopenharmony_ci		struct xc2028_ctrl ctl;
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci		memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
9208c2ecf20Sopenharmony_ci		memset(&ctl, 0, sizeof(ctl));
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci		ctl.demod = XC3028_FE_ZARLINK456;
9238c2ecf20Sopenharmony_ci
9248c2ecf20Sopenharmony_ci		xc2028_cfg.tuner = TUNER_XC2028;
9258c2ecf20Sopenharmony_ci		xc2028_cfg.priv  = &ctl;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci		switch (dev->model) {
9288c2ecf20Sopenharmony_ci		case TM6010_BOARD_HAUPPAUGE_900H:
9298c2ecf20Sopenharmony_ci		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
9308c2ecf20Sopenharmony_ci		case TM6010_BOARD_TWINHAN_TU501:
9318c2ecf20Sopenharmony_ci			ctl.max_len = 80;
9328c2ecf20Sopenharmony_ci			ctl.fname = "xc3028L-v36.fw";
9338c2ecf20Sopenharmony_ci			break;
9348c2ecf20Sopenharmony_ci		default:
9358c2ecf20Sopenharmony_ci			if (dev->dev_type == TM6010)
9368c2ecf20Sopenharmony_ci				ctl.fname = "xc3028-v27.fw";
9378c2ecf20Sopenharmony_ci			else
9388c2ecf20Sopenharmony_ci				ctl.fname = "xc3028-v24.fw";
9398c2ecf20Sopenharmony_ci		}
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci		printk(KERN_INFO "Setting firmware parameters for xc2028\n");
9428c2ecf20Sopenharmony_ci		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
9438c2ecf20Sopenharmony_ci				     &xc2028_cfg);
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci		}
9468c2ecf20Sopenharmony_ci		break;
9478c2ecf20Sopenharmony_ci	case TUNER_XC5000:
9488c2ecf20Sopenharmony_ci		{
9498c2ecf20Sopenharmony_ci		struct v4l2_priv_tun_config  xc5000_cfg;
9508c2ecf20Sopenharmony_ci		struct xc5000_config ctl = {
9518c2ecf20Sopenharmony_ci			.i2c_address = dev->tuner_addr,
9528c2ecf20Sopenharmony_ci			.if_khz      = 4570,
9538c2ecf20Sopenharmony_ci			.radio_input = XC5000_RADIO_FM1_MONO,
9548c2ecf20Sopenharmony_ci			};
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci		xc5000_cfg.tuner = TUNER_XC5000;
9578c2ecf20Sopenharmony_ci		xc5000_cfg.priv  = &ctl;
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config,
9608c2ecf20Sopenharmony_ci				     &xc5000_cfg);
9618c2ecf20Sopenharmony_ci		}
9628c2ecf20Sopenharmony_ci		break;
9638c2ecf20Sopenharmony_ci	default:
9648c2ecf20Sopenharmony_ci		printk(KERN_INFO "Unknown tuner type. Tuner is not configured.\n");
9658c2ecf20Sopenharmony_ci		break;
9668c2ecf20Sopenharmony_ci	}
9678c2ecf20Sopenharmony_ci}
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_cistatic int fill_board_specific_data(struct tm6000_core *dev)
9708c2ecf20Sopenharmony_ci{
9718c2ecf20Sopenharmony_ci	int rc;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	dev->dev_type   = tm6000_boards[dev->model].type;
9748c2ecf20Sopenharmony_ci	dev->tuner_type = tm6000_boards[dev->model].tuner_type;
9758c2ecf20Sopenharmony_ci	dev->tuner_addr = tm6000_boards[dev->model].tuner_addr;
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_ci	dev->gpio = tm6000_boards[dev->model].gpio;
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	dev->ir_codes = tm6000_boards[dev->model].ir_codes;
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	dev->demod_addr = tm6000_boards[dev->model].demod_addr;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	dev->caps = tm6000_boards[dev->model].caps;
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	dev->vinput[0] = tm6000_boards[dev->model].vinput[0];
9868c2ecf20Sopenharmony_ci	dev->vinput[1] = tm6000_boards[dev->model].vinput[1];
9878c2ecf20Sopenharmony_ci	dev->vinput[2] = tm6000_boards[dev->model].vinput[2];
9888c2ecf20Sopenharmony_ci	dev->rinput = tm6000_boards[dev->model].rinput;
9898c2ecf20Sopenharmony_ci
9908c2ecf20Sopenharmony_ci	/* setup per-model quirks */
9918c2ecf20Sopenharmony_ci	switch (dev->model) {
9928c2ecf20Sopenharmony_ci	case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
9938c2ecf20Sopenharmony_ci	case TM6010_BOARD_HAUPPAUGE_900H:
9948c2ecf20Sopenharmony_ci		dev->quirks |= TM6000_QUIRK_NO_USB_DELAY;
9958c2ecf20Sopenharmony_ci		break;
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci	default:
9988c2ecf20Sopenharmony_ci		break;
9998c2ecf20Sopenharmony_ci	}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	/* initialize hardware */
10028c2ecf20Sopenharmony_ci	rc = tm6000_init(dev);
10038c2ecf20Sopenharmony_ci	if (rc < 0)
10048c2ecf20Sopenharmony_ci		return rc;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	return v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
10078c2ecf20Sopenharmony_ci}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_cistatic void use_alternative_detection_method(struct tm6000_core *dev)
10118c2ecf20Sopenharmony_ci{
10128c2ecf20Sopenharmony_ci	int i, model = -1;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	if (!dev->eedata_size)
10158c2ecf20Sopenharmony_ci		return;
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(tm6000_boards); i++) {
10188c2ecf20Sopenharmony_ci		if (!tm6000_boards[i].eename_size)
10198c2ecf20Sopenharmony_ci			continue;
10208c2ecf20Sopenharmony_ci		if (dev->eedata_size < tm6000_boards[i].eename_pos +
10218c2ecf20Sopenharmony_ci				       tm6000_boards[i].eename_size)
10228c2ecf20Sopenharmony_ci			continue;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci		if (!memcmp(&dev->eedata[tm6000_boards[i].eename_pos],
10258c2ecf20Sopenharmony_ci			    tm6000_boards[i].eename,
10268c2ecf20Sopenharmony_ci			    tm6000_boards[i].eename_size)) {
10278c2ecf20Sopenharmony_ci			model = i;
10288c2ecf20Sopenharmony_ci			break;
10298c2ecf20Sopenharmony_ci		}
10308c2ecf20Sopenharmony_ci	}
10318c2ecf20Sopenharmony_ci	if (model < 0) {
10328c2ecf20Sopenharmony_ci		printk(KERN_INFO "Device has eeprom but is currently unknown\n");
10338c2ecf20Sopenharmony_ci		return;
10348c2ecf20Sopenharmony_ci	}
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	dev->model = model;
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	printk(KERN_INFO "Device identified via eeprom as %s (type = %d)\n",
10398c2ecf20Sopenharmony_ci	       tm6000_boards[model].name, model);
10408c2ecf20Sopenharmony_ci}
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci#if defined(CONFIG_MODULES) && defined(MODULE)
10438c2ecf20Sopenharmony_cistatic void request_module_async(struct work_struct *work)
10448c2ecf20Sopenharmony_ci{
10458c2ecf20Sopenharmony_ci	struct tm6000_core *dev = container_of(work, struct tm6000_core,
10468c2ecf20Sopenharmony_ci					       request_module_wk);
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	request_module("tm6000-alsa");
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	if (dev->caps.has_dvb)
10518c2ecf20Sopenharmony_ci		request_module("tm6000-dvb");
10528c2ecf20Sopenharmony_ci}
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_cistatic void request_modules(struct tm6000_core *dev)
10558c2ecf20Sopenharmony_ci{
10568c2ecf20Sopenharmony_ci	INIT_WORK(&dev->request_module_wk, request_module_async);
10578c2ecf20Sopenharmony_ci	schedule_work(&dev->request_module_wk);
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistatic void flush_request_modules(struct tm6000_core *dev)
10618c2ecf20Sopenharmony_ci{
10628c2ecf20Sopenharmony_ci	flush_work(&dev->request_module_wk);
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci#else
10658c2ecf20Sopenharmony_ci#define request_modules(dev)
10668c2ecf20Sopenharmony_ci#define flush_request_modules(dev)
10678c2ecf20Sopenharmony_ci#endif /* CONFIG_MODULES */
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_cistatic int tm6000_init_dev(struct tm6000_core *dev)
10708c2ecf20Sopenharmony_ci{
10718c2ecf20Sopenharmony_ci	struct v4l2_frequency f;
10728c2ecf20Sopenharmony_ci	int rc = 0;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	mutex_init(&dev->lock);
10758c2ecf20Sopenharmony_ci	mutex_lock(&dev->lock);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	if (!is_generic(dev->model)) {
10788c2ecf20Sopenharmony_ci		rc = fill_board_specific_data(dev);
10798c2ecf20Sopenharmony_ci		if (rc < 0)
10808c2ecf20Sopenharmony_ci			goto err;
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci		/* register i2c bus */
10838c2ecf20Sopenharmony_ci		rc = tm6000_i2c_register(dev);
10848c2ecf20Sopenharmony_ci		if (rc < 0)
10858c2ecf20Sopenharmony_ci			goto err;
10868c2ecf20Sopenharmony_ci	} else {
10878c2ecf20Sopenharmony_ci		/* register i2c bus */
10888c2ecf20Sopenharmony_ci		rc = tm6000_i2c_register(dev);
10898c2ecf20Sopenharmony_ci		if (rc < 0)
10908c2ecf20Sopenharmony_ci			goto err;
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci		use_alternative_detection_method(dev);
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci		rc = fill_board_specific_data(dev);
10958c2ecf20Sopenharmony_ci		if (rc < 0)
10968c2ecf20Sopenharmony_ci			goto err;
10978c2ecf20Sopenharmony_ci	}
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	/* Default values for STD and resolutions */
11008c2ecf20Sopenharmony_ci	dev->width = 720;
11018c2ecf20Sopenharmony_ci	dev->height = 480;
11028c2ecf20Sopenharmony_ci	dev->norm = V4L2_STD_NTSC_M;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	/* Configure tuner */
11058c2ecf20Sopenharmony_ci	tm6000_config_tuner(dev);
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	/* Set video standard */
11088c2ecf20Sopenharmony_ci	v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	/* Set tuner frequency - also loads firmware on xc2028/xc3028 */
11118c2ecf20Sopenharmony_ci	f.tuner = 0;
11128c2ecf20Sopenharmony_ci	f.type = V4L2_TUNER_ANALOG_TV;
11138c2ecf20Sopenharmony_ci	f.frequency = 3092;	/* 193.25 MHz */
11148c2ecf20Sopenharmony_ci	dev->freq = f.frequency;
11158c2ecf20Sopenharmony_ci	v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	if (dev->caps.has_tda9874)
11188c2ecf20Sopenharmony_ci		v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
11198c2ecf20Sopenharmony_ci			"tvaudio", I2C_ADDR_TDA9874, NULL);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	/* register and initialize V4L2 */
11228c2ecf20Sopenharmony_ci	rc = tm6000_v4l2_register(dev);
11238c2ecf20Sopenharmony_ci	if (rc < 0)
11248c2ecf20Sopenharmony_ci		goto err;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	tm6000_add_into_devlist(dev);
11278c2ecf20Sopenharmony_ci	tm6000_init_extension(dev);
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	tm6000_ir_init(dev);
11308c2ecf20Sopenharmony_ci
11318c2ecf20Sopenharmony_ci	request_modules(dev);
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	mutex_unlock(&dev->lock);
11348c2ecf20Sopenharmony_ci	return 0;
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_cierr:
11378c2ecf20Sopenharmony_ci	mutex_unlock(&dev->lock);
11388c2ecf20Sopenharmony_ci	return rc;
11398c2ecf20Sopenharmony_ci}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
11428c2ecf20Sopenharmony_ci#define hb_mult(wMaxPacketSize) (1 + (((wMaxPacketSize) >> 11) & 0x03))
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_cistatic void get_max_endpoint(struct usb_device *udev,
11458c2ecf20Sopenharmony_ci			     struct usb_host_interface *alt,
11468c2ecf20Sopenharmony_ci			     char *msgtype,
11478c2ecf20Sopenharmony_ci			     struct usb_host_endpoint *curr_e,
11488c2ecf20Sopenharmony_ci			     struct tm6000_endpoint *tm_ep)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	u16 tmp = le16_to_cpu(curr_e->desc.wMaxPacketSize);
11518c2ecf20Sopenharmony_ci	unsigned int size = tmp & 0x7ff;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	if (udev->speed == USB_SPEED_HIGH)
11548c2ecf20Sopenharmony_ci		size = size * hb_mult(tmp);
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	if (size > tm_ep->maxsize) {
11578c2ecf20Sopenharmony_ci		tm_ep->endp = curr_e;
11588c2ecf20Sopenharmony_ci		tm_ep->maxsize = size;
11598c2ecf20Sopenharmony_ci		tm_ep->bInterfaceNumber = alt->desc.bInterfaceNumber;
11608c2ecf20Sopenharmony_ci		tm_ep->bAlternateSetting = alt->desc.bAlternateSetting;
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci		printk(KERN_INFO "tm6000: %s endpoint: 0x%02x (max size=%u bytes)\n",
11638c2ecf20Sopenharmony_ci					msgtype, curr_e->desc.bEndpointAddress,
11648c2ecf20Sopenharmony_ci					size);
11658c2ecf20Sopenharmony_ci	}
11668c2ecf20Sopenharmony_ci}
11678c2ecf20Sopenharmony_ci
11688c2ecf20Sopenharmony_ci/*
11698c2ecf20Sopenharmony_ci * tm6000_usb_probe()
11708c2ecf20Sopenharmony_ci * checks for supported devices
11718c2ecf20Sopenharmony_ci */
11728c2ecf20Sopenharmony_cistatic int tm6000_usb_probe(struct usb_interface *interface,
11738c2ecf20Sopenharmony_ci			    const struct usb_device_id *id)
11748c2ecf20Sopenharmony_ci{
11758c2ecf20Sopenharmony_ci	struct usb_device *usbdev;
11768c2ecf20Sopenharmony_ci	struct tm6000_core *dev;
11778c2ecf20Sopenharmony_ci	int i, rc;
11788c2ecf20Sopenharmony_ci	int nr = 0;
11798c2ecf20Sopenharmony_ci	char *speed;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	usbdev = usb_get_dev(interface_to_usbdev(interface));
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	/* Selects the proper interface */
11848c2ecf20Sopenharmony_ci	rc = usb_set_interface(usbdev, 0, 1);
11858c2ecf20Sopenharmony_ci	if (rc < 0)
11868c2ecf20Sopenharmony_ci		goto report_failure;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	/* Check to see next free device and mark as used */
11898c2ecf20Sopenharmony_ci	nr = find_first_zero_bit(&tm6000_devused, TM6000_MAXBOARDS);
11908c2ecf20Sopenharmony_ci	if (nr >= TM6000_MAXBOARDS) {
11918c2ecf20Sopenharmony_ci		printk(KERN_ERR "tm6000: Supports only %i tm60xx boards.\n", TM6000_MAXBOARDS);
11928c2ecf20Sopenharmony_ci		rc = -ENOMEM;
11938c2ecf20Sopenharmony_ci		goto put_device;
11948c2ecf20Sopenharmony_ci	}
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	/* Create and initialize dev struct */
11978c2ecf20Sopenharmony_ci	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
11988c2ecf20Sopenharmony_ci	if (!dev) {
11998c2ecf20Sopenharmony_ci		rc = -ENOMEM;
12008c2ecf20Sopenharmony_ci		goto put_device;
12018c2ecf20Sopenharmony_ci	}
12028c2ecf20Sopenharmony_ci	spin_lock_init(&dev->slock);
12038c2ecf20Sopenharmony_ci	mutex_init(&dev->usb_lock);
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	/* Increment usage count */
12068c2ecf20Sopenharmony_ci	set_bit(nr, &tm6000_devused);
12078c2ecf20Sopenharmony_ci	snprintf(dev->name, 29, "tm6000 #%d", nr);
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	dev->model = id->driver_info;
12108c2ecf20Sopenharmony_ci	if (card[nr] < ARRAY_SIZE(tm6000_boards))
12118c2ecf20Sopenharmony_ci		dev->model = card[nr];
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	dev->udev = usbdev;
12148c2ecf20Sopenharmony_ci	dev->devno = nr;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	switch (usbdev->speed) {
12178c2ecf20Sopenharmony_ci	case USB_SPEED_LOW:
12188c2ecf20Sopenharmony_ci		speed = "1.5";
12198c2ecf20Sopenharmony_ci		break;
12208c2ecf20Sopenharmony_ci	case USB_SPEED_UNKNOWN:
12218c2ecf20Sopenharmony_ci	case USB_SPEED_FULL:
12228c2ecf20Sopenharmony_ci		speed = "12";
12238c2ecf20Sopenharmony_ci		break;
12248c2ecf20Sopenharmony_ci	case USB_SPEED_HIGH:
12258c2ecf20Sopenharmony_ci		speed = "480";
12268c2ecf20Sopenharmony_ci		break;
12278c2ecf20Sopenharmony_ci	default:
12288c2ecf20Sopenharmony_ci		speed = "unknown";
12298c2ecf20Sopenharmony_ci	}
12308c2ecf20Sopenharmony_ci
12318c2ecf20Sopenharmony_ci	/* Get endpoints */
12328c2ecf20Sopenharmony_ci	for (i = 0; i < interface->num_altsetting; i++) {
12338c2ecf20Sopenharmony_ci		int ep;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci		for (ep = 0; ep < interface->altsetting[i].desc.bNumEndpoints; ep++) {
12368c2ecf20Sopenharmony_ci			struct usb_host_endpoint	*e;
12378c2ecf20Sopenharmony_ci			int dir_out;
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci			e = &interface->altsetting[i].endpoint[ep];
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci			dir_out = ((e->desc.bEndpointAddress &
12428c2ecf20Sopenharmony_ci					USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci			printk(KERN_INFO "tm6000: alt %d, interface %i, class %i\n",
12458c2ecf20Sopenharmony_ci			       i,
12468c2ecf20Sopenharmony_ci			       interface->altsetting[i].desc.bInterfaceNumber,
12478c2ecf20Sopenharmony_ci			       interface->altsetting[i].desc.bInterfaceClass);
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci			switch (e->desc.bmAttributes) {
12508c2ecf20Sopenharmony_ci			case USB_ENDPOINT_XFER_BULK:
12518c2ecf20Sopenharmony_ci				if (!dir_out) {
12528c2ecf20Sopenharmony_ci					get_max_endpoint(usbdev,
12538c2ecf20Sopenharmony_ci							 &interface->altsetting[i],
12548c2ecf20Sopenharmony_ci							 "Bulk IN", e,
12558c2ecf20Sopenharmony_ci							 &dev->bulk_in);
12568c2ecf20Sopenharmony_ci				} else {
12578c2ecf20Sopenharmony_ci					get_max_endpoint(usbdev,
12588c2ecf20Sopenharmony_ci							 &interface->altsetting[i],
12598c2ecf20Sopenharmony_ci							 "Bulk OUT", e,
12608c2ecf20Sopenharmony_ci							 &dev->bulk_out);
12618c2ecf20Sopenharmony_ci				}
12628c2ecf20Sopenharmony_ci				break;
12638c2ecf20Sopenharmony_ci			case USB_ENDPOINT_XFER_ISOC:
12648c2ecf20Sopenharmony_ci				if (!dir_out) {
12658c2ecf20Sopenharmony_ci					get_max_endpoint(usbdev,
12668c2ecf20Sopenharmony_ci							 &interface->altsetting[i],
12678c2ecf20Sopenharmony_ci							 "ISOC IN", e,
12688c2ecf20Sopenharmony_ci							 &dev->isoc_in);
12698c2ecf20Sopenharmony_ci				} else {
12708c2ecf20Sopenharmony_ci					get_max_endpoint(usbdev,
12718c2ecf20Sopenharmony_ci							 &interface->altsetting[i],
12728c2ecf20Sopenharmony_ci							 "ISOC OUT", e,
12738c2ecf20Sopenharmony_ci							 &dev->isoc_out);
12748c2ecf20Sopenharmony_ci				}
12758c2ecf20Sopenharmony_ci				break;
12768c2ecf20Sopenharmony_ci			case USB_ENDPOINT_XFER_INT:
12778c2ecf20Sopenharmony_ci				if (!dir_out) {
12788c2ecf20Sopenharmony_ci					get_max_endpoint(usbdev,
12798c2ecf20Sopenharmony_ci							&interface->altsetting[i],
12808c2ecf20Sopenharmony_ci							"INT IN", e,
12818c2ecf20Sopenharmony_ci							&dev->int_in);
12828c2ecf20Sopenharmony_ci				} else {
12838c2ecf20Sopenharmony_ci					get_max_endpoint(usbdev,
12848c2ecf20Sopenharmony_ci							&interface->altsetting[i],
12858c2ecf20Sopenharmony_ci							"INT OUT", e,
12868c2ecf20Sopenharmony_ci							&dev->int_out);
12878c2ecf20Sopenharmony_ci				}
12888c2ecf20Sopenharmony_ci				break;
12898c2ecf20Sopenharmony_ci			}
12908c2ecf20Sopenharmony_ci		}
12918c2ecf20Sopenharmony_ci	}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	printk(KERN_INFO "tm6000: New video device @ %s Mbps (%04x:%04x, ifnum %d)\n",
12958c2ecf20Sopenharmony_ci		speed,
12968c2ecf20Sopenharmony_ci		le16_to_cpu(dev->udev->descriptor.idVendor),
12978c2ecf20Sopenharmony_ci		le16_to_cpu(dev->udev->descriptor.idProduct),
12988c2ecf20Sopenharmony_ci		interface->altsetting->desc.bInterfaceNumber);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci/* check if the the device has the iso in endpoint at the correct place */
13018c2ecf20Sopenharmony_ci	if (!dev->isoc_in.endp) {
13028c2ecf20Sopenharmony_ci		printk(KERN_ERR "tm6000: probing error: no IN ISOC endpoint!\n");
13038c2ecf20Sopenharmony_ci		rc = -ENODEV;
13048c2ecf20Sopenharmony_ci		goto free_device;
13058c2ecf20Sopenharmony_ci	}
13068c2ecf20Sopenharmony_ci
13078c2ecf20Sopenharmony_ci	/* save our data pointer in this interface device */
13088c2ecf20Sopenharmony_ci	usb_set_intfdata(interface, dev);
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	printk(KERN_INFO "tm6000: Found %s\n", tm6000_boards[dev->model].name);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	rc = tm6000_init_dev(dev);
13138c2ecf20Sopenharmony_ci	if (rc < 0)
13148c2ecf20Sopenharmony_ci		goto free_device;
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	return 0;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_cifree_device:
13198c2ecf20Sopenharmony_ci	kfree(dev);
13208c2ecf20Sopenharmony_cireport_failure:
13218c2ecf20Sopenharmony_ci	printk(KERN_ERR "tm6000: Error %d while registering\n", rc);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci	clear_bit(nr, &tm6000_devused);
13248c2ecf20Sopenharmony_ciput_device:
13258c2ecf20Sopenharmony_ci	usb_put_dev(usbdev);
13268c2ecf20Sopenharmony_ci	return rc;
13278c2ecf20Sopenharmony_ci}
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci/*
13308c2ecf20Sopenharmony_ci * tm6000_usb_disconnect()
13318c2ecf20Sopenharmony_ci * called when the device gets disconnected
13328c2ecf20Sopenharmony_ci * video device will be unregistered on v4l2_close in case it is still open
13338c2ecf20Sopenharmony_ci */
13348c2ecf20Sopenharmony_cistatic void tm6000_usb_disconnect(struct usb_interface *interface)
13358c2ecf20Sopenharmony_ci{
13368c2ecf20Sopenharmony_ci	struct tm6000_core *dev = usb_get_intfdata(interface);
13378c2ecf20Sopenharmony_ci	usb_set_intfdata(interface, NULL);
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	if (!dev)
13408c2ecf20Sopenharmony_ci		return;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	printk(KERN_INFO "tm6000: disconnecting %s\n", dev->name);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci	flush_request_modules(dev);
13458c2ecf20Sopenharmony_ci
13468c2ecf20Sopenharmony_ci	tm6000_ir_fini(dev);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	if (dev->gpio.power_led) {
13498c2ecf20Sopenharmony_ci		switch (dev->model) {
13508c2ecf20Sopenharmony_ci		case TM6010_BOARD_HAUPPAUGE_900H:
13518c2ecf20Sopenharmony_ci		case TM6010_BOARD_TERRATEC_CINERGY_HYBRID_XE:
13528c2ecf20Sopenharmony_ci		case TM6010_BOARD_TWINHAN_TU501:
13538c2ecf20Sopenharmony_ci			/* Power led off */
13548c2ecf20Sopenharmony_ci			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
13558c2ecf20Sopenharmony_ci				dev->gpio.power_led, 0x01);
13568c2ecf20Sopenharmony_ci			msleep(15);
13578c2ecf20Sopenharmony_ci			break;
13588c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_WANDER:
13598c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_VOYAGER:
13608c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_WANDER_LITE:
13618c2ecf20Sopenharmony_ci		case TM6010_BOARD_BEHOLD_VOYAGER_LITE:
13628c2ecf20Sopenharmony_ci			/* Power led off */
13638c2ecf20Sopenharmony_ci			tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN,
13648c2ecf20Sopenharmony_ci				dev->gpio.power_led, 0x00);
13658c2ecf20Sopenharmony_ci			msleep(15);
13668c2ecf20Sopenharmony_ci			break;
13678c2ecf20Sopenharmony_ci		}
13688c2ecf20Sopenharmony_ci	}
13698c2ecf20Sopenharmony_ci	tm6000_v4l2_unregister(dev);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci	tm6000_i2c_unregister(dev);
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci	v4l2_device_unregister(&dev->v4l2_dev);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	dev->state |= DEV_DISCONNECTED;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	usb_put_dev(dev->udev);
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	tm6000_close_extension(dev);
13808c2ecf20Sopenharmony_ci	tm6000_remove_from_devlist(dev);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	clear_bit(dev->devno, &tm6000_devused);
13838c2ecf20Sopenharmony_ci	kfree(dev);
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_cistatic struct usb_driver tm6000_usb_driver = {
13878c2ecf20Sopenharmony_ci		.name = "tm6000",
13888c2ecf20Sopenharmony_ci		.probe = tm6000_usb_probe,
13898c2ecf20Sopenharmony_ci		.disconnect = tm6000_usb_disconnect,
13908c2ecf20Sopenharmony_ci		.id_table = tm6000_id_table,
13918c2ecf20Sopenharmony_ci};
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_cimodule_usb_driver(tm6000_usb_driver);
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Trident TVMaster TM5600/TM6000/TM6010 USB2 adapter");
13968c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mauro Carvalho Chehab");
13978c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1398