All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] IT930x USB DVB-T2/C tuner
@ 2014-09-21 10:53 Olli Salonen
  2014-09-21 10:53 ` [PATCH 1/3] si2157: Add support for Si2147-A30 Olli Salonen
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Olli Salonen @ 2014-09-21 10:53 UTC (permalink / raw)
  To: linux-media; +Cc: Olli Salonen, crope

This patch set adds support for IT930x reference design. It contains IT9303 USB bridge, Si2168-B40 demodulator and Si2147-A30 tuner.

The patches should be applied on top of Antti's af9035 branch.
http://git.linuxtv.org/cgit.cgi/anttip/media_tree.git/log/?h=af9035

Cc: crope@iki.fi

Olli Salonen (3):
  si2157: Add support for Si2147-A30
  af9035: Add possibility to define which I2C adapter to use
  af9035: Add support for IT930x USB bridge

 drivers/media/dvb-core/dvb-usb-ids.h  |   1 +
 drivers/media/tuners/si2157.c         |  13 +-
 drivers/media/tuners/si2157.h         |   2 +-
 drivers/media/tuners/si2157_priv.h    |   2 +-
 drivers/media/usb/dvb-usb-v2/af9035.c | 333 +++++++++++++++++++++++++++++++---
 drivers/media/usb/dvb-usb-v2/af9035.h |   6 +
 6 files changed, 331 insertions(+), 26 deletions(-)

-- 
1.9.1


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/3] si2157: Add support for Si2147-A30
  2014-09-21 10:53 [PATCH 0/3] IT930x USB DVB-T2/C tuner Olli Salonen
@ 2014-09-21 10:53 ` Olli Salonen
  2014-09-23 12:36   ` Antti Palosaari
  2014-09-21 10:53 ` [PATCH 2/3] af9035: Add possibility to define which I2C adapter to use Olli Salonen
  2014-09-21 10:53 ` [PATCH 3/3] af9035: Add support for IT930x USB bridge Olli Salonen
  2 siblings, 1 reply; 8+ messages in thread
From: Olli Salonen @ 2014-09-21 10:53 UTC (permalink / raw)
  To: linux-media; +Cc: Olli Salonen, crope

This patch adds support for Si2147-A30 tuner. Fairly trivial, no firmware
needed for this tuner. However, command 14 00 02 07 01 00 seems to be
mandatory. On Si2157 and Si2158 the value 0x0100 is the default value, so this
patch does not impact the existing tuners/devices. On Si2147 the default is
0x0000 and I can't get a lock with that value.

Signed-off-by: Olli Salonen <olli.salonen@iki.fi>
Cc: crope@iki.fi
---
 drivers/media/tuners/si2157.c      | 13 +++++++++++--
 drivers/media/tuners/si2157.h      |  2 +-
 drivers/media/tuners/si2157_priv.h |  2 +-
 3 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index efb5cce..41965c7 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
@@ -110,12 +110,14 @@ static int si2157_init(struct dvb_frontend *fe)
 
 	#define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
 	#define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
+	#define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
 
 	switch (chip_id) {
 	case SI2158_A20:
 		fw_file = SI2158_A20_FIRMWARE;
 		break;
 	case SI2157_A30:
+	case SI2147_A30:
 		goto skip_fw_download;
 		break;
 	default:
@@ -258,7 +260,14 @@ static int si2157_set_params(struct dvb_frontend *fe)
 	if (s->inversion)
 		cmd.args[5] = 0x01;
 	cmd.wlen = 6;
-	cmd.rlen = 1;
+	cmd.rlen = 4;
+	ret = si2157_cmd_execute(s, &cmd);
+	if (ret)
+		goto err;
+
+	memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6);
+	cmd.wlen = 6;
+	cmd.rlen = 4;
 	ret = si2157_cmd_execute(s, &cmd);
 	if (ret)
 		goto err;
diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
index 6da4d5d..d3b19ca 100644
--- a/drivers/media/tuners/si2157.h
+++ b/drivers/media/tuners/si2157.h
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index 3ddab5e..02350f8 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -1,5 +1,5 @@
 /*
- * Silicon Labs Si2157/2158 silicon tuner driver
+ * Silicon Labs Si2147/2157/2158 silicon tuner driver
  *
  * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
  *
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/3] af9035: Add possibility to define which I2C adapter to use
  2014-09-21 10:53 [PATCH 0/3] IT930x USB DVB-T2/C tuner Olli Salonen
  2014-09-21 10:53 ` [PATCH 1/3] si2157: Add support for Si2147-A30 Olli Salonen
