brintos

brintos / linux-shallow public Read only

0
0
Text · 8.7 KiB · 0e4773f Raw
379 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * E3C EC168 DVB USB driver4 *5 * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>6 */7 8#include "ec168.h"9#include "ec100.h"10#include "mxl5005s.h"11 12DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);13 14static int ec168_ctrl_msg(struct dvb_usb_device *d, struct ec168_req *req)15{16	int ret;17	unsigned int pipe;18	u8 request, requesttype;19	u8 *buf;20 21	switch (req->cmd) {22	case DOWNLOAD_FIRMWARE:23	case GPIO:24	case WRITE_I2C:25	case STREAMING_CTRL:26		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);27		request = req->cmd;28		break;29	case READ_I2C:30		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);31		request = req->cmd;32		break;33	case GET_CONFIG:34		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);35		request = CONFIG;36		break;37	case SET_CONFIG:38		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);39		request = CONFIG;40		break;41	case WRITE_DEMOD:42		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);43		request = DEMOD_RW;44		break;45	case READ_DEMOD:46		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);47		request = DEMOD_RW;48		break;49	default:50		dev_err(&d->udev->dev, "%s: unknown command=%02x\n",51				KBUILD_MODNAME, req->cmd);52		ret = -EINVAL;53		goto error;54	}55 56	buf = kmalloc(req->size, GFP_KERNEL);57	if (!buf) {58		ret = -ENOMEM;59		goto error;60	}61 62	if (requesttype == (USB_TYPE_VENDOR | USB_DIR_OUT)) {63		/* write */64		memcpy(buf, req->data, req->size);65		pipe = usb_sndctrlpipe(d->udev, 0);66	} else {67		/* read */68		pipe = usb_rcvctrlpipe(d->udev, 0);69	}70 71	msleep(1); /* avoid I2C errors */72 73	ret = usb_control_msg(d->udev, pipe, request, requesttype, req->value,74		req->index, buf, req->size, EC168_USB_TIMEOUT);75 76	dvb_usb_dbg_usb_control_msg(d->udev, request, requesttype, req->value,77			req->index, buf, req->size);78 79	if (ret < 0)80		goto err_dealloc;81	else82		ret = 0;83 84	/* read request, copy returned data to return buf */85	if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))86		memcpy(req->data, buf, req->size);87 88	kfree(buf);89	return ret;90 91err_dealloc:92	kfree(buf);93error:94	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);95	return ret;96}97 98/* I2C */99static struct ec100_config ec168_ec100_config;100 101static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],102	int num)103{104	struct dvb_usb_device *d = i2c_get_adapdata(adap);105	struct ec168_req req;106	int i = 0;107	int ret;108 109	if (num > 2)110		return -EINVAL;111 112	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)113		return -EAGAIN;114 115	while (i < num) {116		if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {117			if (msg[i].addr == ec168_ec100_config.demod_address) {118				if (msg[i].len < 1) {119					i = -EOPNOTSUPP;120					break;121				}122				req.cmd = READ_DEMOD;123				req.value = 0;124				req.index = 0xff00 + msg[i].buf[0]; /* reg */125				req.size = msg[i+1].len; /* bytes to read */126				req.data = &msg[i+1].buf[0];127				ret = ec168_ctrl_msg(d, &req);128				i += 2;129			} else {130				dev_err(&d->udev->dev, "%s: I2C read not " \131						"implemented\n",132						KBUILD_MODNAME);133				ret = -EOPNOTSUPP;134				i += 2;135			}136		} else {137			if (msg[i].addr == ec168_ec100_config.demod_address) {138				if (msg[i].len < 1) {139					i = -EOPNOTSUPP;140					break;141				}142				req.cmd = WRITE_DEMOD;143				req.value = msg[i].buf[1]; /* val */144				req.index = 0xff00 + msg[i].buf[0]; /* reg */145				req.size = 0;146				req.data = NULL;147				ret = ec168_ctrl_msg(d, &req);148				i += 1;149			} else {150				if (msg[i].len < 1) {151					i = -EOPNOTSUPP;152					break;153				}154				req.cmd = WRITE_I2C;155				req.value = msg[i].buf[0]; /* val */156				req.index = 0x0100 + msg[i].addr; /* I2C addr */157				req.size = msg[i].len-1;158				req.data = &msg[i].buf[1];159				ret = ec168_ctrl_msg(d, &req);160				i += 1;161			}162		}163		if (ret)164			goto error;165 166	}167	ret = i;168 169error:170	mutex_unlock(&d->i2c_mutex);171	return ret;172}173 174static u32 ec168_i2c_func(struct i2c_adapter *adapter)175{176	return I2C_FUNC_I2C;177}178 179static struct i2c_algorithm ec168_i2c_algo = {180	.master_xfer   = ec168_i2c_xfer,181	.functionality = ec168_i2c_func,182};183 184/* Callbacks for DVB USB */185static int ec168_identify_state(struct dvb_usb_device *d, const char **name)186{187	int ret;188	u8 reply;189	struct ec168_req req = {GET_CONFIG, 0, 1, sizeof(reply), &reply};190	dev_dbg(&d->udev->dev, "%s:\n", __func__);191 192	ret = ec168_ctrl_msg(d, &req);193	if (ret)194		goto error;195 196	dev_dbg(&d->udev->dev, "%s: reply=%02x\n", __func__, reply);197 198	if (reply == 0x01)199		ret = WARM;200	else201		ret = COLD;202 203	return ret;204error:205	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);206	return ret;207}208 209static int ec168_download_firmware(struct dvb_usb_device *d,210		const struct firmware *fw)211{212	int ret, len, remaining;213	struct ec168_req req = {DOWNLOAD_FIRMWARE, 0, 0, 0, NULL};214	dev_dbg(&d->udev->dev, "%s:\n", __func__);215 216	#define LEN_MAX 2048 /* max packet size */217	for (remaining = fw->size; remaining > 0; remaining -= LEN_MAX) {218		len = remaining;219		if (len > LEN_MAX)220			len = LEN_MAX;221 222		req.size = len;223		req.data = (u8 *) &fw->data[fw->size - remaining];224		req.index = fw->size - remaining;225 226		ret = ec168_ctrl_msg(d, &req);227		if (ret) {228			dev_err(&d->udev->dev,229					"%s: firmware download failed=%d\n",230					KBUILD_MODNAME, ret);231			goto error;232		}233	}234 235	req.size = 0;236 237	/* set "warm"? */238	req.cmd = SET_CONFIG;239	req.value = 0;240	req.index = 0x0001;241	ret = ec168_ctrl_msg(d, &req);242	if (ret)243		goto error;244 245	/* really needed - no idea what does */246	req.cmd = GPIO;247	req.value = 0;248	req.index = 0x0206;249	ret = ec168_ctrl_msg(d, &req);250	if (ret)251		goto error;252 253	/* activate tuner I2C? */254	req.cmd = WRITE_I2C;255	req.value = 0;256	req.index = 0x00c6;257	ret = ec168_ctrl_msg(d, &req);258	if (ret)259		goto error;260 261	return ret;262error:263	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);264	return ret;265}266 267static struct ec100_config ec168_ec100_config = {268	.demod_address = 0xff, /* not real address, demod is integrated */269};270 271static int ec168_ec100_frontend_attach(struct dvb_usb_adapter *adap)272{273	struct dvb_usb_device *d = adap_to_d(adap);274	dev_dbg(&d->udev->dev, "%s:\n", __func__);275 276	adap->fe[0] = dvb_attach(ec100_attach, &ec168_ec100_config,277			&d->i2c_adap);278	if (adap->fe[0] == NULL)279		return -ENODEV;280 281	return 0;282}283 284static struct mxl5005s_config ec168_mxl5003s_config = {285	.i2c_address     = 0xc6,286	.if_freq         = IF_FREQ_4570000HZ,287	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,288	.agc_mode        = MXL_SINGLE_AGC,289	.tracking_filter = MXL_TF_OFF,290	.rssi_enable     = MXL_RSSI_ENABLE,291	.cap_select      = MXL_CAP_SEL_ENABLE,292	.div_out         = MXL_DIV_OUT_4,293	.clock_out       = MXL_CLOCK_OUT_DISABLE,294	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,295	.top		 = MXL5005S_TOP_25P2,296	.mod_mode        = MXL_DIGITAL_MODE,297	.if_mode         = MXL_ZERO_IF,298	.AgcMasterByte   = 0x00,299};300 301static int ec168_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap)302{303	struct dvb_usb_device *d = adap_to_d(adap);304	dev_dbg(&d->udev->dev, "%s:\n", __func__);305 306	return dvb_attach(mxl5005s_attach, adap->fe[0], &d->i2c_adap,307			&ec168_mxl5003s_config) == NULL ? -ENODEV : 0;308}309 310static int ec168_streaming_ctrl(struct dvb_frontend *fe, int onoff)311{312	struct dvb_usb_device *d = fe_to_d(fe);313	struct ec168_req req = {STREAMING_CTRL, 0x7f01, 0x0202, 0, NULL};314	dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);315 316	if (onoff)317		req.index = 0x0102;318	return ec168_ctrl_msg(d, &req);319}320 321/* DVB USB Driver stuff */322/* bInterfaceNumber 0 is HID323 * bInterfaceNumber 1 is DVB-T */324static const struct dvb_usb_device_properties ec168_props = {325	.driver_name = KBUILD_MODNAME,326	.owner = THIS_MODULE,327	.adapter_nr = adapter_nr,328	.bInterfaceNumber = 1,329 330	.identify_state = ec168_identify_state,331	.firmware = EC168_FIRMWARE,332	.download_firmware = ec168_download_firmware,333 334	.i2c_algo = &ec168_i2c_algo,335	.frontend_attach = ec168_ec100_frontend_attach,336	.tuner_attach = ec168_mxl5003s_tuner_attach,337	.streaming_ctrl = ec168_streaming_ctrl,338 339	.num_adapters = 1,340	.adapter = {341		{342			.stream = DVB_USB_STREAM_BULK(0x82, 6, 32 * 512),343		}344	},345};346 347static const struct usb_device_id ec168_id[] = {348	{ DVB_USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168,349		     &ec168_props, "E3C EC168 reference design", NULL)},350	{ DVB_USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_2,351		     &ec168_props, "E3C EC168 reference design", NULL)},352	{ DVB_USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_3,353		     &ec168_props, "E3C EC168 reference design", NULL)},354	{ DVB_USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_4,355		     &ec168_props, "E3C EC168 reference design", NULL)},356	{ DVB_USB_DEVICE(USB_VID_E3C, USB_PID_E3C_EC168_5,357		     &ec168_props, "E3C EC168 reference design", NULL)},358	{}359};360MODULE_DEVICE_TABLE(usb, ec168_id);361 362static struct usb_driver ec168_driver = {363	.name = KBUILD_MODNAME,364	.id_table = ec168_id,365	.probe = dvb_usbv2_probe,366	.disconnect = dvb_usbv2_disconnect,367	.suspend = dvb_usbv2_suspend,368	.resume = dvb_usbv2_resume,369	.no_dynamic_id = 1,370	.soft_unbind = 1,371};372 373module_usb_driver(ec168_driver);374 375MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");376MODULE_DESCRIPTION("E3C EC168 driver");377MODULE_LICENSE("GPL");378MODULE_FIRMWARE(EC168_FIRMWARE);379