Jelajahi Sumber

sdhci: Specific quirk vor VIA SDHCI controller in VX855ES

The SDHCI controller found in the VX855ES requires 10ms
delay between applying power and applying clock.

This issue has been discovered and documented by the OLPC XO1.5 team.

Signed-off-by: Harald Welte <HaraldWelte@viatech.com>
Signed-off-by: Pierre Ossman <pierre@ossman.eu>
Harald Welte 16 tahun lalu
induk
melakukan
557b06971b
3 mengubah file dengan 29 tambahan dan 0 penghapusan
  1. 20 0
      drivers/mmc/host/sdhci-pci.c
  2. 7 0
      drivers/mmc/host/sdhci.c
  3. 2 0
      drivers/mmc/host/sdhci.h

+ 20 - 0
drivers/mmc/host/sdhci-pci.c

@@ -284,6 +284,18 @@ static const struct sdhci_pci_fixes sdhci_jmicron = {
 	.resume		= jmicron_resume,
 	.resume		= jmicron_resume,
 };
 };
 
 
+static int via_probe(struct sdhci_pci_chip *chip)
+{
+	if (chip->pdev->revision == 0x10)
+		chip->quirks |= SDHCI_QUIRK_DELAY_AFTER_POWER;
+
+	return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_via = {
+	.probe		= via_probe,
+};
+
 static const struct pci_device_id pci_ids[] __devinitdata = {
 static const struct pci_device_id pci_ids[] __devinitdata = {
 	{
 	{
 		.vendor		= PCI_VENDOR_ID_RICOH,
 		.vendor		= PCI_VENDOR_ID_RICOH,
@@ -349,6 +361,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
 		.driver_data	= (kernel_ulong_t)&sdhci_jmicron,
 		.driver_data	= (kernel_ulong_t)&sdhci_jmicron,
 	},
 	},
 
 
+	{
+		.vendor		= PCI_VENDOR_ID_VIA,
+		.device		= 0x95d0,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (kernel_ulong_t)&sdhci_via,
+	},
+
 	{	/* Generic SD host controller */
 	{	/* Generic SD host controller */
 		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
 		PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
 	},
 	},

+ 7 - 0
drivers/mmc/host/sdhci.c

@@ -1057,6 +1057,13 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 	pwr |= SDHCI_POWER_ON;
 	pwr |= SDHCI_POWER_ON;
 
 
 	sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
 	sdhci_writeb(host, pwr, SDHCI_POWER_CONTROL);
+
+	/*
+	 * Some controllers need an extra 10ms delay of 10ms before they
+	 * can apply clock after applying power
+	 */
+	if ((host->quirks & SDHCI_QUIRK_DELAY_AFTER_POWER))
+		mdelay(10);
 }
 }
 
 
 /*****************************************************************************\
 /*****************************************************************************\

+ 2 - 0
drivers/mmc/host/sdhci.h

@@ -230,6 +230,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK_NO_MULTIBLOCK			(1<<21)
 #define SDHCI_QUIRK_NO_MULTIBLOCK			(1<<21)
 /* Controller can only handle 1-bit data transfers */
 /* Controller can only handle 1-bit data transfers */
 #define SDHCI_QUIRK_FORCE_1_BIT_DATA			(1<<22)
 #define SDHCI_QUIRK_FORCE_1_BIT_DATA			(1<<22)
+/* Controller needs 10ms delay between applying power and clock */
+#define SDHCI_QUIRK_DELAY_AFTER_POWER			(1<<23)
 
 
 	int			irq;		/* Device IRQ */
 	int			irq;		/* Device IRQ */
 	void __iomem *		ioaddr;		/* Mapped address */
 	void __iomem *		ioaddr;		/* Mapped address */