mmc: sdhci-msm: Implement set_clock callback for sdhci-msm

sdhci-msm controller may have different clk-rates for each
bus speed mode. Thus implement set_clock callback for
sdhci-msm driver.

Signed-off-by: Sahitya Tummala <stummala@codeaurora.org>
Signed-off-by: Ritesh Harjani <riteshh@codeaurora.org>
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
Ritesh Harjani 2016-11-21 12:07:20 +05:30 committed by Ulf Hansson
parent fec7967397
commit edc609fd19
1 changed files with 65 additions and 1 deletions

View File

@ -84,6 +84,7 @@ struct sdhci_msm_host {
struct clk *pclk; /* SDHC peripheral bus clock */
struct clk *bus_clk; /* SDHC bus voter clock */
struct clk *xo_clk; /* TCXO clk needed for FLL feature of cm_dll*/
unsigned long clk_rate;
struct mmc_host *mmc;
bool use_14lpp_dll_reset;
};
@ -571,6 +572,69 @@ static unsigned int sdhci_msm_get_min_clock(struct sdhci_host *host)
return SDHCI_MSM_MIN_CLOCK;
}
/**
* __sdhci_msm_set_clock - sdhci_msm clock control.
*
* Description:
* MSM controller does not use internal divider and
* instead directly control the GCC clock as per
* HW recommendation.
**/
void __sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
{
u16 clk;
/*
* Keep actual_clock as zero -
* - since there is no divider used so no need of having actual_clock.
* - MSM controller uses SDCLK for data timeout calculation. If
* actual_clock is zero, host->clock is taken for calculation.
*/
host->mmc->actual_clock = 0;
sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
if (clock == 0)
return;
/*
* MSM controller do not use clock divider.
* Thus read SDHCI_CLOCK_CONTROL and only enable
* clock with no divider value programmed.
*/
clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
sdhci_enable_clk(host, clk);
}
/* sdhci_msm_set_clock - Called with (host->lock) spinlock held. */
static void sdhci_msm_set_clock(struct sdhci_host *host, unsigned int clock)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
struct sdhci_msm_host *msm_host = sdhci_pltfm_priv(pltfm_host);
int rc;
if (!clock) {
msm_host->clk_rate = clock;
goto out;
}
spin_unlock_irq(&host->lock);
rc = clk_set_rate(msm_host->clk, clock);
if (rc) {
pr_err("%s: Failed to set clock at rate %u\n",
mmc_hostname(host->mmc), clock);
goto out_lock;
}
msm_host->clk_rate = clock;
pr_debug("%s: Setting clock at rate %lu\n",
mmc_hostname(host->mmc), clk_get_rate(msm_host->clk));
out_lock:
spin_lock_irq(&host->lock);
out:
__sdhci_msm_set_clock(host, clock);
}
static const struct of_device_id sdhci_msm_dt_match[] = {
{ .compatible = "qcom,sdhci-msm-v4" },
{},
@ -581,7 +645,7 @@ MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
static const struct sdhci_ops sdhci_msm_ops = {
.platform_execute_tuning = sdhci_msm_execute_tuning,
.reset = sdhci_reset,
.set_clock = sdhci_set_clock,
.set_clock = sdhci_msm_set_clock,
.get_min_clock = sdhci_msm_get_min_clock,
.get_max_clock = sdhci_msm_get_max_clock,
.set_bus_width = sdhci_set_bus_width,