Add bus recovery support for designware_i2c controller. It uses generic gpio
based i2c_gpio_recover_bus() routine. Platforms need to pass struct
i2c_bus_recovery_info as platform data designware I2C controller.

Signed-off-by: Vincenzo Frascino <vincenzo.frasc...@st.com>
Signed-off-by: Shiraz Hashim <shiraz.has...@st.com>
Signed-off-by: Viresh Kumar <viresh.ku...@linaro.org>
---
V6->V7:
- removed include/linux/i2c/i2c-designware.h and use struct
  i2c_bus_recovery_info as platform data.
- initialize recover_bus with i2c_generic_gpio_recovery()

 drivers/i2c/busses/i2c-designware-core.c    |  6 +++++-
 drivers/i2c/busses/i2c-designware-platdrv.c | 18 ++++++++++++++++--
 2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/i2c/busses/i2c-designware-core.c 
b/drivers/i2c/busses/i2c-designware-core.c
index cbba7db..24feaaf 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -538,7 +538,11 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg 
msgs[], int num)
        ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ);
        if (ret == 0) {
                dev_err(dev->dev, "controller timed out\n");
-               i2c_dw_init(dev);
+               if (adap->bus_recovery_info) {
+                       dev_dbg(dev->dev, "try i2c bus recovery\n");
+                       adap->bus_recovery_info->recover_bus(adap);
+               }
+
                ret = -ETIMEDOUT;
                goto done;
        } else if (ret < 0)
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c 
b/drivers/i2c/busses/i2c-designware-platdrv.c
index 0506fef..c7725b2 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -55,6 +55,7 @@ static int __devinit dw_i2c_probe(struct platform_device 
*pdev)
        struct dw_i2c_dev *dev;
        struct i2c_adapter *adap;
        struct resource *mem, *ioarea;
+       struct i2c_bus_recovery_info *recovery_info;
        int irq, r;
 
        /* NOTE: driver uses the static register mapping */
@@ -141,17 +142,28 @@ static int __devinit dw_i2c_probe(struct platform_device 
*pdev)
        adap->dev.parent = &pdev->dev;
        adap->dev.of_node = pdev->dev.of_node;
 
+       /* Bus recovery support */
+       recovery_info = dev_get_platdata(&pdev->dev);
+       if (recovery_info) {
+               recovery_info->recover_bus = i2c_generic_gpio_recovery;
+               recovery_info->clock_rate_khz = clk_get_rate(dev->clk) / 1000;
+               adap->bus_recovery_info = recovery_info;
+       } else {
+               adap->bus_recovery_info = NULL;
+       }
+
        adap->nr = pdev->id;
        r = i2c_add_numbered_adapter(adap);
        if (r) {
                dev_err(&pdev->dev, "failure adding adapter\n");
-               goto err_free_irq;
+               goto err_free_recovery_info;
        }
        of_i2c_register_devices(adap);
 
        return 0;
 
-err_free_irq:
+err_free_recovery_info:
+       kfree(recovery_info);
        free_irq(dev->irq, dev);
 err_iounmap:
        iounmap(dev->base);
@@ -174,6 +186,8 @@ static int __devexit dw_i2c_remove(struct platform_device 
*pdev)
        struct dw_i2c_dev *dev = platform_get_drvdata(pdev);
        struct resource *mem;
 
+       kfree(dev->adapter.bus_recovery_info);
+
        platform_set_drvdata(pdev, NULL);
        i2c_del_adapter(&dev->adapter);
        put_device(&pdev->dev);
-- 
1.7.12.rc2.18.g61b472e

--
To unsubscribe from this list: send the line "unsubscribe linux-i2c" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to