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 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 218 void 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 */ 258 void 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 */ 322 struct 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 362 MODULE_DEVICE_TABLE(usb, au0828_usb_id_table); 363