From 8ebb9b63afc52370a52555ea68b177e9d1bdc8a0 Mon Sep 17 00:00:00 2001 From: Alok Chauhan Date: Wed, 10 Aug 2011 14:45:18 +0530 Subject: 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 Reviewed-by: Alok Chauhan Tested-by: Alok Chauhan Reviewed-by: Bharat Nihalani --- drivers/i2c/busses/i2c-tegra.c | 16 ++++++++++++++++ include/linux/i2c-tegra.h | 3 +++ 2 files changed, 19 insertions(+) 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 */ -- cgit v1.2.3