mmc: sdhci: Fix read-only detection with JMicron 388 chip
authorTakashi Iwai <tiwai@suse.de>
Thu, 21 Apr 2011 18:26:38 +0000 (20:26 +0200)
committerChris Ball <cjb@laptop.org>
Wed, 25 May 2011 01:02:42 +0000 (21:02 -0400)
On HP laptops with JMicron 388 chip, the write-locked SD card isn't
detected correctly as read-only in many cases.  This is because the
PRESENT_STATE register becomes unsable just after plugging, and it
returns the WRITE_PROTECT bit wrongly at the first read.

This patch fixes the read-only detection by adding a new sdhci quirk
indicating to check the register more intensively with a relatively
long delay.

The patch is tested with 2.6.39-rc4 kernel.

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

index 82c5dc41267975c314557834b94c5304b92c87a3..936bbca19c0a47b13066b935221f2b583c574a3c 100644 (file)
@@ -327,6 +327,11 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
                return ret;
        }
 
+       /* quirk for unsable RO-detection on JM388 chips */
+       if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD ||
+           chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD)
+               chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT;
+
        return 0;
 }
 
index a70a3d1ef35a9c5da6ccf8f6667dbd99e2d0e460..e5cfe70dc23b3223e70a7d3433247b9d9ae542d9 100644 (file)
@@ -1256,14 +1256,11 @@ out:
        spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sdhci_get_ro(struct mmc_host *mmc)
+static int check_ro(struct sdhci_host *host)
 {
-       struct sdhci_host *host;
        unsigned long flags;
        int is_readonly;
 
-       host = mmc_priv(mmc);
-
        spin_lock_irqsave(&host->lock, flags);
 
        if (host->flags & SDHCI_DEVICE_DEAD)
@@ -1281,6 +1278,29 @@ static int sdhci_get_ro(struct mmc_host *mmc)
                !is_readonly : is_readonly;
 }
 
+#define SAMPLE_COUNT   5
+
+static int sdhci_get_ro(struct mmc_host *mmc)
+{
+       struct sdhci_host *host;
+       int i, ro_count;
+
+       host = mmc_priv(mmc);
+
+       if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT))
+               return check_ro(host);
+
+       ro_count = 0;
+       for (i = 0; i < SAMPLE_COUNT; i++) {
+               if (check_ro(host)) {
+                       if (++ro_count > SAMPLE_COUNT / 2)
+                               return 1;
+               }
+               msleep(30);
+       }
+       return 0;
+}
+
 static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable)
 {
        struct sdhci_host *host;
index 83bd9f76709aa90b32ad76a175a408bf7725b468..92e1c9ad126cbba5e55bf0189512d6a657d6e7da 100644 (file)
@@ -85,6 +85,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK_NO_HISPD_BIT                       (1<<29)
 /* Controller treats ADMA descriptors with length 0000h incorrectly */
 #define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC           (1<<30)
+/* The read-only detection via SDHCI_PRESENT_STATE register is unstable */
+#define SDHCI_QUIRK_UNSTABLE_RO_DETECT                 (1<<31)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */