diff options
author | Zhangfei Gao <zhangfei.gao@linaro.org> | 2016-12-27 09:22:40 -0500 |
---|---|---|
committer | Wolfram Sang <wsa@the-dreams.de> | 2017-03-08 12:15:18 -0500 |
commit | ab809fd81fde3d416f8656d8f814a0777fb9b65e (patch) | |
tree | 18784d3b6c72ae0f3f87a1820e2c68fa5f78ad67 | |
parent | 3b0277f198ac928f323c42e180680d2f79aa980d (diff) |
i2c: designware: add reset interface
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>
-rw-r--r-- | drivers/i2c/busses/i2c-designware-core.h | 1 | ||||
-rw-r--r-- | drivers/i2c/busses/i2c-designware-platdrv.c | 28 |
2 files changed, 25 insertions, 4 deletions
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index c1db3a5a340f..d9aaf1790e0e 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h | |||
@@ -88,6 +88,7 @@ struct dw_i2c_dev { | |||
88 | void __iomem *base; | 88 | void __iomem *base; |
89 | struct completion cmd_complete; | 89 | struct completion cmd_complete; |
90 | struct clk *clk; | 90 | struct clk *clk; |
91 | struct reset_control *rst; | ||
91 | u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev); | 92 | u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev); |
92 | struct dw_pci_controller *controller; | 93 | struct dw_pci_controller *controller; |
93 | int cmd_err; | 94 | int cmd_err; |
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 6ce431323125..79c4b4ea0539 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/pm_runtime.h> | 38 | #include <linux/pm_runtime.h> |
39 | #include <linux/property.h> | 39 | #include <linux/property.h> |
40 | #include <linux/io.h> | 40 | #include <linux/io.h> |
41 | #include <linux/reset.h> | ||
41 | #include <linux/slab.h> | 42 | #include <linux/slab.h> |
42 | #include <linux/acpi.h> | 43 | #include <linux/acpi.h> |
43 | #include <linux/platform_data/i2c-designware.h> | 44 | #include <linux/platform_data/i2c-designware.h> |
@@ -199,6 +200,14 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) | |||
199 | dev->irq = irq; | 200 | dev->irq = irq; |
200 | platform_set_drvdata(pdev, dev); | 201 | platform_set_drvdata(pdev, dev); |
201 | 202 | ||
203 | dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); | ||
204 | if (IS_ERR(dev->rst)) { | ||
205 | if (PTR_ERR(dev->rst) == -EPROBE_DEFER) | ||
206 | return -EPROBE_DEFER; | ||
207 | } else { | ||
208 | reset_control_deassert(dev->rst); | ||
209 | } | ||
210 | |||
202 | if (pdata) { | 211 | if (pdata) { |
203 | dev->clk_freq = pdata->i2c_scl_freq; | 212 | dev->clk_freq = pdata->i2c_scl_freq; |
204 | } else { | 213 | } else { |
@@ -235,12 +244,13 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) | |||
235 | && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) { | 244 | && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) { |
236 | dev_err(&pdev->dev, | 245 | dev_err(&pdev->dev, |
237 | "Only 100kHz, 400kHz, 1MHz and 3.4MHz supported"); | 246 | "Only 100kHz, 400kHz, 1MHz and 3.4MHz supported"); |
238 | return -EINVAL; | 247 | r = -EINVAL; |
248 | goto exit_reset; | ||
239 | } | 249 | } |
240 | 250 | ||
241 | r = i2c_dw_eval_lock_support(dev); | 251 | r = i2c_dw_eval_lock_support(dev); |
242 | if (r) | 252 | if (r) |
243 | return r; | 253 | goto exit_reset; |
244 | 254 | ||
245 | dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY; | 255 | dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY; |
246 | 256 | ||
@@ -286,10 +296,18 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) | |||
286 | } | 296 | } |
287 | 297 | ||
288 | r = i2c_dw_probe(dev); | 298 | r = i2c_dw_probe(dev); |
289 | if (r && !dev->pm_runtime_disabled) | 299 | if (r) |
290 | pm_runtime_disable(&pdev->dev); | 300 | goto exit_probe; |
291 | 301 | ||
292 | return r; | 302 | return r; |
303 | |||
304 | exit_probe: | ||
305 | if (!dev->pm_runtime_disabled) | ||
306 | pm_runtime_disable(&pdev->dev); | ||
307 | exit_reset: | ||
308 | if (!IS_ERR_OR_NULL(dev->rst)) | ||
309 | reset_control_assert(dev->rst); | ||
310 | return r; | ||
293 | } | 311 | } |
294 | 312 | ||
295 | static int dw_i2c_plat_remove(struct platform_device *pdev) | 313 | static int dw_i2c_plat_remove(struct platform_device *pdev) |
@@ -306,6 +324,8 @@ static int dw_i2c_plat_remove(struct platform_device *pdev) | |||
306 | pm_runtime_put_sync(&pdev->dev); | 324 | pm_runtime_put_sync(&pdev->dev); |
307 | if (!dev->pm_runtime_disabled) | 325 | if (!dev->pm_runtime_disabled) |
308 | pm_runtime_disable(&pdev->dev); | 326 | pm_runtime_disable(&pdev->dev); |
327 | if (!IS_ERR_OR_NULL(dev->rst)) | ||
328 | reset_control_assert(dev->rst); | ||
309 | 329 | ||
310 | return 0; | 330 | return 0; |
311 | } | 331 | } |