diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-15 16:08:50 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-15 16:08:50 -0700 |
commit | 65a6ec0d72a07f16719e9b7a96e1c4bae044b591 (patch) | |
tree | 344e03a5039a44982c1b78d6113633b21b434820 /drivers/mmc/host/pxamci.c | |
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/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 657901eecfc..0601e01aa2c 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -23,6 +23,8 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/dma-mapping.h> +#include <linux/clk.h> +#include <linux/err.h> #include <linux/mmc/host.h> #include <asm/dma.h> @@ -44,6 +46,8 @@ struct pxamci_host { spinlock_t lock; struct resource *res; void __iomem *base; + struct clk *clk; + unsigned long clkrate; int irq; int dma; unsigned int clkrt; @@ -119,7 +123,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) writel(nob, host->base + MMC_NOB); writel(data->blksz, host->base + MMC_BLKLEN); - clks = (unsigned long long)data->timeout_ns * CLOCKRATE; + clks = (unsigned long long)data->timeout_ns * host->clkrate; do_div(clks, 1000000000UL); timeout = (unsigned int)clks + (data->timeout_clks << host->clkrt); 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) struct pxamci_host *host = mmc_priv(mmc); if (ios->clock) { - unsigned int clk = CLOCKRATE / ios->clock; - if (CLOCKRATE / clk > ios->clock) + unsigned long rate = host->clkrate; + unsigned int clk = rate / ios->clock; + + /* + * clk might result in a lower divisor than we + * desire. check for that condition and adjust + * as appropriate. + */ + if (rate / clk > ios->clock) clk <<= 1; host->clkrt = fls(clk) - 1; - pxa_set_cken(CKEN_MMC, 1); + clk_enable(host->clk); /* * we write clkrt on the next command */ } else { pxamci_stop_clock(host); - pxa_set_cken(CKEN_MMC, 0); + clk_disable(host->clk); } if (host->power_mode != ios->power_mode) { @@ -462,8 +473,6 @@ static int pxamci_probe(struct platform_device *pdev) } mmc->ops = &pxamci_ops; - mmc->f_min = CLOCKRATE_MIN; - mmc->f_max = CLOCKRATE_MAX; /* * 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) host->mmc = mmc; host->dma = -1; host->pdata = pdev->dev.platform_data; + + host->clk = clk_get(&pdev->dev, "MMCCLK"); + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); + host->clk = NULL; + goto out; + } + + host->clkrate = clk_get_rate(host->clk); + + /* + * Calculate minimum clock rate, rounding up. + */ + mmc->f_min = (host->clkrate + 63) / 64; + mmc->f_max = host->clkrate; + mmc->ocr_avail = host->pdata ? host->pdata->ocr_mask : MMC_VDD_32_33|MMC_VDD_33_34; @@ -554,6 +579,8 @@ static int pxamci_probe(struct platform_device *pdev) iounmap(host->base); if (host->sg_cpu) dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); + if (host->clk) + clk_put(host->clk); } if (mmc) mmc_free_host(mmc); @@ -588,6 +615,8 @@ static int pxamci_remove(struct platform_device *pdev) iounmap(host->base); dma_free_coherent(&pdev->dev, PAGE_SIZE, host->sg_cpu, host->sg_dma); + clk_put(host->clk); + release_resource(host->res); mmc_free_host(mmc); |