|
@@ -199,6 +199,14 @@ static unsigned int esdhc_of_get_min_clock(struct sdhci_host *host)
|
|
|
|
|
|
static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
|
|
|
{
|
|
|
+
|
|
|
+ int pre_div = 2;
|
|
|
+ int div = 1;
|
|
|
+ u32 temp;
|
|
|
+
|
|
|
+ if (clock == 0)
|
|
|
+ goto out;
|
|
|
+
|
|
|
/* Workaround to reduce the clock frequency for p1010 esdhc */
|
|
|
if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) {
|
|
|
if (clock > 20000000)
|
|
@@ -207,8 +215,31 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock)
|
|
|
clock -= 5000000;
|
|
|
}
|
|
|
|
|
|
- /* Set the clock */
|
|
|
- esdhc_set_clock(host, clock, host->max_clk);
|
|
|
+ temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
|
|
|
+ temp &= ~(ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
|
|
|
+ | ESDHC_CLOCK_MASK);
|
|
|
+ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
|
|
|
+
|
|
|
+ while (host->max_clk / pre_div / 16 > clock && pre_div < 256)
|
|
|
+ pre_div *= 2;
|
|
|
+
|
|
|
+ while (host->max_clk / pre_div / div > clock && div < 16)
|
|
|
+ div++;
|
|
|
+
|
|
|
+ dev_dbg(mmc_dev(host->mmc), "desired SD clock: %d, actual: %d\n",
|
|
|
+ clock, host_clock / pre_div / div);
|
|
|
+
|
|
|
+ pre_div >>= 1;
|
|
|
+ div--;
|
|
|
+
|
|
|
+ temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL);
|
|
|
+ temp |= (ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | ESDHC_CLOCK_PEREN
|
|
|
+ | (div << ESDHC_DIVIDER_SHIFT)
|
|
|
+ | (pre_div << ESDHC_PREDIV_SHIFT));
|
|
|
+ sdhci_writel(host, temp, ESDHC_SYSTEM_CONTROL);
|
|
|
+ mdelay(1);
|
|
|
+out:
|
|
|
+ host->clock = clock;
|
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_PM
|