diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-15 19:08:50 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-15 19:08:50 -0400 |
commit | 65a6ec0d72a07f16719e9b7a96e1c4bae044b591 (patch) | |
tree | 344e03a5039a44982c1b78d6113633b21b434820 /drivers/mmc | |
parent | 541010e4b8921cd781ff02ae68028501457045b6 (diff) | |
parent | 0181b61a988424b5cc44fe09e6968142359c815e (diff) |
Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm: (95 commits)
[ARM] 4578/1: CM-x270: PCMCIA support
[ARM] 4577/1: ITE 8152 PCI bridge support
[ARM] 4576/1: CM-X270 machine support
[ARM] pxa: Avoid pxa_gpio_mode() in gpio_direction_{in,out}put()
[ARM] pxa: move pxa_set_mode() from pxa2xx_mainstone.c to mainstone.c
[ARM] pxa: move pxa_set_mode() from pxa2xx_lubbock.c to lubbock.c
[ARM] pxa: Make cpu_is_pxaXXX dependent on configuration symbols
[ARM] pxa: PXA3xx base support
[NET] smc91x: fix PXA DMA support code
[SERIAL] Fix console initialisation ordering
[ARM] pxa: tidy up arch/arm/mach-pxa/Makefile
[ARM] Update arch/arm/Kconfig for drivers/Kconfig changes
[ARM] 4600/1: fix kernel build failure with build-id-supporting binutils
[ARM] 4599/1: Preserve ATAG list for use with kexec (2.6.23)
[ARM] Rename consistent_sync() as dma_cache_maint()
[ARM] 4572/1: ep93xx: add cirrus logic edb9307 support
[ARM] 4596/1: S3C2412: Correct IRQs for SDI+CF and add decoding support
[ARM] 4595/1: ns9xxx: define registers as void __iomem * instead of volatile u32
[ARM] 4594/1: ns9xxx: use the new gpio functions
[ARM] 4593/1: ns9xxx: implement generic clockevents
...
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/pxamci.c | 43 | ||||
-rw-r--r-- | drivers/mmc/host/pxamci.h | 14 |
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 | |||