diff options
Diffstat (limited to 'drivers/i2c/busses/i2c-designware-platdrv.c')
-rw-r--r-- | drivers/i2c/busses/i2c-designware-platdrv.c | 86 |
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; } |