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	dev->board = au0828_boards[dev->boardnr];
199
200	if (dev->i2c_rc == 0) {
201		dev->i2c_client.addr = 0xa0 >> 1;
202		tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
203	}
204
205	switch (dev->boardnr) {
206	case AU0828_BOARD_HAUPPAUGE_HVR850:
207	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
208	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
209	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
210		if (dev->i2c_rc == 0)
211			hauppauge_eeprom(dev, eeprom+0xa0);
212		break;
213	}
214
215	au0828_card_analog_fe_setup(dev);
216}
217
218void au0828_card_analog_fe_setup(struct au0828_dev *dev)
219{
220#ifdef CONFIG_VIDEO_AU0828_V4L2
221	struct tuner_setup tun_setup;
222	struct v4l2_subdev *sd;
223	unsigned int mode_mask = T_ANALOG_TV;
224
225	if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
226		/* Load the analog demodulator driver (note this would need to
227		   be abstracted out if we ever need to support a different
228		   demod) */
229		sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
230				"au8522", 0x8e >> 1, NULL);
231		if (sd == NULL)
232			pr_err("analog subdev registration failed\n");
233	}
234
235	/* Setup tuners */
236	if (dev->board.tuner_type != TUNER_ABSENT && dev->board.has_analog) {
237		/* Load the tuner module, which does the attach */
238		sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
239				"tuner", dev->board.tuner_addr, NULL);
240		if (sd == NULL)
241			pr_err("tuner subdev registration fail\n");
242
243		tun_setup.mode_mask      = mode_mask;
244		tun_setup.type           = dev->board.tuner_type;
245		tun_setup.addr           = dev->board.tuner_addr;
246		tun_setup.tuner_callback = au0828_tuner_callback;
247		v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
248				     &tun_setup);
249	}
250#endif
251}
252
253/*
254 * The bridge has between 8 and 12 gpios.
255 * Regs 1 and 0 deal with output enables.
256 * Regs 3 and 2 deal with direction.
257 */
258void au0828_gpio_setup(struct au0828_dev *dev)
259{
260	dprintk(1, "%s()\n", __func__);
261
262	switch (dev->boardnr) {
263	case AU0828_BOARD_HAUPPAUGE_HVR850:
264	case AU0828_BOARD_HAUPPAUGE_HVR950Q:
265	case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
266	case AU0828_BOARD_HAUPPAUGE_WOODBURY:
267		/* GPIO's
268		 * 4 - CS5340
269		 * 5 - AU8522 Demodulator
270		 * 6 - eeprom W/P
271		 * 7 - power supply
272		 * 9 - XC5000 Tuner
273		 */
274
275		/* Set relevant GPIOs as outputs (leave the EEPROM W/P
276		   as an input since we will never touch it and it has
277		   a pullup) */
278		au0828_write(dev, REG_003, 0x02);
279		au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
280
281		/* Into reset */
282		au0828_write(dev, REG_001, 0x0);
283		au0828_write(dev, REG_000, 0x0);
284		msleep(50);
285
286		/* Bring power supply out of reset */
287		au0828_write(dev, REG_000, 0x80);
288		msleep(50);
289
290		/* Bring xc5000 and au8522 out of reset (leave the
291		   cs5340 in reset until needed) */
292		au0828_write(dev, REG_001, 0x02); /* xc5000 */
293		au0828_write(dev, REG_000, 0x80 | 0x20); /* PS + au8522 */
294
295		msleep(250);
296		break;
297	case AU0828_BOARD_DVICO_FUSIONHDTV7:
298		/* GPIO's
299		 * 6 - ?
300		 * 8 - AU8522 Demodulator
301		 * 9 - XC5000 Tuner
302		 */
303
304		/* Into reset */
305		au0828_write(dev, REG_003, 0x02);
306		au0828_write(dev, REG_002, 0xa0);
307		au0828_write(dev, REG_001, 0x0);
308		au0828_write(dev, REG_000, 0x0);
309		msleep(100);
310
311		/* Out of reset */
312		au0828_write(dev, REG_003, 0x02);
313		au0828_write(dev, REG_002, 0xa0);
314		au0828_write(dev, REG_001, 0x02);
315		au0828_write(dev, REG_000, 0xa0);
316		msleep(250);
317		break;
318	}
319}
320
321/* table of devices that work with this driver */
322struct usb_device_id au0828_usb_id_table[] = {
323	{ USB_DEVICE(0x2040, 0x7200),
324		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
325	{ USB_DEVICE(0x2040, 0x7240),
326		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
327	{ USB_DEVICE(0x0fe9, 0xd620),
328		.driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
329	{ USB_DEVICE(0x2040, 0x7210),
330		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
331	{ USB_DEVICE(0x2040, 0x7217),
332		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
333	{ USB_DEVICE(0x2040, 0x721b),
334		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
335	{ USB_DEVICE(0x2040, 0x721e),
336		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
337	{ USB_DEVICE(0x2040, 0x721f),
338		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
339	{ USB_DEVICE(0x2040, 0x7280),
340		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
341	{ USB_DEVICE(0x0fd9, 0x0008),
342		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
343	{ USB_DEVICE(0x2040, 0x7201),
344		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
345	{ USB_DEVICE(0x2040, 0x7211),
346		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
347	{ USB_DEVICE(0x2040, 0x7281),
348		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
349	{ USB_DEVICE(0x05e1, 0x0480),
350		.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
351	{ USB_DEVICE(0x2040, 0x8200),
352		.driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
353	{ USB_DEVICE(0x2040, 0x7260),
354		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
355	{ USB_DEVICE(0x2040, 0x7213),
356		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
357	{ USB_DEVICE(0x2040, 0x7270),
358		.driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
359	{ },
360};
361
362MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
363