162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* DVB USB framework compliant Linux driver for the
362306a36Sopenharmony_ci *	DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
462306a36Sopenharmony_ci *	TeVii S421, S480, S482, S600, S630, S632, S650, S660, S662,
562306a36Sopenharmony_ci *	Prof 1100, 7500,
662306a36Sopenharmony_ci *	Geniatech SU3000, T220,
762306a36Sopenharmony_ci *	TechnoTrend S2-4600,
862306a36Sopenharmony_ci *	Terratec Cinergy S2 cards
962306a36Sopenharmony_ci * Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by)
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * see Documentation/driver-api/media/drivers/dvb-usb.rst for more information
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci#include <media/dvb-usb-ids.h>
1462306a36Sopenharmony_ci#include "dw2102.h"
1562306a36Sopenharmony_ci#include "si21xx.h"
1662306a36Sopenharmony_ci#include "stv0299.h"
1762306a36Sopenharmony_ci#include "z0194a.h"
1862306a36Sopenharmony_ci#include "stv0288.h"
1962306a36Sopenharmony_ci#include "stb6000.h"
2062306a36Sopenharmony_ci#include "eds1547.h"
2162306a36Sopenharmony_ci#include "cx24116.h"
2262306a36Sopenharmony_ci#include "tda1002x.h"
2362306a36Sopenharmony_ci#include "mt312.h"
2462306a36Sopenharmony_ci#include "zl10039.h"
2562306a36Sopenharmony_ci#include "ts2020.h"
2662306a36Sopenharmony_ci#include "ds3000.h"
2762306a36Sopenharmony_ci#include "stv0900.h"
2862306a36Sopenharmony_ci#include "stv6110.h"
2962306a36Sopenharmony_ci#include "stb6100.h"
3062306a36Sopenharmony_ci#include "stb6100_proc.h"
3162306a36Sopenharmony_ci#include "m88rs2000.h"
3262306a36Sopenharmony_ci#include "tda18271.h"
3362306a36Sopenharmony_ci#include "cxd2820r.h"
3462306a36Sopenharmony_ci#include "m88ds3103.h"
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci/* Max transfer size done by I2C transfer functions */
3762306a36Sopenharmony_ci#define MAX_XFER_SIZE  64
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define DW210X_READ_MSG 0
4162306a36Sopenharmony_ci#define DW210X_WRITE_MSG 1
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define REG_1F_SYMBOLRATE_BYTE0 0x1f
4462306a36Sopenharmony_ci#define REG_20_SYMBOLRATE_BYTE1 0x20
4562306a36Sopenharmony_ci#define REG_21_SYMBOLRATE_BYTE2 0x21
4662306a36Sopenharmony_ci/* on my own*/
4762306a36Sopenharmony_ci#define DW2102_VOLTAGE_CTRL (0x1800)
4862306a36Sopenharmony_ci#define SU3000_STREAM_CTRL (0x1900)
4962306a36Sopenharmony_ci#define DW2102_RC_QUERY (0x1a00)
5062306a36Sopenharmony_ci#define DW2102_LED_CTRL (0x1b00)
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci#define DW2101_FIRMWARE "dvb-usb-dw2101.fw"
5362306a36Sopenharmony_ci#define DW2102_FIRMWARE "dvb-usb-dw2102.fw"
5462306a36Sopenharmony_ci#define DW2104_FIRMWARE "dvb-usb-dw2104.fw"
5562306a36Sopenharmony_ci#define DW3101_FIRMWARE "dvb-usb-dw3101.fw"
5662306a36Sopenharmony_ci#define S630_FIRMWARE   "dvb-usb-s630.fw"
5762306a36Sopenharmony_ci#define S660_FIRMWARE   "dvb-usb-s660.fw"
5862306a36Sopenharmony_ci#define P1100_FIRMWARE  "dvb-usb-p1100.fw"
5962306a36Sopenharmony_ci#define P7500_FIRMWARE  "dvb-usb-p7500.fw"
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define	err_str "did not find the firmware file '%s'. You can use <kernel_dir>/scripts/get_dvb_firmware to get the firmware"
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistruct dw2102_state {
6462306a36Sopenharmony_ci	u8 initialized;
6562306a36Sopenharmony_ci	u8 last_lock;
6662306a36Sopenharmony_ci	u8 data[MAX_XFER_SIZE + 4];
6762306a36Sopenharmony_ci	struct i2c_client *i2c_client_demod;
6862306a36Sopenharmony_ci	struct i2c_client *i2c_client_tuner;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/* fe hook functions*/
7162306a36Sopenharmony_ci	int (*old_set_voltage)(struct dvb_frontend *f, enum fe_sec_voltage v);
7262306a36Sopenharmony_ci	int (*fe_read_status)(struct dvb_frontend *fe,
7362306a36Sopenharmony_ci			      enum fe_status *status);
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* debug */
7762306a36Sopenharmony_cistatic int dvb_usb_dw2102_debug;
7862306a36Sopenharmony_cimodule_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
7962306a36Sopenharmony_ciMODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
8062306a36Sopenharmony_ci						DVB_USB_DEBUG_STATUS);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci/* demod probe */
8362306a36Sopenharmony_cistatic int demod_probe = 1;
8462306a36Sopenharmony_cimodule_param_named(demod, demod_probe, int, 0644);
8562306a36Sopenharmony_ciMODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 4=stv0903+stb6100(or-able)).");
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic int dw210x_op_rw(struct usb_device *dev, u8 request, u16 value,
9062306a36Sopenharmony_ci			u16 index, u8 * data, u16 len, int flags)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	int ret;
9362306a36Sopenharmony_ci	u8 *u8buf;
9462306a36Sopenharmony_ci	unsigned int pipe = (flags == DW210X_READ_MSG) ?
9562306a36Sopenharmony_ci				usb_rcvctrlpipe(dev, 0) : usb_sndctrlpipe(dev, 0);
9662306a36Sopenharmony_ci	u8 request_type = (flags == DW210X_READ_MSG) ? USB_DIR_IN : USB_DIR_OUT;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	u8buf = kmalloc(len, GFP_KERNEL);
9962306a36Sopenharmony_ci	if (!u8buf)
10062306a36Sopenharmony_ci		return -ENOMEM;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	if (flags == DW210X_WRITE_MSG)
10462306a36Sopenharmony_ci		memcpy(u8buf, data, len);
10562306a36Sopenharmony_ci	ret = usb_control_msg(dev, pipe, request, request_type | USB_TYPE_VENDOR,
10662306a36Sopenharmony_ci				value, index , u8buf, len, 2000);
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	if (flags == DW210X_READ_MSG)
10962306a36Sopenharmony_ci		memcpy(data, u8buf, len);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	kfree(u8buf);
11262306a36Sopenharmony_ci	return ret;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* I2C */
11662306a36Sopenharmony_cistatic int dw2102_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
11762306a36Sopenharmony_ci		int num)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
12062306a36Sopenharmony_ci	int i = 0;
12162306a36Sopenharmony_ci	u8 buf6[] = {0x2c, 0x05, 0xc0, 0, 0, 0, 0};
12262306a36Sopenharmony_ci	u16 value;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (!d)
12562306a36Sopenharmony_ci		return -ENODEV;
12662306a36Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
12762306a36Sopenharmony_ci		return -EAGAIN;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	switch (num) {
13062306a36Sopenharmony_ci	case 2:
13162306a36Sopenharmony_ci		if (msg[0].len < 1) {
13262306a36Sopenharmony_ci			num = -EOPNOTSUPP;
13362306a36Sopenharmony_ci			break;
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci		/* read stv0299 register */
13662306a36Sopenharmony_ci		value = msg[0].buf[0];/* register */
13762306a36Sopenharmony_ci		for (i = 0; i < msg[1].len; i++) {
13862306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb5, value + i, 0,
13962306a36Sopenharmony_ci					buf6, 2, DW210X_READ_MSG);
14062306a36Sopenharmony_ci			msg[1].buf[i] = buf6[0];
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci		break;
14362306a36Sopenharmony_ci	case 1:
14462306a36Sopenharmony_ci		switch (msg[0].addr) {
14562306a36Sopenharmony_ci		case 0x68:
14662306a36Sopenharmony_ci			if (msg[0].len < 2) {
14762306a36Sopenharmony_ci				num = -EOPNOTSUPP;
14862306a36Sopenharmony_ci				break;
14962306a36Sopenharmony_ci			}
15062306a36Sopenharmony_ci			/* write to stv0299 register */
15162306a36Sopenharmony_ci			buf6[0] = 0x2a;
15262306a36Sopenharmony_ci			buf6[1] = msg[0].buf[0];
15362306a36Sopenharmony_ci			buf6[2] = msg[0].buf[1];
15462306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb2, 0, 0,
15562306a36Sopenharmony_ci					buf6, 3, DW210X_WRITE_MSG);
15662306a36Sopenharmony_ci			break;
15762306a36Sopenharmony_ci		case 0x60:
15862306a36Sopenharmony_ci			if (msg[0].flags == 0) {
15962306a36Sopenharmony_ci				if (msg[0].len < 4) {
16062306a36Sopenharmony_ci					num = -EOPNOTSUPP;
16162306a36Sopenharmony_ci					break;
16262306a36Sopenharmony_ci				}
16362306a36Sopenharmony_ci			/* write to tuner pll */
16462306a36Sopenharmony_ci				buf6[0] = 0x2c;
16562306a36Sopenharmony_ci				buf6[1] = 5;
16662306a36Sopenharmony_ci				buf6[2] = 0xc0;
16762306a36Sopenharmony_ci				buf6[3] = msg[0].buf[0];
16862306a36Sopenharmony_ci				buf6[4] = msg[0].buf[1];
16962306a36Sopenharmony_ci				buf6[5] = msg[0].buf[2];
17062306a36Sopenharmony_ci				buf6[6] = msg[0].buf[3];
17162306a36Sopenharmony_ci				dw210x_op_rw(d->udev, 0xb2, 0, 0,
17262306a36Sopenharmony_ci						buf6, 7, DW210X_WRITE_MSG);
17362306a36Sopenharmony_ci			} else {
17462306a36Sopenharmony_ci				if (msg[0].len < 1) {
17562306a36Sopenharmony_ci					num = -EOPNOTSUPP;
17662306a36Sopenharmony_ci					break;
17762306a36Sopenharmony_ci				}
17862306a36Sopenharmony_ci			/* read from tuner */
17962306a36Sopenharmony_ci				dw210x_op_rw(d->udev, 0xb5, 0, 0,
18062306a36Sopenharmony_ci						buf6, 1, DW210X_READ_MSG);
18162306a36Sopenharmony_ci				msg[0].buf[0] = buf6[0];
18262306a36Sopenharmony_ci			}
18362306a36Sopenharmony_ci			break;
18462306a36Sopenharmony_ci		case (DW2102_RC_QUERY):
18562306a36Sopenharmony_ci			if (msg[0].len < 2) {
18662306a36Sopenharmony_ci				num = -EOPNOTSUPP;
18762306a36Sopenharmony_ci				break;
18862306a36Sopenharmony_ci			}
18962306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb8, 0, 0,
19062306a36Sopenharmony_ci					buf6, 2, DW210X_READ_MSG);
19162306a36Sopenharmony_ci			msg[0].buf[0] = buf6[0];
19262306a36Sopenharmony_ci			msg[0].buf[1] = buf6[1];
19362306a36Sopenharmony_ci			break;
19462306a36Sopenharmony_ci		case (DW2102_VOLTAGE_CTRL):
19562306a36Sopenharmony_ci			if (msg[0].len < 1) {
19662306a36Sopenharmony_ci				num = -EOPNOTSUPP;
19762306a36Sopenharmony_ci				break;
19862306a36Sopenharmony_ci			}
19962306a36Sopenharmony_ci			buf6[0] = 0x30;
20062306a36Sopenharmony_ci			buf6[1] = msg[0].buf[0];
20162306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb2, 0, 0,
20262306a36Sopenharmony_ci					buf6, 2, DW210X_WRITE_MSG);
20362306a36Sopenharmony_ci			break;
20462306a36Sopenharmony_ci		}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci		break;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
21062306a36Sopenharmony_ci	return num;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
21462306a36Sopenharmony_ci						struct i2c_msg msg[], int num)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
21762306a36Sopenharmony_ci	u8 buf6[] = {0, 0, 0, 0, 0, 0, 0};
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	if (!d)
22062306a36Sopenharmony_ci		return -ENODEV;
22162306a36Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
22262306a36Sopenharmony_ci		return -EAGAIN;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	switch (num) {
22562306a36Sopenharmony_ci	case 2:
22662306a36Sopenharmony_ci		if (msg[0].len != 1) {
22762306a36Sopenharmony_ci			warn("i2c rd: len=%d is not 1!\n",
22862306a36Sopenharmony_ci			     msg[0].len);
22962306a36Sopenharmony_ci			num = -EOPNOTSUPP;
23062306a36Sopenharmony_ci			break;
23162306a36Sopenharmony_ci		}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci		if (2 + msg[1].len > sizeof(buf6)) {
23462306a36Sopenharmony_ci			warn("i2c rd: len=%d is too big!\n",
23562306a36Sopenharmony_ci			     msg[1].len);
23662306a36Sopenharmony_ci			num = -EOPNOTSUPP;
23762306a36Sopenharmony_ci			break;
23862306a36Sopenharmony_ci		}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		/* read si2109 register by number */
24162306a36Sopenharmony_ci		buf6[0] = msg[0].addr << 1;
24262306a36Sopenharmony_ci		buf6[1] = msg[0].len;
24362306a36Sopenharmony_ci		buf6[2] = msg[0].buf[0];
24462306a36Sopenharmony_ci		dw210x_op_rw(d->udev, 0xc2, 0, 0,
24562306a36Sopenharmony_ci				buf6, msg[0].len + 2, DW210X_WRITE_MSG);
24662306a36Sopenharmony_ci		/* read si2109 register */
24762306a36Sopenharmony_ci		dw210x_op_rw(d->udev, 0xc3, 0xd0, 0,
24862306a36Sopenharmony_ci				buf6, msg[1].len + 2, DW210X_READ_MSG);
24962306a36Sopenharmony_ci		memcpy(msg[1].buf, buf6 + 2, msg[1].len);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci		break;
25262306a36Sopenharmony_ci	case 1:
25362306a36Sopenharmony_ci		switch (msg[0].addr) {
25462306a36Sopenharmony_ci		case 0x68:
25562306a36Sopenharmony_ci			if (2 + msg[0].len > sizeof(buf6)) {
25662306a36Sopenharmony_ci				warn("i2c wr: len=%d is too big!\n",
25762306a36Sopenharmony_ci				     msg[0].len);
25862306a36Sopenharmony_ci				num = -EOPNOTSUPP;
25962306a36Sopenharmony_ci				break;
26062306a36Sopenharmony_ci			}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci			/* write to si2109 register */
26362306a36Sopenharmony_ci			buf6[0] = msg[0].addr << 1;
26462306a36Sopenharmony_ci			buf6[1] = msg[0].len;
26562306a36Sopenharmony_ci			memcpy(buf6 + 2, msg[0].buf, msg[0].len);
26662306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xc2, 0, 0, buf6,
26762306a36Sopenharmony_ci					msg[0].len + 2, DW210X_WRITE_MSG);
26862306a36Sopenharmony_ci			break;
26962306a36Sopenharmony_ci		case(DW2102_RC_QUERY):
27062306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb8, 0, 0,
27162306a36Sopenharmony_ci					buf6, 2, DW210X_READ_MSG);
27262306a36Sopenharmony_ci			msg[0].buf[0] = buf6[0];
27362306a36Sopenharmony_ci			msg[0].buf[1] = buf6[1];
27462306a36Sopenharmony_ci			break;
27562306a36Sopenharmony_ci		case(DW2102_VOLTAGE_CTRL):
27662306a36Sopenharmony_ci			buf6[0] = 0x30;
27762306a36Sopenharmony_ci			buf6[1] = msg[0].buf[0];
27862306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb2, 0, 0,
27962306a36Sopenharmony_ci					buf6, 2, DW210X_WRITE_MSG);
28062306a36Sopenharmony_ci			break;
28162306a36Sopenharmony_ci		}
28262306a36Sopenharmony_ci		break;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
28662306a36Sopenharmony_ci	return num;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_cistatic int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
29262306a36Sopenharmony_ci	int ret;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	if (!d)
29562306a36Sopenharmony_ci		return -ENODEV;
29662306a36Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
29762306a36Sopenharmony_ci		return -EAGAIN;
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	switch (num) {
30062306a36Sopenharmony_ci	case 2: {
30162306a36Sopenharmony_ci		/* read */
30262306a36Sopenharmony_ci		/* first write first register number */
30362306a36Sopenharmony_ci		u8 ibuf[MAX_XFER_SIZE], obuf[3];
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci		if (2 + msg[0].len != sizeof(obuf)) {
30662306a36Sopenharmony_ci			warn("i2c rd: len=%d is not 1!\n",
30762306a36Sopenharmony_ci			     msg[0].len);
30862306a36Sopenharmony_ci			ret = -EOPNOTSUPP;
30962306a36Sopenharmony_ci			goto unlock;
31062306a36Sopenharmony_ci		}
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci		if (2 + msg[1].len > sizeof(ibuf)) {
31362306a36Sopenharmony_ci			warn("i2c rd: len=%d is too big!\n",
31462306a36Sopenharmony_ci			     msg[1].len);
31562306a36Sopenharmony_ci			ret = -EOPNOTSUPP;
31662306a36Sopenharmony_ci			goto unlock;
31762306a36Sopenharmony_ci		}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		obuf[0] = msg[0].addr << 1;
32062306a36Sopenharmony_ci		obuf[1] = msg[0].len;
32162306a36Sopenharmony_ci		obuf[2] = msg[0].buf[0];
32262306a36Sopenharmony_ci		dw210x_op_rw(d->udev, 0xc2, 0, 0,
32362306a36Sopenharmony_ci				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
32462306a36Sopenharmony_ci		/* second read registers */
32562306a36Sopenharmony_ci		dw210x_op_rw(d->udev, 0xc3, 0xd1 , 0,
32662306a36Sopenharmony_ci				ibuf, msg[1].len + 2, DW210X_READ_MSG);
32762306a36Sopenharmony_ci		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci		break;
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci	case 1:
33262306a36Sopenharmony_ci		switch (msg[0].addr) {
33362306a36Sopenharmony_ci		case 0x68: {
33462306a36Sopenharmony_ci			/* write to register */
33562306a36Sopenharmony_ci			u8 obuf[MAX_XFER_SIZE];
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci			if (2 + msg[0].len > sizeof(obuf)) {
33862306a36Sopenharmony_ci				warn("i2c wr: len=%d is too big!\n",
33962306a36Sopenharmony_ci				     msg[1].len);
34062306a36Sopenharmony_ci				ret = -EOPNOTSUPP;
34162306a36Sopenharmony_ci				goto unlock;
34262306a36Sopenharmony_ci			}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci			obuf[0] = msg[0].addr << 1;
34562306a36Sopenharmony_ci			obuf[1] = msg[0].len;
34662306a36Sopenharmony_ci			memcpy(obuf + 2, msg[0].buf, msg[0].len);
34762306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xc2, 0, 0,
34862306a36Sopenharmony_ci					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
34962306a36Sopenharmony_ci			break;
35062306a36Sopenharmony_ci		}
35162306a36Sopenharmony_ci		case 0x61: {
35262306a36Sopenharmony_ci			/* write to tuner */
35362306a36Sopenharmony_ci			u8 obuf[MAX_XFER_SIZE];
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci			if (2 + msg[0].len > sizeof(obuf)) {
35662306a36Sopenharmony_ci				warn("i2c wr: len=%d is too big!\n",
35762306a36Sopenharmony_ci				     msg[1].len);
35862306a36Sopenharmony_ci				ret = -EOPNOTSUPP;
35962306a36Sopenharmony_ci				goto unlock;
36062306a36Sopenharmony_ci			}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci			obuf[0] = msg[0].addr << 1;
36362306a36Sopenharmony_ci			obuf[1] = msg[0].len;
36462306a36Sopenharmony_ci			memcpy(obuf + 2, msg[0].buf, msg[0].len);
36562306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xc2, 0, 0,
36662306a36Sopenharmony_ci					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
36762306a36Sopenharmony_ci			break;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci		case(DW2102_RC_QUERY): {
37062306a36Sopenharmony_ci			u8 ibuf[2];
37162306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb8, 0, 0,
37262306a36Sopenharmony_ci					ibuf, 2, DW210X_READ_MSG);
37362306a36Sopenharmony_ci			memcpy(msg[0].buf, ibuf , 2);
37462306a36Sopenharmony_ci			break;
37562306a36Sopenharmony_ci		}
37662306a36Sopenharmony_ci		case(DW2102_VOLTAGE_CTRL): {
37762306a36Sopenharmony_ci			u8 obuf[2];
37862306a36Sopenharmony_ci			obuf[0] = 0x30;
37962306a36Sopenharmony_ci			obuf[1] = msg[0].buf[0];
38062306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb2, 0, 0,
38162306a36Sopenharmony_ci					obuf, 2, DW210X_WRITE_MSG);
38262306a36Sopenharmony_ci			break;
38362306a36Sopenharmony_ci		}
38462306a36Sopenharmony_ci		}
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		break;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci	ret = num;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ciunlock:
39162306a36Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
39262306a36Sopenharmony_ci	return ret;
39362306a36Sopenharmony_ci}
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_cistatic int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
39662306a36Sopenharmony_ci{
39762306a36Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
39862306a36Sopenharmony_ci	int len, i, j, ret;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	if (!d)
40162306a36Sopenharmony_ci		return -ENODEV;
40262306a36Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
40362306a36Sopenharmony_ci		return -EAGAIN;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	for (j = 0; j < num; j++) {
40662306a36Sopenharmony_ci		switch (msg[j].addr) {
40762306a36Sopenharmony_ci		case(DW2102_RC_QUERY): {
40862306a36Sopenharmony_ci			u8 ibuf[2];
40962306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb8, 0, 0,
41062306a36Sopenharmony_ci					ibuf, 2, DW210X_READ_MSG);
41162306a36Sopenharmony_ci			memcpy(msg[j].buf, ibuf , 2);
41262306a36Sopenharmony_ci			break;
41362306a36Sopenharmony_ci		}
41462306a36Sopenharmony_ci		case(DW2102_VOLTAGE_CTRL): {
41562306a36Sopenharmony_ci			u8 obuf[2];
41662306a36Sopenharmony_ci			obuf[0] = 0x30;
41762306a36Sopenharmony_ci			obuf[1] = msg[j].buf[0];
41862306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb2, 0, 0,
41962306a36Sopenharmony_ci					obuf, 2, DW210X_WRITE_MSG);
42062306a36Sopenharmony_ci			break;
42162306a36Sopenharmony_ci		}
42262306a36Sopenharmony_ci		/*case 0x55: cx24116
42362306a36Sopenharmony_ci		case 0x6a: stv0903
42462306a36Sopenharmony_ci		case 0x68: ds3000, stv0903
42562306a36Sopenharmony_ci		case 0x60: ts2020, stv6110, stb6100 */
42662306a36Sopenharmony_ci		default: {
42762306a36Sopenharmony_ci			if (msg[j].flags == I2C_M_RD) {
42862306a36Sopenharmony_ci				/* read registers */
42962306a36Sopenharmony_ci				u8  ibuf[MAX_XFER_SIZE];
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci				if (2 + msg[j].len > sizeof(ibuf)) {
43262306a36Sopenharmony_ci					warn("i2c rd: len=%d is too big!\n",
43362306a36Sopenharmony_ci					     msg[j].len);
43462306a36Sopenharmony_ci					ret = -EOPNOTSUPP;
43562306a36Sopenharmony_ci					goto unlock;
43662306a36Sopenharmony_ci				}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci				dw210x_op_rw(d->udev, 0xc3,
43962306a36Sopenharmony_ci						(msg[j].addr << 1) + 1, 0,
44062306a36Sopenharmony_ci						ibuf, msg[j].len + 2,
44162306a36Sopenharmony_ci						DW210X_READ_MSG);
44262306a36Sopenharmony_ci				memcpy(msg[j].buf, ibuf + 2, msg[j].len);
44362306a36Sopenharmony_ci				mdelay(10);
44462306a36Sopenharmony_ci			} else if (((msg[j].buf[0] == 0xb0) &&
44562306a36Sopenharmony_ci						(msg[j].addr == 0x68)) ||
44662306a36Sopenharmony_ci						((msg[j].buf[0] == 0xf7) &&
44762306a36Sopenharmony_ci						(msg[j].addr == 0x55))) {
44862306a36Sopenharmony_ci				/* write firmware */
44962306a36Sopenharmony_ci				u8 obuf[19];
45062306a36Sopenharmony_ci				obuf[0] = msg[j].addr << 1;
45162306a36Sopenharmony_ci				obuf[1] = (msg[j].len > 15 ? 17 : msg[j].len);
45262306a36Sopenharmony_ci				obuf[2] = msg[j].buf[0];
45362306a36Sopenharmony_ci				len = msg[j].len - 1;
45462306a36Sopenharmony_ci				i = 1;
45562306a36Sopenharmony_ci				do {
45662306a36Sopenharmony_ci					memcpy(obuf + 3, msg[j].buf + i,
45762306a36Sopenharmony_ci							(len > 16 ? 16 : len));
45862306a36Sopenharmony_ci					dw210x_op_rw(d->udev, 0xc2, 0, 0,
45962306a36Sopenharmony_ci						obuf, (len > 16 ? 16 : len) + 3,
46062306a36Sopenharmony_ci						DW210X_WRITE_MSG);
46162306a36Sopenharmony_ci					i += 16;
46262306a36Sopenharmony_ci					len -= 16;
46362306a36Sopenharmony_ci				} while (len > 0);
46462306a36Sopenharmony_ci			} else {
46562306a36Sopenharmony_ci				/* write registers */
46662306a36Sopenharmony_ci				u8 obuf[MAX_XFER_SIZE];
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci				if (2 + msg[j].len > sizeof(obuf)) {
46962306a36Sopenharmony_ci					warn("i2c wr: len=%d is too big!\n",
47062306a36Sopenharmony_ci					     msg[j].len);
47162306a36Sopenharmony_ci					ret = -EOPNOTSUPP;
47262306a36Sopenharmony_ci					goto unlock;
47362306a36Sopenharmony_ci				}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci				obuf[0] = msg[j].addr << 1;
47662306a36Sopenharmony_ci				obuf[1] = msg[j].len;
47762306a36Sopenharmony_ci				memcpy(obuf + 2, msg[j].buf, msg[j].len);
47862306a36Sopenharmony_ci				dw210x_op_rw(d->udev, 0xc2, 0, 0,
47962306a36Sopenharmony_ci						obuf, msg[j].len + 2,
48062306a36Sopenharmony_ci						DW210X_WRITE_MSG);
48162306a36Sopenharmony_ci			}
48262306a36Sopenharmony_ci			break;
48362306a36Sopenharmony_ci		}
48462306a36Sopenharmony_ci		}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	}
48762306a36Sopenharmony_ci	ret = num;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ciunlock:
49062306a36Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
49162306a36Sopenharmony_ci	return ret;
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
49562306a36Sopenharmony_ci								int num)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
49862306a36Sopenharmony_ci	int ret;
49962306a36Sopenharmony_ci	int i;
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci	if (!d)
50262306a36Sopenharmony_ci		return -ENODEV;
50362306a36Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
50462306a36Sopenharmony_ci		return -EAGAIN;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	switch (num) {
50762306a36Sopenharmony_ci	case 2: {
50862306a36Sopenharmony_ci		/* read */
50962306a36Sopenharmony_ci		/* first write first register number */
51062306a36Sopenharmony_ci		u8 ibuf[MAX_XFER_SIZE], obuf[3];
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci		if (2 + msg[0].len != sizeof(obuf)) {
51362306a36Sopenharmony_ci			warn("i2c rd: len=%d is not 1!\n",
51462306a36Sopenharmony_ci			     msg[0].len);
51562306a36Sopenharmony_ci			ret = -EOPNOTSUPP;
51662306a36Sopenharmony_ci			goto unlock;
51762306a36Sopenharmony_ci		}
51862306a36Sopenharmony_ci		if (2 + msg[1].len > sizeof(ibuf)) {
51962306a36Sopenharmony_ci			warn("i2c rd: len=%d is too big!\n",
52062306a36Sopenharmony_ci			     msg[1].len);
52162306a36Sopenharmony_ci			ret = -EOPNOTSUPP;
52262306a36Sopenharmony_ci			goto unlock;
52362306a36Sopenharmony_ci		}
52462306a36Sopenharmony_ci		obuf[0] = msg[0].addr << 1;
52562306a36Sopenharmony_ci		obuf[1] = msg[0].len;
52662306a36Sopenharmony_ci		obuf[2] = msg[0].buf[0];
52762306a36Sopenharmony_ci		dw210x_op_rw(d->udev, 0xc2, 0, 0,
52862306a36Sopenharmony_ci				obuf, msg[0].len + 2, DW210X_WRITE_MSG);
52962306a36Sopenharmony_ci		/* second read registers */
53062306a36Sopenharmony_ci		dw210x_op_rw(d->udev, 0xc3, 0x19 , 0,
53162306a36Sopenharmony_ci				ibuf, msg[1].len + 2, DW210X_READ_MSG);
53262306a36Sopenharmony_ci		memcpy(msg[1].buf, ibuf + 2, msg[1].len);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci		break;
53562306a36Sopenharmony_ci	}
53662306a36Sopenharmony_ci	case 1:
53762306a36Sopenharmony_ci		switch (msg[0].addr) {
53862306a36Sopenharmony_ci		case 0x60:
53962306a36Sopenharmony_ci		case 0x0c: {
54062306a36Sopenharmony_ci			/* write to register */
54162306a36Sopenharmony_ci			u8 obuf[MAX_XFER_SIZE];
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci			if (2 + msg[0].len > sizeof(obuf)) {
54462306a36Sopenharmony_ci				warn("i2c wr: len=%d is too big!\n",
54562306a36Sopenharmony_ci				     msg[0].len);
54662306a36Sopenharmony_ci				ret = -EOPNOTSUPP;
54762306a36Sopenharmony_ci				goto unlock;
54862306a36Sopenharmony_ci			}
54962306a36Sopenharmony_ci			obuf[0] = msg[0].addr << 1;
55062306a36Sopenharmony_ci			obuf[1] = msg[0].len;
55162306a36Sopenharmony_ci			memcpy(obuf + 2, msg[0].buf, msg[0].len);
55262306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xc2, 0, 0,
55362306a36Sopenharmony_ci					obuf, msg[0].len + 2, DW210X_WRITE_MSG);
55462306a36Sopenharmony_ci			break;
55562306a36Sopenharmony_ci		}
55662306a36Sopenharmony_ci		case(DW2102_RC_QUERY): {
55762306a36Sopenharmony_ci			u8 ibuf[2];
55862306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb8, 0, 0,
55962306a36Sopenharmony_ci					ibuf, 2, DW210X_READ_MSG);
56062306a36Sopenharmony_ci			memcpy(msg[0].buf, ibuf , 2);
56162306a36Sopenharmony_ci			break;
56262306a36Sopenharmony_ci		}
56362306a36Sopenharmony_ci		}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci		break;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	for (i = 0; i < num; i++) {
56962306a36Sopenharmony_ci		deb_xfer("%02x:%02x: %s ", i, msg[i].addr,
57062306a36Sopenharmony_ci				msg[i].flags == 0 ? ">>>" : "<<<");
57162306a36Sopenharmony_ci		debug_dump(msg[i].buf, msg[i].len, deb_xfer);
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci	ret = num;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ciunlock:
57662306a36Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
57762306a36Sopenharmony_ci	return ret;
57862306a36Sopenharmony_ci}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_cistatic int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
58162306a36Sopenharmony_ci								int num)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
58462306a36Sopenharmony_ci	struct usb_device *udev;
58562306a36Sopenharmony_ci	int len, i, j, ret;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (!d)
58862306a36Sopenharmony_ci		return -ENODEV;
58962306a36Sopenharmony_ci	udev = d->udev;
59062306a36Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
59162306a36Sopenharmony_ci		return -EAGAIN;
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	for (j = 0; j < num; j++) {
59462306a36Sopenharmony_ci		switch (msg[j].addr) {
59562306a36Sopenharmony_ci		case (DW2102_RC_QUERY): {
59662306a36Sopenharmony_ci			u8 ibuf[5];
59762306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0xb8, 0, 0,
59862306a36Sopenharmony_ci					ibuf, 5, DW210X_READ_MSG);
59962306a36Sopenharmony_ci			memcpy(msg[j].buf, ibuf + 3, 2);
60062306a36Sopenharmony_ci			break;
60162306a36Sopenharmony_ci		}
60262306a36Sopenharmony_ci		case (DW2102_VOLTAGE_CTRL): {
60362306a36Sopenharmony_ci			u8 obuf[2];
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci			obuf[0] = 1;
60662306a36Sopenharmony_ci			obuf[1] = msg[j].buf[1];/* off-on */
60762306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0x8a, 0, 0,
60862306a36Sopenharmony_ci					obuf, 2, DW210X_WRITE_MSG);
60962306a36Sopenharmony_ci			obuf[0] = 3;
61062306a36Sopenharmony_ci			obuf[1] = msg[j].buf[0];/* 13v-18v */
61162306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0x8a, 0, 0,
61262306a36Sopenharmony_ci					obuf, 2, DW210X_WRITE_MSG);
61362306a36Sopenharmony_ci			break;
61462306a36Sopenharmony_ci		}
61562306a36Sopenharmony_ci		case (DW2102_LED_CTRL): {
61662306a36Sopenharmony_ci			u8 obuf[2];
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci			obuf[0] = 5;
61962306a36Sopenharmony_ci			obuf[1] = msg[j].buf[0];
62062306a36Sopenharmony_ci			dw210x_op_rw(d->udev, 0x8a, 0, 0,
62162306a36Sopenharmony_ci					obuf, 2, DW210X_WRITE_MSG);
62262306a36Sopenharmony_ci			break;
62362306a36Sopenharmony_ci		}
62462306a36Sopenharmony_ci		/*case 0x55: cx24116
62562306a36Sopenharmony_ci		case 0x6a: stv0903
62662306a36Sopenharmony_ci		case 0x68: ds3000, stv0903, rs2000
62762306a36Sopenharmony_ci		case 0x60: ts2020, stv6110, stb6100
62862306a36Sopenharmony_ci		case 0xa0: eeprom */
62962306a36Sopenharmony_ci		default: {
63062306a36Sopenharmony_ci			if (msg[j].flags == I2C_M_RD) {
63162306a36Sopenharmony_ci				/* read registers */
63262306a36Sopenharmony_ci				u8 ibuf[MAX_XFER_SIZE];
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci				if (msg[j].len > sizeof(ibuf)) {
63562306a36Sopenharmony_ci					warn("i2c rd: len=%d is too big!\n",
63662306a36Sopenharmony_ci					     msg[j].len);
63762306a36Sopenharmony_ci					ret = -EOPNOTSUPP;
63862306a36Sopenharmony_ci					goto unlock;
63962306a36Sopenharmony_ci				}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci				dw210x_op_rw(d->udev, 0x91, 0, 0,
64262306a36Sopenharmony_ci						ibuf, msg[j].len,
64362306a36Sopenharmony_ci						DW210X_READ_MSG);
64462306a36Sopenharmony_ci				memcpy(msg[j].buf, ibuf, msg[j].len);
64562306a36Sopenharmony_ci				break;
64662306a36Sopenharmony_ci			} else if ((msg[j].buf[0] == 0xb0) &&
64762306a36Sopenharmony_ci						(msg[j].addr == 0x68)) {
64862306a36Sopenharmony_ci				/* write firmware */
64962306a36Sopenharmony_ci				u8 obuf[19];
65062306a36Sopenharmony_ci				obuf[0] = (msg[j].len > 16 ?
65162306a36Sopenharmony_ci						18 : msg[j].len + 1);
65262306a36Sopenharmony_ci				obuf[1] = msg[j].addr << 1;
65362306a36Sopenharmony_ci				obuf[2] = msg[j].buf[0];
65462306a36Sopenharmony_ci				len = msg[j].len - 1;
65562306a36Sopenharmony_ci				i = 1;
65662306a36Sopenharmony_ci				do {
65762306a36Sopenharmony_ci					memcpy(obuf + 3, msg[j].buf + i,
65862306a36Sopenharmony_ci							(len > 16 ? 16 : len));
65962306a36Sopenharmony_ci					dw210x_op_rw(d->udev, 0x80, 0, 0,
66062306a36Sopenharmony_ci						obuf, (len > 16 ? 16 : len) + 3,
66162306a36Sopenharmony_ci						DW210X_WRITE_MSG);
66262306a36Sopenharmony_ci					i += 16;
66362306a36Sopenharmony_ci					len -= 16;
66462306a36Sopenharmony_ci				} while (len > 0);
66562306a36Sopenharmony_ci			} else if (j < (num - 1)) {
66662306a36Sopenharmony_ci				/* write register addr before read */
66762306a36Sopenharmony_ci				u8 obuf[MAX_XFER_SIZE];
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci				if (2 + msg[j].len > sizeof(obuf)) {
67062306a36Sopenharmony_ci					warn("i2c wr: len=%d is too big!\n",
67162306a36Sopenharmony_ci					     msg[j].len);
67262306a36Sopenharmony_ci					ret = -EOPNOTSUPP;
67362306a36Sopenharmony_ci					goto unlock;
67462306a36Sopenharmony_ci				}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci				obuf[0] = msg[j + 1].len;
67762306a36Sopenharmony_ci				obuf[1] = (msg[j].addr << 1);
67862306a36Sopenharmony_ci				memcpy(obuf + 2, msg[j].buf, msg[j].len);
67962306a36Sopenharmony_ci				dw210x_op_rw(d->udev,
68062306a36Sopenharmony_ci						le16_to_cpu(udev->descriptor.idProduct) ==
68162306a36Sopenharmony_ci						0x7500 ? 0x92 : 0x90, 0, 0,
68262306a36Sopenharmony_ci						obuf, msg[j].len + 2,
68362306a36Sopenharmony_ci						DW210X_WRITE_MSG);
68462306a36Sopenharmony_ci				break;
68562306a36Sopenharmony_ci			} else {
68662306a36Sopenharmony_ci				/* write registers */
68762306a36Sopenharmony_ci				u8 obuf[MAX_XFER_SIZE];
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci				if (2 + msg[j].len > sizeof(obuf)) {
69062306a36Sopenharmony_ci					warn("i2c wr: len=%d is too big!\n",
69162306a36Sopenharmony_ci					     msg[j].len);
69262306a36Sopenharmony_ci					ret = -EOPNOTSUPP;
69362306a36Sopenharmony_ci					goto unlock;
69462306a36Sopenharmony_ci				}
69562306a36Sopenharmony_ci				obuf[0] = msg[j].len + 1;
69662306a36Sopenharmony_ci				obuf[1] = (msg[j].addr << 1);
69762306a36Sopenharmony_ci				memcpy(obuf + 2, msg[j].buf, msg[j].len);
69862306a36Sopenharmony_ci				dw210x_op_rw(d->udev, 0x80, 0, 0,
69962306a36Sopenharmony_ci						obuf, msg[j].len + 2,
70062306a36Sopenharmony_ci						DW210X_WRITE_MSG);
70162306a36Sopenharmony_ci				break;
70262306a36Sopenharmony_ci			}
70362306a36Sopenharmony_ci			break;
70462306a36Sopenharmony_ci		}
70562306a36Sopenharmony_ci		}
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci	ret = num;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ciunlock:
71062306a36Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
71162306a36Sopenharmony_ci	return ret;
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
71562306a36Sopenharmony_ci								int num)
71662306a36Sopenharmony_ci{
71762306a36Sopenharmony_ci	struct dvb_usb_device *d = i2c_get_adapdata(adap);
71862306a36Sopenharmony_ci	struct dw2102_state *state;
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci	if (!d)
72162306a36Sopenharmony_ci		return -ENODEV;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	state = d->priv;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
72662306a36Sopenharmony_ci		return -EAGAIN;
72762306a36Sopenharmony_ci	if (mutex_lock_interruptible(&d->data_mutex) < 0) {
72862306a36Sopenharmony_ci		mutex_unlock(&d->i2c_mutex);
72962306a36Sopenharmony_ci		return -EAGAIN;
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	switch (num) {
73362306a36Sopenharmony_ci	case 1:
73462306a36Sopenharmony_ci		switch (msg[0].addr) {
73562306a36Sopenharmony_ci		case SU3000_STREAM_CTRL:
73662306a36Sopenharmony_ci			state->data[0] = msg[0].buf[0] + 0x36;
73762306a36Sopenharmony_ci			state->data[1] = 3;
73862306a36Sopenharmony_ci			state->data[2] = 0;
73962306a36Sopenharmony_ci			if (dvb_usb_generic_rw(d, state->data, 3,
74062306a36Sopenharmony_ci					state->data, 0, 0) < 0)
74162306a36Sopenharmony_ci				err("i2c transfer failed.");
74262306a36Sopenharmony_ci			break;
74362306a36Sopenharmony_ci		case DW2102_RC_QUERY:
74462306a36Sopenharmony_ci			state->data[0] = 0x10;
74562306a36Sopenharmony_ci			if (dvb_usb_generic_rw(d, state->data, 1,
74662306a36Sopenharmony_ci					state->data, 2, 0) < 0)
74762306a36Sopenharmony_ci				err("i2c transfer failed.");
74862306a36Sopenharmony_ci			msg[0].buf[1] = state->data[0];
74962306a36Sopenharmony_ci			msg[0].buf[0] = state->data[1];
75062306a36Sopenharmony_ci			break;
75162306a36Sopenharmony_ci		default:
75262306a36Sopenharmony_ci			if (3 + msg[0].len > sizeof(state->data)) {
75362306a36Sopenharmony_ci				warn("i2c wr: len=%d is too big!\n",
75462306a36Sopenharmony_ci				     msg[0].len);
75562306a36Sopenharmony_ci				num = -EOPNOTSUPP;
75662306a36Sopenharmony_ci				break;
75762306a36Sopenharmony_ci			}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci			/* always i2c write*/
76062306a36Sopenharmony_ci			state->data[0] = 0x08;
76162306a36Sopenharmony_ci			state->data[1] = msg[0].addr;
76262306a36Sopenharmony_ci			state->data[2] = msg[0].len;
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci			memcpy(&state->data[3], msg[0].buf, msg[0].len);
76562306a36Sopenharmony_ci
76662306a36Sopenharmony_ci			if (dvb_usb_generic_rw(d, state->data, msg[0].len + 3,
76762306a36Sopenharmony_ci						state->data, 1, 0) < 0)
76862306a36Sopenharmony_ci				err("i2c transfer failed.");
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci		}
77162306a36Sopenharmony_ci		break;
77262306a36Sopenharmony_ci	case 2:
77362306a36Sopenharmony_ci		/* always i2c read */
77462306a36Sopenharmony_ci		if (4 + msg[0].len > sizeof(state->data)) {
77562306a36Sopenharmony_ci			warn("i2c rd: len=%d is too big!\n",
77662306a36Sopenharmony_ci			     msg[0].len);
77762306a36Sopenharmony_ci			num = -EOPNOTSUPP;
77862306a36Sopenharmony_ci			break;
77962306a36Sopenharmony_ci		}
78062306a36Sopenharmony_ci		if (1 + msg[1].len > sizeof(state->data)) {
78162306a36Sopenharmony_ci			warn("i2c rd: len=%d is too big!\n",
78262306a36Sopenharmony_ci			     msg[1].len);
78362306a36Sopenharmony_ci			num = -EOPNOTSUPP;
78462306a36Sopenharmony_ci			break;
78562306a36Sopenharmony_ci		}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci		state->data[0] = 0x09;
78862306a36Sopenharmony_ci		state->data[1] = msg[0].len;
78962306a36Sopenharmony_ci		state->data[2] = msg[1].len;
79062306a36Sopenharmony_ci		state->data[3] = msg[0].addr;
79162306a36Sopenharmony_ci		memcpy(&state->data[4], msg[0].buf, msg[0].len);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci		if (dvb_usb_generic_rw(d, state->data, msg[0].len + 4,
79462306a36Sopenharmony_ci					state->data, msg[1].len + 1, 0) < 0)
79562306a36Sopenharmony_ci			err("i2c transfer failed.");
79662306a36Sopenharmony_ci
79762306a36Sopenharmony_ci		memcpy(msg[1].buf, &state->data[1], msg[1].len);
79862306a36Sopenharmony_ci		break;
79962306a36Sopenharmony_ci	default:
80062306a36Sopenharmony_ci		warn("more than 2 i2c messages at a time is not handled yet.");
80162306a36Sopenharmony_ci		break;
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci	mutex_unlock(&d->data_mutex);
80462306a36Sopenharmony_ci	mutex_unlock(&d->i2c_mutex);
80562306a36Sopenharmony_ci	return num;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_cistatic u32 dw210x_i2c_func(struct i2c_adapter *adapter)
80962306a36Sopenharmony_ci{
81062306a36Sopenharmony_ci	return I2C_FUNC_I2C;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_cistatic struct i2c_algorithm dw2102_i2c_algo = {
81462306a36Sopenharmony_ci	.master_xfer = dw2102_i2c_transfer,
81562306a36Sopenharmony_ci	.functionality = dw210x_i2c_func,
81662306a36Sopenharmony_ci};
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic struct i2c_algorithm dw2102_serit_i2c_algo = {
81962306a36Sopenharmony_ci	.master_xfer = dw2102_serit_i2c_transfer,
82062306a36Sopenharmony_ci	.functionality = dw210x_i2c_func,
82162306a36Sopenharmony_ci};
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_cistatic struct i2c_algorithm dw2102_earda_i2c_algo = {
82462306a36Sopenharmony_ci	.master_xfer = dw2102_earda_i2c_transfer,
82562306a36Sopenharmony_ci	.functionality = dw210x_i2c_func,
82662306a36Sopenharmony_ci};
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_cistatic struct i2c_algorithm dw2104_i2c_algo = {
82962306a36Sopenharmony_ci	.master_xfer = dw2104_i2c_transfer,
83062306a36Sopenharmony_ci	.functionality = dw210x_i2c_func,
83162306a36Sopenharmony_ci};
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cistatic struct i2c_algorithm dw3101_i2c_algo = {
83462306a36Sopenharmony_ci	.master_xfer = dw3101_i2c_transfer,
83562306a36Sopenharmony_ci	.functionality = dw210x_i2c_func,
83662306a36Sopenharmony_ci};
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_cistatic struct i2c_algorithm s6x0_i2c_algo = {
83962306a36Sopenharmony_ci	.master_xfer = s6x0_i2c_transfer,
84062306a36Sopenharmony_ci	.functionality = dw210x_i2c_func,
84162306a36Sopenharmony_ci};
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic struct i2c_algorithm su3000_i2c_algo = {
84462306a36Sopenharmony_ci	.master_xfer = su3000_i2c_transfer,
84562306a36Sopenharmony_ci	.functionality = dw210x_i2c_func,
84662306a36Sopenharmony_ci};
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic int dw210x_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
84962306a36Sopenharmony_ci{
85062306a36Sopenharmony_ci	int i;
85162306a36Sopenharmony_ci	u8 ibuf[] = {0, 0};
85262306a36Sopenharmony_ci	u8 eeprom[256], eepromline[16];
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
85562306a36Sopenharmony_ci		if (dw210x_op_rw(d->udev, 0xb6, 0xa0 , i, ibuf, 2, DW210X_READ_MSG) < 0) {
85662306a36Sopenharmony_ci			err("read eeprom failed.");
85762306a36Sopenharmony_ci			return -EIO;
85862306a36Sopenharmony_ci		} else {
85962306a36Sopenharmony_ci			eepromline[i%16] = ibuf[0];
86062306a36Sopenharmony_ci			eeprom[i] = ibuf[0];
86162306a36Sopenharmony_ci		}
86262306a36Sopenharmony_ci		if ((i % 16) == 15) {
86362306a36Sopenharmony_ci			deb_xfer("%02x: ", i - 15);
86462306a36Sopenharmony_ci			debug_dump(eepromline, 16, deb_xfer);
86562306a36Sopenharmony_ci		}
86662306a36Sopenharmony_ci	}
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	memcpy(mac, eeprom + 8, 6);
86962306a36Sopenharmony_ci	return 0;
87062306a36Sopenharmony_ci};
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistatic int s6x0_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
87362306a36Sopenharmony_ci{
87462306a36Sopenharmony_ci	int i, ret;
87562306a36Sopenharmony_ci	u8 ibuf[] = { 0 }, obuf[] = { 0 };
87662306a36Sopenharmony_ci	u8 eeprom[256], eepromline[16];
87762306a36Sopenharmony_ci	struct i2c_msg msg[] = {
87862306a36Sopenharmony_ci		{
87962306a36Sopenharmony_ci			.addr = 0xa0 >> 1,
88062306a36Sopenharmony_ci			.flags = 0,
88162306a36Sopenharmony_ci			.buf = obuf,
88262306a36Sopenharmony_ci			.len = 1,
88362306a36Sopenharmony_ci		}, {
88462306a36Sopenharmony_ci			.addr = 0xa0 >> 1,
88562306a36Sopenharmony_ci			.flags = I2C_M_RD,
88662306a36Sopenharmony_ci			.buf = ibuf,
88762306a36Sopenharmony_ci			.len = 1,
88862306a36Sopenharmony_ci		}
88962306a36Sopenharmony_ci	};
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	for (i = 0; i < 256; i++) {
89262306a36Sopenharmony_ci		obuf[0] = i;
89362306a36Sopenharmony_ci		ret = s6x0_i2c_transfer(&d->i2c_adap, msg, 2);
89462306a36Sopenharmony_ci		if (ret != 2) {
89562306a36Sopenharmony_ci			err("read eeprom failed.");
89662306a36Sopenharmony_ci			return -EIO;
89762306a36Sopenharmony_ci		} else {
89862306a36Sopenharmony_ci			eepromline[i % 16] = ibuf[0];
89962306a36Sopenharmony_ci			eeprom[i] = ibuf[0];
90062306a36Sopenharmony_ci		}
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci		if ((i % 16) == 15) {
90362306a36Sopenharmony_ci			deb_xfer("%02x: ", i - 15);
90462306a36Sopenharmony_ci			debug_dump(eepromline, 16, deb_xfer);
90562306a36Sopenharmony_ci		}
90662306a36Sopenharmony_ci	}
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	memcpy(mac, eeprom + 16, 6);
90962306a36Sopenharmony_ci	return 0;
91062306a36Sopenharmony_ci};
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_cistatic int su3000_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	static u8 command_start[] = {0x00};
91562306a36Sopenharmony_ci	static u8 command_stop[] = {0x01};
91662306a36Sopenharmony_ci	struct i2c_msg msg = {
91762306a36Sopenharmony_ci		.addr = SU3000_STREAM_CTRL,
91862306a36Sopenharmony_ci		.flags = 0,
91962306a36Sopenharmony_ci		.buf = onoff ? command_start : command_stop,
92062306a36Sopenharmony_ci		.len = 1
92162306a36Sopenharmony_ci	};
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	i2c_transfer(&adap->dev->i2c_adap, &msg, 1);
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	return 0;
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_cistatic int su3000_power_ctrl(struct dvb_usb_device *d, int i)
92962306a36Sopenharmony_ci{
93062306a36Sopenharmony_ci	struct dw2102_state *state = d->priv;
93162306a36Sopenharmony_ci	int ret = 0;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	info("%s: %d, initialized %d", __func__, i, state->initialized);
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	if (i && !state->initialized) {
93662306a36Sopenharmony_ci		mutex_lock(&d->data_mutex);
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci		state->data[0] = 0xde;
93962306a36Sopenharmony_ci		state->data[1] = 0;
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci		state->initialized = 1;
94262306a36Sopenharmony_ci		/* reset board */
94362306a36Sopenharmony_ci		ret = dvb_usb_generic_rw(d, state->data, 2, NULL, 0, 0);
94462306a36Sopenharmony_ci		mutex_unlock(&d->data_mutex);
94562306a36Sopenharmony_ci	}
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	return ret;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic int su3000_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	int i;
95362306a36Sopenharmony_ci	u8 obuf[] = { 0x1f, 0xf0 };
95462306a36Sopenharmony_ci	u8 ibuf[] = { 0 };
95562306a36Sopenharmony_ci	struct i2c_msg msg[] = {
95662306a36Sopenharmony_ci		{
95762306a36Sopenharmony_ci			.addr = 0x51,
95862306a36Sopenharmony_ci			.flags = 0,
95962306a36Sopenharmony_ci			.buf = obuf,
96062306a36Sopenharmony_ci			.len = 2,
96162306a36Sopenharmony_ci		}, {
96262306a36Sopenharmony_ci			.addr = 0x51,
96362306a36Sopenharmony_ci			.flags = I2C_M_RD,
96462306a36Sopenharmony_ci			.buf = ibuf,
96562306a36Sopenharmony_ci			.len = 1,
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci		}
96862306a36Sopenharmony_ci	};
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	for (i = 0; i < 6; i++) {
97162306a36Sopenharmony_ci		obuf[1] = 0xf0 + i;
97262306a36Sopenharmony_ci		if (i2c_transfer(&d->i2c_adap, msg, 2) != 2)
97362306a36Sopenharmony_ci			return -EIO;
97462306a36Sopenharmony_ci		else
97562306a36Sopenharmony_ci			mac[i] = ibuf[0];
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	return 0;
97962306a36Sopenharmony_ci}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_cistatic int su3000_identify_state(struct usb_device *udev,
98262306a36Sopenharmony_ci				 const struct dvb_usb_device_properties *props,
98362306a36Sopenharmony_ci				 const struct dvb_usb_device_description **desc,
98462306a36Sopenharmony_ci				 int *cold)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	info("%s", __func__);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	*cold = 0;
98962306a36Sopenharmony_ci	return 0;
99062306a36Sopenharmony_ci}
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_cistatic int dw210x_set_voltage(struct dvb_frontend *fe,
99362306a36Sopenharmony_ci			      enum fe_sec_voltage voltage)
99462306a36Sopenharmony_ci{
99562306a36Sopenharmony_ci	static u8 command_13v[] = {0x00, 0x01};
99662306a36Sopenharmony_ci	static u8 command_18v[] = {0x01, 0x01};
99762306a36Sopenharmony_ci	static u8 command_off[] = {0x00, 0x00};
99862306a36Sopenharmony_ci	struct i2c_msg msg = {
99962306a36Sopenharmony_ci		.addr = DW2102_VOLTAGE_CTRL,
100062306a36Sopenharmony_ci		.flags = 0,
100162306a36Sopenharmony_ci		.buf = command_off,
100262306a36Sopenharmony_ci		.len = 2,
100362306a36Sopenharmony_ci	};
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	struct dvb_usb_adapter *udev_adap = fe->dvb->priv;
100662306a36Sopenharmony_ci	if (voltage == SEC_VOLTAGE_18)
100762306a36Sopenharmony_ci		msg.buf = command_18v;
100862306a36Sopenharmony_ci	else if (voltage == SEC_VOLTAGE_13)
100962306a36Sopenharmony_ci		msg.buf = command_13v;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	return 0;
101462306a36Sopenharmony_ci}
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_cistatic int s660_set_voltage(struct dvb_frontend *fe,
101762306a36Sopenharmony_ci			    enum fe_sec_voltage voltage)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	struct dvb_usb_adapter *d = fe->dvb->priv;
102062306a36Sopenharmony_ci	struct dw2102_state *st = d->dev->priv;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	dw210x_set_voltage(fe, voltage);
102362306a36Sopenharmony_ci	if (st->old_set_voltage)
102462306a36Sopenharmony_ci		st->old_set_voltage(fe, voltage);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_ci	return 0;
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic void dw210x_led_ctrl(struct dvb_frontend *fe, int offon)
103062306a36Sopenharmony_ci{
103162306a36Sopenharmony_ci	static u8 led_off[] = { 0 };
103262306a36Sopenharmony_ci	static u8 led_on[] = { 1 };
103362306a36Sopenharmony_ci	struct i2c_msg msg = {
103462306a36Sopenharmony_ci		.addr = DW2102_LED_CTRL,
103562306a36Sopenharmony_ci		.flags = 0,
103662306a36Sopenharmony_ci		.buf = led_off,
103762306a36Sopenharmony_ci		.len = 1
103862306a36Sopenharmony_ci	};
103962306a36Sopenharmony_ci	struct dvb_usb_adapter *udev_adap = fe->dvb->priv;
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	if (offon)
104262306a36Sopenharmony_ci		msg.buf = led_on;
104362306a36Sopenharmony_ci	i2c_transfer(&udev_adap->dev->i2c_adap, &msg, 1);
104462306a36Sopenharmony_ci}
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic int tt_s2_4600_read_status(struct dvb_frontend *fe,
104762306a36Sopenharmony_ci				  enum fe_status *status)
104862306a36Sopenharmony_ci{
104962306a36Sopenharmony_ci	struct dvb_usb_adapter *d = fe->dvb->priv;
105062306a36Sopenharmony_ci	struct dw2102_state *st = d->dev->priv;
105162306a36Sopenharmony_ci	int ret;
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	ret = st->fe_read_status(fe, status);
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* resync slave fifo when signal change from unlock to lock */
105662306a36Sopenharmony_ci	if ((*status & FE_HAS_LOCK) && (!st->last_lock))
105762306a36Sopenharmony_ci		su3000_streaming_ctrl(d, 1);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	st->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0;
106062306a36Sopenharmony_ci	return ret;
106162306a36Sopenharmony_ci}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_cistatic struct stv0299_config sharp_z0194a_config = {
106462306a36Sopenharmony_ci	.demod_address = 0x68,
106562306a36Sopenharmony_ci	.inittab = sharp_z0194a_inittab,
106662306a36Sopenharmony_ci	.mclk = 88000000UL,
106762306a36Sopenharmony_ci	.invert = 1,
106862306a36Sopenharmony_ci	.skip_reinit = 0,
106962306a36Sopenharmony_ci	.lock_output = STV0299_LOCKOUTPUT_1,
107062306a36Sopenharmony_ci	.volt13_op0_op1 = STV0299_VOLT13_OP1,
107162306a36Sopenharmony_ci	.min_delay_ms = 100,
107262306a36Sopenharmony_ci	.set_symbol_rate = sharp_z0194a_set_symbol_rate,
107362306a36Sopenharmony_ci};
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_cistatic struct cx24116_config dw2104_config = {
107662306a36Sopenharmony_ci	.demod_address = 0x55,
107762306a36Sopenharmony_ci	.mpg_clk_pos_pol = 0x01,
107862306a36Sopenharmony_ci};
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_cistatic struct si21xx_config serit_sp1511lhb_config = {
108162306a36Sopenharmony_ci	.demod_address = 0x68,
108262306a36Sopenharmony_ci	.min_delay_ms = 100,
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci};
108562306a36Sopenharmony_ci
108662306a36Sopenharmony_cistatic struct tda10023_config dw3101_tda10023_config = {
108762306a36Sopenharmony_ci	.demod_address = 0x0c,
108862306a36Sopenharmony_ci	.invert = 1,
108962306a36Sopenharmony_ci};
109062306a36Sopenharmony_ci
109162306a36Sopenharmony_cistatic struct mt312_config zl313_config = {
109262306a36Sopenharmony_ci	.demod_address = 0x0e,
109362306a36Sopenharmony_ci};
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_cistatic struct ds3000_config dw2104_ds3000_config = {
109662306a36Sopenharmony_ci	.demod_address = 0x68,
109762306a36Sopenharmony_ci};
109862306a36Sopenharmony_ci
109962306a36Sopenharmony_cistatic struct ts2020_config dw2104_ts2020_config = {
110062306a36Sopenharmony_ci	.tuner_address = 0x60,
110162306a36Sopenharmony_ci	.clk_out_div = 1,
110262306a36Sopenharmony_ci	.frequency_div = 1060000,
110362306a36Sopenharmony_ci};
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_cistatic struct ds3000_config s660_ds3000_config = {
110662306a36Sopenharmony_ci	.demod_address = 0x68,
110762306a36Sopenharmony_ci	.ci_mode = 1,
110862306a36Sopenharmony_ci	.set_lock_led = dw210x_led_ctrl,
110962306a36Sopenharmony_ci};
111062306a36Sopenharmony_ci
111162306a36Sopenharmony_cistatic struct ts2020_config s660_ts2020_config = {
111262306a36Sopenharmony_ci	.tuner_address = 0x60,
111362306a36Sopenharmony_ci	.clk_out_div = 1,
111462306a36Sopenharmony_ci	.frequency_div = 1146000,
111562306a36Sopenharmony_ci};
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_cistatic struct stv0900_config dw2104a_stv0900_config = {
111862306a36Sopenharmony_ci	.demod_address = 0x6a,
111962306a36Sopenharmony_ci	.demod_mode = 0,
112062306a36Sopenharmony_ci	.xtal = 27000000,
112162306a36Sopenharmony_ci	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
112262306a36Sopenharmony_ci	.diseqc_mode = 2,/* 2/3 PWM */
112362306a36Sopenharmony_ci	.tun1_maddress = 0,/* 0x60 */
112462306a36Sopenharmony_ci	.tun1_adc = 0,/* 2 Vpp */
112562306a36Sopenharmony_ci	.path1_mode = 3,
112662306a36Sopenharmony_ci};
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_cistatic struct stb6100_config dw2104a_stb6100_config = {
112962306a36Sopenharmony_ci	.tuner_address = 0x60,
113062306a36Sopenharmony_ci	.refclock = 27000000,
113162306a36Sopenharmony_ci};
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_cistatic struct stv0900_config dw2104_stv0900_config = {
113462306a36Sopenharmony_ci	.demod_address = 0x68,
113562306a36Sopenharmony_ci	.demod_mode = 0,
113662306a36Sopenharmony_ci	.xtal = 8000000,
113762306a36Sopenharmony_ci	.clkmode = 3,
113862306a36Sopenharmony_ci	.diseqc_mode = 2,
113962306a36Sopenharmony_ci	.tun1_maddress = 0,
114062306a36Sopenharmony_ci	.tun1_adc = 1,/* 1 Vpp */
114162306a36Sopenharmony_ci	.path1_mode = 3,
114262306a36Sopenharmony_ci};
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_cistatic struct stv6110_config dw2104_stv6110_config = {
114562306a36Sopenharmony_ci	.i2c_address = 0x60,
114662306a36Sopenharmony_ci	.mclk = 16000000,
114762306a36Sopenharmony_ci	.clk_div = 1,
114862306a36Sopenharmony_ci};
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_cistatic struct stv0900_config prof_7500_stv0900_config = {
115162306a36Sopenharmony_ci	.demod_address = 0x6a,
115262306a36Sopenharmony_ci	.demod_mode = 0,
115362306a36Sopenharmony_ci	.xtal = 27000000,
115462306a36Sopenharmony_ci	.clkmode = 3,/* 0-CLKI, 2-XTALI, else AUTO */
115562306a36Sopenharmony_ci	.diseqc_mode = 2,/* 2/3 PWM */
115662306a36Sopenharmony_ci	.tun1_maddress = 0,/* 0x60 */
115762306a36Sopenharmony_ci	.tun1_adc = 0,/* 2 Vpp */
115862306a36Sopenharmony_ci	.path1_mode = 3,
115962306a36Sopenharmony_ci	.tun1_type = 3,
116062306a36Sopenharmony_ci	.set_lock_led = dw210x_led_ctrl,
116162306a36Sopenharmony_ci};
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_cistatic struct ds3000_config su3000_ds3000_config = {
116462306a36Sopenharmony_ci	.demod_address = 0x68,
116562306a36Sopenharmony_ci	.ci_mode = 1,
116662306a36Sopenharmony_ci	.set_lock_led = dw210x_led_ctrl,
116762306a36Sopenharmony_ci};
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_cistatic struct cxd2820r_config cxd2820r_config = {
117062306a36Sopenharmony_ci	.i2c_address = 0x6c, /* (0xd8 >> 1) */
117162306a36Sopenharmony_ci	.ts_mode = 0x38,
117262306a36Sopenharmony_ci	.ts_clock_inv = 1,
117362306a36Sopenharmony_ci};
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_cistatic struct tda18271_config tda18271_config = {
117662306a36Sopenharmony_ci	.output_opt = TDA18271_OUTPUT_LT_OFF,
117762306a36Sopenharmony_ci	.gate = TDA18271_GATE_DIGITAL,
117862306a36Sopenharmony_ci};
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_cistatic u8 m88rs2000_inittab[] = {
118162306a36Sopenharmony_ci	DEMOD_WRITE, 0x9a, 0x30,
118262306a36Sopenharmony_ci	DEMOD_WRITE, 0x00, 0x01,
118362306a36Sopenharmony_ci	WRITE_DELAY, 0x19, 0x00,
118462306a36Sopenharmony_ci	DEMOD_WRITE, 0x00, 0x00,
118562306a36Sopenharmony_ci	DEMOD_WRITE, 0x9a, 0xb0,
118662306a36Sopenharmony_ci	DEMOD_WRITE, 0x81, 0xc1,
118762306a36Sopenharmony_ci	DEMOD_WRITE, 0x81, 0x81,
118862306a36Sopenharmony_ci	DEMOD_WRITE, 0x86, 0xc6,
118962306a36Sopenharmony_ci	DEMOD_WRITE, 0x9a, 0x30,
119062306a36Sopenharmony_ci	DEMOD_WRITE, 0xf0, 0x80,
119162306a36Sopenharmony_ci	DEMOD_WRITE, 0xf1, 0xbf,
119262306a36Sopenharmony_ci	DEMOD_WRITE, 0xb0, 0x45,
119362306a36Sopenharmony_ci	DEMOD_WRITE, 0xb2, 0x01,
119462306a36Sopenharmony_ci	DEMOD_WRITE, 0x9a, 0xb0,
119562306a36Sopenharmony_ci	0xff, 0xaa, 0xff
119662306a36Sopenharmony_ci};
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_cistatic struct m88rs2000_config s421_m88rs2000_config = {
119962306a36Sopenharmony_ci	.demod_addr = 0x68,
120062306a36Sopenharmony_ci	.inittab = m88rs2000_inittab,
120162306a36Sopenharmony_ci};
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_cistatic int dw2104_frontend_attach(struct dvb_usb_adapter *d)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	struct dvb_tuner_ops *tuner_ops = NULL;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	if (demod_probe & 4) {
120862306a36Sopenharmony_ci		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104a_stv0900_config,
120962306a36Sopenharmony_ci				&d->dev->i2c_adap, 0);
121062306a36Sopenharmony_ci		if (d->fe_adap[0].fe != NULL) {
121162306a36Sopenharmony_ci			if (dvb_attach(stb6100_attach, d->fe_adap[0].fe,
121262306a36Sopenharmony_ci					&dw2104a_stb6100_config,
121362306a36Sopenharmony_ci					&d->dev->i2c_adap)) {
121462306a36Sopenharmony_ci				tuner_ops = &d->fe_adap[0].fe->ops.tuner_ops;
121562306a36Sopenharmony_ci				tuner_ops->set_frequency = stb6100_set_freq;
121662306a36Sopenharmony_ci				tuner_ops->get_frequency = stb6100_get_freq;
121762306a36Sopenharmony_ci				tuner_ops->set_bandwidth = stb6100_set_bandw;
121862306a36Sopenharmony_ci				tuner_ops->get_bandwidth = stb6100_get_bandw;
121962306a36Sopenharmony_ci				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
122062306a36Sopenharmony_ci				info("Attached STV0900+STB6100!");
122162306a36Sopenharmony_ci				return 0;
122262306a36Sopenharmony_ci			}
122362306a36Sopenharmony_ci		}
122462306a36Sopenharmony_ci	}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (demod_probe & 2) {
122762306a36Sopenharmony_ci		d->fe_adap[0].fe = dvb_attach(stv0900_attach, &dw2104_stv0900_config,
122862306a36Sopenharmony_ci				&d->dev->i2c_adap, 0);
122962306a36Sopenharmony_ci		if (d->fe_adap[0].fe != NULL) {
123062306a36Sopenharmony_ci			if (dvb_attach(stv6110_attach, d->fe_adap[0].fe,
123162306a36Sopenharmony_ci					&dw2104_stv6110_config,
123262306a36Sopenharmony_ci					&d->dev->i2c_adap)) {
123362306a36Sopenharmony_ci				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
123462306a36Sopenharmony_ci				info("Attached STV0900+STV6110A!");
123562306a36Sopenharmony_ci				return 0;
123662306a36Sopenharmony_ci			}
123762306a36Sopenharmony_ci		}
123862306a36Sopenharmony_ci	}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	if (demod_probe & 1) {
124162306a36Sopenharmony_ci		d->fe_adap[0].fe = dvb_attach(cx24116_attach, &dw2104_config,
124262306a36Sopenharmony_ci				&d->dev->i2c_adap);
124362306a36Sopenharmony_ci		if (d->fe_adap[0].fe != NULL) {
124462306a36Sopenharmony_ci			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
124562306a36Sopenharmony_ci			info("Attached cx24116!");
124662306a36Sopenharmony_ci			return 0;
124762306a36Sopenharmony_ci		}
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &dw2104_ds3000_config,
125162306a36Sopenharmony_ci			&d->dev->i2c_adap);
125262306a36Sopenharmony_ci	if (d->fe_adap[0].fe != NULL) {
125362306a36Sopenharmony_ci		dvb_attach(ts2020_attach, d->fe_adap[0].fe,
125462306a36Sopenharmony_ci			&dw2104_ts2020_config, &d->dev->i2c_adap);
125562306a36Sopenharmony_ci		d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
125662306a36Sopenharmony_ci		info("Attached DS3000!");
125762306a36Sopenharmony_ci		return 0;
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	return -EIO;
126162306a36Sopenharmony_ci}
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_cistatic struct dvb_usb_device_properties dw2102_properties;
126462306a36Sopenharmony_cistatic struct dvb_usb_device_properties dw2104_properties;
126562306a36Sopenharmony_cistatic struct dvb_usb_device_properties s6x0_properties;
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_cistatic int dw2102_frontend_attach(struct dvb_usb_adapter *d)
126862306a36Sopenharmony_ci{
126962306a36Sopenharmony_ci	if (dw2102_properties.i2c_algo == &dw2102_serit_i2c_algo) {
127062306a36Sopenharmony_ci		/*dw2102_properties.adapter->tuner_attach = NULL;*/
127162306a36Sopenharmony_ci		d->fe_adap[0].fe = dvb_attach(si21xx_attach, &serit_sp1511lhb_config,
127262306a36Sopenharmony_ci					&d->dev->i2c_adap);
127362306a36Sopenharmony_ci		if (d->fe_adap[0].fe != NULL) {
127462306a36Sopenharmony_ci			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
127562306a36Sopenharmony_ci			info("Attached si21xx!");
127662306a36Sopenharmony_ci			return 0;
127762306a36Sopenharmony_ci		}
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	if (dw2102_properties.i2c_algo == &dw2102_earda_i2c_algo) {
128162306a36Sopenharmony_ci		d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
128262306a36Sopenharmony_ci					&d->dev->i2c_adap);
128362306a36Sopenharmony_ci		if (d->fe_adap[0].fe != NULL) {
128462306a36Sopenharmony_ci			if (dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61,
128562306a36Sopenharmony_ci					&d->dev->i2c_adap)) {
128662306a36Sopenharmony_ci				d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
128762306a36Sopenharmony_ci				info("Attached stv0288!");
128862306a36Sopenharmony_ci				return 0;
128962306a36Sopenharmony_ci			}
129062306a36Sopenharmony_ci		}
129162306a36Sopenharmony_ci	}
129262306a36Sopenharmony_ci
129362306a36Sopenharmony_ci	if (dw2102_properties.i2c_algo == &dw2102_i2c_algo) {
129462306a36Sopenharmony_ci		/*dw2102_properties.adapter->tuner_attach = dw2102_tuner_attach;*/
129562306a36Sopenharmony_ci		d->fe_adap[0].fe = dvb_attach(stv0299_attach, &sharp_z0194a_config,
129662306a36Sopenharmony_ci					&d->dev->i2c_adap);
129762306a36Sopenharmony_ci		if (d->fe_adap[0].fe != NULL) {
129862306a36Sopenharmony_ci			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
129962306a36Sopenharmony_ci			info("Attached stv0299!");
130062306a36Sopenharmony_ci			return 0;
130162306a36Sopenharmony_ci		}
130262306a36Sopenharmony_ci	}
130362306a36Sopenharmony_ci	return -EIO;
130462306a36Sopenharmony_ci}
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_cistatic int dw3101_frontend_attach(struct dvb_usb_adapter *d)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	d->fe_adap[0].fe = dvb_attach(tda10023_attach, &dw3101_tda10023_config,
130962306a36Sopenharmony_ci				&d->dev->i2c_adap, 0x48);
131062306a36Sopenharmony_ci	if (d->fe_adap[0].fe != NULL) {
131162306a36Sopenharmony_ci		info("Attached tda10023!");
131262306a36Sopenharmony_ci		return 0;
131362306a36Sopenharmony_ci	}
131462306a36Sopenharmony_ci	return -EIO;
131562306a36Sopenharmony_ci}
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_cistatic int zl100313_frontend_attach(struct dvb_usb_adapter *d)
131862306a36Sopenharmony_ci{
131962306a36Sopenharmony_ci	d->fe_adap[0].fe = dvb_attach(mt312_attach, &zl313_config,
132062306a36Sopenharmony_ci			&d->dev->i2c_adap);
132162306a36Sopenharmony_ci	if (d->fe_adap[0].fe != NULL) {
132262306a36Sopenharmony_ci		if (dvb_attach(zl10039_attach, d->fe_adap[0].fe, 0x60,
132362306a36Sopenharmony_ci				&d->dev->i2c_adap)) {
132462306a36Sopenharmony_ci			d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
132562306a36Sopenharmony_ci			info("Attached zl100313+zl10039!");
132662306a36Sopenharmony_ci			return 0;
132762306a36Sopenharmony_ci		}
132862306a36Sopenharmony_ci	}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	return -EIO;
133162306a36Sopenharmony_ci}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_cistatic int stv0288_frontend_attach(struct dvb_usb_adapter *d)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	u8 obuf[] = {7, 1};
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	d->fe_adap[0].fe = dvb_attach(stv0288_attach, &earda_config,
133862306a36Sopenharmony_ci			&d->dev->i2c_adap);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	if (d->fe_adap[0].fe == NULL)
134162306a36Sopenharmony_ci		return -EIO;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	if (NULL == dvb_attach(stb6000_attach, d->fe_adap[0].fe, 0x61, &d->dev->i2c_adap))
134462306a36Sopenharmony_ci		return -EIO;
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	info("Attached stv0288+stb6000!");
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	return 0;
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci}
135562306a36Sopenharmony_ci
135662306a36Sopenharmony_cistatic int ds3000_frontend_attach(struct dvb_usb_adapter *d)
135762306a36Sopenharmony_ci{
135862306a36Sopenharmony_ci	struct dw2102_state *st = d->dev->priv;
135962306a36Sopenharmony_ci	u8 obuf[] = {7, 1};
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	d->fe_adap[0].fe = dvb_attach(ds3000_attach, &s660_ds3000_config,
136262306a36Sopenharmony_ci			&d->dev->i2c_adap);
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	if (d->fe_adap[0].fe == NULL)
136562306a36Sopenharmony_ci		return -EIO;
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	dvb_attach(ts2020_attach, d->fe_adap[0].fe, &s660_ts2020_config,
136862306a36Sopenharmony_ci		&d->dev->i2c_adap);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	st->old_set_voltage = d->fe_adap[0].fe->ops.set_voltage;
137162306a36Sopenharmony_ci	d->fe_adap[0].fe->ops.set_voltage = s660_set_voltage;
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci	dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	info("Attached ds3000+ts2020!");
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	return 0;
137862306a36Sopenharmony_ci}
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_cistatic int prof_7500_frontend_attach(struct dvb_usb_adapter *d)
138162306a36Sopenharmony_ci{
138262306a36Sopenharmony_ci	u8 obuf[] = {7, 1};
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	d->fe_adap[0].fe = dvb_attach(stv0900_attach, &prof_7500_stv0900_config,
138562306a36Sopenharmony_ci					&d->dev->i2c_adap, 0);
138662306a36Sopenharmony_ci	if (d->fe_adap[0].fe == NULL)
138762306a36Sopenharmony_ci		return -EIO;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	d->fe_adap[0].fe->ops.set_voltage = dw210x_set_voltage;
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	dw210x_op_rw(d->dev->udev, 0x8a, 0, 0, obuf, 2, DW210X_WRITE_MSG);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	info("Attached STV0900+STB6100A!");
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	return 0;
139662306a36Sopenharmony_ci}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic int su3000_frontend_attach(struct dvb_usb_adapter *adap)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	struct dvb_usb_device *d = adap->dev;
140162306a36Sopenharmony_ci	struct dw2102_state *state = d->priv;
140262306a36Sopenharmony_ci
140362306a36Sopenharmony_ci	mutex_lock(&d->data_mutex);
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	state->data[0] = 0xe;
140662306a36Sopenharmony_ci	state->data[1] = 0x80;
140762306a36Sopenharmony_ci	state->data[2] = 0;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
141062306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	state->data[0] = 0xe;
141362306a36Sopenharmony_ci	state->data[1] = 0x02;
141462306a36Sopenharmony_ci	state->data[2] = 1;
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
141762306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
141862306a36Sopenharmony_ci	msleep(300);
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	state->data[0] = 0xe;
142162306a36Sopenharmony_ci	state->data[1] = 0x83;
142262306a36Sopenharmony_ci	state->data[2] = 0;
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
142562306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	state->data[0] = 0xe;
142862306a36Sopenharmony_ci	state->data[1] = 0x83;
142962306a36Sopenharmony_ci	state->data[2] = 1;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
143262306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	state->data[0] = 0x51;
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
143762306a36Sopenharmony_ci		err("command 0x51 transfer failed.");
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci	mutex_unlock(&d->data_mutex);
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(ds3000_attach, &su3000_ds3000_config,
144262306a36Sopenharmony_ci					&d->i2c_adap);
144362306a36Sopenharmony_ci	if (adap->fe_adap[0].fe == NULL)
144462306a36Sopenharmony_ci		return -EIO;
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe,
144762306a36Sopenharmony_ci				&dw2104_ts2020_config,
144862306a36Sopenharmony_ci				&d->i2c_adap)) {
144962306a36Sopenharmony_ci		info("Attached DS3000/TS2020!");
145062306a36Sopenharmony_ci		return 0;
145162306a36Sopenharmony_ci	}
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	info("Failed to attach DS3000/TS2020!");
145462306a36Sopenharmony_ci	return -EIO;
145562306a36Sopenharmony_ci}
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_cistatic int t220_frontend_attach(struct dvb_usb_adapter *adap)
145862306a36Sopenharmony_ci{
145962306a36Sopenharmony_ci	struct dvb_usb_device *d = adap->dev;
146062306a36Sopenharmony_ci	struct dw2102_state *state = d->priv;
146162306a36Sopenharmony_ci
146262306a36Sopenharmony_ci	mutex_lock(&d->data_mutex);
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	state->data[0] = 0xe;
146562306a36Sopenharmony_ci	state->data[1] = 0x87;
146662306a36Sopenharmony_ci	state->data[2] = 0x0;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
146962306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci	state->data[0] = 0xe;
147262306a36Sopenharmony_ci	state->data[1] = 0x86;
147362306a36Sopenharmony_ci	state->data[2] = 1;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
147662306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	state->data[0] = 0xe;
147962306a36Sopenharmony_ci	state->data[1] = 0x80;
148062306a36Sopenharmony_ci	state->data[2] = 0;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
148362306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	msleep(50);
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci	state->data[0] = 0xe;
148862306a36Sopenharmony_ci	state->data[1] = 0x80;
148962306a36Sopenharmony_ci	state->data[2] = 1;
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
149262306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	state->data[0] = 0x51;
149562306a36Sopenharmony_ci
149662306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
149762306a36Sopenharmony_ci		err("command 0x51 transfer failed.");
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci	mutex_unlock(&d->data_mutex);
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config,
150262306a36Sopenharmony_ci					&d->i2c_adap, NULL);
150362306a36Sopenharmony_ci	if (adap->fe_adap[0].fe != NULL) {
150462306a36Sopenharmony_ci		if (dvb_attach(tda18271_attach, adap->fe_adap[0].fe, 0x60,
150562306a36Sopenharmony_ci					&d->i2c_adap, &tda18271_config)) {
150662306a36Sopenharmony_ci			info("Attached TDA18271HD/CXD2820R!");
150762306a36Sopenharmony_ci			return 0;
150862306a36Sopenharmony_ci		}
150962306a36Sopenharmony_ci	}
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_ci	info("Failed to attach TDA18271HD/CXD2820R!");
151262306a36Sopenharmony_ci	return -EIO;
151362306a36Sopenharmony_ci}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_cistatic int m88rs2000_frontend_attach(struct dvb_usb_adapter *adap)
151662306a36Sopenharmony_ci{
151762306a36Sopenharmony_ci	struct dvb_usb_device *d = adap->dev;
151862306a36Sopenharmony_ci	struct dw2102_state *state = d->priv;
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	mutex_lock(&d->data_mutex);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	state->data[0] = 0x51;
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
152562306a36Sopenharmony_ci		err("command 0x51 transfer failed.");
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci	mutex_unlock(&d->data_mutex);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	adap->fe_adap[0].fe = dvb_attach(m88rs2000_attach,
153062306a36Sopenharmony_ci					&s421_m88rs2000_config,
153162306a36Sopenharmony_ci					&d->i2c_adap);
153262306a36Sopenharmony_ci
153362306a36Sopenharmony_ci	if (adap->fe_adap[0].fe == NULL)
153462306a36Sopenharmony_ci		return -EIO;
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci	if (dvb_attach(ts2020_attach, adap->fe_adap[0].fe,
153762306a36Sopenharmony_ci				&dw2104_ts2020_config,
153862306a36Sopenharmony_ci				&d->i2c_adap)) {
153962306a36Sopenharmony_ci		info("Attached RS2000/TS2020!");
154062306a36Sopenharmony_ci		return 0;
154162306a36Sopenharmony_ci	}
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	info("Failed to attach RS2000/TS2020!");
154462306a36Sopenharmony_ci	return -EIO;
154562306a36Sopenharmony_ci}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_cistatic int tt_s2_4600_frontend_attach_probe_demod(struct dvb_usb_device *d,
154862306a36Sopenharmony_ci						  const int probe_addr)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	struct dw2102_state *state = d->priv;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	state->data[0] = 0x9;
155362306a36Sopenharmony_ci	state->data[1] = 0x1;
155462306a36Sopenharmony_ci	state->data[2] = 0x1;
155562306a36Sopenharmony_ci	state->data[3] = probe_addr;
155662306a36Sopenharmony_ci	state->data[4] = 0x0;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 5, state->data, 2, 0) < 0) {
155962306a36Sopenharmony_ci		err("i2c probe for address 0x%x failed.", probe_addr);
156062306a36Sopenharmony_ci		return 0;
156162306a36Sopenharmony_ci	}
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	if (state->data[0] != 8) /* fail(7) or error, no device at address */
156462306a36Sopenharmony_ci		return 0;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	/* probing successful */
156762306a36Sopenharmony_ci	return 1;
156862306a36Sopenharmony_ci}
156962306a36Sopenharmony_ci
157062306a36Sopenharmony_cistatic int tt_s2_4600_frontend_attach(struct dvb_usb_adapter *adap)
157162306a36Sopenharmony_ci{
157262306a36Sopenharmony_ci	struct dvb_usb_device *d = adap->dev;
157362306a36Sopenharmony_ci	struct dw2102_state *state = d->priv;
157462306a36Sopenharmony_ci	struct i2c_adapter *i2c_adapter;
157562306a36Sopenharmony_ci	struct i2c_client *client;
157662306a36Sopenharmony_ci	struct i2c_board_info board_info;
157762306a36Sopenharmony_ci	struct m88ds3103_platform_data m88ds3103_pdata = {};
157862306a36Sopenharmony_ci	struct ts2020_config ts2020_config = {};
157962306a36Sopenharmony_ci	int demod_addr;
158062306a36Sopenharmony_ci
158162306a36Sopenharmony_ci	mutex_lock(&d->data_mutex);
158262306a36Sopenharmony_ci
158362306a36Sopenharmony_ci	state->data[0] = 0xe;
158462306a36Sopenharmony_ci	state->data[1] = 0x80;
158562306a36Sopenharmony_ci	state->data[2] = 0x0;
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
158862306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	state->data[0] = 0xe;
159162306a36Sopenharmony_ci	state->data[1] = 0x02;
159262306a36Sopenharmony_ci	state->data[2] = 1;
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
159562306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
159662306a36Sopenharmony_ci	msleep(300);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	state->data[0] = 0xe;
159962306a36Sopenharmony_ci	state->data[1] = 0x83;
160062306a36Sopenharmony_ci	state->data[2] = 0;
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
160362306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	state->data[0] = 0xe;
160662306a36Sopenharmony_ci	state->data[1] = 0x83;
160762306a36Sopenharmony_ci	state->data[2] = 1;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 3, state->data, 1, 0) < 0)
161062306a36Sopenharmony_ci		err("command 0x0e transfer failed.");
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_ci	state->data[0] = 0x51;
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci	if (dvb_usb_generic_rw(d, state->data, 1, state->data, 1, 0) < 0)
161562306a36Sopenharmony_ci		err("command 0x51 transfer failed.");
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ci	/* probe for demodulator i2c address */
161862306a36Sopenharmony_ci	demod_addr = -1;
161962306a36Sopenharmony_ci	if (tt_s2_4600_frontend_attach_probe_demod(d, 0x68))
162062306a36Sopenharmony_ci		demod_addr = 0x68;
162162306a36Sopenharmony_ci	else if (tt_s2_4600_frontend_attach_probe_demod(d, 0x69))
162262306a36Sopenharmony_ci		demod_addr = 0x69;
162362306a36Sopenharmony_ci	else if (tt_s2_4600_frontend_attach_probe_demod(d, 0x6a))
162462306a36Sopenharmony_ci		demod_addr = 0x6a;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	mutex_unlock(&d->data_mutex);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	if (demod_addr < 0) {
162962306a36Sopenharmony_ci		err("probing for demodulator failed. Is the external power switched on?");
163062306a36Sopenharmony_ci		return -ENODEV;
163162306a36Sopenharmony_ci	}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	/* attach demod */
163462306a36Sopenharmony_ci	m88ds3103_pdata.clk = 27000000;
163562306a36Sopenharmony_ci	m88ds3103_pdata.i2c_wr_max = 33;
163662306a36Sopenharmony_ci	m88ds3103_pdata.ts_mode = M88DS3103_TS_CI;
163762306a36Sopenharmony_ci	m88ds3103_pdata.ts_clk = 16000;
163862306a36Sopenharmony_ci	m88ds3103_pdata.ts_clk_pol = 0;
163962306a36Sopenharmony_ci	m88ds3103_pdata.spec_inv = 0;
164062306a36Sopenharmony_ci	m88ds3103_pdata.agc = 0x99;
164162306a36Sopenharmony_ci	m88ds3103_pdata.agc_inv = 0;
164262306a36Sopenharmony_ci	m88ds3103_pdata.clk_out = M88DS3103_CLOCK_OUT_ENABLED;
164362306a36Sopenharmony_ci	m88ds3103_pdata.envelope_mode = 0;
164462306a36Sopenharmony_ci	m88ds3103_pdata.lnb_hv_pol = 1;
164562306a36Sopenharmony_ci	m88ds3103_pdata.lnb_en_pol = 0;
164662306a36Sopenharmony_ci	memset(&board_info, 0, sizeof(board_info));
164762306a36Sopenharmony_ci	if (demod_addr == 0x6a)
164862306a36Sopenharmony_ci		strscpy(board_info.type, "m88ds3103b", I2C_NAME_SIZE);
164962306a36Sopenharmony_ci	else
165062306a36Sopenharmony_ci		strscpy(board_info.type, "m88ds3103", I2C_NAME_SIZE);
165162306a36Sopenharmony_ci	board_info.addr = demod_addr;
165262306a36Sopenharmony_ci	board_info.platform_data = &m88ds3103_pdata;
165362306a36Sopenharmony_ci	request_module("m88ds3103");
165462306a36Sopenharmony_ci	client = i2c_new_client_device(&d->i2c_adap, &board_info);
165562306a36Sopenharmony_ci	if (!i2c_client_has_driver(client))
165662306a36Sopenharmony_ci		return -ENODEV;
165762306a36Sopenharmony_ci	if (!try_module_get(client->dev.driver->owner)) {
165862306a36Sopenharmony_ci		i2c_unregister_device(client);
165962306a36Sopenharmony_ci		return -ENODEV;
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci	adap->fe_adap[0].fe = m88ds3103_pdata.get_dvb_frontend(client);
166262306a36Sopenharmony_ci	i2c_adapter = m88ds3103_pdata.get_i2c_adapter(client);
166362306a36Sopenharmony_ci
166462306a36Sopenharmony_ci	state->i2c_client_demod = client;
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	/* attach tuner */
166762306a36Sopenharmony_ci	ts2020_config.fe = adap->fe_adap[0].fe;
166862306a36Sopenharmony_ci	memset(&board_info, 0, sizeof(board_info));
166962306a36Sopenharmony_ci	strscpy(board_info.type, "ts2022", I2C_NAME_SIZE);
167062306a36Sopenharmony_ci	board_info.addr = 0x60;
167162306a36Sopenharmony_ci	board_info.platform_data = &ts2020_config;
167262306a36Sopenharmony_ci	request_module("ts2020");
167362306a36Sopenharmony_ci	client = i2c_new_client_device(i2c_adapter, &board_info);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	if (!i2c_client_has_driver(client)) {
167662306a36Sopenharmony_ci		dvb_frontend_detach(adap->fe_adap[0].fe);
167762306a36Sopenharmony_ci		return -ENODEV;
167862306a36Sopenharmony_ci	}
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	if (!try_module_get(client->dev.driver->owner)) {
168162306a36Sopenharmony_ci		i2c_unregister_device(client);
168262306a36Sopenharmony_ci		dvb_frontend_detach(adap->fe_adap[0].fe);
168362306a36Sopenharmony_ci		return -ENODEV;
168462306a36Sopenharmony_ci	}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci	/* delegate signal strength measurement to tuner */
168762306a36Sopenharmony_ci	adap->fe_adap[0].fe->ops.read_signal_strength =
168862306a36Sopenharmony_ci			adap->fe_adap[0].fe->ops.tuner_ops.get_rf_strength;
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci	state->i2c_client_tuner = client;
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci	/* hook fe: need to resync the slave fifo when signal locks */
169362306a36Sopenharmony_ci	state->fe_read_status = adap->fe_adap[0].fe->ops.read_status;
169462306a36Sopenharmony_ci	adap->fe_adap[0].fe->ops.read_status = tt_s2_4600_read_status;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	state->last_lock = 0;
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_ci	return 0;
169962306a36Sopenharmony_ci}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_cistatic int dw2102_tuner_attach(struct dvb_usb_adapter *adap)
170262306a36Sopenharmony_ci{
170362306a36Sopenharmony_ci	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
170462306a36Sopenharmony_ci		&adap->dev->i2c_adap, DVB_PLL_OPERA1);
170562306a36Sopenharmony_ci	return 0;
170662306a36Sopenharmony_ci}
170762306a36Sopenharmony_ci
170862306a36Sopenharmony_cistatic int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x60,
171162306a36Sopenharmony_ci		&adap->dev->i2c_adap, DVB_PLL_TUA6034);
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	return 0;
171462306a36Sopenharmony_ci}
171562306a36Sopenharmony_ci
171662306a36Sopenharmony_cistatic int dw2102_rc_query(struct dvb_usb_device *d)
171762306a36Sopenharmony_ci{
171862306a36Sopenharmony_ci	u8 key[2];
171962306a36Sopenharmony_ci	struct i2c_msg msg = {
172062306a36Sopenharmony_ci		.addr = DW2102_RC_QUERY,
172162306a36Sopenharmony_ci		.flags = I2C_M_RD,
172262306a36Sopenharmony_ci		.buf = key,
172362306a36Sopenharmony_ci		.len = 2
172462306a36Sopenharmony_ci	};
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
172762306a36Sopenharmony_ci		if (msg.buf[0] != 0xff) {
172862306a36Sopenharmony_ci			deb_rc("%s: rc code: %x, %x\n",
172962306a36Sopenharmony_ci					__func__, key[0], key[1]);
173062306a36Sopenharmony_ci			rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, key[0], 0);
173162306a36Sopenharmony_ci		}
173262306a36Sopenharmony_ci	}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci	return 0;
173562306a36Sopenharmony_ci}
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_cistatic int prof_rc_query(struct dvb_usb_device *d)
173862306a36Sopenharmony_ci{
173962306a36Sopenharmony_ci	u8 key[2];
174062306a36Sopenharmony_ci	struct i2c_msg msg = {
174162306a36Sopenharmony_ci		.addr = DW2102_RC_QUERY,
174262306a36Sopenharmony_ci		.flags = I2C_M_RD,
174362306a36Sopenharmony_ci		.buf = key,
174462306a36Sopenharmony_ci		.len = 2
174562306a36Sopenharmony_ci	};
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
174862306a36Sopenharmony_ci		if (msg.buf[0] != 0xff) {
174962306a36Sopenharmony_ci			deb_rc("%s: rc code: %x, %x\n",
175062306a36Sopenharmony_ci					__func__, key[0], key[1]);
175162306a36Sopenharmony_ci			rc_keydown(d->rc_dev, RC_PROTO_UNKNOWN, key[0] ^ 0xff,
175262306a36Sopenharmony_ci				   0);
175362306a36Sopenharmony_ci		}
175462306a36Sopenharmony_ci	}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	return 0;
175762306a36Sopenharmony_ci}
175862306a36Sopenharmony_ci
175962306a36Sopenharmony_cistatic int su3000_rc_query(struct dvb_usb_device *d)
176062306a36Sopenharmony_ci{
176162306a36Sopenharmony_ci	u8 key[2];
176262306a36Sopenharmony_ci	struct i2c_msg msg = {
176362306a36Sopenharmony_ci		.addr = DW2102_RC_QUERY,
176462306a36Sopenharmony_ci		.flags = I2C_M_RD,
176562306a36Sopenharmony_ci		.buf = key,
176662306a36Sopenharmony_ci		.len = 2
176762306a36Sopenharmony_ci	};
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_ci	if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
177062306a36Sopenharmony_ci		if (msg.buf[0] != 0xff) {
177162306a36Sopenharmony_ci			deb_rc("%s: rc code: %x, %x\n",
177262306a36Sopenharmony_ci					__func__, key[0], key[1]);
177362306a36Sopenharmony_ci			rc_keydown(d->rc_dev, RC_PROTO_RC5,
177462306a36Sopenharmony_ci				   RC_SCANCODE_RC5(key[1], key[0]), 0);
177562306a36Sopenharmony_ci		}
177662306a36Sopenharmony_ci	}
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	return 0;
177962306a36Sopenharmony_ci}
178062306a36Sopenharmony_ci
178162306a36Sopenharmony_cienum dw2102_table_entry {
178262306a36Sopenharmony_ci	CYPRESS_DW2102,
178362306a36Sopenharmony_ci	CYPRESS_DW2101,
178462306a36Sopenharmony_ci	CYPRESS_DW2104,
178562306a36Sopenharmony_ci	TEVII_S650,
178662306a36Sopenharmony_ci	TERRATEC_CINERGY_S,
178762306a36Sopenharmony_ci	CYPRESS_DW3101,
178862306a36Sopenharmony_ci	TEVII_S630,
178962306a36Sopenharmony_ci	PROF_1100,
179062306a36Sopenharmony_ci	TEVII_S660,
179162306a36Sopenharmony_ci	PROF_7500,
179262306a36Sopenharmony_ci	GENIATECH_SU3000,
179362306a36Sopenharmony_ci	HAUPPAUGE_MAX_S2,
179462306a36Sopenharmony_ci	TERRATEC_CINERGY_S2_R1,
179562306a36Sopenharmony_ci	TEVII_S480_1,
179662306a36Sopenharmony_ci	TEVII_S480_2,
179762306a36Sopenharmony_ci	GENIATECH_X3M_SPC1400HD,
179862306a36Sopenharmony_ci	TEVII_S421,
179962306a36Sopenharmony_ci	TEVII_S632,
180062306a36Sopenharmony_ci	TERRATEC_CINERGY_S2_R2,
180162306a36Sopenharmony_ci	TERRATEC_CINERGY_S2_R3,
180262306a36Sopenharmony_ci	TERRATEC_CINERGY_S2_R4,
180362306a36Sopenharmony_ci	TERRATEC_CINERGY_S2_1,
180462306a36Sopenharmony_ci	TERRATEC_CINERGY_S2_2,
180562306a36Sopenharmony_ci	GOTVIEW_SAT_HD,
180662306a36Sopenharmony_ci	GENIATECH_T220,
180762306a36Sopenharmony_ci	TECHNOTREND_CONNECT_S2_4600,
180862306a36Sopenharmony_ci	TEVII_S482_1,
180962306a36Sopenharmony_ci	TEVII_S482_2,
181062306a36Sopenharmony_ci	TERRATEC_CINERGY_S2_BOX,
181162306a36Sopenharmony_ci	TEVII_S662
181262306a36Sopenharmony_ci};
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_cistatic struct usb_device_id dw2102_table[] = {
181562306a36Sopenharmony_ci	DVB_USB_DEV(CYPRESS, CYPRESS_DW2102),
181662306a36Sopenharmony_ci	DVB_USB_DEV(CYPRESS, CYPRESS_DW2101),
181762306a36Sopenharmony_ci	DVB_USB_DEV(CYPRESS, CYPRESS_DW2104),
181862306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S650),
181962306a36Sopenharmony_ci	DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S),
182062306a36Sopenharmony_ci	DVB_USB_DEV(CYPRESS, CYPRESS_DW3101),
182162306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S630),
182262306a36Sopenharmony_ci	DVB_USB_DEV(PROF_1, PROF_1100),
182362306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S660),
182462306a36Sopenharmony_ci	DVB_USB_DEV(PROF_2, PROF_7500),
182562306a36Sopenharmony_ci	DVB_USB_DEV(GTEK, GENIATECH_SU3000),
182662306a36Sopenharmony_ci	DVB_USB_DEV(HAUPPAUGE, HAUPPAUGE_MAX_S2),
182762306a36Sopenharmony_ci	DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_R1),
182862306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S480_1),
182962306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S480_2),
183062306a36Sopenharmony_ci	DVB_USB_DEV(GTEK, GENIATECH_X3M_SPC1400HD),
183162306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S421),
183262306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S632),
183362306a36Sopenharmony_ci	DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_R2),
183462306a36Sopenharmony_ci	DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_R3),
183562306a36Sopenharmony_ci	DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_R4),
183662306a36Sopenharmony_ci	DVB_USB_DEV(TERRATEC_2, TERRATEC_CINERGY_S2_1),
183762306a36Sopenharmony_ci	DVB_USB_DEV(TERRATEC_2, TERRATEC_CINERGY_S2_2),
183862306a36Sopenharmony_ci	DVB_USB_DEV(GOTVIEW, GOTVIEW_SAT_HD),
183962306a36Sopenharmony_ci	DVB_USB_DEV(GTEK, GENIATECH_T220),
184062306a36Sopenharmony_ci	DVB_USB_DEV(TECHNOTREND, TECHNOTREND_CONNECT_S2_4600),
184162306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S482_1),
184262306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S482_2),
184362306a36Sopenharmony_ci	DVB_USB_DEV(TERRATEC, TERRATEC_CINERGY_S2_BOX),
184462306a36Sopenharmony_ci	DVB_USB_DEV(TEVII, TEVII_S662),
184562306a36Sopenharmony_ci	{ }
184662306a36Sopenharmony_ci};
184762306a36Sopenharmony_ci
184862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, dw2102_table);
184962306a36Sopenharmony_ci
185062306a36Sopenharmony_cistatic int dw2102_load_firmware(struct usb_device *dev,
185162306a36Sopenharmony_ci			const struct firmware *frmwr)
185262306a36Sopenharmony_ci{
185362306a36Sopenharmony_ci	u8 *b, *p;
185462306a36Sopenharmony_ci	int ret = 0, i;
185562306a36Sopenharmony_ci	u8 reset;
185662306a36Sopenharmony_ci	u8 reset16[] = {0, 0, 0, 0, 0, 0, 0};
185762306a36Sopenharmony_ci	const struct firmware *fw;
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_ci	switch (le16_to_cpu(dev->descriptor.idProduct)) {
186062306a36Sopenharmony_ci	case 0x2101:
186162306a36Sopenharmony_ci		ret = request_firmware(&fw, DW2101_FIRMWARE, &dev->dev);
186262306a36Sopenharmony_ci		if (ret != 0) {
186362306a36Sopenharmony_ci			err(err_str, DW2101_FIRMWARE);
186462306a36Sopenharmony_ci			return ret;
186562306a36Sopenharmony_ci		}
186662306a36Sopenharmony_ci		break;
186762306a36Sopenharmony_ci	default:
186862306a36Sopenharmony_ci		fw = frmwr;
186962306a36Sopenharmony_ci		break;
187062306a36Sopenharmony_ci	}
187162306a36Sopenharmony_ci	info("start downloading DW210X firmware");
187262306a36Sopenharmony_ci	p = kmalloc(fw->size, GFP_KERNEL);
187362306a36Sopenharmony_ci	reset = 1;
187462306a36Sopenharmony_ci	/*stop the CPU*/
187562306a36Sopenharmony_ci	dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1, DW210X_WRITE_MSG);
187662306a36Sopenharmony_ci	dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1, DW210X_WRITE_MSG);
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	if (p != NULL) {
187962306a36Sopenharmony_ci		memcpy(p, fw->data, fw->size);
188062306a36Sopenharmony_ci		for (i = 0; i < fw->size; i += 0x40) {
188162306a36Sopenharmony_ci			b = (u8 *) p + i;
188262306a36Sopenharmony_ci			if (dw210x_op_rw(dev, 0xa0, i, 0, b , 0x40,
188362306a36Sopenharmony_ci					DW210X_WRITE_MSG) != 0x40) {
188462306a36Sopenharmony_ci				err("error while transferring firmware");
188562306a36Sopenharmony_ci				ret = -EINVAL;
188662306a36Sopenharmony_ci				break;
188762306a36Sopenharmony_ci			}
188862306a36Sopenharmony_ci		}
188962306a36Sopenharmony_ci		/* restart the CPU */
189062306a36Sopenharmony_ci		reset = 0;
189162306a36Sopenharmony_ci		if (ret || dw210x_op_rw(dev, 0xa0, 0x7f92, 0, &reset, 1,
189262306a36Sopenharmony_ci					DW210X_WRITE_MSG) != 1) {
189362306a36Sopenharmony_ci			err("could not restart the USB controller CPU.");
189462306a36Sopenharmony_ci			ret = -EINVAL;
189562306a36Sopenharmony_ci		}
189662306a36Sopenharmony_ci		if (ret || dw210x_op_rw(dev, 0xa0, 0xe600, 0, &reset, 1,
189762306a36Sopenharmony_ci					DW210X_WRITE_MSG) != 1) {
189862306a36Sopenharmony_ci			err("could not restart the USB controller CPU.");
189962306a36Sopenharmony_ci			ret = -EINVAL;
190062306a36Sopenharmony_ci		}
190162306a36Sopenharmony_ci		/* init registers */
190262306a36Sopenharmony_ci		switch (le16_to_cpu(dev->descriptor.idProduct)) {
190362306a36Sopenharmony_ci		case USB_PID_TEVII_S650:
190462306a36Sopenharmony_ci			dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC;
190562306a36Sopenharmony_ci			fallthrough;
190662306a36Sopenharmony_ci		case USB_PID_CYPRESS_DW2104:
190762306a36Sopenharmony_ci			reset = 1;
190862306a36Sopenharmony_ci			dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
190962306a36Sopenharmony_ci					DW210X_WRITE_MSG);
191062306a36Sopenharmony_ci			fallthrough;
191162306a36Sopenharmony_ci		case USB_PID_CYPRESS_DW3101:
191262306a36Sopenharmony_ci			reset = 0;
191362306a36Sopenharmony_ci			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
191462306a36Sopenharmony_ci					DW210X_WRITE_MSG);
191562306a36Sopenharmony_ci			break;
191662306a36Sopenharmony_ci		case USB_PID_TERRATEC_CINERGY_S:
191762306a36Sopenharmony_ci		case USB_PID_CYPRESS_DW2102:
191862306a36Sopenharmony_ci			dw210x_op_rw(dev, 0xbf, 0x0040, 0, &reset, 0,
191962306a36Sopenharmony_ci					DW210X_WRITE_MSG);
192062306a36Sopenharmony_ci			dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
192162306a36Sopenharmony_ci					DW210X_READ_MSG);
192262306a36Sopenharmony_ci			/* check STV0299 frontend  */
192362306a36Sopenharmony_ci			dw210x_op_rw(dev, 0xb5, 0, 0, &reset16[0], 2,
192462306a36Sopenharmony_ci					DW210X_READ_MSG);
192562306a36Sopenharmony_ci			if ((reset16[0] == 0xa1) || (reset16[0] == 0x80)) {
192662306a36Sopenharmony_ci				dw2102_properties.i2c_algo = &dw2102_i2c_algo;
192762306a36Sopenharmony_ci				dw2102_properties.adapter->fe[0].tuner_attach = &dw2102_tuner_attach;
192862306a36Sopenharmony_ci				break;
192962306a36Sopenharmony_ci			} else {
193062306a36Sopenharmony_ci				/* check STV0288 frontend  */
193162306a36Sopenharmony_ci				reset16[0] = 0xd0;
193262306a36Sopenharmony_ci				reset16[1] = 1;
193362306a36Sopenharmony_ci				reset16[2] = 0;
193462306a36Sopenharmony_ci				dw210x_op_rw(dev, 0xc2, 0, 0, &reset16[0], 3,
193562306a36Sopenharmony_ci						DW210X_WRITE_MSG);
193662306a36Sopenharmony_ci				dw210x_op_rw(dev, 0xc3, 0xd1, 0, &reset16[0], 3,
193762306a36Sopenharmony_ci						DW210X_READ_MSG);
193862306a36Sopenharmony_ci				if (reset16[2] == 0x11) {
193962306a36Sopenharmony_ci					dw2102_properties.i2c_algo = &dw2102_earda_i2c_algo;
194062306a36Sopenharmony_ci					break;
194162306a36Sopenharmony_ci				}
194262306a36Sopenharmony_ci			}
194362306a36Sopenharmony_ci			fallthrough;
194462306a36Sopenharmony_ci		case 0x2101:
194562306a36Sopenharmony_ci			dw210x_op_rw(dev, 0xbc, 0x0030, 0, &reset16[0], 2,
194662306a36Sopenharmony_ci					DW210X_READ_MSG);
194762306a36Sopenharmony_ci			dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
194862306a36Sopenharmony_ci					DW210X_READ_MSG);
194962306a36Sopenharmony_ci			dw210x_op_rw(dev, 0xba, 0x0000, 0, &reset16[0], 7,
195062306a36Sopenharmony_ci					DW210X_READ_MSG);
195162306a36Sopenharmony_ci			dw210x_op_rw(dev, 0xb9, 0x0000, 0, &reset16[0], 2,
195262306a36Sopenharmony_ci					DW210X_READ_MSG);
195362306a36Sopenharmony_ci			break;
195462306a36Sopenharmony_ci		}
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci		msleep(100);
195762306a36Sopenharmony_ci		kfree(p);
195862306a36Sopenharmony_ci	}
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	if (le16_to_cpu(dev->descriptor.idProduct) == 0x2101)
196162306a36Sopenharmony_ci		release_firmware(fw);
196262306a36Sopenharmony_ci	return ret;
196362306a36Sopenharmony_ci}
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_cistatic struct dvb_usb_device_properties dw2102_properties = {
196662306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
196762306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
196862306a36Sopenharmony_ci	.firmware = DW2102_FIRMWARE,
196962306a36Sopenharmony_ci	.no_reconnect = 1,
197062306a36Sopenharmony_ci
197162306a36Sopenharmony_ci	.i2c_algo = &dw2102_serit_i2c_algo,
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci	.rc.core = {
197462306a36Sopenharmony_ci		.rc_interval = 150,
197562306a36Sopenharmony_ci		.rc_codes = RC_MAP_DM1105_NEC,
197662306a36Sopenharmony_ci		.module_name = "dw2102",
197762306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_NEC,
197862306a36Sopenharmony_ci		.rc_query = dw2102_rc_query,
197962306a36Sopenharmony_ci	},
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x81,
198262306a36Sopenharmony_ci	/* parameter for the MPEG2-data transfer */
198362306a36Sopenharmony_ci	.num_adapters = 1,
198462306a36Sopenharmony_ci	.download_firmware = dw2102_load_firmware,
198562306a36Sopenharmony_ci	.read_mac_address = dw210x_read_mac_address,
198662306a36Sopenharmony_ci	.adapter = {
198762306a36Sopenharmony_ci		{
198862306a36Sopenharmony_ci		.num_frontends = 1,
198962306a36Sopenharmony_ci		.fe = {{
199062306a36Sopenharmony_ci			.frontend_attach = dw2102_frontend_attach,
199162306a36Sopenharmony_ci			.stream = {
199262306a36Sopenharmony_ci				.type = USB_BULK,
199362306a36Sopenharmony_ci				.count = 8,
199462306a36Sopenharmony_ci				.endpoint = 0x82,
199562306a36Sopenharmony_ci				.u = {
199662306a36Sopenharmony_ci					.bulk = {
199762306a36Sopenharmony_ci						.buffersize = 4096,
199862306a36Sopenharmony_ci					}
199962306a36Sopenharmony_ci				}
200062306a36Sopenharmony_ci			},
200162306a36Sopenharmony_ci		}},
200262306a36Sopenharmony_ci		}
200362306a36Sopenharmony_ci	},
200462306a36Sopenharmony_ci	.num_device_descs = 3,
200562306a36Sopenharmony_ci	.devices = {
200662306a36Sopenharmony_ci		{"DVBWorld DVB-S 2102 USB2.0",
200762306a36Sopenharmony_ci			{&dw2102_table[CYPRESS_DW2102], NULL},
200862306a36Sopenharmony_ci			{NULL},
200962306a36Sopenharmony_ci		},
201062306a36Sopenharmony_ci		{"DVBWorld DVB-S 2101 USB2.0",
201162306a36Sopenharmony_ci			{&dw2102_table[CYPRESS_DW2101], NULL},
201262306a36Sopenharmony_ci			{NULL},
201362306a36Sopenharmony_ci		},
201462306a36Sopenharmony_ci		{"TerraTec Cinergy S USB",
201562306a36Sopenharmony_ci			{&dw2102_table[TERRATEC_CINERGY_S], NULL},
201662306a36Sopenharmony_ci			{NULL},
201762306a36Sopenharmony_ci		},
201862306a36Sopenharmony_ci	}
201962306a36Sopenharmony_ci};
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_cistatic struct dvb_usb_device_properties dw2104_properties = {
202262306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
202362306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
202462306a36Sopenharmony_ci	.firmware = DW2104_FIRMWARE,
202562306a36Sopenharmony_ci	.no_reconnect = 1,
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	.i2c_algo = &dw2104_i2c_algo,
202862306a36Sopenharmony_ci	.rc.core = {
202962306a36Sopenharmony_ci		.rc_interval = 150,
203062306a36Sopenharmony_ci		.rc_codes = RC_MAP_DM1105_NEC,
203162306a36Sopenharmony_ci		.module_name = "dw2102",
203262306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_NEC,
203362306a36Sopenharmony_ci		.rc_query = dw2102_rc_query,
203462306a36Sopenharmony_ci	},
203562306a36Sopenharmony_ci
203662306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x81,
203762306a36Sopenharmony_ci	/* parameter for the MPEG2-data transfer */
203862306a36Sopenharmony_ci	.num_adapters = 1,
203962306a36Sopenharmony_ci	.download_firmware = dw2102_load_firmware,
204062306a36Sopenharmony_ci	.read_mac_address = dw210x_read_mac_address,
204162306a36Sopenharmony_ci	.adapter = {
204262306a36Sopenharmony_ci		{
204362306a36Sopenharmony_ci		.num_frontends = 1,
204462306a36Sopenharmony_ci		.fe = {{
204562306a36Sopenharmony_ci			.frontend_attach = dw2104_frontend_attach,
204662306a36Sopenharmony_ci			.stream = {
204762306a36Sopenharmony_ci				.type = USB_BULK,
204862306a36Sopenharmony_ci				.count = 8,
204962306a36Sopenharmony_ci				.endpoint = 0x82,
205062306a36Sopenharmony_ci				.u = {
205162306a36Sopenharmony_ci					.bulk = {
205262306a36Sopenharmony_ci						.buffersize = 4096,
205362306a36Sopenharmony_ci					}
205462306a36Sopenharmony_ci				}
205562306a36Sopenharmony_ci			},
205662306a36Sopenharmony_ci		}},
205762306a36Sopenharmony_ci		}
205862306a36Sopenharmony_ci	},
205962306a36Sopenharmony_ci	.num_device_descs = 2,
206062306a36Sopenharmony_ci	.devices = {
206162306a36Sopenharmony_ci		{ "DVBWorld DW2104 USB2.0",
206262306a36Sopenharmony_ci			{&dw2102_table[CYPRESS_DW2104], NULL},
206362306a36Sopenharmony_ci			{NULL},
206462306a36Sopenharmony_ci		},
206562306a36Sopenharmony_ci		{ "TeVii S650 USB2.0",
206662306a36Sopenharmony_ci			{&dw2102_table[TEVII_S650], NULL},
206762306a36Sopenharmony_ci			{NULL},
206862306a36Sopenharmony_ci		},
206962306a36Sopenharmony_ci	}
207062306a36Sopenharmony_ci};
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_cistatic struct dvb_usb_device_properties dw3101_properties = {
207362306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
207462306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
207562306a36Sopenharmony_ci	.firmware = DW3101_FIRMWARE,
207662306a36Sopenharmony_ci	.no_reconnect = 1,
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	.i2c_algo = &dw3101_i2c_algo,
207962306a36Sopenharmony_ci	.rc.core = {
208062306a36Sopenharmony_ci		.rc_interval = 150,
208162306a36Sopenharmony_ci		.rc_codes = RC_MAP_DM1105_NEC,
208262306a36Sopenharmony_ci		.module_name = "dw2102",
208362306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_NEC,
208462306a36Sopenharmony_ci		.rc_query = dw2102_rc_query,
208562306a36Sopenharmony_ci	},
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x81,
208862306a36Sopenharmony_ci	/* parameter for the MPEG2-data transfer */
208962306a36Sopenharmony_ci	.num_adapters = 1,
209062306a36Sopenharmony_ci	.download_firmware = dw2102_load_firmware,
209162306a36Sopenharmony_ci	.read_mac_address = dw210x_read_mac_address,
209262306a36Sopenharmony_ci	.adapter = {
209362306a36Sopenharmony_ci		{
209462306a36Sopenharmony_ci		.num_frontends = 1,
209562306a36Sopenharmony_ci		.fe = {{
209662306a36Sopenharmony_ci			.frontend_attach = dw3101_frontend_attach,
209762306a36Sopenharmony_ci			.tuner_attach = dw3101_tuner_attach,
209862306a36Sopenharmony_ci			.stream = {
209962306a36Sopenharmony_ci				.type = USB_BULK,
210062306a36Sopenharmony_ci				.count = 8,
210162306a36Sopenharmony_ci				.endpoint = 0x82,
210262306a36Sopenharmony_ci				.u = {
210362306a36Sopenharmony_ci					.bulk = {
210462306a36Sopenharmony_ci						.buffersize = 4096,
210562306a36Sopenharmony_ci					}
210662306a36Sopenharmony_ci				}
210762306a36Sopenharmony_ci			},
210862306a36Sopenharmony_ci		}},
210962306a36Sopenharmony_ci		}
211062306a36Sopenharmony_ci	},
211162306a36Sopenharmony_ci	.num_device_descs = 1,
211262306a36Sopenharmony_ci	.devices = {
211362306a36Sopenharmony_ci		{ "DVBWorld DVB-C 3101 USB2.0",
211462306a36Sopenharmony_ci			{&dw2102_table[CYPRESS_DW3101], NULL},
211562306a36Sopenharmony_ci			{NULL},
211662306a36Sopenharmony_ci		},
211762306a36Sopenharmony_ci	}
211862306a36Sopenharmony_ci};
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_cistatic struct dvb_usb_device_properties s6x0_properties = {
212162306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
212262306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
212362306a36Sopenharmony_ci	.size_of_priv = sizeof(struct dw2102_state),
212462306a36Sopenharmony_ci	.firmware = S630_FIRMWARE,
212562306a36Sopenharmony_ci	.no_reconnect = 1,
212662306a36Sopenharmony_ci
212762306a36Sopenharmony_ci	.i2c_algo = &s6x0_i2c_algo,
212862306a36Sopenharmony_ci	.rc.core = {
212962306a36Sopenharmony_ci		.rc_interval = 150,
213062306a36Sopenharmony_ci		.rc_codes = RC_MAP_TEVII_NEC,
213162306a36Sopenharmony_ci		.module_name = "dw2102",
213262306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_NEC,
213362306a36Sopenharmony_ci		.rc_query = dw2102_rc_query,
213462306a36Sopenharmony_ci	},
213562306a36Sopenharmony_ci
213662306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x81,
213762306a36Sopenharmony_ci	.num_adapters = 1,
213862306a36Sopenharmony_ci	.download_firmware = dw2102_load_firmware,
213962306a36Sopenharmony_ci	.read_mac_address = s6x0_read_mac_address,
214062306a36Sopenharmony_ci	.adapter = {
214162306a36Sopenharmony_ci		{
214262306a36Sopenharmony_ci		.num_frontends = 1,
214362306a36Sopenharmony_ci		.fe = {{
214462306a36Sopenharmony_ci			.frontend_attach = zl100313_frontend_attach,
214562306a36Sopenharmony_ci			.stream = {
214662306a36Sopenharmony_ci				.type = USB_BULK,
214762306a36Sopenharmony_ci				.count = 8,
214862306a36Sopenharmony_ci				.endpoint = 0x82,
214962306a36Sopenharmony_ci				.u = {
215062306a36Sopenharmony_ci					.bulk = {
215162306a36Sopenharmony_ci						.buffersize = 4096,
215262306a36Sopenharmony_ci					}
215362306a36Sopenharmony_ci				}
215462306a36Sopenharmony_ci			},
215562306a36Sopenharmony_ci		}},
215662306a36Sopenharmony_ci		}
215762306a36Sopenharmony_ci	},
215862306a36Sopenharmony_ci	.num_device_descs = 1,
215962306a36Sopenharmony_ci	.devices = {
216062306a36Sopenharmony_ci		{"TeVii S630 USB",
216162306a36Sopenharmony_ci			{&dw2102_table[TEVII_S630], NULL},
216262306a36Sopenharmony_ci			{NULL},
216362306a36Sopenharmony_ci		},
216462306a36Sopenharmony_ci	}
216562306a36Sopenharmony_ci};
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_cistatic struct dvb_usb_device_properties p1100_properties = {
216862306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
216962306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
217062306a36Sopenharmony_ci	.size_of_priv = sizeof(struct dw2102_state),
217162306a36Sopenharmony_ci	.firmware = P1100_FIRMWARE,
217262306a36Sopenharmony_ci	.no_reconnect = 1,
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	.i2c_algo = &s6x0_i2c_algo,
217562306a36Sopenharmony_ci	.rc.core = {
217662306a36Sopenharmony_ci		.rc_interval = 150,
217762306a36Sopenharmony_ci		.rc_codes = RC_MAP_TBS_NEC,
217862306a36Sopenharmony_ci		.module_name = "dw2102",
217962306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_NEC,
218062306a36Sopenharmony_ci		.rc_query = prof_rc_query,
218162306a36Sopenharmony_ci	},
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x81,
218462306a36Sopenharmony_ci	.num_adapters = 1,
218562306a36Sopenharmony_ci	.download_firmware = dw2102_load_firmware,
218662306a36Sopenharmony_ci	.read_mac_address = s6x0_read_mac_address,
218762306a36Sopenharmony_ci	.adapter = {
218862306a36Sopenharmony_ci		{
218962306a36Sopenharmony_ci			.num_frontends = 1,
219062306a36Sopenharmony_ci			.fe = {{
219162306a36Sopenharmony_ci				.frontend_attach = stv0288_frontend_attach,
219262306a36Sopenharmony_ci				.stream = {
219362306a36Sopenharmony_ci					.type = USB_BULK,
219462306a36Sopenharmony_ci					.count = 8,
219562306a36Sopenharmony_ci					.endpoint = 0x82,
219662306a36Sopenharmony_ci					.u = {
219762306a36Sopenharmony_ci						.bulk = {
219862306a36Sopenharmony_ci							.buffersize = 4096,
219962306a36Sopenharmony_ci						}
220062306a36Sopenharmony_ci					}
220162306a36Sopenharmony_ci				},
220262306a36Sopenharmony_ci			} },
220362306a36Sopenharmony_ci		}
220462306a36Sopenharmony_ci	},
220562306a36Sopenharmony_ci	.num_device_descs = 1,
220662306a36Sopenharmony_ci	.devices = {
220762306a36Sopenharmony_ci		{"Prof 1100 USB ",
220862306a36Sopenharmony_ci			{&dw2102_table[PROF_1100], NULL},
220962306a36Sopenharmony_ci			{NULL},
221062306a36Sopenharmony_ci		},
221162306a36Sopenharmony_ci	}
221262306a36Sopenharmony_ci};
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cistatic struct dvb_usb_device_properties s660_properties = {
221562306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
221662306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
221762306a36Sopenharmony_ci	.size_of_priv = sizeof(struct dw2102_state),
221862306a36Sopenharmony_ci	.firmware = S660_FIRMWARE,
221962306a36Sopenharmony_ci	.no_reconnect = 1,
222062306a36Sopenharmony_ci
222162306a36Sopenharmony_ci	.i2c_algo = &s6x0_i2c_algo,
222262306a36Sopenharmony_ci	.rc.core = {
222362306a36Sopenharmony_ci		.rc_interval = 150,
222462306a36Sopenharmony_ci		.rc_codes = RC_MAP_TEVII_NEC,
222562306a36Sopenharmony_ci		.module_name = "dw2102",
222662306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_NEC,
222762306a36Sopenharmony_ci		.rc_query = dw2102_rc_query,
222862306a36Sopenharmony_ci	},
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x81,
223162306a36Sopenharmony_ci	.num_adapters = 1,
223262306a36Sopenharmony_ci	.download_firmware = dw2102_load_firmware,
223362306a36Sopenharmony_ci	.read_mac_address = s6x0_read_mac_address,
223462306a36Sopenharmony_ci	.adapter = {
223562306a36Sopenharmony_ci		{
223662306a36Sopenharmony_ci			.num_frontends = 1,
223762306a36Sopenharmony_ci			.fe = {{
223862306a36Sopenharmony_ci				.frontend_attach = ds3000_frontend_attach,
223962306a36Sopenharmony_ci				.stream = {
224062306a36Sopenharmony_ci					.type = USB_BULK,
224162306a36Sopenharmony_ci					.count = 8,
224262306a36Sopenharmony_ci					.endpoint = 0x82,
224362306a36Sopenharmony_ci					.u = {
224462306a36Sopenharmony_ci						.bulk = {
224562306a36Sopenharmony_ci							.buffersize = 4096,
224662306a36Sopenharmony_ci						}
224762306a36Sopenharmony_ci					}
224862306a36Sopenharmony_ci				},
224962306a36Sopenharmony_ci			} },
225062306a36Sopenharmony_ci		}
225162306a36Sopenharmony_ci	},
225262306a36Sopenharmony_ci	.num_device_descs = 3,
225362306a36Sopenharmony_ci	.devices = {
225462306a36Sopenharmony_ci		{"TeVii S660 USB",
225562306a36Sopenharmony_ci			{&dw2102_table[TEVII_S660], NULL},
225662306a36Sopenharmony_ci			{NULL},
225762306a36Sopenharmony_ci		},
225862306a36Sopenharmony_ci		{"TeVii S480.1 USB",
225962306a36Sopenharmony_ci			{&dw2102_table[TEVII_S480_1], NULL},
226062306a36Sopenharmony_ci			{NULL},
226162306a36Sopenharmony_ci		},
226262306a36Sopenharmony_ci		{"TeVii S480.2 USB",
226362306a36Sopenharmony_ci			{&dw2102_table[TEVII_S480_2], NULL},
226462306a36Sopenharmony_ci			{NULL},
226562306a36Sopenharmony_ci		},
226662306a36Sopenharmony_ci	}
226762306a36Sopenharmony_ci};
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_cistatic struct dvb_usb_device_properties p7500_properties = {
227062306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
227162306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
227262306a36Sopenharmony_ci	.size_of_priv = sizeof(struct dw2102_state),
227362306a36Sopenharmony_ci	.firmware = P7500_FIRMWARE,
227462306a36Sopenharmony_ci	.no_reconnect = 1,
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	.i2c_algo = &s6x0_i2c_algo,
227762306a36Sopenharmony_ci	.rc.core = {
227862306a36Sopenharmony_ci		.rc_interval = 150,
227962306a36Sopenharmony_ci		.rc_codes = RC_MAP_TBS_NEC,
228062306a36Sopenharmony_ci		.module_name = "dw2102",
228162306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_NEC,
228262306a36Sopenharmony_ci		.rc_query = prof_rc_query,
228362306a36Sopenharmony_ci	},
228462306a36Sopenharmony_ci
228562306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x81,
228662306a36Sopenharmony_ci	.num_adapters = 1,
228762306a36Sopenharmony_ci	.download_firmware = dw2102_load_firmware,
228862306a36Sopenharmony_ci	.read_mac_address = s6x0_read_mac_address,
228962306a36Sopenharmony_ci	.adapter = {
229062306a36Sopenharmony_ci		{
229162306a36Sopenharmony_ci			.num_frontends = 1,
229262306a36Sopenharmony_ci			.fe = {{
229362306a36Sopenharmony_ci				.frontend_attach = prof_7500_frontend_attach,
229462306a36Sopenharmony_ci				.stream = {
229562306a36Sopenharmony_ci					.type = USB_BULK,
229662306a36Sopenharmony_ci					.count = 8,
229762306a36Sopenharmony_ci					.endpoint = 0x82,
229862306a36Sopenharmony_ci					.u = {
229962306a36Sopenharmony_ci						.bulk = {
230062306a36Sopenharmony_ci							.buffersize = 4096,
230162306a36Sopenharmony_ci						}
230262306a36Sopenharmony_ci					}
230362306a36Sopenharmony_ci				},
230462306a36Sopenharmony_ci			} },
230562306a36Sopenharmony_ci		}
230662306a36Sopenharmony_ci	},
230762306a36Sopenharmony_ci	.num_device_descs = 1,
230862306a36Sopenharmony_ci	.devices = {
230962306a36Sopenharmony_ci		{"Prof 7500 USB DVB-S2",
231062306a36Sopenharmony_ci			{&dw2102_table[PROF_7500], NULL},
231162306a36Sopenharmony_ci			{NULL},
231262306a36Sopenharmony_ci		},
231362306a36Sopenharmony_ci	}
231462306a36Sopenharmony_ci};
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_cistatic struct dvb_usb_device_properties su3000_properties = {
231762306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
231862306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
231962306a36Sopenharmony_ci	.size_of_priv = sizeof(struct dw2102_state),
232062306a36Sopenharmony_ci	.power_ctrl = su3000_power_ctrl,
232162306a36Sopenharmony_ci	.num_adapters = 1,
232262306a36Sopenharmony_ci	.identify_state	= su3000_identify_state,
232362306a36Sopenharmony_ci	.i2c_algo = &su3000_i2c_algo,
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	.rc.core = {
232662306a36Sopenharmony_ci		.rc_interval = 150,
232762306a36Sopenharmony_ci		.rc_codes = RC_MAP_SU3000,
232862306a36Sopenharmony_ci		.module_name = "dw2102",
232962306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_RC5,
233062306a36Sopenharmony_ci		.rc_query = su3000_rc_query,
233162306a36Sopenharmony_ci	},
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	.read_mac_address = su3000_read_mac_address,
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
233662306a36Sopenharmony_ci
233762306a36Sopenharmony_ci	.adapter = {
233862306a36Sopenharmony_ci		{
233962306a36Sopenharmony_ci		.num_frontends = 1,
234062306a36Sopenharmony_ci		.fe = {{
234162306a36Sopenharmony_ci			.streaming_ctrl   = su3000_streaming_ctrl,
234262306a36Sopenharmony_ci			.frontend_attach  = su3000_frontend_attach,
234362306a36Sopenharmony_ci			.stream = {
234462306a36Sopenharmony_ci				.type = USB_BULK,
234562306a36Sopenharmony_ci				.count = 8,
234662306a36Sopenharmony_ci				.endpoint = 0x82,
234762306a36Sopenharmony_ci				.u = {
234862306a36Sopenharmony_ci					.bulk = {
234962306a36Sopenharmony_ci						.buffersize = 4096,
235062306a36Sopenharmony_ci					}
235162306a36Sopenharmony_ci				}
235262306a36Sopenharmony_ci			}
235362306a36Sopenharmony_ci		}},
235462306a36Sopenharmony_ci		}
235562306a36Sopenharmony_ci	},
235662306a36Sopenharmony_ci	.num_device_descs = 9,
235762306a36Sopenharmony_ci	.devices = {
235862306a36Sopenharmony_ci		{ "SU3000HD DVB-S USB2.0",
235962306a36Sopenharmony_ci			{ &dw2102_table[GENIATECH_SU3000], NULL },
236062306a36Sopenharmony_ci			{ NULL },
236162306a36Sopenharmony_ci		},
236262306a36Sopenharmony_ci		{ "Hauppauge MAX S2 or WinTV NOVA HD USB2.0",
236362306a36Sopenharmony_ci			{ &dw2102_table[HAUPPAUGE_MAX_S2], NULL },
236462306a36Sopenharmony_ci			{ NULL },
236562306a36Sopenharmony_ci		},
236662306a36Sopenharmony_ci		{ "Terratec Cinergy S2 USB HD",
236762306a36Sopenharmony_ci			{ &dw2102_table[TERRATEC_CINERGY_S2_R1], NULL },
236862306a36Sopenharmony_ci			{ NULL },
236962306a36Sopenharmony_ci		},
237062306a36Sopenharmony_ci		{ "X3M TV SPC1400HD PCI",
237162306a36Sopenharmony_ci			{ &dw2102_table[GENIATECH_X3M_SPC1400HD], NULL },
237262306a36Sopenharmony_ci			{ NULL },
237362306a36Sopenharmony_ci		},
237462306a36Sopenharmony_ci		{ "Terratec Cinergy S2 USB HD Rev.2",
237562306a36Sopenharmony_ci			{ &dw2102_table[TERRATEC_CINERGY_S2_R2], NULL },
237662306a36Sopenharmony_ci			{ NULL },
237762306a36Sopenharmony_ci		},
237862306a36Sopenharmony_ci		{ "Terratec Cinergy S2 USB HD Rev.3",
237962306a36Sopenharmony_ci			{ &dw2102_table[TERRATEC_CINERGY_S2_R3], NULL },
238062306a36Sopenharmony_ci			{ NULL },
238162306a36Sopenharmony_ci		},
238262306a36Sopenharmony_ci		{ "Terratec Cinergy S2 PCIe Dual Port 1",
238362306a36Sopenharmony_ci			{ &dw2102_table[TERRATEC_CINERGY_S2_1], NULL },
238462306a36Sopenharmony_ci			{ NULL },
238562306a36Sopenharmony_ci		},
238662306a36Sopenharmony_ci		{ "Terratec Cinergy S2 PCIe Dual Port 2",
238762306a36Sopenharmony_ci			{ &dw2102_table[TERRATEC_CINERGY_S2_2], NULL },
238862306a36Sopenharmony_ci			{ NULL },
238962306a36Sopenharmony_ci		},
239062306a36Sopenharmony_ci		{ "GOTVIEW Satellite HD",
239162306a36Sopenharmony_ci			{ &dw2102_table[GOTVIEW_SAT_HD], NULL },
239262306a36Sopenharmony_ci			{ NULL },
239362306a36Sopenharmony_ci		},
239462306a36Sopenharmony_ci	}
239562306a36Sopenharmony_ci};
239662306a36Sopenharmony_ci
239762306a36Sopenharmony_cistatic struct dvb_usb_device_properties s421_properties = {
239862306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
239962306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
240062306a36Sopenharmony_ci	.size_of_priv = sizeof(struct dw2102_state),
240162306a36Sopenharmony_ci	.power_ctrl = su3000_power_ctrl,
240262306a36Sopenharmony_ci	.num_adapters = 1,
240362306a36Sopenharmony_ci	.identify_state	= su3000_identify_state,
240462306a36Sopenharmony_ci	.i2c_algo = &su3000_i2c_algo,
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	.rc.core = {
240762306a36Sopenharmony_ci		.rc_interval = 150,
240862306a36Sopenharmony_ci		.rc_codes = RC_MAP_SU3000,
240962306a36Sopenharmony_ci		.module_name = "dw2102",
241062306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_RC5,
241162306a36Sopenharmony_ci		.rc_query = su3000_rc_query,
241262306a36Sopenharmony_ci	},
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci	.read_mac_address = su3000_read_mac_address,
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
241762306a36Sopenharmony_ci
241862306a36Sopenharmony_ci	.adapter = {
241962306a36Sopenharmony_ci		{
242062306a36Sopenharmony_ci		.num_frontends = 1,
242162306a36Sopenharmony_ci		.fe = {{
242262306a36Sopenharmony_ci			.streaming_ctrl   = su3000_streaming_ctrl,
242362306a36Sopenharmony_ci			.frontend_attach  = m88rs2000_frontend_attach,
242462306a36Sopenharmony_ci			.stream = {
242562306a36Sopenharmony_ci				.type = USB_BULK,
242662306a36Sopenharmony_ci				.count = 8,
242762306a36Sopenharmony_ci				.endpoint = 0x82,
242862306a36Sopenharmony_ci				.u = {
242962306a36Sopenharmony_ci					.bulk = {
243062306a36Sopenharmony_ci						.buffersize = 4096,
243162306a36Sopenharmony_ci					}
243262306a36Sopenharmony_ci				}
243362306a36Sopenharmony_ci			}
243462306a36Sopenharmony_ci		} },
243562306a36Sopenharmony_ci		}
243662306a36Sopenharmony_ci	},
243762306a36Sopenharmony_ci	.num_device_descs = 2,
243862306a36Sopenharmony_ci	.devices = {
243962306a36Sopenharmony_ci		{ "TeVii S421 PCI",
244062306a36Sopenharmony_ci			{ &dw2102_table[TEVII_S421], NULL },
244162306a36Sopenharmony_ci			{ NULL },
244262306a36Sopenharmony_ci		},
244362306a36Sopenharmony_ci		{ "TeVii S632 USB",
244462306a36Sopenharmony_ci			{ &dw2102_table[TEVII_S632], NULL },
244562306a36Sopenharmony_ci			{ NULL },
244662306a36Sopenharmony_ci		},
244762306a36Sopenharmony_ci	}
244862306a36Sopenharmony_ci};
244962306a36Sopenharmony_ci
245062306a36Sopenharmony_cistatic struct dvb_usb_device_properties t220_properties = {
245162306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
245262306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
245362306a36Sopenharmony_ci	.size_of_priv = sizeof(struct dw2102_state),
245462306a36Sopenharmony_ci	.power_ctrl = su3000_power_ctrl,
245562306a36Sopenharmony_ci	.num_adapters = 1,
245662306a36Sopenharmony_ci	.identify_state	= su3000_identify_state,
245762306a36Sopenharmony_ci	.i2c_algo = &su3000_i2c_algo,
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci	.rc.core = {
246062306a36Sopenharmony_ci		.rc_interval = 150,
246162306a36Sopenharmony_ci		.rc_codes = RC_MAP_SU3000,
246262306a36Sopenharmony_ci		.module_name = "dw2102",
246362306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_RC5,
246462306a36Sopenharmony_ci		.rc_query = su3000_rc_query,
246562306a36Sopenharmony_ci	},
246662306a36Sopenharmony_ci
246762306a36Sopenharmony_ci	.read_mac_address = su3000_read_mac_address,
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	.adapter = {
247262306a36Sopenharmony_ci		{
247362306a36Sopenharmony_ci		.num_frontends = 1,
247462306a36Sopenharmony_ci		.fe = { {
247562306a36Sopenharmony_ci			.streaming_ctrl   = su3000_streaming_ctrl,
247662306a36Sopenharmony_ci			.frontend_attach  = t220_frontend_attach,
247762306a36Sopenharmony_ci			.stream = {
247862306a36Sopenharmony_ci				.type = USB_BULK,
247962306a36Sopenharmony_ci				.count = 8,
248062306a36Sopenharmony_ci				.endpoint = 0x82,
248162306a36Sopenharmony_ci				.u = {
248262306a36Sopenharmony_ci					.bulk = {
248362306a36Sopenharmony_ci						.buffersize = 4096,
248462306a36Sopenharmony_ci					}
248562306a36Sopenharmony_ci				}
248662306a36Sopenharmony_ci			}
248762306a36Sopenharmony_ci		} },
248862306a36Sopenharmony_ci		}
248962306a36Sopenharmony_ci	},
249062306a36Sopenharmony_ci	.num_device_descs = 1,
249162306a36Sopenharmony_ci	.devices = {
249262306a36Sopenharmony_ci		{ "Geniatech T220 DVB-T/T2 USB2.0",
249362306a36Sopenharmony_ci			{ &dw2102_table[GENIATECH_T220], NULL },
249462306a36Sopenharmony_ci			{ NULL },
249562306a36Sopenharmony_ci		},
249662306a36Sopenharmony_ci	}
249762306a36Sopenharmony_ci};
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_cistatic struct dvb_usb_device_properties tt_s2_4600_properties = {
250062306a36Sopenharmony_ci	.caps = DVB_USB_IS_AN_I2C_ADAPTER,
250162306a36Sopenharmony_ci	.usb_ctrl = DEVICE_SPECIFIC,
250262306a36Sopenharmony_ci	.size_of_priv = sizeof(struct dw2102_state),
250362306a36Sopenharmony_ci	.power_ctrl = su3000_power_ctrl,
250462306a36Sopenharmony_ci	.num_adapters = 1,
250562306a36Sopenharmony_ci	.identify_state	= su3000_identify_state,
250662306a36Sopenharmony_ci	.i2c_algo = &su3000_i2c_algo,
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	.rc.core = {
250962306a36Sopenharmony_ci		.rc_interval = 250,
251062306a36Sopenharmony_ci		.rc_codes = RC_MAP_TT_1500,
251162306a36Sopenharmony_ci		.module_name = "dw2102",
251262306a36Sopenharmony_ci		.allowed_protos   = RC_PROTO_BIT_RC5,
251362306a36Sopenharmony_ci		.rc_query = su3000_rc_query,
251462306a36Sopenharmony_ci	},
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_ci	.read_mac_address = su3000_read_mac_address,
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	.generic_bulk_ctrl_endpoint = 0x01,
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	.adapter = {
252162306a36Sopenharmony_ci		{
252262306a36Sopenharmony_ci		.num_frontends = 1,
252362306a36Sopenharmony_ci		.fe = {{
252462306a36Sopenharmony_ci			.streaming_ctrl   = su3000_streaming_ctrl,
252562306a36Sopenharmony_ci			.frontend_attach  = tt_s2_4600_frontend_attach,
252662306a36Sopenharmony_ci			.stream = {
252762306a36Sopenharmony_ci				.type = USB_BULK,
252862306a36Sopenharmony_ci				.count = 8,
252962306a36Sopenharmony_ci				.endpoint = 0x82,
253062306a36Sopenharmony_ci				.u = {
253162306a36Sopenharmony_ci					.bulk = {
253262306a36Sopenharmony_ci						.buffersize = 4096,
253362306a36Sopenharmony_ci					}
253462306a36Sopenharmony_ci				}
253562306a36Sopenharmony_ci			}
253662306a36Sopenharmony_ci		} },
253762306a36Sopenharmony_ci		}
253862306a36Sopenharmony_ci	},
253962306a36Sopenharmony_ci	.num_device_descs = 5,
254062306a36Sopenharmony_ci	.devices = {
254162306a36Sopenharmony_ci		{ "TechnoTrend TT-connect S2-4600",
254262306a36Sopenharmony_ci			{ &dw2102_table[TECHNOTREND_CONNECT_S2_4600], NULL },
254362306a36Sopenharmony_ci			{ NULL },
254462306a36Sopenharmony_ci		},
254562306a36Sopenharmony_ci		{ "TeVii S482 (tuner 1)",
254662306a36Sopenharmony_ci			{ &dw2102_table[TEVII_S482_1], NULL },
254762306a36Sopenharmony_ci			{ NULL },
254862306a36Sopenharmony_ci		},
254962306a36Sopenharmony_ci		{ "TeVii S482 (tuner 2)",
255062306a36Sopenharmony_ci			{ &dw2102_table[TEVII_S482_2], NULL },
255162306a36Sopenharmony_ci			{ NULL },
255262306a36Sopenharmony_ci		},
255362306a36Sopenharmony_ci		{ "Terratec Cinergy S2 USB BOX",
255462306a36Sopenharmony_ci			{ &dw2102_table[TERRATEC_CINERGY_S2_BOX], NULL },
255562306a36Sopenharmony_ci			{ NULL },
255662306a36Sopenharmony_ci		},
255762306a36Sopenharmony_ci		{ "TeVii S662",
255862306a36Sopenharmony_ci			{ &dw2102_table[TEVII_S662], NULL },
255962306a36Sopenharmony_ci			{ NULL },
256062306a36Sopenharmony_ci		},
256162306a36Sopenharmony_ci	}
256262306a36Sopenharmony_ci};
256362306a36Sopenharmony_ci
256462306a36Sopenharmony_cistatic int dw2102_probe(struct usb_interface *intf,
256562306a36Sopenharmony_ci		const struct usb_device_id *id)
256662306a36Sopenharmony_ci{
256762306a36Sopenharmony_ci	if (!(dvb_usb_device_init(intf, &dw2102_properties,
256862306a36Sopenharmony_ci			          THIS_MODULE, NULL, adapter_nr) &&
256962306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &dw2104_properties,
257062306a36Sopenharmony_ci				  THIS_MODULE, NULL, adapter_nr) &&
257162306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &dw3101_properties,
257262306a36Sopenharmony_ci			          THIS_MODULE, NULL, adapter_nr) &&
257362306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &s6x0_properties,
257462306a36Sopenharmony_ci			          THIS_MODULE, NULL, adapter_nr) &&
257562306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &p1100_properties,
257662306a36Sopenharmony_ci			          THIS_MODULE, NULL, adapter_nr) &&
257762306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &s660_properties,
257862306a36Sopenharmony_ci				  THIS_MODULE, NULL, adapter_nr) &&
257962306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &p7500_properties,
258062306a36Sopenharmony_ci				  THIS_MODULE, NULL, adapter_nr) &&
258162306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &s421_properties,
258262306a36Sopenharmony_ci				  THIS_MODULE, NULL, adapter_nr) &&
258362306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &su3000_properties,
258462306a36Sopenharmony_ci				  THIS_MODULE, NULL, adapter_nr) &&
258562306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &t220_properties,
258662306a36Sopenharmony_ci				  THIS_MODULE, NULL, adapter_nr) &&
258762306a36Sopenharmony_ci	      dvb_usb_device_init(intf, &tt_s2_4600_properties,
258862306a36Sopenharmony_ci				  THIS_MODULE, NULL, adapter_nr))) {
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci		return 0;
259162306a36Sopenharmony_ci	}
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	return -ENODEV;
259462306a36Sopenharmony_ci}
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_cistatic void dw2102_disconnect(struct usb_interface *intf)
259762306a36Sopenharmony_ci{
259862306a36Sopenharmony_ci	struct dvb_usb_device *d = usb_get_intfdata(intf);
259962306a36Sopenharmony_ci	struct dw2102_state *st = d->priv;
260062306a36Sopenharmony_ci	struct i2c_client *client;
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci	/* remove I2C client for tuner */
260362306a36Sopenharmony_ci	client = st->i2c_client_tuner;
260462306a36Sopenharmony_ci	if (client) {
260562306a36Sopenharmony_ci		module_put(client->dev.driver->owner);
260662306a36Sopenharmony_ci		i2c_unregister_device(client);
260762306a36Sopenharmony_ci	}
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	/* remove I2C client for demodulator */
261062306a36Sopenharmony_ci	client = st->i2c_client_demod;
261162306a36Sopenharmony_ci	if (client) {
261262306a36Sopenharmony_ci		module_put(client->dev.driver->owner);
261362306a36Sopenharmony_ci		i2c_unregister_device(client);
261462306a36Sopenharmony_ci	}
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	dvb_usb_device_exit(intf);
261762306a36Sopenharmony_ci}
261862306a36Sopenharmony_ci
261962306a36Sopenharmony_cistatic struct usb_driver dw2102_driver = {
262062306a36Sopenharmony_ci	.name = "dw2102",
262162306a36Sopenharmony_ci	.probe = dw2102_probe,
262262306a36Sopenharmony_ci	.disconnect = dw2102_disconnect,
262362306a36Sopenharmony_ci	.id_table = dw2102_table,
262462306a36Sopenharmony_ci};
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_cimodule_usb_driver(dw2102_driver);
262762306a36Sopenharmony_ci
262862306a36Sopenharmony_ciMODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by");
262962306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101 USB2.0, TeVii S421, S480, S482, S600, S630, S632, S650, TeVii S660, S662, Prof 1100, 7500 USB2.0, Geniatech SU3000, T220, TechnoTrend S2-4600, Terratec Cinergy S2 devices");
263062306a36Sopenharmony_ciMODULE_VERSION("0.1");
263162306a36Sopenharmony_ciMODULE_LICENSE("GPL");
263262306a36Sopenharmony_ciMODULE_FIRMWARE(DW2101_FIRMWARE);
263362306a36Sopenharmony_ciMODULE_FIRMWARE(DW2102_FIRMWARE);
263462306a36Sopenharmony_ciMODULE_FIRMWARE(DW2104_FIRMWARE);
263562306a36Sopenharmony_ciMODULE_FIRMWARE(DW3101_FIRMWARE);
263662306a36Sopenharmony_ciMODULE_FIRMWARE(S630_FIRMWARE);
263762306a36Sopenharmony_ciMODULE_FIRMWARE(S660_FIRMWARE);
263862306a36Sopenharmony_ciMODULE_FIRMWARE(P1100_FIRMWARE);
263962306a36Sopenharmony_ciMODULE_FIRMWARE(P7500_FIRMWARE);
2640