]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mmc/host/omap_hsmmc.c
Merge branch 'omap-fixes'
[linux-2.6-omap-h63xx.git] / drivers / mmc / host / omap_hsmmc.c
index 483e591f7bbb51a0cd38af4ea94c2f10168c16dc..84554db12e73d3a3a4b9ff19a1f8aa6ccd030418 100644 (file)
@@ -77,6 +77,7 @@
 #define MSBS                   (1 << 5)
 #define BCE                    (1 << 1)
 #define FOUR_BIT               (1 << 1)
+#define DW8                    (1 << 5)
 #define CC                     0x1
 #define TC                     0x02
 #define OD                     0x1
  */
 #define OMAP_MMC1_DEVID                0
 #define OMAP_MMC2_DEVID                1
+#define OMAP_MMC3_DEVID                2
 
 #define MMC_TIMEOUT_MS         20
 #define OMAP_MMC_MASTER_CLOCK  96000000
@@ -143,6 +145,7 @@ struct mmc_omap_host {
        int                     irq;
        int                     carddetect;
        int                     use_dma, dma_ch;
+       int                     dma_line_tx, dma_line_rx;
        int                     slot_id;
        int                     dbclk_enabled;
        int                     response_busy;
@@ -215,7 +218,7 @@ mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr,
        struct mmc_omap_host *host = mmc_priv(mmc);
        struct omap_mmc_slot_data slot = host->pdata->slots[host->slot_id];
 
-       return sprintf(buf, "slot:%s\n", slot.name);
+       return sprintf(buf, "%s\n", slot.name);
 }
 
 static DEVICE_ATTR(slot_name, S_IRUGO, mmc_omap_show_slot_name, NULL);
@@ -431,6 +434,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
        if (host->mrq == NULL) {
                OMAP_HSMMC_WRITE(host->base, STAT,
                        OMAP_HSMMC_READ(host->base, STAT));
+               /* Flush posted write */
+               OMAP_HSMMC_READ(host->base, STAT);
                return IRQ_HANDLED;
        }
 
@@ -486,6 +491,8 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
        }
 
        OMAP_HSMMC_WRITE(host->base, STAT, status);
+       /* Flush posted write */
+       OMAP_HSMMC_READ(host->base, STAT);
 
        if (end_cmd || (status & CC))
                mmc_omap_cmd_done(host, host->cmd);
