aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/sdhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r--drivers/mmc/host/sdhci.c81
1 files changed, 66 insertions, 15 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index a1ab22415883..07cca557c4b5 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1013,8 +1013,8 @@ static void sdhci_finish_command(struct sdhci_host *host)
1013 1013
1014static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) 1014static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
1015{ 1015{
1016 int div; 1016 int div = 0; /* Initialized for compiler warning */
1017 u16 clk; 1017 u16 clk = 0;
1018 unsigned long timeout; 1018 unsigned long timeout;
1019 1019
1020 if (clock == host->clock) 1020 if (clock == host->clock)
@@ -1032,14 +1032,45 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
1032 goto out; 1032 goto out;
1033 1033
1034 if (host->version >= SDHCI_SPEC_300) { 1034 if (host->version >= SDHCI_SPEC_300) {
1035 /* Version 3.00 divisors must be a multiple of 2. */ 1035 /*
1036 if (host->max_clk <= clock) 1036 * Check if the Host Controller supports Programmable Clock
1037 div = 1; 1037 * Mode.
1038 else { 1038 */
1039 for (div = 2; div < SDHCI_MAX_DIV_SPEC_300; div += 2) { 1039 if (host->clk_mul) {
1040 if ((host->max_clk / div) <= clock) 1040 u16 ctrl;
1041 break; 1041
1042 /*
1043 * We need to figure out whether the Host Driver needs
1044 * to select Programmable Clock Mode, or the value can
1045 * be set automatically by the Host Controller based on
1046 * the Preset Value registers.
1047 */
1048 ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
1049 if (!(ctrl & SDHCI_CTRL_PRESET_VAL_ENABLE)) {
1050 for (div = 1; div <= 1024; div++) {
1051 if (((host->max_clk * host->clk_mul) /
1052 div) <= clock)
1053 break;
1054 }
1055 /*
1056 * Set Programmable Clock Mode in the Clock
1057 * Control register.
1058 */
1059 clk = SDHCI_PROG_CLOCK_MODE;
1060 div--;
1061 }
1062 } else {
1063 /* Version 3.00 divisors must be a multiple of 2. */
1064 if (host->max_clk <= clock)
1065 div = 1;
1066 else {
1067 for (div = 2; div < SDHCI_MAX_DIV_SPEC_300;
1068 div += 2) {
1069 if ((host->max_clk / div) <= clock)
1070 break;
1071 }
1042 } 1072 }
1073 div >>= 1;
1043 } 1074 }
1044 } else { 1075 } else {
1045 /* Version 2.00 divisors must be a power of 2. */ 1076 /* Version 2.00 divisors must be a power of 2. */
@@ -1047,10 +1078,10 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
1047 if ((host->max_clk / div) <= clock) 1078 if ((host->max_clk / div) <= clock)
1048 break; 1079 break;
1049 } 1080 }
1081 div >>= 1;
1050 } 1082 }
1051 div >>= 1;
1052 1083
1053 clk = (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; 1084 clk |= (div & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT;
1054 clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) 1085 clk |= ((div & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN)
1055 << SDHCI_DIVIDER_HI_SHIFT; 1086 << SDHCI_DIVIDER_HI_SHIFT;
1056 clk |= SDHCI_CLOCK_INT_EN; 1087 clk |= SDHCI_CLOCK_INT_EN;
@@ -2308,17 +2339,37 @@ int sdhci_add_host(struct sdhci_host *host)
2308 host->timeout_clk *= 1000; 2339 host->timeout_clk *= 1000;
2309 2340
2310 /* 2341 /*
2342 * In case of Host Controller v3.00, find out whether clock
2343 * multiplier is supported.
2344 */
2345 host->clk_mul = (caps[1] & SDHCI_CLOCK_MUL_MASK) >>
2346 SDHCI_CLOCK_MUL_SHIFT;
2347
2348 /*
2349 * In case the value in Clock Multiplier is 0, then programmable
2350 * clock mode is not supported, otherwise the actual clock
2351 * multiplier is one more than the value of Clock Multiplier
2352 * in the Capabilities Register.
2353 */
2354 if (host->clk_mul)
2355 host->clk_mul += 1;
2356
2357 /*
2311 * Set host parameters. 2358 * Set host parameters.
2312 */ 2359 */
2313 mmc->ops = &sdhci_ops; 2360 mmc->ops = &sdhci_ops;
2361 mmc->f_max = host->max_clk;
2314 if (host->ops->get_min_clock) 2362 if (host->ops->get_min_clock)
2315 mmc->f_min = host->ops->get_min_clock(host); 2363 mmc->f_min = host->ops->get_min_clock(host);
2316 else if (host->version >= SDHCI_SPEC_300) 2364 else if (host->version >= SDHCI_SPEC_300) {
2317 mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300; 2365 if (host->clk_mul) {
2318 else 2366 mmc->f_min = (host->max_clk * host->clk_mul) / 1024;
2367 mmc->f_max = host->max_clk * host->clk_mul;
2368 } else
2369 mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_300;
2370 } else
2319 mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200; 2371 mmc->f_min = host->max_clk / SDHCI_MAX_DIV_SPEC_200;
2320 2372
2321 mmc->f_max = host->max_clk;
2322 mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE; 2373 mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE;
2323 2374
2324 /* 2375 /*