i2c: designware: add reset interface
authorZhangfei Gao <zhangfei.gao@linaro.org>
Tue, 27 Dec 2016 14:22:40 +0000 (22:22 +0800)
committerWolfram Sang <wsa@the-dreams.de>
Wed, 8 Mar 2017 17:15:18 +0000 (18:15 +0100)
Some platforms like hi3660 need do reset first to allow accessing registers

Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: Ramiro Oliveira <ramiro.oliveira@synopsys.com>
Acked-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-platdrv.c

index c1db3a5a340f599b6bee5c0165112703e2e082fc..d9aaf1790e0eff58dc6b26ca9d4881058e890f79 100644 (file)
@@ -88,6 +88,7 @@ struct dw_i2c_dev {
        void __iomem            *base;
        struct completion       cmd_complete;
        struct clk              *clk;
+       struct reset_control    *rst;
        u32                     (*get_clk_rate_khz) (struct dw_i2c_dev *dev);
        struct dw_pci_controller *controller;
        int                     cmd_err;
index 6ce4313231257f8251b62e02f5aaa390a4619edf..79c4b4ea053969e46226dc749fb12a5b59c3ac2c 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/property.h>
 #include <linux/io.h>
+#include <linux/reset.h>
 #include <linux/slab.h>
 #include <linux/acpi.h>
 #include <linux/platform_data/i2c-designware.h>
@@ -199,6 +200,14 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
        dev->irq = irq;
        platform_set_drvdata(pdev, dev);
 
+       dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
+       if (IS_ERR(dev->rst)) {
+               if (PTR_ERR(dev->rst) == -EPROBE_DEFER)
+                       return -EPROBE_DEFER;
+       } else {
+               reset_control_deassert(dev->rst);
+       }
+
        if (pdata) {
                dev->clk_freq = pdata->i2c_scl_freq;
        } else {
@@ -235,12 +244,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
            && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) {
                dev_err(&pdev->dev,
                        "Only 100kHz, 400kHz, 1MHz and 3.4MHz supported");
-               return -EINVAL;
+               r = -EINVAL;
+               goto exit_reset;
        }
 
        r = i2c_dw_eval_lock_support(dev);
        if (r)
-               return r;
+               goto exit_reset;
 
        dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY;
 
@@ -286,10 +296,18 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
        }
 
        r = i2c_dw_probe(dev);
-       if (r && !dev->pm_runtime_disabled)
-               pm_runtime_disable(&pdev->dev);
+       if (r)
+               goto exit_probe;
 
        return r;
+
+exit_probe:
+       if (!dev->pm_runtime_disabled)
+               pm_runtime_disable(&pdev->dev);
+exit_reset:
+       if (!IS_ERR_OR_NULL(dev->rst))
+               reset_control_assert(dev->rst);
+       return r;
 }
 
 static int dw_i2c_plat_remove(struct platform_device *pdev)
@@ -306,6 +324,8 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
        pm_runtime_put_sync(&pdev->dev);
        if (!dev->pm_runtime_disabled)
                pm_runtime_disable(&pdev->dev);
+       if (!IS_ERR_OR_NULL(dev->rst))
+               reset_control_assert(dev->rst);
 
        return 0;
 }