diff options
-rw-r--r-- | drivers/mmc/host/sdhci.c | 81 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 3 | ||||
-rw-r--r-- | include/linux/mmc/sdhci.h | 1 |
3 files changed, 70 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 | ||
1014 | static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) | 1014 | static 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 | /* |
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index e62367491eee..6b0a0ee9ac6e 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h | |||
@@ -101,6 +101,7 @@ | |||
101 | #define SDHCI_DIV_MASK 0xFF | 101 | #define SDHCI_DIV_MASK 0xFF |
102 | #define SDHCI_DIV_MASK_LEN 8 | 102 | #define SDHCI_DIV_MASK_LEN 8 |
103 | #define SDHCI_DIV_HI_MASK 0x300 | 103 | #define SDHCI_DIV_HI_MASK 0x300 |
104 | #define SDHCI_PROG_CLOCK_MODE 0x0020 | ||
104 | #define SDHCI_CLOCK_CARD_EN 0x0004 | 105 | #define SDHCI_CLOCK_CARD_EN 0x0004 |
105 | #define SDHCI_CLOCK_INT_STABLE 0x0002 | 106 | #define SDHCI_CLOCK_INT_STABLE 0x0002 |
106 | #define SDHCI_CLOCK_INT_EN 0x0001 | 107 | #define SDHCI_CLOCK_INT_EN 0x0001 |
@@ -191,6 +192,8 @@ | |||
191 | #define SDHCI_DRIVER_TYPE_C 0x00000020 | 192 | #define SDHCI_DRIVER_TYPE_C 0x00000020 |
192 | #define SDHCI_DRIVER_TYPE_D 0x00000040 | 193 | #define SDHCI_DRIVER_TYPE_D 0x00000040 |
193 | #define SDHCI_USE_SDR50_TUNING 0x00002000 | 194 | #define SDHCI_USE_SDR50_TUNING 0x00002000 |
195 | #define SDHCI_CLOCK_MUL_MASK 0x00FF0000 | ||
196 | #define SDHCI_CLOCK_MUL_SHIFT 16 | ||
194 | 197 | ||
195 | #define SDHCI_CAPABILITIES_1 0x44 | 198 | #define SDHCI_CAPABILITIES_1 0x44 |
196 | 199 | ||
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index b74c8530e959..a88a799ed7c3 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h | |||
@@ -117,6 +117,7 @@ struct sdhci_host { | |||
117 | 117 | ||
118 | unsigned int max_clk; /* Max possible freq (MHz) */ | 118 | unsigned int max_clk; /* Max possible freq (MHz) */ |
119 | unsigned int timeout_clk; /* Timeout freq (KHz) */ | 119 | unsigned int timeout_clk; /* Timeout freq (KHz) */ |
120 | unsigned int clk_mul; /* Clock Muliplier value */ | ||
120 | 121 | ||
121 | unsigned int clock; /* Current clock (MHz) */ | 122 | unsigned int clock; /* Current clock (MHz) */ |
122 | u8 pwr; /* Current voltage */ | 123 | u8 pwr; /* Current voltage */ |