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