[v5, 2/4] mmc: sdhci-of-esdhc: support both BE and LE host controller

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



To support little endian eSDHC controller, we redefine both BE and
LE IO accessors. In the new accessors, use ioread*/iowrite* instead
of in_be32/out_be32 and will select accessors according to endian
mode in probe function.

Signed-off-by: Yangbo Lu <yangbo.lu@xxxxxxxxxxxxx>
---
 drivers/mmc/host/sdhci-esdhc.h    |   2 +
 drivers/mmc/host/sdhci-of-esdhc.c | 436 ++++++++++++++++++++++++++++----------
 2 files changed, 324 insertions(+), 114 deletions(-)

diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index 163ac99..de132e2 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -24,6 +24,8 @@
 				SDHCI_QUIRK_PIO_NEEDS_DELAY | \
 				SDHCI_QUIRK_NO_HISPD_BIT)
 
+#define ESDHC_PROCTL		0x28
+
 #define ESDHC_SYSTEM_CONTROL	0x2c
 #define ESDHC_CLOCK_MASK	0x0000fff0
 #define ESDHC_PREDIV_SHIFT	8
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 2a54dbe..5315864 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -18,128 +18,326 @@
 #include <linux/of.h>
 #include <linux/delay.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/mmc/host.h>
 #include "sdhci-pltfm.h"
 #include "sdhci-esdhc.h"
 
 #define VENDOR_V_22	0x12
 #define VENDOR_V_23	0x13
-static u32 esdhc_readl(struct sdhci_host *host, int reg)
+
+struct esdhc_host {
+	u8 vendor_ver;
+	u8 spec_ver;
+	u16 xfer_mode_shadow;
+	struct sdhci_host *host;
+};
+
+static struct esdhc_host *esdhc;
+
+/**
+ * esdhc_read*_fixup - Fixup the value read from incompatible eSDHC register
+ *		       to make it compatible with SD spec.
+ *
+ * @esdhc: pointer to esdhc_host
+ * @spec_reg: SD spec register address
+ * @value: 32bit eSDHC register value on spec_reg address
+ *
+ * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC
+ * registers are 32 bits. There are differences in register size, register
+ * address, register function, bit position and function between eSDHC spec
+ * and SD spec.
+ *
+ * Return a fixed up register value
+ */
+static u32 esdhc_readl_fixup(struct esdhc_host *esdhc,
+				     int spec_reg, u32 value)
 {
 	u32 ret;
 
-	ret = in_be32(host->ioaddr + reg);
 	/*
 	 * The bit of ADMA flag in eSDHC is not compatible with standard
 	 * SDHC register, so set fake flag SDHCI_CAN_DO_ADMA2 when ADMA is
 	 * supported by eSDHC.
 	 * And for many FSL eSDHC controller, the reset value of field
-	 * SDHCI_CAN_DO_ADMA1 is one, but some of them can't support ADMA,
+	 * SDHCI_CAN_DO_ADMA1 is 1, but some of them can't support ADMA,
 	 * only these vendor version is greater than 2.2/0x12 support ADMA.
-	 * For FSL eSDHC, must aligned 4-byte, so use 0xFC to read the
-	 * the verdor version number, oxFE is SDHCI_HOST_VERSION.
 	 */
-	if ((reg == SDHCI_CAPABILITIES) && (ret & SDHCI_CAN_DO_ADMA1)) {
-		u32 tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
-		tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
-		if (tmp > VENDOR_V_22)
-			ret |= SDHCI_CAN_DO_ADMA2;
+	if ((spec_reg == SDHCI_CAPABILITIES) && (value & SDHCI_CAN_DO_ADMA1)) {
+		if (esdhc->vendor_ver > VENDOR_V_22) {
+			ret = value | SDHCI_CAN_DO_ADMA2;
+			return ret;
+		}
 	}
-
+	ret = value;
 	return ret;
 }
 
-static u16 esdhc_readw(struct sdhci_host *host, int reg)
+static u16 esdhc_readw_fixup(struct esdhc_host *esdhc,
+				     int spec_reg, u32 value)
 {
 	u16 ret;
-	int base = reg & ~0x3;
-	int shift = (reg & 0x2) * 8;
+	int shift = (spec_reg & 0x2) * 8;
 
-	if (unlikely(reg == SDHCI_HOST_VERSION))
-		ret = in_be32(host->ioaddr + base) & 0xffff;
+	if (spec_reg == SDHCI_HOST_VERSION)
+		ret = value & 0xffff;
 	else
-		ret = (in_be32(host->ioaddr + base) >> shift) & 0xffff;
+		ret = (value >> shift) & 0xffff;
 	return ret;
 }
 
-static u8 esdhc_readb(struct sdhci_host *host, int reg)
+static u8 esdhc_readb_fixup(struct esdhc_host *esdhc,
+				     int spec_reg, u32 value)
 {
-	int base = reg & ~0x3;
-	int shift = (reg & 0x3) * 8;
-	u8 ret = (in_be32(host->ioaddr + base) >> shift) & 0xff;
+	u8 ret;
+	u8 dma_bits;
+	int shift = (spec_reg & 0x3) * 8;
+
+	ret = (value >> shift) & 0xff;
 
 	/*
 	 * "DMA select" locates at offset 0x28 in SD specification, but on
 	 * P5020 or P3041, it locates at 0x29.
 	 */
-	if (reg == SDHCI_HOST_CONTROL) {
-		u32 dma_bits;
-
-		dma_bits = in_be32(host->ioaddr + reg);
+	if (spec_reg == SDHCI_HOST_CONTROL) {
 		/* DMA select is 22,23 bits in Protocol Control Register */
-		dma_bits = (dma_bits >> 5) & SDHCI_CTRL_DMA_MASK;
-
+		dma_bits = (value >> 5) & SDHCI_CTRL_DMA_MASK;
 		/* fixup the result */
 		ret &= ~SDHCI_CTRL_DMA_MASK;
 		ret |= dma_bits;
 	}
-
 	return ret;
 }
 
-static void esdhc_writel(struct sdhci_host *host, u32 val, int reg)
+/**
+ * esdhc_write*_fixup - Fixup the SD spec register value so that it could be
+ *			written into eSDHC register.
+ *
+ * @esdhc: pointer to esdhc_host
+ * @spec_reg: SD spec register address
+ * @value: 8/16/32bit SD spec register value that would be written
+ * @old_value: 32bit eSDHC register value on spec_reg address
+ *
+ * In SD spec, there are 8/16/32/64 bits registers, while all of eSDHC
+ * registers are 32 bits. There are differences in register size, register
+ * address, register function, bit position and function between eSDHC spec
+ * and SD spec.
+ *
+ * Return a fixed up register value
+ */
+static u32 esdhc_writel_fixup(struct esdhc_host *esdhc,
+				     int spec_reg, u32 value, u32 old_value)
 {
+	u32 ret;
+
 	/*
-	 * Enable IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
-	 * when SYSCTL[RSTD]) is set for some special operations.
-	 * No any impact other operation.
+	 * Enabling IRQSTATEN[BGESEN] is just to set IRQSTAT[BGE]
+	 * when SYSCTL[RSTD] is set for some special operations.
+	 * No any impact on other operation.
 	 */
-	if (reg == SDHCI_INT_ENABLE)
-		val |= SDHCI_INT_BLK_GAP;
-	sdhci_be32bs_writel(host, val, reg);
+	if (spec_reg == SDHCI_INT_ENABLE)
+		ret = value | SDHCI_INT_BLK_GAP;
+	else
+		ret = value;
+
+	return ret;
 }
 
-static void esdhc_writew(struct sdhci_host *host, u16 val, int reg)
+static u32 esdhc_writew_fixup(struct esdhc_host *esdhc,
+				     int spec_reg, u16 value, u32 old_value)
 {
-	if (reg == SDHCI_BLOCK_SIZE) {
+	u32 ret;
+	int shift = (spec_reg & 0x2) * 8;
+
+	switch (spec_reg) {
+	case SDHCI_TRANSFER_MODE:
+		/*
+		 * Postpone this write, we must do it together with a
+		 * command write that is down below. Return old value.
+		 */
+		esdhc->xfer_mode_shadow = value;
+		return old_value;
+	case SDHCI_COMMAND:
+		ret = (value << 16) | esdhc->xfer_mode_shadow;
+		return ret;
+	}
+
+	ret = old_value & (~(0xffff << shift));
+	ret |= (value << shift);
+
+	if (spec_reg == SDHCI_BLOCK_SIZE) {
 		/*
 		 * Two last DMA bits are reserved, and first one is used for
 		 * non-standard blksz of 4096 bytes that we don't support
 		 * yet. So clear the DMA boundary bits.
 		 */
-		val &= ~SDHCI_MAKE_BLKSZ(0x7, 0);
+		ret &= (~SDHCI_MAKE_BLKSZ(0x7, 0));
 	}
-	sdhci_be32bs_writew(host, val, reg);
+	return ret;
 }
 
-static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
+static u32 esdhc_writeb_fixup(struct esdhc_host *esdhc,
+				     int spec_reg, u8 value, u32 old_value)
 {
+	u32 ret;
+	u32 dma_bits;
+	u8 tmp;
+	int shift = (spec_reg & 0x3) * 8;
+
 	/*
 	 * "DMA select" location is offset 0x28 in SD specification, but on
 	 * P5020 or P3041, it's located at 0x29.
 	 */
-	if (reg == SDHCI_HOST_CONTROL) {
-		u32 dma_bits;
-
+	if (spec_reg == SDHCI_HOST_CONTROL) {
 		/*
 		 * If host control register is not standard, exit
 		 * this function
 		 */
-		if (host->quirks2 & SDHCI_QUIRK2_BROKEN_HOST_CONTROL)
-			return;
+		if (esdhc->host->quirks2 & SDHCI_QUIRK2_BROKEN_HOST_CONTROL)
+			return old_value;
 
 		/* DMA select is 22,23 bits in Protocol Control Register */
-		dma_bits = (val & SDHCI_CTRL_DMA_MASK) << 5;
-		clrsetbits_be32(host->ioaddr + reg , SDHCI_CTRL_DMA_MASK << 5,
-			dma_bits);
-		val &= ~SDHCI_CTRL_DMA_MASK;
-		val |= in_be32(host->ioaddr + reg) & SDHCI_CTRL_DMA_MASK;
+		dma_bits = (value & SDHCI_CTRL_DMA_MASK) << 5;
+		ret = (old_value & (~(SDHCI_CTRL_DMA_MASK << 5))) | dma_bits;
+		tmp = (value & (~SDHCI_CTRL_DMA_MASK)) |
+		      (old_value & SDHCI_CTRL_DMA_MASK);
+		ret = (ret & (~0xff)) | tmp;
+
+		/* Prevent SDHCI core from writing reserved bits (e.g. HISPD) */
+		ret &= ~ESDHC_HOST_CONTROL_RES;
+		return ret;
 	}
 
-	/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
-	if (reg == SDHCI_HOST_CONTROL)
-		val &= ~ESDHC_HOST_CONTROL_RES;
-	sdhci_be32bs_writeb(host, val, reg);
+	ret = (old_value & (~(0xff << shift))) | (value << shift);
+	return ret;
+}
+
+static u32 esdhc_be_readl(struct sdhci_host *host, int reg)
+{
+	u32 ret;
+	u32 value;
+
+	value = ioread32be(host->ioaddr + reg);
+	ret = esdhc_readl_fixup(esdhc, reg, value);
+
+	return ret;
+}
+
+static u32 esdhc_le_readl(struct sdhci_host *host, int reg)
+{
+	u32 ret;
+	u32 value;
+
+	value = ioread32(host->ioaddr + reg);
+	ret = esdhc_readl_fixup(esdhc, reg, value);
+
+	return ret;
+}
+
+static u16 esdhc_be_readw(struct sdhci_host *host, int reg)
+{
+	u16 ret;
+	u32 value;
+	int base = reg & ~0x3;
+
+	value = ioread32be(host->ioaddr + base);
+	ret = esdhc_readw_fixup(esdhc, reg, value);
+	return ret;
+}
+
+static u16 esdhc_le_readw(struct sdhci_host *host, int reg)
+{
+	u16 ret;
+	u32 value;
+	int base = reg & ~0x3;
+
+	value = ioread32(host->ioaddr + base);
+	ret = esdhc_readw_fixup(esdhc, reg, value);
+	return ret;
+}
+
+static u8 esdhc_be_readb(struct sdhci_host *host, int reg)
+{
+	u8 ret;
+	u32 value;
+	int base = reg & ~0x3;
+
+	value = ioread32be(host->ioaddr + base);
+	ret = esdhc_readb_fixup(esdhc, reg, value);
+	return ret;
+}
+
+static u8 esdhc_le_readb(struct sdhci_host *host, int reg)
+{
+	u8 ret;
+	u32 value;
+	int base = reg & ~0x3;
+
+	value = ioread32(host->ioaddr + base);
+	ret = esdhc_readb_fixup(esdhc, reg, value);
+	return ret;
+}
+
+static void esdhc_be_writel(struct sdhci_host *host, u32 val, int reg)
+{
+	u32 value;
+
+	value = esdhc_writel_fixup(esdhc, reg, val, 0);
+	iowrite32be(value, host->ioaddr + reg);
+}
+
+static void esdhc_le_writel(struct sdhci_host *host, u32 val, int reg)
+{
+	u32 value;
+
+	value = esdhc_writel_fixup(esdhc, reg, val, 0);
+	iowrite32(value, host->ioaddr + reg);
+}
+
+static void esdhc_be_writew(struct sdhci_host *host, u16 val, int reg)
+{
+	int base = reg & ~0x3;
+	u32 value;
+	u32 ret;
+
+	value = ioread32be(host->ioaddr + base);
+	ret = esdhc_writew_fixup(esdhc, reg, val, value);
+	if (reg != SDHCI_TRANSFER_MODE)
+		iowrite32be(ret, host->ioaddr + base);
+}
+
+static void esdhc_le_writew(struct sdhci_host *host, u16 val, int reg)
+{
+	int base = reg & ~0x3;
+	u32 value;
+	u32 ret;
+
+	value = ioread32(host->ioaddr + base);
+	ret = esdhc_writew_fixup(esdhc, reg, val, value);
+	if (reg != SDHCI_TRANSFER_MODE)
+		iowrite32(ret, host->ioaddr + base);
+}
+
+static void esdhc_be_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+	int base = reg & ~0x3;
+	u32 value;
+	u32 ret;
+
+	value = ioread32be(host->ioaddr + base);
+	ret = esdhc_writeb_fixup(esdhc, reg, val, value);
+	iowrite32be(ret, host->ioaddr + base);
+}
+
+static void esdhc_le_writeb(struct sdhci_host *host, u8 val, int reg)
+{
+	int base = reg & ~0x3;
+	u32 value;
+	u32 ret;
+
+	value = ioread32(host->ioaddr + base);
+	ret = esdhc_writeb_fixup(esdhc, reg, val, value);
+	iowrite32(ret, host->ioaddr + base);
 }
 
 /*
@@ -149,19 +347,15 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
  * For Continue, apply soft reset for data(SYSCTL[RSTD]);
  * and re-issue the entire read transaction from beginning.
  */
-static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
+static void esdhc_of_adma_workaround(struct sdhci_host *host, u32 intmask)
 {
-	u32 tmp;
 	bool applicable;
 	dma_addr_t dmastart;
 	dma_addr_t dmanow;
 
-	tmp = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
-	tmp = (tmp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
-
 	applicable = (intmask & SDHCI_INT_DATA_END) &&
-		(intmask & SDHCI_INT_BLK_GAP) &&
-		(tmp == VENDOR_V_23);
+		     (intmask & SDHCI_INT_BLK_GAP) &&
+		     (esdhc->vendor_ver == VENDOR_V_23);
 	if (!applicable)
 		return;
 
@@ -179,7 +373,11 @@ static void esdhci_of_adma_workaround(struct sdhci_host *host, u32 intmask)
 
 static int esdhc_of_enable_dma(struct sdhci_host *host)
 {
-	setbits32(host->ioaddr + ESDHC_DMA_SYSCTL, ESDHC_DMA_SNOOP);
+	u32 value;
+
+	value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+	value |= ESDHC_DMA_SNOOP;
+	sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
 	return 0;
 }
 
@@ -209,9 +407,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 		return;
 
 	/* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */
-	temp = esdhc_readw(host, SDHCI_HOST_VERSION);
-	temp = (temp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
-	if (temp < VENDOR_V_23)
+	if (esdhc->vendor_ver < VENDOR_V_23)
 		pre_div = 2;
 
 	/* Workaround to reduce the clock frequency for p1010 esdhc */
@@ -247,39 +443,26 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
 	mdelay(1);
 }
 
-static void esdhc_of_platform_init(struct sdhci_host *host)
-{
-	u32 vvn;
-
-	vvn = in_be32(host->ioaddr + SDHCI_SLOT_INT_STATUS);
-	vvn = (vvn & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT;
-	if (vvn == VENDOR_V_22)
-		host->quirks2 |= SDHCI_QUIRK2_HOST_NO_CMD23;
-
-	if (vvn > VENDOR_V_22)
-		host->quirks &= ~SDHCI_QUIRK_NO_BUSY_IRQ;
-}
-
 static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
 {
 	u32 ctrl;
 
+	ctrl = sdhci_readl(host, ESDHC_PROCTL);
+	ctrl &= (~ESDHC_CTRL_BUSWIDTH_MASK);
 	switch (width) {
 	case MMC_BUS_WIDTH_8:
-		ctrl = ESDHC_CTRL_8BITBUS;
+		ctrl |= ESDHC_CTRL_8BITBUS;
 		break;
 
 	case MMC_BUS_WIDTH_4:
-		ctrl = ESDHC_CTRL_4BITBUS;
+		ctrl |= ESDHC_CTRL_4BITBUS;
 		break;
 
 	default:
-		ctrl = 0;
 		break;
 	}
 
-	clrsetbits_be32(host->ioaddr + SDHCI_HOST_CONTROL,
-			ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
+	sdhci_writel(host, ctrl, ESDHC_PROCTL);
 }
 
 static void esdhc_reset(struct sdhci_host *host, u8 mask)
@@ -290,32 +473,13 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
-static const struct sdhci_ops sdhci_esdhc_ops = {
-	.read_l = esdhc_readl,
-	.read_w = esdhc_readw,
-	.read_b = esdhc_readb,
-	.write_l = esdhc_writel,
-	.write_w = esdhc_writew,
-	.write_b = esdhc_writeb,
-	.set_clock = esdhc_of_set_clock,
-	.enable_dma = esdhc_of_enable_dma,
-	.get_max_clock = esdhc_of_get_max_clock,
-	.get_min_clock = esdhc_of_get_min_clock,
-	.platform_init = esdhc_of_platform_init,
-	.adma_workaround = esdhci_of_adma_workaround,
-	.set_bus_width = esdhc_pltfm_set_bus_width,
-	.reset = esdhc_reset,
-	.set_uhs_signaling = sdhci_set_uhs_signaling,
-};
-
 #ifdef CONFIG_PM
-
 static u32 esdhc_proctl;
 static int esdhc_of_suspend(struct device *dev)
 {
 	struct sdhci_host *host = dev_get_drvdata(dev);
 
-	esdhc_proctl = sdhci_be32bs_readl(host, SDHCI_HOST_CONTROL);
+	esdhc_proctl = sdhci_readl(host, SDHCI_HOST_CONTROL);
 
 	return sdhci_suspend_host(host);
 }
@@ -328,9 +492,8 @@ static int esdhc_of_resume(struct device *dev)
 	if (ret == 0) {
 		/* Isn't this already done by sdhci_resume_host() ? --rmk */
 		esdhc_of_enable_dma(host);
-		sdhci_be32bs_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
+		sdhci_writel(host, esdhc_proctl, SDHCI_HOST_CONTROL);
 	}
-
 	return ret;
 }
 
@@ -343,16 +506,56 @@ static const struct dev_pm_ops esdhc_pmops = {
 #define ESDHC_PMOPS NULL
 #endif
 
-static const struct sdhci_pltfm_data sdhci_esdhc_pdata = {
-	/*
-	 * card detection could be handled via GPIO
-	 * eSDHC cannot support End Attribute in NOP ADMA descriptor
-	 */
-	.quirks = ESDHC_DEFAULT_QUIRKS | SDHCI_QUIRK_BROKEN_CARD_DETECTION
-		| SDHCI_QUIRK_NO_CARD_NO_RESET
-		| SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
-	.ops = &sdhci_esdhc_ops,
+static struct sdhci_ops sdhci_esdhc_ops = {
+	.set_clock = esdhc_of_set_clock,
+	.enable_dma = esdhc_of_enable_dma,
+	.get_max_clock = esdhc_of_get_max_clock,
+	.get_min_clock = esdhc_of_get_min_clock,
+	.adma_workaround = esdhc_of_adma_workaround,
+	.set_bus_width = esdhc_pltfm_set_bus_width,
+	.reset = esdhc_reset,
+	.set_uhs_signaling = sdhci_set_uhs_signaling,
 };
+static struct sdhci_pltfm_data sdhci_esdhc_pdata;
+
+static void esdhc_setup_pltfm_data(struct platform_device *pdev)
+{
+	struct device_node *np;
+
+	np = pdev->dev.of_node;
+	if (of_get_property(np, "little-endian", NULL)) {
+		sdhci_esdhc_ops.read_l	= esdhc_le_readl;
+		sdhci_esdhc_ops.read_w	= esdhc_le_readw;
+		sdhci_esdhc_ops.read_b	= esdhc_le_readb;
+		sdhci_esdhc_ops.write_l	= esdhc_le_writel;
+		sdhci_esdhc_ops.write_w	= esdhc_le_writew;
+		sdhci_esdhc_ops.write_b	= esdhc_le_writeb;
+	} else {
+		sdhci_esdhc_ops.read_l	= esdhc_be_readl;
+		sdhci_esdhc_ops.read_w	= esdhc_be_readw;
+		sdhci_esdhc_ops.read_b	= esdhc_be_readb;
+		sdhci_esdhc_ops.write_l	= esdhc_be_writel;
+		sdhci_esdhc_ops.write_w	= esdhc_be_writew;
+		sdhci_esdhc_ops.write_b	= esdhc_be_writeb;
+	}
+
+	sdhci_esdhc_pdata.quirks = ESDHC_DEFAULT_QUIRKS |
+				   SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+				   SDHCI_QUIRK_NO_CARD_NO_RESET |
+				   SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC;
+	sdhci_esdhc_pdata.ops = &sdhci_esdhc_ops;
+}
+
+static void esdhc_init(struct esdhc_host *esdhc, struct sdhci_host *host)
+{
+	u16 host_ver;
+
+	host_ver = sdhci_readw(host, SDHCI_HOST_VERSION);
+	esdhc->vendor_ver = (host_ver & SDHCI_VENDOR_VER_MASK) >>
+			     SDHCI_VENDOR_VER_SHIFT;
+	esdhc->spec_ver = host_ver & SDHCI_SPEC_VER_MASK;
+	esdhc->host = host;
+}
 
 static int sdhci_esdhc_probe(struct platform_device *pdev)
 {
@@ -360,10 +563,15 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
 	struct device_node *np;
 	int ret;
 
+	esdhc_setup_pltfm_data(pdev);
+
 	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
 	if (IS_ERR(host))
 		return PTR_ERR(host);
 
+	esdhc = kmalloc(sizeof(struct esdhc_host), GFP_KERNEL);
+	esdhc_init(esdhc, host);
+
 	sdhci_get_of_property(pdev);
 
 	np = pdev->dev.of_node;
-- 
2.1.0.27.g96db324

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux