18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Driver for DVBSky USB2.0 receiver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013 Max nibble <nibble.max@gmail.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "dvb_usb.h"
98c2ecf20Sopenharmony_ci#include "m88ds3103.h"
108c2ecf20Sopenharmony_ci#include "ts2020.h"
118c2ecf20Sopenharmony_ci#include "sp2.h"
128c2ecf20Sopenharmony_ci#include "si2168.h"
138c2ecf20Sopenharmony_ci#include "si2157.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#define DVBSKY_MSG_DELAY	0/*2000*/
168c2ecf20Sopenharmony_ci#define DVBSKY_BUF_LEN	64
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic int dvb_usb_dvbsky_disable_rc;
198c2ecf20Sopenharmony_cimodule_param_named(disable_rc, dvb_usb_dvbsky_disable_rc, int, 0644);
208c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_rc, "Disable inbuilt IR receiver.");
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct dvbsky_state {
258c2ecf20Sopenharmony_ci	u8 ibuf[DVBSKY_BUF_LEN];
268c2ecf20Sopenharmony_ci	u8 obuf[DVBSKY_BUF_LEN];
278c2ecf20Sopenharmony_ci	u8 last_lock;
288c2ecf20Sopenharmony_ci	struct i2c_client *i2c_client_demod;
298c2ecf20Sopenharmony_ci	struct i2c_client *i2c_client_tuner;
308c2ecf20Sopenharmony_ci	struct i2c_client *i2c_client_ci;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	/* fe hook functions*/
338c2ecf20Sopenharmony_ci	int (*fe_set_voltage)(struct dvb_frontend *fe,
348c2ecf20Sopenharmony_ci		enum fe_sec_voltage voltage);
358c2ecf20Sopenharmony_ci	int (*fe_read_status)(struct dvb_frontend *fe,
368c2ecf20Sopenharmony_ci		enum fe_status *status);
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic int dvbsky_usb_generic_rw(struct dvb_usb_device *d,
408c2ecf20Sopenharmony_ci		u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	int ret;
438c2ecf20Sopenharmony_ci	struct dvbsky_state *state = d_to_priv(d);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	mutex_lock(&d->usb_mutex);
468c2ecf20Sopenharmony_ci	if (wlen != 0)
478c2ecf20Sopenharmony_ci		memcpy(state->obuf, wbuf, wlen);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	ret = dvb_usbv2_generic_rw_locked(d, state->obuf, wlen,
508c2ecf20Sopenharmony_ci			state->ibuf, rlen);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	if (!ret && (rlen != 0))
538c2ecf20Sopenharmony_ci		memcpy(rbuf, state->ibuf, rlen);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
568c2ecf20Sopenharmony_ci	return ret;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic int dvbsky_stream_ctrl(struct dvb_usb_device *d, u8 onoff)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct dvbsky_state *state = d_to_priv(d);
628c2ecf20Sopenharmony_ci	static const u8 obuf_pre[3] = { 0x37, 0, 0 };
638c2ecf20Sopenharmony_ci	static const u8 obuf_post[3] = { 0x36, 3, 0 };
648c2ecf20Sopenharmony_ci	int ret;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	mutex_lock(&d->usb_mutex);
678c2ecf20Sopenharmony_ci	memcpy(state->obuf, obuf_pre, 3);
688c2ecf20Sopenharmony_ci	ret = dvb_usbv2_generic_write_locked(d, state->obuf, 3);
698c2ecf20Sopenharmony_ci	if (!ret && onoff) {
708c2ecf20Sopenharmony_ci		msleep(20);
718c2ecf20Sopenharmony_ci		memcpy(state->obuf, obuf_post, 3);
728c2ecf20Sopenharmony_ci		ret = dvb_usbv2_generic_write_locked(d, state->obuf, 3);
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci	mutex_unlock(&d->usb_mutex);
758c2ecf20Sopenharmony_ci	return ret;
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic int dvbsky_streaming_ctrl(struct dvb_frontend *fe, int onoff)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = fe_to_d(fe);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return dvbsky_stream_ctrl(d, (onoff == 0) ? 0 : 1);
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci/* GPIO */
868c2ecf20Sopenharmony_cistatic int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	int ret;
898c2ecf20Sopenharmony_ci	u8 obuf[3], ibuf[2];
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	obuf[0] = 0x0e;
928c2ecf20Sopenharmony_ci	obuf[1] = gport;
938c2ecf20Sopenharmony_ci	obuf[2] = value;
948c2ecf20Sopenharmony_ci	ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1);
958c2ecf20Sopenharmony_ci	return ret;
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci/* I2C */
998c2ecf20Sopenharmony_cistatic int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
1008c2ecf20Sopenharmony_ci	int num)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
1038c2ecf20Sopenharmony_ci	int ret = 0;
1048c2ecf20Sopenharmony_ci	u8 ibuf[64], obuf[64];
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
1078c2ecf20Sopenharmony_ci		return -EAGAIN;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	if (num > 2) {
1108c2ecf20Sopenharmony_ci		dev_err(&d->udev->dev,
1118c2ecf20Sopenharmony_ci		"too many i2c messages[%d], max 2.", num);
1128c2ecf20Sopenharmony_ci		ret = -EOPNOTSUPP;
1138c2ecf20Sopenharmony_ci		goto i2c_error;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (num == 1) {
1178c2ecf20Sopenharmony_ci		if (msg[0].len > 60) {
1188c2ecf20Sopenharmony_ci			dev_err(&d->udev->dev,
1198c2ecf20Sopenharmony_ci			"too many i2c bytes[%d], max 60.",
1208c2ecf20Sopenharmony_ci			msg[0].len);
1218c2ecf20Sopenharmony_ci			ret = -EOPNOTSUPP;
1228c2ecf20Sopenharmony_ci			goto i2c_error;
1238c2ecf20Sopenharmony_ci		}
1248c2ecf20Sopenharmony_ci		if (msg[0].flags & I2C_M_RD) {
1258c2ecf20Sopenharmony_ci			/* single read */
1268c2ecf20Sopenharmony_ci			obuf[0] = 0x09;
1278c2ecf20Sopenharmony_ci			obuf[1] = 0;
1288c2ecf20Sopenharmony_ci			obuf[2] = msg[0].len;
1298c2ecf20Sopenharmony_ci			obuf[3] = msg[0].addr;
1308c2ecf20Sopenharmony_ci			ret = dvbsky_usb_generic_rw(d, obuf, 4,
1318c2ecf20Sopenharmony_ci					ibuf, msg[0].len + 1);
1328c2ecf20Sopenharmony_ci			if (!ret)
1338c2ecf20Sopenharmony_ci				memcpy(msg[0].buf, &ibuf[1], msg[0].len);
1348c2ecf20Sopenharmony_ci		} else {
1358c2ecf20Sopenharmony_ci			/* write */
1368c2ecf20Sopenharmony_ci			obuf[0] = 0x08;
1378c2ecf20Sopenharmony_ci			obuf[1] = msg[0].addr;
1388c2ecf20Sopenharmony_ci			obuf[2] = msg[0].len;
1398c2ecf20Sopenharmony_ci			memcpy(&obuf[3], msg[0].buf, msg[0].len);
1408c2ecf20Sopenharmony_ci			ret = dvbsky_usb_generic_rw(d, obuf,
1418c2ecf20Sopenharmony_ci					msg[0].len + 3, ibuf, 1);
1428c2ecf20Sopenharmony_ci		}
1438c2ecf20Sopenharmony_ci	} else {
1448c2ecf20Sopenharmony_ci		if ((msg[0].len > 60) || (msg[1].len > 60)) {
1458c2ecf20Sopenharmony_ci			dev_err(&d->udev->dev,
1468c2ecf20Sopenharmony_ci			"too many i2c bytes[w-%d][r-%d], max 60.",
1478c2ecf20Sopenharmony_ci			msg[0].len, msg[1].len);
1488c2ecf20Sopenharmony_ci			ret = -EOPNOTSUPP;
1498c2ecf20Sopenharmony_ci			goto i2c_error;
1508c2ecf20Sopenharmony_ci		}
1518c2ecf20Sopenharmony_ci		/* write then read */
1528c2ecf20Sopenharmony_ci		obuf[0] = 0x09;
1538c2ecf20Sopenharmony_ci		obuf[1] = msg[0].len;
1548c2ecf20Sopenharmony_ci		obuf[2] = msg[1].len;
1558c2ecf20Sopenharmony_ci		obuf[3] = msg[0].addr;
1568c2ecf20Sopenharmony_ci		memcpy(&obuf[4], msg[0].buf, msg[0].len);
1578c2ecf20Sopenharmony_ci		ret = dvbsky_usb_generic_rw(d, obuf,
1588c2ecf20Sopenharmony_ci			msg[0].len + 4, ibuf, msg[1].len + 1);
1598c2ecf20Sopenharmony_ci		if (!ret)
1608c2ecf20Sopenharmony_ci			memcpy(msg[1].buf, &ibuf[1], msg[1].len);
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_cii2c_error:
1638c2ecf20Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
1648c2ecf20Sopenharmony_ci	return (ret) ? ret : num;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic u32 dvbsky_i2c_func(struct i2c_adapter *adapter)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	return I2C_FUNC_I2C;
1708c2ecf20Sopenharmony_ci}
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic struct i2c_algorithm dvbsky_i2c_algo = {
1738c2ecf20Sopenharmony_ci	.master_xfer   = dvbsky_i2c_xfer,
1748c2ecf20Sopenharmony_ci	.functionality = dvbsky_i2c_func,
1758c2ecf20Sopenharmony_ci};
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_RC_CORE)
1788c2ecf20Sopenharmony_cistatic int dvbsky_rc_query(struct dvb_usb_device *d)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	u32 code = 0xffff, scancode;
1818c2ecf20Sopenharmony_ci	u8 rc5_command, rc5_system;
1828c2ecf20Sopenharmony_ci	u8 obuf[2], ibuf[2], toggle;
1838c2ecf20Sopenharmony_ci	int ret;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	obuf[0] = 0x10;
1868c2ecf20Sopenharmony_ci	ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2);
1878c2ecf20Sopenharmony_ci	if (ret == 0)
1888c2ecf20Sopenharmony_ci		code = (ibuf[0] << 8) | ibuf[1];
1898c2ecf20Sopenharmony_ci	if (code != 0xffff) {
1908c2ecf20Sopenharmony_ci		dev_dbg(&d->udev->dev, "rc code: %x\n", code);
1918c2ecf20Sopenharmony_ci		rc5_command = code & 0x3F;
1928c2ecf20Sopenharmony_ci		rc5_system = (code & 0x7C0) >> 6;
1938c2ecf20Sopenharmony_ci		toggle = (code & 0x800) ? 1 : 0;
1948c2ecf20Sopenharmony_ci		scancode = rc5_system << 8 | rc5_command;
1958c2ecf20Sopenharmony_ci		rc_keydown(d->rc_dev, RC_PROTO_RC5, scancode, toggle);
1968c2ecf20Sopenharmony_ci	}
1978c2ecf20Sopenharmony_ci	return 0;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	if (dvb_usb_dvbsky_disable_rc) {
2038c2ecf20Sopenharmony_ci		rc->map_name = NULL;
2048c2ecf20Sopenharmony_ci		return 0;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	rc->allowed_protos = RC_PROTO_BIT_RC5;
2088c2ecf20Sopenharmony_ci	rc->query          = dvbsky_rc_query;
2098c2ecf20Sopenharmony_ci	rc->interval       = 300;
2108c2ecf20Sopenharmony_ci	return 0;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci#else
2138c2ecf20Sopenharmony_ci	#define dvbsky_get_rc_config NULL
2148c2ecf20Sopenharmony_ci#endif
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int dvbsky_usb_set_voltage(struct dvb_frontend *fe,
2178c2ecf20Sopenharmony_ci	enum fe_sec_voltage voltage)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = fe_to_d(fe);
2208c2ecf20Sopenharmony_ci	struct dvbsky_state *state = d_to_priv(d);
2218c2ecf20Sopenharmony_ci	u8 value;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	if (voltage == SEC_VOLTAGE_OFF)
2248c2ecf20Sopenharmony_ci		value = 0;
2258c2ecf20Sopenharmony_ci	else
2268c2ecf20Sopenharmony_ci		value = 1;
2278c2ecf20Sopenharmony_ci	dvbsky_gpio_ctrl(d, 0x80, value);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	return state->fe_set_voltage(fe, voltage);
2308c2ecf20Sopenharmony_ci}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
2358c2ecf20Sopenharmony_ci	u8 obuf[] = { 0x1e, 0x00 };
2368c2ecf20Sopenharmony_ci	u8 ibuf[6] = { 0 };
2378c2ecf20Sopenharmony_ci	struct i2c_msg msg[] = {
2388c2ecf20Sopenharmony_ci		{
2398c2ecf20Sopenharmony_ci			.addr = 0x51,
2408c2ecf20Sopenharmony_ci			.flags = 0,
2418c2ecf20Sopenharmony_ci			.buf = obuf,
2428c2ecf20Sopenharmony_ci			.len = 2,
2438c2ecf20Sopenharmony_ci		}, {
2448c2ecf20Sopenharmony_ci			.addr = 0x51,
2458c2ecf20Sopenharmony_ci			.flags = I2C_M_RD,
2468c2ecf20Sopenharmony_ci			.buf = ibuf,
2478c2ecf20Sopenharmony_ci			.len = 6,
2488c2ecf20Sopenharmony_ci		}
2498c2ecf20Sopenharmony_ci	};
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	if (i2c_transfer(&d->i2c_adap, msg, 2) == 2)
2528c2ecf20Sopenharmony_ci		memcpy(mac, ibuf, 6);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	return 0;
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_cistatic int dvbsky_usb_read_status(struct dvb_frontend *fe,
2588c2ecf20Sopenharmony_ci				  enum fe_status *status)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = fe_to_d(fe);
2618c2ecf20Sopenharmony_ci	struct dvbsky_state *state = d_to_priv(d);
2628c2ecf20Sopenharmony_ci	int ret;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	ret = state->fe_read_status(fe, status);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	/* it need resync slave fifo when signal change from unlock to lock.*/
2678c2ecf20Sopenharmony_ci	if ((*status & FE_HAS_LOCK) && (!state->last_lock))
2688c2ecf20Sopenharmony_ci		dvbsky_stream_ctrl(d, 1);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0;
2718c2ecf20Sopenharmony_ci	return ret;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic int dvbsky_s960_attach(struct dvb_usb_adapter *adap)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	struct dvbsky_state *state = adap_to_priv(adap);
2778c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
2788c2ecf20Sopenharmony_ci	struct i2c_adapter *i2c_adapter;
2798c2ecf20Sopenharmony_ci	struct m88ds3103_platform_data m88ds3103_pdata = {};
2808c2ecf20Sopenharmony_ci	struct ts2020_config ts2020_config = {};
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	/* attach demod */
2838c2ecf20Sopenharmony_ci	m88ds3103_pdata.clk = 27000000;
2848c2ecf20Sopenharmony_ci	m88ds3103_pdata.i2c_wr_max = 33;
2858c2ecf20Sopenharmony_ci	m88ds3103_pdata.clk_out = 0;
2868c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_mode = M88DS3103_TS_CI;
2878c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_clk = 16000;
2888c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_clk_pol = 0;
2898c2ecf20Sopenharmony_ci	m88ds3103_pdata.agc = 0x99;
2908c2ecf20Sopenharmony_ci	m88ds3103_pdata.lnb_hv_pol = 1,
2918c2ecf20Sopenharmony_ci	m88ds3103_pdata.lnb_en_pol = 1,
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	state->i2c_client_demod = dvb_module_probe("m88ds3103", NULL,
2948c2ecf20Sopenharmony_ci						   &d->i2c_adap,
2958c2ecf20Sopenharmony_ci						   0x68, &m88ds3103_pdata);
2968c2ecf20Sopenharmony_ci	if (!state->i2c_client_demod)
2978c2ecf20Sopenharmony_ci		return -ENODEV;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	adap->fe[0] = m88ds3103_pdata.get_dvb_frontend(state->i2c_client_demod);
3008c2ecf20Sopenharmony_ci	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(state->i2c_client_demod);
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	/* attach tuner */
3038c2ecf20Sopenharmony_ci	ts2020_config.fe = adap->fe[0];
3048c2ecf20Sopenharmony_ci	ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	state->i2c_client_tuner = dvb_module_probe("ts2020", NULL,
3078c2ecf20Sopenharmony_ci						   i2c_adapter,
3088c2ecf20Sopenharmony_ci						   0x60, &ts2020_config);
3098c2ecf20Sopenharmony_ci	if (!state->i2c_client_tuner) {
3108c2ecf20Sopenharmony_ci		dvb_module_release(state->i2c_client_demod);
3118c2ecf20Sopenharmony_ci		return -ENODEV;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/* delegate signal strength measurement to tuner */
3158c2ecf20Sopenharmony_ci	adap->fe[0]->ops.read_signal_strength =
3168c2ecf20Sopenharmony_ci			adap->fe[0]->ops.tuner_ops.get_rf_strength;
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* hook fe: need to resync the slave fifo when signal locks. */
3198c2ecf20Sopenharmony_ci	state->fe_read_status = adap->fe[0]->ops.read_status;
3208c2ecf20Sopenharmony_ci	adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	/* hook fe: LNB off/on is control by Cypress usb chip. */
3238c2ecf20Sopenharmony_ci	state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
3248c2ecf20Sopenharmony_ci	adap->fe[0]->ops.set_voltage = dvbsky_usb_set_voltage;
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	return 0;
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic int dvbsky_usb_ci_set_voltage(struct dvb_frontend *fe,
3308c2ecf20Sopenharmony_ci	enum fe_sec_voltage voltage)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = fe_to_d(fe);
3338c2ecf20Sopenharmony_ci	struct dvbsky_state *state = d_to_priv(d);
3348c2ecf20Sopenharmony_ci	u8 value;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	if (voltage == SEC_VOLTAGE_OFF)
3378c2ecf20Sopenharmony_ci		value = 0;
3388c2ecf20Sopenharmony_ci	else
3398c2ecf20Sopenharmony_ci		value = 1;
3408c2ecf20Sopenharmony_ci	dvbsky_gpio_ctrl(d, 0x00, value);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return state->fe_set_voltage(fe, voltage);
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int dvbsky_ci_ctrl(void *priv, u8 read, int addr,
3468c2ecf20Sopenharmony_ci					u8 data, int *mem)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = priv;
3498c2ecf20Sopenharmony_ci	int ret = 0;
3508c2ecf20Sopenharmony_ci	u8 command[4], respond[2], command_size, respond_size;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	command[1] = (u8)((addr >> 8) & 0xff); /*high part of address*/
3538c2ecf20Sopenharmony_ci	command[2] = (u8)(addr & 0xff); /*low part of address*/
3548c2ecf20Sopenharmony_ci	if (read) {
3558c2ecf20Sopenharmony_ci		command[0] = 0x71;
3568c2ecf20Sopenharmony_ci		command_size = 3;
3578c2ecf20Sopenharmony_ci		respond_size = 2;
3588c2ecf20Sopenharmony_ci	} else {
3598c2ecf20Sopenharmony_ci		command[0] = 0x70;
3608c2ecf20Sopenharmony_ci		command[3] = data;
3618c2ecf20Sopenharmony_ci		command_size = 4;
3628c2ecf20Sopenharmony_ci		respond_size = 1;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci	ret = dvbsky_usb_generic_rw(d, command, command_size,
3658c2ecf20Sopenharmony_ci			respond, respond_size);
3668c2ecf20Sopenharmony_ci	if (ret)
3678c2ecf20Sopenharmony_ci		goto err;
3688c2ecf20Sopenharmony_ci	if (read)
3698c2ecf20Sopenharmony_ci		*mem = respond[1];
3708c2ecf20Sopenharmony_ci	return ret;
3718c2ecf20Sopenharmony_cierr:
3728c2ecf20Sopenharmony_ci	dev_err(&d->udev->dev, "ci control failed=%d\n", ret);
3738c2ecf20Sopenharmony_ci	return ret;
3748c2ecf20Sopenharmony_ci}
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_cistatic int dvbsky_s960c_attach(struct dvb_usb_adapter *adap)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	struct dvbsky_state *state = adap_to_priv(adap);
3798c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
3808c2ecf20Sopenharmony_ci	struct i2c_adapter *i2c_adapter;
3818c2ecf20Sopenharmony_ci	struct m88ds3103_platform_data m88ds3103_pdata = {};
3828c2ecf20Sopenharmony_ci	struct ts2020_config ts2020_config = {};
3838c2ecf20Sopenharmony_ci	struct sp2_config sp2_config = {};
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	/* attach demod */
3868c2ecf20Sopenharmony_ci	m88ds3103_pdata.clk = 27000000,
3878c2ecf20Sopenharmony_ci	m88ds3103_pdata.i2c_wr_max = 33,
3888c2ecf20Sopenharmony_ci	m88ds3103_pdata.clk_out = 0,
3898c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_mode = M88DS3103_TS_CI,
3908c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_clk = 10000,
3918c2ecf20Sopenharmony_ci	m88ds3103_pdata.ts_clk_pol = 1,
3928c2ecf20Sopenharmony_ci	m88ds3103_pdata.agc = 0x99,
3938c2ecf20Sopenharmony_ci	m88ds3103_pdata.lnb_hv_pol = 0,
3948c2ecf20Sopenharmony_ci	m88ds3103_pdata.lnb_en_pol = 1,
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	state->i2c_client_demod = dvb_module_probe("m88ds3103", NULL,
3978c2ecf20Sopenharmony_ci						   &d->i2c_adap,
3988c2ecf20Sopenharmony_ci						   0x68, &m88ds3103_pdata);
3998c2ecf20Sopenharmony_ci	if (!state->i2c_client_demod)
4008c2ecf20Sopenharmony_ci		return -ENODEV;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	adap->fe[0] = m88ds3103_pdata.get_dvb_frontend(state->i2c_client_demod);
4038c2ecf20Sopenharmony_ci	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(state->i2c_client_demod);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	/* attach tuner */
4068c2ecf20Sopenharmony_ci	ts2020_config.fe = adap->fe[0];
4078c2ecf20Sopenharmony_ci	ts2020_config.get_agc_pwm = m88ds3103_get_agc_pwm;
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	state->i2c_client_tuner = dvb_module_probe("ts2020", NULL,
4108c2ecf20Sopenharmony_ci						   i2c_adapter,
4118c2ecf20Sopenharmony_ci						   0x60, &ts2020_config);
4128c2ecf20Sopenharmony_ci	if (!state->i2c_client_tuner) {
4138c2ecf20Sopenharmony_ci		dvb_module_release(state->i2c_client_demod);
4148c2ecf20Sopenharmony_ci		return -ENODEV;
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	/* attach ci controller */
4188c2ecf20Sopenharmony_ci	sp2_config.dvb_adap = &adap->dvb_adap;
4198c2ecf20Sopenharmony_ci	sp2_config.priv = d;
4208c2ecf20Sopenharmony_ci	sp2_config.ci_control = dvbsky_ci_ctrl;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	state->i2c_client_ci = dvb_module_probe("sp2", NULL,
4238c2ecf20Sopenharmony_ci						&d->i2c_adap,
4248c2ecf20Sopenharmony_ci						0x40, &sp2_config);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	if (!state->i2c_client_ci) {
4278c2ecf20Sopenharmony_ci		dvb_module_release(state->i2c_client_tuner);
4288c2ecf20Sopenharmony_ci		dvb_module_release(state->i2c_client_demod);
4298c2ecf20Sopenharmony_ci		return -ENODEV;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	/* delegate signal strength measurement to tuner */
4338c2ecf20Sopenharmony_ci	adap->fe[0]->ops.read_signal_strength =
4348c2ecf20Sopenharmony_ci			adap->fe[0]->ops.tuner_ops.get_rf_strength;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/* hook fe: need to resync the slave fifo when signal locks. */
4378c2ecf20Sopenharmony_ci	state->fe_read_status = adap->fe[0]->ops.read_status;
4388c2ecf20Sopenharmony_ci	adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	/* hook fe: LNB off/on is control by Cypress usb chip. */
4418c2ecf20Sopenharmony_ci	state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
4428c2ecf20Sopenharmony_ci	adap->fe[0]->ops.set_voltage = dvbsky_usb_ci_set_voltage;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	return 0;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic int dvbsky_t680c_attach(struct dvb_usb_adapter *adap)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct dvbsky_state *state = adap_to_priv(adap);
4508c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
4518c2ecf20Sopenharmony_ci	struct i2c_adapter *i2c_adapter;
4528c2ecf20Sopenharmony_ci	struct si2168_config si2168_config = {};
4538c2ecf20Sopenharmony_ci	struct si2157_config si2157_config = {};
4548c2ecf20Sopenharmony_ci	struct sp2_config sp2_config = {};
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	/* attach demod */
4578c2ecf20Sopenharmony_ci	si2168_config.i2c_adapter = &i2c_adapter;
4588c2ecf20Sopenharmony_ci	si2168_config.fe = &adap->fe[0];
4598c2ecf20Sopenharmony_ci	si2168_config.ts_mode = SI2168_TS_PARALLEL;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	state->i2c_client_demod = dvb_module_probe("si2168", NULL,
4628c2ecf20Sopenharmony_ci						   &d->i2c_adap,
4638c2ecf20Sopenharmony_ci						   0x64, &si2168_config);
4648c2ecf20Sopenharmony_ci	if (!state->i2c_client_demod)
4658c2ecf20Sopenharmony_ci		return -ENODEV;
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	/* attach tuner */
4688c2ecf20Sopenharmony_ci	si2157_config.fe = adap->fe[0];
4698c2ecf20Sopenharmony_ci	si2157_config.if_port = 1;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	state->i2c_client_tuner = dvb_module_probe("si2157", NULL,
4728c2ecf20Sopenharmony_ci						   i2c_adapter,
4738c2ecf20Sopenharmony_ci						   0x60, &si2157_config);
4748c2ecf20Sopenharmony_ci	if (!state->i2c_client_tuner) {
4758c2ecf20Sopenharmony_ci		dvb_module_release(state->i2c_client_demod);
4768c2ecf20Sopenharmony_ci		return -ENODEV;
4778c2ecf20Sopenharmony_ci	}
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	/* attach ci controller */
4808c2ecf20Sopenharmony_ci	sp2_config.dvb_adap = &adap->dvb_adap;
4818c2ecf20Sopenharmony_ci	sp2_config.priv = d;
4828c2ecf20Sopenharmony_ci	sp2_config.ci_control = dvbsky_ci_ctrl;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	state->i2c_client_ci = dvb_module_probe("sp2", NULL,
4858c2ecf20Sopenharmony_ci						&d->i2c_adap,
4868c2ecf20Sopenharmony_ci						0x40, &sp2_config);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (!state->i2c_client_ci) {
4898c2ecf20Sopenharmony_ci		dvb_module_release(state->i2c_client_tuner);
4908c2ecf20Sopenharmony_ci		dvb_module_release(state->i2c_client_demod);
4918c2ecf20Sopenharmony_ci		return -ENODEV;
4928c2ecf20Sopenharmony_ci	}
4938c2ecf20Sopenharmony_ci
4948c2ecf20Sopenharmony_ci	return 0;
4958c2ecf20Sopenharmony_ci}
4968c2ecf20Sopenharmony_ci
4978c2ecf20Sopenharmony_cistatic int dvbsky_t330_attach(struct dvb_usb_adapter *adap)
4988c2ecf20Sopenharmony_ci{
4998c2ecf20Sopenharmony_ci	struct dvbsky_state *state = adap_to_priv(adap);
5008c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
5018c2ecf20Sopenharmony_ci	struct i2c_adapter *i2c_adapter;
5028c2ecf20Sopenharmony_ci	struct si2168_config si2168_config = {};
5038c2ecf20Sopenharmony_ci	struct si2157_config si2157_config = {};
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	/* attach demod */
5068c2ecf20Sopenharmony_ci	si2168_config.i2c_adapter = &i2c_adapter;
5078c2ecf20Sopenharmony_ci	si2168_config.fe = &adap->fe[0];
5088c2ecf20Sopenharmony_ci	si2168_config.ts_mode = SI2168_TS_PARALLEL;
5098c2ecf20Sopenharmony_ci	si2168_config.ts_clock_gapped = true;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	state->i2c_client_demod = dvb_module_probe("si2168", NULL,
5128c2ecf20Sopenharmony_ci						   &d->i2c_adap,
5138c2ecf20Sopenharmony_ci						   0x64, &si2168_config);
5148c2ecf20Sopenharmony_ci	if (!state->i2c_client_demod)
5158c2ecf20Sopenharmony_ci		return -ENODEV;
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/* attach tuner */
5188c2ecf20Sopenharmony_ci	si2157_config.fe = adap->fe[0];
5198c2ecf20Sopenharmony_ci	si2157_config.if_port = 1;
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_ci	state->i2c_client_tuner = dvb_module_probe("si2157", NULL,
5228c2ecf20Sopenharmony_ci						   i2c_adapter,
5238c2ecf20Sopenharmony_ci						   0x60, &si2157_config);
5248c2ecf20Sopenharmony_ci	if (!state->i2c_client_tuner) {
5258c2ecf20Sopenharmony_ci		dvb_module_release(state->i2c_client_demod);
5268c2ecf20Sopenharmony_ci		return -ENODEV;
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	return 0;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic int dvbsky_mygica_t230c_attach(struct dvb_usb_adapter *adap)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct dvbsky_state *state = adap_to_priv(adap);
5358c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
5368c2ecf20Sopenharmony_ci	struct i2c_adapter *i2c_adapter;
5378c2ecf20Sopenharmony_ci	struct si2168_config si2168_config = {};
5388c2ecf20Sopenharmony_ci	struct si2157_config si2157_config = {};
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	/* attach demod */
5418c2ecf20Sopenharmony_ci	si2168_config.i2c_adapter = &i2c_adapter;
5428c2ecf20Sopenharmony_ci	si2168_config.fe = &adap->fe[0];
5438c2ecf20Sopenharmony_ci	si2168_config.ts_mode = SI2168_TS_PARALLEL;
5448c2ecf20Sopenharmony_ci	if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230C2)
5458c2ecf20Sopenharmony_ci		si2168_config.ts_mode |= SI2168_TS_CLK_MANUAL;
5468c2ecf20Sopenharmony_ci	si2168_config.ts_clock_inv = 1;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	state->i2c_client_demod = dvb_module_probe("si2168", NULL,
5498c2ecf20Sopenharmony_ci						   &d->i2c_adap,
5508c2ecf20Sopenharmony_ci						   0x64, &si2168_config);
5518c2ecf20Sopenharmony_ci	if (!state->i2c_client_demod)
5528c2ecf20Sopenharmony_ci		return -ENODEV;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	/* attach tuner */
5558c2ecf20Sopenharmony_ci	si2157_config.fe = adap->fe[0];
5568c2ecf20Sopenharmony_ci	if (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_MYGICA_T230) {
5578c2ecf20Sopenharmony_ci		si2157_config.if_port = 1;
5588c2ecf20Sopenharmony_ci		state->i2c_client_tuner = dvb_module_probe("si2157", NULL,
5598c2ecf20Sopenharmony_ci							   i2c_adapter,
5608c2ecf20Sopenharmony_ci							   0x60,
5618c2ecf20Sopenharmony_ci							   &si2157_config);
5628c2ecf20Sopenharmony_ci	} else {
5638c2ecf20Sopenharmony_ci		si2157_config.if_port = 0;
5648c2ecf20Sopenharmony_ci		state->i2c_client_tuner = dvb_module_probe("si2157", "si2141",
5658c2ecf20Sopenharmony_ci							   i2c_adapter,
5668c2ecf20Sopenharmony_ci							   0x60,
5678c2ecf20Sopenharmony_ci							   &si2157_config);
5688c2ecf20Sopenharmony_ci	}
5698c2ecf20Sopenharmony_ci	if (!state->i2c_client_tuner) {
5708c2ecf20Sopenharmony_ci		dvb_module_release(state->i2c_client_demod);
5718c2ecf20Sopenharmony_ci		return -ENODEV;
5728c2ecf20Sopenharmony_ci	}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	return 0;
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_cistatic int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	dvbsky_gpio_ctrl(d, 0x04, 1);
5818c2ecf20Sopenharmony_ci	msleep(20);
5828c2ecf20Sopenharmony_ci	dvbsky_gpio_ctrl(d, 0x83, 0);
5838c2ecf20Sopenharmony_ci	dvbsky_gpio_ctrl(d, 0xc0, 1);
5848c2ecf20Sopenharmony_ci	msleep(100);
5858c2ecf20Sopenharmony_ci	dvbsky_gpio_ctrl(d, 0x83, 1);
5868c2ecf20Sopenharmony_ci	dvbsky_gpio_ctrl(d, 0xc0, 0);
5878c2ecf20Sopenharmony_ci	msleep(50);
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ci	return WARM;
5908c2ecf20Sopenharmony_ci}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_cistatic int dvbsky_init(struct dvb_usb_device *d)
5938c2ecf20Sopenharmony_ci{
5948c2ecf20Sopenharmony_ci	struct dvbsky_state *state = d_to_priv(d);
5958c2ecf20Sopenharmony_ci	state->last_lock = 0;
5968c2ecf20Sopenharmony_ci	return 0;
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ci
5998c2ecf20Sopenharmony_cistatic int dvbsky_frontend_detach(struct dvb_usb_adapter *adap)
6008c2ecf20Sopenharmony_ci{
6018c2ecf20Sopenharmony_ci	struct dvb_usb_device *d = adap_to_d(adap);
6028c2ecf20Sopenharmony_ci	struct dvbsky_state *state = d_to_priv(d);
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	dvb_module_release(state->i2c_client_tuner);
6078c2ecf20Sopenharmony_ci	dvb_module_release(state->i2c_client_demod);
6088c2ecf20Sopenharmony_ci	dvb_module_release(state->i2c_client_ci);
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci/* DVB USB Driver stuff */
6148c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties dvbsky_s960_props = {
6158c2ecf20Sopenharmony_ci	.driver_name = KBUILD_MODNAME,
6168c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
6178c2ecf20Sopenharmony_ci	.adapter_nr = adapter_nr,
6188c2ecf20Sopenharmony_ci	.size_of_priv = sizeof(struct dvbsky_state),
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
6218c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint_response = 0x81,
6228c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	.i2c_algo         = &dvbsky_i2c_algo,
6258c2ecf20Sopenharmony_ci	.frontend_attach  = dvbsky_s960_attach,
6268c2ecf20Sopenharmony_ci	.frontend_detach  = dvbsky_frontend_detach,
6278c2ecf20Sopenharmony_ci	.init             = dvbsky_init,
6288c2ecf20Sopenharmony_ci	.get_rc_config    = dvbsky_get_rc_config,
6298c2ecf20Sopenharmony_ci	.streaming_ctrl   = dvbsky_streaming_ctrl,
6308c2ecf20Sopenharmony_ci	.identify_state	  = dvbsky_identify_state,
6318c2ecf20Sopenharmony_ci	.read_mac_address = dvbsky_read_mac_addr,
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_ci	.num_adapters = 1,
6348c2ecf20Sopenharmony_ci	.adapter = {
6358c2ecf20Sopenharmony_ci		{
6368c2ecf20Sopenharmony_ci			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
6378c2ecf20Sopenharmony_ci		}
6388c2ecf20Sopenharmony_ci	}
6398c2ecf20Sopenharmony_ci};
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties dvbsky_s960c_props = {
6428c2ecf20Sopenharmony_ci	.driver_name = KBUILD_MODNAME,
6438c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
6448c2ecf20Sopenharmony_ci	.adapter_nr = adapter_nr,
6458c2ecf20Sopenharmony_ci	.size_of_priv = sizeof(struct dvbsky_state),
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
6488c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint_response = 0x81,
6498c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	.i2c_algo         = &dvbsky_i2c_algo,
6528c2ecf20Sopenharmony_ci	.frontend_attach  = dvbsky_s960c_attach,
6538c2ecf20Sopenharmony_ci	.frontend_detach  = dvbsky_frontend_detach,
6548c2ecf20Sopenharmony_ci	.init             = dvbsky_init,
6558c2ecf20Sopenharmony_ci	.get_rc_config    = dvbsky_get_rc_config,
6568c2ecf20Sopenharmony_ci	.streaming_ctrl   = dvbsky_streaming_ctrl,
6578c2ecf20Sopenharmony_ci	.identify_state	  = dvbsky_identify_state,
6588c2ecf20Sopenharmony_ci	.read_mac_address = dvbsky_read_mac_addr,
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	.num_adapters = 1,
6618c2ecf20Sopenharmony_ci	.adapter = {
6628c2ecf20Sopenharmony_ci		{
6638c2ecf20Sopenharmony_ci			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
6648c2ecf20Sopenharmony_ci		}
6658c2ecf20Sopenharmony_ci	}
6668c2ecf20Sopenharmony_ci};
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties dvbsky_t680c_props = {
6698c2ecf20Sopenharmony_ci	.driver_name = KBUILD_MODNAME,
6708c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
6718c2ecf20Sopenharmony_ci	.adapter_nr = adapter_nr,
6728c2ecf20Sopenharmony_ci	.size_of_priv = sizeof(struct dvbsky_state),
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
6758c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint_response = 0x81,
6768c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	.i2c_algo         = &dvbsky_i2c_algo,
6798c2ecf20Sopenharmony_ci	.frontend_attach  = dvbsky_t680c_attach,
6808c2ecf20Sopenharmony_ci	.frontend_detach  = dvbsky_frontend_detach,
6818c2ecf20Sopenharmony_ci	.init             = dvbsky_init,
6828c2ecf20Sopenharmony_ci	.get_rc_config    = dvbsky_get_rc_config,
6838c2ecf20Sopenharmony_ci	.streaming_ctrl   = dvbsky_streaming_ctrl,
6848c2ecf20Sopenharmony_ci	.identify_state	  = dvbsky_identify_state,
6858c2ecf20Sopenharmony_ci	.read_mac_address = dvbsky_read_mac_addr,
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	.num_adapters = 1,
6888c2ecf20Sopenharmony_ci	.adapter = {
6898c2ecf20Sopenharmony_ci		{
6908c2ecf20Sopenharmony_ci			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
6918c2ecf20Sopenharmony_ci		}
6928c2ecf20Sopenharmony_ci	}
6938c2ecf20Sopenharmony_ci};
6948c2ecf20Sopenharmony_ci
6958c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties dvbsky_t330_props = {
6968c2ecf20Sopenharmony_ci	.driver_name = KBUILD_MODNAME,
6978c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
6988c2ecf20Sopenharmony_ci	.adapter_nr = adapter_nr,
6998c2ecf20Sopenharmony_ci	.size_of_priv = sizeof(struct dvbsky_state),
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
7028c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint_response = 0x81,
7038c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
7048c2ecf20Sopenharmony_ci
7058c2ecf20Sopenharmony_ci	.i2c_algo         = &dvbsky_i2c_algo,
7068c2ecf20Sopenharmony_ci	.frontend_attach  = dvbsky_t330_attach,
7078c2ecf20Sopenharmony_ci	.frontend_detach  = dvbsky_frontend_detach,
7088c2ecf20Sopenharmony_ci	.init             = dvbsky_init,
7098c2ecf20Sopenharmony_ci	.get_rc_config    = dvbsky_get_rc_config,
7108c2ecf20Sopenharmony_ci	.streaming_ctrl   = dvbsky_streaming_ctrl,
7118c2ecf20Sopenharmony_ci	.identify_state	  = dvbsky_identify_state,
7128c2ecf20Sopenharmony_ci	.read_mac_address = dvbsky_read_mac_addr,
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci	.num_adapters = 1,
7158c2ecf20Sopenharmony_ci	.adapter = {
7168c2ecf20Sopenharmony_ci		{
7178c2ecf20Sopenharmony_ci			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
7188c2ecf20Sopenharmony_ci		}
7198c2ecf20Sopenharmony_ci	}
7208c2ecf20Sopenharmony_ci};
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic struct dvb_usb_device_properties mygica_t230c_props = {
7238c2ecf20Sopenharmony_ci	.driver_name = KBUILD_MODNAME,
7248c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
7258c2ecf20Sopenharmony_ci	.adapter_nr = adapter_nr,
7268c2ecf20Sopenharmony_ci	.size_of_priv = sizeof(struct dvbsky_state),
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
7298c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_endpoint_response = 0x81,
7308c2ecf20Sopenharmony_ci	.generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	.i2c_algo         = &dvbsky_i2c_algo,
7338c2ecf20Sopenharmony_ci	.frontend_attach  = dvbsky_mygica_t230c_attach,
7348c2ecf20Sopenharmony_ci	.frontend_detach  = dvbsky_frontend_detach,
7358c2ecf20Sopenharmony_ci	.init             = dvbsky_init,
7368c2ecf20Sopenharmony_ci	.get_rc_config    = dvbsky_get_rc_config,
7378c2ecf20Sopenharmony_ci	.streaming_ctrl   = dvbsky_streaming_ctrl,
7388c2ecf20Sopenharmony_ci	.identify_state	  = dvbsky_identify_state,
7398c2ecf20Sopenharmony_ci
7408c2ecf20Sopenharmony_ci	.num_adapters = 1,
7418c2ecf20Sopenharmony_ci	.adapter = {
7428c2ecf20Sopenharmony_ci		{
7438c2ecf20Sopenharmony_ci			.stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
7448c2ecf20Sopenharmony_ci		}
7458c2ecf20Sopenharmony_ci	}
7468c2ecf20Sopenharmony_ci};
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_cistatic const struct usb_device_id dvbsky_id_table[] = {
7498c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(0x0572, 0x6831,
7508c2ecf20Sopenharmony_ci		&dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) },
7518c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(0x0572, 0x960c,
7528c2ecf20Sopenharmony_ci		&dvbsky_s960c_props, "DVBSky S960CI", RC_MAP_DVBSKY) },
7538c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(0x0572, 0x680c,
7548c2ecf20Sopenharmony_ci		&dvbsky_t680c_props, "DVBSky T680CI", RC_MAP_DVBSKY) },
7558c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(0x0572, 0x0320,
7568c2ecf20Sopenharmony_ci		&dvbsky_t330_props, "DVBSky T330", RC_MAP_DVBSKY) },
7578c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
7588c2ecf20Sopenharmony_ci		USB_PID_TECHNOTREND_TVSTICK_CT2_4400,
7598c2ecf20Sopenharmony_ci		&dvbsky_t330_props, "TechnoTrend TVStick CT2-4400",
7608c2ecf20Sopenharmony_ci		RC_MAP_TT_1500) },
7618c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
7628c2ecf20Sopenharmony_ci		USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI,
7638c2ecf20Sopenharmony_ci		&dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI",
7648c2ecf20Sopenharmony_ci		RC_MAP_TT_1500) },
7658c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
7668c2ecf20Sopenharmony_ci		USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI_2,
7678c2ecf20Sopenharmony_ci		&dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI v1.1",
7688c2ecf20Sopenharmony_ci		RC_MAP_TT_1500) },
7698c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TECHNOTREND,
7708c2ecf20Sopenharmony_ci		USB_PID_TECHNOTREND_CONNECT_S2_4650_CI,
7718c2ecf20Sopenharmony_ci		&dvbsky_s960c_props, "TechnoTrend TT-connect S2-4650 CI",
7728c2ecf20Sopenharmony_ci		RC_MAP_TT_1500) },
7738c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TERRATEC,
7748c2ecf20Sopenharmony_ci		USB_PID_TERRATEC_H7_3,
7758c2ecf20Sopenharmony_ci		&dvbsky_t680c_props, "Terratec H7 Rev.4",
7768c2ecf20Sopenharmony_ci		RC_MAP_TT_1500) },
7778c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R4,
7788c2ecf20Sopenharmony_ci		&dvbsky_s960_props, "Terratec Cinergy S2 Rev.4",
7798c2ecf20Sopenharmony_ci		RC_MAP_DVBSKY) },
7808c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230,
7818c2ecf20Sopenharmony_ci		&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230",
7828c2ecf20Sopenharmony_ci		RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
7838c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C,
7848c2ecf20Sopenharmony_ci		&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C",
7858c2ecf20Sopenharmony_ci		RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
7868c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C_LITE,
7878c2ecf20Sopenharmony_ci		&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C Lite",
7888c2ecf20Sopenharmony_ci		NULL) },
7898c2ecf20Sopenharmony_ci	{ DVB_USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230C2,
7908c2ecf20Sopenharmony_ci		&mygica_t230c_props, "MyGica Mini DVB-(T/T2/C) USB Stick T230C v2",
7918c2ecf20Sopenharmony_ci		RC_MAP_TOTAL_MEDIA_IN_HAND_02) },
7928c2ecf20Sopenharmony_ci	{ }
7938c2ecf20Sopenharmony_ci};
7948c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, dvbsky_id_table);
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic struct usb_driver dvbsky_usb_driver = {
7978c2ecf20Sopenharmony_ci	.name = KBUILD_MODNAME,
7988c2ecf20Sopenharmony_ci	.id_table = dvbsky_id_table,
7998c2ecf20Sopenharmony_ci	.probe = dvb_usbv2_probe,
8008c2ecf20Sopenharmony_ci	.disconnect = dvb_usbv2_disconnect,
8018c2ecf20Sopenharmony_ci	.suspend = dvb_usbv2_suspend,
8028c2ecf20Sopenharmony_ci	.resume = dvb_usbv2_resume,
8038c2ecf20Sopenharmony_ci	.reset_resume = dvb_usbv2_reset_resume,
8048c2ecf20Sopenharmony_ci	.no_dynamic_id = 1,
8058c2ecf20Sopenharmony_ci	.soft_unbind = 1,
8068c2ecf20Sopenharmony_ci};
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_cimodule_usb_driver(dvbsky_usb_driver);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ciMODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
8118c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for DVBSky USB");
8128c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
813