@ 2014-09-21 10:53 ` Olli Salonen
  2014-09-23 12:37   ` Antti Palosaari
  2014-09-21 10:53 ` [PATCH 3/3] af9035: Add support for IT930x USB bridge Olli Salonen
  2 siblings, 1 reply; 8+ messages in thread
From: Olli Salonen @ 2014-09-21 10:53 UTC (permalink / raw)
  To: linux-media; +Cc: Olli Salonen, crope

Some I2C tuner drivers require that the I2C device of the tuner is added to the I2C adapter of the demodulator (Si2168+Si2157 for example). Add possibility to tell af9035_add_i2c_dev which I2C adapter should be used.

Cc: crope@iki.fi
Signed-off-by: Olli Salonen <olli.salonen@iki.fi>
---
 drivers/media/usb/dvb-usb-v2/af9035.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 440ecb4..c50d27d 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -194,12 +194,11 @@ static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
 }
 
 static int af9035_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
-		void *platform_data)
+		void *platform_data, struct i2c_adapter *adapter)
 {
 	int ret, num;
 	struct state *state = d_to_priv(d);
 	struct i2c_client *client;
-	struct i2c_adapter *adapter = &d->i2c_adap;
 	struct i2c_board_info board_info = {
 		.addr = addr,
 		.platform_data = platform_data,
@@ -1091,7 +1090,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
 	state->af9033_config[adap->id].fe = &adap->fe[0];
 	state->af9033_config[adap->id].ops = &state->ops;
 	ret = af9035_add_i2c_dev(d, "af9033", state->af9033_i2c_addr[adap->id],
-			&state->af9033_config[adap->id]);
+			&state->af9033_config[adap->id], &d->i2c_adap);
 	if (ret)
 		goto err;
 
@@ -1382,7 +1381,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
 
 		ret = af9035_add_i2c_dev(d, "it913x",
 				state->af9033_i2c_addr[adap->id] >> 1,
-				&it913x_config);
+				&it913x_config, &d->i2c_adap);
 		if (ret)
 			goto err;
 
@@ -1407,7 +1406,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
 
 		ret = af9035_add_i2c_dev(d, "it913x",
 				state->af9033_i2c_addr[adap->id] >> 1,
-				&it913x_config);
+				&it913x_config, &d->i2c_adap);
 		if (ret)
 			goto err;
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/3] af9035: Add support for IT930x USB bridge
  2014-09-21 10:53 [PATCH 0/3] IT930x USB DVB-T2/C tuner Olli Salonen
  2014-09-21 10:53 ` [PATCH 1/3] si2157: Add support for Si2147-A30 Olli Salonen
  2014-09-21 10:53 ` [PATCH 2/3] af9035: Add possibility to define which I2C adapter to use Olli Salonen
@ 2014-09-21 10:53 ` Olli Salonen
  2014-09-23 12:46   ` Antti Palosaari
  2 siblings, 1 reply; 8+ messages in thread
From: Olli Salonen @ 2014-09-21 10:53 UTC (permalink / raw)
  To: linux-media; +Cc: Olli Salonen, crope

Add support for IT930x USB bridge and IT9303 reference design.

It is a DVB-T/T2/C tuner with the following components:
- IT9303 USB bridge
- Si2168-B40 demodulator
- Si2147-A30 tuner

The IT9303 requires firmware that can be downloaded here:
http://trsqr.net/olli/linux/firmwares/it930x/

The Si2168-B40 requires firmware, but the one that is used by PCTV 292e can be used.
http://palosaari.fi/linux/v4l-dvb/firmware/Si2168/Si2168-B40/

The Si2147-A30 tuner does not require firmware loading.

Cc: crope@iki.fi
Signed-off-by: Olli Salonen <olli.salonen@iki.fi>
---
 drivers/media/dvb-core/dvb-usb-ids.h  |   1 +
 drivers/media/usb/dvb-usb-v2/af9035.c | 324 ++++++++++++++++++++++++++++++++--
 drivers/media/usb/dvb-usb-v2/af9035.h |   6 +
 3 files changed, 314 insertions(+), 17 deletions(-)

diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index d484a51..e07a84e 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -144,6 +144,7 @@
 #define USB_PID_ITETECH_IT9135				0x9135
 #define USB_PID_ITETECH_IT9135_9005			0x9005
 #define USB_PID_ITETECH_IT9135_9006			0x9006
+#define USB_PID_ITETECH_IT9303				0x9306
 #define USB_PID_KWORLD_399U				0xe399
 #define USB_PID_KWORLD_399U_2				0xe400
 #define USB_PID_KWORLD_395U				0xe396
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index c50d27d..00758c8 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -290,7 +290,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
 		return -EAGAIN;
 
 	/*
-	 * I2C sub header is 5 bytes long. Meaning of those bytes are:
+	 * AF9035 I2C sub header is 5 bytes long. Meaning of those bytes are:
 	 * 0: data len
 	 * 1: I2C addr << 1
 	 * 2: reg addr len
@@ -317,6 +317,12 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
 	 * bus. I2C subsystem does not allow register multiple devices to same
 	 * bus, having same slave address. Due to that we reuse demod address,
 	 * shifted by one bit, on that case.
+	 *
+	 * For IT930x we use a different command and the sub header is
+	 * different as well:
+	 * 0: data len
+	 * 1: I2C bus (0x03 seems to be only value used)
+	 * 2: I2C addr << 1
 	 */
 #define AF9035_IS_I2C_XFER_WRITE_READ(_msg, _num) \
 	(_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD))
@@ -348,13 +354,24 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
 			struct usb_req req = { CMD_I2C_RD, 0, 5 + msg[0].len,
 					buf, msg[1].len, msg[1].buf };
 
+			if (state->chip_type == 0x9306) {
+				req.cmd = CMD_GENERIC_I2C_RD;
+				req.wlen = 3 + msg[0].len;
+			}
 			req.mbox |= ((msg[0].addr & 0x80)  >>  3);
+
 			buf[0] = msg[1].len;
-			buf[1] = msg[0].addr << 1;
-			buf[2] = 0x00; /* reg addr len */
-			buf[3] = 0x00; /* reg addr MSB */
-			buf[4] = 0x00; /* reg addr LSB */
-			memcpy(&buf[5], msg[0].buf, msg[0].len);
+			if (state->chip_type == 0x9306) {
+				buf[1] = 0x03; /* I2C bus */
+				buf[2] = msg[0].addr << 1;
+				memcpy(&buf[3], msg[0].buf, msg[0].len);
+			} else {
+				buf[1] = msg[0].addr << 1;
+				buf[2] = 0x00; /* reg addr len */
+				buf[3] = 0x00; /* reg addr MSB */
+				buf[4] = 0x00; /* reg addr LSB */
+				memcpy(&buf[5], msg[0].buf, msg[0].len);
+			}
 			ret = af9035_ctrl_msg(d, &req);
 		}
 	} else if (AF9035_IS_I2C_XFER_WRITE(msg, num)) {
@@ -380,13 +397,24 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
 			struct usb_req req = { CMD_I2C_WR, 0, 5 + msg[0].len,
 					buf, 0, NULL };
 
+			if (state->chip_type == 0x9306) {
+				req.cmd = CMD_GENERIC_I2C_WR;
+				req.wlen = 3 + msg[0].len;
+			}
+
 			req.mbox |= ((msg[0].addr & 0x80)  >>  3);
 			buf[0] = msg[0].len;
-			buf[1] = msg[0].addr << 1;
-			buf[2] = 0x00; /* reg addr len */
-			buf[3] = 0x00; /* reg addr MSB */
-			buf[4] = 0x00; /* reg addr LSB */
-			memcpy(&buf[5], msg[0].buf, msg[0].len);
+			if (state->chip_type == 0x9306) {
+				buf[1] = 0x03; /* I2C bus */
+				buf[2] = msg[0].addr << 1;
+				memcpy(&buf[3], msg[0].buf, msg[0].len);
+			} else {
+				buf[1] = msg[0].addr << 1;
+				buf[2] = 0x00; /* reg addr len */
+				buf[3] = 0x00; /* reg addr MSB */
+				buf[4] = 0x00; /* reg addr LSB */
+				memcpy(&buf[5], msg[0].buf, msg[0].len);
+			}
 			ret = af9035_ctrl_msg(d, &req);
 		}
 	} else if (AF9035_IS_I2C_XFER_READ(msg, num)) {
@@ -397,13 +425,23 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
 			/* I2C read */
 			u8 buf[5];
 			struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
-					buf, msg[0].len, msg[0].buf };
+						buf, msg[0].len, msg[0].buf };
+
+			if (state->chip_type == 0x9306) {
+				req.cmd = CMD_GENERIC_I2C_RD;
+				req.wlen = 3;
+			}
 			req.mbox |= ((msg[0].addr & 0x80)  >>  3);
 			buf[0] = msg[0].len;
-			buf[1] = msg[0].addr << 1;
-			buf[2] = 0x00; /* reg addr len */
-			buf[3] = 0x00; /* reg addr MSB */
-			buf[4] = 0x00; /* reg addr LSB */
+			if (state->chip_type == 0x9306) {
+				buf[1] = 0x03; /* I2C bus */
+				buf[2] = msg[0].addr << 1;
+			} else {
+				buf[1] = msg[0].addr << 1;
+				buf[2] = 0x00; /* reg addr len */
+				buf[3] = 0x00; /* reg addr MSB */
+				buf[4] = 0x00; /* reg addr LSB */
+			}
 			ret = af9035_ctrl_msg(d, &req);
 		}
 	} else {
@@ -465,6 +503,9 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
 		else
 			*name = AF9035_FIRMWARE_IT9135_V1;
 		state->eeprom_addr = EEPROM_BASE_IT9135;
+	} else if (state->chip_type == 0x9306) {
+		*name = AF9035_FIRMWARE_IT9303;
+		state->eeprom_addr = EEPROM_BASE_IT9135;
 	} else {
 		*name = AF9035_FIRMWARE_AF9035;
 		state->eeprom_addr = EEPROM_BASE_AF9035;
@@ -674,7 +715,8 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
 		if (!tmp)
 			tmp = 0x3a;
 
-		if (state->chip_type == 0x9135) {
+		if ((state->chip_type == 0x9135) ||
+				(state->chip_type == 0x9306)) {
 			ret = af9035_wr_reg(d, 0x004bfb, tmp);
 			if (ret < 0)
 				goto err;
@@ -766,8 +808,16 @@ static int af9035_read_config(struct dvb_usb_device *d)
 			dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__);
 			goto skip_eeprom;
 		}
+	} else if (state->chip_type == 0x9306) {
+		/*
+		 * IT930x is an USB bridge, only single demod-single tuner
+		 * configurations seen so far.
+		 */
+		return 0;
 	}
 
+
+
 	/* check if there is dual tuners */
 	ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
 	if (ret < 0)
@@ -1111,6 +1161,41 @@ err:
 	return ret;
 }
 
+static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret;
+	struct si2168_config si2168_config;
+	struct i2c_adapter *adapter;
+
+	dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
+
+	si2168_config.i2c_adapter = &adapter;
+	si2168_config.fe = &adap->fe[0];
+	si2168_config.ts_mode = SI2168_TS_SERIAL;
+
+	state->af9033_config[adap->id].fe = &adap->fe[0];
+	state->af9033_config[adap->id].ops = &state->ops;
+	ret = af9035_add_i2c_dev(d, "si2168", 0x67, &si2168_config,
+				&d->i2c_adap);
+	if (ret)
+		goto err;
+
+	if (adap->fe[0] == NULL) {
+		ret = -ENODEV;
+		goto err;
+	}
+	state->i2c_adapter_demod = adapter;
+
+	return 0;
+
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
 static int af9035_frontend_detach(struct dvb_usb_adapter *adap)
 {
 	struct state *state = adap_to_priv(adap);
@@ -1430,6 +1515,93 @@ err:
 	return ret;
 }
 
+static int it930x_tuner_attach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+	int ret;
+	struct si2157_config si2157_config;
+
+	dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
+
+	/* I2C master bus 2 clock speed 300k */
+	ret = af9035_wr_reg(d, 0x00f6a7, 0x07);
+	if (ret < 0)
+		goto err;
+
+	/* I2C master bus 1,3 clock speed 300k */
+	ret = af9035_wr_reg(d, 0x00f103, 0x07);
+	if (ret < 0)
+		goto err;
+
+	/* set gpio11 low */
+	ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	/* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */
+	ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01);
+	if (ret < 0)
+		goto err;
+
+	msleep(200);
+
+	ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01);
+	if (ret < 0)
+		goto err;
+
+	memset(&si2157_config, 0, sizeof(si2157_config));
+	si2157_config.fe = adap->fe[0];
+	ret = af9035_add_i2c_dev(d, "si2157", 0x63,
+			&si2157_config, state->i2c_adapter_demod);
+
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+
+static int it930x_tuner_detach(struct dvb_usb_adapter *adap)
+{
+	struct state *state = adap_to_priv(adap);
+	struct dvb_usb_device *d = adap_to_d(adap);
+
+	dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
+
+	if (adap->id == 1) {
+		if (state->i2c_client[3])
+			af9035_del_i2c_dev(d);
+	} else if (adap->id == 0) {
+		if (state->i2c_client[1])
+			af9035_del_i2c_dev(d);
+	}
+
+	return 0;
+}
+
+
 static int af9035_tuner_detach(struct dvb_usb_adapter *adap)
 {
 	struct state *state = adap_to_priv(adap);
@@ -1503,6 +1675,89 @@ err:
 	return ret;
 }
 
+static int it930x_init(struct dvb_usb_device *d)
+{
+	struct state *state = d_to_priv(d);
+	int ret, i;
+	u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 816) * 188 / 4;
+	u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4;
+	struct reg_val_mask tab[] = {
+		{ 0x00da1a, 0x00, 0x01 }, /* ignore_sync_byte */
+		{ 0x00f41f, 0x04, 0x04 }, /* dvbt_inten */
+		{ 0x00da10, 0x00, 0x01 }, /* mpeg_full_speed */
+		{ 0x00f41a, 0x01, 0x01 }, /* dvbt_en */
+		{ 0x00da1d, 0x01, 0x01 }, /* mp2_sw_rst, reset EP4 */
+		{ 0x00dd11, 0x00, 0x20 }, /* ep4_tx_en, disable EP4 */
+		{ 0x00dd13, 0x00, 0x20 }, /* ep4_tx_nak, disable EP4 NAK */
+		{ 0x00dd11, 0x20, 0x20 }, /* ep4_tx_en, enable EP4 */
+		{ 0x00dd11, 0x00, 0x40 }, /* ep5_tx_en, disable EP5 */
+		{ 0x00dd13, 0x00, 0x40 }, /* ep5_tx_nak, disable EP5 NAK */
+		{ 0x00dd11, state->dual_mode << 6, 0x40 }, /* enable EP5 */
+		{ 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
+		{ 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
+		{ 0x00dd0c, packet_size, 0xff},
+		{ 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
+		{ 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
+		{ 0x00dd0d, packet_size, 0xff },
+		{ 0x00da1d, 0x00, 0x01 }, /* mp2_sw_rst, disable */
+		{ 0x00d833, 0x01, 0xff }, /* slew rate ctrl: slew rate boosts */
+		{ 0x00d830, 0x00, 0xff }, /* Bit 0 of output driving control */
+		{ 0x00d831, 0x01, 0xff }, /* Bit 1 of output driving control */
+		{ 0x00d832, 0x00, 0xff }, /* Bit 2 of output driving control */
+
+		/* suspend gpio1 for TS-C */
+		{ 0x00d8b0, 0x01, 0xff }, /* gpio1 */
+		{ 0x00d8b1, 0x01, 0xff }, /* gpio1 */
+		{ 0x00d8af, 0x00, 0xff }, /* gpio1 */
+
+		/* suspend gpio7 for TS-D */
+		{ 0x00d8c4, 0x01, 0xff }, /* gpio7 */
+		{ 0x00d8c5, 0x01, 0xff }, /* gpio7 */
+		{ 0x00d8c3, 0x00, 0xff }, /* gpio7 */
+
+		/* suspend gpio13 for TS-B */
+		{ 0x00d8dc, 0x01, 0xff }, /* gpio13 */
+		{ 0x00d8dd, 0x01, 0xff }, /* gpio13 */
+		{ 0x00d8db, 0x00, 0xff }, /* gpio13 */
+
+		/* suspend gpio14 for TS-E */
+		{ 0x00d8e4, 0x01, 0xff }, /* gpio14 */
+		{ 0x00d8e5, 0x01, 0xff }, /* gpio14 */
+		{ 0x00d8e3, 0x00, 0xff }, /* gpio14 */
+
+		/* suspend gpio15 for TS-A */
+		{ 0x00d8e8, 0x01, 0xff }, /* gpio15 */
+		{ 0x00d8e9, 0x01, 0xff }, /* gpio15 */
+		{ 0x00d8e7, 0x00, 0xff }, /* gpio15 */
+
+		{ 0x00da58, 0x00, 0x01 }, /* ts_in_src, serial */
+		{ 0x00da73, 0x01, 0xff }, /* ts0_aggre_mode */
+		{ 0x00da78, 0x47, 0xff }, /* ts0_sync_byte */
+		{ 0x00da4c, 0x01, 0xff }, /* ts0_en */
+		{ 0x00da5a, 0x1f, 0xff }, /* ts_fail_ignore */
+	};
+
+	dev_dbg(&d->udev->dev,
+			"%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
+			__func__, d->udev->speed, frame_size, packet_size);
+
+	/* init endpoints */
+	for (i = 0; i < ARRAY_SIZE(tab); i++) {
+		ret = af9035_wr_reg_mask(d, tab[i].reg,
+				tab[i].val, tab[i].mask);
+
+		if (ret < 0)
+			goto err;
+	}
+
+	return 0;
+err:
+	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+	return ret;
+}
+
+
 #if IS_ENABLED(CONFIG_RC_CORE)
 static int af9035_rc_query(struct dvb_usb_device *d)
 {
@@ -1706,6 +1961,37 @@ static const struct dvb_usb_device_properties af9035_props = {
 	},
 };
 
+static const struct dvb_usb_device_properties it930x_props = {
+	.driver_name = KBUILD_MODNAME,
+	.owner = THIS_MODULE,
+	.adapter_nr = adapter_nr,
+	.size_of_priv = sizeof(struct state),
+
+	.generic_bulk_ctrl_endpoint = 0x02,
+	.generic_bulk_ctrl_endpoint_response = 0x81,
+
+	.identify_state = af9035_identify_state,
+	.download_firmware = af9035_download_firmware,
+
+	.i2c_algo = &af9035_i2c_algo,
+	.read_config = af9035_read_config,
+	.frontend_attach = it930x_frontend_attach,
+	.frontend_detach = af9035_frontend_detach,
+	.tuner_attach = it930x_tuner_attach,
+	.tuner_detach = it930x_tuner_detach,
+	.init = it930x_init,
+	.get_stream_config = af9035_get_stream_config,
+
+	.get_adapter_count = af9035_get_adapter_count,
+	.adapter = {
+		{
+			.stream = DVB_USB_STREAM_BULK(0x84, 4, 816 * 188),
+		}, {
+			.stream = DVB_USB_STREAM_BULK(0x85, 4, 816 * 188),
+		},
+	},
+};
+
 static const struct usb_device_id af9035_id_table[] = {
 	/* AF9035 devices */
 	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
@@ -1759,6 +2045,9 @@ static const struct usb_device_id af9035_id_table[] = {
 	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
 		&af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2",
 							RC_MAP_IT913X_V1) },
+	/* IT930x devices */
+	{ DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303,
+		&it930x_props, "ITE 9303 Generic", NULL) },
 	/* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
 	{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
 		&af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)",
@@ -1795,3 +2084,4 @@ MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035);
 MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1);
 MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2);
+MODULE_FIRMWARE(AF9035_FIRMWARE_IT9303);
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
index edb3871..416a97f 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.h
+++ b/drivers/media/usb/dvb-usb-v2/af9035.h
@@ -31,6 +31,8 @@
 #include "tda18218.h"
 #include "fc2580.h"
 #include "it913x.h"
+#include "si2168.h"
+#include "si2157.h"
 
 struct reg_val {
 	u32 reg;
@@ -66,6 +68,7 @@ struct state {
 	struct af9033_ops ops;
 	#define AF9035_I2C_CLIENT_MAX 4
 	struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX];
+	struct i2c_adapter *i2c_adapter_demod;
 };
 
 static const u32 clock_lut_af9035[] = {
@@ -99,6 +102,7 @@ static const u32 clock_lut_it9135[] = {
 #define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw"
 #define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw"
 #define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw"
+#define AF9035_FIRMWARE_IT9303 "dvb-usb-it9303-01.fw"
 
 /*
  * eeprom is memory mapped as read only. Writing that memory mapped address
@@ -140,5 +144,7 @@ static const u32 clock_lut_it9135[] = {
 #define CMD_FW_DL_BEGIN             0x24
 #define CMD_FW_DL_END               0x25
 #define CMD_FW_SCATTER_WR           0x29
+#define CMD_GENERIC_I2C_RD          0x2a
+#define CMD_GENERIC_I2C_WR          0x2b
 
 #endif
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/3] si2157: Add support for Si2147-A30
  2014-09-21 10:53 ` [PATCH 1/3] si2157: Add support for Si2147-A30 Olli Salonen
@ 2014-09-23 12:36   ` Antti Palosaari
  0 siblings, 0 replies; 8+ messages in thread
From: Antti Palosaari @ 2014-09-23 12:36 UTC (permalink / raw)
  To: Olli Salonen, linux-media

Acked-by: Antti Palosaari <crope@iki.fi>
Reviewed-by: Antti Palosaari <crope@iki.fi>


On 09/21/2014 01:53 PM, Olli Salonen wrote:
> This patch adds support for Si2147-A30 tuner. Fairly trivial, no firmware
> needed for this tuner. However, command 14 00 02 07 01 00 seems to be
> mandatory. On Si2157 and Si2158 the value 0x0100 is the default value, so this
> patch does not impact the existing tuners/devices. On Si2147 the default is
> 0x0000 and I can't get a lock with that value.
>
> Signed-off-by: Olli Salonen <olli.salonen@iki.fi>
> Cc: crope@iki.fi
> ---
>   drivers/media/tuners/si2157.c      | 13 +++++++++++--
>   drivers/media/tuners/si2157.h      |  2 +-
>   drivers/media/tuners/si2157_priv.h |  2 +-
>   3 files changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
> index efb5cce..41965c7 100644
> --- a/drivers/media/tuners/si2157.c
> +++ b/drivers/media/tuners/si2157.c
> @@ -1,5 +1,5 @@
>   /*
> - * Silicon Labs Si2157/2158 silicon tuner driver
> + * Silicon Labs Si2147/2157/2158 silicon tuner driver
>    *
>    * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
>    *
> @@ -110,12 +110,14 @@ static int si2157_init(struct dvb_frontend *fe)
>
>   	#define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
>   	#define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
> +	#define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
>
>   	switch (chip_id) {
>   	case SI2158_A20:
>   		fw_file = SI2158_A20_FIRMWARE;
>   		break;
>   	case SI2157_A30:
> +	case SI2147_A30:
>   		goto skip_fw_download;
>   		break;
>   	default:
> @@ -258,7 +260,14 @@ static int si2157_set_params(struct dvb_frontend *fe)
>   	if (s->inversion)
>   		cmd.args[5] = 0x01;
>   	cmd.wlen = 6;
> -	cmd.rlen = 1;
> +	cmd.rlen = 4;
> +	ret = si2157_cmd_execute(s, &cmd);
> +	if (ret)
> +		goto err;
> +
> +	memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6);
> +	cmd.wlen = 6;
> +	cmd.rlen = 4;
>   	ret = si2157_cmd_execute(s, &cmd);
>   	if (ret)
>   		goto err;
> diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
> index 6da4d5d..d3b19ca 100644
> --- a/drivers/media/tuners/si2157.h
> +++ b/drivers/media/tuners/si2157.h
> @@ -1,5 +1,5 @@
>   /*
> - * Silicon Labs Si2157/2158 silicon tuner driver
> + * Silicon Labs Si2147/2157/2158 silicon tuner driver
>    *
>    * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
>    *
> diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
> index 3ddab5e..02350f8 100644
> --- a/drivers/media/tuners/si2157_priv.h
> +++ b/drivers/media/tuners/si2157_priv.h
> @@ -1,5 +1,5 @@
>   /*
> - * Silicon Labs Si2157/2158 silicon tuner driver
> + * Silicon Labs Si2147/2157/2158 silicon tuner driver
>    *
>    * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
>    *
>

-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/3] af9035: Add possibility to define which I2C adapter to use
  2014-09-21 10:53 ` [PATCH 2/3] af9035: Add possibility to define which I2C adapter to use Olli Salonen