@@ -495,6 +502,19 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
+static void set_sd_bus_power(struct mmc_omap_host *host)
+{
+       unsigned long i;
+
+       OMAP_HSMMC_WRITE(host->base, HCTL,
+                        OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+       for (i = 0; i < loops_per_jiffy; i++) {
+               if (OMAP_HSMMC_READ(host->base, HCTL) & SDBP)
+                       break;
+               cpu_relax();
+       }
+}
+
 /*
  * Switch MMC interface voltage ... only relevant for MMC1.
  *
@@ -551,9 +571,7 @@ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
                reg_val |= SDVS30;
 
        OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
-
-       OMAP_HSMMC_WRITE(host->base, HCTL,
-               OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
+       set_sd_bus_power(host);
 
        return 0;
 err:
@@ -570,7 +588,10 @@ static void mmc_omap_detect(struct work_struct *work)
                                                mmc_carddetect_work);
        struct omap_mmc_slot_data *slot = &mmc_slot(host);
 
-       host->carddetect = slot->card_detect(slot->card_detect_irq);
+       if (mmc_slot(host).card_detect)
+               host->carddetect = slot->card_detect(slot->card_detect_irq);
+       else
+               host->carddetect = -ENOSYS;
 
        sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
        if (host->carddetect) {
@@ -598,17 +619,10 @@ static int mmc_omap_get_dma_sync_dev(struct mmc_omap_host *host,
 {
        int sync_dev;
 
-       if (data->flags & MMC_DATA_WRITE) {
-               if (host->id == OMAP_MMC1_DEVID)
-                       sync_dev = OMAP24XX_DMA_MMC1_TX;
-               else
-                       sync_dev = OMAP24XX_DMA_MMC2_TX;
-       } else {
-               if (host->id == OMAP_MMC1_DEVID)
-                       sync_dev = OMAP24XX_DMA_MMC1_RX;
-               else
-                       sync_dev = OMAP24XX_DMA_MMC2_RX;
-       }
+       if (data->flags & MMC_DATA_WRITE)
+               sync_dev = host->dma_line_tx;
+       else
+               sync_dev = host->dma_line_rx;
        return sync_dev;
 }
 
@@ -817,6 +831,7 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        u16 dsor = 0;
        unsigned long regval;
        unsigned long timeout;
+       u32 con;
 
        switch (ios->power_mode) {
        case MMC_POWER_OFF:
@@ -827,12 +842,18 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                break;
        }
 
+       con = OMAP_HSMMC_READ(host->base, CON);
        switch (mmc->ios.bus_width) {
+       case MMC_BUS_WIDTH_8:
+               OMAP_HSMMC_WRITE(host->base, CON, con | DW8);
+               break;
        case MMC_BUS_WIDTH_4:
+               OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
                OMAP_HSMMC_WRITE(host->base, HCTL,
                        OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
                break;
        case MMC_BUS_WIDTH_1:
+               OMAP_HSMMC_WRITE(host->base, CON, con & ~DW8);
                OMAP_HSMMC_WRITE(host->base, HCTL,
                        OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
                break;
@@ -936,8 +957,7 @@ static void omap_hsmmc_init(struct mmc_omap_host *host)
        OMAP_HSMMC_WRITE(host->base, SYSCONFIG, value | AUTOIDLE);
 
        /* Set SD bus power bit */
-       value = OMAP_HSMMC_READ(host->base, HCTL);
-       OMAP_HSMMC_WRITE(host->base, HCTL, value | SDBP);
+       set_sd_bus_power(host);
 }
 
 static struct mmc_host_ops mmc_omap_ops = {
@@ -1004,13 +1024,13 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
 
        sema_init(&host->sem, 1);
 
-       host->iclk = clk_get(&pdev->dev, "mmchs_ick");
+       host->iclk = clk_get(&pdev->dev, "ick");
        if (IS_ERR(host->iclk)) {
                ret = PTR_ERR(host->iclk);
                host->iclk = NULL;
                goto err1;
        }
-       host->fclk = clk_get(&pdev->dev, "mmchs_fck");
+       host->fclk = clk_get(&pdev->dev, "fck");
        if (IS_ERR(host->fclk)) {
                ret = PTR_ERR(host->fclk);
                host->fclk = NULL;
@@ -1054,14 +1074,34 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_seg_size = mmc->max_req_size;
 
-       mmc->ocr_avail = mmc_slot(host).ocr_mask;
        mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
-       if (pdata->slots[host->slot_id].wires >= 4)
+       if (pdata->slots[host->slot_id].wires >= 8)
+               mmc->caps |= MMC_CAP_8_BIT_DATA;
+       else if (pdata->slots[host->slot_id].wires >= 4)
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
        omap_hsmmc_init(host);
 
+       /* Select DMA lines */
+       switch (host->id) {
+       case OMAP_MMC1_DEVID:
+               host->dma_line_tx = OMAP24XX_DMA_MMC1_TX;
+               host->dma_line_rx = OMAP24XX_DMA_MMC1_RX;
+               break;
+       case OMAP_MMC2_DEVID:
+               host->dma_line_tx = OMAP24XX_DMA_MMC2_TX;
+               host->dma_line_rx = OMAP24XX_DMA_MMC2_RX;
+               break;
+       case OMAP_MMC3_DEVID:
+               host->dma_line_tx = OMAP34XX_DMA_MMC3_TX;
+               host->dma_line_rx = OMAP34XX_DMA_MMC3_RX;
+               break;
+       default:
+               dev_err(mmc_dev(host->mmc), "Invalid MMC id\n");
+               goto err_irq;
+       }
+
        /* Request IRQ for MMC operations */
        ret = request_irq(host->irq, mmc_omap_irq, IRQF_DISABLED,
                        mmc_hostname(mmc), host);
@@ -1070,16 +1110,17 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
                goto err_irq;
        }
 
+       /* initialize power supplies, gpios, etc */
        if (pdata->init != NULL) {
                if (pdata->init(&pdev->dev) != 0) {
-                       dev_dbg(mmc_dev(host->mmc),
-                               "Unable to configure MMC IRQs\n");
+                       dev_dbg(mmc_dev(host->mmc), "late init error\n");
                        goto err_irq_cd_init;
                }
        }
+       mmc->ocr_avail = mmc_slot(host).ocr_mask;
 
        /* Request IRQ for card detect */
-       if ((mmc_slot(host).card_detect_irq) && (mmc_slot(host).card_detect)) {
+       if ((mmc_slot(host).card_detect_irq)) {
                ret = request_irq(mmc_slot(host).card_detect_irq,
                                  omap_mmc_cd_handler,
                                  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
@@ -1102,8 +1143,8 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
                if (ret < 0)
                        goto err_slot_name;
        }
-       if (mmc_slot(host).card_detect_irq && mmc_slot(host).card_detect &&
-                       host->pdata->slots[host->slot_id].get_cover_state) {
+       if (mmc_slot(host).card_detect_irq &&
+           host->pdata->slots[host->slot_id].get_cover_state) {
                ret = device_create_file(&mmc->class_dev,
                                        &dev_attr_cover_switch);
                if (ret < 0)
@@ -1201,20 +1242,8 @@ static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state)
                                                " level suspend\n");
                        }
 
-                       if (host->id == OMAP_MMC1_DEVID
-                                       && !(OMAP_HSMMC_READ(host->base, HCTL)
-                                                       & SDVSDET)) {
-                               OMAP_HSMMC_WRITE(host->base, HCTL,
-                                       OMAP_HSMMC_READ(host->base, HCTL)
-                                       & SDVSCLR);
-                               OMAP_HSMMC_WRITE(host->base, HCTL,
-                                       OMAP_HSMMC_READ(host->base, HCTL)
-                                       | SDVS30);
-                               OMAP_HSMMC_WRITE(host->base, HCTL,
-                                       OMAP_HSMMC_READ(host->base, HCTL)
-                                       | SDBP);
-                       }
-
+                       OMAP_HSMMC_WRITE(host->base, HCTL,
+                                        OMAP_HSMMC_READ(host->base, HCTL) & ~SDBP);
                        clk_disable(host->fclk);
                        clk_disable(host->iclk);
                        clk_disable(host->dbclk);