aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2007-08-20 05:20:03 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2007-10-12 16:15:03 -0400
commitebebd9b0a1463d5de89017ad59a6b9cd4044687f (patch)
tree20ca1b530967ee235f454e00706eb89ef597cb51 /drivers/mmc
parent22d8a73a8b39ef236c80ea73704884f7a7862193 (diff)
[ARM] pxa: update PXA MMC interface driver to use clk support
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mmc')
-rw-r--r--drivers/mmc/host/pxamci.c43
-rw-r--r--drivers/mmc/host/pxamci.h14
2 files changed, 36 insertions, 21 deletions
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c
index 657901eecfce..0601e01aa2c2 100644
--- a/drivers/mmc/host/pxamci.c
+++ b/drivers/mmc/host/pxamci.c
@@ -23,6 +23,8 @@
23#include <linux/delay.h> 23#include <linux/delay.h>
24#include <linux/interrupt.h> 24#include <linux/interrupt.h>
25#include <linux/dma-mapping.h> 25#include <linux/dma-mapping.h>
26#include <linux/clk.h>
27#include <linux/err.h>
26#include <linux/mmc/host.h> 28#include <linux/mmc/host.h>
27 29
28#include <asm/dma.h> 30#include <asm/dma.h>
@@ -44,6 +46,8 @@ struct pxamci_host {
44 spinlock_t lock; 46 spinlock_t lock;
45 struct resource *res; 47 struct resource *res;
46 void __iomem *base; 48 void __iomem *base;
49 struct clk *clk;
50 unsigned long clkrate;
47 int irq; 51 int irq;
48 int dma; 52 int dma;
49 unsigned int clkrt; 53 unsigned int clkrt;
@@ -119,7 +123,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
119 writel(nob, host->base + MMC_NOB); 123 writel(nob, host->base + MMC_NOB);
120 writel(data->blksz, host->base + MMC_BLKLEN); 124 writel(data->blksz, host->base + MMC_BLKLEN);
121 125
122 clks = (unsigned long long)data->timeout_ns * CLOCKRATE; 126 clks = (unsigned long long)data->timeout_ns * host->clkrate;
123 do_div(clks, 1000000000UL); 127 do_div(clks, 1000000000UL);
124 timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); 128 timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt);
125 writel((timeout + 255) / 256, host->base + MMC_RDTO); 129 writel((timeout + 255) / 256, host->base + MMC_RDTO);
@@ -365,18 +369,25 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
365 struct pxamci_host *host = mmc_priv(mmc); 369 struct pxamci_host *host = mmc_priv(mmc);
366 370
367 if (ios->clock) { 371 if (ios->clock) {
368 unsigned int clk = CLOCKRATE / ios->clock; 372 unsigned long rate = host->clkrate;
369 if (CLOCKRATE / clk > ios->clock) 373 unsigned int clk = rate / ios->clock;
374
375 /*
376 * clk might result in a lower divisor than we
377 * desire. check for that condition and adjust
378 * as appropriate.
379 */
380 if (rate / clk > ios->clock)
370 clk <<= 1; 381 clk <<= 1;
371 host->clkrt = fls(clk) - 1; 382 host->clkrt = fls(clk) - 1;
372 pxa_set_cken(CKEN_MMC, 1); 383 clk_enable(host->clk);
373 384
374 /* 385 /*
375 * we write clkrt on the next command 386 * we write clkrt on the next command
376 */ 387 */
377 } else { 388 } else {
378 pxamci_stop_clock(host); 389 pxamci_stop_clock(host);
379 pxa_set_cken(CKEN_MMC, 0); 390 clk_disable(host->clk);
380 } 391 }
381 392
382 if (host->power_mode != ios->power_mode) { 393 if (host->power_mode != ios->power_mode) {
@@ -462,8 +473,6 @@ static int pxamci_probe(struct platform_device *pdev)
462 } 473 }
463 474
464 mmc->ops = &pxamci_ops; 475 mmc->ops = &pxamci_ops;
465 mmc->f_min = CLOCKRATE_MIN;
466 mmc->f_max = CLOCKRATE_MAX;
467 476
468 /* 477 /*
469 * We can do SG-DMA, but we don't because we never know how much 478 * We can do SG-DMA, but we don't because we never know how much
@@ -490,6 +499,22 @@ static int pxamci_probe(struct platform_device *pdev)
490 host->mmc = mmc; 499 host->mmc = mmc;
491 host->dma = -1; 500 host->dma = -1;
492 host->pdata = pdev->dev.platform_data; 501 host->pdata = pdev->dev.platform_data;
502
503 host->clk = clk_get(&pdev->dev, "MMCCLK");
504 if (IS_ERR(host->clk)) {
505 ret = PTR_ERR(host->clk);
506 host->clk = NULL;
507 goto out;
508 }
509
510 host->clkrate = clk_get_rate(host->clk);
511
512 /*
513 * Calculate minimum clock rate, rounding up.
514 */
515 mmc->f_min = (host->clkrate + 63) / 64;
516 mmc->f_max = host->clkrate;
517
493 mmc->ocr_avail = host->pdata ? 518 mmc->ocr_avail = host->pdata ?
494 host->pdata->ocr_mask : 519 host->pdata->ocr_mask :
495 MMC_VDD_32_33|MMC_VDD_33_34; 520 MMC_VDD_32_33|MMC_VDD_33_34;
@@ -554,6 +579,8 @@ static int pxamci_probe(struct platform_device *pdev)
554 iounmap(host->base); 579 iounmap(host->base);
555 if (host->sg_cpu) 580 if (host->sg_cpu)
556 dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 581 dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
582 if (host->clk)
583 clk_put(host->clk);
557 } 584 }
558 if (mmc) 585 if (mmc)
559 mmc_free_host(mmc); 586 mmc_free_host(mmc);
@@ -588,6 +615,8 @@ static int pxamci_remove(struct platform_device *pdev)
588 iounmap(host->base); 615 iounmap(host->base);
589 dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); 616 dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma);
590 617
618 clk_put(host->clk);
619
591 release_resource(host->res); 620 release_resource(host->res);
592 621
593 mmc_free_host(mmc); 622 mmc_free_host(mmc);
diff --git a/drivers/mmc/host/pxamci.h b/drivers/mmc/host/pxamci.h
index 3153e779d46a..748c7706f237 100644
--- a/drivers/mmc/host/pxamci.h
+++ b/drivers/mmc/host/pxamci.h
@@ -88,17 +88,3 @@
88#define MMC_RXFIFO 0x0040 /* 8 bit */ 88#define MMC_RXFIFO 0x0040 /* 8 bit */
89 89
90#define MMC_TXFIFO 0x0044 /* 8 bit */ 90#define MMC_TXFIFO 0x0044 /* 8 bit */
91
92/*
93 * The base MMC clock rate
94 */
95#ifdef CONFIG_PXA27x
96#define CLOCKRATE_MIN 304688
97#define CLOCKRATE_MAX 19500000
98#else
99#define CLOCKRATE_MIN 312500
100#define CLOCKRATE_MAX 20000000
101#endif
102
103#define CLOCKRATE CLOCKRATE_MAX
104