Path: blob/master/drivers/media/dvb/dvb-usb/ce6230.c
15111 views
/*1* DVB USB Linux driver for Intel CE6230 DVB-T USB2.0 receiver2*3* Copyright (C) 2009 Antti Palosaari <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.18*19*/2021#include "ce6230.h"22#include "zl10353.h"23#include "mxl5005s.h"2425/* debug */26static int dvb_usb_ce6230_debug;27module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);28MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);29DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);3031static struct zl10353_config ce6230_zl10353_config;3233static int ce6230_rw_udev(struct usb_device *udev, struct req_t *req)34{35int ret;36unsigned int pipe;37u8 request;38u8 requesttype;39u16 value;40u16 index;41u8 *buf;4243request = req->cmd;44value = req->value;45index = req->index;4647switch (req->cmd) {48case I2C_READ:49case DEMOD_READ:50case REG_READ:51requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);52break;53case I2C_WRITE:54case DEMOD_WRITE:55case REG_WRITE:56requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);57break;58default:59err("unknown command:%02x", req->cmd);60ret = -EPERM;61goto error;62}6364buf = kmalloc(req->data_len, GFP_KERNEL);65if (!buf) {66ret = -ENOMEM;67goto error;68}6970if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {71/* write */72memcpy(buf, req->data, req->data_len);73pipe = usb_sndctrlpipe(udev, 0);74} else {75/* read */76pipe = usb_rcvctrlpipe(udev, 0);77}7879msleep(1); /* avoid I2C errors */8081ret = usb_control_msg(udev, pipe, request, requesttype, value, index,82buf, req->data_len, CE6230_USB_TIMEOUT);8384ce6230_debug_dump(request, requesttype, value, index, buf,85req->data_len, deb_xfer);8687if (ret < 0)88deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);89else90ret = 0;9192/* read request, copy returned data to return buf */93if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))94memcpy(req->data, buf, req->data_len);9596kfree(buf);97error:98return ret;99}100101static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)102{103return ce6230_rw_udev(d->udev, req);104}105106/* I2C */107static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],108int num)109{110struct dvb_usb_device *d = i2c_get_adapdata(adap);111int i = 0;112struct req_t req;113int ret = 0;114memset(&req, 0, sizeof(req));115116if (num > 2)117return -EINVAL;118119if (mutex_lock_interruptible(&d->i2c_mutex) < 0)120return -EAGAIN;121122while (i < num) {123if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {124if (msg[i].addr ==125ce6230_zl10353_config.demod_address) {126req.cmd = DEMOD_READ;127req.value = msg[i].addr >> 1;128req.index = msg[i].buf[0];129req.data_len = msg[i+1].len;130req.data = &msg[i+1].buf[0];131ret = ce6230_ctrl_msg(d, &req);132} else {133err("i2c read not implemented");134ret = -EPERM;135}136i += 2;137} else {138if (msg[i].addr ==139ce6230_zl10353_config.demod_address) {140req.cmd = DEMOD_WRITE;141req.value = msg[i].addr >> 1;142req.index = msg[i].buf[0];143req.data_len = msg[i].len-1;144req.data = &msg[i].buf[1];145ret = ce6230_ctrl_msg(d, &req);146} else {147req.cmd = I2C_WRITE;148req.value = 0x2000 + (msg[i].addr >> 1);149req.index = 0x0000;150req.data_len = msg[i].len;151req.data = &msg[i].buf[0];152ret = ce6230_ctrl_msg(d, &req);153}154i += 1;155}156if (ret)157break;158}159160mutex_unlock(&d->i2c_mutex);161return ret ? ret : i;162}163164static u32 ce6230_i2c_func(struct i2c_adapter *adapter)165{166return I2C_FUNC_I2C;167}168169static struct i2c_algorithm ce6230_i2c_algo = {170.master_xfer = ce6230_i2c_xfer,171.functionality = ce6230_i2c_func,172};173174/* Callbacks for DVB USB */175static struct zl10353_config ce6230_zl10353_config = {176.demod_address = 0x1e,177.adc_clock = 450000,178.if2 = 45700,179.no_tuner = 1,180.parallel_ts = 1,181.clock_ctl_1 = 0x34,182.pll_0 = 0x0e,183};184185static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)186{187deb_info("%s:\n", __func__);188adap->fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,189&adap->dev->i2c_adap);190if (adap->fe == NULL)191return -ENODEV;192return 0;193}194195static struct mxl5005s_config ce6230_mxl5003s_config = {196.i2c_address = 0xc6,197.if_freq = IF_FREQ_4570000HZ,198.xtal_freq = CRYSTAL_FREQ_16000000HZ,199.agc_mode = MXL_SINGLE_AGC,200.tracking_filter = MXL_TF_DEFAULT,201.rssi_enable = MXL_RSSI_ENABLE,202.cap_select = MXL_CAP_SEL_ENABLE,203.div_out = MXL_DIV_OUT_4,204.clock_out = MXL_CLOCK_OUT_DISABLE,205.output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,206.top = MXL5005S_TOP_25P2,207.mod_mode = MXL_DIGITAL_MODE,208.if_mode = MXL_ZERO_IF,209.AgcMasterByte = 0x00,210};211212static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)213{214int ret;215deb_info("%s:\n", __func__);216ret = dvb_attach(mxl5005s_attach, adap->fe, &adap->dev->i2c_adap,217&ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;218return ret;219}220221static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)222{223int ret;224deb_info("%s: onoff:%d\n", __func__, onoff);225226/* InterfaceNumber 1 / AlternateSetting 0 idle227InterfaceNumber 1 / AlternateSetting 1 streaming */228ret = usb_set_interface(d->udev, 1, onoff);229if (ret)230err("usb_set_interface failed with error:%d", ret);231232return ret;233}234235/* DVB USB Driver stuff */236static struct dvb_usb_device_properties ce6230_properties;237238static int ce6230_probe(struct usb_interface *intf,239const struct usb_device_id *id)240{241int ret = 0;242struct dvb_usb_device *d = NULL;243244deb_info("%s: interface:%d\n", __func__,245intf->cur_altsetting->desc.bInterfaceNumber);246247if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {248ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,249&d, adapter_nr);250if (ret)251err("init failed with error:%d\n", ret);252}253254return ret;255}256257static struct usb_device_id ce6230_table[] = {258{ USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },259{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) },260{ } /* Terminating entry */261};262MODULE_DEVICE_TABLE(usb, ce6230_table);263264static struct dvb_usb_device_properties ce6230_properties = {265.caps = DVB_USB_IS_AN_I2C_ADAPTER,266267.usb_ctrl = DEVICE_SPECIFIC,268.no_reconnect = 1,269270.size_of_priv = 0,271272.num_adapters = 1,273.adapter = {274{275.frontend_attach = ce6230_zl10353_frontend_attach,276.tuner_attach = ce6230_mxl5003s_tuner_attach,277.stream = {278.type = USB_BULK,279.count = 6,280.endpoint = 0x82,281.u = {282.bulk = {283.buffersize = (16*512),284}285}286},287}288},289290.power_ctrl = ce6230_power_ctrl,291292.i2c_algo = &ce6230_i2c_algo,293294.num_device_descs = 2,295.devices = {296{297.name = "Intel CE9500 reference design",298.cold_ids = {NULL},299.warm_ids = {&ce6230_table[0], NULL},300},301{302.name = "AVerMedia A310 USB 2.0 DVB-T tuner",303.cold_ids = {NULL},304.warm_ids = {&ce6230_table[1], NULL},305},306}307};308309static struct usb_driver ce6230_driver = {310.name = "dvb_usb_ce6230",311.probe = ce6230_probe,312.disconnect = dvb_usb_device_exit,313.id_table = ce6230_table,314};315316/* module stuff */317static int __init ce6230_module_init(void)318{319int ret;320deb_info("%s:\n", __func__);321ret = usb_register(&ce6230_driver);322if (ret)323err("usb_register failed with error:%d", ret);324325return ret;326}327328static void __exit ce6230_module_exit(void)329{330deb_info("%s:\n", __func__);331/* deregister this driver from the USB subsystem */332usb_deregister(&ce6230_driver);333}334335module_init(ce6230_module_init);336module_exit(ce6230_module_exit);337338MODULE_AUTHOR("Antti Palosaari <[email protected]>");339MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");340MODULE_LICENSE("GPL");341342343