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