diff options
author | Alok Chauhan <alokc@nvidia.com> | 2011-07-26 16:08:21 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:48:09 -0800 |
commit | d4476f10445a81c69246f9140a8b9b3f9981ad74 (patch) | |
tree | 89a3f74460ee94e4bb8b63f061585ae2b24e5a79 | |
parent | 92692aa917457cbc595948f4eab10bd1cfe065a4 (diff) |
i2c: tegra: Added arbitration lost error recovery
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
-rw-r--r-- | drivers/i2c/busses/i2c-tegra.c | 18 | ||||
-rw-r--r-- | include/linux/i2c-tegra.h | 3 |
2 files changed, 21 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 58cf7030860f..7997f7556af5 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -112,6 +112,8 @@ #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) diff --git a/include/linux/i2c-tegra.h b/include/linux/i2c-tegra.h index d48db31cb9bb..c9fc57b7f67b 100644 --- a/include/linux/i2c-tegra.h +++ b/include/linux/i2c-tegra.h @@ -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 { |