linux/drivers/media/dvb/dvb-usb/ce6230.c
<<
>>
Prefs
   1/*
   2 * DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver
   3 *
   4 * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
   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 *    GNU General Public License for more details.
  15 *
  16 *    You should have received a copy of the GNU General Public License
  17 *    along with this program; if not, write to the Free Software
  18 *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19 *
  20 */
  21
  22#include "ce6230.h"
  23#include "zl10353.h"
  24#include "mxl5005s.h"
  25
  26/* debug */
  27static int dvb_usb_ce6230_debug;
  28module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);
  29MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
  30DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
  31
  32static struct zl10353_config ce6230_zl10353_config;
  33
  34static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)
  35{
  36        int ret;
  37        unsigned int pipe;
  38        u8 request;
  39        u8 requesttype;
  40        u16 value;
  41        u16 index;
  42        u8 buf[req->data_len];
  43
  44        request = req->cmd;
  45        value = req->value;
  46        index = req->index;
  47
  48        switch (req->cmd) {
  49        case I2C_READ:
  50        case DEMOD_READ:
  51        case REG_READ:
  52                requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
  53                break;
  54        case I2C_WRITE:
  55        case DEMOD_WRITE:
  56        case REG_WRITE:
  57                requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
  58                break;
  59        default:
  60                err("unknown command:%02x", req->cmd);
  61                ret = -EPERM;
  62                goto error;
  63        }
  64
  65        if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
  66                /* write */
  67                memcpy(buf, req->data, req->data_len);
  68                pipe = usb_sndctrlpipe(udev, 0);
  69        } else {
  70                /* read */
  71                pipe = usb_rcvctrlpipe(udev, 0);
  72        }
  73
  74        msleep(1); /* avoid I2C errors */
  75
  76        ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
  77                                buf, sizeof(buf), CE6230_USB_TIMEOUT);
  78
  79        ce6230_debug_dump(request, requesttype, value, index, buf,
  80                req->data_len, deb_xfer);
  81
  82        if (ret < 0)
  83                deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
  84        else
  85                ret = 0;
  86
  87        /* read request, copy returned data to return buf */
  88        if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
  89                memcpy(req->data, buf, req->data_len);
  90
  91error:
  92        return ret;
  93}
  94
  95static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
  96{
  97        return ce6230_rw_udev(d->udev, req);
  98}
  99
 100/* I2C */
 101static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 102                           int num)
 103{
 104        struct dvb_usb_device *d = i2c_get_adapdata(adap);
 105        int i = 0;
 106        struct req_t req;
 107        int ret = 0;
 108        memset(&req, 0, sizeof(req));
 109
 110        if (num > 2)
 111                return -EINVAL;
 112
 113        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
 114                return -EAGAIN;
 115
 116        while (i < num) {
 117                if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
 118                        if (msg[i].addr ==
 119                                ce6230_zl10353_config.demod_address) {
 120                                req.cmd = DEMOD_READ;
 121                                req.value = msg[i].addr >> 1;
 122                                req.index = msg[i].buf[0];
 123                                req.data_len = msg[i+1].len;
 124                                req.data = &msg[i+1].buf[0];
 125                                ret = ce6230_ctrl_msg(d, &req);
 126                        } else {
 127                                err("i2c read not implemented");
 128                                ret = -EPERM;
 129                        }
 130                        i += 2;
 131                } else {
 132                        if (msg[i].addr ==
 133                                ce6230_zl10353_config.demod_address) {
 134                                req.cmd = DEMOD_WRITE;
 135                                req.value = msg[i].addr >> 1;
 136                                req.index = msg[i].buf[0];
 137                                req.data_len = msg[i].len-1;
 138                                req.data = &msg[i].buf[1];
 139                                ret = ce6230_ctrl_msg(d, &req);
 140                        } else {
 141                                req.cmd = I2C_WRITE;
 142                                req.value = 0x2000 + (msg[i].addr >> 1);
 143                                req.index = 0x0000;
 144                                req.data_len = msg[i].len;
 145                                req.data = &msg[i].buf[0];
 146                                ret = ce6230_ctrl_msg(d, &req);
 147                        }
 148                        i += 1;
 149                }
 150                if (ret)
 151                        break;
 152        }
 153
 154        mutex_unlock(&d->i2c_mutex);
 155        return ret ? ret : i;
 156}
 157
 158static u32 ce6230_i2c_func(struct i2c_adapter *adapter)
 159{
 160        return I2C_FUNC_I2C;
 161}
 162
 163static struct i2c_algorithm ce6230_i2c_algo = {
 164        .master_xfer   = ce6230_i2c_xfer,
 165        .functionality = ce6230_i2c_func,
 166};
 167
 168/* Callbacks for DVB USB */
 169static struct zl10353_config ce6230_zl10353_config = {
 170        .demod_address = 0x1e,
 171        .adc_clock = 450000,
 172        .if2 = 45700,
 173        .no_tuner = 1,
 174        .parallel_ts = 1,
 175        .clock_ctl_1 = 0x34,
 176        .pll_0 = 0x0e,
 177};
 178
 179static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
 180{
 181        deb_info("%s:\n", __func__);
 182        adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
 183                &adap->dev->i2c_adap);
 184        if (adap->fe == NULL)
 185                return -ENODEV;
 186        return 0;
 187}
 188
 189static struct mxl5005s_config ce6230_mxl5003s_config = {
 190        .i2c_address     = 0xc6,
 191        .if_freq         = IF_FREQ_4570000HZ,
 192        .xtal_freq       = CRYSTAL_FREQ_16000000HZ,
 193        .agc_mode        = MXL_SINGLE_AGC,
 194        .tracking_filter = MXL_TF_DEFAULT,
 195        .rssi_enable     = MXL_RSSI_ENABLE,
 196        .cap_select      = MXL_CAP_SEL_ENABLE,
 197        .div_out         = MXL_DIV_OUT_4,
 198        .clock_out       = MXL_CLOCK_OUT_DISABLE,
 199        .output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
 200        .top             = MXL5005S_TOP_25P2,
 201        .mod_mode        = MXL_DIGITAL_MODE,
 202        .if_mode         = MXL_ZERO_IF,
 203        .AgcMasterByte   = 0x00,
 204};
 205
 206static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
 207{
 208        int ret;
 209        deb_info("%s:\n", __func__);
 210        ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,
 211                        &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
 212        return ret;
 213}
 214
 215static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
 216{
 217        int ret;
 218        deb_info("%s: onoff:%d\n", __func__, onoff);
 219
 220        /* InterfaceNumber 1 / AlternateSetting 0     idle
 221           InterfaceNumber 1 / AlternateSetting 1     streaming */
 222        ret = usb_set_interface(d->udev, 1, onoff);
 223        if (ret)
 224                err("usb_set_interface failed with error:%d", ret);
 225
 226        return ret;
 227}
 228
 229/* DVB USB Driver stuff */
 230static struct dvb_usb_device_properties ce6230_properties;
 231
 232static int ce6230_probe(struct usb_interface *intf,
 233                        const struct usb_device_id *id)
 234{
 235        int ret = 0;
 236        struct dvb_usb_device *d = NULL;
 237
 238        deb_info("%s: interface:%d\n", __func__,
 239                intf->cur_altsetting->desc.bInterfaceNumber);
 240
 241        if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
 242                ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,
 243                        &d, adapter_nr);
 244                if (ret)
 245                        err("init failed with error:%d\n", ret);
 246        }
 247
 248        return ret;
 249}
 250
 251static struct usb_device_id ce6230_table[] = {
 252        { USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
 253        { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) },
 254        { } /* Terminating entry */
 255};
 256MODULE_DEVICE_TABLE(usb, ce6230_table);
 257
 258static struct dvb_usb_device_properties ce6230_properties = {
 259        .caps = DVB_USB_IS_AN_I2C_ADAPTER,
 260
 261        .usb_ctrl = DEVICE_SPECIFIC,
 262        .no_reconnect = 1,
 263
 264        .size_of_priv = 0,
 265
 266        .num_adapters = 1,
 267        .adapter = {
 268                {
 269                        .frontend_attach  = ce6230_zl10353_frontend_attach,
 270                        .tuner_attach     = ce6230_mxl5003s_tuner_attach,
 271                        .stream = {
 272                                .type = USB_BULK,
 273                                .count = 6,
 274                                .endpoint = 0x82,
 275                                .u = {
 276                                        .bulk = {
 277                                                .buffersize = (16*512),
 278                                        }
 279                                }
 280                        },
 281                }
 282        },
 283
 284        .power_ctrl = ce6230_power_ctrl,
 285
 286        .i2c_algo = &ce6230_i2c_algo,
 287
 288        .num_device_descs = 2,
 289        .devices = {
 290                {
 291                        .name = "Intel CE9500 reference design",
 292                        .cold_ids = {NULL},
 293                        .warm_ids = {&ce6230_table[0], NULL},
 294                },
 295                {
 296                        .name = "AVerMedia A310 USB 2.0 DVB-T tuner",
 297                        .cold_ids = {NULL},
 298                        .warm_ids = {&ce6230_table[1], NULL},
 299                },
 300        }
 301};
 302
 303static struct usb_driver ce6230_driver = {
 304        .name       = "dvb_usb_ce6230",
 305        .probe      = ce6230_probe,
 306        .disconnect = dvb_usb_device_exit,
 307        .id_table   = ce6230_table,
 308};
 309
 310/* module stuff */
 311static int __init ce6230_module_init(void)
 312{
 313        int ret;
 314        deb_info("%s:\n", __func__);
 315        ret = usb_register(&ce6230_driver);
 316        if (ret)
 317                err("usb_register failed with error:%d", ret);
 318
 319        return ret;
 320}
 321
 322static void __exit ce6230_module_exit(void)
 323{
 324        deb_info("%s:\n", __func__);
 325        /* deregister this driver from the USB subsystem */
 326        usb_deregister(&ce6230_driver);
 327}
 328
 329module_init(ce6230_module_init);
 330module_exit(ce6230_module_exit);
 331
 332MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
 333MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");
 334MODULE_LICENSE("GPL");
 335