diff options
Diffstat (limited to 'drivers/mmc/host/sdhci-pci.c')
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 99 |
1 files changed, 92 insertions, 7 deletions
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index e0356644d1aa..8e1020cf73f4 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -80,9 +80,6 @@ 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 || chip->pdev->subsystem_vendor == PCI_VENDOR_ID_SONY) chip->quirks |= SDHCI_QUIRK_NO_CARD_NO_RESET; @@ -92,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 = { @@ -285,6 +284,73 @@ 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) @@ -363,6 +429,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = { }, { + .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, @@ -426,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); @@ -444,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) { @@ -456,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; } @@ -578,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; |