diff mbox series

[3/4] media: af9035: add support for Logilink VG0022A

Message ID 9618316567493f917c41109f7dba94e533fbfb4b.1570194906.git.mchehab+samsung@kernel.org (mailing list archive)
State New, archived
Headers show
Series [1/4] media: si2168: use bits instead of bool for flags | expand

Commit Message

Mauro Carvalho Chehab Oct. 4, 2019, 1:15 p.m. UTC
This it930x-based device has an issue with si2068.

When the si2168 firmware that came with the device is replaced
by a new one, any I2C data received from the tuner will be
replaced by 0xff.

Probably, the vendor firmware has some patch specifically
designed for this device. So, we can't replace by the generic
firmware.

The right solution would be to extract the si2168 firmware from
the original driver and ask the driver to load the specifically
designed firmware, but, while we don't have that, the next best
solution is to just keep the original firmware at the device.

For more details, see the discussions at:
	https://lore.kernel.org/linux-media/20191002141359.30166-2-gonsolo@gmail.com/

Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
---
 drivers/media/usb/dvb-usb-v2/af9035.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

Comments

Gon Solo Oct. 9, 2019, 9:44 p.m. UTC | #1
> This it930x-based device has an issue with si2068.
> 
> When the si2168 firmware that came with the device is replaced
> by a new one, any I2C data received from the tuner will be
> replaced by 0xff.
> 
> Probably, the vendor firmware has some patch specifically
> designed for this device. So, we can't replace by the generic
> firmware.
> 
> The right solution would be to extract the si2168 firmware from
> the original driver and ask the driver to load the specifically
> designed firmware, but, while we don't have that, the next best
> solution is to just keep the original firmware at the device.

Unfortunately, after applying these four patches it doesn't work for me.
The messages when inserting the stick:

[  244.133448] i2c i2c-1: Added multiplexed i2c bus 2
[  244.133455] si2168 1-0067: Silicon Labs Si2168-B40 successfully identified
[  244.133458] si2168 1-0067: firmware version: B 4.0.2
[  244.133500] usb 2-1: DVB: registering adapter 0 frontend 0 (Silicon Labs Si2168)...
[  244.133514] dvbdev: dvb_create_media_entity: media entity 'Silicon Labs Si2168' registered.
[  244.138367] si2157 2-0063: Silicon Labs Si2147/2148/2157/2158 successfully attached
[  244.156956] usb 2-1: dvb_usb_v2: 'Logilink VG0022A' successfully initialized and connected

The messages when starting VLC:

[  260.490253] si2157 2-0063: found a 'Silicon Labs Si2147-A30'
[  260.541347] si2157 2-0063: firmware version: 3.0.5

But it doesn't work. :(

g

> 
> For more details, see the discussions at:
> 	https://lore.kernel.org/linux-media/20191002141359.30166-2-gonsolo@gmail.com/
> 
> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
> ---
>  drivers/media/usb/dvb-usb-v2/af9035.c | 19 +++++++++++++++++++
>  1 file changed, 19 insertions(+)
> 
> diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
> index 3afd18733614..e555483c3077 100644
> --- a/drivers/media/usb/dvb-usb-v2/af9035.c
> +++ b/drivers/media/usb/dvb-usb-v2/af9035.c
> @@ -1255,6 +1255,23 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
>  	si2168_config.fe = &adap->fe[0];
>  	si2168_config.ts_mode = SI2168_TS_SERIAL;
>  
> +	/*
> +	 * HACK: The Logilink VG0022A has a bug: when the si2168
> +	 * firmware that came with the device is replaced by a new
> +	 * one, the I2C transfers to the tuner will return just 0xff.
> +	 *
> +	 * Probably, the vendor firmware has some patch specifically
> +	 * designed for this device. So, we can't replace by the
> +	 * generic firmware. The right solution would be to extract
> +	 * the si2168 firmware from the original driver and ask the
> +	 * driver to load the specifically designed firmware, but,
> +	 * while we don't have that, the next best solution is to just
> +	 * keep the original firmware at the device.
> +	 */
> +	if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_DEXATEK &&
> +	    le16_to_cpu(d->udev->descriptor.idProduct) == 0x0100)
> +		si2168_config.dont_load_firmware = true;
> +
>  	state->af9033_config[adap->id].fe = &adap->fe[0];
>  	state->af9033_config[adap->id].ops = &state->ops;
>  	ret = af9035_add_i2c_dev(d, "si2168",
> @@ -2121,6 +2138,8 @@ static const struct usb_device_id af9035_id_table[] = {
>  		&it930x_props, "ITE 9303 Generic", NULL) },
>  	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD310,
>  		&it930x_props, "AVerMedia TD310 DVB-T2", NULL) },
> +	{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x0100,
> +		&it930x_props, "Logilink VG0022A", NULL) },
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(usb, af9035_id_table);
> -- 
> 2.21.0
>
Gon Solo Oct. 9, 2019, 10:04 p.m. UTC | #2
> Unfortunately, after applying these four patches it doesn't work for me.

Your patch disables firmware loading at dvb-frontends/si2168.c:449 while
my original one disabled it at tuners/si2157.c:554:

        case SI_BOGUS:
                dev_info(&client->dev, "bogus chip version, trying with no firmware\n");
                fw_name = NULL;

According to my dmesg the following chip is found:

[  141.726488] si2157 10-0063: found a 'Silicon Labs Si2147-A30'
[  141.777647] si2157 10-0063: firmware version: 3.0.5

So according to:

        case SI2147_A30:
        case SI2146_A10:
                fw_name = NULL;

it should work. Hmmm.

g
Gon Solo Oct. 10, 2019, 8:23 a.m. UTC | #3
Hi!

I rebased Mauros patch on top of mine and this patch [3/4] is the first bad
commit. I believe these lines are the culprit:

+       if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_DEXATEK &&
+           le16_to_cpu(d->udev->descriptor.idProduct) == 0x0100)
+               si2168_config.dont_load_firmware = true;

> From: JP <jp@jpvw.nl>
> Mauro just took the wrong firmware to skip. demod instead of tuner.
> It would not be hard to fix that.

It seems so.

g
Gon Solo Oct. 10, 2019, 9:18 a.m. UTC | #4
Hi!

This patch works for me. It disables firmware downloading for the si2157
instead of the si2168.

Convert si2157 and si2168 to kernel-doc format as suggested by Mauro.
Use bits instead of bool.  Add a flag to si2157 for not loading the
firmware.  Make computation of speed register clear. Add hack for
Logilink VG0022A.

Signed-off-by: Andreas Wendleder <andreas.wendleder@gmail.com>

diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
index 50dccb394efa..ecd21adf8950 100644
--- a/drivers/media/dvb-frontends/si2168.h
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -9,38 +9,43 @@
 #define SI2168_H
 
 #include <linux/dvb/frontend.h>
-/*
- * I2C address
- * 0x64
+/**
+ * struct si2168_config - configuration parameters for si2168
+ *
+ * @fe:
+ *	frontend returned by driver
+ * @i2c_adapter:
+ *	tuner I2C adapter returned by driver
+ * @ts_mode:
+ *	Transport Stream mode. Can be:
+ *	- %SI2168_TS_PARALLEL
+ *	- %SI2168_TS_SERIAL
+ *	- %SI2168_TS_TRISTATE
+ *	- %SI2168_TS_CLK_MANUAL
+ * @ts_clock_inv:
+ *	TS clock inverted
+ * @ts_clock_gapped:
+ *	TS clock gapped
+ * @spectral_inversion:
+ *	Inverted spectrum
+ *
+ * Note:
+ *	The I2C address of this demod is 0x64.
  */
 struct si2168_config {
-	/*
-	 * frontend
-	 * returned by driver
-	 */
 	struct dvb_frontend **fe;
-
-	/*
-	 * tuner I2C adapter
-	 * returned by driver
-	 */
 	struct i2c_adapter **i2c_adapter;
 
-	/* TS mode */
 #define SI2168_TS_PARALLEL	0x06
 #define SI2168_TS_SERIAL	0x03
 #define SI2168_TS_TRISTATE	0x00
 #define SI2168_TS_CLK_MANUAL	0x20
 	u8 ts_mode;
 
-	/* TS clock inverted */
-	bool ts_clock_inv;
-
-	/* TS clock gapped */
-	bool ts_clock_gapped;
-
-	/* Inverted spectrum */
-	bool spectral_inversion;
+	/* Flags */
+	unsigned int ts_clock_inv:1;
+	unsigned int ts_clock_gapped:1;
+	unsigned int spectral_inversion:1;
 };
 
 #endif
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index 804d5b30c697..18bea5222082 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -34,12 +34,12 @@ struct si2168_dev {
 	unsigned int chip_id;
 	unsigned int version;
 	const char *firmware_name;
-	bool active;
-	bool warm;
 	u8 ts_mode;
-	bool ts_clock_inv;
-	bool ts_clock_gapped;
-	bool spectral_inversion;
+	unsigned int active:1;
+	unsigned int warm:1;
+	unsigned int ts_clock_inv:1;
+	unsigned int ts_clock_gapped:1;
+	unsigned int spectral_inversion:1;
 };
 
 /* firmware command struct */
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index e87040d6eca7..898e0f9f8b70 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -118,6 +118,11 @@ static int si2157_init(struct dvb_frontend *fe)
 			goto err;
 	}
 
+	if (dev->dont_load_firmware) {
+		dev_info(&client->dev, "device is buggy, skipping firmware download\n");
+		goto skip_fw_download;
+	}
+
 	/* query chip revision */
 	memcpy(cmd.args, "\x02", 1);
 	cmd.wlen = 1;
@@ -440,6 +445,7 @@ static int si2157_probe(struct i2c_client *client,
 	i2c_set_clientdata(client, dev);
 	dev->fe = cfg->fe;
 	dev->inversion = cfg->inversion;
+	dev->dont_load_firmware = cfg->dont_load_firmware;
 	dev->if_port = cfg->if_port;
 	dev->chiptype = (u8)id->driver_data;
 	dev->if_frequency = 5000000; /* default value of property 0x0706 */
diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
index c22ca784f43f..ffdece3c2eaa 100644
--- a/drivers/media/tuners/si2157.h
+++ b/drivers/media/tuners/si2157.h
@@ -11,29 +11,34 @@
 #include <media/media-device.h>
 #include <media/dvb_frontend.h>
 
-/*
- * I2C address
- * 0x60
+/**
+ * struct si2157_config - configuration parameters for si2157
+ *
+ * @fe:
+ *	frontend returned by driver
+ * @mdev:
+ *	media device returned by driver
+ * @inversion:
+ *	spectral inversion
+ * @dont_load_firmware:
+ *	Instead of uploading a new firmware, use the existing one
+ * @if_port:
+ *	Port selection
+ *	Select the RF interface to use (pins 9+11 or 12+13)
+ *
+ * Note:
+ *	The I2C address of this demod is 0x60.
  */
 struct si2157_config {
-	/*
-	 * frontend
-	 */
 	struct dvb_frontend *fe;
 
 #if defined(CONFIG_MEDIA_CONTROLLER)
 	struct media_device *mdev;
 #endif
 
-	/*
-	 * Spectral Inversion
-	 */
-	bool inversion;
+	unsigned int inversion:1;
+	unsigned int dont_load_firmware:1;
 
-	/*
-	 * Port selection
-	 * Select the RF interface to use (pins 9+11 or 12+13)
-	 */
 	u8 if_port;
 };
 
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index 2bda903358da..778f81b39996 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -23,8 +23,9 @@ enum si2157_pads {
 struct si2157_dev {
 	struct mutex i2c_mutex;
 	struct dvb_frontend *fe;
-	bool active;
-	bool inversion;
+	unsigned int active:1;
+	unsigned int inversion:1;
+	unsigned int dont_load_firmware:1;
 	u8 chiptype;
 	u8 if_port;
 	u32 if_frequency;
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 3afd18733614..792667ee5ebc 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -1197,6 +1197,15 @@ static int af9035_frontend_attach(struct dvb_usb_adapter *adap)
 	return ret;
 }
 
+/*
+ * The I2C speed register is calculated with:
+ *	I2C speed register = (1000000000 / (24.4 * 16 * I2C_speed))
+ *
+ * The default speed register for it930x is 7, with means a
+ * speed of ~366 kbps
+ */
+#define I2C_SPEED_366K 7
+
 static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	struct state *state = adap_to_priv(adap);
@@ -1208,13 +1217,13 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
 
 	dev_dbg(&intf->dev, "adap->id=%d\n", adap->id);
 
-	/* I2C master bus 2 clock speed 300k */
-	ret = af9035_wr_reg(d, 0x00f6a7, 0x07);
+	/* I2C master bus 2 clock speed 366k */
+	ret = af9035_wr_reg(d, 0x00f6a7, I2C_SPEED_366K);
 	if (ret < 0)
 		goto err;
 
-	/* I2C master bus 1,3 clock speed 300k */
-	ret = af9035_wr_reg(d, 0x00f103, 0x07);
+	/* I2C master bus 1,3 clock speed 366k */
+	ret = af9035_wr_reg(d, 0x00f103, I2C_SPEED_366K);
 	if (ret < 0)
 		goto err;
 
@@ -1610,6 +1619,24 @@ static int it930x_tuner_attach(struct dvb_usb_adapter *adap)
 
 	memset(&si2157_config, 0, sizeof(si2157_config));
 	si2157_config.fe = adap->fe[0];
+
+	/*
+	 * HACK: The Logilink VG0022A has a bug: when the si2157
+	 * firmware that came with the device is replaced by a new
+	 * one, the I2C transfers to the tuner will return just 0xff.
+	 *
+	 * Probably, the vendor firmware has some patch specifically
+	 * designed for this device. So, we can't replace by the
+	 * generic firmware. The right solution would be to extract
+	 * the si2157 firmware from the original driver and ask the
+	 * driver to load the specifically designed firmware, but,
+	 * while we don't have that, the next best solution is to just
+	 * keep the original firmware at the device.
+	 */
+	if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_DEXATEK &&
+	    le16_to_cpu(d->udev->descriptor.idProduct) == 0x0100)
+		si2157_config.dont_load_firmware = true;
+
 	si2157_config.if_port = it930x_addresses_table[state->it930x_addresses].tuner_if_port;
 	ret = af9035_add_i2c_dev(d, "si2157",
 				 it930x_addresses_table[state->it930x_addresses].tuner_i2c_addr,
@@ -2121,6 +2148,8 @@ static const struct usb_device_id af9035_id_table[] = {
 		&it930x_props, "ITE 9303 Generic", NULL) },
 	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD310,
 		&it930x_props, "AVerMedia TD310 DVB-T2", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x0100,
+		&it930x_props, "Logilink VG0022A", NULL) },
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, af9035_id_table);
diff mbox series

