aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/mmci.c
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2009-09-14 07:56:14 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-09-15 17:11:05 -0400
commita6a6464a0ecd20c5f1594a4fe5b24af6181b7366 (patch)
treef97039472b6a10b36d9e068e59f00c2bf290819e /drivers/mmc/host/mmci.c
parentbc581770cfdd8c17ea17d324dc05e2f9c599e7ca (diff)
ARM: 5697/1: MMCI Break out clock divider setup
This breaks out the clock divider set-up code from the mmci_set_ios() code and surrounds the two register writes with a host lock so we don't get collisions if (in future code) two code paths want to change the clock divider at the same time as can be the case if we get something like pre/post- clock frequency change notifications soonish. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mmc/host/mmci.c')
-rw-r--r--drivers/mmc/host/mmci.c51
1 files changed, 34 insertions, 17 deletions
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 8741d0f5146a..031141a7c87e 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -38,6 +38,33 @@
38 38
39static unsigned int fmax = 515633; 39static unsigned int fmax = 515633;
40 40
41/*
42 * This must be called with host->lock held
43 */
44static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
45{
46 u32 clk = 0;
47
48 if (desired) {
49 if (desired >= host->mclk) {
50 clk = MCI_CLK_BYPASS;
51 host->cclk = host->mclk;
52 } else {
53 clk = host->mclk / (2 * desired) - 1;
54 if (clk >= 256)
55 clk = 255;
56 host->cclk = host->mclk / (2 * (clk + 1));
57 }
58 if (host->hw_designer == 0x80)
59 clk |= MCI_FCEN; /* Bug fix in ST IP block */
60 clk |= MCI_CLK_ENABLE;
61 /* This hasn't proven to be worthwhile */
62 /* clk |= MCI_CLK_PWRSAVE; */
63 }
64
65 writel(clk, host->base + MMCICLOCK);
66}
67
41static void 68static void
42mmci_request_end(struct mmci_host *host, struct mmc_request *mrq) 69mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
43{ 70{
@@ -419,22 +446,8 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
419static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 446static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
420{ 447{
421 struct mmci_host *host = mmc_priv(mmc); 448 struct mmci_host *host = mmc_priv(mmc);
422 u32 clk = 0, pwr = 0; 449 u32 pwr = 0;
423 450 unsigned long flags;
424 if (ios->clock) {
425 if (ios->clock >= host->mclk) {
426 clk = MCI_CLK_BYPASS;
427 host->cclk = host->mclk;
428 } else {
429 clk = host->mclk / (2 * ios->clock) - 1;
430 if (clk >= 256)
431 clk = 255;
432 host->cclk = host->mclk / (2 * (clk + 1));
433 }
434 if (host->hw_designer == AMBA_VENDOR_ST)
435 clk |= MCI_FCEN; /* Bug fix in ST IP block */
436 clk |= MCI_CLK_ENABLE;
437 }
438 451
439 if (host->plat->translate_vdd) 452 if (host->plat->translate_vdd)
440 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd); 453 pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
@@ -465,12 +478,16 @@ static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
465 } 478 }
466 } 479 }
467 480
468 writel(clk, host->base + MMCICLOCK); 481 spin_lock_irqsave(&host->lock, flags);
482
483 mmci_set_clkreg(host, ios->clock);
469 484
470 if (host->pwr != pwr) { 485 if (host->pwr != pwr) {
471 host->pwr = pwr; 486 host->pwr = pwr;
472 writel(pwr, host->base + MMCIPOWER); 487 writel(pwr, host->base + MMCIPOWER);
473 } 488 }
489
490 spin_unlock_irqrestore(&host->lock, flags);
474} 491}
475 492
476static int mmci_get_ro(struct mmc_host *mmc) 493static int mmci_get_ro(struct mmc_host *mmc)