summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses/i2c-designware-platdrv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses/i2c-designware-platdrv.c')
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c86
1 files changed, 48 insertions, 38 deletions
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index a2ae2213ef3e..1db66ed8161d 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -209,16 +209,17 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST;
dev->clk = devm_clk_get(&pdev->dev, NULL);
- dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
- if (IS_ERR(dev->clk))
- return PTR_ERR(dev->clk);
- clk_prepare_enable(dev->clk);
+ if (!IS_ERR(dev->clk)) {
+ r = clk_prepare_enable(dev->clk);
+ if (r)
+ return r;
- if (!dev->sda_hold_time && ht) {
- u32 ic_clk = dev->get_clk_rate_khz(dev);
+ dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
- dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
- 1000000);
+ if (!dev->sda_hold_time && ht)
+ dev->sda_hold_time = div_u64(
+ (u64)dev->get_clk_rate_khz(dev) * ht + 500000,
+ 1000000);
}
if (!dev->tx_fifo_depth) {
@@ -235,18 +236,26 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev));
adap->dev.of_node = pdev->dev.of_node;
- if (dev->pm_runtime_disabled) {
- pm_runtime_forbid(&pdev->dev);
- } else {
- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
- }
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ if (dev->pm_runtime_disabled)
+ pm_runtime_get_noresume(&pdev->dev);
r = i2c_dw_probe(dev);
- if (r && !dev->pm_runtime_disabled)
+ if (r) {
+ if (!IS_ERR(dev->clk))
+ clk_disable_unprepare(dev->clk);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_dont_use_autosuspend(&pdev->dev);
+ if (dev->pm_runtime_disabled)
+ pm_runtime_put_noidle(&pdev->dev);
+ }
+ pm_runtime_mark_last_busy(&pdev->dev);
+ pm_runtime_put(&pdev->dev);
return r;
}
@@ -261,10 +270,16 @@ static int dw_i2c_plat_remove(struct platform_device *pdev)
i2c_dw_disable(dev);
+ if (!IS_ERR(dev->clk))
+ clk_disable_unprepare(dev->clk);
+
+ pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
- pm_runtime_put_sync(&pdev->dev);
- if (!dev->pm_runtime_disabled)
- pm_runtime_disable(&pdev->dev);
+ if (dev->pm_runtime_disabled)
+ pm_runtime_put_noidle(&pdev->dev);
+
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
return 0;
}
@@ -277,21 +292,18 @@ static const struct of_device_id dw_i2c_of_match[] = {
MODULE_DEVICE_TABLE(of, dw_i2c_of_match);
#endif
-#ifdef CONFIG_PM_SLEEP
-static int dw_i2c_plat_prepare(struct device *dev)
+#ifdef CONFIG_PM
+static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare)
{
- return pm_runtime_suspended(dev);
-}
+ if (IS_ERR(i_dev->clk))
+ return PTR_ERR(i_dev->clk);
-static void dw_i2c_plat_complete(struct device *dev)
-{
- if (dev->power.direct_complete)
- pm_request_resume(dev);
+ if (prepare)
+ return clk_prepare_enable(i_dev->clk);
+
+ clk_disable_unprepare(i_dev->clk);
+ return 0;
}
-#else
-#define dw_i2c_plat_prepare NULL
-#define dw_i2c_plat_complete NULL
-#endif
#ifdef CONFIG_PM
static int dw_i2c_plat_runtime_suspend(struct device *dev)
@@ -300,20 +312,18 @@ static int dw_i2c_plat_runtime_suspend(struct device *dev)
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
i2c_dw_disable(i_dev);
- clk_disable_unprepare(i_dev->clk);
+ i2c_dw_plat_prepare_clk(i_dev, false);
return 0;
}
-static int dw_i2c_plat_resume(struct device *dev)
+static int dw_i2c_plat_runtime_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
- clk_prepare_enable(i_dev->clk);
-
- if (!i_dev->pm_runtime_disabled)
- i2c_dw_init(i_dev);
+ i2c_dw_plat_prepare_clk(i_dev, true);
+ i2c_dw_init(i_dev);
return 0;
}