summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlok Chauhan <alokc@nvidia.com>2011-07-26 16:08:21 +0530
committerVarun Colbert <vcolbert@nvidia.com>2011-08-09 16:02:05 -0700
commitefc6e2c49a4b387feaaa88b44a16fe12d34dc4c2 (patch)
tree5ea534a5dca6ffc5c3a0f06713d9b09f077d9756
parentc7f57cc760411c030dd0fae88e2b78bf8439791f (diff)
i2c: tegra: Added arbitration lost error recovery
Added the arbitration lost error recovery code into i2c driver. bug 854305 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>
-rw-r--r--[-rwxr-xr-x]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 3064fc4863ad..6eac092deb4a 100755..100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -111,6 +111,8 @@
#define SL_ADDR1(addr) (addr & 0xff)
#define SL_ADDR2(addr) ((addr >> 8) & 0xff)
+
+
struct tegra_i2c_dev;
struct tegra_i2c_bus {
@@ -154,6 +156,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)
@@ -553,6 +558,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);
@@ -628,6 +634,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);
@@ -799,6 +814,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 {