Commit | Line | Data |
---|---|---|
265a6510 ST |
1 | /* |
2 | * Driver for the Auvitek USB bridge | |
3 | * | |
6d897616 | 4 | * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> |
265a6510 ST |
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" | |
8b2f0795 | 24 | #include "au8522.h" |
f1add5b5 DH |
25 | #include "media/tuner.h" |
26 | #include "media/v4l2-common.h" | |
8b2f0795 | 27 | |
a094ca46 | 28 | static void hvr950q_cs5340_audio(void *priv, int enable) |
8b2f0795 DH |
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 | } | |
265a6510 | 38 | |
5d1f00a2 MCC |
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 | */ | |
265a6510 ST |
44 | struct au0828_board au0828_boards[] = { |
45 | [AU0828_BOARD_UNKNOWN] = { | |
46 | .name = "Unknown board", | |
9bc1022f | 47 | .tuner_type = -1U, |
f1add5b5 | 48 | .tuner_addr = ADDR_UNSET, |
265a6510 ST |
49 | }, |
50 | [AU0828_BOARD_HAUPPAUGE_HVR850] = { | |
51 | .name = "Hauppauge HVR850", | |
f1add5b5 DH |
52 | .tuner_type = TUNER_XC5000, |
53 | .tuner_addr = 0x61, | |
d84fdc77 | 54 | .has_ir_i2c = 1, |
b13b47e0 | 55 | .has_analog = 1, |
cfd0c77d | 56 | .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, |
7fdd7c72 DH |
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 | }, | |
265a6510 ST |
76 | }, |
77 | [AU0828_BOARD_HAUPPAUGE_HVR950Q] = { | |
78 | .name = "Hauppauge HVR950Q", | |
f1add5b5 DH |
79 | .tuner_type = TUNER_XC5000, |
80 | .tuner_addr = 0x61, | |
2fcfd317 | 81 | .has_ir_i2c = 1, |
b13b47e0 | 82 | .has_analog = 1, |
cfd0c77d | 83 | .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, |
8b2f0795 DH |
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 | }, | |
265a6510 | 103 | }, |
59d27521 MK |
104 | [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = { |
105 | .name = "Hauppauge HVR950Q rev xxF8", | |
5d400186 MCC |
106 | .tuner_type = TUNER_XC5000, |
107 | .tuner_addr = 0x61, | |
16af6f5a | 108 | .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, |
59d27521 | 109 | }, |
265a6510 ST |
110 | [AU0828_BOARD_DVICO_FUSIONHDTV7] = { |
111 | .name = "DViCO FusionHDTV USB", | |
5d400186 MCC |
112 | .tuner_type = TUNER_XC5000, |
113 | .tuner_addr = 0x61, | |
cfd0c77d | 114 | .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, |
265a6510 | 115 | }, |
8e8bd229 MK |
116 | [AU0828_BOARD_HAUPPAUGE_WOODBURY] = { |
117 | .name = "Hauppauge Woodbury", | |
5d400186 MCC |
118 | .tuner_type = TUNER_NXP_TDA18271, |
119 | .tuner_addr = 0x60, | |
16af6f5a | 120 | .i2c_clk_divider = AU0828_I2C_CLK_250KHZ, |
8e8bd229 | 121 | }, |
265a6510 | 122 | }; |
265a6510 ST |
123 | |
124 | /* Tuner callback function for au0828 boards. Currently only needed | |
125 | * for HVR1500Q, which has an xc5000 tuner. | |
126 | */ | |
d7cba043 | 127 | int au0828_tuner_callback(void *priv, int component, int command, int arg) |
265a6510 ST |
128 | { |
129 | struct au0828_dev *dev = priv; | |
130 | ||
f07e8e4b | 131 | dprintk(1, "%s()\n", __func__); |
bc3c613c | 132 | |
f1add5b5 | 133 | switch (dev->boardnr) { |
265a6510 ST |
134 | case AU0828_BOARD_HAUPPAUGE_HVR850: |
135 | case AU0828_BOARD_HAUPPAUGE_HVR950Q: | |
59d27521 | 136 | case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: |
265a6510 | 137 | case AU0828_BOARD_DVICO_FUSIONHDTV7: |
a9c36aad | 138 | if (command == 0) { |
265a6510 ST |
139 | /* Tuner Reset Command from xc5000 */ |
140 | /* Drive the tuner into reset and out */ | |
141 | au0828_clear(dev, REG_001, 2); | |
b25ed9c5 | 142 | mdelay(10); |
265a6510 | 143 | au0828_set(dev, REG_001, 2); |
b25ed9c5 | 144 | mdelay(10); |
265a6510 | 145 | return 0; |
18d73c58 | 146 | } else { |
83afb32a | 147 | pr_err("%s(): Unknown command.\n", __func__); |
265a6510 ST |
148 | return -EINVAL; |
149 | } | |
150 | break; | |
151 | } | |
152 | ||
153 | return 0; /* Should never be here */ | |
154 | } | |
155 | ||
28930fa9 ST |
156 | static 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); | |
f1add5b5 | 161 | dev->board.tuner_type = tv.tuner_type; |
28930fa9 ST |
162 | |
163 | /* Make sure we support the board model */ | |
a9c36aad | 164 | switch (tv.model) { |
104fe9a2 | 165 | case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */ |
62899a28 | 166 | case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ |
6b536a6c MK |
167 | case 72101: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */ |
168 | case 72201: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */ | |
62899a28 DH |
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 */ | |
c70ffd59 MK |
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 */ | |
62899a28 | 177 | case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */ |
104fe9a2 | 178 | case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */ |
28930fa9 ST |
179 | break; |
180 | default: | |
83afb32a MCC |
181 | pr_warn("%s: warning: unknown hauppauge model #%d\n", |
182 | __func__, tv.model); | |
28930fa9 ST |
183 | break; |
184 | } | |
185 | ||
83afb32a | 186 | pr_info("%s: hauppauge eeprom: model=%d\n", |
f07e8e4b | 187 | __func__, tv.model); |
28930fa9 ST |
188 | } |
189 | ||
5b7d8de7 MK |
190 | void au0828_card_analog_fe_setup(struct au0828_dev *dev); |
191 | ||
28930fa9 ST |
192 | void au0828_card_setup(struct au0828_dev *dev) |
193 | { | |
28930fa9 ST |
194 | static u8 eeprom[256]; |
195 | ||
f07e8e4b | 196 | dprintk(1, "%s()\n", __func__); |
bc3c613c | 197 | |
28930fa9 ST |
198 | if (dev->i2c_rc == 0) { |
199 | dev->i2c_client.addr = 0xa0 >> 1; | |
200 | tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom)); | |
201 | } | |
202 | ||
f1add5b5 | 203 | switch (dev->boardnr) { |
28930fa9 ST |
204 | case AU0828_BOARD_HAUPPAUGE_HVR850: |
205 | case AU0828_BOARD_HAUPPAUGE_HVR950Q: | |
59d27521 | 206 | case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: |
8e8bd229 | 207 | case AU0828_BOARD_HAUPPAUGE_WOODBURY: |
28930fa9 ST |
208 | if (dev->i2c_rc == 0) |
209 | hauppauge_eeprom(dev, eeprom+0xa0); | |
210 | break; | |
211 | } | |
f1add5b5 | 212 | |
5b7d8de7 MK |
213 | au0828_card_analog_fe_setup(dev); |
214 | } | |
215 | ||
216 | void au0828_card_analog_fe_setup(struct au0828_dev *dev) | |
217 | { | |
8a4e7866 | 218 | #ifdef CONFIG_VIDEO_AU0828_V4L2 |
5b7d8de7 MK |
219 | struct tuner_setup tun_setup; |
220 | struct v4l2_subdev *sd; | |
221 | unsigned int mode_mask = T_ANALOG_TV; | |
222 | ||
220be77c | 223 | if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) { |
f1add5b5 DH |
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) */ | |
e6574f2f | 227 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
9a1f8b34 | 228 | "au8522", 0x8e >> 1, NULL); |
62899a28 | 229 | if (sd == NULL) |
83afb32a | 230 | pr_err("analog subdev registration failed\n"); |
f1add5b5 DH |
231 | } |
232 | ||
233 | /* Setup tuners */ | |
b13b47e0 | 234 | if (dev->board.tuner_type != TUNER_ABSENT && dev->board.has_analog) { |
f1add5b5 | 235 | /* Load the tuner module, which does the attach */ |
e6574f2f | 236 | sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, |
9a1f8b34 | 237 | "tuner", dev->board.tuner_addr, NULL); |
62899a28 | 238 | if (sd == NULL) |
83afb32a | 239 | pr_err("tuner subdev registration fail\n"); |
f1add5b5 DH |
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; | |
2689d3dc DH |
245 | v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, |
246 | &tun_setup); | |
f1add5b5 | 247 | } |
8a4e7866 | 248 | #endif |
28930fa9 ST |
249 | } |
250 | ||
265a6510 ST |
251 | /* |
252 | * The bridge has between 8 and 12 gpios. | |
253 | * Regs 1 and 0 deal with output enables. | |
a9c36aad | 254 | * Regs 3 and 2 deal with direction. |
265a6510 ST |
255 | */ |
256 | void au0828_gpio_setup(struct au0828_dev *dev) | |
257 | { | |
f07e8e4b | 258 | dprintk(1, "%s()\n", __func__); |
bc3c613c | 259 | |
f1add5b5 | 260 | switch (dev->boardnr) { |
265a6510 ST |
261 | case AU0828_BOARD_HAUPPAUGE_HVR850: |
262 | case AU0828_BOARD_HAUPPAUGE_HVR950Q: | |
59d27521 | 263 | case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: |
8e8bd229 | 264 | case AU0828_BOARD_HAUPPAUGE_WOODBURY: |
265a6510 ST |
265 | /* GPIO's |
266 | * 4 - CS5340 | |
267 | * 5 - AU8522 Demodulator | |
268 | * 6 - eeprom W/P | |
8b2f0795 | 269 | * 7 - power supply |
265a6510 ST |
270 | * 9 - XC5000 Tuner |
271 | */ | |
272 | ||
a06b429d DH |
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) */ | |
265a6510 | 276 | au0828_write(dev, REG_003, 0x02); |
8b2f0795 | 277 | au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10); |
a06b429d DH |
278 | |
279 | /* Into reset */ | |
265a6510 ST |
280 | au0828_write(dev, REG_001, 0x0); |
281 | au0828_write(dev, REG_000, 0x0); | |
a06b429d | 282 | msleep(50); |
265a6510 | 283 | |
a06b429d DH |
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 */ | |
8b2f0795 | 292 | |
265a6510 ST |
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 */ | |
a8eb912c | 320 | struct usb_device_id au0828_usb_id_table[] = { |
265a6510 ST |
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 }, | |
104fe9a2 MK |
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 }, | |
a636da6b MK |
333 | { USB_DEVICE(0x2040, 0x721e), |
334 | .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, | |
104fe9a2 MK |
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 }, | |
59d27521 MK |
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 }, | |
e2b710bf IL |
347 | { USB_DEVICE(0x05e1, 0x0480), |
348 | .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, | |
8e8bd229 MK |
349 | { USB_DEVICE(0x2040, 0x8200), |
350 | .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, | |
23bbba34 MK |
351 | { USB_DEVICE(0x2040, 0x7260), |
352 | .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, | |
64a6b6cb MK |
353 | { USB_DEVICE(0x2040, 0x7213), |
354 | .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, | |
ffc80988 MK |
355 | { USB_DEVICE(0x2040, 0x7270), |
356 | .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, | |
265a6510 ST |
357 | { }, |
358 | }; | |
359 | ||
360 | MODULE_DEVICE_TABLE(usb, au0828_usb_id_table); |