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 * 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 24 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 25 26 static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) 27 { 28 int ret; 29 unsigned int pipe; 30 u8 request; 31 u8 requesttype; 32 u16 value; 33 u16 index; 34 u8 *buf; 35 36 request = req->cmd; 37 value = req->value; 38 index = req->index; 39 40 switch (req->cmd) { 41 case I2C_READ: 42 case DEMOD_READ: 43 case REG_READ: 44 requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); 45 break; 46 case I2C_WRITE: 47 case DEMOD_WRITE: 48 case REG_WRITE: 49 requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); 50 break; 51 default: 52 dev_err(&d->udev->dev, "%s: unknown command=%02x\n", 53 KBUILD_MODNAME, req->cmd); 54 ret = -EINVAL; 55 goto error; 56 } 57 58 buf = kmalloc(req->data_len, GFP_KERNEL); 59 if (!buf) { 60 ret = -ENOMEM; 61 goto error; 62 } 63 64 if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { 65 /* write */ 66 memcpy(buf, req->data, req->data_len); 67 pipe = usb_sndctrlpipe(d->udev, 0); 68 } else { 69 /* read */ 70 pipe = usb_rcvctrlpipe(d->udev, 0); 71 } 72 73 msleep(1); /* avoid I2C errors */ 74 75 ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index, 76 buf, req->data_len, CE6230_USB_TIMEOUT); 77 78 dvb_usb_dbg_usb_control_msg(d->udev, request, requesttype, value, index, 79 buf, req->data_len); 80 81 if (ret < 0) 82 dev_err(&d->udev->dev, "%s: usb_control_msg() failed=%d\n", 83 KBUILD_MODNAME, 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 91 kfree(buf); 92 error: 93 return ret; 94 } 95 96 /* I2C */ 97 static struct zl10353_config ce6230_zl10353_config; 98 99 static int ce6230_i2c_master_xfer(struct i2c_adapter *adap, 100 struct i2c_msg msg[], int num) 101 { 102 struct dvb_usb_device *d = i2c_get_adapdata(adap); 103 int ret = 0, i = 0; 104 struct usb_req req; 105 106 if (num > 2) 107 return -EOPNOTSUPP; 108 109 memset(&req, 0, sizeof(req)); 110 111 if (mutex_lock_interruptible(&d->i2c_mutex) < 0) 112 return -EAGAIN; 113 114 while (i < num) { 115 if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { 116 if (msg[i].addr == 117 ce6230_zl10353_config.demod_address) { 118 req.cmd = DEMOD_READ; 119 req.value = msg[i].addr >> 1; 120 req.index = msg[i].buf[0]; 121 req.data_len = msg[i+1].len; 122 req.data = &msg[i+1].buf[0]; 123 ret = ce6230_ctrl_msg(d, &req); 124 } else { 125 dev_err(&d->udev->dev, "%s: I2C read not " \ 126 "implemented\n", 127 KBUILD_MODNAME); 128 ret = -EOPNOTSUPP; 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 158 static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter) 159 { 160 return I2C_FUNC_I2C; 161 } 162 163 static struct i2c_algorithm ce6230_i2c_algorithm = { 164 .master_xfer = ce6230_i2c_master_xfer, 165 .functionality = ce6230_i2c_functionality, 166 }; 167 168 /* Callbacks for DVB USB */ 169 static 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 179 static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap) 180 { 181 struct dvb_usb_device *d = adap_to_d(adap); 182 183 dev_dbg(&d->udev->dev, "%s:\n", __func__); 184 185 adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config, 186 &d->i2c_adap); 187 if (adap->fe[0] == NULL) 188 return -ENODEV; 189 190 return 0; 191 } 192 193 static struct mxl5005s_config ce6230_mxl5003s_config = { 194 .i2c_address = 0xc6, 195 .if_freq = IF_FREQ_4570000HZ, 196 .xtal_freq = CRYSTAL_FREQ_16000000HZ, 197 .agc_mode = MXL_SINGLE_AGC, 198 .tracking_filter = MXL_TF_DEFAULT, 199 .rssi_enable = MXL_RSSI_ENABLE, 200 .cap_select = MXL_CAP_SEL_ENABLE, 201 .div_out = MXL_DIV_OUT_4, 202 .clock_out = MXL_CLOCK_OUT_DISABLE, 203 .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, 204 .top = MXL5005S_TOP_25P2, 205 .mod_mode = MXL_DIGITAL_MODE, 206 .if_mode = MXL_ZERO_IF, 207 .AgcMasterByte = 0x00, 208 }; 209 210 static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) 211 { 212 struct dvb_usb_device *d = adap_to_d(adap); 213 int ret; 214 215 dev_dbg(&d->udev->dev, "%s:\n", __func__); 216 217 ret = dvb_attach(mxl5005s_attach, adap->fe[0], &d->i2c_adap, 218 &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0; 219 return ret; 220 } 221 222 static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff) 223 { 224 int ret; 225 226 dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); 227 228 /* InterfaceNumber 1 / AlternateSetting 0 idle 229 InterfaceNumber 1 / AlternateSetting 1 streaming */ 230 ret = usb_set_interface(d->udev, 1, onoff); 231 if (ret) 232 dev_err(&d->udev->dev, "%s: usb_set_interface() failed=%d\n", 233 KBUILD_MODNAME, ret); 234 235 return ret; 236 } 237 238 /* DVB USB Driver stuff */ 239 static struct dvb_usb_device_properties ce6230_props = { 240 .driver_name = KBUILD_MODNAME, 241 .owner = THIS_MODULE, 242 .adapter_nr = adapter_nr, 243 .bInterfaceNumber = 1, 244 245 .i2c_algo = &ce6230_i2c_algorithm, 246 .power_ctrl = ce6230_power_ctrl, 247 .frontend_attach = ce6230_zl10353_frontend_attach, 248 .tuner_attach = ce6230_mxl5003s_tuner_attach, 249 250 .num_adapters = 1, 251 .adapter = { 252 { 253 .stream = { 254 .type = USB_BULK, 255 .count = 6, 256 .endpoint = 0x82, 257 .u = { 258 .bulk = { 259 .buffersize = (16 * 512), 260 } 261 } 262 }, 263 } 264 }, 265 }; 266 267 static const struct usb_device_id ce6230_id_table[] = { 268 { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500, 269 &ce6230_props, "Intel CE9500 reference design", NULL) }, 270 { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310, 271 &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) }, 272 { } 273 }; 274 MODULE_DEVICE_TABLE(usb, ce6230_id_table); 275 276 static struct usb_driver ce6230_usb_driver = { 277 .name = KBUILD_MODNAME, 278 .id_table = ce6230_id_table, 279 .probe = dvb_usbv2_probe, 280 .disconnect = dvb_usbv2_disconnect, 281 .suspend = dvb_usbv2_suspend, 282 .resume = dvb_usbv2_resume, 283 .reset_resume = dvb_usbv2_reset_resume, 284 .no_dynamic_id = 1, 285 .soft_unbind = 1, 286 }; 287 288 module_usb_driver(ce6230_usb_driver); 289 290 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); 291 MODULE_DESCRIPTION("Intel CE6230 driver"); 292 MODULE_LICENSE("GPL"); 293