diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-s3c.c')
-rw-r--r-- | drivers/mmc/host/sdhci-s3c.c | 62 |
1 files changed, 62 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c index a7710f557849..17203586305c 100644 --- a/drivers/mmc/host/sdhci-s3c.c +++ b/drivers/mmc/host/sdhci-s3c.c | |||
@@ -130,6 +130,15 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost, | |||
130 | if (!clksrc) | 130 | if (!clksrc) |
131 | return UINT_MAX; | 131 | return UINT_MAX; |
132 | 132 | ||
133 | /* | ||
134 | * Clock divider's step is different as 1 from that of host controller | ||
135 | * when 'clk_type' is S3C_SDHCI_CLK_DIV_EXTERNAL. | ||
136 | */ | ||
137 | if (ourhost->pdata->clk_type) { | ||
138 | rate = clk_round_rate(clksrc, wanted); | ||
139 | return wanted - rate; | ||
140 | } | ||
141 | |||
133 | rate = clk_get_rate(clksrc); | 142 | rate = clk_get_rate(clksrc); |
134 | 143 | ||
135 | for (div = 1; div < 256; div *= 2) { | 144 | for (div = 1; div < 256; div *= 2) { |
@@ -232,6 +241,42 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host) | |||
232 | return min; | 241 | return min; |
233 | } | 242 | } |
234 | 243 | ||
244 | /* sdhci_cmu_get_max_clk - callback to get maximum clock frequency.*/ | ||
245 | static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host) | ||
246 | { | ||
247 | struct sdhci_s3c *ourhost = to_s3c(host); | ||
248 | |||
249 | return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX); | ||
250 | } | ||
251 | |||
252 | /* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */ | ||
253 | static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host) | ||
254 | { | ||
255 | struct sdhci_s3c *ourhost = to_s3c(host); | ||
256 | |||
257 | /* | ||
258 | * initial clock can be in the frequency range of | ||
259 | * 100KHz-400KHz, so we set it as max value. | ||
260 | */ | ||
261 | return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000); | ||
262 | } | ||
263 | |||
264 | /* sdhci_cmu_set_clock - callback on clock change.*/ | ||
265 | static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock) | ||
266 | { | ||
267 | struct sdhci_s3c *ourhost = to_s3c(host); | ||
268 | |||
269 | /* don't bother if the clock is going off */ | ||
270 | if (clock == 0) | ||
271 | return; | ||
272 | |||
273 | sdhci_s3c_set_clock(host, clock); | ||
274 | |||
275 | clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock); | ||
276 | |||
277 | host->clock = clock; | ||
278 | } | ||
279 | |||
235 | static struct sdhci_ops sdhci_s3c_ops = { | 280 | static struct sdhci_ops sdhci_s3c_ops = { |
236 | .get_max_clock = sdhci_s3c_get_max_clk, | 281 | .get_max_clock = sdhci_s3c_get_max_clk, |
237 | .set_clock = sdhci_s3c_set_clock, | 282 | .set_clock = sdhci_s3c_set_clock, |
@@ -361,6 +406,13 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
361 | 406 | ||
362 | clks++; | 407 | clks++; |
363 | sc->clk_bus[ptr] = clk; | 408 | sc->clk_bus[ptr] = clk; |
409 | |||
410 | /* | ||
411 | * save current clock index to know which clock bus | ||
412 | * is used later in overriding functions. | ||
413 | */ | ||
414 | sc->cur_clk = ptr; | ||
415 | |||
364 | clk_enable(clk); | 416 | clk_enable(clk); |
365 | 417 | ||
366 | dev_info(dev, "clock source %d: %s (%ld Hz)\n", | 418 | dev_info(dev, "clock source %d: %s (%ld Hz)\n", |
@@ -427,6 +479,16 @@ static int __devinit sdhci_s3c_probe(struct platform_device *pdev) | |||
427 | /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */ | 479 | /* HSMMC on Samsung SoCs uses SDCLK as timeout clock */ |
428 | host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; | 480 | host->quirks |= SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK; |
429 | 481 | ||
482 | /* | ||
483 | * If controller does not have internal clock divider, | ||
484 | * we can use overriding functions instead of default. | ||
485 | */ | ||
486 | if (pdata->clk_type) { | ||
487 | sdhci_s3c_ops.set_clock = sdhci_cmu_set_clock; | ||
488 | sdhci_s3c_ops.get_min_clock = sdhci_cmu_get_min_clock; | ||
489 | sdhci_s3c_ops.get_max_clock = sdhci_cmu_get_max_clock; | ||
490 | } | ||
491 | |||
430 | /* It supports additional host capabilities if needed */ | 492 | /* It supports additional host capabilities if needed */ |
431 | if (pdata->host_caps) | 493 | if (pdata->host_caps) |
432 | host->mmc->caps |= pdata->host_caps; | 494 | host->mmc->caps |= pdata->host_caps; |