mmc: Add support for JMicron 388 SD/MMC controller
authorTakashi Iwai <tiwai@suse.de>
Wed, 8 Dec 2010 09:04:30 +0000 (10:04 +0100)
committerChris Ball <cjb@laptop.org>
Sun, 9 Jan 2011 03:48:04 +0000 (22:48 -0500)
JMicron 388 SD/MMC combo controller supports the 1.8V low-voltage for
SD, but MMC doesn't work with the low-voltage, resulting in an error
at probing.

This patch adds the support for multiple voltage mask per device type,
so that SD works with 1.8V while MMC forces 3.3V.  Here new ocr_avail_*
fields for each device are introduced, so that the actual OCR mask is
switched dynamically.

Also, the restriction of low-voltage in core/sd.c is removed when the
bit is allowed explicitly via ocr_avail_sd mask.

This patch was rewritten from scratch based on Aries' original code.

Signed-off-by: Aries Lee <arieslee@jmicron.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Reviewed-by: Chris Ball <cjb@laptop.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
drivers/mmc/core/mmc.c
drivers/mmc/core/sd.c
drivers/mmc/core/sdio.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci.c
include/linux/mmc/host.h
include/linux/mmc/sdhci.h
include/linux/pci_ids.h

index 77f93c3b88086d5ee802da97ae03754d86c82e9a..76bb621e9aa922df274e9a3b192ebdd663f05e9e 100644 (file)
@@ -745,6 +745,8 @@ int mmc_attach_mmc(struct mmc_host *host, u32 ocr)
        WARN_ON(!host->claimed);
 
        mmc_attach_bus_ops(host);
+       if (host->ocr_avail_mmc)
+               host->ocr_avail = host->ocr_avail_mmc;
 
        /*
         * We need to get OCR a different way for SPI.
index 49da4dffd28ec076368ba3bfd72fa4a25f4a44bb..de062ebd8b263f848386eac1226014dcb38ed3ee 100644 (file)
@@ -772,6 +772,8 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
        WARN_ON(!host->claimed);
 
        mmc_sd_attach_bus_ops(host);
+       if (host->ocr_avail_sd)
+               host->ocr_avail = host->ocr_avail_sd;
 
        /*
         * We need to get OCR a different way for SPI.
@@ -795,7 +797,8 @@ int mmc_attach_sd(struct mmc_host *host, u32 ocr)
                ocr &= ~0x7F;
        }
 
-       if (ocr & MMC_VDD_165_195) {
+       if ((ocr & MMC_VDD_165_195) &&
+           !(host->ocr_avail_sd & MMC_VDD_165_195)) {
                printk(KERN_WARNING "%s: SD card claims to support the "
                       "incompletely defined 'low voltage range'. This "
                       "will be ignored.\n", mmc_hostname(host));
index efef5f94ac429081c5211a984a100b575c5fd986..c18810ab6465f8b80c2151682f80662df287228d 100644 (file)
@@ -700,6 +700,8 @@ int mmc_attach_sdio(struct mmc_host *host, u32 ocr)
        WARN_ON(!host->claimed);
 
        mmc_attach_bus(host, &mmc_sdio_ops);
+       if (host->ocr_avail_sdio)
+               host->ocr_avail = host->ocr_avail_sdio;
 
        /*
         * Sanity check the voltages that the card claims to
index 831cf91b644a1a95eb5e91bd264a772c490866a0..d2638ffc4ed20dd82767eb2708145208dee02fb1 100644 (file)
@@ -272,6 +272,7 @@ static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
 static int jmicron_probe(struct sdhci_pci_chip *chip)
 {
        int ret;
+       u16 mmcdev = 0;
 
        if (chip->pdev->revision == 0) {
                chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
@@ -293,12 +294,17 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
         * 2. The MMC interface has a lower subfunction number
         *    than the SD interface.
         */
-       if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD) {
+       if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_SD)
+               mmcdev = PCI_DEVICE_ID_JMICRON_JMB38X_MMC;
+       else if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD)
+               mmcdev = PCI_DEVICE_ID_JMICRON_JMB388_ESD;
+
+       if (mmcdev) {
                struct pci_dev *sd_dev;
 
                sd_dev = NULL;
                while ((sd_dev = pci_get_device(PCI_VENDOR_ID_JMICRON,
-                       PCI_DEVICE_ID_JMICRON_JMB38X_MMC, sd_dev)) != NULL) {
+                                               mmcdev, sd_dev)) != NULL) {
                        if ((PCI_SLOT(chip->pdev->devfn) ==
                                PCI_SLOT(sd_dev->devfn)) &&
                                (chip->pdev->bus == sd_dev->bus))
@@ -358,11 +364,21 @@ static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
                        slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
        }
 
+       /* JM388 MMC doesn't support 1.8V while SD supports it */
+       if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
+               slot->host->ocr_avail_sd = MMC_VDD_32_33 | MMC_VDD_33_34 |
+                       MMC_VDD_29_30 | MMC_VDD_30_31 |
+                       MMC_VDD_165_195; /* allow 1.8V */
+               slot->host->ocr_avail_mmc = MMC_VDD_32_33 | MMC_VDD_33_34 |
+                       MMC_VDD_29_30 | MMC_VDD_30_31; /* no 1.8V for MMC */
+       }
+
        /*
         * The secondary interface requires a bit set to get the
         * interrupts.
         */
-       if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC)
+       if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
+           slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
                jmicron_enable_mmc(slot->host, 1);
 
        return 0;
