1/*
2 *  Driver for the Auvitek USB bridge
3 *
4 *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
5 *
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; either version 2 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *
15 *  GNU General Public License for more details.
16 *
17 *  You should have received a copy of the GNU General Public License
18 *  along with this program; if not, write to the Free Software
19 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include "au0828.h"
23#include "au0828-cards.h"
24#include "au8522.h"
25#include "media/tuner.h"
26#include "media/v4l2-common.h"
27
28static void hvr950q_cs5340_audio(void *priv, int enable)
29{
30	/* Because the HVR-950q shares an i2s bus between the cs5340 and the
31	   au8522, we need to hold cs5340 in reset when using the au8522 */
32	struct au0828_dev *dev = priv;
33	if (enable == 1)
34		au0828_set(dev, REG_000, 0x10);
35	else
36		au0828_clear(dev, REG_000, 0x10);
37}
38
39/*
40 * WARNING: There's a quirks table at sound/usb/quirks-table.h
41 * that should also be updated every time a new device with V4L2 support
42 * is added here.
43 */
44struct au0828_board au0828_boards[] = {
45	[AU0828_BOARD_UNKNOWN] = {
46		.name	= "Unknown board",
47		.tuner_type = -1U,
48		.tuner_addr = ADDR_UNSET,
49	},
50	[AU0828_BOARD_HAUPPAUGE_HVR850] = {
51		.name	= "Hauppauge HVR850",
52		.tuner_type = TUNER_XC5000,
53		.tuner_addr = 0x61,
54		.has_ir_i2c = 1,
55		.has_analog = 1,
56		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
57		.input = {
58			{
59				.type = AU0828_VMUX_TELEVISION,
60				.vmux = AU8522_COMPOSITE_CH4_SIF,
61				.amux = AU8522_AUDIO_SIF,
62			},
63			{
64				.type = AU0828_VMUX_COMPOSITE,
65				.vmux = AU8522_COMPOSITE_CH1,
66				.amux = AU8522_AUDIO_NONE,
67				.audio_setup = hvr950q_cs5340_audio,
68			},
69			{
70				.type = AU0828_VMUX_SVIDEO,
71				.vmux = AU8522_SVIDEO_CH13,
72				.amux = AU8522_AUDIO_NONE,
73				.audio_setup = hvr950q_cs5340_audio,
74			},
75		},
76	},
77	[AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
78		.name	= "Hauppauge HVR950Q",
79		.tuner_type = TUNER_XC5000,
80		.tuner_addr = 0x61,
81		.has_ir_i2c = 1,
82		.has_analog = 1,
83		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
84		.input = {
85			{
86				.type = AU0828_VMUX_TELEVISION,
87				.vmux = AU8522_COMPOSITE_CH4_SIF,
88				.amux = AU8522_AUDIO_SIF,
89			},
90			{
91				.type = AU0828_VMUX_COMPOSITE,
92				.vmux = AU8522_COMPOSITE_CH1,
93				.amux = AU8522_AUDIO_NONE,
94				.audio_setup = hvr950q_cs5340_audio,
95			},
96			{
97				.type = AU0828_VMUX_SVIDEO,
98				.vmux = AU8522_SVIDEO_CH13,
99				.amux = AU8522_AUDIO_NONE,
100				.audio_setup = hvr950q_cs5340_audio,
101			},
102		},
103	},
104	[AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
105		.name	= "Hauppauge HVR950Q rev xxF8",
106		.tuner_type = TUNER_XC5000,
107		.tuner_addr = 0x61,
108		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
109	},
110	[AU0828_BOARD_DVICO_FUSIONHDTV7] = {
111		.name	= "DViCO FusionHDTV USB",
112		.tuner_type = TUNER_XC5000,
113		.tuner_addr = 0x61,
114		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
115	},
116	[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
117		.name = "Hauppauge Woodbury",
118		.tuner_type = TUNER_NXP_TDA18271,
119		.tuner_addr = 0x60,
120		.i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
121	},
122};
123
124/* Tuner callback function for au0828 boards. Currently only needed
125 * for HVR1500Q, which has an xc5000 tuner.
126 */
127int au0828_tuner_callback(void *priv, int component, int command, int arg)
128{
129	struct au0828_dev *dev = priv;
130
131	dprintk(1, "%s()\n", __func__);
132
133	switch (dev->boardnr) {
134	case AU0828_BOARD_HAUPPAUGE_HVR850:
135	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
136	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
137	case AU0828_BOARD_DVICO_FUSIONHDTV7:
138		if (command == 0) {
139			/* Tuner Reset Command from xc5000 */
140			/* Drive the tuner into reset and out */
141			au0828_clear(dev, REG_001, 2);
142			mdelay(10);
143			au0828_set(dev, REG_001, 2);
144			mdelay(10);
145			return 0;
146		} else {
147			pr_err("%s(): Unknown command.\n", __func__);
148			return -EINVAL;
149		}
150		break;
151	}
152
153	return 0; /* Should never be here */
154}
155
156static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
157{
158	struct tveeprom tv;
159
160	tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
161	dev->board.tuner_type = tv.tuner_type;
162
163	/* Make sure we support the board model */
164	switch (tv.model) {
165	case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
166	case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
167	case 72101: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
168	case 72201: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
169	case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
170	case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
171	case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
172	case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
173	case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
174	case 72261: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
175	case 72271: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
176	case 72281: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
177	case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
178	case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
179		break;
180	default:
181		pr_warn("%s: warning: unknown hauppauge model #%d\n",
182			__func__, tv.model);
183		break;
184	}
185
186	pr_info("%s: hauppauge eeprom: model=%d\n",
187	       __func__, tv.model);
188}
189
190void au0828_card_analog_fe_setup(struct au0828_dev *dev);
191
192void au0828_card_setup(struct au0828_dev *dev)
193{
194	static u8 eeprom[256];
195
196	dprintk(1, "%s()\n", __func__);
197
198	if (dev->i2c_rc == 0) {
199		dev->i2c_client.addr = 0xa0 >> 1;
200		tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
201	}
202
203	switch (dev->boardnr) {
204	case AU0828_BOARD_HAUPPAUGE_HVR850:
205	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
206	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
207	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
208		if (dev->i2c_rc == 0)
209			hauppauge_eeprom(dev, eeprom+0xa0);
210		break;
211	}
212
213	au0828_card_analog_fe_setup(dev);
214}
215
216void au0828_card_analog_fe_setup(struct au0828_dev *dev)
217{
218#ifdef CONFIG_VIDEO_AU0828_V4L2
219	struct tuner_setup tun_setup;
220	struct v4l2_subdev *sd;
221	unsigned int mode_mask = T_ANALOG_TV;
222
223	if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
224		/* Load the analog demodulator driver (note this would need to
225		   be abstracted out if we ever need to support a different
226		   demod) */
227		sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
228				"au8522", 0x8e >> 1, NULL);
229		if (sd == NULL)
230			pr_err("analog subdev registration failed\n");
231	}
232
233	/* Setup tuners */
234	if (dev->board.tuner_type != TUNER_ABSENT && dev->board.has_analog) {
235		/* Load the tuner module, which does the attach */
236		sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
237				"tuner", dev->board.tuner_addr, NULL);
238		if (sd == NULL)
239			pr_err("tuner subdev registration fail\n");
240
241		tun_setup.mode_mask      = mode_mask;
242		tun_setup.type           = dev->board.tuner_type;
243		tun_setup.addr           = dev->board.tuner_addr;
244		tun_setup.tuner_callback = au0828_tuner_callback;
245		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
246				     &tun_setup);
247	}
248#endif
249}
250
251/*
252 * The bridge has between 8 and 12 gpios.
253 * Regs 1 and 0 deal with output enables.
254 * Regs 3 and 2 deal with direction.
255 */
256void au0828_gpio_setup(struct au0828_dev *dev)
257{
258	dprintk(1, "%s()\n", __func__);
259
260	switch (dev->boardnr) {
261	case AU0828_BOARD_HAUPPAUGE_HVR850:
262	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
263	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
264	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
265		/* GPIO's
266		 * 4 - CS5340
267		 * 5 - AU8522 Demodulator
268		 * 6 - eeprom W/P
269		 * 7 - power supply
270		 * 9 - XC5000 Tuner
271		 */
272
273		/* Set relevant GPIOs as outputs (leave the EEPROM W/P
274		   as an input since we will never touch it and it has
275		   a pullup) */
276		au0828_write(dev, REG_003, 0x02);
277		au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
278
279		/* Into reset */
280		au0828_write(dev, REG_001, 0x0);
281		au0828_write(dev, REG_000, 0x0);
282		msleep(50);
283
284		/* Bring power supply out of reset */
285		au0828_write(dev, REG_000, 0x80);
286		msleep(50);
287
288		/* Bring xc5000 and au8522 out of reset (leave the
289		   cs5340 in reset until needed) */
290		au0828_write(dev, REG_001, 0x02); /* xc5000 */
291		au0828_write(dev, REG_000, 0x80 | 0x20); /* PS + au8522 */
292
293		msleep(250);
294		break;
295	case AU0828_BOARD_DVICO_FUSIONHDTV7:
296		/* GPIO's
297		 * 6 - ?
298		 * 8 - AU8522 Demodulator
299		 * 9 - XC5000 Tuner
300		 */
301
302		/* Into reset */
303		au0828_write(dev, REG_003, 0x02);
304		au0828_write(dev, REG_002, 0xa0);
305		au0828_write(dev, REG_001, 0x0);
306		au0828_write(dev, REG_000, 0x0);
307		msleep(100);
308
309		/* Out of reset */
310		au0828_write(dev, REG_003, 0x02);
311		au0828_write(dev, REG_002, 0xa0);
312		au0828_write(dev, REG_001, 0x02);
313		au0828_write(dev, REG_000, 0xa0);
314		msleep(250);
315		break;
316	}
317}
318
319/* table of devices that work with this driver */
320struct usb_device_id au0828_usb_id_table[] = {
321	{ USB_DEVICE(0x2040, 0x7200),
322		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
323	{ USB_DEVICE(0x2040, 0x7240),
324		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
325	{ USB_DEVICE(0x0fe9, 0xd620),
326		.driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
327	{ USB_DEVICE(0x2040, 0x7210),
328		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
329	{ USB_DEVICE(0x2040, 0x7217),
330		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
331	{ USB_DEVICE(0x2040, 0x721b),
332		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
333	{ USB_DEVICE(0x2040, 0x721e),
334		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
335	{ USB_DEVICE(0x2040, 0x721f),
336		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
337	{ USB_DEVICE(0x2040, 0x7280),
338		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
339	{ USB_DEVICE(0x0fd9, 0x0008),
340		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
341	{ USB_DEVICE(0x2040, 0x7201),
342		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
343	{ USB_DEVICE(0x2040, 0x7211),
344		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
345	{ USB_DEVICE(0x2040, 0x7281),
346		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
347	{ USB_DEVICE(0x05e1, 0x0480),
348		.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
349	{ USB_DEVICE(0x2040, 0x8200),
350		.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
351	{ USB_DEVICE(0x2040, 0x7260),
352		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
353	{ USB_DEVICE(0x2040, 0x7213),
354		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
355	{ USB_DEVICE(0x2040, 0x7270),
356		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
357	{ },
358};
359
360MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
361