mirror of https://gitee.com/openkylin/linux.git
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:
parent
fec7967397
commit
edc609fd19
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue