diff options
-rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 59 |
1 files changed, 42 insertions, 17 deletions
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 11ecd98fcbb1..572f14676170 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -1389,10 +1389,20 @@ static void sdhci_msm_bus_voting(struct sdhci_host *host, u32 enable) return; bw = sdhci_get_bw_required(host, ios); - if (enable) + if (enable) { sdhci_msm_bus_cancel_work_and_set_vote(host, bw); - else - sdhci_msm_bus_queue_work(host); + } else { + /* + * If clock gating is enabled, then remove the vote + * immediately because clocks will be disabled only + * after SDHCI_MSM_MMC_CLK_GATE_DELAY and thus no + * additional delay is required to remove the bus vote. + */ + if (host->mmc->clkgate_delay) + sdhci_msm_bus_cancel_work_and_set_vote(host, 0); + else + sdhci_msm_bus_queue_work(host); + } } /* Regulator utility functions */ @@ -1901,12 +1911,15 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable) if (enable && !atomic_read(&msm_host->clks_on)) { pr_debug("%s: request to enable clocks\n", mmc_hostname(host->mmc)); + + sdhci_msm_bus_voting(host, 1); + 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 out; + goto remove_vote; } } if (!IS_ERR(msm_host->pclk)) { @@ -1935,6 +1948,8 @@ static int sdhci_msm_prepare_clocks(struct sdhci_host *host, bool enable) clk_disable_unprepare(msm_host->pclk); if (!IS_ERR_OR_NULL(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); + + sdhci_msm_bus_voting(host, 0); } atomic_set(&msm_host->clks_on, enable); goto out; @@ -1944,6 +1959,9 @@ disable_pclk: disable_bus_clk: if (!IS_ERR_OR_NULL(msm_host->bus_clk)) clk_disable_unprepare(msm_host->bus_clk); +remove_vote: + if (msm_host->msm_bus_vote.client_handle) + sdhci_msm_bus_cancel_work_and_set_vote(host, 0); out: return rc; } @@ -1990,6 +2008,11 @@ static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock) } msm_host->clk_rate = sup_clock; host->clock = clock; + /* + * Update the bus vote in case of frequency change due to + * clock scaling. + */ + sdhci_msm_bus_voting(host, 1); } out: sdhci_set_clock(host, clock); @@ -2037,7 +2060,6 @@ static struct sdhci_ops sdhci_msm_ops = { .toggle_cdr = sdhci_msm_toggle_cdr, .get_max_segments = sdhci_msm_max_segs, .set_clock = sdhci_msm_set_clock, - .platform_bus_voting = sdhci_msm_bus_voting, .get_min_clock = sdhci_msm_get_min_clock, .get_max_clock = sdhci_msm_get_max_clock, }; @@ -2139,11 +2161,20 @@ static int sdhci_msm_probe(struct platform_device *pdev) msm_host->clk_rate = sdhci_msm_get_min_clock(host); atomic_set(&msm_host->clks_on, 1); + ret = sdhci_msm_bus_register(msm_host, pdev); + if (ret) + goto clk_disable; + + if (msm_host->msm_bus_vote.client_handle) + INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work, + sdhci_msm_bus_work); + sdhci_msm_bus_voting(host, 1); + /* Setup regulators */ ret = sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, true); if (ret) { dev_err(&pdev->dev, "Regulator setup failed (%d)\n", ret); - goto clk_disable; + goto bus_unregister; } /* Reset the core and Enable SDHC mode */ @@ -2271,14 +2302,6 @@ static int sdhci_msm_probe(struct platform_device *pdev) host->cpu_dma_latency_us = msm_host->pdata->cpu_dma_latency_us; - ret = sdhci_msm_bus_register(msm_host, pdev); - if (ret) - goto vreg_deinit; - - if (msm_host->msm_bus_vote.client_handle) - INIT_DELAYED_WORK(&msm_host->msm_bus_vote.vote_work, - sdhci_msm_bus_work); - init_completion(&msm_host->pwr_irq_completion); if (gpio_is_valid(msm_host->pdata->status_gpio)) { @@ -2287,7 +2310,7 @@ static int sdhci_msm_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "%s: Failed to request card detection IRQ %d\n", __func__, ret); - goto bus_unregister; + goto vreg_deinit; } } @@ -2323,10 +2346,12 @@ remove_host: free_cd_gpio: if (gpio_is_valid(msm_host->pdata->status_gpio)) mmc_gpio_free_cd(msm_host->mmc); -bus_unregister: - sdhci_msm_bus_unregister(msm_host); vreg_deinit: sdhci_msm_vreg_init(&pdev->dev, msm_host->pdata, false); +bus_unregister: + if (msm_host->msm_bus_vote.client_handle) + sdhci_msm_bus_cancel_work_and_set_vote(host, 0); + sdhci_msm_bus_unregister(msm_host); clk_disable: if (!IS_ERR(msm_host->clk)) clk_disable_unprepare(msm_host->clk); |