Merge tag 'regmap-fix-v5.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux/fpc-iii.git] / drivers / media / usb / dvb-usb-v2 / ce6230.c
blob44540de1a206686fcc366a2a8701bf15fe5b221b
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Intel CE6230 DVB USB driver
5 * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
6 */
8 #include "ce6230.h"
10 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
12 static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req)
14 int ret;
15 unsigned int pipe;
16 u8 request;
17 u8 requesttype;
18 u16 value;
19 u16 index;
20 u8 *buf;
22 request = req->cmd;
23 value = req->value;
24 index = req->index;
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;
44 buf = kmalloc(req->data_len, GFP_KERNEL);
45 if (!buf) {
46 ret = -ENOMEM;
47 goto error;
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);
59 msleep(1); /* avoid I2C errors */
61 ret = usb_control_msg(d->udev, pipe, request, requesttype, value, index,
62 buf, req->data_len, CE6230_USB_TIMEOUT);
64 dvb_usb_dbg_usb_control_msg(d->udev, request, requesttype, value, index,
65 buf, req->data_len);
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;
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);
77 kfree(buf);
78 error:
79 return ret;
82 /* I2C */
83 static struct zl10353_config ce6230_zl10353_config;
85 static int ce6230_i2c_master_xfer(struct i2c_adapter *adap,
86 struct i2c_msg msg[], int num)
88 struct dvb_usb_device *d = i2c_get_adapdata(adap);
89 int ret = 0, i = 0;
90 struct usb_req req;
92 if (num > 2)
93 return -EOPNOTSUPP;
95 memset(&req, 0, sizeof(req));
97 if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
98 return -EAGAIN;
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 req.cmd = DEMOD_READ;
105 req.value = msg[i].addr >> 1;
106 req.index = msg[i].buf[0];
107 req.data_len = msg[i+1].len;
108 req.data = &msg[i+1].buf[0];
109 ret = ce6230_ctrl_msg(d, &req);
110 } else {
111 dev_err(&d->udev->dev, "%s: I2C read not " \
112 "implemented\n",
113 KBUILD_MODNAME);
114 ret = -EOPNOTSUPP;
116 i += 2;
117 } else {
118 if (msg[i].addr ==
119 ce6230_zl10353_config.demod_address) {
120 req.cmd = DEMOD_WRITE;
121 req.value = msg[i].addr >> 1;
122 req.index = msg[i].buf[0];
123 req.data_len = msg[i].len-1;
124 req.data = &msg[i].buf[1];
125 ret = ce6230_ctrl_msg(d, &req);
126 } else {
127 req.cmd = I2C_WRITE;
128 req.value = 0x2000 + (msg[i].addr >> 1);
129 req.index = 0x0000;
130 req.data_len = msg[i].len;
131 req.data = &msg[i].buf[0];
132 ret = ce6230_ctrl_msg(d, &req);
134 i += 1;
136 if (ret)
137 break;
140 mutex_unlock(&d->i2c_mutex);
141 return ret ? ret : i;
144 static u32 ce6230_i2c_functionality(struct i2c_adapter *adapter)
146 return I2C_FUNC_I2C;
149 static struct i2c_algorithm ce6230_i2c_algorithm = {
150 .master_xfer = ce6230_i2c_master_xfer,
151 .functionality = ce6230_i2c_functionality,
154 /* Callbacks for DVB USB */
155 static struct zl10353_config ce6230_zl10353_config = {
156 .demod_address = 0x1e,
157 .adc_clock = 450000,
158 .if2 = 45700,
159 .no_tuner = 1,
160 .parallel_ts = 1,
161 .clock_ctl_1 = 0x34,
162 .pll_0 = 0x0e,
165 static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
167 struct dvb_usb_device *d = adap_to_d(adap);
169 dev_dbg(&d->udev->dev, "%s:\n", __func__);
171 adap->fe[0] = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
172 &d->i2c_adap);
173 if (adap->fe[0] == NULL)
174 return -ENODEV;
176 return 0;
179 static struct mxl5005s_config ce6230_mxl5003s_config = {
180 .i2c_address = 0xc6,
181 .if_freq = IF_FREQ_4570000HZ,
182 .xtal_freq = CRYSTAL_FREQ_16000000HZ,
183 .agc_mode = MXL_SINGLE_AGC,
184 .tracking_filter = MXL_TF_DEFAULT,
185 .rssi_enable = MXL_RSSI_ENABLE,
186 .cap_select = MXL_CAP_SEL_ENABLE,
187 .div_out = MXL_DIV_OUT_4,
188 .clock_out = MXL_CLOCK_OUT_DISABLE,
189 .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
190 .top = MXL5005S_TOP_25P2,
191 .mod_mode = MXL_DIGITAL_MODE,
192 .if_mode = MXL_ZERO_IF,
193 .AgcMasterByte = 0x00,
196 static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
198 struct dvb_usb_device *d = adap_to_d(adap);
199 int ret;
201 dev_dbg(&d->udev->dev, "%s:\n", __func__);
203 ret = dvb_attach(mxl5005s_attach, adap->fe[0], &d->i2c_adap,
204 &ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
205 return ret;
208 static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
210 int ret;
212 dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
214 /* InterfaceNumber 1 / AlternateSetting 0 idle
215 InterfaceNumber 1 / AlternateSetting 1 streaming */
216 ret = usb_set_interface(d->udev, 1, onoff);
217 if (ret)
218 dev_err(&d->udev->dev, "%s: usb_set_interface() failed=%d\n",
219 KBUILD_MODNAME, ret);
221 return ret;
224 /* DVB USB Driver stuff */
225 static struct dvb_usb_device_properties ce6230_props = {
226 .driver_name = KBUILD_MODNAME,
227 .owner = THIS_MODULE,
228 .adapter_nr = adapter_nr,
229 .bInterfaceNumber = 1,
231 .i2c_algo = &ce6230_i2c_algorithm,
232 .power_ctrl = ce6230_power_ctrl,
233 .frontend_attach = ce6230_zl10353_frontend_attach,
234 .tuner_attach = ce6230_mxl5003s_tuner_attach,
236 .num_adapters = 1,
237 .adapter = {
239 .stream = {
240 .type = USB_BULK,
241 .count = 6,
242 .endpoint = 0x82,
243 .u = {
244 .bulk = {
245 .buffersize = (16 * 512),
253 static const struct usb_device_id ce6230_id_table[] = {
254 { DVB_USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500,
255 &ce6230_props, "Intel CE9500 reference design", NULL) },
256 { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310,
257 &ce6230_props, "AVerMedia A310 USB 2.0 DVB-T tuner", NULL) },
260 MODULE_DEVICE_TABLE(usb, ce6230_id_table);
262 static struct usb_driver ce6230_usb_driver = {
263 .name = KBUILD_MODNAME,
264 .id_table = ce6230_id_table,
265 .probe = dvb_usbv2_probe,
266 .disconnect = dvb_usbv2_disconnect,
267 .suspend = dvb_usbv2_suspend,
268 .resume = dvb_usbv2_resume,
269 .reset_resume = dvb_usbv2_reset_resume,
270 .no_dynamic_id = 1,
271 .soft_unbind = 1,
274 module_usb_driver(ce6230_usb_driver);
276 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
277 MODULE_DESCRIPTION("Intel CE6230 driver");
278 MODULE_LICENSE("GPL");