@@ -373,7 +389,8 @@ 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)
+       if (slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
+           slot->chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
                jmicron_enable_mmc(slot->host, 0);
 }
 
@@ -381,7 +398,8 @@ static int jmicron_suspend(struct sdhci_pci_chip *chip, pm_message_t state)
 {
        int i;
 
-       if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) {
+       if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
+           chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
                for (i = 0;i < chip->num_slots;i++)
                        jmicron_enable_mmc(chip->slots[i]->host, 0);
        }
@@ -393,7 +411,8 @@ static int jmicron_resume(struct sdhci_pci_chip *chip)
 {
        int ret, i;
 
-       if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC) {
+       if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB38X_MMC ||
+           chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) {
                for (i = 0;i < chip->num_slots;i++)
                        jmicron_enable_mmc(chip->slots[i]->host, 1);
        }
@@ -581,6 +600,22 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .driver_data    = (kernel_ulong_t)&sdhci_jmicron,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_JMICRON,
+               .device         = PCI_DEVICE_ID_JMICRON_JMB388_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_jmicron,
+       },
+
+       {
+               .vendor         = PCI_VENDOR_ID_JMICRON,
+               .device         = PCI_DEVICE_ID_JMICRON_JMB388_ESD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_jmicron,
+       },
+
        {
                .vendor         = PCI_VENDOR_ID_SYSKONNECT,
                .device         = 0x8000,
index 8a74fcbfe13b33d78dffd6438995a0441f38e945..55698864c2cdf252e8f257e9f215ccbfbeca7983 100644 (file)
@@ -1739,7 +1739,7 @@ EXPORT_SYMBOL_GPL(sdhci_alloc_host);
 int sdhci_add_host(struct sdhci_host *host)
 {
        struct mmc_host *mmc;
-       unsigned int caps;
+       unsigned int caps, ocr_avail;
        int ret;
 
        WARN_ON(host == NULL);
@@ -1893,13 +1893,26 @@ int sdhci_add_host(struct sdhci_host *host)
            mmc_card_is_removable(mmc))
                mmc->caps |= MMC_CAP_NEEDS_POLL;
 
-       mmc->ocr_avail = 0;
+       ocr_avail = 0;
        if (caps & SDHCI_CAN_VDD_330)
-               mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
+               ocr_avail |= MMC_VDD_32_33 | MMC_VDD_33_34;
        if (caps & SDHCI_CAN_VDD_300)
-               mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
+               ocr_avail |= MMC_VDD_29_30 | MMC_VDD_30_31;
        if (caps & SDHCI_CAN_VDD_180)
-               mmc->ocr_avail |= MMC_VDD_165_195;
+               ocr_avail |= MMC_VDD_165_195;
+
+       mmc->ocr_avail = ocr_avail;
+       mmc->ocr_avail_sdio = ocr_avail;
+       if (host->ocr_avail_sdio)
+               mmc->ocr_avail_sdio &= host->ocr_avail_sdio;
+       mmc->ocr_avail_sd = ocr_avail;
+       if (host->ocr_avail_sd)
+               mmc->ocr_avail_sd &= host->ocr_avail_sd;
+       else /* normal SD controllers don't support 1.8V */
+               mmc->ocr_avail_sd &= ~MMC_VDD_165_195;
+       mmc->ocr_avail_mmc = ocr_avail;
+       if (host->ocr_avail_mmc)
+               mmc->ocr_avail_mmc &= host->ocr_avail_mmc;
 
        if (mmc->ocr_avail == 0) {
                printk(KERN_ERR "%s: Hardware doesn't report any "
index 381c77fd4dca0dfbc2c6e22a244abc9f5f81d9fb..4a9d9d2589c7a93a540e695db0960dcd7aeb1517 100644 (file)
@@ -131,6 +131,9 @@ struct mmc_host {
        unsigned int            f_max;
        unsigned int            f_init;
        u32                     ocr_avail;
+       u32                     ocr_avail_sdio; /* SDIO-specific OCR */
+       u32                     ocr_avail_sd;   /* SD-specific OCR */
+       u32                     ocr_avail_mmc;  /* MMC-specific OCR */
        struct notifier_block   pm_notify;
 
 #define MMC_VDD_165_195                0x00000080      /* VDD voltage 1.65 - 1.95 */
index 1fdc673f239605053ff9630107d51bc720b9925b..0d953f513d81464b7da8821e29b90c1aed56e53e 100644 (file)
@@ -139,6 +139,10 @@ struct sdhci_host {
 
        unsigned int caps;      /* Alternative capabilities */
 
+       unsigned int            ocr_avail_sdio; /* OCR bit masks */
+       unsigned int            ocr_avail_sd;
+       unsigned int            ocr_avail_mmc;
+
        unsigned long private[0] ____cacheline_aligned;
 };
 #endif /* __SDHCI_H */
index 7a58875cdad585e1ab72170d9804e149439ef6ce..2f17b4ccbb58d3c02baf7e982a4683007912d234 100644 (file)
 #define PCI_DEVICE_ID_JMICRON_JMB38X_SD        0x2381
 #define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382
 #define PCI_DEVICE_ID_JMICRON_JMB38X_MS        0x2383
+#define PCI_DEVICE_ID_JMICRON_JMB388_SD        0x2391
+#define PCI_DEVICE_ID_JMICRON_JMB388_ESD 0x2392
 
 #define PCI_VENDOR_ID_KORENIX          0x1982
 #define PCI_DEVICE_ID_KORENIX_JETCARDF0        0x1600