[media] xc4000: handle dib0700 broken i2c stretching
authorDevin Heitmueller <dheitmueller@kernellabs.com>
Mon, 5 Oct 2009 02:09:18 +0000 (23:09 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Wed, 27 Jul 2011 20:52:30 +0000 (17:52 -0300)
It was confirmed by DibCom that i2c stretching is broken in the i2c master
on the dib7700.  So we need to put a hack into the xc4000 driver to not
complain in certain very specific cases where we know i2c stretching occurs.

Signed-off-by: Devin Heitmueller <dheitmueller@kernellabs.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/common/tuners/xc4000.c

index 2dacf209d427a61c99cf1d7967b9b6f2a1246293..b3b33d266b7cdbb17bf984f30d274bd9fa418a4a 100644 (file)
@@ -89,6 +89,7 @@ struct xc4000_priv {
        struct firmware_properties cur_fw;
        __u16                   hwmodel;
        __u16                   hwvers;
+       u8 ignore_i2c_write_errors;
 };
 
 /* Misc Defines */
@@ -255,8 +256,15 @@ static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len)
        struct i2c_msg msg = { .addr = priv->i2c_props.addr,
                               .flags = 0, .buf = buf, .len = len };
        if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
-               printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n", len);
-               return XC_RESULT_I2C_WRITE_FAILURE;
+               if (priv->ignore_i2c_write_errors == 0) {
+                       printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n",
+                              len);
+                       if (len == 4) {
+                               printk("bytes %02x %02x %02x %02x\n", buf[0],
+                                      buf[1], buf[2], buf[3]);
+                       }
+                       return XC_RESULT_I2C_WRITE_FAILURE;
+               }
        }
        return XC_RESULT_SUCCESS;
 }
@@ -371,10 +379,15 @@ static int xc_SetTVStandard(struct xc4000_priv *priv,
                __func__,
                XC4000_Standard[priv->video_standard].Name);
 
+       /* Don't complain when the request fails because of i2c stretching */
+       priv->ignore_i2c_write_errors = 1;
+
        ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
        if (ret == XC_RESULT_SUCCESS)
                ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
 
+       priv->ignore_i2c_write_errors = 0;
+
        return ret;
 }
 
@@ -506,10 +519,16 @@ static u16 WaitForLock(struct xc4000_priv *priv)
 static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz, int mode)
 {
        int found = 0;
+       int result = 0;
 
        dprintk(1, "%s(%u)\n", __func__, freq_hz);
 
-       if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
+       /* Don't complain when the request fails because of i2c stretching */
+       priv->ignore_i2c_write_errors = 1;
+       result = xc_set_RF_frequency(priv, freq_hz);
+       priv->ignore_i2c_write_errors = 0;
+
+       if (result != XC_RESULT_SUCCESS)
                return 0;
 
        if (mode == XC_TUNE_ANALOG) {
@@ -721,8 +740,13 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
        p = priv->firm[pos].ptr;
        printk("firmware length = %d\n", priv->firm[pos].size);
 
+       /* Don't complain when the request fails because of i2c stretching */
+       priv->ignore_i2c_write_errors = 1;
+
        rc = xc_load_i2c_sequence(fe, p);
 
+       priv->ignore_i2c_write_errors = 0;
+
        return rc;
 }
 
@@ -954,7 +978,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
        int                        rc = 0, is_retry = 0;
        u16                        version, hwmodel;
        v4l2_std_id                std0;
-       u8                         hw_major, hw_minor, fw_major, fw_minor;
+       u8                         hw_major, hw_minor, fw_major, fw_minor;
 
        dprintk(1, "%s called\n", __func__);
 
@@ -1071,7 +1095,7 @@ skip_std_specific:
 check_device:
        rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel);
 
-       if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major, 
+       if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major,
                           &fw_minor) != XC_RESULT_SUCCESS) {
                printk("Unable to read tuner registers.\n");
                goto fail;