Commit d982dcdc authored by Koen Beel's avatar Koen Beel Committed by Chris Ball

mmc: mxs-mmc: fix clock rate setting

Fix clock rate setting in the mxs-mmc driver. Previously, if div2 was 0
then the value for TIMING_CLOCK_RATE would have been 255 instead of 0.
The limits for div1 (TIMING_CLOCK_DIVIDE) and div2 (TIMING_CLOCK_RATE+1)
were also not correctly defined.

Can easily be reproduced on mx23evk: default clock for high speed sdio
cards is 50 MHz. With a SSP_CLK of 28.8 MHz default), this resulted in
an actual clock rate of about 56 kHz.  Tested on mx23evk.
Signed-off-by: default avatarKoen Beel <koen.beel@barco.com>
Reviewed-by: default avatarWolfram Sang <w.sang@pengutronix.de>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent 162f43e3
...@@ -564,40 +564,38 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ...@@ -564,40 +564,38 @@ static void mxs_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate) static void mxs_mmc_set_clk_rate(struct mxs_mmc_host *host, unsigned int rate)
{ {
unsigned int ssp_rate, bit_rate; unsigned int ssp_clk, ssp_sck;
u32 div1, div2; u32 clock_divide, clock_rate;
u32 val; u32 val;
ssp_rate = clk_get_rate(host->clk); ssp_clk = clk_get_rate(host->clk);
for (div1 = 2; div1 < 254; div1 += 2) { for (clock_divide = 2; clock_divide <= 254; clock_divide += 2) {
div2 = ssp_rate / rate / div1; clock_rate = DIV_ROUND_UP(ssp_clk, rate * clock_divide);
if (div2 < 0x100) clock_rate = (clock_rate > 0) ? clock_rate - 1 : 0;
if (clock_rate <= 255)
break; break;
} }
if (div1 >= 254) { if (clock_divide > 254) {
dev_err(mmc_dev(host->mmc), dev_err(mmc_dev(host->mmc),
"%s: cannot set clock to %d\n", __func__, rate); "%s: cannot set clock to %d\n", __func__, rate);
return; return;
} }
if (div2 == 0) ssp_sck = ssp_clk / clock_divide / (1 + clock_rate);
bit_rate = ssp_rate / div1;
else
bit_rate = ssp_rate / div1 / div2;
val = readl(host->base + HW_SSP_TIMING); val = readl(host->base + HW_SSP_TIMING);
val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE); val &= ~(BM_SSP_TIMING_CLOCK_DIVIDE | BM_SSP_TIMING_CLOCK_RATE);
val |= BF_SSP(div1, TIMING_CLOCK_DIVIDE); val |= BF_SSP(clock_divide, TIMING_CLOCK_DIVIDE);
val |= BF_SSP(div2 - 1, TIMING_CLOCK_RATE); val |= BF_SSP(clock_rate, TIMING_CLOCK_RATE);
writel(val, host->base + HW_SSP_TIMING); writel(val, host->base + HW_SSP_TIMING);
host->clk_rate = bit_rate; host->clk_rate = ssp_sck;
dev_dbg(mmc_dev(host->mmc), dev_dbg(mmc_dev(host->mmc),
"%s: div1 %d, div2 %d, ssp %d, bit %d, rate %d\n", "%s: clock_divide %d, clock_rate %d, ssp_clk %d, rate_actual %d, rate_requested %d\n",
__func__, div1, div2, ssp_rate, bit_rate, rate); __func__, clock_divide, clock_rate, ssp_clk, ssp_sck, rate);
} }
static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) static void mxs_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment