summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlok Chauhan <alokc@nvidia.com>2011-07-26 16:08:21 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:48:09 -0800
commitd4476f10445a81c69246f9140a8b9b3f9981ad74 (patch)
tree89a3f74460ee94e4bb8b63f061585ae2b24e5a79
parent92692aa917457cbc595948f4eab10bd1cfe065a4 (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.c18
-rw-r--r--include/linux/i2c-tegra.h3
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 {