diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2007-08-20 05:20:03 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2007-10-12 16:15:03 -0400 |
commit | ebebd9b0a1463d5de89017ad59a6b9cd4044687f (patch) | |
tree | 20ca1b530967ee235f454e00706eb89ef597cb51 /drivers/mmc/host/pxamci.c | |
parent | 22d8a73a8b39ef236c80ea73704884f7a7862193 (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/host/pxamci.c')
-rw-r--r-- | drivers/mmc/host/pxamci.c | 43 |
1 files changed, 36 insertions, 7 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); |