Patch

diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 3afd18733614..e555483c3077 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -1255,6 +1255,23 @@  static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
 	si2168_config.fe = &adap->fe[0];
 	si2168_config.ts_mode = SI2168_TS_SERIAL;
 
+	/*
+	 * HACK: The Logilink VG0022A has a bug: when the si2168
+	 * firmware that came with the device is replaced by a new
+	 * one, the I2C transfers to the tuner will return just 0xff.
+	 *
+	 * Probably, the vendor firmware has some patch specifically
+	 * designed for this device. So, we can't replace by the
+	 * generic firmware. The right solution would be to extract
+	 * the si2168 firmware from the original driver and ask the
+	 * driver to load the specifically designed firmware, but,
+	 * while we don't have that, the next best solution is to just
+	 * keep the original firmware at the device.
+	 */
+	if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_DEXATEK &&
+	    le16_to_cpu(d->udev->descriptor.idProduct) == 0x0100)
+		si2168_config.dont_load_firmware = true;
+
 	state->af9033_config[adap->id].fe = &adap->fe[0];
 	state->af9033_config[adap->id].ops = &state->ops;
 	ret = af9035_add_i2c_dev(d, "si2168",
@@ -2121,6 +2138,8 @@  static const struct usb_device_id af9035_id_table[] = {
 		&it930x_props, "ITE 9303 Generic", NULL) },
 	{ DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD310,
 		&it930x_props, "AVerMedia TD310 DVB-T2", NULL) },
+	{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x0100,
+		&it930x_props, "Logilink VG0022A", NULL) },
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, af9035_id_table);