Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Intel CE6230 DVB USB driver
0004  *
0005  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
0006  */
0007 
0008 #include "ce6230.h"
0009 
0010 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
0011 
0012 static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
0013 {
0014     int ret;
0015     unsigned int pipe;
0016     u8 request;
0017     u8 requesttype;
0018     u16 value;
0019     u16 index;
0020     u8 *buf;
0021 
0022     request = req->cmd;
0023     value = req->value;
0024     index = req->index;
0025 
0026     switch (req->cmd) {
0027     case I2C_READ:
0028     case DEMOD_READ:
0029     case REG_READ:
0030         requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
0031         break;
0032     case I2C_WRITE:
0033     case DEMOD_WRITE:
0034     case REG_WRITE:
0035         requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
0036         break;
0037     default:
0038         dev_err(&d->udev->dev, "%s: unknown command=%02x\n",
0039                 KBUILD_MODNAME, req->cmd);
0040         ret = -EINVAL;
0041         goto error;
0042     }
0043 
0044     buf = kmalloc(req->data_len, GFP_KERNEL);
0045     if (!buf) {
0046         ret = -ENOMEM;
0047         goto error;
0048     }
0049 
0050     if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
0051         /* write */
0052         memcpy(buf, req->data, req->data_len);
0053         pipe = usb_sndctrlpipe(d->udev, 0);
0054     } else {
0055         /* read */
0056         pipe = usb_rcvctrlpipe(d->udev, 0);
0057     }
0058 
0059     msleep(1); /* avoid I2C errors */
0060 
0061     ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index,
0062             buf, req->data_len, CE6230_USB_TIMEOUT);
0063 
0064     dvb_usb_dbg_usb_control_msg(d->udev, request, requesttype, value, index,
0065             buf, req->data_len);
0066 
0067     if (ret < 0)
0068         dev_err(&d->udev->dev, "%s: usb_control_msg() failed=%d\n",
0069                 KBUILD_MODNAME, ret);
0070     else
0071         ret = 0;
0072 
0073     /* read request, copy returned data to return buf */
0074     if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
0075         memcpy(req->data, buf, req->data_len);
0076 
0077     kfree(buf);
0078 error:
0079     return ret;
0080 }
0081 
0082 /* I2C */
0083 static struct zl10353_config ce6230_zl10353_config;
0084 
0085 static int ce6230_i2c_master_xfer(struct i2c_adapter *adap,
0086         struct i2c_msg msg[], int num)
0087 {
0088     struct dvb_usb_device *d = i2c_get_adapdata(adap);
0089     int ret = 0, i = 0;
0090     struct usb_req req;
0091 
0092     if (num > 2)
0093         return -EOPNOTSUPP;
0094 
0095     memset(&req, 0, sizeof(req));
0096 
0097     if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
0098         return -EAGAIN;
0099 
0100     while (i < num) {
0101         if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
0102             if (msg[i].addr ==
0103                 ce6230_zl10353_config.demod_address) {
0104                 req.cmd = DEMOD_READ;
0105                 req.value = msg[i].addr >> 1;
0106                 req.index = msg[i].buf[0];
0107                 req.data_len = msg[i+1].len;
0108                 req.data = &msg[i+1].buf[0];
0109                 ret = ce6230_ctrl_msg(d, &req);
0110             } else {
0111                 dev_err(&d->udev->dev, "%s: I2C read not " \
0112                         "implemented\n",
0113                         KBUILD_MODNAME);
0114                 ret = -EOPNOTSUPP;
0115             }
0116             i += 2;
0117         } else {
0118             if (msg[i].addr ==
0119                 ce6230_zl10353_config.demod_address) {
0120                 req.cmd = DEMOD_WRITE;
0121                 req.value = msg[i].addr >> 1;
0122                 req.index = msg[i].buf[0];
0123                 req.data_len = msg[i].len-1;
0124                 req.data = &msg[i].buf[1];
0125                 ret = ce6230_ctrl_msg(d, &req);
0126             } else {
0127                 req.cmd = I2C_WRITE;
0128                 req.value = 0x2000 + (msg[i].addr >> 1);
0129                 req.index = 0x0000;
0130                 req.data_len = msg[i].len;
0131                 req.data = &msg[i].buf[0];
0132                 ret = ce6230_ctrl_msg(d, &req);
0133             }
0134             i += 1;
0135         }
0136         if (ret)
0137             break;
0138     }
0139 
0140     mutex_unlock(&d->i2c_mutex);
0141     return ret ? ret : i;
0142 }
0143 
0144 static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter)
0145 {
0146     return I2C_FUNC_I2C;
0147 }
0148 
0149 static struct i2c_algorithm ce6230_i2c_algorithm = {
0150     .master_xfer   = ce6230_i2c_master_xfer,
0151     .functionality = ce6230_i2c_functionality,
0152 };
0153 
0154 /* Callbacks for DVB USB */
0155 static struct zl10353_config ce6230_zl10353_config = {
0156     .demod_address = 0x1e,
0157     .adc_clock = 450000,
0158     .if2 = 45700,
0159     .no_tuner = 1,
0160     .parallel_ts = 1,
0161     .clock_ctl_1 = 0x34,
0162     .pll_0 = 0x0e,
0163 };
0164 
0165 static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
0166 {
0167     struct dvb_usb_device *d = adap_to_d(adap);
0168 
0169     dev_dbg(&d->udev->dev, "%s:\n", __func__);
0170 
0171     adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
0172             &d->i2c_adap);
0173     if (adap->fe[0] == NULL)
0174         return -ENODEV;
0175 
0176     return 0;
0177 }
0178 
0179 static struct mxl5005s_config ce6230_mxl5003s_config = {
0180     .i2c_address     = 0xc6,
0181     .if_freq         = IF_FREQ_4570000HZ,
0182     .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
0183     .agc_mode        = MXL_SINGLE_AGC,
0184     .tracking_filter = MXL_TF_DEFAULT,
0185     .rssi_enable     = MXL_RSSI_ENABLE,
0186     .cap_select      = MXL_CAP_SEL_ENABLE,
0187     .div_out         = MXL_DIV_OUT_4,
0188     .clock_out       = MXL_CLOCK_OUT_DISABLE,
0189     .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
0190     .top         = MXL5005S_TOP_25P2,
0191     .mod_mode        = MXL_DIGITAL_MODE,
0192     .if_mode         = MXL_ZERO_IF,
0193     .AgcMasterByte   = 0x00,
0194 };
0195 
0196 static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
0197 {
0198     struct dvb_usb_device *d = adap_to_d(adap);
0199     int ret;
0200 
0201     dev_dbg(&d->udev->dev, "%s:\n", __func__);
0202 
0203     ret = dvb_attach(mxl5005s_attach, adap->fe[0], &d->i2c_adap,
0204             &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
0205     return ret;
0206 }
0207 
0208 static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
0209 {
0210     int ret;
0211 
0212     dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
0213 
0214     /* InterfaceNumber 1 / AlternateSetting 0     idle
0215        InterfaceNumber 1 / AlternateSetting 1     streaming */
0216     ret = usb_set_interface(d->udev, 1, onoff);
0217     if (ret)
0218         dev_err(&d->udev->dev, "%s: usb_set_interface() failed=%d\n",
0219                 KBUILD_MODNAME, ret);
0220 
0221     return ret;
0222 }
0223 
0224 /* DVB USB Driver stuff */
0225 static struct dvb_usb_device_properties ce6230_props = {
0226     .driver_name = KBUILD_MODNAME,
0227     .owner = THIS_MODULE,
0228     .adapter_nr = adapter_nr,
0229     .bInterfaceNumber = 1,
0230 
0231     .i2c_algo = &ce6230_i2c_algorithm,
0232     .power_ctrl = ce6230_power_ctrl,
0233     .frontend_attach = ce6230_zl10353_frontend_attach,
0234     .tuner_attach = ce6230_mxl5003s_tuner_attach,
0235 
0236     .num_adapters = 1,
0237     .adapter = {
0238         {
0239             .stream = {
0240                 .type = USB_BULK,
0241                 .count = 6,
0242                 .endpoint = 0x82,
0243                 .u = {
0244                     .bulk = {
0245                         .buffersize = (16 * 512),
0246                     }
0247                 }
0248             },
0249         }
0250     },
0251 };
0252 
0253 static const struct usb_device_id ce6230_id_table[] = {
0254     { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500,
0255         &ce6230_props, "Intel CE9500 reference design", NULL) },
0256     { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310,
0257         &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) },
0258     { }
0259 };
0260 MODULE_DEVICE_TABLE(usb, ce6230_id_table);
0261 
0262 static struct usb_driver ce6230_usb_driver = {
0263     .name = KBUILD_MODNAME,
0264     .id_table = ce6230_id_table,
0265     .probe = dvb_usbv2_probe,
0266     .disconnect = dvb_usbv2_disconnect,
0267     .suspend = dvb_usbv2_suspend,
0268     .resume = dvb_usbv2_resume,
0269     .reset_resume = dvb_usbv2_reset_resume,
0270     .no_dynamic_id = 1,
0271     .soft_unbind = 1,
0272 };
0273 
0274 module_usb_driver(ce6230_usb_driver);
0275 
0276 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
0277 MODULE_DESCRIPTION("Intel CE6230 driver");
0278 MODULE_LICENSE("GPL");