1/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
2 *
3 *	This program is free software; you can redistribute it and/or modify it
4 *	under the terms of the GNU General Public License as published by the Free
5 *	Software Foundation, version 2.
6 *
7 *  Copyright (C) 2005-6 DiBcom, SA
8 */
9#include "dib0700.h"
10
11#include "dib3000mc.h"
12#include "dib7000m.h"
13#include "dib7000p.h"
14#include "mt2060.h"
15
16static int force_lna_activation;
17module_param(force_lna_activation, int, 0644);
18MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
19		"if applicable for the device (default: 0=automatic/off).");
20
21/* Hauppauge Nova-T 500
22 *  has a LNA on GPIO0 which is enabled by setting 1 */
23static struct mt2060_config bristol_mt2060_config[2] = {
24	{
25		.i2c_address = 0x60,
26		.clock_out   = 3,
27	}, {
28		.i2c_address = 0x61,
29	}
30};
31
32static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
33	.band_caps = BAND_VHF | BAND_UHF,
34	.setup     = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),
35
36	.agc1_max = 42598,
37	.agc1_min = 17694,
38	.agc2_max = 45875,
39	.agc2_min = 0,
40
41	.agc1_pt1 = 0,
42	.agc1_pt2 = 59,
43
44	.agc1_slope1 = 0,
45	.agc1_slope2 = 69,
46
47	.agc2_pt1 = 0,
48	.agc2_pt2 = 59,
49
50	.agc2_slope1 = 111,
51	.agc2_slope2 = 28,
52};
53
54static struct dib3000mc_config bristol_dib3000mc_config[2] = {
55	{	.agc          = &bristol_dib3000p_mt2060_agc_config,
56		.max_time     = 0x196,
57		.ln_adc_level = 0x1cc7,
58		.output_mpeg2_in_188_bytes = 1,
59	},
60	{	.agc          = &bristol_dib3000p_mt2060_agc_config,
61		.max_time     = 0x196,
62		.ln_adc_level = 0x1cc7,
63		.output_mpeg2_in_188_bytes = 1,
64	}
65};
66
67static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
68{
69	struct dib0700_state *st = adap->dev->priv;
70	if (adap->id == 0) {
71		dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0); msleep(10);
72		dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1); msleep(10);
73		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
74		dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);
75
76		if (force_lna_activation)
77			dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
78		else
79			dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
80
81		if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) {
82			dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
83			return -ENODEV;
84		}
85	}
86	st->mt2060_if1[adap->id] = 1220;
87	return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap,
88		(10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
89}
90
91static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
92{
93	struct dib0700_state *st = adap->dev->priv;
94	struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
95	return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id],
96		st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
97}
98
99/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
100static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
101	BAND_UHF | BAND_VHF,       // band_caps
102
103	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
104	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
105	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
106
107	712,  // inv_gain
108	41,  // time_stabiliz
109
110	0,  // alpha_level
111	118,  // thlock
112
113	0,     // wbd_inv
114	4095,  // wbd_ref
115	0,     // wbd_sel
116	0,     // wbd_alpha
117
118	42598,  // agc1_max
119	17694,  // agc1_min
120	45875,  // agc2_max
121	2621,  // agc2_min
122	0,  // agc1_pt1
123	76,  // agc1_pt2
124	139,  // agc1_pt3
125	52,  // agc1_slope1
126	59,  // agc1_slope2
127	107,  // agc2_pt1
128	172,  // agc2_pt2
129	57,  // agc2_slope1
130	70,  // agc2_slope2
131
132	21,  // alpha_mant
133	25,  // alpha_exp
134	28,  // beta_mant
135	48,  // beta_exp
136
137	1,  // perform_agc_softsplit
138	{  0,     // split_min
139	   107,   // split_max
140	   51800, // global_split_min
141	   24700  // global_split_max
142	},
143};
144
145static struct dibx000_agc_config stk7700p_7000p_mt2060_agc_config = {
146	BAND_UHF | BAND_VHF,
147
148	/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
149	 * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
150	(0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), // setup
151
152	712, // inv_gain
153	41,  // time_stabiliz
154
155	0,   // alpha_level
156	118, // thlock
157
158	0,    // wbd_inv
159	4095, // wbd_ref
160	0,    // wbd_sel
161	0,    // wbd_alpha
162
163	42598, // agc1_max
164	16384, // agc1_min
165	42598, // agc2_max
166	    0, // agc2_min
167
168	  0,   // agc1_pt1
169	137,   // agc1_pt2
170	255,   // agc1_pt3
171
172	  0,   // agc1_slope1
173	255,   // agc1_slope2
174
175	0,     // agc2_pt1
176	0,     // agc2_pt2
177
178	 0,    // agc2_slope1
179	41,    // agc2_slope2
180
181	15, // alpha_mant
182	25, // alpha_exp
183
184	28, // beta_mant
185	48, // beta_exp
186
187	0, // perform_agc_softsplit
188};
189
190static struct dibx000_bandwidth_config stk7700p_pll_config = {
191	60000, 30000, // internal, sampling
192	1, 8, 3, 1, 0, // pll_cfg: prediv, ratio, range, reset, bypass
193	0, 0, 1, 1, 0, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
194	(3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
195	60258167, // ifreq
196	20452225, // timf
197};
198
199static struct dib7000m_config stk7700p_dib7000m_config = {
200	.dvbt_mode = 1,
201	.output_mpeg2_in_188_bytes = 1,
202	.quartz_direct = 1,
203
204	.agc_config_count = 1,
205	.agc = &stk7700p_7000m_mt2060_agc_config,
206	.bw  = &stk7700p_pll_config,
207
208	.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
209	.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
210	.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
211};
212
213static struct dib7000p_config stk7700p_dib7000p_config = {
214	.output_mpeg2_in_188_bytes = 1,
215
216	.agc = &stk7700p_7000p_mt2060_agc_config,
217	.bw  = &stk7700p_pll_config,
218
219	.gpio_dir = DIB7000M_GPIO_DEFAULT_DIRECTIONS,
220	.gpio_val = DIB7000M_GPIO_DEFAULT_VALUES,
221	.gpio_pwm_pos = DIB7000M_GPIO_DEFAULT_PWM_POS,
222};
223
224static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
225{
226	struct dib0700_state *st = adap->dev->priv;
227	/* unless there is no real power management in DVB - we leave the device on GPIO6 */
228
229	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
230	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 0); msleep(50);
231
232	dib0700_set_gpio(adap->dev, GPIO6,  GPIO_OUT, 1); msleep(10);
233	dib0700_set_gpio(adap->dev, GPIO9,  GPIO_OUT, 1);
234
235	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
236	dib0700_ctrl_clock(adap->dev, 72, 1);
237	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(100);
238
239	dib0700_set_gpio(adap->dev,  GPIO0, GPIO_OUT, 1);
240
241	st->mt2060_if1[0] = 1220;
242
243	if (dib7000pc_detection(&adap->dev->i2c_adap)) {
244		adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
245		st->is_dib7000pc = 1;
246	} else
247		adap->fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
248
249	return adap->fe == NULL ? -ENODEV : 0;
250}
251
252static struct mt2060_config stk7700p_mt2060_config = {
253	0x60
254};
255
256static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
257{
258	struct dib0700_state *st = adap->dev->priv;
259	struct i2c_adapter *tun_i2c;
260
261	if (st->is_dib7000pc)
262		tun_i2c = dib7000p_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
263	else
264		tun_i2c = dib7000m_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
265
266	return dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk7700p_mt2060_config,
267		st->mt2060_if1[0]) == NULL ? -ENODEV : 0;
268}
269
270struct usb_device_id dib0700_usb_id_table[] = {
271		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P) },
272		{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK7700P_PC) },
273
274		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
275		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
276		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
277		{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
278		{ USB_DEVICE(USB_VID_COMPRO,    USB_PID_COMPRO_VIDEOMATE_U500) },
279		{ USB_DEVICE(USB_VID_UNIWILL,   USB_PID_UNIWILL_STK7700P) },
280		{ USB_DEVICE(USB_VID_LEADTEK,   USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
281		{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
282		{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
283		{ }		/* Terminating entry */
284};
285MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
286
287#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
288	.caps              = DVB_USB_IS_AN_I2C_ADAPTER, \
289	.usb_ctrl          = DEVICE_SPECIFIC, \
290	.firmware          = "dvb-usb-dib0700-01.fw", \
291	.download_firmware = dib0700_download_firmware, \
292	.no_reconnect      = 1, \
293	.size_of_priv      = sizeof(struct dib0700_state), \
294	.i2c_algo          = &dib0700_i2c_algo, \
295	.identify_state    = dib0700_identify_state
296
297#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \
298	.streaming_ctrl   = dib0700_streaming_ctrl, \
299	.stream = { \
300		.type = USB_BULK, \
301		.count = 4, \
302		.endpoint = ep, \
303		.u = { \
304			.bulk = { \
305				.buffersize = 39480, \
306			} \
307		} \
308	}
309
310struct dvb_usb_device_properties dib0700_devices[] = {
311	{
312		DIB0700_DEFAULT_DEVICE_PROPERTIES,
313
314		.num_adapters = 1,
315		.adapter = {
316			{
317				.frontend_attach  = stk7700p_frontend_attach,
318				.tuner_attach     = stk7700p_tuner_attach,
319
320				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
321			},
322		},
323
324		.num_device_descs = 6,
325		.devices = {
326			{   "DiBcom STK7700P reference design",
327				{ &dib0700_usb_id_table[0], &dib0700_usb_id_table[1] },
328				{ NULL },
329			},
330			{   "Hauppauge Nova-T Stick",
331				{ &dib0700_usb_id_table[4], &dib0700_usb_id_table[9], NULL },
332				{ NULL },
333			},
334			{   "AVerMedia AVerTV DVB-T Volar",
335				{ &dib0700_usb_id_table[5], &dib0700_usb_id_table[10] },
336				{ NULL },
337			},
338			{   "Compro Videomate U500",
339				{ &dib0700_usb_id_table[6], NULL },
340				{ NULL },
341			},
342			{   "Uniwill STK7700P based (Hama and others)",
343				{ &dib0700_usb_id_table[7], NULL },
344				{ NULL },
345			},
346			{   "Leadtek Winfast DTV Dongle (STK7700P based)",
347				{ &dib0700_usb_id_table[8], NULL },
348				{ NULL },
349			}
350		}
351	}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
352
353		.num_adapters = 2,
354		.adapter = {
355			{
356				.frontend_attach  = bristol_frontend_attach,
357				.tuner_attach     = bristol_tuner_attach,
358
359				DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
360			}, {
361				.frontend_attach  = bristol_frontend_attach,
362				.tuner_attach     = bristol_tuner_attach,
363
364				DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
365			}
366		},
367
368		.num_device_descs = 1,
369		.devices = {
370			{   "Hauppauge Nova-T 500 Dual DVB-T",
371				{ &dib0700_usb_id_table[2], &dib0700_usb_id_table[3], NULL },
372				{ NULL },
373			},
374		}
375	}
376};
377
378int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
379