]> err.no Git - linux-2.6/blobdiff - drivers/mmc/host/sdhci-pci.c
mmc: host driver for Ricoh Bay1Controllers
[linux-2.6] / drivers / mmc / host / sdhci-pci.c
index 5dcb4958e47b6d6a72e178b6318acb3d4fc6da5f..deb607c52c0d8ebbee60751e7a120692a22ddd9f 100644 (file)
@@ -47,7 +47,7 @@ struct sdhci_pci_fixes {
        int                     (*probe)(struct sdhci_pci_chip*);
 
        int                     (*probe_slot)(struct sdhci_pci_slot*);
-       void                    (*remove_slot)(struct sdhci_pci_slot*);
+       void                    (*remove_slot)(struct sdhci_pci_slot*, int);
 
        int                     (*suspend)(struct sdhci_pci_chip*,
                                        pm_message_t);
@@ -91,6 +91,7 @@ static int ricoh_probe(struct sdhci_pci_chip *chip)
 
 static const struct sdhci_pci_fixes sdhci_ricoh = {
        .probe          = ricoh_probe,
+       .quirks         = SDHCI_QUIRK_32BIT_DMA_ADDR,
 };
 
 static const struct sdhci_pci_fixes sdhci_ene_712 = {
@@ -138,6 +139,13 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
 {
        int ret;
 
+       if (chip->pdev->revision == 0) {
+               chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
+                         SDHCI_QUIRK_32BIT_DMA_SIZE |
+                         SDHCI_QUIRK_32BIT_ADMA_SIZE |
+                         SDHCI_QUIRK_RESET_AFTER_REQUEST;
+       }
+
        /*
         * JMicron chips can have two interfaces to the same hardware
         * in order to work around limitations in Microsoft's driver.
@@ -199,6 +207,22 @@ static void jmicron_enable_mmc(struct sdhci_host *host, int on)
 
 static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
 {
+       if (slot->chip->pdev->revision == 0) {
+               u16 version;
+
+               version = readl(slot->host->ioaddr + SDHCI_HOST_VERSION);
+               version = (version & SDHCI_VENDOR_VER_MASK) >>
+                       SDHCI_VENDOR_VER_SHIFT;
+
+               /*
+                * Older versions of the chip have lots of nasty glitches
+                * in the ADMA engine. It's best just to avoid it
+                * completely.
+                */
+               if (version < 0xAC)
+                       slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
+       }
+
        /*
         * The secondary interface requires a bit set to get the
         * interrupts.
@@ -209,8 +233,11 @@ static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
        return 0;
 }
 
-static void jmicron_remove_slot(struct sdhci_pci_slot *slot)
+static void jmicron_remove_slot(struct sdhci_pci_slot *slot, int dead)
 {
+       if (dead)
+               return;
+
        if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC)
                jmicron_enable_mmc(slot->host, 0);
 }
@@ -246,10 +273,6 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
 }
 
 static const struct sdhci_pci_fixes sdhci_jmicron = {
-       .quirks         = SDHCI_QUIRK_32BIT_DMA_ADDR |
-                         SDHCI_QUIRK_32BIT_DMA_SIZE |
-                         SDHCI_QUIRK_RESET_AFTER_REQUEST,
-
        .probe          = jmicron_probe,
 
        .probe_slot     = jmicron_probe_slot,
@@ -540,7 +563,7 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
 
 remove:
        if (chip->fixes && chip->fixes->remove_slot)
-               chip->fixes->remove_slot(slot);
+               chip->fixes->remove_slot(slot, 0);
 
 unmap:
        iounmap(host->ioaddr);
@@ -554,10 +577,18 @@ release:
 
 static void sdhci_pci_remove_slot(struct sdhci_pci_slot *slot)
 {
-       sdhci_remove_host(slot->host);
+       int dead;
+       u32 scratch;
+
+       dead = 0;
+       scratch = readl(slot->host->ioaddr + SDHCI_INT_STATUS);
+       if (scratch == (u32)-1)
+               dead = 1;
+
+       sdhci_remove_host(slot->host, dead);
 
        if (slot->chip->fixes && slot->chip->fixes->remove_slot)
-               slot->chip->fixes->remove_slot(slot);
+               slot->chip->fixes->remove_slot(slot, dead);
 
        pci_release_region(slot->chip->pdev, slot->pci_bar);