brintos

brintos / linux-shallow public Read only

0
0
Text · 6.9 KiB · 72aa6a9 Raw
290 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * ZyDAS ZD1301 driver (USB interface)4 *5 * Copyright (C) 2015 Antti Palosaari <crope@iki.fi>6 */7 8#include "dvb_usb.h"9#include "zd1301_demod.h"10#include "mt2060.h"11#include <linux/i2c.h>12#include <linux/platform_device.h>13 14DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);15 16struct zd1301_dev {17	#define BUF_LEN 818	u8 buf[BUF_LEN]; /* bulk USB control message */19	struct zd1301_demod_platform_data demod_pdata;20	struct mt2060_platform_data mt2060_pdata;21	struct platform_device *platform_device_demod;22	struct i2c_client *i2c_client_tuner;23};24 25static int zd1301_ctrl_msg(struct dvb_usb_device *d, const u8 *wbuf,26			   unsigned int wlen, u8 *rbuf, unsigned int rlen)27{28	struct zd1301_dev *dev = d_to_priv(d);29	struct usb_interface *intf = d->intf;30	int ret, actual_length;31 32	mutex_lock(&d->usb_mutex);33 34	memcpy(&dev->buf, wbuf, wlen);35 36	dev_dbg(&intf->dev, ">>> %*ph\n", wlen, dev->buf);37 38	ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, 0x04), dev->buf,39			   wlen, &actual_length, 1000);40	if (ret) {41		dev_err(&intf->dev, "1st usb_bulk_msg() failed %d\n", ret);42		goto err_mutex_unlock;43	}44 45	if (rlen) {46		ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev, 0x83),47				   dev->buf, rlen, &actual_length, 1000);48		if (ret) {49			dev_err(&intf->dev,50				"2nd usb_bulk_msg() failed %d\n", ret);51			goto err_mutex_unlock;52		}53 54		dev_dbg(&intf->dev, "<<< %*ph\n", actual_length, dev->buf);55 56		if (actual_length != rlen) {57			/*58			 * Chip replies often with 3 byte len stub. On that case59			 * we have to query new reply.60			 */61			dev_dbg(&intf->dev, "repeating reply message\n");62 63			ret = usb_bulk_msg(d->udev,64					   usb_rcvbulkpipe(d->udev, 0x83),65					   dev->buf, rlen, &actual_length,66					   1000);67			if (ret) {68				dev_err(&intf->dev,69					"3rd usb_bulk_msg() failed %d\n", ret);70				goto err_mutex_unlock;71			}72 73			dev_dbg(&intf->dev,74				"<<< %*ph\n", actual_length, dev->buf);75		}76 77		memcpy(rbuf, dev->buf, rlen);78	}79 80err_mutex_unlock:81	mutex_unlock(&d->usb_mutex);82	return ret;83}84 85static int zd1301_demod_wreg(void *reg_priv, u16 reg, u8 val)86{87	struct dvb_usb_device *d = reg_priv;88	struct usb_interface *intf = d->intf;89	int ret;90	u8 buf[7] = {0x07, 0x00, 0x03, 0x01,91		     (reg >> 0) & 0xff, (reg >> 8) & 0xff, val};92 93	ret = zd1301_ctrl_msg(d, buf, 7, NULL, 0);94	if (ret)95		goto err;96 97	return 0;98err:99	dev_dbg(&intf->dev, "failed=%d\n", ret);100	return ret;101}102 103static int zd1301_demod_rreg(void *reg_priv, u16 reg, u8 *val)104{105	struct dvb_usb_device *d = reg_priv;106	struct usb_interface *intf = d->intf;107	int ret;108	u8 buf[7] = {0x07, 0x00, 0x04, 0x01,109		     (reg >> 0) & 0xff, (reg >> 8) & 0xff, 0};110 111	ret = zd1301_ctrl_msg(d, buf, 7, buf, 7);112	if (ret)113		goto err;114 115	*val = buf[6];116 117	return 0;118err:119	dev_dbg(&intf->dev, "failed=%d\n", ret);120	return ret;121}122 123static int zd1301_frontend_attach(struct dvb_usb_adapter *adap)124{125	struct dvb_usb_device *d = adap_to_d(adap);126	struct zd1301_dev *dev = adap_to_priv(adap);127	struct usb_interface *intf = d->intf;128	struct platform_device *pdev;129	struct i2c_client *client;130	struct i2c_board_info board_info;131	struct i2c_adapter *adapter;132	struct dvb_frontend *frontend;133	int ret;134 135	dev_dbg(&intf->dev, "\n");136 137	/* Add platform demod */138	dev->demod_pdata.reg_priv = d;139	dev->demod_pdata.reg_read = zd1301_demod_rreg;140	dev->demod_pdata.reg_write = zd1301_demod_wreg;141	request_module("%s", "zd1301_demod");142	pdev = platform_device_register_data(&intf->dev,143					     "zd1301_demod",144					     PLATFORM_DEVID_AUTO,145					     &dev->demod_pdata,146					     sizeof(dev->demod_pdata));147	if (IS_ERR(pdev)) {148		ret = PTR_ERR(pdev);149		goto err;150	}151	if (!pdev->dev.driver) {152		ret = -ENODEV;153		goto err_platform_device_unregister;154	}155	if (!try_module_get(pdev->dev.driver->owner)) {156		ret = -ENODEV;157		goto err_platform_device_unregister;158	}159 160	adapter = zd1301_demod_get_i2c_adapter(pdev);161	frontend = zd1301_demod_get_dvb_frontend(pdev);162	if (!adapter || !frontend) {163		ret = -ENODEV;164		goto err_module_put_demod;165	}166 167	/* Add I2C tuner */168	dev->mt2060_pdata.i2c_write_max = 9;169	dev->mt2060_pdata.dvb_frontend = frontend;170	memset(&board_info, 0, sizeof(board_info));171	strscpy(board_info.type, "mt2060", I2C_NAME_SIZE);172	board_info.addr = 0x60;173	board_info.platform_data = &dev->mt2060_pdata;174	request_module("%s", "mt2060");175	client = i2c_new_client_device(adapter, &board_info);176	if (!i2c_client_has_driver(client)) {177		ret = -ENODEV;178		goto err_module_put_demod;179	}180	if (!try_module_get(client->dev.driver->owner)) {181		ret = -ENODEV;182		goto err_i2c_unregister_device;183	}184 185	dev->platform_device_demod = pdev;186	dev->i2c_client_tuner = client;187	adap->fe[0] = frontend;188 189	return 0;190err_i2c_unregister_device:191	i2c_unregister_device(client);192err_module_put_demod:193	module_put(pdev->dev.driver->owner);194err_platform_device_unregister:195	platform_device_unregister(pdev);196err:197	dev_dbg(&intf->dev, "failed=%d\n", ret);198	return ret;199}200 201static int zd1301_frontend_detach(struct dvb_usb_adapter *adap)202{203	struct dvb_usb_device *d = adap_to_d(adap);204	struct zd1301_dev *dev = d_to_priv(d);205	struct usb_interface *intf = d->intf;206	struct platform_device *pdev;207	struct i2c_client *client;208 209	dev_dbg(&intf->dev, "\n");210 211	client = dev->i2c_client_tuner;212	pdev = dev->platform_device_demod;213 214	/* Remove I2C tuner */215	if (client) {216		module_put(client->dev.driver->owner);217		i2c_unregister_device(client);218	}219 220	/* Remove platform demod */221	if (pdev) {222		module_put(pdev->dev.driver->owner);223		platform_device_unregister(pdev);224	}225 226	return 0;227}228 229static int zd1301_streaming_ctrl(struct dvb_frontend *fe, int onoff)230{231	struct dvb_usb_device *d = fe_to_d(fe);232	struct usb_interface *intf = d->intf;233	int ret;234	u8 buf[3] = {0x03, 0x00, onoff ? 0x07 : 0x08};235 236	dev_dbg(&intf->dev, "onoff=%d\n", onoff);237 238	ret = zd1301_ctrl_msg(d, buf, 3, NULL, 0);239	if (ret)240		goto err;241 242	return 0;243err:244	dev_dbg(&intf->dev, "failed=%d\n", ret);245	return ret;246}247 248static const struct dvb_usb_device_properties zd1301_props = {249	.driver_name = KBUILD_MODNAME,250	.owner = THIS_MODULE,251	.adapter_nr = adapter_nr,252	.size_of_priv = sizeof(struct zd1301_dev),253 254	.frontend_attach = zd1301_frontend_attach,255	.frontend_detach = zd1301_frontend_detach,256	.streaming_ctrl  = zd1301_streaming_ctrl,257 258	.num_adapters = 1,259	.adapter = {260		{261			.stream = DVB_USB_STREAM_BULK(0x81, 6, 21 * 188),262		},263	},264};265 266static const struct usb_device_id zd1301_id_table[] = {267	{DVB_USB_DEVICE(USB_VID_ZYDAS, 0x13a1, &zd1301_props,268			"ZyDAS ZD1301 reference design", NULL)},269	{}270};271MODULE_DEVICE_TABLE(usb, zd1301_id_table);272 273/* Usb specific object needed to register this driver with the usb subsystem */274static struct usb_driver zd1301_usb_driver = {275	.name = KBUILD_MODNAME,276	.id_table = zd1301_id_table,277	.probe = dvb_usbv2_probe,278	.disconnect = dvb_usbv2_disconnect,279	.suspend = dvb_usbv2_suspend,280	.resume = dvb_usbv2_resume,281	.reset_resume = dvb_usbv2_reset_resume,282	.no_dynamic_id = 1,283	.soft_unbind = 1,284};285module_usb_driver(zd1301_usb_driver);286 287MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");288MODULE_DESCRIPTION("ZyDAS ZD1301 driver");289MODULE_LICENSE("GPL");290