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