summaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorludovic.desroches@atmel.com <ludovic.desroches@atmel.com>2015-07-29 16:22:46 +0200
committerUlf Hansson <ulf.hansson@linaro.org>2015-08-24 11:25:53 +0200
commit5497159c460fadf0d8190b6ef144ec22fa26aa6b (patch)
tree7f96b78d9b1b2ef162c22cc98b6cb07815aa4dfa /drivers/mmc
parent57e104864bc4874a36796fd222d8d084dbf90b9b (diff)
downloadop-kernel-dev-5497159c460fadf0d8190b6ef144ec22fa26aa6b.zip
op-kernel-dev-5497159c460fadf0d8190b6ef144ec22fa26aa6b.tar.gz
mmc: sdhci: switch from programmable clock mode to divided one if needed
In programmable mode, if the clock frequency is too high, the divider can be too small to meet the clock frequency requirement especially to init the SD card. In this case, switch to the divided clock mode. Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/sdhci.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index c83d110..0f1a887 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1151,6 +1151,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
int real_div = div, clk_mul = 1;
u16 clk = 0;
unsigned long timeout;
+ bool switch_base_clk = false;
host->mmc->actual_clock = 0;
@@ -1188,15 +1189,25 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
<= clock)
break;
}
- /*
- * Set Programmable Clock Mode in the Clock
- * Control register.
- */
- clk = SDHCI_PROG_CLOCK_MODE;
- real_div = div;
- clk_mul = host->clk_mul;
- div--;
- } else {
+ if ((host->max_clk * host->clk_mul / div) <= clock) {
+ /*
+ * Set Programmable Clock Mode in the Clock
+ * Control register.
+ */
+ clk = SDHCI_PROG_CLOCK_MODE;
+ real_div = div;
+ clk_mul = host->clk_mul;
+ div--;
+ } else {
+ /*
+ * Divisor can be too small to reach clock
+ * speed requirement. Then use the base clock.
+ */
+ switch_base_clk = true;
+ }
+ }
+
+ if (!host->clk_mul || switch_base_clk) {
/* Version 3.00 divisors must be a multiple of 2. */
if (host->max_clk <= clock)
div = 1;
OpenPOWER on IntegriCloud