Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit edc609fd authored by Ritesh Harjani's avatar Ritesh Harjani Committed by Ulf Hansson
Browse files

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: default avatarSahitya Tummala <stummala@codeaurora.org>
Signed-off-by: default avatarRitesh Harjani <riteshh@codeaurora.org>
Acked-by: default avatarAdrian Hunter <adrian.hunter@intel.com>
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent fec79673
Loading
Loading
Loading
Loading
+65 −1
Original line number Original line Diff line number Diff line
@@ -84,6 +84,7 @@ struct sdhci_msm_host {
	struct clk *pclk;	/* SDHC peripheral bus clock */
	struct clk *pclk;	/* SDHC peripheral bus clock */
	struct clk *bus_clk;	/* SDHC bus voter clock */
	struct clk *bus_clk;	/* SDHC bus voter clock */
	struct clk *xo_clk;	/* TCXO clk needed for FLL feature of cm_dll*/
	struct clk *xo_clk;	/* TCXO clk needed for FLL feature of cm_dll*/
	unsigned long clk_rate;
	struct mmc_host *mmc;
	struct mmc_host *mmc;
	bool use_14lpp_dll_reset;
	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;
	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[] = {
static const struct of_device_id sdhci_msm_dt_match[] = {
	{ .compatible = "qcom,sdhci-msm-v4" },
	{ .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 = {
static const struct sdhci_ops sdhci_msm_ops = {
	.platform_execute_tuning = sdhci_msm_execute_tuning,
	.platform_execute_tuning = sdhci_msm_execute_tuning,
	.reset = sdhci_reset,
	.reset = sdhci_reset,
	.set_clock = sdhci_set_clock,
	.set_clock = sdhci_msm_set_clock,
	.get_min_clock = sdhci_msm_get_min_clock,
	.get_min_clock = sdhci_msm_get_min_clock,
	.get_max_clock = sdhci_msm_get_max_clock,
	.get_max_clock = sdhci_msm_get_max_clock,
	.set_bus_width = sdhci_set_bus_width,
	.set_bus_width = sdhci_set_bus_width,