linux/drivers/media/usb/au0828/au0828-cards.c
<<
>>
Prefs
   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
  24static 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 */
  40struct 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 */
 123int 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
 152static 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
 186void au0828_card_analog_fe_setup(struct au0828_dev *dev);
 187
 188void 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
 212void 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 */
 252void 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 */
 316struct 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
 356MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
 357