*/
#include <linux/io.h>
+#include <linux/iopoll.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/clk.h>
writel(((readl(base) & ~(mask << shift)) | (val << shift)), base);
}
+static inline void esdhc_wait_for_card_clock_gate_off(struct sdhci_host *host)
+{
+ u32 present_state;
+ int ret;
+
+ ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, present_state,
+ (present_state & ESDHC_CLOCK_GATE_OFF), 2, 100);
+ if (ret == -ETIMEDOUT)
+ dev_warn(mmc_dev(host->mmc), "%s: card clock still not gate off in 100us!.\n", __func__);
+}
+
static u32 esdhc_readl_le(struct sdhci_host *host, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
else
new_val &= ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON;
writel(new_val, host->ioaddr + ESDHC_VENDOR_SPEC);
+ if (!(new_val & ESDHC_VENDOR_SPEC_FRC_SDCLK_ON))
+ esdhc_wait_for_card_clock_gate_off(host);
return;
case SDHCI_HOST_CONTROL2:
new_val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
int ddr_pre_div = imx_data->is_ddr ? 2 : 1;
int pre_div = 1;
int div = 1;
+ int ret;
u32 temp, val;
if (esdhc_is_usdhc(imx_data)) {
val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
writel(val & ~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
host->ioaddr + ESDHC_VENDOR_SPEC);
+ esdhc_wait_for_card_clock_gate_off(host);
}
if (clock == 0) {
| (pre_div << ESDHC_PREDIV_SHIFT));
sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
+ /* need to wait the bit 3 of the PRSSTAT to be set, make sure card clock is stable */
+ ret = readl_poll_timeout(host->ioaddr + ESDHC_PRSSTAT, temp,
+ (temp & ESDHC_CLOCK_STABLE), 2, 100);
+ if (ret == -ETIMEDOUT)
+ dev_warn(mmc_dev(host->mmc), "card clock still not stable in 100us!.\n");
+
if (esdhc_is_usdhc(imx_data)) {
val = readl(host->ioaddr + ESDHC_VENDOR_SPEC);
writel(val | ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
host->ioaddr + ESDHC_VENDOR_SPEC);
}
- mdelay(1);
}
static unsigned int esdhc_pltfm_get_ro(struct sdhci_host *host)
writel(readl(host->ioaddr + ESDHC_VENDOR_SPEC) &
~ESDHC_VENDOR_SPEC_FRC_SDCLK_ON,
host->ioaddr + ESDHC_VENDOR_SPEC);
+ esdhc_wait_for_card_clock_gate_off(host);
/* force a reset on strobe dll */
writel(ESDHC_STROBE_DLL_CTRL_RESET,