diff options
-rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index c2ae599c7133..8a055ddfdaff 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -10,6 +10,7 @@ #include <linux/delay.h> #include <linux/mmc/mmc.h> #include <linux/pm_runtime.h> +#include <linux/pm_opp.h> #include <linux/slab.h> #include <linux/iopoll.h> #include <linux/regulator/consumer.h> @@ -243,6 +244,8 @@ struct sdhci_msm_host { struct clk_bulk_data bulk_clks[4]; /* core, iface, cal, sleep clocks */ unsigned long clk_rate; struct mmc_host *mmc; + struct opp_table *opp; + bool opp_table; bool use_14lpp_dll_reset; bool tuning_done; bool calibration_done; @@ -332,7 +335,7 @@ static void msm_set_clock_rate_for_bus_mode(struct sdhci_host *host, int rc; clock = msm_get_clock_rate_for_bus_mode(host, clock); - rc = clk_set_rate(core_clk, clock); + rc = dev_pm_opp_set_rate(mmc_dev(host->mmc), clock); if (rc) { pr_err("%s: Failed to set clock at rate %u at timing %d\n", mmc_hostname(host->mmc), clock, @@ -1964,8 +1967,18 @@ static int sdhci_msm_probe(struct platform_device *pdev) } msm_host->bulk_clks[0].clk = clk; + msm_host->opp = dev_pm_opp_set_clkname(&pdev->dev, "core"); + if (IS_ERR(msm_host->opp)) { + ret = PTR_ERR(msm_host->opp); + goto bus_clk_disable; + } + + /* OPP table is optional */ + if (!dev_pm_opp_of_add_table(&pdev->dev)) + msm_host->opp_table = true; + /* Vote for maximum clock rate for maximum performance */ - ret = clk_set_rate(clk, INT_MAX); + ret = dev_pm_opp_set_rate(&pdev->dev, INT_MAX); if (ret) dev_warn(&pdev->dev, "core clock boost failed\n"); @@ -1982,7 +1995,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); if (ret) - goto bus_clk_disable; + goto opp_cleanup; /* * xo clock is needed for FLL feature of cm_dll. @@ -2119,6 +2132,10 @@ pm_runtime_disable: clk_disable: clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); +opp_cleanup: + if (msm_host->opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(msm_host->opp); bus_clk_disable: if (!IS_ERR(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); @@ -2137,6 +2154,9 @@ static int sdhci_msm_remove(struct platform_device *pdev) sdhci_remove_host(host, dead); + if (msm_host->opp_table) + dev_pm_opp_of_remove_table(&pdev->dev); + dev_pm_opp_put_clkname(msm_host->opp); pm_runtime_get_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); pm_runtime_put_noidle(&pdev->dev); @@ -2155,6 +2175,8 @@ static __maybe_unused int sdhci_msm_runtime_suspend(struct device *dev) struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host); + /* Drop the performance vote */ + dev_pm_opp_set_rate(dev, 0); clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks), msm_host->bulk_clks); @@ -2177,9 +2199,11 @@ static __maybe_unused int sdhci_msm_runtime_resume(struct device *dev) * restore the SDR DLL settings when the clock is ungated. */ if (msm_host->restore_dll_config && msm_host->clk_rate) - return sdhci_msm_restore_sdr_dll_config(host); + ret = sdhci_msm_restore_sdr_dll_config(host); - return 0; + dev_pm_opp_set_rate(dev, msm_host->clk_rate); + + return ret; } static const struct dev_pm_ops sdhci_msm_pm_ops = { |