diff mbox

[3/3] af9035: Add support for IT930x USB bridge

Message ID 1411296799-3525-4-git-send-email-olli.salonen@iki.fi (mailing list archive)
State New, archived
Headers show

Commit Message

Olli Salonen Sept. 21, 2014, 10:53 a.m. UTC
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(-)

Comments

Antti Palosaari Sept. 23, 2014, 12:46 p.m. UTC | #1
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
>
Olli Salonen Sept. 23, 2014, 1:25 p.m. UTC | #2
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/
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

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