Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Driver for the Auvitek USB bridge
0004  *
0005  *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
0006  */
0007 
0008 #include "au0828.h"
0009 #include "au0828-cards.h"
0010 #include "au8522.h"
0011 #include "media/tuner.h"
0012 #include "media/v4l2-common.h"
0013 
0014 static void hvr950q_cs5340_audio(void *priv, int enable)
0015 {
0016     /* Because the HVR-950q shares an i2s bus between the cs5340 and the
0017        au8522, we need to hold cs5340 in reset when using the au8522 */
0018     struct au0828_dev *dev = priv;
0019     if (enable == 1)
0020         au0828_set(dev, REG_000, 0x10);
0021     else
0022         au0828_clear(dev, REG_000, 0x10);
0023 }
0024 
0025 /*
0026  * WARNING: There's a quirks table at sound/usb/quirks-table.h
0027  * that should also be updated every time a new device with V4L2 support
0028  * is added here.
0029  */
0030 struct au0828_board au0828_boards[] = {
0031     [AU0828_BOARD_UNKNOWN] = {
0032         .name   = "Unknown board",
0033         .tuner_type = -1U,
0034         .tuner_addr = ADDR_UNSET,
0035     },
0036     [AU0828_BOARD_HAUPPAUGE_HVR850] = {
0037         .name   = "Hauppauge HVR850",
0038         .tuner_type = TUNER_XC5000,
0039         .tuner_addr = 0x61,
0040         .has_ir_i2c = 1,
0041         .has_analog = 1,
0042         .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
0043         .input = {
0044             {
0045                 .type = AU0828_VMUX_TELEVISION,
0046                 .vmux = AU8522_COMPOSITE_CH4_SIF,
0047                 .amux = AU8522_AUDIO_SIF,
0048             },
0049             {
0050                 .type = AU0828_VMUX_COMPOSITE,
0051                 .vmux = AU8522_COMPOSITE_CH1,
0052                 .amux = AU8522_AUDIO_NONE,
0053                 .audio_setup = hvr950q_cs5340_audio,
0054             },
0055             {
0056                 .type = AU0828_VMUX_SVIDEO,
0057                 .vmux = AU8522_SVIDEO_CH13,
0058                 .amux = AU8522_AUDIO_NONE,
0059                 .audio_setup = hvr950q_cs5340_audio,
0060             },
0061         },
0062     },
0063     [AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
0064         .name   = "Hauppauge HVR950Q",
0065         .tuner_type = TUNER_XC5000,
0066         .tuner_addr = 0x61,
0067         .has_ir_i2c = 1,
0068         .has_analog = 1,
0069         .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
0070         .input = {
0071             {
0072                 .type = AU0828_VMUX_TELEVISION,
0073                 .vmux = AU8522_COMPOSITE_CH4_SIF,
0074                 .amux = AU8522_AUDIO_SIF,
0075             },
0076             {
0077                 .type = AU0828_VMUX_COMPOSITE,
0078                 .vmux = AU8522_COMPOSITE_CH1,
0079                 .amux = AU8522_AUDIO_NONE,
0080                 .audio_setup = hvr950q_cs5340_audio,
0081             },
0082             {
0083                 .type = AU0828_VMUX_SVIDEO,
0084                 .vmux = AU8522_SVIDEO_CH13,
0085                 .amux = AU8522_AUDIO_NONE,
0086                 .audio_setup = hvr950q_cs5340_audio,
0087             },
0088         },
0089     },
0090     [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = {
0091         .name   = "Hauppauge HVR950Q rev xxF8",
0092         .tuner_type = TUNER_XC5000,
0093         .tuner_addr = 0x61,
0094         .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
0095     },
0096     [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
0097         .name   = "DViCO FusionHDTV USB",
0098         .tuner_type = TUNER_XC5000,
0099         .tuner_addr = 0x61,
0100         .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
0101     },
0102     [AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
0103         .name = "Hauppauge Woodbury",
0104         .tuner_type = TUNER_NXP_TDA18271,
0105         .tuner_addr = 0x60,
0106         .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
0107     },
0108 };
0109 
0110 /* Tuner callback function for au0828 boards. Currently only needed
0111  * for HVR1500Q, which has an xc5000 tuner.
0112  */
0113 int au0828_tuner_callback(void *priv, int component, int command, int arg)
0114 {
0115     struct au0828_dev *dev = priv;
0116 
0117     dprintk(1, "%s()\n", __func__);
0118 
0119     switch (dev->boardnr) {
0120     case AU0828_BOARD_HAUPPAUGE_HVR850:
0121     case AU0828_BOARD_HAUPPAUGE_HVR950Q:
0122     case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
0123     case AU0828_BOARD_DVICO_FUSIONHDTV7:
0124         if (command == 0) {
0125             /* Tuner Reset Command from xc5000 */
0126             /* Drive the tuner into reset and out */
0127             au0828_clear(dev, REG_001, 2);
0128             mdelay(10);
0129             au0828_set(dev, REG_001, 2);
0130             mdelay(10);
0131             return 0;
0132         } else {
0133             pr_err("%s(): Unknown command.\n", __func__);
0134             return -EINVAL;
0135         }
0136         break;
0137     }
0138 
0139     return 0; /* Should never be here */
0140 }
0141 
0142 static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
0143 {
0144     struct tveeprom tv;
0145 
0146     tveeprom_hauppauge_analog(&tv, eeprom_data);
0147     dev->board.tuner_type = tv.tuner_type;
0148 
0149     /* Make sure we support the board model */
0150     switch (tv.model) {
0151     case 72000: /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
0152     case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
0153     case 72101: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
0154     case 72201: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
0155     case 72211: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
0156     case 72221: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
0157     case 72231: /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
0158     case 72241: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
0159     case 72251: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
0160     case 72261: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
0161     case 72271: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
0162     case 72281: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
0163     case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
0164     case 72500: /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
0165         break;
0166     default:
0167         pr_warn("%s: warning: unknown hauppauge model #%d\n",
0168             __func__, tv.model);
0169         break;
0170     }
0171 
0172     pr_info("%s: hauppauge eeprom: model=%d\n",
0173            __func__, tv.model);
0174 }
0175 
0176 void au0828_card_analog_fe_setup(struct au0828_dev *dev);
0177 
0178 void au0828_card_setup(struct au0828_dev *dev)
0179 {
0180     static u8 eeprom[256];
0181 
0182     dprintk(1, "%s()\n", __func__);
0183 
0184     if (dev->i2c_rc == 0) {
0185         dev->i2c_client.addr = 0xa0 >> 1;
0186         tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
0187     }
0188 
0189     switch (dev->boardnr) {
0190     case AU0828_BOARD_HAUPPAUGE_HVR850:
0191     case AU0828_BOARD_HAUPPAUGE_HVR950Q:
0192     case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
0193     case AU0828_BOARD_HAUPPAUGE_WOODBURY:
0194         if (dev->i2c_rc == 0)
0195             hauppauge_eeprom(dev, eeprom+0xa0);
0196         break;
0197     }
0198 
0199     au0828_card_analog_fe_setup(dev);
0200 }
0201 
0202 void au0828_card_analog_fe_setup(struct au0828_dev *dev)
0203 {
0204 #ifdef CONFIG_VIDEO_AU0828_V4L2
0205     struct tuner_setup tun_setup;
0206     struct v4l2_subdev *sd;
0207     unsigned int mode_mask = T_ANALOG_TV;
0208 
0209     if (AUVI_INPUT(0).type != AU0828_VMUX_UNDEFINED) {
0210         /* Load the analog demodulator driver (note this would need to
0211            be abstracted out if we ever need to support a different
0212            demod) */
0213         sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
0214                 "au8522", 0x8e >> 1, NULL);
0215         if (sd == NULL)
0216             pr_err("analog subdev registration failed\n");
0217     }
0218 
0219     /* Setup tuners */
0220     if (dev->board.tuner_type != TUNER_ABSENT && dev->board.has_analog) {
0221         /* Load the tuner module, which does the attach */
0222         sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
0223                 "tuner", dev->board.tuner_addr, NULL);
0224         if (sd == NULL)
0225             pr_err("tuner subdev registration fail\n");
0226 
0227         tun_setup.mode_mask      = mode_mask;
0228         tun_setup.type           = dev->board.tuner_type;
0229         tun_setup.addr           = dev->board.tuner_addr;
0230         tun_setup.tuner_callback = au0828_tuner_callback;
0231         v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr,
0232                      &tun_setup);
0233     }
0234 #endif
0235 }
0236 
0237 /*
0238  * The bridge has between 8 and 12 gpios.
0239  * Regs 1 and 0 deal with output enables.
0240  * Regs 3 and 2 deal with direction.
0241  */
0242 void au0828_gpio_setup(struct au0828_dev *dev)
0243 {
0244     dprintk(1, "%s()\n", __func__);
0245 
0246     switch (dev->boardnr) {
0247     case AU0828_BOARD_HAUPPAUGE_HVR850:
0248     case AU0828_BOARD_HAUPPAUGE_HVR950Q:
0249     case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL:
0250     case AU0828_BOARD_HAUPPAUGE_WOODBURY:
0251         /* GPIO's
0252          * 4 - CS5340
0253          * 5 - AU8522 Demodulator
0254          * 6 - eeprom W/P
0255          * 7 - power supply
0256          * 9 - XC5000 Tuner
0257          */
0258 
0259         /* Set relevant GPIOs as outputs (leave the EEPROM W/P
0260            as an input since we will never touch it and it has
0261            a pullup) */
0262         au0828_write(dev, REG_003, 0x02);
0263         au0828_write(dev, REG_002, 0x80 | 0x20 | 0x10);
0264 
0265         /* Into reset */
0266         au0828_write(dev, REG_001, 0x0);
0267         au0828_write(dev, REG_000, 0x0);
0268         msleep(50);
0269 
0270         /* Bring power supply out of reset */
0271         au0828_write(dev, REG_000, 0x80);
0272         msleep(50);
0273 
0274         /* Bring xc5000 and au8522 out of reset (leave the
0275            cs5340 in reset until needed) */
0276         au0828_write(dev, REG_001, 0x02); /* xc5000 */
0277         au0828_write(dev, REG_000, 0x80 | 0x20); /* PS + au8522 */
0278 
0279         msleep(250);
0280         break;
0281     case AU0828_BOARD_DVICO_FUSIONHDTV7:
0282         /* GPIO's
0283          * 6 - ?
0284          * 8 - AU8522 Demodulator
0285          * 9 - XC5000 Tuner
0286          */
0287 
0288         /* Into reset */
0289         au0828_write(dev, REG_003, 0x02);
0290         au0828_write(dev, REG_002, 0xa0);
0291         au0828_write(dev, REG_001, 0x0);
0292         au0828_write(dev, REG_000, 0x0);
0293         msleep(100);
0294 
0295         /* Out of reset */
0296         au0828_write(dev, REG_003, 0x02);
0297         au0828_write(dev, REG_002, 0xa0);
0298         au0828_write(dev, REG_001, 0x02);
0299         au0828_write(dev, REG_000, 0xa0);
0300         msleep(250);
0301         break;
0302     }
0303 }
0304 
0305 /* table of devices that work with this driver */
0306 struct usb_device_id au0828_usb_id_table[] = {
0307     { USB_DEVICE(0x2040, 0x7200),
0308         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0309     { USB_DEVICE(0x2040, 0x7240),
0310         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
0311     { USB_DEVICE(0x0fe9, 0xd620),
0312         .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
0313     { USB_DEVICE(0x2040, 0x7210),
0314         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0315     { USB_DEVICE(0x2040, 0x7217),
0316         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0317     { USB_DEVICE(0x2040, 0x721b),
0318         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0319     { USB_DEVICE(0x2040, 0x721e),
0320         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0321     { USB_DEVICE(0x2040, 0x721f),
0322         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0323     { USB_DEVICE(0x2040, 0x7280),
0324         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0325     { USB_DEVICE(0x0fd9, 0x0008),
0326         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0327     { USB_DEVICE(0x2040, 0x7201),
0328         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
0329     { USB_DEVICE(0x2040, 0x7211),
0330         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
0331     { USB_DEVICE(0x2040, 0x7281),
0332         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL },
0333     { USB_DEVICE(0x05e1, 0x0480),
0334         .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
0335     { USB_DEVICE(0x2040, 0x8200),
0336         .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY },
0337     { USB_DEVICE(0x2040, 0x7260),
0338         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0339     { USB_DEVICE(0x2040, 0x7213),
0340         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0341     { USB_DEVICE(0x2040, 0x7270),
0342         .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
0343     { },
0344 };
0345 
0346 MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);