diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-04-21 14:26:38 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-05-24 21:02:42 -0400 |
commit | 82b0e23a295cc58d1290017ee97a40956ad68d94 (patch) | |
tree | f3f140be979623ae8b83b79841eb842858ed054b | |
parent | f06c9153f5ecd47dfed23f87b9d08e42ff0e4170 (diff) |
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 <arieslee@jmicron.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/host/sdhci-pci.c | 5 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 28 | ||||
-rw-r--r-- | 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 82c5dc412679..936bbca19c0a 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) | |||
327 | return ret; | 327 | return ret; |
328 | } | 328 | } |
329 | 329 | ||
330 | /* quirk for unsable RO-detection on JM388 chips */ | ||
331 | if (chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_SD || | ||
332 | chip->pdev->device == PCI_DEVICE_ID_JMICRON_JMB388_ESD) | ||
333 | chip->quirks |= SDHCI_QUIRK_UNSTABLE_RO_DETECT; | ||
334 | |||
330 | return 0; | 335 | return 0; |
331 | } | 336 | } |
332 | 337 | ||
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index a70a3d1ef35a..e5cfe70dc23b 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c | |||
@@ -1256,14 +1256,11 @@ out: | |||
1256 | spin_unlock_irqrestore(&host->lock, flags); | 1256 | spin_unlock_irqrestore(&host->lock, flags); |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | static int sdhci_get_ro(struct mmc_host *mmc) | 1259 | static int check_ro(struct sdhci_host *host) |
1260 | { | 1260 | { |
1261 | struct sdhci_host *host; | ||
1262 | unsigned long flags; | 1261 | unsigned long flags; |
1263 | int is_readonly; | 1262 | int is_readonly; |
1264 | 1263 | ||
1265 | host = mmc_priv(mmc); | ||
1266 | |||
1267 | spin_lock_irqsave(&host->lock, flags); | 1264 | spin_lock_irqsave(&host->lock, flags); |
1268 | 1265 | ||
1269 | if (host->flags & SDHCI_DEVICE_DEAD) | 1266 | if (host->flags & SDHCI_DEVICE_DEAD) |
@@ -1281,6 +1278,29 @@ static int sdhci_get_ro(struct mmc_host *mmc) | |||
1281 | !is_readonly : is_readonly; | 1278 | !is_readonly : is_readonly; |
1282 | } | 1279 | } |
1283 | 1280 | ||
1281 | #define SAMPLE_COUNT 5 | ||
1282 | |||
1283 | static int sdhci_get_ro(struct mmc_host *mmc) | ||
1284 | { | ||
1285 | struct sdhci_host *host; | ||
1286 | int i, ro_count; | ||
1287 | |||
1288 | host = mmc_priv(mmc); | ||
1289 | |||
1290 | if (!(host->quirks & SDHCI_QUIRK_UNSTABLE_RO_DETECT)) | ||
1291 | return check_ro(host); | ||
1292 | |||
1293 | ro_count = 0; | ||
1294 | for (i = 0; i < SAMPLE_COUNT; i++) { | ||
1295 | if (check_ro(host)) { | ||
1296 | if (++ro_count > SAMPLE_COUNT / 2) | ||
1297 | return 1; | ||
1298 | } | ||
1299 | msleep(30); | ||
1300 | } | ||
1301 | return 0; | ||
1302 | } | ||
1303 | |||
1284 | static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) | 1304 | static void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable) |
1285 | { | 1305 | { |
1286 | struct sdhci_host *host; | 1306 | struct sdhci_host *host; |
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h index 83bd9f76709a..92e1c9ad126c 100644 --- a/include/linux/mmc/sdhci.h +++ b/include/linux/mmc/sdhci.h | |||
@@ -85,6 +85,8 @@ struct sdhci_host { | |||
85 | #define SDHCI_QUIRK_NO_HISPD_BIT (1<<29) | 85 | #define SDHCI_QUIRK_NO_HISPD_BIT (1<<29) |
86 | /* Controller treats ADMA descriptors with length 0000h incorrectly */ | 86 | /* Controller treats ADMA descriptors with length 0000h incorrectly */ |
87 | #define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30) | 87 | #define SDHCI_QUIRK_BROKEN_ADMA_ZEROLEN_DESC (1<<30) |
88 | /* The read-only detection via SDHCI_PRESENT_STATE register is unstable */ | ||
89 | #define SDHCI_QUIRK_UNSTABLE_RO_DETECT (1<<31) | ||
88 | 90 | ||
89 | int irq; /* Device IRQ */ | 91 | int irq; /* Device IRQ */ |
90 | void __iomem *ioaddr; /* Mapped address */ | 92 | void __iomem *ioaddr; /* Mapped address */ |