From 82b0e23a295cc58d1290017ee97a40956ad68d94 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 21 Apr 2011 20:26:38 +0200 Subject: [PATCH] mmc: sdhci: Fix read-only detection with JMicron 388 chip 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 Signed-off-by: Takashi Iwai Signed-off-by: Chris Ball --- drivers/mmc/host/sdhci-pci.c | 5 +++++ drivers/mmc/host/sdhci.c | 28 ++++++++++++++++++++++++---- include/linux/mmc/sdhci.h | 2 ++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 82c5dc41267..936bbca19c0 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -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; } diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a70a3d1ef35..e5cfe70dc23 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -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; diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 83bd9f76709..92e1c9ad126 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h @@ -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 */ -- 2.46.0