1 /* 2 * Intel CE6230 DVB USB driver 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 */ 17 18 #include "ce6230.h" 19 20 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 21 22 static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) 23 { 24 int ret; 25 unsigned int pipe; 26 u8 request; 27 u8 requesttype; 28 u16 value; 29 u16 index; 30 u8 *buf; 31 32 request = req->cmd; 33 value = req->value; 34 index = req->index; 35 36 switch (req->cmd) { 37 case I2C_READ: 38 case DEMOD_READ: 39 case REG_READ: 40 requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); 41 break; 42 case I2C_WRITE: 43 case DEMOD_WRITE: 44 case REG_WRITE: 45 requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); 46 break; 47 default: 48 dev_err(&d->udev->dev, "%s: unknown command=%02x\n", 49 KBUILD_MODNAME, req->cmd); 50 ret = -EINVAL; 51 goto error; 52 } 53 54 buf = kmalloc(req->data_len, GFP_KERNEL); 55 if (!buf) { 56 ret = -ENOMEM; 57 goto error; 58 } 59 60 if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { 61 /* write */ 62 memcpy(buf, req->data, req->data_len); 63 pipe = usb_sndctrlpipe(d->udev, 0); 64 } else { 65 /* read */ 66 pipe = usb_rcvctrlpipe(d->udev, 0); 67 } 68 69 msleep(1); /* avoid I2C errors */ 70 71 ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index, 72 buf, req->data_len, CE6230_USB_TIMEOUT); 73 74 dvb_usb_dbg_usb_control_msg(d->udev, request, requesttype, value, index, 75 buf, req->data_len); 76 77 if (ret < 0) 78 dev_err(&d->udev->dev, "%s: usb_control_msg() failed=%d\n", 79 KBUILD_MODNAME, ret); 80 else 81 ret = 0; 82 83 /* read request, copy returned data to return buf */ 84 if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) 85 memcpy(req->data, buf, req->data_len); 86 87 kfree(buf); 88 error: 89 return ret; 90 } 91 92 /* I2C */ 93 static struct zl10353_config ce6230_zl10353_config; 94 95 static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, 96 struct i2c_msg msg[], int num) 97 { 98 struct dvb_usb_device *d = i2c_get_adapdata(adap); 99 int ret = 0, i = 0; 100 struct usb_req req; 101 102 if (num > 2) 103 return -EOPNOTSUPP; 104 105 memset(&req, 0, sizeof(req)); 106 107 if (mutex_lock_interruptible(&d->i2c_mutex) < 0) 108 return -EAGAIN; 109 110 while (i < num) { 111 if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { 112 if (msg[i].addr == 113 ce6230_zl10353_config.demod_address) { 114 req.cmd = DEMOD_READ; 115 req.value = msg[i].addr >> 1; 116 req.index = msg[i].buf[0]; 117 req.data_len = msg[i+1].len; 118 req.data = &msg[i+1].buf[0]; 119 ret = ce6230_ctrl_msg(d, &req); 120 } else { 121 dev_err(&d->udev->dev, "%s: I2C read not " \ 122 "implemented\n", 123 KBUILD_MODNAME); 124 ret = -EOPNOTSUPP; 125 } 126 i += 2; 127 } else { 128 if (msg[i].addr == 129 ce6230_zl10353_config.demod_address) { 130 req.cmd = DEMOD_WRITE; 131 req.value = msg[i].addr >> 1; 132 req.index = msg[i].buf[0]; 133 req.data_len = msg[i].len-1; 134 req.data = &msg[i].buf[1]; 135 ret = ce6230_ctrl_msg(d, &req); 136 } else { 137 req.cmd = I2C_WRITE; 138 req.value = 0x2000 + (msg[i].addr >> 1); 139 req.index = 0x0000; 140 req.data_len = msg[i].len; 141 req.data = &msg[i].buf[0]; 142 ret = ce6230_ctrl_msg(d, &req); 143 } 144 i += 1; 145 } 146 if (ret) 147 break; 148 } 149 150 mutex_unlock(&d->i2c_mutex); 151 return ret ? ret : i; 152 } 153 154 static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter) 155 { 156 return I2C_FUNC_I2C; 157 } 158 159 static struct i2c_algorithm ce6230_i2c_algorithm = { 160 .master_xfer = ce6230_i2c_master_xfer, 161 .functionality = ce6230_i2c_functionality, 162 }; 163 164 /* Callbacks for DVB USB */ 165 static struct zl10353_config ce6230_zl10353_config = { 166 .demod_address = 0x1e, 167 .adc_clock = 450000, 168 .if2 = 45700, 169 .no_tuner = 1, 170 .parallel_ts = 1, 171 .clock_ctl_1 = 0x34, 172 .pll_0 = 0x0e, 173 }; 174 175 static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) 176 { 177 struct dvb_usb_device *d = adap_to_d(adap); 178 179 dev_dbg(&d->udev->dev, "%s:\n", __func__); 180 181 adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, 182 &d->i2c_adap); 183 if (adap->fe[0] == NULL) 184 return -ENODEV; 185 186 return 0; 187 } 188 189 static 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 206 static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) 207 { 208 struct dvb_usb_device *d = adap_to_d(adap); 209 int ret; 210 211 dev_dbg(&d->udev->dev, "%s:\n", __func__); 212 213 ret = dvb_attach(mxl5005s_attach, adap->fe[0], &d->i2c_adap, 214 &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; 215 return ret; 216 } 217 218 static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) 219 { 220 int ret; 221 222 dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); 223 224 /* InterfaceNumber 1 / AlternateSetting 0 idle 225 InterfaceNumber 1 / AlternateSetting 1 streaming */ 226 ret = usb_set_interface(d->udev, 1, onoff); 227 if (ret) 228 dev_err(&d->udev->dev, "%s: usb_set_interface() failed=%d\n", 229 KBUILD_MODNAME, ret); 230 231 return ret; 232 } 233 234 /* DVB USB Driver stuff */ 235 static struct dvb_usb_device_properties ce6230_props = { 236 .driver_name = KBUILD_MODNAME, 237 .owner = THIS_MODULE, 238 .adapter_nr = adapter_nr, 239 .bInterfaceNumber = 1, 240 241 .i2c_algo = &ce6230_i2c_algorithm, 242 .power_ctrl = ce6230_power_ctrl, 243 .frontend_attach = ce6230_zl10353_frontend_attach, 244 .tuner_attach = ce6230_mxl5003s_tuner_attach, 245 246 .num_adapters = 1, 247 .adapter = { 248 { 249 .stream = { 250 .type = USB_BULK, 251 .count = 6, 252 .endpoint = 0x82, 253 .u = { 254 .bulk = { 255 .buffersize = (16 * 512), 256 } 257 } 258 }, 259 } 260 }, 261 }; 262 263 static const struct usb_device_id ce6230_id_table[] = { 264 { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500, 265 &ce6230_props, "Intel CE9500 reference design", NULL) }, 266 { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310, 267 &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) }, 268 { } 269 }; 270 MODULE_DEVICE_TABLE(usb, ce6230_id_table); 271 272 static struct usb_driver ce6230_usb_driver = { 273 .name = KBUILD_MODNAME, 274 .id_table = ce6230_id_table, 275 .probe = dvb_usbv2_probe, 276 .disconnect = dvb_usbv2_disconnect, 277 .suspend = dvb_usbv2_suspend, 278 .resume = dvb_usbv2_resume, 279 .reset_resume = dvb_usbv2_reset_resume, 280 .no_dynamic_id = 1, 281 .soft_unbind = 1, 282 }; 283 284 module_usb_driver(ce6230_usb_driver); 285 286 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 287 MODULE_DESCRIPTION("Intel CE6230 driver"); 288 MODULE_LICENSE("GPL"); 289