[media] af9035: fix for MXL5007T devices with I2C read issues
authorAlessandro Radicati <alessandro@radicati.net>
Thu, 12 May 2016 10:47:12 +0000 (07:47 -0300)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Thu, 9 Jun 2016 11:46:00 +0000 (08:46 -0300)
The MXL5007T tuner will lock-up on some devices after an I2C read
transaction.  This patch works around this issue by inhibiting such
operations and emulating a 0x00 response. The workaround is only
applied to USB devices known to exhibit this flaw.

Signed-off-by: Alessandro Radicati <alessandro@radicati.net>
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/usb/dvb-usb-v2/af9035.c
drivers/media/usb/dvb-usb-v2/af9035.h

index 09a549b494003f89b96ea05fbe7b962f1bb1b27a..a8ab592bf76179972c1dac0d41794096dfb89872 100644 (file)
@@ -348,6 +348,9 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
 
                        ret = af9035_rd_regs(d, reg, &msg[1].buf[0],
                                        msg[1].len);
+               } else if (state->no_read) {
+                       memset(msg[1].buf, 0, msg[1].len);
+                       ret = 0;
                } else {
                        /* I2C write + read */
                        u8 buf[MAX_XFER_SIZE];
@@ -436,6 +439,9 @@ static int af9035_i2c_master_xfer(struct i2c_adapter *adap,
                if (msg[0].len > 40) {
                        /* TODO: correct limits > 40 */
                        ret = -EOPNOTSUPP;
+               } else if (state->no_read) {
+                       memset(msg[0].buf, 0, msg[0].len);
+                       ret = 0;
                } else {
                        /* I2C read */
                        u8 buf[5];
@@ -977,6 +983,21 @@ skip_eeprom:
                        state->af9033_config[i].clock = clock_lut_af9035[tmp];
        }
 
+       state->no_read = false;
+       /* Some MXL5007T devices cannot properly handle tuner I2C read ops. */
+       if (state->af9033_config[0].tuner == AF9033_TUNER_MXL5007T &&
+               le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA)
+
+               switch (le16_to_cpu(d->udev->descriptor.idProduct)) {
+               case USB_PID_AVERMEDIA_A867:
+               case USB_PID_AVERMEDIA_TWINSTAR:
+                       dev_info(&d->udev->dev,
+                               "%s: Device may have issues with I2C read operations. Enabling fix.\n",
+                               KBUILD_MODNAME);
+                       state->no_read = true;
+                       break;
+               }
+
        return 0;
 
 err:
index 89e629a24aec9bd69d0fc020afd3eb3346ed4cd6..c91d1a3789e6e9c5796b2340e0aedb05dfdb0c25 100644 (file)
@@ -62,6 +62,7 @@ struct state {
        u8 chip_version;
        u16 chip_type;
        u8 dual_mode:1;
+       u8 no_read:1;
        u16 eeprom_addr;
        u8 af9033_i2c_addr[2];
        struct af9033_config af9033_config[2];