Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 82b0e23a authored by Takashi Iwai's avatar Takashi Iwai Committed by Chris Ball
Browse files

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: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarChris Ball <cjb@laptop.org>
parent f06c9153
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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;
}

+24 −4
Original line number Diff line number Diff line
@@ -1256,14 +1256,11 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
	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;
+2 −0
Original line number Diff line number Diff line
@@ -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 */