瀏覽代碼

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>
ludovic.desroches@atmel.com 10 年之前
父節點
當前提交
5497159c46
共有 1 個文件被更改,包括 20 次插入9 次删除
  1. 20 9
      drivers/mmc/host/sdhci.c

+ 20 - 9
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;
 	int real_div = div, clk_mul = 1;
 	u16 clk = 0;
 	u16 clk = 0;
 	unsigned long timeout;
 	unsigned long timeout;
+	bool switch_base_clk = false;
 
 
 	host->mmc->actual_clock = 0;
 	host->mmc->actual_clock = 0;
 
 
@@ -1188,15 +1189,25 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 					<= clock)
 					<= clock)
 					break;
 					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. */
 			/* Version 3.00 divisors must be a multiple of 2. */
 			if (host->max_clk <= clock)
 			if (host->max_clk <= clock)
 				div = 1;
 				div = 1;