18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Realtek RTL28xxU DVB USB driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
68c2ecf20Sopenharmony_ci * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
78c2ecf20Sopenharmony_ci * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "rtl28xxu.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_cistatic int rtl28xxu_disable_rc;
138c2ecf20Sopenharmony_cimodule_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644);
148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller");
158c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d->priv;
208c2ecf20Sopenharmony_ci	int ret;
218c2ecf20Sopenharmony_ci	unsigned int pipe;
228c2ecf20Sopenharmony_ci	u8 requesttype;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	mutex_lock(&d->usb_mutex);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (req->size > sizeof(dev->buf)) {
278c2ecf20Sopenharmony_ci		dev_err(&d->intf->dev, "too large message %u\n", req->size);
288c2ecf20Sopenharmony_ci		ret = -EINVAL;
298c2ecf20Sopenharmony_ci		goto err_mutex_unlock;
308c2ecf20Sopenharmony_ci	}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (req->index & CMD_WR_FLAG) {
338c2ecf20Sopenharmony_ci		/* write */
348c2ecf20Sopenharmony_ci		memcpy(dev->buf, req->data, req->size);
358c2ecf20Sopenharmony_ci		requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
368c2ecf20Sopenharmony_ci		pipe = usb_sndctrlpipe(d->udev, 0);
378c2ecf20Sopenharmony_ci	} else {
388c2ecf20Sopenharmony_ci		/* read */
398c2ecf20Sopenharmony_ci		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci		/*
428c2ecf20Sopenharmony_ci		 * Zero-length transfers must use usb_sndctrlpipe() and
438c2ecf20Sopenharmony_ci		 * rtl28xxu_identify_state() uses a zero-length i2c read
448c2ecf20Sopenharmony_ci		 * command to determine the chip type.
458c2ecf20Sopenharmony_ci		 */
468c2ecf20Sopenharmony_ci		if (req->size)
478c2ecf20Sopenharmony_ci			pipe = usb_rcvctrlpipe(d->udev, 0);
488c2ecf20Sopenharmony_ci		else
498c2ecf20Sopenharmony_ci			pipe = usb_sndctrlpipe(d->udev, 0);
508c2ecf20Sopenharmony_ci	}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
538c2ecf20Sopenharmony_ci			req->index, dev->buf, req->size, 1000);
548c2ecf20Sopenharmony_ci	dvb_usb_dbg_usb_control_msg(d->udev, 0, requesttype, req->value,
558c2ecf20Sopenharmony_ci			req->index, dev->buf, req->size);
568c2ecf20Sopenharmony_ci	if (ret < 0)
578c2ecf20Sopenharmony_ci		goto err_mutex_unlock;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	/* read request, copy returned data to return buf */
608c2ecf20Sopenharmony_ci	if (requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
618c2ecf20Sopenharmony_ci		memcpy(req->data, dev->buf, req->size);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return 0;
668c2ecf20Sopenharmony_cierr_mutex_unlock:
678c2ecf20Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
688c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
698c2ecf20Sopenharmony_ci	return ret;
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_cistatic int rtl28xxu_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct rtl28xxu_req req;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	if (reg < 0x3000)
778c2ecf20Sopenharmony_ci		req.index = CMD_USB_WR;
788c2ecf20Sopenharmony_ci	else if (reg < 0x4000)
798c2ecf20Sopenharmony_ci		req.index = CMD_SYS_WR;
808c2ecf20Sopenharmony_ci	else
818c2ecf20Sopenharmony_ci		req.index = CMD_IR_WR;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	req.value = reg;
848c2ecf20Sopenharmony_ci	req.size = len;
858c2ecf20Sopenharmony_ci	req.data = val;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	return rtl28xxu_ctrl_msg(d, &req);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic int rtl28xxu_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	struct rtl28xxu_req req;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci	if (reg < 0x3000)
958c2ecf20Sopenharmony_ci		req.index = CMD_USB_RD;
968c2ecf20Sopenharmony_ci	else if (reg < 0x4000)
978c2ecf20Sopenharmony_ci		req.index = CMD_SYS_RD;
988c2ecf20Sopenharmony_ci	else
998c2ecf20Sopenharmony_ci		req.index = CMD_IR_RD;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	req.value = reg;
1028c2ecf20Sopenharmony_ci	req.size = len;
1038c2ecf20Sopenharmony_ci	req.data = val;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return rtl28xxu_ctrl_msg(d, &req);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic int rtl28xxu_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	return rtl28xxu_wr_regs(d, reg, &val, 1);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_cistatic int rtl28xxu_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	return rtl28xxu_rd_regs(d, reg, val, 1);
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic int rtl28xxu_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
1198c2ecf20Sopenharmony_ci		u8 mask)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	int ret;
1228c2ecf20Sopenharmony_ci	u8 tmp;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	/* no need for read if whole reg is written */
1258c2ecf20Sopenharmony_ci	if (mask != 0xff) {
1268c2ecf20Sopenharmony_ci		ret = rtl28xxu_rd_reg(d, reg, &tmp);
1278c2ecf20Sopenharmony_ci		if (ret)
1288c2ecf20Sopenharmony_ci			return ret;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci		val &= mask;
1318c2ecf20Sopenharmony_ci		tmp &= ~mask;
1328c2ecf20Sopenharmony_ci		val |= tmp;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return rtl28xxu_wr_reg(d, reg, val);
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/* I2C */
1398c2ecf20Sopenharmony_cistatic int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
1408c2ecf20Sopenharmony_ci	int num)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	int ret;
1438c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
1448c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d->priv;
1458c2ecf20Sopenharmony_ci	struct rtl28xxu_req req;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/*
1488c2ecf20Sopenharmony_ci	 * It is not known which are real I2C bus xfer limits, but testing
1498c2ecf20Sopenharmony_ci	 * with RTL2831U + MT2060 gives max RD 24 and max WR 22 bytes.
1508c2ecf20Sopenharmony_ci	 * TODO: find out RTL2832U lens
1518c2ecf20Sopenharmony_ci	 */
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/*
1548c2ecf20Sopenharmony_ci	 * I2C adapter logic looks rather complicated due to fact it handles
1558c2ecf20Sopenharmony_ci	 * three different access methods. Those methods are;
1568c2ecf20Sopenharmony_ci	 * 1) integrated demod access
1578c2ecf20Sopenharmony_ci	 * 2) old I2C access
1588c2ecf20Sopenharmony_ci	 * 3) new I2C access
1598c2ecf20Sopenharmony_ci	 *
1608c2ecf20Sopenharmony_ci	 * Used method is selected in order 1, 2, 3. Method 3 can handle all
1618c2ecf20Sopenharmony_ci	 * requests but there is two reasons why not use it always;
1628c2ecf20Sopenharmony_ci	 * 1) It is most expensive, usually two USB messages are needed
1638c2ecf20Sopenharmony_ci	 * 2) At least RTL2831U does not support it
1648c2ecf20Sopenharmony_ci	 *
1658c2ecf20Sopenharmony_ci	 * Method 3 is needed in case of I2C write+read (typical register read)
1668c2ecf20Sopenharmony_ci	 * where write is more than one byte.
1678c2ecf20Sopenharmony_ci	 */
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
1708c2ecf20Sopenharmony_ci		return -EAGAIN;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	if (num == 2 && !(msg[0].flags & I2C_M_RD) &&
1738c2ecf20Sopenharmony_ci		(msg[1].flags & I2C_M_RD)) {
1748c2ecf20Sopenharmony_ci		if (msg[0].len > 24 || msg[1].len > 24) {
1758c2ecf20Sopenharmony_ci			/* TODO: check msg[0].len max */
1768c2ecf20Sopenharmony_ci			ret = -EOPNOTSUPP;
1778c2ecf20Sopenharmony_ci			goto err_mutex_unlock;
1788c2ecf20Sopenharmony_ci		} else if (msg[0].addr == 0x10) {
1798c2ecf20Sopenharmony_ci			if (msg[0].len < 1 || msg[1].len < 1) {
1808c2ecf20Sopenharmony_ci				ret = -EOPNOTSUPP;
1818c2ecf20Sopenharmony_ci				goto err_mutex_unlock;
1828c2ecf20Sopenharmony_ci			}
1838c2ecf20Sopenharmony_ci			/* method 1 - integrated demod */
1848c2ecf20Sopenharmony_ci			if (msg[0].buf[0] == 0x00) {
1858c2ecf20Sopenharmony_ci				/* return demod page from driver cache */
1868c2ecf20Sopenharmony_ci				msg[1].buf[0] = dev->page;
1878c2ecf20Sopenharmony_ci				ret = 0;
1888c2ecf20Sopenharmony_ci			} else {
1898c2ecf20Sopenharmony_ci				req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
1908c2ecf20Sopenharmony_ci				req.index = CMD_DEMOD_RD | dev->page;
1918c2ecf20Sopenharmony_ci				req.size = msg[1].len;
1928c2ecf20Sopenharmony_ci				req.data = &msg[1].buf[0];
1938c2ecf20Sopenharmony_ci				ret = rtl28xxu_ctrl_msg(d, &req);
1948c2ecf20Sopenharmony_ci			}
1958c2ecf20Sopenharmony_ci		} else if (msg[0].len < 2) {
1968c2ecf20Sopenharmony_ci			if (msg[0].len < 1) {
1978c2ecf20Sopenharmony_ci				ret = -EOPNOTSUPP;
1988c2ecf20Sopenharmony_ci				goto err_mutex_unlock;
1998c2ecf20Sopenharmony_ci			}
2008c2ecf20Sopenharmony_ci			/* method 2 - old I2C */
2018c2ecf20Sopenharmony_ci			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
2028c2ecf20Sopenharmony_ci			req.index = CMD_I2C_RD;
2038c2ecf20Sopenharmony_ci			req.size = msg[1].len;
2048c2ecf20Sopenharmony_ci			req.data = &msg[1].buf[0];
2058c2ecf20Sopenharmony_ci			ret = rtl28xxu_ctrl_msg(d, &req);
2068c2ecf20Sopenharmony_ci		} else {
2078c2ecf20Sopenharmony_ci			/* method 3 - new I2C */
2088c2ecf20Sopenharmony_ci			req.value = (msg[0].addr << 1);
2098c2ecf20Sopenharmony_ci			req.index = CMD_I2C_DA_WR;
2108c2ecf20Sopenharmony_ci			req.size = msg[0].len;
2118c2ecf20Sopenharmony_ci			req.data = msg[0].buf;
2128c2ecf20Sopenharmony_ci			ret = rtl28xxu_ctrl_msg(d, &req);
2138c2ecf20Sopenharmony_ci			if (ret)
2148c2ecf20Sopenharmony_ci				goto err_mutex_unlock;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci			req.value = (msg[0].addr << 1);
2178c2ecf20Sopenharmony_ci			req.index = CMD_I2C_DA_RD;
2188c2ecf20Sopenharmony_ci			req.size = msg[1].len;
2198c2ecf20Sopenharmony_ci			req.data = msg[1].buf;
2208c2ecf20Sopenharmony_ci			ret = rtl28xxu_ctrl_msg(d, &req);
2218c2ecf20Sopenharmony_ci		}
2228c2ecf20Sopenharmony_ci	} else if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
2238c2ecf20Sopenharmony_ci		if (msg[0].len > 22) {
2248c2ecf20Sopenharmony_ci			/* TODO: check msg[0].len max */
2258c2ecf20Sopenharmony_ci			ret = -EOPNOTSUPP;
2268c2ecf20Sopenharmony_ci			goto err_mutex_unlock;
2278c2ecf20Sopenharmony_ci		} else if (msg[0].addr == 0x10) {
2288c2ecf20Sopenharmony_ci			if (msg[0].len < 1) {
2298c2ecf20Sopenharmony_ci				ret = -EOPNOTSUPP;
2308c2ecf20Sopenharmony_ci				goto err_mutex_unlock;
2318c2ecf20Sopenharmony_ci			}
2328c2ecf20Sopenharmony_ci			/* method 1 - integrated demod */
2338c2ecf20Sopenharmony_ci			if (msg[0].buf[0] == 0x00) {
2348c2ecf20Sopenharmony_ci				if (msg[0].len < 2) {
2358c2ecf20Sopenharmony_ci					ret = -EOPNOTSUPP;
2368c2ecf20Sopenharmony_ci					goto err_mutex_unlock;
2378c2ecf20Sopenharmony_ci				}
2388c2ecf20Sopenharmony_ci				/* save demod page for later demod access */
2398c2ecf20Sopenharmony_ci				dev->page = msg[0].buf[1];
2408c2ecf20Sopenharmony_ci				ret = 0;
2418c2ecf20Sopenharmony_ci			} else {
2428c2ecf20Sopenharmony_ci				req.value = (msg[0].buf[0] << 8) |
2438c2ecf20Sopenharmony_ci					(msg[0].addr << 1);
2448c2ecf20Sopenharmony_ci				req.index = CMD_DEMOD_WR | dev->page;
2458c2ecf20Sopenharmony_ci				req.size = msg[0].len-1;
2468c2ecf20Sopenharmony_ci				req.data = &msg[0].buf[1];
2478c2ecf20Sopenharmony_ci				ret = rtl28xxu_ctrl_msg(d, &req);
2488c2ecf20Sopenharmony_ci			}
2498c2ecf20Sopenharmony_ci		} else if ((msg[0].len < 23) && (!dev->new_i2c_write)) {
2508c2ecf20Sopenharmony_ci			if (msg[0].len < 1) {
2518c2ecf20Sopenharmony_ci				ret = -EOPNOTSUPP;
2528c2ecf20Sopenharmony_ci				goto err_mutex_unlock;
2538c2ecf20Sopenharmony_ci			}
2548c2ecf20Sopenharmony_ci			/* method 2 - old I2C */
2558c2ecf20Sopenharmony_ci			req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
2568c2ecf20Sopenharmony_ci			req.index = CMD_I2C_WR;
2578c2ecf20Sopenharmony_ci			req.size = msg[0].len-1;
2588c2ecf20Sopenharmony_ci			req.data = &msg[0].buf[1];
2598c2ecf20Sopenharmony_ci			ret = rtl28xxu_ctrl_msg(d, &req);
2608c2ecf20Sopenharmony_ci		} else {
2618c2ecf20Sopenharmony_ci			/* method 3 - new I2C */
2628c2ecf20Sopenharmony_ci			req.value = (msg[0].addr << 1);
2638c2ecf20Sopenharmony_ci			req.index = CMD_I2C_DA_WR;
2648c2ecf20Sopenharmony_ci			req.size = msg[0].len;
2658c2ecf20Sopenharmony_ci			req.data = msg[0].buf;
2668c2ecf20Sopenharmony_ci			ret = rtl28xxu_ctrl_msg(d, &req);
2678c2ecf20Sopenharmony_ci		}
2688c2ecf20Sopenharmony_ci	} else if (num == 1 && (msg[0].flags & I2C_M_RD)) {
2698c2ecf20Sopenharmony_ci		req.value = (msg[0].addr << 1);
2708c2ecf20Sopenharmony_ci		req.index = CMD_I2C_DA_RD;
2718c2ecf20Sopenharmony_ci		req.size = msg[0].len;
2728c2ecf20Sopenharmony_ci		req.data = msg[0].buf;
2738c2ecf20Sopenharmony_ci		ret = rtl28xxu_ctrl_msg(d, &req);
2748c2ecf20Sopenharmony_ci	} else {
2758c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
2768c2ecf20Sopenharmony_ci	}
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	/* Retry failed I2C messages */
2798c2ecf20Sopenharmony_ci	if (ret == -EPIPE)
2808c2ecf20Sopenharmony_ci		ret = -EAGAIN;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cierr_mutex_unlock:
2838c2ecf20Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	return ret ? ret : num;
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic u32 rtl28xxu_i2c_func(struct i2c_adapter *adapter)
2898c2ecf20Sopenharmony_ci{
2908c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic struct i2c_algorithm rtl28xxu_i2c_algo = {
2948c2ecf20Sopenharmony_ci	.master_xfer   = rtl28xxu_i2c_xfer,
2958c2ecf20Sopenharmony_ci	.functionality = rtl28xxu_i2c_func,
2968c2ecf20Sopenharmony_ci};
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_cistatic int rtl2831u_read_config(struct dvb_usb_device *d)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
3018c2ecf20Sopenharmony_ci	int ret;
3028c2ecf20Sopenharmony_ci	u8 buf[1];
3038c2ecf20Sopenharmony_ci	/* open RTL2831U/RTL2830 I2C gate */
3048c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x08"};
3058c2ecf20Sopenharmony_ci	/* tuner probes */
3068c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_mt2060 = {0x00c0, CMD_I2C_RD, 1, buf};
3078c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_qt1010 = {0x0fc4, CMD_I2C_RD, 1, buf};
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	/*
3128c2ecf20Sopenharmony_ci	 * RTL2831U GPIOs
3138c2ecf20Sopenharmony_ci	 * =========================================================
3148c2ecf20Sopenharmony_ci	 * GPIO0 | tuner#0 | 0 off | 1 on  | MXL5005S (?)
3158c2ecf20Sopenharmony_ci	 * GPIO2 | LED     | 0 off | 1 on  |
3168c2ecf20Sopenharmony_ci	 * GPIO4 | tuner#1 | 0 on  | 1 off | MT2060
3178c2ecf20Sopenharmony_ci	 */
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/* GPIO direction */
3208c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg(d, SYS_GPIO_DIR, 0x0a);
3218c2ecf20Sopenharmony_ci	if (ret)
3228c2ecf20Sopenharmony_ci		goto err;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	/* enable as output GPIO0, GPIO2, GPIO4 */
3258c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg(d, SYS_GPIO_OUT_EN, 0x15);
3268c2ecf20Sopenharmony_ci	if (ret)
3278c2ecf20Sopenharmony_ci		goto err;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	/*
3308c2ecf20Sopenharmony_ci	 * Probe used tuner. We need to know used tuner before demod attach
3318c2ecf20Sopenharmony_ci	 * since there is some demod params needed to set according to tuner.
3328c2ecf20Sopenharmony_ci	 */
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	/* demod needs some time to wake up */
3358c2ecf20Sopenharmony_ci	msleep(20);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	dev->tuner_name = "NONE";
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	/* open demod I2C gate */
3408c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_gate_open);
3418c2ecf20Sopenharmony_ci	if (ret)
3428c2ecf20Sopenharmony_ci		goto err;
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ci	/* check QT1010 ID(?) register; reg=0f val=2c */
3458c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_qt1010);
3468c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x2c) {
3478c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2830_QT1010;
3488c2ecf20Sopenharmony_ci		dev->tuner_name = "QT1010";
3498c2ecf20Sopenharmony_ci		goto found;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	/* open demod I2C gate */
3538c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_gate_open);
3548c2ecf20Sopenharmony_ci	if (ret)
3558c2ecf20Sopenharmony_ci		goto err;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	/* check MT2060 ID register; reg=00 val=63 */
3588c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_mt2060);
3598c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x63) {
3608c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2830_MT2060;
3618c2ecf20Sopenharmony_ci		dev->tuner_name = "MT2060";
3628c2ecf20Sopenharmony_ci		goto found;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	/* assume MXL5005S */
3668c2ecf20Sopenharmony_ci	dev->tuner = TUNER_RTL2830_MXL5005S;
3678c2ecf20Sopenharmony_ci	dev->tuner_name = "MXL5005S";
3688c2ecf20Sopenharmony_ci	goto found;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_cifound:
3718c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "tuner=%s\n", dev->tuner_name);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	return 0;
3748c2ecf20Sopenharmony_cierr:
3758c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
3768c2ecf20Sopenharmony_ci	return ret;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_cistatic int rtl2832u_read_config(struct dvb_usb_device *d)
3808c2ecf20Sopenharmony_ci{
3818c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
3828c2ecf20Sopenharmony_ci	int ret;
3838c2ecf20Sopenharmony_ci	u8 buf[2];
3848c2ecf20Sopenharmony_ci	/* open RTL2832U/RTL2832 I2C gate */
3858c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
3868c2ecf20Sopenharmony_ci	/* close RTL2832U/RTL2832 I2C gate */
3878c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
3888c2ecf20Sopenharmony_ci	/* tuner probes */
3898c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
3908c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_fc0013 = {0x00c6, CMD_I2C_RD, 1, buf};
3918c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_mt2266 = {0x00c0, CMD_I2C_RD, 1, buf};
3928c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
3938c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_mt2063 = {0x00c0, CMD_I2C_RD, 1, buf};
3948c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_max3543 = {0x00c0, CMD_I2C_RD, 1, buf};
3958c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_tua9001 = {0x7ec0, CMD_I2C_RD, 2, buf};
3968c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_mxl5007t = {0xd9c0, CMD_I2C_RD, 1, buf};
3978c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_e4000 = {0x02c8, CMD_I2C_RD, 1, buf};
3988c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
3998c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 1, buf};
4008c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf};
4018c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_mn88472 = {0xff38, CMD_I2C_RD, 1, buf};
4028c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_mn88473 = {0xff38, CMD_I2C_RD, 1, buf};
4038c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_cxd2837er = {0xfdd8, CMD_I2C_RD, 1, buf};
4048c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_si2157 = {0x00c0, CMD_I2C_RD, 1, buf};
4058c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_si2168 = {0x00c8, CMD_I2C_RD, 1, buf};
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* enable GPIO3 and GPIO6 as output */
4108c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x40);
4118c2ecf20Sopenharmony_ci	if (ret)
4128c2ecf20Sopenharmony_ci		goto err;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x48, 0x48);
4158c2ecf20Sopenharmony_ci	if (ret)
4168c2ecf20Sopenharmony_ci		goto err;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	/*
4198c2ecf20Sopenharmony_ci	 * Probe used tuner. We need to know used tuner before demod attach
4208c2ecf20Sopenharmony_ci	 * since there is some demod params needed to set according to tuner.
4218c2ecf20Sopenharmony_ci	 */
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	/* open demod I2C gate */
4248c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_gate_open);
4258c2ecf20Sopenharmony_ci	if (ret)
4268c2ecf20Sopenharmony_ci		goto err;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	dev->tuner_name = "NONE";
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	/* check FC0012 ID register; reg=00 val=a1 */
4318c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_fc0012);
4328c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0xa1) {
4338c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_FC0012;
4348c2ecf20Sopenharmony_ci		dev->tuner_name = "FC0012";
4358c2ecf20Sopenharmony_ci		goto tuner_found;
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	/* check FC0013 ID register; reg=00 val=a3 */
4398c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_fc0013);
4408c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0xa3) {
4418c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_FC0013;
4428c2ecf20Sopenharmony_ci		dev->tuner_name = "FC0013";
4438c2ecf20Sopenharmony_ci		goto tuner_found;
4448c2ecf20Sopenharmony_ci	}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci	/* check MT2266 ID register; reg=00 val=85 */
4478c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_mt2266);
4488c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x85) {
4498c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_MT2266;
4508c2ecf20Sopenharmony_ci		dev->tuner_name = "MT2266";
4518c2ecf20Sopenharmony_ci		goto tuner_found;
4528c2ecf20Sopenharmony_ci	}
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	/* check FC2580 ID register; reg=01 val=56 */
4558c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_fc2580);
4568c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x56) {
4578c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_FC2580;
4588c2ecf20Sopenharmony_ci		dev->tuner_name = "FC2580";
4598c2ecf20Sopenharmony_ci		goto tuner_found;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	/* check MT2063 ID register; reg=00 val=9e || 9c */
4638c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_mt2063);
4648c2ecf20Sopenharmony_ci	if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
4658c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_MT2063;
4668c2ecf20Sopenharmony_ci		dev->tuner_name = "MT2063";
4678c2ecf20Sopenharmony_ci		goto tuner_found;
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	/* check MAX3543 ID register; reg=00 val=38 */
4718c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_max3543);
4728c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x38) {
4738c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_MAX3543;
4748c2ecf20Sopenharmony_ci		dev->tuner_name = "MAX3543";
4758c2ecf20Sopenharmony_ci		goto tuner_found;
4768c2ecf20Sopenharmony_ci	}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/* check TUA9001 ID register; reg=7e val=2328 */
4798c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_tua9001);
4808c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
4818c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_TUA9001;
4828c2ecf20Sopenharmony_ci		dev->tuner_name = "TUA9001";
4838c2ecf20Sopenharmony_ci		goto tuner_found;
4848c2ecf20Sopenharmony_ci	}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_ci	/* check MXL5007R ID register; reg=d9 val=14 */
4878c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_mxl5007t);
4888c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x14) {
4898c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_MXL5007T;
4908c2ecf20Sopenharmony_ci		dev->tuner_name = "MXL5007T";
4918c2ecf20Sopenharmony_ci		goto tuner_found;
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	/* check E4000 ID register; reg=02 val=40 */
4958c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_e4000);
4968c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x40) {
4978c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_E4000;
4988c2ecf20Sopenharmony_ci		dev->tuner_name = "E4000";
4998c2ecf20Sopenharmony_ci		goto tuner_found;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	/* check TDA18272 ID register; reg=00 val=c760  */
5038c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_tda18272);
5048c2ecf20Sopenharmony_ci	if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
5058c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_TDA18272;
5068c2ecf20Sopenharmony_ci		dev->tuner_name = "TDA18272";
5078c2ecf20Sopenharmony_ci		goto tuner_found;
5088c2ecf20Sopenharmony_ci	}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	/* check R820T ID register; reg=00 val=69 */
5118c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_r820t);
5128c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x69) {
5138c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_R820T;
5148c2ecf20Sopenharmony_ci		dev->tuner_name = "R820T";
5158c2ecf20Sopenharmony_ci		goto tuner_found;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	/* check R828D ID register; reg=00 val=69 */
5198c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_r828d);
5208c2ecf20Sopenharmony_ci	if (ret == 0 && buf[0] == 0x69) {
5218c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_R828D;
5228c2ecf20Sopenharmony_ci		dev->tuner_name = "R828D";
5238c2ecf20Sopenharmony_ci		goto tuner_found;
5248c2ecf20Sopenharmony_ci	}
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	/* GPIO0 and GPIO5 to reset Si2157/Si2168 tuner and demod */
5278c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x21);
5288c2ecf20Sopenharmony_ci	if (ret)
5298c2ecf20Sopenharmony_ci		goto err;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x00, 0x21);
5328c2ecf20Sopenharmony_ci	if (ret)
5338c2ecf20Sopenharmony_ci		goto err;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	msleep(50);
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x21, 0x21);
5388c2ecf20Sopenharmony_ci	if (ret)
5398c2ecf20Sopenharmony_ci		goto err;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x21, 0x21);
5428c2ecf20Sopenharmony_ci	if (ret)
5438c2ecf20Sopenharmony_ci		goto err;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	msleep(50);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	/* check Si2157 ID register; reg=c0 val=80 */
5488c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_si2157);
5498c2ecf20Sopenharmony_ci	if (ret == 0 && ((buf[0] & 0x80) == 0x80)) {
5508c2ecf20Sopenharmony_ci		dev->tuner = TUNER_RTL2832_SI2157;
5518c2ecf20Sopenharmony_ci		dev->tuner_name = "SI2157";
5528c2ecf20Sopenharmony_ci		goto tuner_found;
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_cituner_found:
5568c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "tuner=%s\n", dev->tuner_name);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	/* probe slave demod */
5598c2ecf20Sopenharmony_ci	if (dev->tuner == TUNER_RTL2832_R828D) {
5608c2ecf20Sopenharmony_ci		/* power off slave demod on GPIO0 to reset CXD2837ER */
5618c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x01);
5628c2ecf20Sopenharmony_ci		if (ret)
5638c2ecf20Sopenharmony_ci			goto err;
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x00, 0x01);
5668c2ecf20Sopenharmony_ci		if (ret)
5678c2ecf20Sopenharmony_ci			goto err;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci		msleep(50);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci		/* power on slave demod on GPIO0 */
5728c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x01, 0x01);
5738c2ecf20Sopenharmony_ci		if (ret)
5748c2ecf20Sopenharmony_ci			goto err;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01);
5778c2ecf20Sopenharmony_ci		if (ret)
5788c2ecf20Sopenharmony_ci			goto err;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01);
5818c2ecf20Sopenharmony_ci		if (ret)
5828c2ecf20Sopenharmony_ci			goto err;
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci		/* slave demod needs some time to wake up */
5858c2ecf20Sopenharmony_ci		msleep(20);
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci		/* check slave answers */
5888c2ecf20Sopenharmony_ci		ret = rtl28xxu_ctrl_msg(d, &req_mn88472);
5898c2ecf20Sopenharmony_ci		if (ret == 0 && buf[0] == 0x02) {
5908c2ecf20Sopenharmony_ci			dev_dbg(&d->intf->dev, "MN88472 found\n");
5918c2ecf20Sopenharmony_ci			dev->slave_demod = SLAVE_DEMOD_MN88472;
5928c2ecf20Sopenharmony_ci			goto demod_found;
5938c2ecf20Sopenharmony_ci		}
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci		ret = rtl28xxu_ctrl_msg(d, &req_mn88473);
5968c2ecf20Sopenharmony_ci		if (ret == 0 && buf[0] == 0x03) {
5978c2ecf20Sopenharmony_ci			dev_dbg(&d->intf->dev, "MN88473 found\n");
5988c2ecf20Sopenharmony_ci			dev->slave_demod = SLAVE_DEMOD_MN88473;
5998c2ecf20Sopenharmony_ci			goto demod_found;
6008c2ecf20Sopenharmony_ci		}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci		ret = rtl28xxu_ctrl_msg(d, &req_cxd2837er);
6038c2ecf20Sopenharmony_ci		if (ret == 0 && buf[0] == 0xb1) {
6048c2ecf20Sopenharmony_ci			dev_dbg(&d->intf->dev, "CXD2837ER found\n");
6058c2ecf20Sopenharmony_ci			dev->slave_demod = SLAVE_DEMOD_CXD2837ER;
6068c2ecf20Sopenharmony_ci			goto demod_found;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci	if (dev->tuner == TUNER_RTL2832_SI2157) {
6108c2ecf20Sopenharmony_ci		/* check Si2168 ID register; reg=c8 val=80 */
6118c2ecf20Sopenharmony_ci		ret = rtl28xxu_ctrl_msg(d, &req_si2168);
6128c2ecf20Sopenharmony_ci		if (ret == 0 && ((buf[0] & 0x80) == 0x80)) {
6138c2ecf20Sopenharmony_ci			dev_dbg(&d->intf->dev, "Si2168 found\n");
6148c2ecf20Sopenharmony_ci			dev->slave_demod = SLAVE_DEMOD_SI2168;
6158c2ecf20Sopenharmony_ci			goto demod_found;
6168c2ecf20Sopenharmony_ci		}
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_cidemod_found:
6208c2ecf20Sopenharmony_ci	/* close demod I2C gate */
6218c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_gate_close);
6228c2ecf20Sopenharmony_ci	if (ret < 0)
6238c2ecf20Sopenharmony_ci		goto err;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	return 0;
6268c2ecf20Sopenharmony_cierr:
6278c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
6288c2ecf20Sopenharmony_ci	return ret;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic int rtl28xxu_read_config(struct dvb_usb_device *d)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	if (dev->chip_id == CHIP_ID_RTL2831U)
6368c2ecf20Sopenharmony_ci		return rtl2831u_read_config(d);
6378c2ecf20Sopenharmony_ci	else
6388c2ecf20Sopenharmony_ci		return rtl2832u_read_config(d);
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name)
6428c2ecf20Sopenharmony_ci{
6438c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
6448c2ecf20Sopenharmony_ci	int ret;
6458c2ecf20Sopenharmony_ci	struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 0, NULL};
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_ci	/*
6508c2ecf20Sopenharmony_ci	 * Detect chip type using I2C command that is not supported
6518c2ecf20Sopenharmony_ci	 * by old RTL2831U.
6528c2ecf20Sopenharmony_ci	 */
6538c2ecf20Sopenharmony_ci	ret = rtl28xxu_ctrl_msg(d, &req_demod_i2c);
6548c2ecf20Sopenharmony_ci	if (ret == -EPIPE) {
6558c2ecf20Sopenharmony_ci		dev->chip_id = CHIP_ID_RTL2831U;
6568c2ecf20Sopenharmony_ci	} else if (ret == 0) {
6578c2ecf20Sopenharmony_ci		dev->chip_id = CHIP_ID_RTL2832U;
6588c2ecf20Sopenharmony_ci	} else {
6598c2ecf20Sopenharmony_ci		dev_err(&d->intf->dev, "chip type detection failed %d\n", ret);
6608c2ecf20Sopenharmony_ci		goto err;
6618c2ecf20Sopenharmony_ci	}
6628c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "chip_id=%u\n", dev->chip_id);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	/* Retry failed I2C messages */
6658c2ecf20Sopenharmony_ci	d->i2c_adap.retries = 3;
6668c2ecf20Sopenharmony_ci	d->i2c_adap.timeout = msecs_to_jiffies(10);
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	return WARM;
6698c2ecf20Sopenharmony_cierr:
6708c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
6718c2ecf20Sopenharmony_ci	return ret;
6728c2ecf20Sopenharmony_ci}
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic const struct rtl2830_platform_data rtl2830_mt2060_platform_data = {
6758c2ecf20Sopenharmony_ci	.clk = 28800000,
6768c2ecf20Sopenharmony_ci	.spec_inv = 1,
6778c2ecf20Sopenharmony_ci	.vtop = 0x20,
6788c2ecf20Sopenharmony_ci	.krf = 0x04,
6798c2ecf20Sopenharmony_ci	.agc_targ_val = 0x2d,
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci};
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_cistatic const struct rtl2830_platform_data rtl2830_qt1010_platform_data = {
6848c2ecf20Sopenharmony_ci	.clk = 28800000,
6858c2ecf20Sopenharmony_ci	.spec_inv = 1,
6868c2ecf20Sopenharmony_ci	.vtop = 0x20,
6878c2ecf20Sopenharmony_ci	.krf = 0x04,
6888c2ecf20Sopenharmony_ci	.agc_targ_val = 0x2d,
6898c2ecf20Sopenharmony_ci};
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_cistatic const struct rtl2830_platform_data rtl2830_mxl5005s_platform_data = {
6928c2ecf20Sopenharmony_ci	.clk = 28800000,
6938c2ecf20Sopenharmony_ci	.spec_inv = 0,
6948c2ecf20Sopenharmony_ci	.vtop = 0x3f,
6958c2ecf20Sopenharmony_ci	.krf = 0x04,
6968c2ecf20Sopenharmony_ci	.agc_targ_val = 0x3e,
6978c2ecf20Sopenharmony_ci};
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_cistatic int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
7008c2ecf20Sopenharmony_ci{
7018c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
7028c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
7038c2ecf20Sopenharmony_ci	struct rtl2830_platform_data *pdata = &dev->rtl2830_platform_data;
7048c2ecf20Sopenharmony_ci	struct i2c_board_info board_info;
7058c2ecf20Sopenharmony_ci	struct i2c_client *client;
7068c2ecf20Sopenharmony_ci	int ret;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	switch (dev->tuner) {
7118c2ecf20Sopenharmony_ci	case TUNER_RTL2830_QT1010:
7128c2ecf20Sopenharmony_ci		*pdata = rtl2830_qt1010_platform_data;
7138c2ecf20Sopenharmony_ci		break;
7148c2ecf20Sopenharmony_ci	case TUNER_RTL2830_MT2060:
7158c2ecf20Sopenharmony_ci		*pdata = rtl2830_mt2060_platform_data;
7168c2ecf20Sopenharmony_ci		break;
7178c2ecf20Sopenharmony_ci	case TUNER_RTL2830_MXL5005S:
7188c2ecf20Sopenharmony_ci		*pdata = rtl2830_mxl5005s_platform_data;
7198c2ecf20Sopenharmony_ci		break;
7208c2ecf20Sopenharmony_ci	default:
7218c2ecf20Sopenharmony_ci		dev_err(&d->intf->dev, "unknown tuner %s\n", dev->tuner_name);
7228c2ecf20Sopenharmony_ci		ret = -ENODEV;
7238c2ecf20Sopenharmony_ci		goto err;
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	/* attach demodulator */
7278c2ecf20Sopenharmony_ci	memset(&board_info, 0, sizeof(board_info));
7288c2ecf20Sopenharmony_ci	strscpy(board_info.type, "rtl2830", I2C_NAME_SIZE);
7298c2ecf20Sopenharmony_ci	board_info.addr = 0x10;
7308c2ecf20Sopenharmony_ci	board_info.platform_data = pdata;
7318c2ecf20Sopenharmony_ci	request_module("%s", board_info.type);
7328c2ecf20Sopenharmony_ci	client = i2c_new_client_device(&d->i2c_adap, &board_info);
7338c2ecf20Sopenharmony_ci	if (!i2c_client_has_driver(client)) {
7348c2ecf20Sopenharmony_ci		ret = -ENODEV;
7358c2ecf20Sopenharmony_ci		goto err;
7368c2ecf20Sopenharmony_ci	}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	if (!try_module_get(client->dev.driver->owner)) {
7398c2ecf20Sopenharmony_ci		i2c_unregister_device(client);
7408c2ecf20Sopenharmony_ci		ret = -ENODEV;
7418c2ecf20Sopenharmony_ci		goto err;
7428c2ecf20Sopenharmony_ci	}
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	adap->fe[0] = pdata->get_dvb_frontend(client);
7458c2ecf20Sopenharmony_ci	dev->demod_i2c_adapter = pdata->get_i2c_adapter(client);
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	dev->i2c_client_demod = client;
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	return 0;
7508c2ecf20Sopenharmony_cierr:
7518c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
7528c2ecf20Sopenharmony_ci	return ret;
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic const struct rtl2832_platform_data rtl2832_fc2580_platform_data = {
7568c2ecf20Sopenharmony_ci	.clk = 28800000,
7578c2ecf20Sopenharmony_ci	.tuner = TUNER_RTL2832_FC2580,
7588c2ecf20Sopenharmony_ci};
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_cistatic const struct rtl2832_platform_data rtl2832_fc0012_platform_data = {
7618c2ecf20Sopenharmony_ci	.clk = 28800000,
7628c2ecf20Sopenharmony_ci	.tuner = TUNER_RTL2832_FC0012
7638c2ecf20Sopenharmony_ci};
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_cistatic const struct rtl2832_platform_data rtl2832_fc0013_platform_data = {
7668c2ecf20Sopenharmony_ci	.clk = 28800000,
7678c2ecf20Sopenharmony_ci	.tuner = TUNER_RTL2832_FC0013
7688c2ecf20Sopenharmony_ci};
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_cistatic const struct rtl2832_platform_data rtl2832_tua9001_platform_data = {
7718c2ecf20Sopenharmony_ci	.clk = 28800000,
7728c2ecf20Sopenharmony_ci	.tuner = TUNER_RTL2832_TUA9001,
7738c2ecf20Sopenharmony_ci};
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic const struct rtl2832_platform_data rtl2832_e4000_platform_data = {
7768c2ecf20Sopenharmony_ci	.clk = 28800000,
7778c2ecf20Sopenharmony_ci	.tuner = TUNER_RTL2832_E4000,
7788c2ecf20Sopenharmony_ci};
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cistatic const struct rtl2832_platform_data rtl2832_r820t_platform_data = {
7818c2ecf20Sopenharmony_ci	.clk = 28800000,
7828c2ecf20Sopenharmony_ci	.tuner = TUNER_RTL2832_R820T,
7838c2ecf20Sopenharmony_ci};
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_cistatic const struct rtl2832_platform_data rtl2832_si2157_platform_data = {
7868c2ecf20Sopenharmony_ci	.clk = 28800000,
7878c2ecf20Sopenharmony_ci	.tuner = TUNER_RTL2832_SI2157,
7888c2ecf20Sopenharmony_ci};
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cistatic int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
7918c2ecf20Sopenharmony_ci		int cmd, int arg)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	int ret;
7948c2ecf20Sopenharmony_ci	u8 val;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "cmd=%d arg=%d\n", cmd, arg);
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci	switch (cmd) {
7998c2ecf20Sopenharmony_ci	case FC_FE_CALLBACK_VHF_ENABLE:
8008c2ecf20Sopenharmony_ci		/* set output values */
8018c2ecf20Sopenharmony_ci		ret = rtl28xxu_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
8028c2ecf20Sopenharmony_ci		if (ret)
8038c2ecf20Sopenharmony_ci			goto err;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci		if (arg)
8068c2ecf20Sopenharmony_ci			val &= 0xbf; /* set GPIO6 low */
8078c2ecf20Sopenharmony_ci		else
8088c2ecf20Sopenharmony_ci			val |= 0x40; /* set GPIO6 high */
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg(d, SYS_GPIO_OUT_VAL, val);
8128c2ecf20Sopenharmony_ci		if (ret)
8138c2ecf20Sopenharmony_ci			goto err;
8148c2ecf20Sopenharmony_ci		break;
8158c2ecf20Sopenharmony_ci	default:
8168c2ecf20Sopenharmony_ci		ret = -EINVAL;
8178c2ecf20Sopenharmony_ci		goto err;
8188c2ecf20Sopenharmony_ci	}
8198c2ecf20Sopenharmony_ci	return 0;
8208c2ecf20Sopenharmony_cierr:
8218c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
8228c2ecf20Sopenharmony_ci	return ret;
8238c2ecf20Sopenharmony_ci}
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_cistatic int rtl2832u_tua9001_tuner_callback(struct dvb_usb_device *d,
8268c2ecf20Sopenharmony_ci		int cmd, int arg)
8278c2ecf20Sopenharmony_ci{
8288c2ecf20Sopenharmony_ci	int ret;
8298c2ecf20Sopenharmony_ci	u8 val;
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "cmd=%d arg=%d\n", cmd, arg);
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	/*
8348c2ecf20Sopenharmony_ci	 * CEN     always enabled by hardware wiring
8358c2ecf20Sopenharmony_ci	 * RESETN  GPIO4
8368c2ecf20Sopenharmony_ci	 * RXEN    GPIO1
8378c2ecf20Sopenharmony_ci	 */
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci	switch (cmd) {
8408c2ecf20Sopenharmony_ci	case TUA9001_CMD_RESETN:
8418c2ecf20Sopenharmony_ci		if (arg)
8428c2ecf20Sopenharmony_ci			val = (1 << 4);
8438c2ecf20Sopenharmony_ci		else
8448c2ecf20Sopenharmony_ci			val = (0 << 4);
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x10);
8478c2ecf20Sopenharmony_ci		if (ret)
8488c2ecf20Sopenharmony_ci			goto err;
8498c2ecf20Sopenharmony_ci		break;
8508c2ecf20Sopenharmony_ci	case TUA9001_CMD_RXEN:
8518c2ecf20Sopenharmony_ci		if (arg)
8528c2ecf20Sopenharmony_ci			val = (1 << 1);
8538c2ecf20Sopenharmony_ci		else
8548c2ecf20Sopenharmony_ci			val = (0 << 1);
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x02);
8578c2ecf20Sopenharmony_ci		if (ret)
8588c2ecf20Sopenharmony_ci			goto err;
8598c2ecf20Sopenharmony_ci		break;
8608c2ecf20Sopenharmony_ci	}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	return 0;
8638c2ecf20Sopenharmony_cierr:
8648c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
8658c2ecf20Sopenharmony_ci	return ret;
8668c2ecf20Sopenharmony_ci}
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_cistatic int rtl2832u_frontend_callback(void *adapter_priv, int component,
8698c2ecf20Sopenharmony_ci		int cmd, int arg)
8708c2ecf20Sopenharmony_ci{
8718c2ecf20Sopenharmony_ci	struct i2c_adapter *adapter = adapter_priv;
8728c2ecf20Sopenharmony_ci	struct device *parent = adapter->dev.parent;
8738c2ecf20Sopenharmony_ci	struct i2c_adapter *parent_adapter;
8748c2ecf20Sopenharmony_ci	struct dvb_usb_device *d;
8758c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev;
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	/*
8788c2ecf20Sopenharmony_ci	 * All tuners are connected to demod muxed I2C adapter. We have to
8798c2ecf20Sopenharmony_ci	 * resolve its parent adapter in order to get handle for this driver
8808c2ecf20Sopenharmony_ci	 * private data. That is a bit hackish solution, GPIO or direct driver
8818c2ecf20Sopenharmony_ci	 * callback would be better...
8828c2ecf20Sopenharmony_ci	 */
8838c2ecf20Sopenharmony_ci	if (parent != NULL && parent->type == &i2c_adapter_type)
8848c2ecf20Sopenharmony_ci		parent_adapter = to_i2c_adapter(parent);
8858c2ecf20Sopenharmony_ci	else
8868c2ecf20Sopenharmony_ci		return -EINVAL;
8878c2ecf20Sopenharmony_ci
8888c2ecf20Sopenharmony_ci	d = i2c_get_adapdata(parent_adapter);
8898c2ecf20Sopenharmony_ci	dev = d->priv;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "component=%d cmd=%d arg=%d\n",
8928c2ecf20Sopenharmony_ci		component, cmd, arg);
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	switch (component) {
8958c2ecf20Sopenharmony_ci	case DVB_FRONTEND_COMPONENT_TUNER:
8968c2ecf20Sopenharmony_ci		switch (dev->tuner) {
8978c2ecf20Sopenharmony_ci		case TUNER_RTL2832_FC0012:
8988c2ecf20Sopenharmony_ci			return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
8998c2ecf20Sopenharmony_ci		case TUNER_RTL2832_TUA9001:
9008c2ecf20Sopenharmony_ci			return rtl2832u_tua9001_tuner_callback(d, cmd, arg);
9018c2ecf20Sopenharmony_ci		}
9028c2ecf20Sopenharmony_ci	}
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci	return 0;
9058c2ecf20Sopenharmony_ci}
9068c2ecf20Sopenharmony_ci
9078c2ecf20Sopenharmony_cistatic int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
9088c2ecf20Sopenharmony_ci{
9098c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
9108c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
9118c2ecf20Sopenharmony_ci	struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data;
9128c2ecf20Sopenharmony_ci	struct i2c_board_info board_info;
9138c2ecf20Sopenharmony_ci	struct i2c_client *client;
9148c2ecf20Sopenharmony_ci	int ret;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	switch (dev->tuner) {
9198c2ecf20Sopenharmony_ci	case TUNER_RTL2832_FC0012:
9208c2ecf20Sopenharmony_ci		*pdata = rtl2832_fc0012_platform_data;
9218c2ecf20Sopenharmony_ci		break;
9228c2ecf20Sopenharmony_ci	case TUNER_RTL2832_FC0013:
9238c2ecf20Sopenharmony_ci		*pdata = rtl2832_fc0013_platform_data;
9248c2ecf20Sopenharmony_ci		break;
9258c2ecf20Sopenharmony_ci	case TUNER_RTL2832_FC2580:
9268c2ecf20Sopenharmony_ci		*pdata = rtl2832_fc2580_platform_data;
9278c2ecf20Sopenharmony_ci		break;
9288c2ecf20Sopenharmony_ci	case TUNER_RTL2832_TUA9001:
9298c2ecf20Sopenharmony_ci		*pdata = rtl2832_tua9001_platform_data;
9308c2ecf20Sopenharmony_ci		break;
9318c2ecf20Sopenharmony_ci	case TUNER_RTL2832_E4000:
9328c2ecf20Sopenharmony_ci		*pdata = rtl2832_e4000_platform_data;
9338c2ecf20Sopenharmony_ci		break;
9348c2ecf20Sopenharmony_ci	case TUNER_RTL2832_R820T:
9358c2ecf20Sopenharmony_ci	case TUNER_RTL2832_R828D:
9368c2ecf20Sopenharmony_ci		*pdata = rtl2832_r820t_platform_data;
9378c2ecf20Sopenharmony_ci		break;
9388c2ecf20Sopenharmony_ci	case TUNER_RTL2832_SI2157:
9398c2ecf20Sopenharmony_ci		*pdata = rtl2832_si2157_platform_data;
9408c2ecf20Sopenharmony_ci		break;
9418c2ecf20Sopenharmony_ci	default:
9428c2ecf20Sopenharmony_ci		dev_err(&d->intf->dev, "unknown tuner %s\n", dev->tuner_name);
9438c2ecf20Sopenharmony_ci		ret = -ENODEV;
9448c2ecf20Sopenharmony_ci		goto err;
9458c2ecf20Sopenharmony_ci	}
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/* attach demodulator */
9488c2ecf20Sopenharmony_ci	memset(&board_info, 0, sizeof(board_info));
9498c2ecf20Sopenharmony_ci	strscpy(board_info.type, "rtl2832", I2C_NAME_SIZE);
9508c2ecf20Sopenharmony_ci	board_info.addr = 0x10;
9518c2ecf20Sopenharmony_ci	board_info.platform_data = pdata;
9528c2ecf20Sopenharmony_ci	request_module("%s", board_info.type);
9538c2ecf20Sopenharmony_ci	client = i2c_new_client_device(&d->i2c_adap, &board_info);
9548c2ecf20Sopenharmony_ci	if (!i2c_client_has_driver(client)) {
9558c2ecf20Sopenharmony_ci		ret = -ENODEV;
9568c2ecf20Sopenharmony_ci		goto err;
9578c2ecf20Sopenharmony_ci	}
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	if (!try_module_get(client->dev.driver->owner)) {
9608c2ecf20Sopenharmony_ci		i2c_unregister_device(client);
9618c2ecf20Sopenharmony_ci		ret = -ENODEV;
9628c2ecf20Sopenharmony_ci		goto err;
9638c2ecf20Sopenharmony_ci	}
9648c2ecf20Sopenharmony_ci
9658c2ecf20Sopenharmony_ci	adap->fe[0] = pdata->get_dvb_frontend(client);
9668c2ecf20Sopenharmony_ci	dev->demod_i2c_adapter = pdata->get_i2c_adapter(client);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	dev->i2c_client_demod = client;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci	/* set fe callback */
9718c2ecf20Sopenharmony_ci	adap->fe[0]->callback = rtl2832u_frontend_callback;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	if (dev->slave_demod) {
9748c2ecf20Sopenharmony_ci		struct i2c_board_info info = {};
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci		/*
9778c2ecf20Sopenharmony_ci		 * We continue on reduced mode, without DVB-T2/C, using master
9788c2ecf20Sopenharmony_ci		 * demod, when slave demod fails.
9798c2ecf20Sopenharmony_ci		 */
9808c2ecf20Sopenharmony_ci		ret = 0;
9818c2ecf20Sopenharmony_ci
9828c2ecf20Sopenharmony_ci		/* attach slave demodulator */
9838c2ecf20Sopenharmony_ci		if (dev->slave_demod == SLAVE_DEMOD_MN88472) {
9848c2ecf20Sopenharmony_ci			struct mn88472_config mn88472_config = {};
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci			mn88472_config.fe = &adap->fe[1];
9878c2ecf20Sopenharmony_ci			mn88472_config.i2c_wr_max = 22,
9888c2ecf20Sopenharmony_ci			strscpy(info.type, "mn88472", I2C_NAME_SIZE);
9898c2ecf20Sopenharmony_ci			mn88472_config.xtal = 20500000;
9908c2ecf20Sopenharmony_ci			mn88472_config.ts_mode = SERIAL_TS_MODE;
9918c2ecf20Sopenharmony_ci			mn88472_config.ts_clock = VARIABLE_TS_CLOCK;
9928c2ecf20Sopenharmony_ci			info.addr = 0x18;
9938c2ecf20Sopenharmony_ci			info.platform_data = &mn88472_config;
9948c2ecf20Sopenharmony_ci			request_module(info.type);
9958c2ecf20Sopenharmony_ci			client = i2c_new_client_device(&d->i2c_adap, &info);
9968c2ecf20Sopenharmony_ci			if (!i2c_client_has_driver(client)) {
9978c2ecf20Sopenharmony_ci				dev->slave_demod = SLAVE_DEMOD_NONE;
9988c2ecf20Sopenharmony_ci				goto err_slave_demod_failed;
9998c2ecf20Sopenharmony_ci			}
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci			if (!try_module_get(client->dev.driver->owner)) {
10028c2ecf20Sopenharmony_ci				i2c_unregister_device(client);
10038c2ecf20Sopenharmony_ci				dev->slave_demod = SLAVE_DEMOD_NONE;
10048c2ecf20Sopenharmony_ci				goto err_slave_demod_failed;
10058c2ecf20Sopenharmony_ci			}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci			dev->i2c_client_slave_demod = client;
10088c2ecf20Sopenharmony_ci		} else if (dev->slave_demod == SLAVE_DEMOD_MN88473) {
10098c2ecf20Sopenharmony_ci			struct mn88473_config mn88473_config = {};
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci			mn88473_config.fe = &adap->fe[1];
10128c2ecf20Sopenharmony_ci			mn88473_config.i2c_wr_max = 22,
10138c2ecf20Sopenharmony_ci			strscpy(info.type, "mn88473", I2C_NAME_SIZE);
10148c2ecf20Sopenharmony_ci			info.addr = 0x18;
10158c2ecf20Sopenharmony_ci			info.platform_data = &mn88473_config;
10168c2ecf20Sopenharmony_ci			request_module(info.type);
10178c2ecf20Sopenharmony_ci			client = i2c_new_client_device(&d->i2c_adap, &info);
10188c2ecf20Sopenharmony_ci			if (!i2c_client_has_driver(client)) {
10198c2ecf20Sopenharmony_ci				dev->slave_demod = SLAVE_DEMOD_NONE;
10208c2ecf20Sopenharmony_ci				goto err_slave_demod_failed;
10218c2ecf20Sopenharmony_ci			}
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci			if (!try_module_get(client->dev.driver->owner)) {
10248c2ecf20Sopenharmony_ci				i2c_unregister_device(client);
10258c2ecf20Sopenharmony_ci				dev->slave_demod = SLAVE_DEMOD_NONE;
10268c2ecf20Sopenharmony_ci				goto err_slave_demod_failed;
10278c2ecf20Sopenharmony_ci			}
10288c2ecf20Sopenharmony_ci
10298c2ecf20Sopenharmony_ci			dev->i2c_client_slave_demod = client;
10308c2ecf20Sopenharmony_ci		} else if (dev->slave_demod == SLAVE_DEMOD_CXD2837ER) {
10318c2ecf20Sopenharmony_ci			struct cxd2841er_config cxd2837er_config = {};
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci			cxd2837er_config.i2c_addr = 0xd8;
10348c2ecf20Sopenharmony_ci			cxd2837er_config.xtal = SONY_XTAL_20500;
10358c2ecf20Sopenharmony_ci			cxd2837er_config.flags = (CXD2841ER_AUTO_IFHZ |
10368c2ecf20Sopenharmony_ci				CXD2841ER_NO_AGCNEG | CXD2841ER_TSBITS |
10378c2ecf20Sopenharmony_ci				CXD2841ER_EARLY_TUNE | CXD2841ER_TS_SERIAL);
10388c2ecf20Sopenharmony_ci			adap->fe[1] = dvb_attach(cxd2841er_attach_t_c,
10398c2ecf20Sopenharmony_ci						 &cxd2837er_config,
10408c2ecf20Sopenharmony_ci						 &d->i2c_adap);
10418c2ecf20Sopenharmony_ci			if (!adap->fe[1]) {
10428c2ecf20Sopenharmony_ci				dev->slave_demod = SLAVE_DEMOD_NONE;
10438c2ecf20Sopenharmony_ci				goto err_slave_demod_failed;
10448c2ecf20Sopenharmony_ci			}
10458c2ecf20Sopenharmony_ci			adap->fe[1]->id = 1;
10468c2ecf20Sopenharmony_ci			dev->i2c_client_slave_demod = NULL;
10478c2ecf20Sopenharmony_ci		} else {
10488c2ecf20Sopenharmony_ci			struct si2168_config si2168_config = {};
10498c2ecf20Sopenharmony_ci			struct i2c_adapter *adapter;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci			si2168_config.i2c_adapter = &adapter;
10528c2ecf20Sopenharmony_ci			si2168_config.fe = &adap->fe[1];
10538c2ecf20Sopenharmony_ci			si2168_config.ts_mode = SI2168_TS_SERIAL;
10548c2ecf20Sopenharmony_ci			si2168_config.ts_clock_inv = false;
10558c2ecf20Sopenharmony_ci			si2168_config.ts_clock_gapped = true;
10568c2ecf20Sopenharmony_ci			strscpy(info.type, "si2168", I2C_NAME_SIZE);
10578c2ecf20Sopenharmony_ci			info.addr = 0x64;
10588c2ecf20Sopenharmony_ci			info.platform_data = &si2168_config;
10598c2ecf20Sopenharmony_ci			request_module(info.type);
10608c2ecf20Sopenharmony_ci			client = i2c_new_client_device(&d->i2c_adap, &info);
10618c2ecf20Sopenharmony_ci			if (!i2c_client_has_driver(client)) {
10628c2ecf20Sopenharmony_ci				dev->slave_demod = SLAVE_DEMOD_NONE;
10638c2ecf20Sopenharmony_ci				goto err_slave_demod_failed;
10648c2ecf20Sopenharmony_ci			}
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci			if (!try_module_get(client->dev.driver->owner)) {
10678c2ecf20Sopenharmony_ci				i2c_unregister_device(client);
10688c2ecf20Sopenharmony_ci				dev->slave_demod = SLAVE_DEMOD_NONE;
10698c2ecf20Sopenharmony_ci				goto err_slave_demod_failed;
10708c2ecf20Sopenharmony_ci			}
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci			dev->i2c_client_slave_demod = client;
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci			/* for Si2168 devices use only new I2C write method */
10758c2ecf20Sopenharmony_ci			dev->new_i2c_write = true;
10768c2ecf20Sopenharmony_ci		}
10778c2ecf20Sopenharmony_ci	}
10788c2ecf20Sopenharmony_ci	return 0;
10798c2ecf20Sopenharmony_cierr_slave_demod_failed:
10808c2ecf20Sopenharmony_cierr:
10818c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
10828c2ecf20Sopenharmony_ci	return ret;
10838c2ecf20Sopenharmony_ci}
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_cistatic int rtl28xxu_frontend_attach(struct dvb_usb_adapter *adap)
10868c2ecf20Sopenharmony_ci{
10878c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = adap_to_priv(adap);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	if (dev->chip_id == CHIP_ID_RTL2831U)
10908c2ecf20Sopenharmony_ci		return rtl2831u_frontend_attach(adap);
10918c2ecf20Sopenharmony_ci	else
10928c2ecf20Sopenharmony_ci		return rtl2832u_frontend_attach(adap);
10938c2ecf20Sopenharmony_ci}
10948c2ecf20Sopenharmony_ci
10958c2ecf20Sopenharmony_cistatic int rtl28xxu_frontend_detach(struct dvb_usb_adapter *adap)
10968c2ecf20Sopenharmony_ci{
10978c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
10988c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
10998c2ecf20Sopenharmony_ci	struct i2c_client *client;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	/* remove I2C slave demod */
11048c2ecf20Sopenharmony_ci	client = dev->i2c_client_slave_demod;
11058c2ecf20Sopenharmony_ci	if (client) {
11068c2ecf20Sopenharmony_ci		module_put(client->dev.driver->owner);
11078c2ecf20Sopenharmony_ci		i2c_unregister_device(client);
11088c2ecf20Sopenharmony_ci	}
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	/* remove I2C demod */
11118c2ecf20Sopenharmony_ci	client = dev->i2c_client_demod;
11128c2ecf20Sopenharmony_ci	if (client) {
11138c2ecf20Sopenharmony_ci		module_put(client->dev.driver->owner);
11148c2ecf20Sopenharmony_ci		i2c_unregister_device(client);
11158c2ecf20Sopenharmony_ci	}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	return 0;
11188c2ecf20Sopenharmony_ci}
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_cistatic struct qt1010_config rtl28xxu_qt1010_config = {
11218c2ecf20Sopenharmony_ci	.i2c_address = 0x62, /* 0xc4 */
11228c2ecf20Sopenharmony_ci};
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_cistatic struct mt2060_config rtl28xxu_mt2060_config = {
11258c2ecf20Sopenharmony_ci	.i2c_address = 0x60, /* 0xc0 */
11268c2ecf20Sopenharmony_ci	.clock_out = 0,
11278c2ecf20Sopenharmony_ci};
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_cistatic struct mxl5005s_config rtl28xxu_mxl5005s_config = {
11308c2ecf20Sopenharmony_ci	.i2c_address     = 0x63, /* 0xc6 */
11318c2ecf20Sopenharmony_ci	.if_freq         = IF_FREQ_4570000HZ,
11328c2ecf20Sopenharmony_ci	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
11338c2ecf20Sopenharmony_ci	.agc_mode        = MXL_SINGLE_AGC,
11348c2ecf20Sopenharmony_ci	.tracking_filter = MXL_TF_C_H,
11358c2ecf20Sopenharmony_ci	.rssi_enable     = MXL_RSSI_ENABLE,
11368c2ecf20Sopenharmony_ci	.cap_select      = MXL_CAP_SEL_ENABLE,
11378c2ecf20Sopenharmony_ci	.div_out         = MXL_DIV_OUT_4,
11388c2ecf20Sopenharmony_ci	.clock_out       = MXL_CLOCK_OUT_DISABLE,
11398c2ecf20Sopenharmony_ci	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
11408c2ecf20Sopenharmony_ci	.top		 = MXL5005S_TOP_25P2,
11418c2ecf20Sopenharmony_ci	.mod_mode        = MXL_DIGITAL_MODE,
11428c2ecf20Sopenharmony_ci	.if_mode         = MXL_ZERO_IF,
11438c2ecf20Sopenharmony_ci	.AgcMasterByte   = 0x00,
11448c2ecf20Sopenharmony_ci};
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_cistatic int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
11478c2ecf20Sopenharmony_ci{
11488c2ecf20Sopenharmony_ci	int ret;
11498c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
11508c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
11518c2ecf20Sopenharmony_ci	struct dvb_frontend *fe;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci	switch (dev->tuner) {
11568c2ecf20Sopenharmony_ci	case TUNER_RTL2830_QT1010:
11578c2ecf20Sopenharmony_ci		fe = dvb_attach(qt1010_attach, adap->fe[0],
11588c2ecf20Sopenharmony_ci				dev->demod_i2c_adapter,
11598c2ecf20Sopenharmony_ci				&rtl28xxu_qt1010_config);
11608c2ecf20Sopenharmony_ci		break;
11618c2ecf20Sopenharmony_ci	case TUNER_RTL2830_MT2060:
11628c2ecf20Sopenharmony_ci		fe = dvb_attach(mt2060_attach, adap->fe[0],
11638c2ecf20Sopenharmony_ci				dev->demod_i2c_adapter,
11648c2ecf20Sopenharmony_ci				&rtl28xxu_mt2060_config, 1220);
11658c2ecf20Sopenharmony_ci		break;
11668c2ecf20Sopenharmony_ci	case TUNER_RTL2830_MXL5005S:
11678c2ecf20Sopenharmony_ci		fe = dvb_attach(mxl5005s_attach, adap->fe[0],
11688c2ecf20Sopenharmony_ci				dev->demod_i2c_adapter,
11698c2ecf20Sopenharmony_ci				&rtl28xxu_mxl5005s_config);
11708c2ecf20Sopenharmony_ci		break;
11718c2ecf20Sopenharmony_ci	default:
11728c2ecf20Sopenharmony_ci		fe = NULL;
11738c2ecf20Sopenharmony_ci		dev_err(&d->intf->dev, "unknown tuner %d\n", dev->tuner);
11748c2ecf20Sopenharmony_ci	}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ci	if (fe == NULL) {
11778c2ecf20Sopenharmony_ci		ret = -ENODEV;
11788c2ecf20Sopenharmony_ci		goto err;
11798c2ecf20Sopenharmony_ci	}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	return 0;
11828c2ecf20Sopenharmony_cierr:
11838c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
11848c2ecf20Sopenharmony_ci	return ret;
11858c2ecf20Sopenharmony_ci}
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_cistatic const struct fc0012_config rtl2832u_fc0012_config = {
11888c2ecf20Sopenharmony_ci	.i2c_address = 0x63, /* 0xc6 >> 1 */
11898c2ecf20Sopenharmony_ci	.xtal_freq = FC_XTAL_28_8_MHZ,
11908c2ecf20Sopenharmony_ci};
11918c2ecf20Sopenharmony_ci
11928c2ecf20Sopenharmony_cistatic const struct r820t_config rtl2832u_r820t_config = {
11938c2ecf20Sopenharmony_ci	.i2c_addr = 0x1a,
11948c2ecf20Sopenharmony_ci	.xtal = 28800000,
11958c2ecf20Sopenharmony_ci	.max_i2c_msg_len = 2,
11968c2ecf20Sopenharmony_ci	.rafael_chip = CHIP_R820T,
11978c2ecf20Sopenharmony_ci};
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistatic const struct r820t_config rtl2832u_r828d_config = {
12008c2ecf20Sopenharmony_ci	.i2c_addr = 0x3a,
12018c2ecf20Sopenharmony_ci	.xtal = 16000000,
12028c2ecf20Sopenharmony_ci	.max_i2c_msg_len = 2,
12038c2ecf20Sopenharmony_ci	.rafael_chip = CHIP_R828D,
12048c2ecf20Sopenharmony_ci};
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_cistatic int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
12078c2ecf20Sopenharmony_ci{
12088c2ecf20Sopenharmony_ci	int ret;
12098c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
12108c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
12118c2ecf20Sopenharmony_ci	struct dvb_frontend *fe = NULL;
12128c2ecf20Sopenharmony_ci	struct i2c_board_info info;
12138c2ecf20Sopenharmony_ci	struct i2c_client *client;
12148c2ecf20Sopenharmony_ci	struct v4l2_subdev *subdev = NULL;
12158c2ecf20Sopenharmony_ci	struct platform_device *pdev;
12168c2ecf20Sopenharmony_ci	struct rtl2832_sdr_platform_data pdata;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci	memset(&info, 0, sizeof(struct i2c_board_info));
12218c2ecf20Sopenharmony_ci	memset(&pdata, 0, sizeof(pdata));
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	switch (dev->tuner) {
12248c2ecf20Sopenharmony_ci	case TUNER_RTL2832_FC0012:
12258c2ecf20Sopenharmony_ci		fe = dvb_attach(fc0012_attach, adap->fe[0],
12268c2ecf20Sopenharmony_ci			dev->demod_i2c_adapter, &rtl2832u_fc0012_config);
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci		/* since fc0012 includs reading the signal strength delegate
12298c2ecf20Sopenharmony_ci		 * that to the tuner driver */
12308c2ecf20Sopenharmony_ci		adap->fe[0]->ops.read_signal_strength =
12318c2ecf20Sopenharmony_ci				adap->fe[0]->ops.tuner_ops.get_rf_strength;
12328c2ecf20Sopenharmony_ci		break;
12338c2ecf20Sopenharmony_ci	case TUNER_RTL2832_FC0013:
12348c2ecf20Sopenharmony_ci		fe = dvb_attach(fc0013_attach, adap->fe[0],
12358c2ecf20Sopenharmony_ci			dev->demod_i2c_adapter, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci		/* fc0013 also supports signal strength reading */
12388c2ecf20Sopenharmony_ci		adap->fe[0]->ops.read_signal_strength =
12398c2ecf20Sopenharmony_ci				adap->fe[0]->ops.tuner_ops.get_rf_strength;
12408c2ecf20Sopenharmony_ci		break;
12418c2ecf20Sopenharmony_ci	case TUNER_RTL2832_E4000: {
12428c2ecf20Sopenharmony_ci			struct e4000_config e4000_config = {
12438c2ecf20Sopenharmony_ci				.fe = adap->fe[0],
12448c2ecf20Sopenharmony_ci				.clock = 28800000,
12458c2ecf20Sopenharmony_ci			};
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci			strscpy(info.type, "e4000", I2C_NAME_SIZE);
12488c2ecf20Sopenharmony_ci			info.addr = 0x64;
12498c2ecf20Sopenharmony_ci			info.platform_data = &e4000_config;
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci			request_module(info.type);
12528c2ecf20Sopenharmony_ci			client = i2c_new_client_device(dev->demod_i2c_adapter,
12538c2ecf20Sopenharmony_ci						       &info);
12548c2ecf20Sopenharmony_ci			if (!i2c_client_has_driver(client))
12558c2ecf20Sopenharmony_ci				break;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci			if (!try_module_get(client->dev.driver->owner)) {
12588c2ecf20Sopenharmony_ci				i2c_unregister_device(client);
12598c2ecf20Sopenharmony_ci				break;
12608c2ecf20Sopenharmony_ci			}
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci			dev->i2c_client_tuner = client;
12638c2ecf20Sopenharmony_ci			subdev = i2c_get_clientdata(client);
12648c2ecf20Sopenharmony_ci		}
12658c2ecf20Sopenharmony_ci		break;
12668c2ecf20Sopenharmony_ci	case TUNER_RTL2832_FC2580: {
12678c2ecf20Sopenharmony_ci			struct fc2580_platform_data fc2580_pdata = {
12688c2ecf20Sopenharmony_ci				.dvb_frontend = adap->fe[0],
12698c2ecf20Sopenharmony_ci			};
12708c2ecf20Sopenharmony_ci			struct i2c_board_info board_info = {};
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci			strscpy(board_info.type, "fc2580", I2C_NAME_SIZE);
12738c2ecf20Sopenharmony_ci			board_info.addr = 0x56;
12748c2ecf20Sopenharmony_ci			board_info.platform_data = &fc2580_pdata;
12758c2ecf20Sopenharmony_ci			request_module("fc2580");
12768c2ecf20Sopenharmony_ci			client = i2c_new_client_device(dev->demod_i2c_adapter,
12778c2ecf20Sopenharmony_ci						       &board_info);
12788c2ecf20Sopenharmony_ci			if (!i2c_client_has_driver(client))
12798c2ecf20Sopenharmony_ci				break;
12808c2ecf20Sopenharmony_ci			if (!try_module_get(client->dev.driver->owner)) {
12818c2ecf20Sopenharmony_ci				i2c_unregister_device(client);
12828c2ecf20Sopenharmony_ci				break;
12838c2ecf20Sopenharmony_ci			}
12848c2ecf20Sopenharmony_ci			dev->i2c_client_tuner = client;
12858c2ecf20Sopenharmony_ci			subdev = fc2580_pdata.get_v4l2_subdev(client);
12868c2ecf20Sopenharmony_ci		}
12878c2ecf20Sopenharmony_ci		break;
12888c2ecf20Sopenharmony_ci	case TUNER_RTL2832_TUA9001: {
12898c2ecf20Sopenharmony_ci		struct tua9001_platform_data tua9001_pdata = {
12908c2ecf20Sopenharmony_ci			.dvb_frontend = adap->fe[0],
12918c2ecf20Sopenharmony_ci		};
12928c2ecf20Sopenharmony_ci		struct i2c_board_info board_info = {};
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		/* enable GPIO1 and GPIO4 as output */
12958c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x12);
12968c2ecf20Sopenharmony_ci		if (ret)
12978c2ecf20Sopenharmony_ci			goto err;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x12, 0x12);
13008c2ecf20Sopenharmony_ci		if (ret)
13018c2ecf20Sopenharmony_ci			goto err;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci		strscpy(board_info.type, "tua9001", I2C_NAME_SIZE);
13048c2ecf20Sopenharmony_ci		board_info.addr = 0x60;
13058c2ecf20Sopenharmony_ci		board_info.platform_data = &tua9001_pdata;
13068c2ecf20Sopenharmony_ci		request_module("tua9001");
13078c2ecf20Sopenharmony_ci		client = i2c_new_client_device(dev->demod_i2c_adapter,
13088c2ecf20Sopenharmony_ci					       &board_info);
13098c2ecf20Sopenharmony_ci		if (!i2c_client_has_driver(client))
13108c2ecf20Sopenharmony_ci			break;
13118c2ecf20Sopenharmony_ci		if (!try_module_get(client->dev.driver->owner)) {
13128c2ecf20Sopenharmony_ci			i2c_unregister_device(client);
13138c2ecf20Sopenharmony_ci			break;
13148c2ecf20Sopenharmony_ci		}
13158c2ecf20Sopenharmony_ci		dev->i2c_client_tuner = client;
13168c2ecf20Sopenharmony_ci		break;
13178c2ecf20Sopenharmony_ci	}
13188c2ecf20Sopenharmony_ci	case TUNER_RTL2832_R820T:
13198c2ecf20Sopenharmony_ci		fe = dvb_attach(r820t_attach, adap->fe[0],
13208c2ecf20Sopenharmony_ci				dev->demod_i2c_adapter,
13218c2ecf20Sopenharmony_ci				&rtl2832u_r820t_config);
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci		/* Use tuner to get the signal strength */
13248c2ecf20Sopenharmony_ci		adap->fe[0]->ops.read_signal_strength =
13258c2ecf20Sopenharmony_ci				adap->fe[0]->ops.tuner_ops.get_rf_strength;
13268c2ecf20Sopenharmony_ci		break;
13278c2ecf20Sopenharmony_ci	case TUNER_RTL2832_R828D:
13288c2ecf20Sopenharmony_ci		fe = dvb_attach(r820t_attach, adap->fe[0],
13298c2ecf20Sopenharmony_ci				dev->demod_i2c_adapter,
13308c2ecf20Sopenharmony_ci				&rtl2832u_r828d_config);
13318c2ecf20Sopenharmony_ci		adap->fe[0]->ops.read_signal_strength =
13328c2ecf20Sopenharmony_ci				adap->fe[0]->ops.tuner_ops.get_rf_strength;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci		if (adap->fe[1]) {
13358c2ecf20Sopenharmony_ci			fe = dvb_attach(r820t_attach, adap->fe[1],
13368c2ecf20Sopenharmony_ci					dev->demod_i2c_adapter,
13378c2ecf20Sopenharmony_ci					&rtl2832u_r828d_config);
13388c2ecf20Sopenharmony_ci			adap->fe[1]->ops.read_signal_strength =
13398c2ecf20Sopenharmony_ci					adap->fe[1]->ops.tuner_ops.get_rf_strength;
13408c2ecf20Sopenharmony_ci		}
13418c2ecf20Sopenharmony_ci		break;
13428c2ecf20Sopenharmony_ci	case TUNER_RTL2832_SI2157: {
13438c2ecf20Sopenharmony_ci			struct si2157_config si2157_config = {
13448c2ecf20Sopenharmony_ci				.fe = adap->fe[0],
13458c2ecf20Sopenharmony_ci				.if_port = 0,
13468c2ecf20Sopenharmony_ci				.inversion = false,
13478c2ecf20Sopenharmony_ci			};
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci			strscpy(info.type, "si2157", I2C_NAME_SIZE);
13508c2ecf20Sopenharmony_ci			info.addr = 0x60;
13518c2ecf20Sopenharmony_ci			info.platform_data = &si2157_config;
13528c2ecf20Sopenharmony_ci			request_module(info.type);
13538c2ecf20Sopenharmony_ci			client = i2c_new_client_device(&d->i2c_adap, &info);
13548c2ecf20Sopenharmony_ci			if (!i2c_client_has_driver(client))
13558c2ecf20Sopenharmony_ci				break;
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci			if (!try_module_get(client->dev.driver->owner)) {
13588c2ecf20Sopenharmony_ci				i2c_unregister_device(client);
13598c2ecf20Sopenharmony_ci				break;
13608c2ecf20Sopenharmony_ci			}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci			dev->i2c_client_tuner = client;
13638c2ecf20Sopenharmony_ci			subdev = i2c_get_clientdata(client);
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci			/* copy tuner ops for 2nd FE as tuner is shared */
13668c2ecf20Sopenharmony_ci			if (adap->fe[1]) {
13678c2ecf20Sopenharmony_ci				adap->fe[1]->tuner_priv =
13688c2ecf20Sopenharmony_ci						adap->fe[0]->tuner_priv;
13698c2ecf20Sopenharmony_ci				memcpy(&adap->fe[1]->ops.tuner_ops,
13708c2ecf20Sopenharmony_ci						&adap->fe[0]->ops.tuner_ops,
13718c2ecf20Sopenharmony_ci						sizeof(struct dvb_tuner_ops));
13728c2ecf20Sopenharmony_ci			}
13738c2ecf20Sopenharmony_ci		}
13748c2ecf20Sopenharmony_ci		break;
13758c2ecf20Sopenharmony_ci	default:
13768c2ecf20Sopenharmony_ci		dev_err(&d->intf->dev, "unknown tuner %d\n", dev->tuner);
13778c2ecf20Sopenharmony_ci	}
13788c2ecf20Sopenharmony_ci	if (fe == NULL && dev->i2c_client_tuner == NULL) {
13798c2ecf20Sopenharmony_ci		ret = -ENODEV;
13808c2ecf20Sopenharmony_ci		goto err;
13818c2ecf20Sopenharmony_ci	}
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	/* register SDR */
13848c2ecf20Sopenharmony_ci	switch (dev->tuner) {
13858c2ecf20Sopenharmony_ci	case TUNER_RTL2832_FC2580:
13868c2ecf20Sopenharmony_ci	case TUNER_RTL2832_FC0012:
13878c2ecf20Sopenharmony_ci	case TUNER_RTL2832_FC0013:
13888c2ecf20Sopenharmony_ci	case TUNER_RTL2832_E4000:
13898c2ecf20Sopenharmony_ci	case TUNER_RTL2832_R820T:
13908c2ecf20Sopenharmony_ci	case TUNER_RTL2832_R828D:
13918c2ecf20Sopenharmony_ci		pdata.clk = dev->rtl2832_platform_data.clk;
13928c2ecf20Sopenharmony_ci		pdata.tuner = dev->tuner;
13938c2ecf20Sopenharmony_ci		pdata.regmap = dev->rtl2832_platform_data.regmap;
13948c2ecf20Sopenharmony_ci		pdata.dvb_frontend = adap->fe[0];
13958c2ecf20Sopenharmony_ci		pdata.dvb_usb_device = d;
13968c2ecf20Sopenharmony_ci		pdata.v4l2_subdev = subdev;
13978c2ecf20Sopenharmony_ci
13988c2ecf20Sopenharmony_ci		request_module("%s", "rtl2832_sdr");
13998c2ecf20Sopenharmony_ci		pdev = platform_device_register_data(&d->intf->dev,
14008c2ecf20Sopenharmony_ci						     "rtl2832_sdr",
14018c2ecf20Sopenharmony_ci						     PLATFORM_DEVID_AUTO,
14028c2ecf20Sopenharmony_ci						     &pdata, sizeof(pdata));
14038c2ecf20Sopenharmony_ci		if (IS_ERR(pdev) || pdev->dev.driver == NULL)
14048c2ecf20Sopenharmony_ci			break;
14058c2ecf20Sopenharmony_ci		dev->platform_device_sdr = pdev;
14068c2ecf20Sopenharmony_ci		break;
14078c2ecf20Sopenharmony_ci	default:
14088c2ecf20Sopenharmony_ci		dev_dbg(&d->intf->dev, "no SDR for tuner=%d\n", dev->tuner);
14098c2ecf20Sopenharmony_ci	}
14108c2ecf20Sopenharmony_ci
14118c2ecf20Sopenharmony_ci	return 0;
14128c2ecf20Sopenharmony_cierr:
14138c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
14148c2ecf20Sopenharmony_ci	return ret;
14158c2ecf20Sopenharmony_ci}
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_cistatic int rtl28xxu_tuner_attach(struct dvb_usb_adapter *adap)
14188c2ecf20Sopenharmony_ci{
14198c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = adap_to_priv(adap);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	if (dev->chip_id == CHIP_ID_RTL2831U)
14228c2ecf20Sopenharmony_ci		return rtl2831u_tuner_attach(adap);
14238c2ecf20Sopenharmony_ci	else
14248c2ecf20Sopenharmony_ci		return rtl2832u_tuner_attach(adap);
14258c2ecf20Sopenharmony_ci}
14268c2ecf20Sopenharmony_ci
14278c2ecf20Sopenharmony_cistatic int rtl28xxu_tuner_detach(struct dvb_usb_adapter *adap)
14288c2ecf20Sopenharmony_ci{
14298c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
14308c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
14318c2ecf20Sopenharmony_ci	struct i2c_client *client;
14328c2ecf20Sopenharmony_ci	struct platform_device *pdev;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	/* remove platform SDR */
14378c2ecf20Sopenharmony_ci	pdev = dev->platform_device_sdr;
14388c2ecf20Sopenharmony_ci	if (pdev)
14398c2ecf20Sopenharmony_ci		platform_device_unregister(pdev);
14408c2ecf20Sopenharmony_ci
14418c2ecf20Sopenharmony_ci	/* remove I2C tuner */
14428c2ecf20Sopenharmony_ci	client = dev->i2c_client_tuner;
14438c2ecf20Sopenharmony_ci	if (client) {
14448c2ecf20Sopenharmony_ci		module_put(client->dev.driver->owner);
14458c2ecf20Sopenharmony_ci		i2c_unregister_device(client);
14468c2ecf20Sopenharmony_ci	}
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	return 0;
14498c2ecf20Sopenharmony_ci}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_cistatic int rtl28xxu_init(struct dvb_usb_device *d)
14528c2ecf20Sopenharmony_ci{
14538c2ecf20Sopenharmony_ci	int ret;
14548c2ecf20Sopenharmony_ci	u8 val;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "\n");
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	/* init USB endpoints */
14598c2ecf20Sopenharmony_ci	ret = rtl28xxu_rd_reg(d, USB_SYSCTL_0, &val);
14608c2ecf20Sopenharmony_ci	if (ret)
14618c2ecf20Sopenharmony_ci		goto err;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	/* enable DMA and Full Packet Mode*/
14648c2ecf20Sopenharmony_ci	val |= 0x09;
14658c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg(d, USB_SYSCTL_0, val);
14668c2ecf20Sopenharmony_ci	if (ret)
14678c2ecf20Sopenharmony_ci		goto err;
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_ci	/* set EPA maximum packet size to 0x0200 */
14708c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
14718c2ecf20Sopenharmony_ci	if (ret)
14728c2ecf20Sopenharmony_ci		goto err;
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_ci	/* change EPA FIFO length */
14758c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
14768c2ecf20Sopenharmony_ci	if (ret)
14778c2ecf20Sopenharmony_ci		goto err;
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	return ret;
14808c2ecf20Sopenharmony_cierr:
14818c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
14828c2ecf20Sopenharmony_ci	return ret;
14838c2ecf20Sopenharmony_ci}
14848c2ecf20Sopenharmony_ci
14858c2ecf20Sopenharmony_cistatic int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
14868c2ecf20Sopenharmony_ci{
14878c2ecf20Sopenharmony_ci	int ret;
14888c2ecf20Sopenharmony_ci	u8 gpio, sys0, epa_ctl[2];
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "onoff=%d\n", onoff);
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	/* demod adc */
14938c2ecf20Sopenharmony_ci	ret = rtl28xxu_rd_reg(d, SYS_SYS0, &sys0);
14948c2ecf20Sopenharmony_ci	if (ret)
14958c2ecf20Sopenharmony_ci		goto err;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	/* tuner power, read GPIOs */
14988c2ecf20Sopenharmony_ci	ret = rtl28xxu_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
14998c2ecf20Sopenharmony_ci	if (ret)
15008c2ecf20Sopenharmony_ci		goto err;
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "RD SYS0=%02x GPIO_OUT_VAL=%02x\n", sys0, gpio);
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	if (onoff) {
15058c2ecf20Sopenharmony_ci		gpio |= 0x01; /* GPIO0 = 1 */
15068c2ecf20Sopenharmony_ci		gpio &= (~0x10); /* GPIO4 = 0 */
15078c2ecf20Sopenharmony_ci		gpio |= 0x04; /* GPIO2 = 1, LED on */
15088c2ecf20Sopenharmony_ci		sys0 = sys0 & 0x0f;
15098c2ecf20Sopenharmony_ci		sys0 |= 0xe0;
15108c2ecf20Sopenharmony_ci		epa_ctl[0] = 0x00; /* clear stall */
15118c2ecf20Sopenharmony_ci		epa_ctl[1] = 0x00; /* clear reset */
15128c2ecf20Sopenharmony_ci	} else {
15138c2ecf20Sopenharmony_ci		gpio &= (~0x01); /* GPIO0 = 0 */
15148c2ecf20Sopenharmony_ci		gpio |= 0x10; /* GPIO4 = 1 */
15158c2ecf20Sopenharmony_ci		gpio &= (~0x04); /* GPIO2 = 1, LED off */
15168c2ecf20Sopenharmony_ci		sys0 = sys0 & (~0xc0);
15178c2ecf20Sopenharmony_ci		epa_ctl[0] = 0x10; /* set stall */
15188c2ecf20Sopenharmony_ci		epa_ctl[1] = 0x02; /* set reset */
15198c2ecf20Sopenharmony_ci	}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "WR SYS0=%02x GPIO_OUT_VAL=%02x\n", sys0, gpio);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	/* demod adc */
15248c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg(d, SYS_SYS0, sys0);
15258c2ecf20Sopenharmony_ci	if (ret)
15268c2ecf20Sopenharmony_ci		goto err;
15278c2ecf20Sopenharmony_ci
15288c2ecf20Sopenharmony_ci	/* tuner power, write GPIOs */
15298c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
15308c2ecf20Sopenharmony_ci	if (ret)
15318c2ecf20Sopenharmony_ci		goto err;
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	/* streaming EP: stall & reset */
15348c2ecf20Sopenharmony_ci	ret = rtl28xxu_wr_regs(d, USB_EPA_CTL, epa_ctl, 2);
15358c2ecf20Sopenharmony_ci	if (ret)
15368c2ecf20Sopenharmony_ci		goto err;
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	if (onoff)
15398c2ecf20Sopenharmony_ci		usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x81));
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ci	return ret;
15428c2ecf20Sopenharmony_cierr:
15438c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
15448c2ecf20Sopenharmony_ci	return ret;
15458c2ecf20Sopenharmony_ci}
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_cistatic int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
15488c2ecf20Sopenharmony_ci{
15498c2ecf20Sopenharmony_ci	int ret;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "onoff=%d\n", onoff);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	if (onoff) {
15548c2ecf20Sopenharmony_ci		/* GPIO3=1, GPIO4=0 */
15558c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x08, 0x18);
15568c2ecf20Sopenharmony_ci		if (ret)
15578c2ecf20Sopenharmony_ci			goto err;
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci		/* suspend? */
15608c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL1, 0x00, 0x10);
15618c2ecf20Sopenharmony_ci		if (ret)
15628c2ecf20Sopenharmony_ci			goto err;
15638c2ecf20Sopenharmony_ci
15648c2ecf20Sopenharmony_ci		/* enable PLL */
15658c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, 0x80, 0x80);
15668c2ecf20Sopenharmony_ci		if (ret)
15678c2ecf20Sopenharmony_ci			goto err;
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_ci		/* disable reset */
15708c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, 0x20, 0x20);
15718c2ecf20Sopenharmony_ci		if (ret)
15728c2ecf20Sopenharmony_ci			goto err;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ci		/* streaming EP: clear stall & reset */
15758c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_regs(d, USB_EPA_CTL, "\x00\x00", 2);
15768c2ecf20Sopenharmony_ci		if (ret)
15778c2ecf20Sopenharmony_ci			goto err;
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_ci		ret = usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x81));
15808c2ecf20Sopenharmony_ci		if (ret)
15818c2ecf20Sopenharmony_ci			goto err;
15828c2ecf20Sopenharmony_ci	} else {
15838c2ecf20Sopenharmony_ci		/* GPIO4=1 */
15848c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x10, 0x10);
15858c2ecf20Sopenharmony_ci		if (ret)
15868c2ecf20Sopenharmony_ci			goto err;
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_ci		/* disable PLL */
15898c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x80);
15908c2ecf20Sopenharmony_ci		if (ret)
15918c2ecf20Sopenharmony_ci			goto err;
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci		/* streaming EP: set stall & reset */
15948c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_regs(d, USB_EPA_CTL, "\x10\x02", 2);
15958c2ecf20Sopenharmony_ci		if (ret)
15968c2ecf20Sopenharmony_ci			goto err;
15978c2ecf20Sopenharmony_ci	}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	return ret;
16008c2ecf20Sopenharmony_cierr:
16018c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
16028c2ecf20Sopenharmony_ci	return ret;
16038c2ecf20Sopenharmony_ci}
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_cistatic int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
16068c2ecf20Sopenharmony_ci{
16078c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	if (dev->chip_id == CHIP_ID_RTL2831U)
16108c2ecf20Sopenharmony_ci		return rtl2831u_power_ctrl(d, onoff);
16118c2ecf20Sopenharmony_ci	else
16128c2ecf20Sopenharmony_ci		return rtl2832u_power_ctrl(d, onoff);
16138c2ecf20Sopenharmony_ci}
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_cistatic int rtl28xxu_frontend_ctrl(struct dvb_frontend *fe, int onoff)
16168c2ecf20Sopenharmony_ci{
16178c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = fe_to_d(fe);
16188c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = fe_to_priv(fe);
16198c2ecf20Sopenharmony_ci	struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data;
16208c2ecf20Sopenharmony_ci	int ret;
16218c2ecf20Sopenharmony_ci	u8 val;
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "fe=%d onoff=%d\n", fe->id, onoff);
16248c2ecf20Sopenharmony_ci
16258c2ecf20Sopenharmony_ci	if (dev->chip_id == CHIP_ID_RTL2831U)
16268c2ecf20Sopenharmony_ci		return 0;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	if (fe->id == 0) {
16298c2ecf20Sopenharmony_ci		/* control internal demod ADC */
16308c2ecf20Sopenharmony_ci		if (onoff)
16318c2ecf20Sopenharmony_ci			val = 0x48; /* enable ADC */
16328c2ecf20Sopenharmony_ci		else
16338c2ecf20Sopenharmony_ci			val = 0x00; /* disable ADC */
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, val, 0x48);
16368c2ecf20Sopenharmony_ci		if (ret)
16378c2ecf20Sopenharmony_ci			goto err;
16388c2ecf20Sopenharmony_ci	} else if (fe->id == 1) {
16398c2ecf20Sopenharmony_ci		/* bypass slave demod TS through master demod */
16408c2ecf20Sopenharmony_ci		ret = pdata->slave_ts_ctrl(dev->i2c_client_demod, onoff);
16418c2ecf20Sopenharmony_ci		if (ret)
16428c2ecf20Sopenharmony_ci			goto err;
16438c2ecf20Sopenharmony_ci	}
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci	return 0;
16468c2ecf20Sopenharmony_cierr:
16478c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
16488c2ecf20Sopenharmony_ci	return ret;
16498c2ecf20Sopenharmony_ci}
16508c2ecf20Sopenharmony_ci
16518c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_RC_CORE)
16528c2ecf20Sopenharmony_cistatic int rtl2831u_rc_query(struct dvb_usb_device *d)
16538c2ecf20Sopenharmony_ci{
16548c2ecf20Sopenharmony_ci	int ret, i;
16558c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d->priv;
16568c2ecf20Sopenharmony_ci	u8 buf[5];
16578c2ecf20Sopenharmony_ci	u32 rc_code;
16588c2ecf20Sopenharmony_ci	static const struct rtl28xxu_reg_val rc_nec_tab[] = {
16598c2ecf20Sopenharmony_ci		{ 0x3033, 0x80 },
16608c2ecf20Sopenharmony_ci		{ 0x3020, 0x43 },
16618c2ecf20Sopenharmony_ci		{ 0x3021, 0x16 },
16628c2ecf20Sopenharmony_ci		{ 0x3022, 0x16 },
16638c2ecf20Sopenharmony_ci		{ 0x3023, 0x5a },
16648c2ecf20Sopenharmony_ci		{ 0x3024, 0x2d },
16658c2ecf20Sopenharmony_ci		{ 0x3025, 0x16 },
16668c2ecf20Sopenharmony_ci		{ 0x3026, 0x01 },
16678c2ecf20Sopenharmony_ci		{ 0x3028, 0xb0 },
16688c2ecf20Sopenharmony_ci		{ 0x3029, 0x04 },
16698c2ecf20Sopenharmony_ci		{ 0x302c, 0x88 },
16708c2ecf20Sopenharmony_ci		{ 0x302e, 0x13 },
16718c2ecf20Sopenharmony_ci		{ 0x3030, 0xdf },
16728c2ecf20Sopenharmony_ci		{ 0x3031, 0x05 },
16738c2ecf20Sopenharmony_ci	};
16748c2ecf20Sopenharmony_ci
16758c2ecf20Sopenharmony_ci	/* init remote controller */
16768c2ecf20Sopenharmony_ci	if (!dev->rc_active) {
16778c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
16788c2ecf20Sopenharmony_ci			ret = rtl28xxu_wr_reg(d, rc_nec_tab[i].reg,
16798c2ecf20Sopenharmony_ci					rc_nec_tab[i].val);
16808c2ecf20Sopenharmony_ci			if (ret)
16818c2ecf20Sopenharmony_ci				goto err;
16828c2ecf20Sopenharmony_ci		}
16838c2ecf20Sopenharmony_ci		dev->rc_active = true;
16848c2ecf20Sopenharmony_ci	}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	ret = rtl28xxu_rd_regs(d, SYS_IRRC_RP, buf, 5);
16878c2ecf20Sopenharmony_ci	if (ret)
16888c2ecf20Sopenharmony_ci		goto err;
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	if (buf[4] & 0x01) {
16918c2ecf20Sopenharmony_ci		enum rc_proto proto;
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci		if (buf[2] == (u8) ~buf[3]) {
16948c2ecf20Sopenharmony_ci			if (buf[0] == (u8) ~buf[1]) {
16958c2ecf20Sopenharmony_ci				/* NEC standard (16 bit) */
16968c2ecf20Sopenharmony_ci				rc_code = RC_SCANCODE_NEC(buf[0], buf[2]);
16978c2ecf20Sopenharmony_ci				proto = RC_PROTO_NEC;
16988c2ecf20Sopenharmony_ci			} else {
16998c2ecf20Sopenharmony_ci				/* NEC extended (24 bit) */
17008c2ecf20Sopenharmony_ci				rc_code = RC_SCANCODE_NECX(buf[0] << 8 | buf[1],
17018c2ecf20Sopenharmony_ci							   buf[2]);
17028c2ecf20Sopenharmony_ci				proto = RC_PROTO_NECX;
17038c2ecf20Sopenharmony_ci			}
17048c2ecf20Sopenharmony_ci		} else {
17058c2ecf20Sopenharmony_ci			/* NEC full (32 bit) */
17068c2ecf20Sopenharmony_ci			rc_code = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 |
17078c2ecf20Sopenharmony_ci						    buf[2] << 8  | buf[3]);
17088c2ecf20Sopenharmony_ci			proto = RC_PROTO_NEC32;
17098c2ecf20Sopenharmony_ci		}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci		rc_keydown(d->rc_dev, proto, rc_code, 0);
17128c2ecf20Sopenharmony_ci
17138c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg(d, SYS_IRRC_SR, 1);
17148c2ecf20Sopenharmony_ci		if (ret)
17158c2ecf20Sopenharmony_ci			goto err;
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci		/* repeated intentionally to avoid extra keypress */
17188c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg(d, SYS_IRRC_SR, 1);
17198c2ecf20Sopenharmony_ci		if (ret)
17208c2ecf20Sopenharmony_ci			goto err;
17218c2ecf20Sopenharmony_ci	}
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	return ret;
17248c2ecf20Sopenharmony_cierr:
17258c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
17268c2ecf20Sopenharmony_ci	return ret;
17278c2ecf20Sopenharmony_ci}
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_cistatic int rtl2831u_get_rc_config(struct dvb_usb_device *d,
17308c2ecf20Sopenharmony_ci		struct dvb_usb_rc *rc)
17318c2ecf20Sopenharmony_ci{
17328c2ecf20Sopenharmony_ci	rc->map_name = RC_MAP_EMPTY;
17338c2ecf20Sopenharmony_ci	rc->allowed_protos = RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX |
17348c2ecf20Sopenharmony_ci							RC_PROTO_BIT_NEC32;
17358c2ecf20Sopenharmony_ci	rc->query = rtl2831u_rc_query;
17368c2ecf20Sopenharmony_ci	rc->interval = 400;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	return 0;
17398c2ecf20Sopenharmony_ci}
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_cistatic int rtl2832u_rc_query(struct dvb_usb_device *d)
17428c2ecf20Sopenharmony_ci{
17438c2ecf20Sopenharmony_ci	int ret, i, len;
17448c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d->priv;
17458c2ecf20Sopenharmony_ci	struct ir_raw_event ev = {};
17468c2ecf20Sopenharmony_ci	u8 buf[128];
17478c2ecf20Sopenharmony_ci	static const struct rtl28xxu_reg_val_mask refresh_tab[] = {
17488c2ecf20Sopenharmony_ci		{IR_RX_IF,               0x03, 0xff},
17498c2ecf20Sopenharmony_ci		{IR_RX_BUF_CTRL,         0x80, 0xff},
17508c2ecf20Sopenharmony_ci		{IR_RX_CTRL,             0x80, 0xff},
17518c2ecf20Sopenharmony_ci	};
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	/* init remote controller */
17548c2ecf20Sopenharmony_ci	if (!dev->rc_active) {
17558c2ecf20Sopenharmony_ci		static const struct rtl28xxu_reg_val_mask init_tab[] = {
17568c2ecf20Sopenharmony_ci			{SYS_DEMOD_CTL1,         0x00, 0x04},
17578c2ecf20Sopenharmony_ci			{SYS_DEMOD_CTL1,         0x00, 0x08},
17588c2ecf20Sopenharmony_ci			{USB_CTRL,               0x20, 0x20},
17598c2ecf20Sopenharmony_ci			{SYS_GPIO_DIR,           0x00, 0x08},
17608c2ecf20Sopenharmony_ci			{SYS_GPIO_OUT_EN,        0x08, 0x08},
17618c2ecf20Sopenharmony_ci			{SYS_GPIO_OUT_VAL,       0x08, 0x08},
17628c2ecf20Sopenharmony_ci			{IR_MAX_DURATION0,       0xd0, 0xff},
17638c2ecf20Sopenharmony_ci			{IR_MAX_DURATION1,       0x07, 0xff},
17648c2ecf20Sopenharmony_ci			{IR_IDLE_LEN0,           0xc0, 0xff},
17658c2ecf20Sopenharmony_ci			{IR_IDLE_LEN1,           0x00, 0xff},
17668c2ecf20Sopenharmony_ci			{IR_GLITCH_LEN,          0x03, 0xff},
17678c2ecf20Sopenharmony_ci			{IR_RX_CLK,              0x09, 0xff},
17688c2ecf20Sopenharmony_ci			{IR_RX_CFG,              0x1c, 0xff},
17698c2ecf20Sopenharmony_ci			{IR_MAX_H_TOL_LEN,       0x1e, 0xff},
17708c2ecf20Sopenharmony_ci			{IR_MAX_L_TOL_LEN,       0x1e, 0xff},
17718c2ecf20Sopenharmony_ci			{IR_RX_CTRL,             0x80, 0xff},
17728c2ecf20Sopenharmony_ci		};
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(init_tab); i++) {
17758c2ecf20Sopenharmony_ci			ret = rtl28xxu_wr_reg_mask(d, init_tab[i].reg,
17768c2ecf20Sopenharmony_ci					init_tab[i].val, init_tab[i].mask);
17778c2ecf20Sopenharmony_ci			if (ret)
17788c2ecf20Sopenharmony_ci				goto err;
17798c2ecf20Sopenharmony_ci		}
17808c2ecf20Sopenharmony_ci
17818c2ecf20Sopenharmony_ci		dev->rc_active = true;
17828c2ecf20Sopenharmony_ci	}
17838c2ecf20Sopenharmony_ci
17848c2ecf20Sopenharmony_ci	ret = rtl28xxu_rd_reg(d, IR_RX_IF, &buf[0]);
17858c2ecf20Sopenharmony_ci	if (ret)
17868c2ecf20Sopenharmony_ci		goto err;
17878c2ecf20Sopenharmony_ci
17888c2ecf20Sopenharmony_ci	if (buf[0] != 0x83)
17898c2ecf20Sopenharmony_ci		goto exit;
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ci	ret = rtl28xxu_rd_reg(d, IR_RX_BC, &buf[0]);
17928c2ecf20Sopenharmony_ci	if (ret || buf[0] > sizeof(buf))
17938c2ecf20Sopenharmony_ci		goto err;
17948c2ecf20Sopenharmony_ci
17958c2ecf20Sopenharmony_ci	len = buf[0];
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	/* read raw code from hw */
17988c2ecf20Sopenharmony_ci	ret = rtl28xxu_rd_regs(d, IR_RX_BUF, buf, len);
17998c2ecf20Sopenharmony_ci	if (ret)
18008c2ecf20Sopenharmony_ci		goto err;
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci	/* let hw receive new code */
18038c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(refresh_tab); i++) {
18048c2ecf20Sopenharmony_ci		ret = rtl28xxu_wr_reg_mask(d, refresh_tab[i].reg,
18058c2ecf20Sopenharmony_ci				refresh_tab[i].val, refresh_tab[i].mask);
18068c2ecf20Sopenharmony_ci		if (ret)
18078c2ecf20Sopenharmony_ci			goto err;
18088c2ecf20Sopenharmony_ci	}
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	/* pass data to Kernel IR decoder */
18118c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
18128c2ecf20Sopenharmony_ci		ev.pulse = buf[i] >> 7;
18138c2ecf20Sopenharmony_ci		ev.duration = 51 * (buf[i] & 0x7f);
18148c2ecf20Sopenharmony_ci		ir_raw_event_store_with_filter(d->rc_dev, &ev);
18158c2ecf20Sopenharmony_ci	}
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	/* 'flush' ir_raw_event_store_with_filter() */
18188c2ecf20Sopenharmony_ci	ir_raw_event_handle(d->rc_dev);
18198c2ecf20Sopenharmony_ciexit:
18208c2ecf20Sopenharmony_ci	return ret;
18218c2ecf20Sopenharmony_cierr:
18228c2ecf20Sopenharmony_ci	dev_dbg(&d->intf->dev, "failed=%d\n", ret);
18238c2ecf20Sopenharmony_ci	return ret;
18248c2ecf20Sopenharmony_ci}
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_cistatic int rtl2832u_get_rc_config(struct dvb_usb_device *d,
18278c2ecf20Sopenharmony_ci		struct dvb_usb_rc *rc)
18288c2ecf20Sopenharmony_ci{
18298c2ecf20Sopenharmony_ci	/* disable IR interrupts in order to avoid SDR sample loss */
18308c2ecf20Sopenharmony_ci	if (rtl28xxu_disable_rc)
18318c2ecf20Sopenharmony_ci		return rtl28xxu_wr_reg(d, IR_RX_IE, 0x00);
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	/* load empty to enable rc */
18348c2ecf20Sopenharmony_ci	if (!rc->map_name)
18358c2ecf20Sopenharmony_ci		rc->map_name = RC_MAP_EMPTY;
18368c2ecf20Sopenharmony_ci	rc->allowed_protos = RC_PROTO_BIT_ALL_IR_DECODER;
18378c2ecf20Sopenharmony_ci	rc->driver_type = RC_DRIVER_IR_RAW;
18388c2ecf20Sopenharmony_ci	rc->query = rtl2832u_rc_query;
18398c2ecf20Sopenharmony_ci	rc->interval = 200;
18408c2ecf20Sopenharmony_ci	/* we program idle len to 0xc0, set timeout to one less */
18418c2ecf20Sopenharmony_ci	rc->timeout = 0xbf * 51;
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_ci	return 0;
18448c2ecf20Sopenharmony_ci}
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_cistatic int rtl28xxu_get_rc_config(struct dvb_usb_device *d,
18478c2ecf20Sopenharmony_ci		struct dvb_usb_rc *rc)
18488c2ecf20Sopenharmony_ci{
18498c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = d_to_priv(d);
18508c2ecf20Sopenharmony_ci
18518c2ecf20Sopenharmony_ci	if (dev->chip_id == CHIP_ID_RTL2831U)
18528c2ecf20Sopenharmony_ci		return rtl2831u_get_rc_config(d, rc);
18538c2ecf20Sopenharmony_ci	else
18548c2ecf20Sopenharmony_ci		return rtl2832u_get_rc_config(d, rc);
18558c2ecf20Sopenharmony_ci}
18568c2ecf20Sopenharmony_ci#else
18578c2ecf20Sopenharmony_ci#define rtl28xxu_get_rc_config NULL
18588c2ecf20Sopenharmony_ci#endif
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_cistatic int rtl28xxu_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
18618c2ecf20Sopenharmony_ci{
18628c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = adap_to_priv(adap);
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	if (dev->chip_id == CHIP_ID_RTL2831U) {
18658c2ecf20Sopenharmony_ci		struct rtl2830_platform_data *pdata = &dev->rtl2830_platform_data;
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci		return pdata->pid_filter_ctrl(adap->fe[0], onoff);
18688c2ecf20Sopenharmony_ci	} else {
18698c2ecf20Sopenharmony_ci		struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data;
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci		return pdata->pid_filter_ctrl(adap->fe[0], onoff);
18728c2ecf20Sopenharmony_ci	}
18738c2ecf20Sopenharmony_ci}
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_cistatic int rtl28xxu_pid_filter(struct dvb_usb_adapter *adap, int index,
18768c2ecf20Sopenharmony_ci			       u16 pid, int onoff)
18778c2ecf20Sopenharmony_ci{
18788c2ecf20Sopenharmony_ci	struct rtl28xxu_dev *dev = adap_to_priv(adap);
18798c2ecf20Sopenharmony_ci
18808c2ecf20Sopenharmony_ci	if (dev->chip_id == CHIP_ID_RTL2831U) {
18818c2ecf20Sopenharmony_ci		struct rtl2830_platform_data *pdata = &dev->rtl2830_platform_data;
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_ci		return pdata->pid_filter(adap->fe[0], index, pid, onoff);
18848c2ecf20Sopenharmony_ci	} else {
18858c2ecf20Sopenharmony_ci		struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data;
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci		return pdata->pid_filter(adap->fe[0], index, pid, onoff);
18888c2ecf20Sopenharmony_ci	}
18898c2ecf20Sopenharmony_ci}
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_cistatic const struct dvb_usb_device_properties rtl28xxu_props = {
18928c2ecf20Sopenharmony_ci	.driver_name = KBUILD_MODNAME,
18938c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
18948c2ecf20Sopenharmony_ci	.adapter_nr = adapter_nr,
18958c2ecf20Sopenharmony_ci	.size_of_priv = sizeof(struct rtl28xxu_dev),
18968c2ecf20Sopenharmony_ci
18978c2ecf20Sopenharmony_ci	.identify_state = rtl28xxu_identify_state,
18988c2ecf20Sopenharmony_ci	.power_ctrl = rtl28xxu_power_ctrl,
18998c2ecf20Sopenharmony_ci	.frontend_ctrl = rtl28xxu_frontend_ctrl,
19008c2ecf20Sopenharmony_ci	.i2c_algo = &rtl28xxu_i2c_algo,
19018c2ecf20Sopenharmony_ci	.read_config = rtl28xxu_read_config,
19028c2ecf20Sopenharmony_ci	.frontend_attach = rtl28xxu_frontend_attach,
19038c2ecf20Sopenharmony_ci	.frontend_detach = rtl28xxu_frontend_detach,
19048c2ecf20Sopenharmony_ci	.tuner_attach = rtl28xxu_tuner_attach,
19058c2ecf20Sopenharmony_ci	.tuner_detach = rtl28xxu_tuner_detach,
19068c2ecf20Sopenharmony_ci	.init = rtl28xxu_init,
19078c2ecf20Sopenharmony_ci	.get_rc_config = rtl28xxu_get_rc_config,
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	.num_adapters = 1,
19108c2ecf20Sopenharmony_ci	.adapter = {
19118c2ecf20Sopenharmony_ci		{
19128c2ecf20Sopenharmony_ci			.caps = DVB_USB_ADAP_HAS_PID_FILTER |
19138c2ecf20Sopenharmony_ci				DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci			.pid_filter_count = 32,
19168c2ecf20Sopenharmony_ci			.pid_filter_ctrl = rtl28xxu_pid_filter_ctrl,
19178c2ecf20Sopenharmony_ci			.pid_filter = rtl28xxu_pid_filter,
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci			.stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512),
19208c2ecf20Sopenharmony_ci		},
19218c2ecf20Sopenharmony_ci	},
19228c2ecf20Sopenharmony_ci};
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_cistatic const struct usb_device_id rtl28xxu_id_table[] = {
19258c2ecf20Sopenharmony_ci	/* RTL2831U devices: */
19268c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U,
19278c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Realtek RTL2831U reference design", NULL) },
19288c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT,
19298c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Freecom USB2.0 DVB-T", NULL) },
19308c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2,
19318c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Freecom USB2.0 DVB-T", NULL) },
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	/* RTL2832U devices: */
19348c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2832,
19358c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Realtek RTL2832U reference design", NULL) },
19368c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838,
19378c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Realtek RTL2832U reference design", NULL) },
19388c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1,
19398c2ecf20Sopenharmony_ci		&rtl28xxu_props, "TerraTec Cinergy T Stick Black", RC_MAP_TERRATEC_SLIM) },
19408c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT,
19418c2ecf20Sopenharmony_ci		&rtl28xxu_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) },
19428c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK,
19438c2ecf20Sopenharmony_ci		&rtl28xxu_props, "TerraTec NOXON DAB Stick", NULL) },
19448c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV2,
19458c2ecf20Sopenharmony_ci		&rtl28xxu_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) },
19468c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV3,
19478c2ecf20Sopenharmony_ci		&rtl28xxu_props, "TerraTec NOXON DAB Stick (rev 3)", NULL) },
19488c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TREKSTOR_TERRES_2_0,
19498c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Trekstor DVB-T Stick Terres 2.0", NULL) },
19508c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1101,
19518c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Dexatek DK DVB-T Dongle", NULL) },
19528c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6680,
19538c2ecf20Sopenharmony_ci		&rtl28xxu_props, "DigitalNow Quad DVB-T Receiver", NULL) },
19548c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_MINID,
19558c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Leadtek Winfast DTV Dongle Mini D", NULL) },
19568c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS_PLUS,
19578c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Leadtek WinFast DTV2000DS Plus", RC_MAP_LEADTEK_Y04G0051) },
19588c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3,
19598c2ecf20Sopenharmony_ci		&rtl28xxu_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) },
19608c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102,
19618c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Dexatek DK mini DVB-T Dongle", NULL) },
19628c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d7,
19638c2ecf20Sopenharmony_ci		&rtl28xxu_props, "TerraTec Cinergy T Stick+", NULL) },
19648c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd3a8,
19658c2ecf20Sopenharmony_ci		&rtl28xxu_props, "ASUS My Cinema-U3100Mini Plus V2", NULL) },
19668c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd393,
19678c2ecf20Sopenharmony_ci		&rtl28xxu_props, "GIGABYTE U7300", NULL) },
19688c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1104,
19698c2ecf20Sopenharmony_ci		&rtl28xxu_props, "MSI DIGIVOX Micro HD", NULL) },
19708c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_COMPRO, 0x0620,
19718c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Compro VideoMate U620F", NULL) },
19728c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_COMPRO, 0x0650,
19738c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Compro VideoMate U650F", NULL) },
19748c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
19758c2ecf20Sopenharmony_ci		&rtl28xxu_props, "MaxMedia HU394-T", NULL) },
19768c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
19778c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) },
19788c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
19798c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Crypto ReDi PC 50 A", NULL) },
19808c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_KYE, 0x707f,
19818c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Genius TVGo DVB-T03", NULL) },
19828c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd395,
19838c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Peak DVB-T USB", NULL) },
19848c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20_RTL2832U,
19858c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Sveon STV20", NULL) },
19868c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV21,
19878c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Sveon STV21", NULL) },
19888c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV27,
19898c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Sveon STV27", NULL) },
19908c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_TURBOX_DTT_2000,
19918c2ecf20Sopenharmony_ci		&rtl28xxu_props, "TURBO-X Pure TV Tuner DTT-2000", NULL) },
19928c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_PROLECTRIX_DV107669,
19938c2ecf20Sopenharmony_ci		&rtl28xxu_props, "PROlectrix DV107669", NULL) },
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	/* RTL2832P devices: */
19968c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131,
19978c2ecf20Sopenharmony_ci		&rtl28xxu_props, "Astrometa DVB-T2",
19988c2ecf20Sopenharmony_ci		RC_MAP_ASTROMETA_T2HYBRID) },
19998c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(0x5654, 0xca42,
20008c2ecf20Sopenharmony_ci		&rtl28xxu_props, "GoTView MasterHD 3", NULL) },
20018c2ecf20Sopenharmony_ci	{ }
20028c2ecf20Sopenharmony_ci};
20038c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_cistatic struct usb_driver rtl28xxu_usb_driver = {
20068c2ecf20Sopenharmony_ci	.name = KBUILD_MODNAME,
20078c2ecf20Sopenharmony_ci	.id_table = rtl28xxu_id_table,
20088c2ecf20Sopenharmony_ci	.probe = dvb_usbv2_probe,
20098c2ecf20Sopenharmony_ci	.disconnect = dvb_usbv2_disconnect,
20108c2ecf20Sopenharmony_ci	.suspend = dvb_usbv2_suspend,
20118c2ecf20Sopenharmony_ci	.resume = dvb_usbv2_resume,
20128c2ecf20Sopenharmony_ci	.reset_resume = dvb_usbv2_reset_resume,
20138c2ecf20Sopenharmony_ci	.no_dynamic_id = 1,
20148c2ecf20Sopenharmony_ci	.soft_unbind = 1,
20158c2ecf20Sopenharmony_ci};
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_cimodule_usb_driver(rtl28xxu_usb_driver);
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
20208c2ecf20Sopenharmony_ciMODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
20218c2ecf20Sopenharmony_ciMODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
20228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
2023