@ 2014-09-23 12:37   ` Antti Palosaari
  0 siblings, 0 replies; 8+ messages in thread
From: Antti Palosaari @ 2014-09-23 12:37 UTC (permalink / raw)
  To: Olli Salonen, linux-media

Acked-by: Antti Palosaari <crope@iki.fi>
Reviewed-by: Antti Palosaari <crope@iki.fi>


On 09/21/2014 01:53 PM, Olli Salonen wrote:
> Some I2C tuner drivers require that the I2C device of the tuner is added to the I2C adapter of the demodulator (Si2168+Si2157 for example). Add possibility to tell af9035_add_i2c_dev which I2C adapter should be used.
>
> Cc: crope@iki.fi
> Signed-off-by: Olli Salonen <olli.salonen@iki.fi>
> ---
>   drivers/media/usb/dvb-usb-v2/af9035.c | 9 ++++-----
>   1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
> index 440ecb4..c50d27d 100644
> --- a/drivers/media/usb/dvb-usb-v2/af9035.c
> +++ b/drivers/media/usb/dvb-usb-v2/af9035.c
> @@ -194,12 +194,11 @@ static int af9035_wr_reg_mask(struct dvb_usb_device *d, u32 reg, u8 val,
>   }
>
>   static int af9035_add_i2c_dev(struct dvb_usb_device *d, char *type, u8 addr,
> -		void *platform_data)
> +		void *platform_data, struct i2c_adapter *adapter)
>   {
>   	int ret, num;
>   	struct state *state = d_to_priv(d);
>   	struct i2c_client *client;
> -	struct i2c_adapter *adapter = &d->i2c_adap;
>   	struct i2c_board_info board_info = {
>   		.addr = addr,
>   		.platform_data = platform_data,
> @@ -1091,7 +1090,7 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
>   	state->af9033_config[adap->id].fe = &adap->fe[0];
>   	state->af9033_config[adap->id].ops = &state->ops;
>   	ret = af9035_add_i2c_dev(d, "af9033", state->af9033_i2c_addr[adap->id],
> -			&state->af9033_config[adap->id]);
> +			&state->af9033_config[adap->id], &d->i2c_adap);
>   	if (ret)
>   		goto err;
>
> @@ -1382,7 +1381,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
>
>   		ret = af9035_add_i2c_dev(d, "it913x",
>   				state->af9033_i2c_addr[adap->id] >> 1,
> -				&it913x_config);
> +				&it913x_config, &d->i2c_adap);
>   		if (ret)
>   			goto err;
>
> @@ -1407,7 +1406,7 @@ static int af9035_tuner_attach(struct dvb_usb_adapter *adap)
>
>   		ret = af9035_add_i2c_dev(d, "it913x",
>   				state->af9033_i2c_addr[adap->id] >> 1,
> -				&it913x_config);
> +				&it913x_config, &d->i2c_adap);
>   		if (ret)
>   			goto err;
>
>

-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] af9035: Add support for IT930x USB bridge
  2014-09-21 10:53 ` [PATCH 3/3] af9035: Add support for IT930x USB bridge Olli Salonen
@ 2014-09-23 12:46   ` Antti Palosaari
  2014-09-23 13:25     ` Olli Salonen
  0 siblings, 1 reply; 8+ messages in thread
From: Antti Palosaari @ 2014-09-23 12:46 UTC (permalink / raw)
  To: Olli Salonen, linux-media

Acked-by: Antti Palosaari <crope@iki.fi>
Reviewed-by: Antti Palosaari <crope@iki.fi>

Changes were a bit complicated, but I understood those in general and 
there is nothing wrong for my eyes. Mostly I was surprised of new 
implementation of init() (init is mainly for configuring TS interfaces).

Also I2C adapter xfer goes pretty complex, but that is because there is 
actually 3 I2C adapters and some of those even offer multiple access 
methods by firmware. Maybe there is also room for later improvement.

But as I said, patch it is OK.

regards
Antti


