mmc: enable DMA on Ricoh sdhci reader by default
[safe/jmp/linux-2.6] / drivers / mmc / host / sdhci-pci.c
index deb607c..8e1020c 100644 (file)
@@ -80,10 +80,8 @@ struct sdhci_pci_chip {
 
 static int ricoh_probe(struct sdhci_pci_chip *chip)
 {
-       if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM)
-               chip->quirks |= SDHCI_QUIRK_CLOCK_BEFORE_RESET;
-
-       if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG)
+       if (chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG ||
+           chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY)
                chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET;
 
        return 0;
@@ -91,7 +89,9 @@ 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,
+       .quirks         = SDHCI_QUIRK_32BIT_DMA_ADDR |
+                         SDHCI_QUIRK_FORCE_DMA |
+                         SDHCI_QUIRK_CLOCK_BEFORE_RESET,
 };
 
 static const struct sdhci_pci_fixes sdhci_ene_712 = {
@@ -107,6 +107,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = {
 
 static const struct sdhci_pci_fixes sdhci_cafe = {
        .quirks         = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+                         SDHCI_QUIRK_NO_BUSY_IRQ |
                          SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 };
 
@@ -143,7 +144,8 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
                chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
                          SDHCI_QUIRK_32BIT_DMA_SIZE |
                          SDHCI_QUIRK_32BIT_ADMA_SIZE |
-                         SDHCI_QUIRK_RESET_AFTER_REQUEST;
+                         SDHCI_QUIRK_RESET_AFTER_REQUEST |
+                         SDHCI_QUIRK_BROKEN_SMALL_PIO;
        }
 
        /*
@@ -282,6 +284,85 @@ static const struct sdhci_pci_fixes sdhci_jmicron = {
        .resume         = jmicron_resume,
 };
 
+/* SysKonnect CardBus2SDIO extra registers */
+#define SYSKT_CTRL             0x200
+#define SYSKT_RDFIFO_STAT      0x204
+#define SYSKT_WRFIFO_STAT      0x208
+#define SYSKT_POWER_DATA       0x20c
+#define   SYSKT_POWER_330      0xef
+#define   SYSKT_POWER_300      0xf8
+#define   SYSKT_POWER_184      0xcc
+#define SYSKT_POWER_CMD                0x20d
+#define   SYSKT_POWER_START    (1 << 7)
+#define SYSKT_POWER_STATUS     0x20e
+#define   SYSKT_POWER_STATUS_OK        (1 << 0)
+#define SYSKT_BOARD_REV                0x210
+#define SYSKT_CHIP_REV         0x211
+#define SYSKT_CONF_DATA                0x212
+#define   SYSKT_CONF_DATA_1V8  (1 << 2)
+#define   SYSKT_CONF_DATA_2V5  (1 << 1)
+#define   SYSKT_CONF_DATA_3V3  (1 << 0)
+
+static int syskt_probe(struct sdhci_pci_chip *chip)
+{
+       if ((chip->pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
+               chip->pdev->class &= ~0x0000FF;
+               chip->pdev->class |= PCI_SDHCI_IFDMA;
+       }
+       return 0;
+}
+
+static int syskt_probe_slot(struct sdhci_pci_slot *slot)
+{
+       int tm, ps;
+
+       u8 board_rev = readb(slot->host->ioaddr + SYSKT_BOARD_REV);
+       u8  chip_rev = readb(slot->host->ioaddr + SYSKT_CHIP_REV);
+       dev_info(&slot->chip->pdev->dev, "SysKonnect CardBus2SDIO, "
+                                        "board rev %d.%d, chip rev %d.%d\n",
+                                        board_rev >> 4, board_rev & 0xf,
+                                        chip_rev >> 4,  chip_rev & 0xf);
+       if (chip_rev >= 0x20)
+               slot->host->quirks |= SDHCI_QUIRK_FORCE_DMA;
+
+       writeb(SYSKT_POWER_330, slot->host->ioaddr + SYSKT_POWER_DATA);
+       writeb(SYSKT_POWER_START, slot->host->ioaddr + SYSKT_POWER_CMD);
+       udelay(50);
+       tm = 10;  /* Wait max 1 ms */
+       do {
+               ps = readw(slot->host->ioaddr + SYSKT_POWER_STATUS);
+               if (ps & SYSKT_POWER_STATUS_OK)
+                       break;
+               udelay(100);
+       } while (--tm);
+       if (!tm) {
+               dev_err(&slot->chip->pdev->dev,
+                       "power regulator never stabilized");
+               writeb(0, slot->host->ioaddr + SYSKT_POWER_CMD);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_syskt = {
+       .quirks         = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER,
+       .probe          = syskt_probe,
+       .probe_slot     = syskt_probe_slot,
+};
+
+static int via_probe(struct sdhci_pci_chip *chip)
+{
+       if (chip->pdev->revision == 0x10)
+               chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER;
+
+       return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_via = {
+       .probe          = via_probe,
+};
+
 static const struct pci_device_id pci_ids[] __devinitdata = {
        {
                .vendor         = PCI_VENDOR_ID_RICOH,
@@ -325,7 +406,7 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 
        {
                .vendor         = PCI_VENDOR_ID_MARVELL,
-               .device         = PCI_DEVICE_ID_MARVELL_CAFE_SD,
+               .device         = PCI_DEVICE_ID_MARVELL_88ALP01_SD,
                .subvendor      = PCI_ANY_ID,
                .subdevice      = PCI_ANY_ID,
                .driver_data    = (kernel_ulong_t)&sdhci_cafe,
@@ -347,6 +428,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .driver_data    = (kernel_ulong_t)&sdhci_jmicron,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_SYSKONNECT,
+               .device         = 0x8000,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_syskt,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_VIA,
+               .device         = 0x95d0,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_via,
+       },
+
        {       /* Generic SD host controller */
                PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
        },
@@ -373,12 +470,12 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
 
        if (((pdev->class & 0xFFFF00) == (PCI_CLASS_SYSTEM_SDHCI << 8)) &&
                ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA) &&
-               (host->flags & SDHCI_USE_DMA)) {
+               (host->flags & SDHCI_USE_SDMA)) {
                dev_warn(&pdev->dev, "Will use DMA mode even though HW "
                        "doesn't fully claim to support it.\n");
        }
 
-       ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
        if (ret)
                return ret;
 
@@ -403,6 +500,7 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
 {
        struct sdhci_pci_chip *chip;
        struct sdhci_pci_slot *slot;
+       mmc_pm_flag_t pm_flags = 0;
        int i, ret;
 
        chip = pci_get_drvdata(pdev);
@@ -421,6 +519,8 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
                                sdhci_resume_host(chip->slots[i]->host);
                        return ret;
                }
+
+               pm_flags |= slot->host->mmc->pm_flags;
        }
 
        if (chip->fixes && chip->fixes->suspend) {
@@ -433,9 +533,15 @@ static int sdhci_pci_suspend (struct pci_dev *pdev, pm_message_t state)
        }
 
        pci_save_state(pdev);
-       pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       if (pm_flags & MMC_PM_KEEP_POWER) {
+               if (pm_flags & MMC_PM_WAKE_SDIO_IRQ)
+                       pci_enable_wake(pdev, PCI_D3hot, 1);
+               pci_set_power_state(pdev, PCI_D3hot);
+       } else {
+               pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+               pci_disable_device(pdev);
+               pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       }
 
        return 0;
 }
@@ -520,8 +626,8 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
 
        host = sdhci_alloc_host(&pdev->dev, sizeof(struct sdhci_pci_slot));
        if (IS_ERR(host)) {
-               ret = PTR_ERR(host);
-               goto unmap;
+               dev_err(&pdev->dev, "cannot allocate host\n");
+               return ERR_PTR(PTR_ERR(host));
        }
 
        slot = sdhci_priv(host);
@@ -539,11 +645,11 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
        ret = pci_request_region(pdev, bar, mmc_hostname(host->mmc));
        if (ret) {
                dev_err(&pdev->dev, "cannot request region\n");
-               return ERR_PTR(ret);
+               goto free;
        }
 
        addr = pci_resource_start(pdev, bar);
-       host->ioaddr = ioremap_nocache(addr, pci_resource_len(pdev, bar));
+       host->ioaddr = pci_ioremap_bar(pdev, bar);
        if (!host->ioaddr) {
                dev_err(&pdev->dev, "failed to remap registers\n");
                goto release;
@@ -555,6 +661,8 @@ static struct sdhci_pci_slot * __devinit sdhci_pci_probe_slot(
                        goto unmap;
        }
 
+       host->mmc->pm_caps = MMC_PM_KEEP_POWER | MMC_PM_WAKE_SDIO_IRQ;
+
        ret = sdhci_add_host(host);
        if (ret)
                goto remove;
@@ -570,6 +678,8 @@ unmap:
 
 release:
        pci_release_region(pdev, bar);
+
+free:
        sdhci_free_host(host);
 
        return ERR_PTR(ret);
@@ -727,6 +837,6 @@ static void __exit sdhci_drv_exit(void)
 module_init(sdhci_drv_init);
 module_exit(sdhci_drv_exit);
 
-MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
+MODULE_AUTHOR("Pierre Ossman <pierre@ossman.eu>");
 MODULE_DESCRIPTION("Secure Digital Host Controller Interface PCI driver");
 MODULE_LICENSE("GPL");