| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * E3C EC168 DVB USB driver | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  *    it under the terms of the GNU General Public License as published by | 
					
						
							|  |  |  |  *    the Free Software Foundation; either version 2 of the License, or | 
					
						
							|  |  |  |  *    (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  *    but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  *    GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *    You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  *    along with this program; if not, write to the Free Software | 
					
						
							|  |  |  |  *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "ec168.h"
 | 
					
						
							|  |  |  | #include "ec100.h"
 | 
					
						
							|  |  |  | #include "mxl5005s.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req) | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	unsigned int pipe; | 
					
						
							|  |  |  | 	u8 request, requesttype; | 
					
						
							| 
									
										
										
										
											2011-03-20 18:50:48 -03:00
										 |  |  | 	u8 *buf; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	switch (req->cmd) { | 
					
						
							|  |  |  | 	case DOWNLOAD_FIRMWARE: | 
					
						
							|  |  |  | 	case GPIO: | 
					
						
							|  |  |  | 	case WRITE_I2C: | 
					
						
							|  |  |  | 	case STREAMING_CTRL: | 
					
						
							|  |  |  | 		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); | 
					
						
							|  |  |  | 		request = req->cmd; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case READ_I2C: | 
					
						
							|  |  |  | 		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); | 
					
						
							|  |  |  | 		request = req->cmd; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case GET_CONFIG: | 
					
						
							|  |  |  | 		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); | 
					
						
							|  |  |  | 		request = CONFIG; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case SET_CONFIG: | 
					
						
							|  |  |  | 		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); | 
					
						
							|  |  |  | 		request = CONFIG; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case WRITE_DEMOD: | 
					
						
							|  |  |  | 		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); | 
					
						
							|  |  |  | 		request = DEMOD_RW; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case READ_DEMOD: | 
					
						
							|  |  |  | 		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); | 
					
						
							|  |  |  | 		request = DEMOD_RW; | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 		dev_err(&d->udev->dev, "%s: unknown command=%02x\n", | 
					
						
							|  |  |  | 				KBUILD_MODNAME, req->cmd); | 
					
						
							| 
									
										
										
										
											2012-06-12 20:40:21 -03:00
										 |  |  | 		ret = -EINVAL; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-20 18:50:48 -03:00
										 |  |  | 	buf = kmalloc(req->size, GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!buf) { | 
					
						
							|  |  |  | 		ret = -ENOMEM; | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) { | 
					
						
							|  |  |  | 		/* write */ | 
					
						
							|  |  |  | 		memcpy(buf, req->data, req->size); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 		pipe = usb_sndctrlpipe(d->udev, 0); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		/* read */ | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 		pipe = usb_rcvctrlpipe(d->udev, 0); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	msleep(1); /* avoid I2C errors */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value, | 
					
						
							| 
									
										
										
										
											2011-03-20 18:50:48 -03:00
										 |  |  | 		req->index, buf, req->size, EC168_USB_TIMEOUT); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-22 19:42:00 -03:00
										 |  |  | 	dvb_usb_dbg_usb_control_msg(d->udev, request, requesttype, req->value, | 
					
						
							|  |  |  | 			req->index, buf, req->size); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (ret < 0) | 
					
						
							| 
									
										
										
										
											2011-03-20 18:50:48 -03:00
										 |  |  | 		goto err_dealloc; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	else | 
					
						
							|  |  |  | 		ret = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* read request, copy returned data to return buf */ | 
					
						
							|  |  |  | 	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN)) | 
					
						
							|  |  |  | 		memcpy(req->data, buf, req->size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-20 18:50:48 -03:00
										 |  |  | 	kfree(buf); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2011-03-20 18:50:48 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | err_dealloc: | 
					
						
							|  |  |  | 	kfree(buf); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | error: | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* I2C */ | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | static struct ec100_config ec168_ec100_config; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], | 
					
						
							|  |  |  | 	int num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct dvb_usb_device *d = i2c_get_adapdata(adap); | 
					
						
							|  |  |  | 	struct ec168_req req; | 
					
						
							|  |  |  | 	int i = 0; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (num > 2) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0) | 
					
						
							|  |  |  | 		return -EAGAIN; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (i < num) { | 
					
						
							|  |  |  | 		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) { | 
					
						
							|  |  |  | 			if (msg[i].addr == ec168_ec100_config.demod_address) { | 
					
						
							|  |  |  | 				req.cmd = READ_DEMOD; | 
					
						
							|  |  |  | 				req.value = 0; | 
					
						
							|  |  |  | 				req.index = 0xff00 + msg[i].buf[0]; /* reg */ | 
					
						
							|  |  |  | 				req.size = msg[i+1].len; /* bytes to read */ | 
					
						
							|  |  |  | 				req.data = &msg[i+1].buf[0]; | 
					
						
							|  |  |  | 				ret = ec168_ctrl_msg(d, &req); | 
					
						
							|  |  |  | 				i += 2; | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 				dev_err(&d->udev->dev, "%s: I2C read not " \ | 
					
						
							|  |  |  | 						"implemented\n", | 
					
						
							| 
									
										
										
										
											2012-06-12 20:40:21 -03:00
										 |  |  | 						KBUILD_MODNAME); | 
					
						
							|  |  |  | 				ret = -EOPNOTSUPP; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 				i += 2; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			if (msg[i].addr == ec168_ec100_config.demod_address) { | 
					
						
							|  |  |  | 				req.cmd = WRITE_DEMOD; | 
					
						
							|  |  |  | 				req.value = msg[i].buf[1]; /* val */ | 
					
						
							|  |  |  | 				req.index = 0xff00 + msg[i].buf[0]; /* reg */ | 
					
						
							|  |  |  | 				req.size = 0; | 
					
						
							|  |  |  | 				req.data = NULL; | 
					
						
							|  |  |  | 				ret = ec168_ctrl_msg(d, &req); | 
					
						
							|  |  |  | 				i += 1; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				req.cmd = WRITE_I2C; | 
					
						
							|  |  |  | 				req.value = msg[i].buf[0]; /* val */ | 
					
						
							|  |  |  | 				req.index = 0x0100 + msg[i].addr; /* I2C addr */ | 
					
						
							|  |  |  | 				req.size = msg[i].len-1; | 
					
						
							|  |  |  | 				req.data = &msg[i].buf[1]; | 
					
						
							|  |  |  | 				ret = ec168_ctrl_msg(d, &req); | 
					
						
							|  |  |  | 				i += 1; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ret = i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | error: | 
					
						
							|  |  |  | 	mutex_unlock(&d->i2c_mutex); | 
					
						
							| 
									
										
										
										
											2013-12-29 19:47:18 -03:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static u32 ec168_i2c_func(struct i2c_adapter *adapter) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return I2C_FUNC_I2C; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct i2c_algorithm ec168_i2c_algo = { | 
					
						
							|  |  |  | 	.master_xfer   = ec168_i2c_xfer, | 
					
						
							|  |  |  | 	.functionality = ec168_i2c_func, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Callbacks for DVB USB */ | 
					
						
							| 
									
										
										
										
											2012-06-18 23:42:53 -03:00
										 |  |  | static int ec168_identify_state(struct dvb_usb_device *d, const char **name) | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	int ret; | 
					
						
							|  |  |  | 	u8 reply; | 
					
						
							|  |  |  | 	struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply}; | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	dev_dbg(&d->udev->dev, "%s:\n", __func__); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	ret = ec168_ctrl_msg(d, &req); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	dev_dbg(&d->udev->dev, "%s: reply=%02x\n", __func__, reply); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	if (reply == 0x01) | 
					
						
							|  |  |  | 		ret = WARM; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		ret = COLD; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | error: | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | static int ec168_download_firmware(struct dvb_usb_device *d, | 
					
						
							|  |  |  | 		const struct firmware *fw) | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-06-12 22:16:12 -03:00
										 |  |  | 	int ret, len, remaining; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL}; | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	dev_dbg(&d->udev->dev, "%s:\n", __func__); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 22:16:12 -03:00
										 |  |  | 	#define LEN_MAX 2048 /* max packet size */
 | 
					
						
							|  |  |  | 	for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) { | 
					
						
							|  |  |  | 		len = remaining; | 
					
						
							|  |  |  | 		if (len > LEN_MAX) | 
					
						
							|  |  |  | 			len = LEN_MAX; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		req.size = len; | 
					
						
							| 
									
										
										
										
											2012-06-12 22:16:12 -03:00
										 |  |  | 		req.data = (u8 *) &fw->data[fw->size - remaining]; | 
					
						
							|  |  |  | 		req.index = fw->size - remaining; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 		ret = ec168_ctrl_msg(d, &req); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 		if (ret) { | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 			dev_err(&d->udev->dev, | 
					
						
							|  |  |  | 					"%s: firmware download failed=%d\n", | 
					
						
							| 
									
										
										
										
											2012-06-12 22:16:12 -03:00
										 |  |  | 					KBUILD_MODNAME, ret); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 			goto error; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-12 22:16:12 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	req.size = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* set "warm"? */ | 
					
						
							|  |  |  | 	req.cmd = SET_CONFIG; | 
					
						
							|  |  |  | 	req.value = 0; | 
					
						
							|  |  |  | 	req.index = 0x0001; | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	ret = ec168_ctrl_msg(d, &req); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* really needed - no idea what does */ | 
					
						
							|  |  |  | 	req.cmd = GPIO; | 
					
						
							|  |  |  | 	req.value = 0; | 
					
						
							|  |  |  | 	req.index = 0x0206; | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	ret = ec168_ctrl_msg(d, &req); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* activate tuner I2C? */ | 
					
						
							|  |  |  | 	req.cmd = WRITE_I2C; | 
					
						
							|  |  |  | 	req.value = 0; | 
					
						
							|  |  |  | 	req.index = 0x00c6; | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	ret = ec168_ctrl_msg(d, &req); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	if (ret) | 
					
						
							|  |  |  | 		goto error; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							|  |  |  | error: | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 	return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | static struct ec100_config ec168_ec100_config = { | 
					
						
							|  |  |  | 	.demod_address = 0xff, /* not real address, demod is integrated */ | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap) | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	struct dvb_usb_device *d = adap_to_d(adap); | 
					
						
							|  |  |  | 	dev_dbg(&d->udev->dev, "%s:\n", __func__); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config, | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 			&d->i2c_adap); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	if (adap->fe[0] == NULL) | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | static struct mxl5005s_config ec168_mxl5003s_config = { | 
					
						
							|  |  |  | 	.i2c_address     = 0xc6, | 
					
						
							|  |  |  | 	.if_freq         = IF_FREQ_4570000HZ, | 
					
						
							|  |  |  | 	.xtal_freq       = CRYSTAL_FREQ_16000000HZ, | 
					
						
							|  |  |  | 	.agc_mode        = MXL_SINGLE_AGC, | 
					
						
							|  |  |  | 	.tracking_filter = MXL_TF_OFF, | 
					
						
							|  |  |  | 	.rssi_enable     = MXL_RSSI_ENABLE, | 
					
						
							|  |  |  | 	.cap_select      = MXL_CAP_SEL_ENABLE, | 
					
						
							|  |  |  | 	.div_out         = MXL_DIV_OUT_4, | 
					
						
							|  |  |  | 	.clock_out       = MXL_CLOCK_OUT_DISABLE, | 
					
						
							|  |  |  | 	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM, | 
					
						
							|  |  |  | 	.top		 = MXL5005S_TOP_25P2, | 
					
						
							|  |  |  | 	.mod_mode        = MXL_DIGITAL_MODE, | 
					
						
							|  |  |  | 	.if_mode         = MXL_ZERO_IF, | 
					
						
							|  |  |  | 	.AgcMasterByte   = 0x00, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	struct dvb_usb_device *d = adap_to_d(adap); | 
					
						
							|  |  |  | 	dev_dbg(&d->udev->dev, "%s:\n", __func__); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return dvb_attach(mxl5005s_attach, adap->fe[0], &d->i2c_adap, | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 			&ec168_mxl5003s_config) == NULL ? -ENODEV : 0; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-26 00:04:33 -03:00
										 |  |  | static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff) | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	struct dvb_usb_device *d = fe_to_d(fe); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL}; | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	if (onoff) | 
					
						
							|  |  |  | 		req.index = 0x0102; | 
					
						
							| 
									
										
										
										
											2012-09-12 20:23:56 -03:00
										 |  |  | 	return ec168_ctrl_msg(d, &req); | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | /* DVB USB Driver stuff */ | 
					
						
							|  |  |  | /* bInterfaceNumber 0 is HID
 | 
					
						
							|  |  |  |  * bInterfaceNumber 1 is DVB-T */ | 
					
						
							|  |  |  | static struct dvb_usb_device_properties ec168_props = { | 
					
						
							|  |  |  | 	.driver_name = KBUILD_MODNAME, | 
					
						
							|  |  |  | 	.owner = THIS_MODULE, | 
					
						
							|  |  |  | 	.adapter_nr = adapter_nr, | 
					
						
							|  |  |  | 	.bInterfaceNumber = 1, | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	.identify_state = ec168_identify_state, | 
					
						
							| 
									
										
										
										
											2012-09-12 11:37:27 -03:00
										 |  |  | 	.firmware = EC168_FIRMWARE, | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	.download_firmware = ec168_download_firmware, | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	.i2c_algo = &ec168_i2c_algo, | 
					
						
							|  |  |  | 	.frontend_attach = ec168_ec100_frontend_attach, | 
					
						
							|  |  |  | 	.tuner_attach = ec168_mxl5003s_tuner_attach, | 
					
						
							|  |  |  | 	.streaming_ctrl = ec168_streaming_ctrl, | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	.num_adapters = 1, | 
					
						
							|  |  |  | 	.adapter = { | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2012-06-18 19:58:44 -03:00
										 |  |  | 			.stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512), | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | static const struct dvb_usb_driver_info ec168_driver_info = { | 
					
						
							|  |  |  | 	.name = "E3C EC168 reference design", | 
					
						
							|  |  |  | 	.props = &ec168_props, | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | static const struct usb_device_id ec168_id[] = { | 
					
						
							|  |  |  | 	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168), | 
					
						
							|  |  |  | 		.driver_info = (kernel_ulong_t) &ec168_driver_info }, | 
					
						
							|  |  |  | 	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2), | 
					
						
							|  |  |  | 		.driver_info = (kernel_ulong_t) &ec168_driver_info }, | 
					
						
							|  |  |  | 	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3), | 
					
						
							|  |  |  | 		.driver_info = (kernel_ulong_t) &ec168_driver_info }, | 
					
						
							|  |  |  | 	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4), | 
					
						
							|  |  |  | 		.driver_info = (kernel_ulong_t) &ec168_driver_info }, | 
					
						
							|  |  |  | 	{ USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5), | 
					
						
							|  |  |  | 		.driver_info = (kernel_ulong_t) &ec168_driver_info }, | 
					
						
							|  |  |  | 	{} | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | MODULE_DEVICE_TABLE(usb, ec168_id); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | static struct usb_driver ec168_driver = { | 
					
						
							| 
									
										
										
										
											2012-06-12 16:45:54 -03:00
										 |  |  | 	.name = KBUILD_MODNAME, | 
					
						
							|  |  |  | 	.id_table = ec168_id, | 
					
						
							|  |  |  | 	.probe = dvb_usbv2_probe, | 
					
						
							|  |  |  | 	.disconnect = dvb_usbv2_disconnect, | 
					
						
							|  |  |  | 	.suspend = dvb_usbv2_suspend, | 
					
						
							|  |  |  | 	.resume = dvb_usbv2_resume, | 
					
						
							|  |  |  | 	.no_dynamic_id = 1, | 
					
						
							|  |  |  | 	.soft_unbind = 1, | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-18 09:46:12 -08:00
										 |  |  | module_usb_driver(ec168_driver); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | 
					
						
							| 
									
										
										
										
											2012-06-12 20:40:21 -03:00
										 |  |  | MODULE_DESCRIPTION("E3C EC168 driver"); | 
					
						
							| 
									
										
										
										
											2009-11-13 22:38:55 -03:00
										 |  |  | MODULE_LICENSE("GPL"); | 
					
						
							| 
									
										
										
										
											2012-09-12 11:37:27 -03:00
										 |  |  | MODULE_FIRMWARE(EC168_FIRMWARE); |