diff options
Diffstat (limited to 'drivers/mmc/host/pxamci.c')
-rw-r--r-- | drivers/mmc/host/pxamci.c | 72 |
1 files changed, 54 insertions, 18 deletions
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index a25ee71998a..1ea8482037b 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c @@ -39,6 +39,7 @@ #define DRIVER_NAME "pxa2xx-mci" #define NR_SG 1 +#define CLKRT_OFF (~0) struct pxamci_host { struct mmc_host *mmc; @@ -64,6 +65,8 @@ struct pxamci_host { unsigned int dma_len; unsigned int dma_dir; + unsigned int dma_drcmrrx; + unsigned int dma_drcmrtx; }; static void pxamci_stop_clock(struct pxamci_host *host) @@ -130,13 +133,13 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) if (data->flags & MMC_DATA_READ) { host->dma_dir = DMA_FROM_DEVICE; dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; - DRCMRTXMMC = 0; - DRCMRRXMMC = host->dma | DRCMR_MAPVLD; + DRCMR(host->dma_drcmrtx) = 0; + DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD; } else { host->dma_dir = DMA_TO_DEVICE; dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; - DRCMRRXMMC = 0; - DRCMRTXMMC = host->dma | DRCMR_MAPVLD; + DRCMR(host->dma_drcmrrx) = 0; + DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD; } dcmd |= DCMD_BURST32 | DCMD_WIDTH1; @@ -371,22 +374,36 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 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; - clk_enable(host->clk); + if (host->clkrt == CLKRT_OFF) + clk_enable(host->clk); + + if (ios->clock == 26000000) { + /* to support 26MHz on pxa300/pxa310 */ + host->clkrt = 7; + } else { + /* to handle (19.5MHz, 26MHz) */ + if (!clk) + clk = 1; + + /* + * 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; + } /* * we write clkrt on the next command */ } else { pxamci_stop_clock(host); - clk_disable(host->clk); + if (host->clkrt != CLKRT_OFF) { + host->clkrt = CLKRT_OFF; + clk_disable(host->clk); + } } if (host->power_mode != ios->power_mode) { @@ -453,7 +470,7 @@ static int pxamci_probe(struct platform_device *pdev) { struct mmc_host *mmc; struct pxamci_host *host = NULL; - struct resource *r; + struct resource *r, *dmarx, *dmatx; int ret, irq; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -498,6 +515,7 @@ static int pxamci_probe(struct platform_device *pdev) host->mmc = mmc; host->dma = -1; host->pdata = pdev->dev.platform_data; + host->clkrt = CLKRT_OFF; host->clk = clk_get(&pdev->dev, "MMCCLK"); if (IS_ERR(host->clk)) { @@ -512,7 +530,8 @@ static int pxamci_probe(struct platform_device *pdev) * Calculate minimum clock rate, rounding up. */ mmc->f_min = (host->clkrate + 63) / 64; - mmc->f_max = host->clkrate; + mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000 + : host->clkrate; mmc->ocr_avail = host->pdata ? host->pdata->ocr_mask : @@ -522,6 +541,9 @@ static int pxamci_probe(struct platform_device *pdev) if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) { mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; host->cmdat |= CMDAT_SDIO_INT_EN; + if (cpu_is_pxa300() || cpu_is_pxa310()) + mmc->caps |= MMC_CAP_MMC_HIGHSPEED | + MMC_CAP_SD_HIGHSPEED; } host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); @@ -563,6 +585,20 @@ static int pxamci_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mmc); + dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); + if (!dmarx) { + ret = -ENXIO; + goto out; + } + host->dma_drcmrrx = dmarx->start; + + dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1); + if (!dmatx) { + ret = -ENXIO; + goto out; + } + host->dma_drcmrtx = dmatx->start; + if (host->pdata && host->pdata->init) host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); @@ -606,8 +642,8 @@ static int pxamci_remove(struct platform_device *pdev) END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, host->base + MMC_I_MASK); - DRCMRRXMMC = 0; - DRCMRTXMMC = 0; + DRCMR(host->dma_drcmrrx) = 0; + DRCMR(host->dma_drcmrtx) = 0; free_irq(host->irq, host); pxa_free_dma(host->dma); |