[ARM] tegra: i2c: Fix i2c driver behavior on timeout/nack
authorColin Cross <ccross@android.com>
Fri, 14 May 2010 02:08:32 +0000 (19:08 -0700)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:26:42 +0000 (16:26 -0700)
Change-Id: Ia0968df649fa56d93cf3522d983fde16413e854d
Signed-off-by: Colin Cross <ccross@android.com>
drivers/i2c/busses/i2c-tegra.c

index ae0c848c70f7371a592e88e434b4498058b2da91..a88c8a1810d9b58cb568602dfd39875571bc605f 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+
 #include <asm/unaligned.h>
 
+#include <mach/clk.h>
+
 #define TEGRA_I2C_TIMEOUT (msecs_to_jiffies(1000))
 #define BYTES_PER_FIFO_WORD 4
 
@@ -289,6 +292,11 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev)
        u32 val;
        int err = 0;
 
+       tegra_periph_reset_assert(i2c_dev->clk);
+       msleep(1);
+       tegra_periph_reset_deassert(i2c_dev->clk);
+       msleep(1);
+
        clk_enable(i2c_dev->clk);
 
        dev_dbg(i2c_dev->dev, "init\n");
@@ -435,8 +443,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
        dev_dbg(i2c_dev->dev, "after transfer: %08x fifo %02x\n", i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS), i2c_readl(i2c_dev, I2C_FIFO_STATUS));
        if (ret == 0) {
                dev_err(i2c_dev->dev, "i2c transfer timed out\n");
-               dev_err(i2c_dev->dev, "");
-               BUG();
+
                tegra_i2c_init(i2c_dev);
                return -ETIMEDOUT;
        }
@@ -445,7 +452,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
 
        if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
                return 0;
-       BUG();
+
        tegra_i2c_init(i2c_dev);
        if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
                if (msg->flags & I2C_M_IGNORE_NAK)
@@ -460,13 +467,16 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int n
 {
        struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
        int i;
+       int ret = 0;
        clk_enable(i2c_dev->clk);
        for (i = 0; i < num; i++) {
                int stop = (i == (num - 1)) ? 1  : 0;
-               tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
+               ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], stop);
+               if (ret)
+                       break;
        }
        clk_disable(i2c_dev->clk);
-       return num;
+       return i;
 }
 
 static u32 tegra_i2c_func(struct i2c_adapter *adap)