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 */
27 static int dvb_usb_ce6230_debug;
28 module_param_named(debug, dvb_usb_ce6230_debug, int, 0644);
29 MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS);
30 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
31 
32 static struct zl10353_config ce6230_zl10353_config;
33 
ce6230_rw_udev(struct usb_device * udev,struct req_t * req)34 static 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;
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 	buf = kmalloc(req->data_len, GFP_KERNEL);
66 	if (!buf) {
67 		ret = -ENOMEM;
68 		goto error;
69 	}
70 
71 	if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {
72 		/* write */
73 		memcpy(buf, req->data, req->data_len);
74 		pipe = usb_sndctrlpipe(udev, 0);
75 	} else {
76 		/* read */
77 		pipe = usb_rcvctrlpipe(udev, 0);
78 	}
79 
80 	msleep(1); /* avoid I2C errors */
81 
82 	ret = usb_control_msg(udev, pipe, request, requesttype, value, index,
83 				buf, req->data_len, CE6230_USB_TIMEOUT);
84 
85 	ce6230_debug_dump(request, requesttype, value, index, buf,
86 		req->data_len, deb_xfer);
87 
88 	if (ret < 0)
89 		deb_info("%s: usb_control_msg failed:%d\n", __func__, ret);
90 	else
91 		ret = 0;
92 
93 	/* read request, copy returned data to return buf */
94 	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
95 		memcpy(req->data, buf, req->data_len);
96 
97 	kfree(buf);
98 error:
99 	return ret;
100 }
101 
ce6230_ctrl_msg(struct dvb_usb_device * d,struct req_t * req)102 static int ce6230_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
103 {
104 	return ce6230_rw_udev(d->udev, req);
105 }
106 
107 /* I2C */
ce6230_i2c_xfer(struct i2c_adapter * adap,struct i2c_msg msg[],int num)108 static int ce6230_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
109 			   int num)
110 {
111 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
112 	int i = 0;
113 	struct req_t req;
114 	int ret = 0;
115 	memset(&req, 0, sizeof(req));
116 
117 	if (num > 2)
118 		return -EINVAL;
119 
120 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
121 		return -EAGAIN;
122 
123 	while (i < num) {
124 		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
125 			if (msg[i].addr ==
126 				ce6230_zl10353_config.demod_address) {
127 				req.cmd = DEMOD_READ;
128 				req.value = msg[i].addr >> 1;
129 				req.index = msg[i].buf[0];
130 				req.data_len = msg[i+1].len;
131 				req.data = &msg[i+1].buf[0];
132 				ret = ce6230_ctrl_msg(d, &req);
133 			} else {
134 				err("i2c read not implemented");
135 				ret = -EPERM;
136 			}
137 			i += 2;
138 		} else {
139 			if (msg[i].addr ==
140 				ce6230_zl10353_config.demod_address) {
141 				req.cmd = DEMOD_WRITE;
142 				req.value = msg[i].addr >> 1;
143 				req.index = msg[i].buf[0];
144 				req.data_len = msg[i].len-1;
145 				req.data = &msg[i].buf[1];
146 				ret = ce6230_ctrl_msg(d, &req);
147 			} else {
148 				req.cmd = I2C_WRITE;
149 				req.value = 0x2000 + (msg[i].addr >> 1);
150 				req.index = 0x0000;
151 				req.data_len = msg[i].len;
152 				req.data = &msg[i].buf[0];
153 				ret = ce6230_ctrl_msg(d, &req);
154 			}
155 			i += 1;
156 		}
157 		if (ret)
158 			break;
159 	}
160 
161 	mutex_unlock(&d->i2c_mutex);
162 	return ret ? ret : i;
163 }
164 
ce6230_i2c_func(struct i2c_adapter * adapter)165 static u32 ce6230_i2c_func(struct i2c_adapter *adapter)
166 {
167 	return I2C_FUNC_I2C;
168 }
169 
170 static struct i2c_algorithm ce6230_i2c_algo = {
171 	.master_xfer   = ce6230_i2c_xfer,
172 	.functionality = ce6230_i2c_func,
173 };
174 
175 /* Callbacks for DVB USB */
176 static struct zl10353_config ce6230_zl10353_config = {
177 	.demod_address = 0x1e,
178 	.adc_clock = 450000,
179 	.if2 = 45700,
180 	.no_tuner = 1,
181 	.parallel_ts = 1,
182 	.clock_ctl_1 = 0x34,
183 	.pll_0 = 0x0e,
184 };
185 
ce6230_zl10353_frontend_attach(struct dvb_usb_adapter * adap)186 static int ce6230_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
187 {
188 	deb_info("%s:\n", __func__);
189 	adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &ce6230_zl10353_config,
190 		&adap->dev->i2c_adap);
191 	if (adap->fe_adap[0].fe == NULL)
192 		return -ENODEV;
193 	return 0;
194 }
195 
196 static struct mxl5005s_config ce6230_mxl5003s_config = {
197 	.i2c_address     = 0xc6,
198 	.if_freq         = IF_FREQ_4570000HZ,
199 	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
200 	.agc_mode        = MXL_SINGLE_AGC,
201 	.tracking_filter = MXL_TF_DEFAULT,
202 	.rssi_enable     = MXL_RSSI_ENABLE,
203 	.cap_select      = MXL_CAP_SEL_ENABLE,
204 	.div_out         = MXL_DIV_OUT_4,
205 	.clock_out       = MXL_CLOCK_OUT_DISABLE,
206 	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
207 	.top		 = MXL5005S_TOP_25P2,
208 	.mod_mode        = MXL_DIGITAL_MODE,
209 	.if_mode         = MXL_ZERO_IF,
210 	.AgcMasterByte   = 0x00,
211 };
212 
ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter * adap)213 static int ce6230_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)
214 {
215 	int ret;
216 	deb_info("%s:\n", __func__);
217 	ret = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap,
218 			&ce6230_mxl5003s_config) == NULL ? -ENODEV : 0;
219 	return ret;
220 }
221 
ce6230_power_ctrl(struct dvb_usb_device * d,int onoff)222 static int ce6230_power_ctrl(struct dvb_usb_device *d, int onoff)
223 {
224 	int ret;
225 	deb_info("%s: onoff:%d\n", __func__, onoff);
226 
227 	/* InterfaceNumber 1 / AlternateSetting 0     idle
228 	   InterfaceNumber 1 / AlternateSetting 1     streaming */
229 	ret = usb_set_interface(d->udev, 1, onoff);
230 	if (ret)
231 		err("usb_set_interface failed with error:%d", ret);
232 
233 	return ret;
234 }
235 
236 /* DVB USB Driver stuff */
237 static struct dvb_usb_device_properties ce6230_properties;
238 
ce6230_probe(struct usb_interface * intf,const struct usb_device_id * id)239 static int ce6230_probe(struct usb_interface *intf,
240 			const struct usb_device_id *id)
241 {
242 	int ret = 0;
243 	struct dvb_usb_device *d = NULL;
244 
245 	deb_info("%s: interface:%d\n", __func__,
246 		intf->cur_altsetting->desc.bInterfaceNumber);
247 
248 	if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
249 		ret = dvb_usb_device_init(intf, &ce6230_properties, THIS_MODULE,
250 			&d, adapter_nr);
251 		if (ret)
252 			err("init failed with error:%d\n", ret);
253 	}
254 
255 	return ret;
256 }
257 
258 static struct usb_device_id ce6230_table[] = {
259 	{ USB_DEVICE(USB_VID_INTEL, USB_PID_INTEL_CE9500) },
260 	{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A310) },
261 	{ } /* Terminating entry */
262 };
263 MODULE_DEVICE_TABLE(usb, ce6230_table);
264 
265 static struct dvb_usb_device_properties ce6230_properties = {
266 	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
267 
268 	.usb_ctrl = DEVICE_SPECIFIC,
269 	.no_reconnect = 1,
270 
271 	.size_of_priv = 0,
272 
273 	.num_adapters = 1,
274 	.adapter = {
275 		{
276 		.num_frontends = 1,
277 		.fe = {{
278 			.frontend_attach  = ce6230_zl10353_frontend_attach,
279 			.tuner_attach     = ce6230_mxl5003s_tuner_attach,
280 			.stream = {
281 				.type = USB_BULK,
282 				.count = 6,
283 				.endpoint = 0x82,
284 				.u = {
285 					.bulk = {
286 						.buffersize = (16*512),
287 					}
288 				}
289 			},
290 		}},
291 		}
292 	},
293 
294 	.power_ctrl = ce6230_power_ctrl,
295 
296 	.i2c_algo = &ce6230_i2c_algo,
297 
298 	.num_device_descs = 2,
299 	.devices = {
300 		{
301 			.name = "Intel CE9500 reference design",
302 			.cold_ids = {NULL},
303 			.warm_ids = {&ce6230_table[0], NULL},
304 		},
305 		{
306 			.name = "AVerMedia A310 USB 2.0 DVB-T tuner",
307 			.cold_ids = {NULL},
308 			.warm_ids = {&ce6230_table[1], NULL},
309 		},
310 	}
311 };
312 
313 static struct usb_driver ce6230_driver = {
314 	.name       = "dvb_usb_ce6230",
315 	.probe      = ce6230_probe,
316 	.disconnect = dvb_usb_device_exit,
317 	.id_table   = ce6230_table,
318 };
319 
320 module_usb_driver(ce6230_driver);
321 
322 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
323 MODULE_DESCRIPTION("Driver for Intel CE6230 DVB-T USB2.0");
324 MODULE_LICENSE("GPL");
325