diff options
Diffstat (limited to 'drivers/mmc/host/pxamci.c')
-rw-r--r-- | drivers/mmc/host/pxamci.c | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 1654a3330340..1ea8482037bb 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c | |||
@@ -65,6 +65,8 @@ struct pxamci_host { | |||
65 | unsigned int dma_len; | 65 | unsigned int dma_len; |
66 | 66 | ||
67 | unsigned int dma_dir; | 67 | unsigned int dma_dir; |
68 | unsigned int dma_drcmrrx; | ||
69 | unsigned int dma_drcmrtx; | ||
68 | }; | 70 | }; |
69 | 71 | ||
70 | static void pxamci_stop_clock(struct pxamci_host *host) | 72 | static void pxamci_stop_clock(struct pxamci_host *host) |
@@ -131,13 +133,13 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) | |||
131 | if (data->flags & MMC_DATA_READ) { | 133 | if (data->flags & MMC_DATA_READ) { |
132 | host->dma_dir = DMA_FROM_DEVICE; | 134 | host->dma_dir = DMA_FROM_DEVICE; |
133 | dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; | 135 | dcmd = DCMD_INCTRGADDR | DCMD_FLOWTRG; |
134 | DRCMRTXMMC = 0; | 136 | DRCMR(host->dma_drcmrtx) = 0; |
135 | DRCMRRXMMC = host->dma | DRCMR_MAPVLD; | 137 | DRCMR(host->dma_drcmrrx) = host->dma | DRCMR_MAPVLD; |
136 | } else { | 138 | } else { |
137 | host->dma_dir = DMA_TO_DEVICE; | 139 | host->dma_dir = DMA_TO_DEVICE; |
138 | dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; | 140 | dcmd = DCMD_INCSRCADDR | DCMD_FLOWSRC; |
139 | DRCMRRXMMC = 0; | 141 | DRCMR(host->dma_drcmrrx) = 0; |
140 | DRCMRTXMMC = host->dma | DRCMR_MAPVLD; | 142 | DRCMR(host->dma_drcmrtx) = host->dma | DRCMR_MAPVLD; |
141 | } | 143 | } |
142 | 144 | ||
143 | dcmd |= DCMD_BURST32 | DCMD_WIDTH1; | 145 | dcmd |= DCMD_BURST32 | DCMD_WIDTH1; |
@@ -375,14 +377,23 @@ static void pxamci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | |||
375 | if (host->clkrt == CLKRT_OFF) | 377 | if (host->clkrt == CLKRT_OFF) |
376 | clk_enable(host->clk); | 378 | clk_enable(host->clk); |
377 | 379 | ||
378 | /* | 380 | if (ios->clock == 26000000) { |
379 | * clk might result in a lower divisor than we | 381 | /* to support 26MHz on pxa300/pxa310 */ |
380 | * desire. check for that condition and adjust | 382 | host->clkrt = 7; |
381 | * as appropriate. | 383 | } else { |
382 | */ | 384 | /* to handle (19.5MHz, 26MHz) */ |
383 | if (rate / clk > ios->clock) | 385 | if (!clk) |
384 | clk <<= 1; | 386 | clk = 1; |
385 | host->clkrt = fls(clk) - 1; | 387 | |
388 | /* | ||
389 | * clk might result in a lower divisor than we | ||
390 | * desire. check for that condition and adjust | ||
391 | * as appropriate. | ||
392 | */ | ||
393 | if (rate / clk > ios->clock) | ||
394 | clk <<= 1; | ||
395 | host->clkrt = fls(clk) - 1; | ||
396 | } | ||
386 | 397 | ||
387 | /* | 398 | /* |
388 | * we write clkrt on the next command | 399 | * we write clkrt on the next command |
@@ -459,7 +470,7 @@ static int pxamci_probe(struct platform_device *pdev) | |||
459 | { | 470 | { |
460 | struct mmc_host *mmc; | 471 | struct mmc_host *mmc; |
461 | struct pxamci_host *host = NULL; | 472 | struct pxamci_host *host = NULL; |
462 | struct resource *r; | 473 | struct resource *r, *dmarx, *dmatx; |
463 | int ret, irq; | 474 | int ret, irq; |
464 | 475 | ||
465 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 476 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -519,7 +530,8 @@ static int pxamci_probe(struct platform_device *pdev) | |||
519 | * Calculate minimum clock rate, rounding up. | 530 | * Calculate minimum clock rate, rounding up. |
520 | */ | 531 | */ |
521 | mmc->f_min = (host->clkrate + 63) / 64; | 532 | mmc->f_min = (host->clkrate + 63) / 64; |
522 | mmc->f_max = host->clkrate; | 533 | mmc->f_max = (cpu_is_pxa300() || cpu_is_pxa310()) ? 26000000 |
534 | : host->clkrate; | ||
523 | 535 | ||
524 | mmc->ocr_avail = host->pdata ? | 536 | mmc->ocr_avail = host->pdata ? |
525 | host->pdata->ocr_mask : | 537 | host->pdata->ocr_mask : |
@@ -529,6 +541,9 @@ static int pxamci_probe(struct platform_device *pdev) | |||
529 | if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) { | 541 | if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) { |
530 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; | 542 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; |
531 | host->cmdat |= CMDAT_SDIO_INT_EN; | 543 | host->cmdat |= CMDAT_SDIO_INT_EN; |
544 | if (cpu_is_pxa300() || cpu_is_pxa310()) | ||
545 | mmc->caps |= MMC_CAP_MMC_HIGHSPEED | | ||
546 | MMC_CAP_SD_HIGHSPEED; | ||
532 | } | 547 | } |
533 | 548 | ||
534 | host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); | 549 | host->sg_cpu = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, &host->sg_dma, GFP_KERNEL); |
@@ -570,6 +585,20 @@ static int pxamci_probe(struct platform_device *pdev) | |||
570 | 585 | ||
571 | platform_set_drvdata(pdev, mmc); | 586 | platform_set_drvdata(pdev, mmc); |
572 | 587 | ||
588 | dmarx = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
589 | if (!dmarx) { | ||
590 | ret = -ENXIO; | ||
591 | goto out; | ||
592 | } | ||
593 | host->dma_drcmrrx = dmarx->start; | ||
594 | |||
595 | dmatx = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
596 | if (!dmatx) { | ||
597 | ret = -ENXIO; | ||
598 | goto out; | ||
599 | } | ||
600 | host->dma_drcmrtx = dmatx->start; | ||
601 | |||
573 | if (host->pdata && host->pdata->init) | 602 | if (host->pdata && host->pdata->init) |
574 | host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); | 603 | host->pdata->init(&pdev->dev, pxamci_detect_irq, mmc); |
575 | 604 | ||
@@ -613,8 +642,8 @@ static int pxamci_remove(struct platform_device *pdev) | |||
613 | END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, | 642 | END_CMD_RES|PRG_DONE|DATA_TRAN_DONE, |
614 | host->base + MMC_I_MASK); | 643 | host->base + MMC_I_MASK); |
615 | 644 | ||
616 | DRCMRRXMMC = 0; | 645 | DRCMR(host->dma_drcmrrx) = 0; |
617 | DRCMRTXMMC = 0; | 646 | DRCMR(host->dma_drcmrtx) = 0; |
618 | 647 | ||
619 | free_irq(host->irq, host); | 648 | free_irq(host->irq, host); |
620 | pxa_free_dma(host->dma); | 649 | pxa_free_dma(host->dma); |