linux/drivers/media/video/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 *  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
  28void 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
  39struct au0828_board au0828_boards[] = {
  40        [AU0828_BOARD_UNKNOWN] = {
  41                .name   = "Unknown board",
  42                .tuner_type = UNSET,
  43                .tuner_addr = ADDR_UNSET,
  44        },
  45        [AU0828_BOARD_HAUPPAUGE_HVR850] = {
  46                .name   = "Hauppauge HVR850",
  47                .tuner_type = TUNER_XC5000,
  48                .tuner_addr = 0x61,
  49                .i2c_clk_divider = AU0828_I2C_CLK_30KHZ,
  50                .input = {
  51                        {
  52                                .type = AU0828_VMUX_TELEVISION,
  53                                .vmux = AU8522_COMPOSITE_CH4_SIF,
  54                                .amux = AU8522_AUDIO_SIF,
  55                        },
  56                        {
  57                                .type = AU0828_VMUX_COMPOSITE,
  58                                .vmux = AU8522_COMPOSITE_CH1,
  59                                .amux = AU8522_AUDIO_NONE,
  60                                .audio_setup = hvr950q_cs5340_audio,
  61                        },
  62                        {
  63                                .type = AU0828_VMUX_SVIDEO,
  64                                .vmux = AU8522_SVIDEO_CH13,
  65                                .amux = AU8522_AUDIO_NONE,
  66                                .audio_setup = hvr950q_cs5340_audio,
  67                        },
  68                },
  69        },
  70        [AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
  71                .name   = "Hauppauge HVR950Q",
  72                .tuner_type = TUNER_XC5000,
  73                .tuner_addr = 0x61,
  74                /* The au0828 hardware i2c implementation does not properly
  75                   support the xc5000's i2c clock stretching.  So we need to
  76                   lower the clock frequency enough where the 15us clock
  77                   stretch fits inside of a normal clock cycle, or else the
  78                   au0828 fails to set the STOP bit.  A 30 KHz clock puts the
  79                   clock pulse width at 18us */
  80                .i2c_clk_divider = AU0828_I2C_CLK_30KHZ,
  81                .input = {
  82                        {
  83                                .type = AU0828_VMUX_TELEVISION,
  84                                .vmux = AU8522_COMPOSITE_CH4_SIF,
  85                                .amux = AU8522_AUDIO_SIF,
  86                        },
  87                        {
  88                                .type = AU0828_VMUX_COMPOSITE,
  89                                .vmux = AU8522_COMPOSITE_CH1,
  90                                .amux = AU8522_AUDIO_NONE,
  91                                .audio_setup = hvr950q_cs5340_audio,
  92                        },
  93                        {
  94                                .type = AU0828_VMUX_SVIDEO,
  95                                .vmux = AU8522_SVIDEO_CH13,
  96                                .amux = AU8522_AUDIO_NONE,
  97                                .audio_setup = hvr950q_cs5340_audio,
  98                        },
  99                },
 100        },
 101        [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
 102                .name   = "Hauppauge HVR950Q rev xxF8",
 103                .tuner_type = UNSET,
 104                .tuner_addr = ADDR_UNSET,
 105                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
 106        },
 107        [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
 108                .name   = "DViCO FusionHDTV USB",
 109                .tuner_type = UNSET,
 110                .tuner_addr = ADDR_UNSET,
 111                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
 112        },
 113        [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
 114                .name = "Hauppauge Woodbury",
 115                .tuner_type = UNSET,
 116                .tuner_addr = ADDR_UNSET,
 117                .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
 118        },
 119};
 120
 121/* Tuner callback function for au0828 boards. Currently only needed
 122 * for HVR1500Q, which has an xc5000 tuner.
 123 */
 124int au0828_tuner_callback(void *priv, int component, int command, int arg)
 125{
 126        struct au0828_dev *dev = priv;
 127
 128        dprintk(1, "%s()\n", __func__);
 129
 130        switch (dev->boardnr) {
 131        case AU0828_BOARD_HAUPPAUGE_HVR850:
 132        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
 133        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
 134        case AU0828_BOARD_DVICO_FUSIONHDTV7:
 135                if (command == 0) {
 136                        /* Tuner Reset Command from xc5000 */
 137                        /* Drive the tuner into reset and out */
 138                        au0828_clear(dev, REG_001, 2);
 139                        mdelay(10);
 140                        au0828_set(dev, REG_001, 2);
 141                        mdelay(10);
 142                        return 0;
 143                } else {
 144                        printk(KERN_ERR
 145                                "%s(): Unknown command.\n", __func__);
 146                        return -EINVAL;
 147                }
 148                break;
 149        }
 150
 151        return 0; /* Should never be here */
 152}
 153
 154static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
 155{
 156        struct tveeprom tv;
 157
 158        tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
 159        dev->board.tuner_type = tv.tuner_type;
 160
 161        /* Make sure we support the board model */
 162        switch (tv.model) {
 163        case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
 164        case 72001: /* WinTV-HVR950q (Retail, 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 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
 171        case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
 172                break;
 173        default:
 174                printk(KERN_WARNING "%s: warning: "
 175                       "unknown hauppauge model #%d\n", __func__, tv.model);
 176                break;
 177        }
 178
 179        printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
 180               __func__, tv.model);
 181}
 182
 183void au0828_card_setup(struct au0828_dev *dev)
 184{
 185        static u8 eeprom[256];
 186        struct tuner_setup tun_setup;
 187        struct v4l2_subdev *sd;
 188        unsigned int mode_mask = T_ANALOG_TV |
 189                                 T_DIGITAL_TV;
 190
 191        dprintk(1, "%s()\n", __func__);
 192
 193        memcpy(&dev->board, &au0828_boards[dev->boardnr], sizeof(dev->board));
 194
 195        if (dev->i2c_rc == 0) {
 196                dev->i2c_client.addr = 0xa0 >> 1;
 197                tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
 198        }
 199
 200        switch (dev->boardnr) {
 201        case AU0828_BOARD_HAUPPAUGE_HVR850:
 202        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
 203        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
 204        case AU0828_BOARD_HAUPPAUGE_WOODBURY:
 205                if (dev->i2c_rc == 0)
 206                        hauppauge_eeprom(dev, eeprom+0xa0);
 207                break;
 208        }
 209
 210        if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
 211                /* Load the analog demodulator driver (note this would need to
 212                   be abstracted out if we ever need to support a different
 213                   demod) */
 214                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
 215                                "au8522", "au8522", 0x8e >> 1, NULL);
 216                if (sd == NULL)
 217                        printk(KERN_ERR "analog subdev registration failed\n");
 218        }
 219
 220        /* Setup tuners */
 221        if (dev->board.tuner_type != TUNER_ABSENT) {
 222                /* Load the tuner module, which does the attach */
 223                sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
 224                                "tuner", "tuner", dev->board.tuner_addr, NULL);
 225                if (sd == NULL)
 226                        printk(KERN_ERR "tuner subdev registration fail\n");
 227
 228                tun_setup.mode_mask      = mode_mask;
 229                tun_setup.type           = dev->board.tuner_type;
 230                tun_setup.addr           = dev->board.tuner_addr;
 231                tun_setup.tuner_callback = au0828_tuner_callback;
 232                v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
 233                                     &tun_setup);
 234        }
 235}
 236
 237/*
 238 * The bridge has between 8 and 12 gpios.
 239 * Regs 1 and 0 deal with output enables.
 240 * Regs 3 and 2 deal with direction.
 241 */
 242void au0828_gpio_setup(struct au0828_dev *dev)
 243{
 244        dprintk(1, "%s()\n", __func__);
 245
 246        switch (dev->boardnr) {
 247        case AU0828_BOARD_HAUPPAUGE_HVR850:
 248        case AU0828_BOARD_HAUPPAUGE_HVR950Q:
 249        case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
 250        case AU0828_BOARD_HAUPPAUGE_WOODBURY:
 251                /* GPIO's
 252                 * 4 - CS5340
 253                 * 5 - AU8522 Demodulator
 254                 * 6 - eeprom W/P
 255                 * 7 - power supply
 256                 * 9 - XC5000 Tuner
 257                 */
 258
 259                /* Into reset */
 260                au0828_write(dev, REG_003, 0x02);
 261                au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
 262                au0828_write(dev, REG_001, 0x0);
 263                au0828_write(dev, REG_000, 0x0);
 264                msleep(100);
 265
 266                /* Out of reset (leave the cs5340 in reset until needed) */
 267                au0828_write(dev, REG_003, 0x02);
 268                au0828_write(dev, REG_001, 0x02);
 269                au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
 270                au0828_write(dev, REG_000, 0x80 | 0x40 | 0x20);
 271
 272                msleep(250);
 273                break;
 274        case AU0828_BOARD_DVICO_FUSIONHDTV7:
 275                /* GPIO's
 276                 * 6 - ?
 277                 * 8 - AU8522 Demodulator
 278                 * 9 - XC5000 Tuner
 279                 */
 280
 281                /* Into reset */
 282                au0828_write(dev, REG_003, 0x02);
 283                au0828_write(dev, REG_002, 0xa0);
 284                au0828_write(dev, REG_001, 0x0);
 285                au0828_write(dev, REG_000, 0x0);
 286                msleep(100);
 287
 288                /* Out of reset */
 289                au0828_write(dev, REG_003, 0x02);
 290                au0828_write(dev, REG_002, 0xa0);
 291                au0828_write(dev, REG_001, 0x02);
 292                au0828_write(dev, REG_000, 0xa0);
 293                msleep(250);
 294                break;
 295        }
 296}
 297
 298/* table of devices that work with this driver */
 299struct usb_device_id au0828_usb_id_table[] = {
 300        { USB_DEVICE(0x2040, 0x7200),
 301                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
 302        { USB_DEVICE(0x2040, 0x7240),
 303                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
 304        { USB_DEVICE(0x0fe9, 0xd620),
 305                .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
 306        { USB_DEVICE(0x2040, 0x7210),
 307                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
 308        { USB_DEVICE(0x2040, 0x7217),
 309                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
 310        { USB_DEVICE(0x2040, 0x721b),
 311                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
 312        { USB_DEVICE(0x2040, 0x721e),
 313                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
 314        { USB_DEVICE(0x2040, 0x721f),
 315                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
 316        { USB_DEVICE(0x2040, 0x7280),
 317                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
 318        { USB_DEVICE(0x0fd9, 0x0008),
 319                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
 320        { USB_DEVICE(0x2040, 0x7201),
 321                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
 322        { USB_DEVICE(0x2040, 0x7211),
 323                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
 324        { USB_DEVICE(0x2040, 0x7281),
 325                .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
 326        { USB_DEVICE(0x2040, 0x8200),
 327                .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
 328        { },
 329};
 330
 331MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
 332