diff mbox

[v4,6/6] mmc: esdhc: add eMMC DDR mode support

Message ID 1438314911-47902-1-git-send-email-yangbo.lu@freescale.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

yangbo lu July 31, 2015, 3:55 a.m. UTC
Add eMMC DDR mode support for Freescale SDHC adapter card.
The u-boot should provide device tree properties 'adapter-type'
and 'periperal-frequency' for this feature, if not, the card
would not use DDR mode.

Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
---
 drivers/mmc/host/sdhci-esdhc.h    |  24 +++++++
 drivers/mmc/host/sdhci-of-esdhc.c | 132 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 152 insertions(+), 4 deletions(-)

Comments

Dong Aisheng Aug. 4, 2015, 9:22 a.m. UTC | #1
On Fri, Jul 31, 2015 at 11:55 AM, Yangbo Lu <yangbo.lu@freescale.com> wrote:
> Add eMMC DDR mode support for Freescale SDHC adapter card.
> The u-boot should provide device tree properties 'adapter-type'
> and 'periperal-frequency' for this feature, if not, the card
> would not use DDR mode.
>
> Signed-off-by: Yangbo Lu <yangbo.lu@freescale.com>
> ---
>  drivers/mmc/host/sdhci-esdhc.h    |  24 +++++++
>  drivers/mmc/host/sdhci-of-esdhc.c | 132 ++++++++++++++++++++++++++++++++++++--
>  2 files changed, 152 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
> index 163ac99..015ec01 100644
> --- a/drivers/mmc/host/sdhci-esdhc.h
> +++ b/drivers/mmc/host/sdhci-esdhc.h
> @@ -28,10 +28,32 @@
>  #define ESDHC_CLOCK_MASK       0x0000fff0
>  #define ESDHC_PREDIV_SHIFT     8
>  #define ESDHC_DIVIDER_SHIFT    4
> +#define ESDHC_CLOCK_CRDEN      0x00000008
>  #define ESDHC_CLOCK_PEREN      0x00000004
>  #define ESDHC_CLOCK_HCKEN      0x00000002
>  #define ESDHC_CLOCK_IPGEN      0x00000001
>
> +#define ESDHCI_PRESENT_STATE   0x24
> +#define ESDHC_CLK_STABLE       0x00000008
> +
> +#define ESDHC_CAPABILITIES_1   0x114
> +#define ESDHC_MODE_MASK                0x00000007
> +#define ESDHC_MODE_DDR50_SEL   0xfffffffc
> +#define ESDHC_MODE_DDR50       0x00000004
> +
> +#define ESDHC_CLOCK_CONTROL    0x144
> +#define ESDHC_CLKLPBK_EXTPIN   0x80000000
> +#define ESDHC_CMDCLK_SHIFTED   0x00008000
> +
> +/* SDHC Adapter Card Type */
> +#define ESDHC_ADAPTER_TYPE_EMMC45       0x1    /* eMMC Card Rev4.5 */
> +#define ESDHC_ADAPTER_TYPE_SDMMC_LEGACY 0x2    /* SD/MMC Legacy Card */
> +#define ESDHC_ADAPTER_TYPE_EMMC44       0x3    /* eMMC Card Rev4.4 */
> +#define ESDHC_ADAPTER_TYPE_RSV          0x4    /* Reserved */
> +#define ESDHC_ADAPTER_TYPE_MMC          0x5    /* MMC Card */
> +#define ESDHC_ADAPTER_TYPE_SD           0x6    /* SD Card Rev2.0 Rev3.0 */
> +#define ESDHC_NO_ADAPTER                0x7    /* No Card is Present*/
> +

Hi Yangbo,

You could put those of_esdhc specific defines in of_esdhc driver since
sdhci-esdhc.h
is shared by both sdhci-imx-esdhc and sdhci-of-esdhc driver.
Or it may be time to remove such dependency that each driver uses its
own head file
separately since there's already a lot difference between them and no
reason to share
the headfile anymore.
The later one might be a more reasonable way to me.

Regards
Dong Aisheng

>  /* pltfm-specific */
>  #define ESDHC_HOST_CONTROL_LE  0x20
>
> @@ -45,6 +67,8 @@
>  /* OF-specific */
>  #define ESDHC_DMA_SYSCTL       0x40c
>  #define ESDHC_DMA_SNOOP                0x00000040
> +#define ESDHC_FLUSH_ASYNC_FIFO          0x00040000
> +#define ESDHC_USE_PERIPHERAL_CLK        0x00080000
>
>  #define ESDHC_HOST_CONTROL_RES 0x01
>
> diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
> index f1021d8..6d7e3f9 100644
> --- a/drivers/mmc/host/sdhci-of-esdhc.c
> +++ b/drivers/mmc/host/sdhci-of-esdhc.c
> @@ -24,11 +24,30 @@
>
>  #define VENDOR_V_22    0x12
>  #define VENDOR_V_23    0x13
> +
> +static u32 adapter_type;
> +static bool peripheral_clk_available;
> +
>  static u32 esdhc_readl(struct sdhci_host *host, int reg)
>  {
>         u32 ret;
>
> -       ret = sdhci_32bs_readl(host, reg);
> +       if (reg == SDHCI_CAPABILITIES_1) {
> +               ret = sdhci_32bs_readl(host, ESDHC_CAPABILITIES_1);
> +               switch (adapter_type) {
> +               case ESDHC_ADAPTER_TYPE_EMMC44:
> +                       if (ret & ESDHC_MODE_DDR50) {
> +                               ret &= ESDHC_MODE_DDR50_SEL;
> +                               /* enable 1/8V DDR capable */
> +                               host->mmc->caps |= MMC_CAP_1_8V_DDR;
> +                       } else
> +                               ret &= ~ESDHC_MODE_MASK;
> +                       break;
> +               default:
> +                       ret &= ~ESDHC_MODE_MASK;
> +               }
> +       } else
> +               ret = sdhci_32bs_readl(host, 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
> @@ -159,8 +178,11 @@ static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
>         }
>
>         /* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
> -       if (reg == SDHCI_HOST_CONTROL)
> +       if (reg == SDHCI_HOST_CONTROL) {
>                 val &= ~ESDHC_HOST_CONTROL_RES;
> +               val &= ~SDHCI_CTRL_HISPD;
> +               val |= (sdhci_32bs_readl(host, reg) & SDHCI_CTRL_HISPD);
> +       }
>         sdhci_clrsetbits(host, 0xff, val, reg);
>  }
>
> @@ -307,6 +329,84 @@ static void esdhc_reset(struct sdhci_host *host, u8 mask)
>         sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
>  }
>
> +static void esdhc_clock_control(struct sdhci_host *host, bool enable)
> +{
> +       u32 value;
> +       u32 time_out;
> +
> +       value = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
> +
> +       if (enable)
> +               value |= ESDHC_CLOCK_CRDEN;
> +       else
> +               value &= ~ESDHC_CLOCK_CRDEN;
> +
> +       sdhci_writel(host, value, ESDHC_SYSTEM_CONTROL);
> +
> +       time_out = 20;
> +       value = ESDHC_CLK_STABLE;
> +       while (!(sdhci_readl(host, ESDHCI_PRESENT_STATE) & value)) {
> +               if (time_out == 0) {
> +                       pr_err("%s: Internal clock never stabilised.\n",
> +                               mmc_hostname(host->mmc));
> +                       break;
> +               }
> +               time_out--;
> +               mdelay(1);
> +       }
> +}
> +
> +static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
> +{
> +       u16 ctrl_2;
> +       u32 time_out;
> +       u32 value;
> +
> +       ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
> +       /* Select Bus Speed Mode for host */
> +       ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
> +       if ((uhs == MMC_TIMING_MMC_HS200) ||
> +               (uhs == MMC_TIMING_UHS_SDR104))
> +               ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
> +       else if (uhs == MMC_TIMING_UHS_SDR12)
> +               ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
> +       else if (uhs == MMC_TIMING_UHS_SDR25)
> +               ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
> +       else if (uhs == MMC_TIMING_UHS_SDR50)
> +               ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
> +       else if (uhs == MMC_TIMING_UHS_DDR50)
> +               ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
> +
> +       if (uhs == MMC_TIMING_UHS_DDR50) {
> +               esdhc_clock_control(host, false);
> +               sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
> +               value = sdhci_readl(host, ESDHC_CLOCK_CONTROL);
> +               value |= (ESDHC_CLKLPBK_EXTPIN | ESDHC_CMDCLK_SHIFTED);
> +               sdhci_writel(host, value, ESDHC_CLOCK_CONTROL);
> +               esdhc_clock_control(host, true);
> +
> +               esdhc_clock_control(host, false);
> +               value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
> +               value |= ESDHC_FLUSH_ASYNC_FIFO;
> +               sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
> +               /* Wait max 20 ms */
> +               time_out = 20;
> +               value = ESDHC_FLUSH_ASYNC_FIFO;
> +               while (sdhci_readl(host, ESDHC_DMA_SYSCTL) & value) {
> +                       if (time_out == 0) {
> +                               pr_err("%s: FAF bit is auto cleaned failed.\n",
> +                                       mmc_hostname(host->mmc));
> +
> +                               break;
> +                       }
> +                       time_out--;
> +                       mdelay(1);
> +               }
> +               esdhc_clock_control(host, true);
> +       } else
> +               sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
> +}
> +
>  static const struct sdhci_ops sdhci_esdhc_ops = {
>         .read_l = esdhc_readl,
>         .read_w = esdhc_readw,
> @@ -322,7 +422,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
>         .adma_workaround = esdhci_of_adma_workaround,
>         .set_bus_width = esdhc_pltfm_set_bus_width,
>         .reset = esdhc_reset,
> -       .set_uhs_signaling = sdhci_set_uhs_signaling,
> +       .set_uhs_signaling = esdhc_set_uhs_signaling,
>  };
>
>  #ifdef CONFIG_PM
> @@ -376,6 +476,8 @@ static void esdhc_get_property(struct platform_device *pdev)
>         struct device_node *np = pdev->dev.of_node;
>         struct sdhci_host *host = platform_get_drvdata(pdev);
>         struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +       const __be32 *value;
> +       int size;
>
>         sdhci_get_of_property(pdev);
>
> @@ -383,6 +485,18 @@ static void esdhc_get_property(struct platform_device *pdev)
>         mmc_of_parse(host->mmc);
>         mmc_of_parse_voltage(np, &host->ocr_mask);
>
> +       value = of_get_property(np, "adapter-type", &size);
> +       if (value && size == sizeof(*value) && *value)
> +               adapter_type = be32_to_cpup(value);
> +
> +       /* If getting a peripheral-frequency, use it instead */
> +       value = of_get_property(np, "peripheral-frequency", &size);
> +       if (value && size == sizeof(*value) && *value) {
> +               pltfm_host->clock = be32_to_cpup(value);
> +               peripheral_clk_available = true;
> +       } else
> +               peripheral_clk_available = false;
> +
>         if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
>             of_device_is_compatible(np, "fsl,p5020-esdhc") ||
>             of_device_is_compatible(np, "fsl,p4080-esdhc") ||
> @@ -409,13 +523,23 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
>  {
>         struct sdhci_host *host;
>         int ret;
> -
> +       u32 value;
>
>         host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
>         if (IS_ERR(host))
>                 return PTR_ERR(host);
>
>         esdhc_get_property(pdev);
> +
> +       /* Select peripheral clock as the eSDHC clock */
> +       if (peripheral_clk_available) {
> +               esdhc_clock_control(host, false);
> +               value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
> +               value |= ESDHC_USE_PERIPHERAL_CLK;
> +               sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
> +               esdhc_clock_control(host, true);
> +       }
> +
>         ret = sdhci_add_host(host);
>         if (ret)
>                 goto err;
> --
> 2.1.0.27.g96db324
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/host/sdhci-esdhc.h b/drivers/mmc/host/sdhci-esdhc.h
index 163ac99..015ec01 100644
--- a/drivers/mmc/host/sdhci-esdhc.h
+++ b/drivers/mmc/host/sdhci-esdhc.h
@@ -28,10 +28,32 @@ 
 #define ESDHC_CLOCK_MASK	0x0000fff0
 #define ESDHC_PREDIV_SHIFT	8
 #define ESDHC_DIVIDER_SHIFT	4
+#define ESDHC_CLOCK_CRDEN	0x00000008
 #define ESDHC_CLOCK_PEREN	0x00000004
 #define ESDHC_CLOCK_HCKEN	0x00000002
 #define ESDHC_CLOCK_IPGEN	0x00000001
 
+#define ESDHCI_PRESENT_STATE	0x24
+#define ESDHC_CLK_STABLE	0x00000008
+
+#define ESDHC_CAPABILITIES_1	0x114
+#define ESDHC_MODE_MASK		0x00000007
+#define ESDHC_MODE_DDR50_SEL	0xfffffffc
+#define ESDHC_MODE_DDR50	0x00000004
+
+#define ESDHC_CLOCK_CONTROL	0x144
+#define ESDHC_CLKLPBK_EXTPIN	0x80000000
+#define ESDHC_CMDCLK_SHIFTED	0x00008000
+
+/* SDHC Adapter Card Type */
+#define ESDHC_ADAPTER_TYPE_EMMC45       0x1	/* eMMC Card Rev4.5 */
+#define ESDHC_ADAPTER_TYPE_SDMMC_LEGACY 0x2	/* SD/MMC Legacy Card */
+#define ESDHC_ADAPTER_TYPE_EMMC44       0x3	/* eMMC Card Rev4.4 */
+#define ESDHC_ADAPTER_TYPE_RSV          0x4	/* Reserved */
+#define ESDHC_ADAPTER_TYPE_MMC          0x5	/* MMC Card */
+#define ESDHC_ADAPTER_TYPE_SD           0x6	/* SD Card Rev2.0 Rev3.0 */
+#define ESDHC_NO_ADAPTER                0x7	/* No Card is Present*/
+
 /* pltfm-specific */
 #define ESDHC_HOST_CONTROL_LE	0x20
 
@@ -45,6 +67,8 @@ 
 /* OF-specific */
 #define ESDHC_DMA_SYSCTL	0x40c
 #define ESDHC_DMA_SNOOP		0x00000040
+#define ESDHC_FLUSH_ASYNC_FIFO          0x00040000
+#define ESDHC_USE_PERIPHERAL_CLK        0x00080000
 
 #define ESDHC_HOST_CONTROL_RES	0x01
 
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index f1021d8..6d7e3f9 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -24,11 +24,30 @@ 
 
 #define VENDOR_V_22	0x12
 #define VENDOR_V_23	0x13
+
+static u32 adapter_type;
+static bool peripheral_clk_available;
+
 static u32 esdhc_readl(struct sdhci_host *host, int reg)
 {
 	u32 ret;
 
-	ret = sdhci_32bs_readl(host, reg);
+	if (reg == SDHCI_CAPABILITIES_1) {
+		ret = sdhci_32bs_readl(host, ESDHC_CAPABILITIES_1);
+		switch (adapter_type) {
+		case ESDHC_ADAPTER_TYPE_EMMC44:
+			if (ret & ESDHC_MODE_DDR50) {
+				ret &= ESDHC_MODE_DDR50_SEL;
+				/* enable 1/8V DDR capable */
+				host->mmc->caps |= MMC_CAP_1_8V_DDR;
+			} else
+				ret &= ~ESDHC_MODE_MASK;
+			break;
+		default:
+			ret &= ~ESDHC_MODE_MASK;
+		}
+	} else
+		ret = sdhci_32bs_readl(host, 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
@@ -159,8 +178,11 @@  static void esdhc_writeb(struct sdhci_host *host, u8 val, int reg)
 	}
 
 	/* Prevent SDHCI core from writing reserved bits (e.g. HISPD). */
-	if (reg == SDHCI_HOST_CONTROL)
+	if (reg == SDHCI_HOST_CONTROL) {
 		val &= ~ESDHC_HOST_CONTROL_RES;
+		val &= ~SDHCI_CTRL_HISPD;
+		val |= (sdhci_32bs_readl(host, reg) & SDHCI_CTRL_HISPD);
+	}
 	sdhci_clrsetbits(host, 0xff, val, reg);
 }
 
@@ -307,6 +329,84 @@  static void esdhc_reset(struct sdhci_host *host, u8 mask)
 	sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
 }
 
+static void esdhc_clock_control(struct sdhci_host *host, bool enable)
+{
+	u32 value;
+	u32 time_out;
+
+	value = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
+
+	if (enable)
+		value |= ESDHC_CLOCK_CRDEN;
+	else
+		value &= ~ESDHC_CLOCK_CRDEN;
+
+	sdhci_writel(host, value, ESDHC_SYSTEM_CONTROL);
+
+	time_out = 20;
+	value = ESDHC_CLK_STABLE;
+	while (!(sdhci_readl(host, ESDHCI_PRESENT_STATE) & value)) {
+		if (time_out == 0) {
+			pr_err("%s: Internal clock never stabilised.\n",
+				mmc_hostname(host->mmc));
+			break;
+		}
+		time_out--;
+		mdelay(1);
+	}
+}
+
+static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
+{
+	u16 ctrl_2;
+	u32 time_out;
+	u32 value;
+
+	ctrl_2 = sdhci_readw(host, SDHCI_HOST_CONTROL2);
+	/* Select Bus Speed Mode for host */
+	ctrl_2 &= ~SDHCI_CTRL_UHS_MASK;
+	if ((uhs == MMC_TIMING_MMC_HS200) ||
+		(uhs == MMC_TIMING_UHS_SDR104))
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR104;
+	else if (uhs == MMC_TIMING_UHS_SDR12)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR12;
+	else if (uhs == MMC_TIMING_UHS_SDR25)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR25;
+	else if (uhs == MMC_TIMING_UHS_SDR50)
+		ctrl_2 |= SDHCI_CTRL_UHS_SDR50;
+	else if (uhs == MMC_TIMING_UHS_DDR50)
+		ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+
+	if (uhs == MMC_TIMING_UHS_DDR50) {
+		esdhc_clock_control(host, false);
+		sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+		value = sdhci_readl(host, ESDHC_CLOCK_CONTROL);
+		value |= (ESDHC_CLKLPBK_EXTPIN | ESDHC_CMDCLK_SHIFTED);
+		sdhci_writel(host, value, ESDHC_CLOCK_CONTROL);
+		esdhc_clock_control(host, true);
+
+		esdhc_clock_control(host, false);
+		value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+		value |= ESDHC_FLUSH_ASYNC_FIFO;
+		sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
+		/* Wait max 20 ms */
+		time_out = 20;
+		value = ESDHC_FLUSH_ASYNC_FIFO;
+		while (sdhci_readl(host, ESDHC_DMA_SYSCTL) & value) {
+			if (time_out == 0) {
+				pr_err("%s: FAF bit is auto cleaned failed.\n",
+					mmc_hostname(host->mmc));
+
+				break;
+			}
+			time_out--;
+			mdelay(1);
+		}
+		esdhc_clock_control(host, true);
+	} else
+		sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
+}
+
 static const struct sdhci_ops sdhci_esdhc_ops = {
 	.read_l = esdhc_readl,
 	.read_w = esdhc_readw,
@@ -322,7 +422,7 @@  static const struct sdhci_ops sdhci_esdhc_ops = {
 	.adma_workaround = esdhci_of_adma_workaround,
 	.set_bus_width = esdhc_pltfm_set_bus_width,
 	.reset = esdhc_reset,
-	.set_uhs_signaling = sdhci_set_uhs_signaling,
+	.set_uhs_signaling = esdhc_set_uhs_signaling,
 };
 
 #ifdef CONFIG_PM
@@ -376,6 +476,8 @@  static void esdhc_get_property(struct platform_device *pdev)
 	struct device_node *np = pdev->dev.of_node;
 	struct sdhci_host *host = platform_get_drvdata(pdev);
 	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	const __be32 *value;
+	int size;
 
 	sdhci_get_of_property(pdev);
 
@@ -383,6 +485,18 @@  static void esdhc_get_property(struct platform_device *pdev)
 	mmc_of_parse(host->mmc);
 	mmc_of_parse_voltage(np, &host->ocr_mask);
 
+	value = of_get_property(np, "adapter-type", &size);
+	if (value && size == sizeof(*value) && *value)
+		adapter_type = be32_to_cpup(value);
+
+	/* If getting a peripheral-frequency, use it instead */
+	value = of_get_property(np, "peripheral-frequency", &size);
+	if (value && size == sizeof(*value) && *value) {
+		pltfm_host->clock = be32_to_cpup(value);
+		peripheral_clk_available = true;
+	} else
+		peripheral_clk_available = false;
+
 	if (of_device_is_compatible(np, "fsl,p5040-esdhc") ||
 	    of_device_is_compatible(np, "fsl,p5020-esdhc") ||
 	    of_device_is_compatible(np, "fsl,p4080-esdhc") ||
@@ -409,13 +523,23 @@  static int sdhci_esdhc_probe(struct platform_device *pdev)
 {
 	struct sdhci_host *host;
 	int ret;
-
+	u32 value;
 
 	host = sdhci_pltfm_init(pdev, &sdhci_esdhc_pdata, 0);
 	if (IS_ERR(host))
 		return PTR_ERR(host);
 
 	esdhc_get_property(pdev);
+
+	/* Select peripheral clock as the eSDHC clock */
+	if (peripheral_clk_available) {
+		esdhc_clock_control(host, false);
+		value = sdhci_readl(host, ESDHC_DMA_SYSCTL);
+		value |= ESDHC_USE_PERIPHERAL_CLK;
+		sdhci_writel(host, value, ESDHC_DMA_SYSCTL);
+		esdhc_clock_control(host, true);
+	}
+
 	ret = sdhci_add_host(host);
 	if (ret)
 		goto err;