]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mmc/host/omap_hsmmc.c
ARM: OMAP: hsmmc requires data reset after data timeout
[linux-2.6-omap-h63xx.git] / drivers / mmc / host / omap_hsmmc.c
index b5931de315b111deb2e4c71f7ec8d1d0247d5719..8fb677e94c469f73aad91c6ff97819f3ebcbb6e7 100644 (file)
 #define SRC                    (1 << 25)
 #define SRD                    (1 << 26)
 
-#define OMAP_MMC1_DEVID                1
-#define OMAP_MMC2_DEVID                2
+/*
+ * FIXME: Most likely all the data using these _DEVID defines should come
+ * from the platform_data, or implemented in controller and slot specific
+ * functions.
+ */
+#define OMAP_MMC1_DEVID                0
+#define OMAP_MMC2_DEVID                1
+
 #define OMAP_MMC_DATADIR_NONE  0
 #define OMAP_MMC_DATADIR_READ  1
 #define OMAP_MMC_DATADIR_WRITE 2
 #define MMC_TIMEOUT_MS         20
 #define OMAP_MMC_MASTER_CLOCK  96000000
 #define DRIVER_NAME            "mmci-omap"
+
 /*
- * slot_id is device id - 1, device id is a static value
- * of 1 to represent device 1 etc..
+ * One controller can have multiple slots, like on some omap boards using
+ * omap.c controller driver. Luckily this is not currently done on any known
+ * omap_hsmmc.c device.
  */
 #define mmc_slot(host)         (host->pdata->slots[host->slot_id])
 
@@ -174,6 +182,27 @@ static void send_init_stream(struct mmc_omap_host *host)
        enable_irq(host->irq);
 }
 
+static inline
+int mmc_omap_cover_is_closed(struct mmc_omap_host *host)
+{
+       if (host->pdata->slots[host->slot_id].get_cover_state)
+               return host->pdata->slots[host->slot_id].get_cover_state(host->dev, host->slot_id);
+       return 1;
+}
+
+static ssize_t
+mmc_omap_show_cover_switch(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
+       struct mmc_omap_host *host = mmc_priv(mmc);
+
+       return sprintf(buf, "%s\n", mmc_omap_cover_is_closed(host) ? "closed" :
+                      "open");
+}
+
+static DEVICE_ATTR(cover_switch, S_IRUGO, mmc_omap_show_cover_switch, NULL);
+
 static ssize_t
 mmc_omap_show_slot_name(struct device *dev, struct device_attribute *attr,
                        char *buf)
@@ -388,6 +417,11 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
                                        mmc_dma_cleanup(host);
                                else
                                        host->data->error = -EILSEQ;
+                               OMAP_HSMMC_WRITE(host->base, SYSCTL,
+                                       OMAP_HSMMC_READ(host->base,
+                                                       SYSCTL) | SRD);
+                               while (OMAP_HSMMC_READ(host->base,
+                                                       SYSCTL) & SRD) ;
                                end_trans = 1;
                        }
                }
@@ -475,6 +509,7 @@ static void mmc_omap_detect(struct work_struct *work)
        struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
                                                mmc_carddetect_work);
 
+       sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
        if (host->carddetect) {
                if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
                        /*
@@ -794,7 +829,9 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
        host            = mmc_priv(mmc);
        host->mmc       = mmc;
        host->pdata     = pdata;
+       host->dev       = &pdev->dev;
        host->use_dma   = 1;
+       host->dev->dma_mask = &pdata->dma_mask;
        host->dma_ch    = -1;
        host->irq       = irq;
        host->id        = pdev->id;
@@ -859,7 +896,7 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
        mmc->ocr_avail = mmc_slot(host).ocr_mask;
        mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
-       if (pdata->conf.wire4)
+       if (pdata->slots[host->slot_id].wire4)
                mmc->caps |= MMC_CAP_4_BIT_DATA;
 
        /* Only MMC1 supports 3.0V */
@@ -886,8 +923,8 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
                        OMAP_HSMMC_READ(host->base, HCTL) | SDBP);
 
        /* Request IRQ for MMC operations */
-       ret = request_irq(host->irq, mmc_omap_irq, IRQF_DISABLED, pdev->name,
-                        host);
+       ret = request_irq(host->irq, mmc_omap_irq, IRQF_DISABLED,
+                       mmc_hostname(mmc), host);
        if (ret) {
                dev_dbg(mmc_dev(host->mmc), "Unable to grab HSMMC IRQ\n");
                goto err_irq;
@@ -896,8 +933,10 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
        /* Request IRQ for card detect */
        if ((mmc_slot(host).card_detect_irq) && (mmc_slot(host).card_detect)) {
                ret = request_irq(mmc_slot(host).card_detect_irq,
-                                 omap_mmc_cd_handler, IRQF_DISABLED, "MMC CD",
-                                 host);
+                                 omap_mmc_cd_handler,
+                                 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+                                         | IRQF_DISABLED,
+                                 mmc_hostname(mmc), host);
                if (ret) {
                        dev_dbg(mmc_dev(host->mmc),
                                "Unable to grab MMC CD IRQ\n");
@@ -925,9 +964,17 @@ 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) {
+               ret = device_create_file(&mmc->class_dev, &dev_attr_cover_switch);
+               if (ret < 0)
+                       goto err_cover_switch;
+       }
 
        return 0;
 
+err_cover_switch:
+       device_remove_file(&mmc->class_dev, &dev_attr_cover_switch);
 err_slot_name:
        mmc_remove_host(mmc);
 err_irq_cd_init: