diff options
| author | Asutosh Das <asutoshd@codeaurora.org> | 2013-11-08 12:33:47 +0530 |
|---|---|---|
| committer | Subhash Jadavani <subhashj@codeaurora.org> | 2016-05-27 10:28:57 -0700 |
| commit | 21512ff94960e3d9bfdfae860dcbdca698578f95 (patch) | |
| tree | 1a59e108f0e086535082d9ec9b7a0761444aed93 | |
| parent | deba741527aa75d03e2d0d1f6010b5bae538a4ac (diff) | |
mmc: sdhci-msm: enable controller clocks at MMC_POWER_UP
A callback to turn-on the controller clocks is implemented.
This callback would ensure that the pclk and mclk are enabled
but the output clock to the card is disabled.
CRs-Fixed: 567658
Change-Id: Ic97e600a6388fb64f1267a097b201f31d114a1fb
Signed-off-by: Asutosh Das <asutoshd@codeaurora.org>
Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org>
| -rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 88 |
1 files changed, 66 insertions, 22 deletions
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 2a5f2cc6b758..d4517938cb64 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -301,6 +301,7 @@ struct sdhci_msm_host { u8 saved_tuning_phase; bool en_auto_cmd21; struct device_attribute auto_cmd21_attr; + atomic_t controller_clock; }; enum vdd_io_level { @@ -2297,6 +2298,50 @@ static unsigned int sdhci_msm_get_sup_clk_rate(struct sdhci_host *host, return sel_clk; } +static int sdhci_msm_enable_controller_clock(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + int rc = 0; + + if (atomic_read(&msm_host->controller_clock)) + return 0; + + sdhci_msm_bus_voting(host, 1); + + if (!IS_ERR(msm_host->pclk)) { + rc = clk_prepare_enable(msm_host->pclk); + if (rc) { + pr_err("%s: %s: failed to enable the pclk with error %d\n", + mmc_hostname(host->mmc), __func__, rc); + goto remove_vote; + } + } + + rc = clk_prepare_enable(msm_host->clk); + if (rc) { + pr_err("%s: %s: failed to enable the host-clk with error %d\n", + mmc_hostname(host->mmc), __func__, rc); + goto disable_pclk; + } + + atomic_set(&msm_host->controller_clock, 1); + pr_debug("%s: %s: enabled controller clock\n", + mmc_hostname(host->mmc), __func__); + goto out; + +disable_pclk: + if (!IS_ERR(msm_host->pclk)) + clk_disable_unprepare(msm_host->pclk); +remove_vote: + if (msm_host->msm_bus_vote.client_handle) + sdhci_msm_bus_cancel_work_and_set_vote(host, 0); +out: + return rc; +} + + + static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -2307,36 +2352,32 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable) pr_debug("%s: request to enable clocks\n", mmc_hostname(host->mmc)); - sdhci_msm_bus_voting(host, 1); + /* + * The bus-width or the clock rate might have changed + * after controller clocks are enbaled, update bus vote + * in such case. + */ + if (atomic_read(&msm_host->controller_clock)) + sdhci_msm_bus_voting(host, 1); + + rc = sdhci_msm_enable_controller_clock(host); + if (rc) + goto remove_vote; if (!IS_ERR_OR_NULL(msm_host->bus_clk)) { rc = clk_prepare_enable(msm_host->bus_clk); if (rc) { pr_err("%s: %s: failed to enable the bus-clock with error %d\n", mmc_hostname(host->mmc), __func__, rc); - goto remove_vote; + goto disable_controller_clk; } } - if (!IS_ERR(msm_host->pclk)) { - rc = clk_prepare_enable(msm_host->pclk); - if (rc) { - pr_err("%s: %s: failed to enable the pclk with error %d\n", - mmc_hostname(host->mmc), __func__, rc); - goto disable_bus_clk; - } - } - rc = clk_prepare_enable(msm_host->clk); - if (rc) { - pr_err("%s: %s: failed to enable the host-clk with error %d\n", - mmc_hostname(host->mmc), __func__, rc); - goto disable_pclk; - } if (!IS_ERR(msm_host->ff_clk)) { rc = clk_prepare_enable(msm_host->ff_clk); if (rc) { pr_err("%s: %s: failed to enable the ff_clk with error %d\n", mmc_hostname(host->mmc), __func__, rc); - goto disable_clk; + goto disable_bus_clk; } } if (!IS_ERR(msm_host->sleep_clk)) { @@ -2372,6 +2413,7 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable) if (!IS_ERR_OR_NULL(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); + atomic_set(&msm_host->controller_clock, 0); sdhci_msm_bus_voting(host, 0); } atomic_set(&msm_host->clks_on, enable); @@ -2379,15 +2421,15 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable) disable_ff_clk: if (!IS_ERR_OR_NULL(msm_host->ff_clk)) clk_disable_unprepare(msm_host->ff_clk); -disable_clk: +disable_bus_clk: + if (!IS_ERR_OR_NULL(msm_host->bus_clk)) + clk_disable_unprepare(msm_host->bus_clk); +disable_controller_clk: if (!IS_ERR_OR_NULL(msm_host->clk)) clk_disable_unprepare(msm_host->clk); -disable_pclk: if (!IS_ERR_OR_NULL(msm_host->pclk)) clk_disable_unprepare(msm_host->pclk); -disable_bus_clk: - if (!IS_ERR_OR_NULL(msm_host->bus_clk)) - clk_disable_unprepare(msm_host->bus_clk); + atomic_set(&msm_host->controller_clock, 0); remove_vote: if (msm_host->msm_bus_vote.client_handle) sdhci_msm_bus_cancel_work_and_set_vote(host, 0); @@ -2656,6 +2698,7 @@ static struct sdhci_ops sdhci_msm_ops = { .get_max_clock = sdhci_msm_get_max_clock, .dump_vendor_regs = sdhci_msm_dump_vendor_regs, .config_auto_tuning_cmd = sdhci_msm_config_auto_tuning_cmd, + .enable_controller_clock = sdhci_msm_enable_controller_clock, }; static int sdhci_msm_probe(struct platform_device *pdev) @@ -2734,6 +2777,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) if (ret) goto bus_clk_disable; } + atomic_set(&msm_host->controller_clock, 1); /* Setup SDC MMC clock */ msm_host->clk = devm_clk_get(&pdev->dev, "core_clk"); |
