]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mmc/host/pxamci.c
mmc: fix platform driver hotplug/coldplug
[linux-2.6-omap-h63xx.git] / drivers / mmc / host / pxamci.c
index 0601e01aa2c20e1faf576015ad441ce695388dd6..65210fca37ede70f3c42199579b142e01a2a120c 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <asm/dma.h>
 #include <asm/io.h>
-#include <asm/scatterlist.h>
 #include <asm/sizes.h>
 
 #include <asm/arch/pxa-regs.h>
@@ -40,6 +39,7 @@
 #define DRIVER_NAME    "pxa2xx-mci"
 
 #define NR_SG  1
+#define CLKRT_OFF      (~0)
 
 struct pxamci_host {
        struct mmc_host         *mmc;
@@ -65,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)
@@ -131,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;
@@ -372,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) {
@@ -454,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);
@@ -499,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)) {
@@ -513,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 :
@@ -523,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);
@@ -564,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);
 
@@ -607,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);
@@ -658,6 +693,7 @@ static struct platform_driver pxamci_driver = {
        .resume         = pxamci_resume,
        .driver         = {
                .name   = DRIVER_NAME,
+               .owner  = THIS_MODULE,
        },
 };
 
@@ -676,3 +712,4 @@ module_exit(pxamci_exit);
 
 MODULE_DESCRIPTION("PXA Multimedia Card Interface Driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-mci");