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 28 static 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 */ 44 struct 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 */ 127 int 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 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); 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 190 void au0828_card_analog_fe_setup(struct au0828_dev *dev); 191 192 void 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 216 void 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 */ 256 void 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 */ 320 struct 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 360 MODULE_DEVICE_TABLE(usb, au0828_usb_id_table); 361