i2c: tegra: Added arbitration lost error recovery
Alok Chauhan [Tue, 26 Jul 2011 10:38:21 +0000 (15:38 +0530)]
Added the arbitration lost error recovery code into
i2c driver.

bug 854305

Original-Change-Id: Ib855f3541d139c01ea34fd9070feef7969eed395
Reviewed-on: http://git-master/r/43201
Reviewed-by: Bandi Krishna Chaitanya <bandik@nvidia.com>
Tested-by: Bandi Krishna Chaitanya <bandik@nvidia.com>
Reviewed-by: Alok Chauhan <alokc@nvidia.com>
Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>

Rebase-Id: R7cda6214579416b3b0a4eafe412a18293260e669

drivers/i2c/busses/i2c-tegra.c
include/linux/i2c-tegra.h

index 58cf703..7997f75 100644 (file)
 #define SL_ADDR1(addr) (addr & 0xff)
 #define SL_ADDR2(addr) ((addr >> 8) & 0xff)
 
+
+
 struct tegra_i2c_dev;
 
 struct tegra_i2c_bus {
@@ -173,6 +175,9 @@ struct tegra_i2c_dev {
        u16 slave_addr;
        bool is_clkon_always;
        struct tegra_i2c_bus busses[1];
+       int scl_gpio;
+       int sda_gpio;
+       int (*arb_recovery)(int scl_gpio, int sda_gpio);
 };
 
 static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg)
@@ -583,6 +588,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
        u32 int_mask;
        int ret;
        unsigned long flags;
+       int arb_stat;
 
        tegra_i2c_flush_fifos(i2c_dev);
 
@@ -652,6 +658,15 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
        if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
                return 0;
 
+       /* Arbitration Lost occurs, Start recovery */
+       if (i2c_dev->msg_err == I2C_ERR_ARBITRATION_LOST) {
+               if (i2c_dev->arb_recovery) {
+                       arb_stat = i2c_dev->arb_recovery(i2c_dev->scl_gpio, i2c_dev->sda_gpio);
+                       if (!arb_stat)
+                               return -EAGAIN;
+               }
+       }
+
        spin_lock_irqsave(&i2c_dev->clk_lock, flags);
        i2c_dev->controller_enabled = false;
        tegra_i2c_init(i2c_dev);
@@ -833,6 +848,9 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 
        i2c_dev->slave_addr = plat->slave_addr;
        i2c_dev->is_dvc = plat->is_dvc;
+       i2c_dev->scl_gpio = plat->scl_gpio;
+       i2c_dev->sda_gpio = plat->sda_gpio;
+       i2c_dev->arb_recovery = plat->arb_recovery;
        init_completion(&i2c_dev->msg_complete);
 
        if (irq == INT_I2C || irq == INT_I2C2 || irq == INT_I2C3)
index d48db31..c9fc57b 100644 (file)
@@ -35,6 +35,9 @@ struct tegra_i2c_platform_data {
        int retries;
        int timeout;    /* in jiffies */
        u16 slave_addr;
+       int scl_gpio;
+       int sda_gpio;
+       int (*arb_recovery)(void);
 };
 
 struct tegra_i2c_slave_platform_data {