summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlok Chauhan <alokc@nvidia.com>2011-08-10 14:45:18 +0530
committerNiket Sirsi <nsirsi@nvidia.com>2011-08-16 16:21:13 -0700
commit8ebb9b63afc52370a52555ea68b177e9d1bdc8a0 (patch)
tree8856a28397a922d1625bba9bdc8efbffd7b6d890
parentb62c26752baae70fb82fe997a9cac1c55c71e773 (diff)
i2c: tegra: Added arbitration lost error recovery
Added the arbitration lost error recovery code into i2c driver. bug 854305 This is cherry pick of change http://git-master/r/#change,43201 in main but hand-merged. Change-Id: Ic745491f1914c1e4c470f7b8b4ff9a29eb030a82 Reviewed-on: http://git-master/r/46289 Reviewed-by: Mayuresh Kulkarni <mkulkarni@nvidia.com> Reviewed-by: Alok Chauhan <alokc@nvidia.com> Tested-by: Alok Chauhan <alokc@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com>
-rw-r--r--drivers/i2c/busses/i2c-tegra.c16
-rw-r--r--include/linux/i2c-tegra.h3
2 files changed, 19 insertions, 0 deletions
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index d50c5e5db862..74308457d73c 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -113,6 +113,8 @@ struct tegra_i2c_bus {
int mux_len;
unsigned long bus_clk_rate;
struct i2c_adapter adapter;
+ int scl_gpio;
+ int sda_gpio;
};
struct tegra_i2c_dev {
@@ -146,6 +148,7 @@ struct tegra_i2c_dev {
unsigned long last_bus_clk;
u16 slave_addr;
struct tegra_i2c_bus busses[1];
+ int (*arb_recovery)(int scl_gpio, int sda_gpio);
};
static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg)
@@ -534,6 +537,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_bus *i2c_bus,
struct tegra_i2c_dev *i2c_dev = i2c_bus->dev;
u32 int_mask;
int ret;
+ int arb_stat;
tegra_i2c_flush_fifos(i2c_dev);
i2c_writel(i2c_dev, 0xFF, I2C_INT_STATUS);
@@ -606,6 +610,14 @@ 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_bus->scl_gpio, i2c_bus->sda_gpio);
+ if (!arb_stat)
+ return -EAGAIN;
+ }
+ }
tegra_i2c_init(i2c_dev);
if (i2c_dev->msg_err == I2C_ERR_NO_ACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
@@ -766,6 +778,7 @@ 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->arb_recovery = plat->arb_recovery;
init_completion(&i2c_dev->msg_complete);
if (irq == INT_I2C || irq == INT_I2C2 || irq == INT_I2C3)
@@ -794,6 +807,9 @@ static int tegra_i2c_probe(struct platform_device *pdev)
i2c_bus->mux_len = plat->bus_mux_len[i];
i2c_bus->bus_clk_rate = plat->bus_clk_rate[i] ?: 100000;
+ i2c_bus->scl_gpio = plat->scl_gpio[i];
+ i2c_bus->sda_gpio = plat->sda_gpio[i];
+
i2c_bus->adapter.algo = &tegra_i2c_algo;
i2c_set_adapdata(&i2c_bus->adapter, i2c_bus);
i2c_bus->adapter.owner = THIS_MODULE;
diff --git a/include/linux/i2c-tegra.h b/include/linux/i2c-tegra.h
index b104504c0b9c..096b3d26d595 100644
--- a/include/linux/i2c-tegra.h
+++ b/include/linux/i2c-tegra.h
@@ -32,6 +32,9 @@ struct tegra_i2c_platform_data {
int retries;
int timeout; /* in jiffies */
u16 slave_addr;
+ int scl_gpio[TEGRA_I2C_MAX_BUS];
+ int sda_gpio[TEGRA_I2C_MAX_BUS];
+ int (*arb_recovery)(void);
};
#endif /* _LINUX_I2C_TEGRA_H */