aboutsummaryrefslogtreecommitdiff
path: root/drivers/mmc/host/pxamci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/pxamci.c')
-rw-r--r--drivers/mmc/host/pxamci.c72
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);