On 09/21/2014 01:53 PM, Olli Salonen wrote:
> Add support for IT930x USB bridge and IT9303 reference design.
>
> It is a DVB-T/T2/C tuner with the following components:
> - IT9303 USB bridge
> - Si2168-B40 demodulator
> - Si2147-A30 tuner
>
> The IT9303 requires firmware that can be downloaded here:
> http://trsqr.net/olli/linux/firmwares/it930x/
>
> The Si2168-B40 requires firmware, but the one that is used by PCTV 292e can be used.
> http://palosaari.fi/linux/v4l-dvb/firmware/Si2168/Si2168-B40/
>
> The Si2147-A30 tuner does not require firmware loading.
>
> Cc: crope@iki.fi
> Signed-off-by: Olli Salonen <olli.salonen@iki.fi>
> ---
>   drivers/media/dvb-core/dvb-usb-ids.h  |   1 +
>   drivers/media/usb/dvb-usb-v2/af9035.c | 324 ++++++++++++++++++++++++++++++++--
>   drivers/media/usb/dvb-usb-v2/af9035.h |   6 +
>   3 files changed, 314 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
> index d484a51..e07a84e 100644
> --- a/drivers/media/dvb-core/dvb-usb-ids.h
> +++ b/drivers/media/dvb-core/dvb-usb-ids.h
> @@ -144,6 +144,7 @@
>   #define USB_PID_ITETECH_IT9135				0x9135
>   #define USB_PID_ITETECH_IT9135_9005			0x9005
>   #define USB_PID_ITETECH_IT9135_9006			0x9006
> +#define USB_PID_ITETECH_IT9303				0x9306
>   #define USB_PID_KWORLD_399U				0xe399
>   #define USB_PID_KWORLD_399U_2				0xe400
>   #define USB_PID_KWORLD_395U				0xe396
> diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
> index c50d27d..00758c8 100644
> --- a/drivers/media/usb/dvb-usb-v2/af9035.c
> +++ b/drivers/media/usb/dvb-usb-v2/af9035.c
> @@ -290,7 +290,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
>   		return -EAGAIN;
>
>   	/*
> -	 * I2C sub header is 5 bytes long. Meaning of those bytes are:
> +	 * AF9035 I2C sub header is 5 bytes long. Meaning of those bytes are:
>   	 * 0: data len
>   	 * 1: I2C addr << 1
>   	 * 2: reg addr len
> @@ -317,6 +317,12 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
>   	 * bus. I2C subsystem does not allow register multiple devices to same
>   	 * bus, having same slave address. Due to that we reuse demod address,
>   	 * shifted by one bit, on that case.
> +	 *
> +	 * For IT930x we use a different command and the sub header is
> +	 * different as well:
> +	 * 0: data len
> +	 * 1: I2C bus (0x03 seems to be only value used)
> +	 * 2: I2C addr << 1
>   	 */
>   #define AF9035_IS_I2C_XFER_WRITE_READ(_msg, _num) \
>   	(_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags & I2C_M_RD))
> @@ -348,13 +354,24 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
>   			struct usb_req req = { CMD_I2C_RD, 0, 5 + msg[0].len,
>   					buf, msg[1].len, msg[1].buf };
>
> +			if (state->chip_type == 0x9306) {
> +				req.cmd = CMD_GENERIC_I2C_RD;
> +				req.wlen = 3 + msg[0].len;
> +			}
>   			req.mbox |= ((msg[0].addr & 0x80)  >>  3);
> +
>   			buf[0] = msg[1].len;
> -			buf[1] = msg[0].addr << 1;
> -			buf[2] = 0x00; /* reg addr len */
> -			buf[3] = 0x00; /* reg addr MSB */
> -			buf[4] = 0x00; /* reg addr LSB */
> -			memcpy(&buf[5], msg[0].buf, msg[0].len);
> +			if (state->chip_type == 0x9306) {
> +				buf[1] = 0x03; /* I2C bus */
> +				buf[2] = msg[0].addr << 1;
> +				memcpy(&buf[3], msg[0].buf, msg[0].len);
> +			} else {
> +				buf[1] = msg[0].addr << 1;
> +				buf[2] = 0x00; /* reg addr len */
> +				buf[3] = 0x00; /* reg addr MSB */
> +				buf[4] = 0x00; /* reg addr LSB */
> +				memcpy(&buf[5], msg[0].buf, msg[0].len);
> +			}
>   			ret = af9035_ctrl_msg(d, &req);
>   		}
>   	} else if (AF9035_IS_I2C_XFER_WRITE(msg, num)) {
> @@ -380,13 +397,24 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
>   			struct usb_req req = { CMD_I2C_WR, 0, 5 + msg[0].len,
>   					buf, 0, NULL };
>
> +			if (state->chip_type == 0x9306) {
> +				req.cmd = CMD_GENERIC_I2C_WR;
> +				req.wlen = 3 + msg[0].len;
> +			}
> +
>   			req.mbox |= ((msg[0].addr & 0x80)  >>  3);
>   			buf[0] = msg[0].len;
> -			buf[1] = msg[0].addr << 1;
> -			buf[2] = 0x00; /* reg addr len */
> -			buf[3] = 0x00; /* reg addr MSB */
> -			buf[4] = 0x00; /* reg addr LSB */
> -			memcpy(&buf[5], msg[0].buf, msg[0].len);
> +			if (state->chip_type == 0x9306) {
> +				buf[1] = 0x03; /* I2C bus */
> +				buf[2] = msg[0].addr << 1;
> +				memcpy(&buf[3], msg[0].buf, msg[0].len);
> +			} else {
> +				buf[1] = msg[0].addr << 1;
> +				buf[2] = 0x00; /* reg addr len */
> +				buf[3] = 0x00; /* reg addr MSB */
> +				buf[4] = 0x00; /* reg addr LSB */
> +				memcpy(&buf[5], msg[0].buf, msg[0].len);
> +			}
>   			ret = af9035_ctrl_msg(d, &req);
>   		}
>   	} else if (AF9035_IS_I2C_XFER_READ(msg, num)) {
> @@ -397,13 +425,23 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
>   			/* I2C read */
>   			u8 buf[5];
>   			struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
> -					buf, msg[0].len, msg[0].buf };
> +						buf, msg[0].len, msg[0].buf };
> +
> +			if (state->chip_type == 0x9306) {
> +				req.cmd = CMD_GENERIC_I2C_RD;
> +				req.wlen = 3;
> +			}
>   			req.mbox |= ((msg[0].addr & 0x80)  >>  3);
>   			buf[0] = msg[0].len;
> -			buf[1] = msg[0].addr << 1;
> -			buf[2] = 0x00; /* reg addr len */
> -			buf[3] = 0x00; /* reg addr MSB */
> -			buf[4] = 0x00; /* reg addr LSB */
> +			if (state->chip_type == 0x9306) {
> +				buf[1] = 0x03; /* I2C bus */
> +				buf[2] = msg[0].addr << 1;
> +			} else {
> +				buf[1] = msg[0].addr << 1;
> +				buf[2] = 0x00; /* reg addr len */
> +				buf[3] = 0x00; /* reg addr MSB */
> +				buf[4] = 0x00; /* reg addr LSB */
> +			}
>   			ret = af9035_ctrl_msg(d, &req);
>   		}
>   	} else {
> @@ -465,6 +503,9 @@ static int af9035_identify_state(struct dvb_usb_device *d, const char **name)
>   		else
>   			*name = AF9035_FIRMWARE_IT9135_V1;
>   		state->eeprom_addr = EEPROM_BASE_IT9135;
> +	} else if (state->chip_type == 0x9306) {
> +		*name = AF9035_FIRMWARE_IT9303;
> +		state->eeprom_addr = EEPROM_BASE_IT9135;
>   	} else {
>   		*name = AF9035_FIRMWARE_AF9035;
>   		state->eeprom_addr = EEPROM_BASE_AF9035;
> @@ -674,7 +715,8 @@ static int af9035_download_firmware(struct dvb_usb_device *d,
>   		if (!tmp)
>   			tmp = 0x3a;
>
> -		if (state->chip_type == 0x9135) {
> +		if ((state->chip_type == 0x9135) ||
> +				(state->chip_type == 0x9306)) {
>   			ret = af9035_wr_reg(d, 0x004bfb, tmp);
>   			if (ret < 0)
>   				goto err;
> @@ -766,8 +808,16 @@ static int af9035_read_config(struct dvb_usb_device *d)
>   			dev_dbg(&d->udev->dev, "%s: no eeprom\n", __func__);
>   			goto skip_eeprom;
>   		}
> +	} else if (state->chip_type == 0x9306) {
> +		/*
> +		 * IT930x is an USB bridge, only single demod-single tuner
> +		 * configurations seen so far.
> +		 */
> +		return 0;
>   	}
>
> +
> +
>   	/* check if there is dual tuners */
>   	ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
>   	if (ret < 0)
> @@ -1111,6 +1161,41 @@ err:
>   	return ret;
>   }
>
> +static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
> +{
> +	struct state *state = adap_to_priv(adap);
> +	struct dvb_usb_device *d = adap_to_d(adap);
> +	int ret;
> +	struct si2168_config si2168_config;
> +	struct i2c_adapter *adapter;
> +
> +	dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
> +
> +	si2168_config.i2c_adapter = &adapter;
> +	si2168_config.fe = &adap->fe[0];
> +	si2168_config.ts_mode = SI2168_TS_SERIAL;
> +
> +	state->af9033_config[adap->id].fe = &adap->fe[0];
> +	state->af9033_config[adap->id].ops = &state->ops;
> +	ret = af9035_add_i2c_dev(d, "si2168", 0x67, &si2168_config,
> +				&d->i2c_adap);
> +	if (ret)
> +		goto err;
> +
> +	if (adap->fe[0] == NULL) {
> +		ret = -ENODEV;
> +		goto err;
> +	}
> +	state->i2c_adapter_demod = adapter;
> +
> +	return 0;
> +
> +err:
> +	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
> +
> +	return ret;
> +}
> +
>   static int af9035_frontend_detach(struct dvb_usb_adapter *adap)
>   {
>   	struct state *state = adap_to_priv(adap);
> @@ -1430,6 +1515,93 @@ err:
>   	return ret;
>   }
>
> +static int it930x_tuner_attach(struct dvb_usb_adapter *adap)
> +{
> +	struct state *state = adap_to_priv(adap);
> +	struct dvb_usb_device *d = adap_to_d(adap);
> +	int ret;
> +	struct si2157_config si2157_config;
> +
> +	dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
> +
> +	/* I2C master bus 2 clock speed 300k */
> +	ret = af9035_wr_reg(d, 0x00f6a7, 0x07);
> +	if (ret < 0)
> +		goto err;
> +
> +	/* I2C master bus 1,3 clock speed 300k */
> +	ret = af9035_wr_reg(d, 0x00f103, 0x07);
> +	if (ret < 0)
> +		goto err;
> +
> +	/* set gpio11 low */
> +	ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01);
> +	if (ret < 0)
> +		goto err;
> +
> +	ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01);
> +	if (ret < 0)
> +		goto err;
> +
> +	ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01);
> +	if (ret < 0)
> +		goto err;
> +
> +	/* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */
> +	ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01);
> +	if (ret < 0)
> +		goto err;
> +
> +	ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01);
> +	if (ret < 0)
> +		goto err;
> +
> +	ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01);
> +	if (ret < 0)
> +		goto err;
> +
> +	msleep(200);
> +
> +	ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01);
> +	if (ret < 0)
> +		goto err;
> +
> +	memset(&si2157_config, 0, sizeof(si2157_config));
> +	si2157_config.fe = adap->fe[0];
> +	ret = af9035_add_i2c_dev(d, "si2157", 0x63,
> +			&si2157_config, state->i2c_adapter_demod);
> +
> +	if (ret)
> +		goto err;
> +
> +	return 0;
> +
> +err:
> +	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
> +
> +	return ret;
> +}
> +
> +
> +static int it930x_tuner_detach(struct dvb_usb_adapter *adap)
> +{
> +	struct state *state = adap_to_priv(adap);
> +	struct dvb_usb_device *d = adap_to_d(adap);
> +
> +	dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
> +
> +	if (adap->id == 1) {
> +		if (state->i2c_client[3])
> +			af9035_del_i2c_dev(d);
> +	} else if (adap->id == 0) {
> +		if (state->i2c_client[1])
> +			af9035_del_i2c_dev(d);
> +	}
> +
> +	return 0;
> +}
> +
> +
>   static int af9035_tuner_detach(struct dvb_usb_adapter *adap)
>   {
>   	struct state *state = adap_to_priv(adap);
> @@ -1503,6 +1675,89 @@ err:
>   	return ret;
>   }
>
> +static int it930x_init(struct dvb_usb_device *d)
> +{
> +	struct state *state = d_to_priv(d);
> +	int ret, i;
> +	u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 816) * 188 / 4;
> +	u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) / 4;
> +	struct reg_val_mask tab[] = {
> +		{ 0x00da1a, 0x00, 0x01 }, /* ignore_sync_byte */
> +		{ 0x00f41f, 0x04, 0x04 }, /* dvbt_inten */
> +		{ 0x00da10, 0x00, 0x01 }, /* mpeg_full_speed */
> +		{ 0x00f41a, 0x01, 0x01 }, /* dvbt_en */
> +		{ 0x00da1d, 0x01, 0x01 }, /* mp2_sw_rst, reset EP4 */
> +		{ 0x00dd11, 0x00, 0x20 }, /* ep4_tx_en, disable EP4 */
> +		{ 0x00dd13, 0x00, 0x20 }, /* ep4_tx_nak, disable EP4 NAK */
> +		{ 0x00dd11, 0x20, 0x20 }, /* ep4_tx_en, enable EP4 */
> +		{ 0x00dd11, 0x00, 0x40 }, /* ep5_tx_en, disable EP5 */
> +		{ 0x00dd13, 0x00, 0x40 }, /* ep5_tx_nak, disable EP5 NAK */
> +		{ 0x00dd11, state->dual_mode << 6, 0x40 }, /* enable EP5 */
> +		{ 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
> +		{ 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
> +		{ 0x00dd0c, packet_size, 0xff},
> +		{ 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
> +		{ 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
> +		{ 0x00dd0d, packet_size, 0xff },
> +		{ 0x00da1d, 0x00, 0x01 }, /* mp2_sw_rst, disable */
> +		{ 0x00d833, 0x01, 0xff }, /* slew rate ctrl: slew rate boosts */
> +		{ 0x00d830, 0x00, 0xff }, /* Bit 0 of output driving control */
> +		{ 0x00d831, 0x01, 0xff }, /* Bit 1 of output driving control */
> +		{ 0x00d832, 0x00, 0xff }, /* Bit 2 of output driving control */
> +
> +		/* suspend gpio1 for TS-C */
> +		{ 0x00d8b0, 0x01, 0xff }, /* gpio1 */
> +		{ 0x00d8b1, 0x01, 0xff }, /* gpio1 */
> +		{ 0x00d8af, 0x00, 0xff }, /* gpio1 */
> +
> +		/* suspend gpio7 for TS-D */
> +		{ 0x00d8c4, 0x01, 0xff }, /* gpio7 */
> +		{ 0x00d8c5, 0x01, 0xff }, /* gpio7 */
> +		{ 0x00d8c3, 0x00, 0xff }, /* gpio7 */
> +
> +		/* suspend gpio13 for TS-B */
> +		{ 0x00d8dc, 0x01, 0xff }, /* gpio13 */
> +		{ 0x00d8dd, 0x01, 0xff }, /* gpio13 */
> +		{ 0x00d8db, 0x00, 0xff }, /* gpio13 */
> +
> +		/* suspend gpio14 for TS-E */
> +		{ 0x00d8e4, 0x01, 0xff }, /* gpio14 */
> +		{ 0x00d8e5, 0x01, 0xff }, /* gpio14 */
> +		{ 0x00d8e3, 0x00, 0xff }, /* gpio14 */
> +
> +		/* suspend gpio15 for TS-A */
> +		{ 0x00d8e8, 0x01, 0xff }, /* gpio15 */
> +		{ 0x00d8e9, 0x01, 0xff }, /* gpio15 */
> +		{ 0x00d8e7, 0x00, 0xff }, /* gpio15 */
> +
> +		{ 0x00da58, 0x00, 0x01 }, /* ts_in_src, serial */
> +		{ 0x00da73, 0x01, 0xff }, /* ts0_aggre_mode */
> +		{ 0x00da78, 0x47, 0xff }, /* ts0_sync_byte */
> +		{ 0x00da4c, 0x01, 0xff }, /* ts0_en */
> +		{ 0x00da5a, 0x1f, 0xff }, /* ts_fail_ignore */
> +	};
> +
> +	dev_dbg(&d->udev->dev,
> +			"%s: USB speed=%d frame_size=%04x packet_size=%02x\n",
> +			__func__, d->udev->speed, frame_size, packet_size);
> +
> +	/* init endpoints */
> +	for (i = 0; i < ARRAY_SIZE(tab); i++) {
> +		ret = af9035_wr_reg_mask(d, tab[i].reg,
> +				tab[i].val, tab[i].mask);
> +
> +		if (ret < 0)
> +			goto err;
> +	}
> +
> +	return 0;
> +err:
> +	dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
> +
> +	return ret;
> +}
> +
> +
>   #if IS_ENABLED(CONFIG_RC_CORE)
>   static int af9035_rc_query(struct dvb_usb_device *d)
>   {
> @@ -1706,6 +1961,37 @@ static const struct dvb_usb_device_properties af9035_props = {
>   	},
>   };
>
> +static const struct dvb_usb_device_properties it930x_props = {
> +	.driver_name = KBUILD_MODNAME,
> +	.owner = THIS_MODULE,
> +	.adapter_nr = adapter_nr,
> +	.size_of_priv = sizeof(struct state),
> +
> +	.generic_bulk_ctrl_endpoint = 0x02,
> +	.generic_bulk_ctrl_endpoint_response = 0x81,
> +
> +	.identify_state = af9035_identify_state,
> +	.download_firmware = af9035_download_firmware,
> +
> +	.i2c_algo = &af9035_i2c_algo,
> +	.read_config = af9035_read_config,
> +	.frontend_attach = it930x_frontend_attach,
> +	.frontend_detach = af9035_frontend_detach,
> +	.tuner_attach = it930x_tuner_attach,
> +	.tuner_detach = it930x_tuner_detach,
> +	.init = it930x_init,
> +	.get_stream_config = af9035_get_stream_config,
> +
> +	.get_adapter_count = af9035_get_adapter_count,
> +	.adapter = {
> +		{
> +			.stream = DVB_USB_STREAM_BULK(0x84, 4, 816 * 188),
> +		}, {
> +			.stream = DVB_USB_STREAM_BULK(0x85, 4, 816 * 188),
> +		},
> +	},
> +};
> +
>   static const struct usb_device_id af9035_id_table[] = {
>   	/* AF9035 devices */
>   	{ DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
> @@ -1759,6 +2045,9 @@ static const struct usb_device_id af9035_id_table[] = {
>   	{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
>   		&af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2",
>   							RC_MAP_IT913X_V1) },
> +	/* IT930x devices */
> +	{ DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303,
> +		&it930x_props, "ITE 9303 Generic", NULL) },
>   	/* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
>   	{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
>   		&af9035_props, "TerraTec Cinergy T Stick Dual RC (rev. 2)",
> @@ -1795,3 +2084,4 @@ MODULE_LICENSE("GPL");
>   MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035);
>   MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1);
>   MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2);
> +MODULE_FIRMWARE(AF9035_FIRMWARE_IT9303);
> diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h
> index edb3871..416a97f 100644
> --- a/drivers/media/usb/dvb-usb-v2/af9035.h
> +++ b/drivers/media/usb/dvb-usb-v2/af9035.h
> @@ -31,6 +31,8 @@
>   #include "tda18218.h"
>   #include "fc2580.h"
>   #include "it913x.h"
> +#include "si2168.h"
> +#include "si2157.h"
>
>   struct reg_val {
>   	u32 reg;
> @@ -66,6 +68,7 @@ struct state {
>   	struct af9033_ops ops;
>   	#define AF9035_I2C_CLIENT_MAX 4
>   	struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX];
> +	struct i2c_adapter *i2c_adapter_demod;
>   };
>
>   static const u32 clock_lut_af9035[] = {
> @@ -99,6 +102,7 @@ static const u32 clock_lut_it9135[] = {
>   #define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw"
>   #define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw"
>   #define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw"
> +#define AF9035_FIRMWARE_IT9303 "dvb-usb-it9303-01.fw"
>
>   /*
>    * eeprom is memory mapped as read only. Writing that memory mapped address
> @@ -140,5 +144,7 @@ static const u32 clock_lut_it9135[] = {
>   #define CMD_FW_DL_BEGIN             0x24
>   #define CMD_FW_DL_END               0x25
>   #define CMD_FW_SCATTER_WR           0x29
> +#define CMD_GENERIC_I2C_RD          0x2a
> +#define CMD_GENERIC_I2C_WR          0x2b
>
>   #endif
>

-- 
http://palosaari.fi/

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/3] af9035: Add support for IT930x USB bridge
  2014-09-23 12:46   ` Antti Palosaari
@ 2014-09-23 13:25     ` Olli Salonen
  0 siblings, 0 replies; 8+ messages in thread
From: Olli Salonen @ 2014-09-23 13:25 UTC (permalink / raw)
  To: Linux Media Mailing List

Hi Antti,

Thanks for the review. I agree that the I2C xfer does not look too
elegant at the moment. Maybe it could be worth investigating if same
methods could be used for all these devices. Alternatively I could
have created another function for I2C xfer using the I2C_GENERIC_RD
and WR commands, but then again the differences were so small...

Would you suggest to move the non-endpoint related registers somewhere
else from the init function? I just reused that as it was
convenient... Tuner attach?

Cheers,
-olli

On 23 September 2014 15:46, Antti Palosaari <crope@iki.fi> wrote:
> Acked-by: Antti Palosaari <crope@iki.fi>
> Reviewed-by: Antti Palosaari <crope@iki.fi>
>
> Changes were a bit complicated, but I understood those in general and there
> is nothing wrong for my eyes. Mostly I was surprised of new implementation
> of init() (init is mainly for configuring TS interfaces).
>
> Also I2C adapter xfer goes pretty complex, but that is because there is
> actually 3 I2C adapters and some of those even offer multiple access methods
> by firmware. Maybe there is also room for later improvement.
>
> But as I said, patch it is OK.
>
> regards
> Antti
>
>
> On 09/21/2014 01:53 PM, Olli Salonen wrote:
>>
>> Add support for IT930x USB bridge and IT9303 reference design.
>>
>> It is a DVB-T/T2/C tuner with the following components:
>> - IT9303 USB bridge
>> - Si2168-B40 demodulator
>> - Si2147-A30 tuner
>>
>> The IT9303 requires firmware that can be downloaded here:
>> http://trsqr.net/olli/linux/firmwares/it930x/
>>
>> The Si2168-B40 requires firmware, but the one that is used by PCTV 292e
>> can be used.
>> http://palosaari.fi/linux/v4l-dvb/firmware/Si2168/Si2168-B40/
>>
>> The Si2147-A30 tuner does not require firmware loading.
>>
>> Cc: crope@iki.fi
>> Signed-off-by: Olli Salonen <olli.salonen@iki.fi>
>> ---
>>   drivers/media/dvb-core/dvb-usb-ids.h  |   1 +
>>   drivers/media/usb/dvb-usb-v2/af9035.c | 324
>> ++++++++++++++++++++++++++++++++--
>>   drivers/media/usb/dvb-usb-v2/af9035.h |   6 +
>>   3 files changed, 314 insertions(+), 17 deletions(-)
>>
>> diff --git a/drivers/media/dvb-core/dvb-usb-ids.h
>> b/drivers/media/dvb-core/dvb-usb-ids.h
>> index d484a51..e07a84e 100644
>> --- a/drivers/media/dvb-core/dvb-usb-ids.h
>> +++ b/drivers/media/dvb-core/dvb-usb-ids.h
>> @@ -144,6 +144,7 @@
>>   #define USB_PID_ITETECH_IT9135                                0x9135
>>   #define USB_PID_ITETECH_IT9135_9005                   0x9005
>>   #define USB_PID_ITETECH_IT9135_9006                   0x9006
>> +#define USB_PID_ITETECH_IT9303                         0x9306
>>   #define USB_PID_KWORLD_399U                           0xe399
>>   #define USB_PID_KWORLD_399U_2                         0xe400
>>   #define USB_PID_KWORLD_395U                           0xe396
>> diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c
>> b/drivers/media/usb/dvb-usb-v2/af9035.c
>> index c50d27d..00758c8 100644
>> --- a/drivers/media/usb/dvb-usb-v2/af9035.c
>> +++ b/drivers/media/usb/dvb-usb-v2/af9035.c
>> @@ -290,7 +290,7 @@ static int af9035_i2c_master_xfer(struct i2c_adapter
>> *adap,
>>                 return -EAGAIN;
>>
>>         /*
>> -        * I2C sub header is 5 bytes long. Meaning of those bytes are:
>> +        * AF9035 I2C sub header is 5 bytes long. Meaning of those bytes
>> are:
>>          * 0: data len
>>          * 1: I2C addr << 1
>>          * 2: reg addr len
>> @@ -317,6 +317,12 @@ static int af9035_i2c_master_xfer(struct i2c_adapter
>> *adap,
>>          * bus. I2C subsystem does not allow register multiple devices to
>> same
>>          * bus, having same slave address. Due to that we reuse demod
>> address,
>>          * shifted by one bit, on that case.
>> +        *
>> +        * For IT930x we use a different command and the sub header is
>> +        * different as well:
>> +        * 0: data len
>> +        * 1: I2C bus (0x03 seems to be only value used)
>> +        * 2: I2C addr << 1
>>          */
>>   #define AF9035_IS_I2C_XFER_WRITE_READ(_msg, _num) \
>>         (_num == 2 && !(_msg[0].flags & I2C_M_RD) && (_msg[1].flags &
>> I2C_M_RD))
>> @@ -348,13 +354,24 @@ static int af9035_i2c_master_xfer(struct i2c_adapter
>> *adap,
>>                         struct usb_req req = { CMD_I2C_RD, 0, 5 +
>> msg[0].len,
>>                                         buf, msg[1].len, msg[1].buf };
>>
>> +                       if (state->chip_type == 0x9306) {
>> +                               req.cmd = CMD_GENERIC_I2C_RD;
>> +                               req.wlen = 3 + msg[0].len;
>> +                       }
>>                         req.mbox |= ((msg[0].addr & 0x80)  >>  3);
>> +
>>                         buf[0] = msg[1].len;
>> -                       buf[1] = msg[0].addr << 1;
>> -                       buf[2] = 0x00; /* reg addr len */
>> -                       buf[3] = 0x00; /* reg addr MSB */
>> -                       buf[4] = 0x00; /* reg addr LSB */
>> -                       memcpy(&buf[5], msg[0].buf, msg[0].len);
>> +                       if (state->chip_type == 0x9306) {
>> +                               buf[1] = 0x03; /* I2C bus */
>> +                               buf[2] = msg[0].addr << 1;
>> +                               memcpy(&buf[3], msg[0].buf, msg[0].len);
>> +                       } else {
>> +                               buf[1] = msg[0].addr << 1;
>> +                               buf[2] = 0x00; /* reg addr len */
>> +                               buf[3] = 0x00; /* reg addr MSB */
>> +                               buf[4] = 0x00; /* reg addr LSB */
>> +                               memcpy(&buf[5], msg[0].buf, msg[0].len);
>> +                       }
>>                         ret = af9035_ctrl_msg(d, &req);
>>                 }
>>         } else if (AF9035_IS_I2C_XFER_WRITE(msg, num)) {
>> @@ -380,13 +397,24 @@ static int af9035_i2c_master_xfer(struct i2c_adapter
>> *adap,
>>                         struct usb_req req = { CMD_I2C_WR, 0, 5 +
>> msg[0].len,
>>                                         buf, 0, NULL };
>>
>> +                       if (state->chip_type == 0x9306) {
>> +                               req.cmd = CMD_GENERIC_I2C_WR;
>> +                               req.wlen = 3 + msg[0].len;
>> +                       }
>> +
>>                         req.mbox |= ((msg[0].addr & 0x80)  >>  3);
>>                         buf[0] = msg[0].len;
>> -                       buf[1] = msg[0].addr << 1;
>> -                       buf[2] = 0x00; /* reg addr len */
>> -                       buf[3] = 0x00; /* reg addr MSB */
>> -                       buf[4] = 0x00; /* reg addr LSB */
>> -                       memcpy(&buf[5], msg[0].buf, msg[0].len);
>> +                       if (state->chip_type == 0x9306) {
>> +                               buf[1] = 0x03; /* I2C bus */
>> +                               buf[2] = msg[0].addr << 1;
>> +                               memcpy(&buf[3], msg[0].buf, msg[0].len);
>> +                       } else {
>> +                               buf[1] = msg[0].addr << 1;
>> +                               buf[2] = 0x00; /* reg addr len */
>> +                               buf[3] = 0x00; /* reg addr MSB */
>> +                               buf[4] = 0x00; /* reg addr LSB */
>> +                               memcpy(&buf[5], msg[0].buf, msg[0].len);
>> +                       }
>>                         ret = af9035_ctrl_msg(d, &req);
>>                 }
>>         } else if (AF9035_IS_I2C_XFER_READ(msg, num)) {
>> @@ -397,13 +425,23 @@ static int af9035_i2c_master_xfer(struct i2c_adapter
>> *adap,
>>                         /* I2C read */
>>                         u8 buf[5];
>>                         struct usb_req req = { CMD_I2C_RD, 0, sizeof(buf),
>> -                                       buf, msg[0].len, msg[0].buf };
>> +                                               buf, msg[0].len,
>> msg[0].buf };
>> +
>> +                       if (state->chip_type == 0x9306) {
>> +                               req.cmd = CMD_GENERIC_I2C_RD;
>> +                               req.wlen = 3;
>> +                       }
>>                         req.mbox |= ((msg[0].addr & 0x80)  >>  3);
>>                         buf[0] = msg[0].len;
>> -                       buf[1] = msg[0].addr << 1;
>> -                       buf[2] = 0x00; /* reg addr len */
>> -                       buf[3] = 0x00; /* reg addr MSB */
>> -                       buf[4] = 0x00; /* reg addr LSB */
>> +                       if (state->chip_type == 0x9306) {
>> +                               buf[1] = 0x03; /* I2C bus */
>> +                               buf[2] = msg[0].addr << 1;
>> +                       } else {
>> +                               buf[1] = msg[0].addr << 1;
>> +                               buf[2] = 0x00; /* reg addr len */
>> +                               buf[3] = 0x00; /* reg addr MSB */
>> +                               buf[4] = 0x00; /* reg addr LSB */
>> +                       }
>>                         ret = af9035_ctrl_msg(d, &req);
>>                 }
>>         } else {
>> @@ -465,6 +503,9 @@ static int af9035_identify_state(struct dvb_usb_device
>> *d, const char **name)
>>                 else
>>                         *name = AF9035_FIRMWARE_IT9135_V1;
>>                 state->eeprom_addr = EEPROM_BASE_IT9135;
>> +       } else if (state->chip_type == 0x9306) {
>> +               *name = AF9035_FIRMWARE_IT9303;
>> +               state->eeprom_addr = EEPROM_BASE_IT9135;
>>         } else {
>>                 *name = AF9035_FIRMWARE_AF9035;
>>                 state->eeprom_addr = EEPROM_BASE_AF9035;
>> @@ -674,7 +715,8 @@ static int af9035_download_firmware(struct
>> dvb_usb_device *d,
>>                 if (!tmp)
>>                         tmp = 0x3a;
>>
>> -               if (state->chip_type == 0x9135) {
>> +               if ((state->chip_type == 0x9135) ||
>> +                               (state->chip_type == 0x9306)) {
>>                         ret = af9035_wr_reg(d, 0x004bfb, tmp);
>>                         if (ret < 0)
>>                                 goto err;
>> @@ -766,8 +808,16 @@ static int af9035_read_config(struct dvb_usb_device
>> *d)
>>                         dev_dbg(&d->udev->dev, "%s: no eeprom\n",
>> __func__);
>>                         goto skip_eeprom;
>>                 }
>> +       } else if (state->chip_type == 0x9306) {
>> +               /*
>> +                * IT930x is an USB bridge, only single demod-single tuner
>> +                * configurations seen so far.
>> +                */
>> +               return 0;
>>         }
>>
>> +
>> +
>>         /* check if there is dual tuners */
>>         ret = af9035_rd_reg(d, state->eeprom_addr + EEPROM_TS_MODE, &tmp);
>>         if (ret < 0)
>> @@ -1111,6 +1161,41 @@ err:
>>         return ret;
>>   }
>>
>> +static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
>> +{
>> +       struct state *state = adap_to_priv(adap);
>> +       struct dvb_usb_device *d = adap_to_d(adap);
>> +       int ret;
>> +       struct si2168_config si2168_config;
>> +       struct i2c_adapter *adapter;
>> +
>> +       dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
>> +
>> +       si2168_config.i2c_adapter = &adapter;
>> +       si2168_config.fe = &adap->fe[0];
>> +       si2168_config.ts_mode = SI2168_TS_SERIAL;
>> +
>> +       state->af9033_config[adap->id].fe = &adap->fe[0];
>> +       state->af9033_config[adap->id].ops = &state->ops;
>> +       ret = af9035_add_i2c_dev(d, "si2168", 0x67, &si2168_config,
>> +                               &d->i2c_adap);
>> +       if (ret)
>> +               goto err;
>> +
>> +       if (adap->fe[0] == NULL) {
>> +               ret = -ENODEV;
>> +               goto err;
>> +       }
>> +       state->i2c_adapter_demod = adapter;
>> +
>> +       return 0;
>> +
>> +err:
>> +       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
>> +
>> +       return ret;
>> +}
>> +
>>   static int af9035_frontend_detach(struct dvb_usb_adapter *adap)
>>   {
>>         struct state *state = adap_to_priv(adap);
>> @@ -1430,6 +1515,93 @@ err:
>>         return ret;
>>   }
>>
>> +static int it930x_tuner_attach(struct dvb_usb_adapter *adap)
>> +{
>> +       struct state *state = adap_to_priv(adap);
>> +       struct dvb_usb_device *d = adap_to_d(adap);
>> +       int ret;
>> +       struct si2157_config si2157_config;
>> +
>> +       dev_dbg(&d->udev->dev, "%s: adap->id=%d\n", __func__, adap->id);
>> +
>> +       /* I2C master bus 2 clock speed 300k */
>> +       ret = af9035_wr_reg(d, 0x00f6a7, 0x07);
>> +       if (ret < 0)
>> +               goto err;
>> +
>> +       /* I2C master bus 1,3 clock speed 300k */
>> +       ret = af9035_wr_reg(d, 0x00f103, 0x07);
>> +       if (ret < 0)
>> +               goto err;
>> +
>> +       /* set gpio11 low */
>> +       ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01);
>> +       if (ret < 0)
>> +               goto err;
>> +
>> +       ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01);
>> +       if (ret < 0)
>> +               goto err;
>> +
>> +       ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01);
>> +       if (ret < 0)
>> +               goto err;
>> +
>> +       /* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */
>> +       ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01);
>> +       if (ret < 0)
>> +               goto err;
>> +
>> +       ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01);
>> +       if (ret < 0)
>> +               goto err;
>> +
>> +       ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01);
>> +       if (ret < 0)
>> +               goto err;
>> +
>> +       msleep(200);
>> +
>> +       ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01);
>> +       if (ret < 0)
>> +               goto err;
>> +
>> +       memset(&si2157_config, 0, sizeof(si2157_config));
>> +       si2157_config.fe = adap->fe[0];
>> +       ret = af9035_add_i2c_dev(d, "si2157", 0x63,
>> +                       &si2157_config, state->i2c_adapter_demod);
>> +
>> +       if (ret)
>> +               goto err;
>> +
>> +       return 0;
>> +
>> +err:
>> +       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
>> +
>> +       return ret;
>> +}
>> +
>> +
>> +static int it930x_tuner_detach(struct dvb_usb_adapter *adap)
>> +{
>> +       struct state *state = adap_to_priv(adap);
>> +       struct dvb_usb_device *d = adap_to_d(adap);
>> +
>> +       dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
>> +
>> +       if (adap->id == 1) {
>> +               if (state->i2c_client[3])
>> +                       af9035_del_i2c_dev(d);
>> +       } else if (adap->id == 0) {
>> +               if (state->i2c_client[1])
>> +                       af9035_del_i2c_dev(d);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +
>>   static int af9035_tuner_detach(struct dvb_usb_adapter *adap)
>>   {
>>         struct state *state = adap_to_priv(adap);
>> @@ -1503,6 +1675,89 @@ err:
>>         return ret;
>>   }
>>
>> +static int it930x_init(struct dvb_usb_device *d)
>> +{
>> +       struct state *state = d_to_priv(d);
>> +       int ret, i;
>> +       u16 frame_size = (d->udev->speed == USB_SPEED_FULL ? 5 : 816) *
>> 188 / 4;
>> +       u8 packet_size = (d->udev->speed == USB_SPEED_FULL ? 64 : 512) /
>> 4;
>> +       struct reg_val_mask tab[] = {
>> +               { 0x00da1a, 0x00, 0x01 }, /* ignore_sync_byte */
>> +               { 0x00f41f, 0x04, 0x04 }, /* dvbt_inten */
>> +               { 0x00da10, 0x00, 0x01 }, /* mpeg_full_speed */
>> +               { 0x00f41a, 0x01, 0x01 }, /* dvbt_en */
>> +               { 0x00da1d, 0x01, 0x01 }, /* mp2_sw_rst, reset EP4 */
>> +               { 0x00dd11, 0x00, 0x20 }, /* ep4_tx_en, disable EP4 */
>> +               { 0x00dd13, 0x00, 0x20 }, /* ep4_tx_nak, disable EP4 NAK
>> */
>> +               { 0x00dd11, 0x20, 0x20 }, /* ep4_tx_en, enable EP4 */
>> +               { 0x00dd11, 0x00, 0x40 }, /* ep5_tx_en, disable EP5 */
>> +               { 0x00dd13, 0x00, 0x40 }, /* ep5_tx_nak, disable EP5 NAK
>> */
>> +               { 0x00dd11, state->dual_mode << 6, 0x40 }, /* enable EP5
>> */
>> +               { 0x00dd88, (frame_size >> 0) & 0xff, 0xff},
>> +               { 0x00dd89, (frame_size >> 8) & 0xff, 0xff},
>> +               { 0x00dd0c, packet_size, 0xff},
>> +               { 0x00dd8a, (frame_size >> 0) & 0xff, 0xff},
>> +               { 0x00dd8b, (frame_size >> 8) & 0xff, 0xff},
>> +               { 0x00dd0d, packet_size, 0xff },
>> +               { 0x00da1d, 0x00, 0x01 }, /* mp2_sw_rst, disable */
>> +               { 0x00d833, 0x01, 0xff }, /* slew rate ctrl: slew rate
>> boosts */
>> +               { 0x00d830, 0x00, 0xff }, /* Bit 0 of output driving
>> control */
>> +               { 0x00d831, 0x01, 0xff }, /* Bit 1 of output driving
>> control */
>> +               { 0x00d832, 0x00, 0xff }, /* Bit 2 of output driving
>> control */
>> +
>> +               /* suspend gpio1 for TS-C */
>> +               { 0x00d8b0, 0x01, 0xff }, /* gpio1 */
>> +               { 0x00d8b1, 0x01, 0xff }, /* gpio1 */
>> +               { 0x00d8af, 0x00, 0xff }, /* gpio1 */
>> +
>> +               /* suspend gpio7 for TS-D */
>> +               { 0x00d8c4, 0x01, 0xff }, /* gpio7 */
>> +               { 0x00d8c5, 0x01, 0xff }, /* gpio7 */
>> +               { 0x00d8c3, 0x00, 0xff }, /* gpio7 */
>> +
>> +               /* suspend gpio13 for TS-B */
>> +               { 0x00d8dc, 0x01, 0xff }, /* gpio13 */
>> +               { 0x00d8dd, 0x01, 0xff }, /* gpio13 */
>> +               { 0x00d8db, 0x00, 0xff }, /* gpio13 */
>> +
>> +               /* suspend gpio14 for TS-E */
>> +               { 0x00d8e4, 0x01, 0xff }, /* gpio14 */
>> +               { 0x00d8e5, 0x01, 0xff }, /* gpio14 */
>> +               { 0x00d8e3, 0x00, 0xff }, /* gpio14 */
>> +
>> +               /* suspend gpio15 for TS-A */
>> +               { 0x00d8e8, 0x01, 0xff }, /* gpio15 */
>> +               { 0x00d8e9, 0x01, 0xff }, /* gpio15 */
>> +               { 0x00d8e7, 0x00, 0xff }, /* gpio15 */
>> +
>> +               { 0x00da58, 0x00, 0x01 }, /* ts_in_src, serial */
>> +               { 0x00da73, 0x01, 0xff }, /* ts0_aggre_mode */
>> +               { 0x00da78, 0x47, 0xff }, /* ts0_sync_byte */
>> +               { 0x00da4c, 0x01, 0xff }, /* ts0_en */
>> +               { 0x00da5a, 0x1f, 0xff }, /* ts_fail_ignore */
>> +       };
>> +
>> +       dev_dbg(&d->udev->dev,
>> +                       "%s: USB speed=%d frame_size=%04x
>> packet_size=%02x\n",
>> +                       __func__, d->udev->speed, frame_size,
>> packet_size);
>> +
>> +       /* init endpoints */
>> +       for (i = 0; i < ARRAY_SIZE(tab); i++) {
>> +               ret = af9035_wr_reg_mask(d, tab[i].reg,
>> +                               tab[i].val, tab[i].mask);
>> +
>> +               if (ret < 0)
>> +                       goto err;
>> +       }
>> +
>> +       return 0;
>> +err:
>> +       dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
>> +
>> +       return ret;
>> +}
>> +
>> +
>>   #if IS_ENABLED(CONFIG_RC_CORE)
>>   static int af9035_rc_query(struct dvb_usb_device *d)
>>   {
>> @@ -1706,6 +1961,37 @@ static const struct dvb_usb_device_properties
>> af9035_props = {
>>         },
>>   };
>>
>> +static const struct dvb_usb_device_properties it930x_props = {
>> +       .driver_name = KBUILD_MODNAME,
>> +       .owner = THIS_MODULE,
>> +       .adapter_nr = adapter_nr,
>> +       .size_of_priv = sizeof(struct state),
>> +
>> +       .generic_bulk_ctrl_endpoint = 0x02,
>> +       .generic_bulk_ctrl_endpoint_response = 0x81,
>> +
>> +       .identify_state = af9035_identify_state,
>> +       .download_firmware = af9035_download_firmware,
>> +
>> +       .i2c_algo = &af9035_i2c_algo,
>> +       .read_config = af9035_read_config,
>> +       .frontend_attach = it930x_frontend_attach,
>> +       .frontend_detach = af9035_frontend_detach,
>> +       .tuner_attach = it930x_tuner_attach,
>> +       .tuner_detach = it930x_tuner_detach,
>> +       .init = it930x_init,
>> +       .get_stream_config = af9035_get_stream_config,
>> +
>> +       .get_adapter_count = af9035_get_adapter_count,
>> +       .adapter = {
>> +               {
>> +                       .stream = DVB_USB_STREAM_BULK(0x84, 4, 816 * 188),
>> +               }, {
>> +                       .stream = DVB_USB_STREAM_BULK(0x85, 4, 816 * 188),
>> +               },
>> +       },
>> +};
>> +
>>   static const struct usb_device_id af9035_id_table[] = {
>>         /* AF9035 devices */
>>         { DVB_USB_DEVICE(USB_VID_AFATECH, USB_PID_AFATECH_AF9035_9035,
>> @@ -1759,6 +2045,9 @@ static const struct usb_device_id af9035_id_table[]
>> = {
>>         { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
>>                 &af9035_props, "Digital Dual TV Receiver CTVDIGDUAL_V2",
>>                                                         RC_MAP_IT913X_V1)
>> },
>> +       /* IT930x devices */
>> +       { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303,
>> +               &it930x_props, "ITE 9303 Generic", NULL) },
>>         /* XXX: that same ID [0ccd:0099] is used by af9015 driver too */
>>         { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x0099,
>>                 &af9035_props, "TerraTec Cinergy T Stick Dual RC (rev.
>> 2)",
>> @@ -1795,3 +2084,4 @@ MODULE_LICENSE("GPL");
>>   MODULE_FIRMWARE(AF9035_FIRMWARE_AF9035);
>>   MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V1);
>>   MODULE_FIRMWARE(AF9035_FIRMWARE_IT9135_V2);
>> +MODULE_FIRMWARE(AF9035_FIRMWARE_IT9303);
>> diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h
>> b/drivers/media/usb/dvb-usb-v2/af9035.h
>> index edb3871..416a97f 100644
>> --- a/drivers/media/usb/dvb-usb-v2/af9035.h
>> +++ b/drivers/media/usb/dvb-usb-v2/af9035.h
>> @@ -31,6 +31,8 @@
>>   #include "tda18218.h"
>>   #include "fc2580.h"
>>   #include "it913x.h"
>> +#include "si2168.h"
>> +#include "si2157.h"
>>
>>   struct reg_val {
>>         u32 reg;
>> @@ -66,6 +68,7 @@ struct state {
>>         struct af9033_ops ops;
>>         #define AF9035_I2C_CLIENT_MAX 4
>>         struct i2c_client *i2c_client[AF9035_I2C_CLIENT_MAX];
>> +       struct i2c_adapter *i2c_adapter_demod;
>>   };
>>
>>   static const u32 clock_lut_af9035[] = {
>> @@ -99,6 +102,7 @@ static const u32 clock_lut_it9135[] = {
>>   #define AF9035_FIRMWARE_AF9035 "dvb-usb-af9035-02.fw"
>>   #define AF9035_FIRMWARE_IT9135_V1 "dvb-usb-it9135-01.fw"
>>   #define AF9035_FIRMWARE_IT9135_V2 "dvb-usb-it9135-02.fw"
>> +#define AF9035_FIRMWARE_IT9303 "dvb-usb-it9303-01.fw"
>>
>>   /*
>>    * eeprom is memory mapped as read only. Writing that memory mapped
>> address
>> @@ -140,5 +144,7 @@ static const u32 clock_lut_it9135[] = {
>>   #define CMD_FW_DL_BEGIN             0x24
>>   #define CMD_FW_DL_END               0x25
>>   #define CMD_FW_SCATTER_WR           0x29
>> +#define CMD_GENERIC_I2C_RD          0x2a
>> +#define CMD_GENERIC_I2C_WR          0x2b
>>
>>   #endif
>>
>
> --
> http://palosaari.fi/

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-09-23 13:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-21 10:53 [PATCH 0/3] IT930x USB DVB-T2/C tuner Olli Salonen
2014-09-21 10:53 ` [PATCH 1/3] si2157: Add support for Si2147-A30 Olli Salonen
2014-09-23 12:36   ` Antti Palosaari
2014-09-21 10:53 ` [PATCH 2/3] af9035: Add possibility to define which I2C adapter to use Olli Salonen
2014-09-23 12:37   ` Antti Palosaari
2014-09-21 10:53 ` [PATCH 3/3] af9035: Add support for IT930x USB bridge Olli Salonen
2014-09-23 12:46   ` Antti Palosaari
2014-09-23 13:25     ` Olli Salonen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.