From: yinbo.zhu <yinbo.zhu@xxxxxxx> Convert to use soc_device_match method to fix up eSDHC clock for ls1046a/ls1012a/p1010. Also add eSDHC clock fixup for ls1021a according to its datasheet. The maxmum speed for ls1021a eSDHC high speed mode is 46.5MHz. Signed-off-by: Yinbo Zhu <yinbo.zhu@xxxxxxx> --- drivers/mmc/host/sdhci-of-esdhc.c | 105 ++++++++++++++++++++++++++++++------- 1 files changed, 85 insertions(+), 20 deletions(-) diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 4ffa6b1..4d82c6d 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -29,11 +29,58 @@ #define VENDOR_V_22 0x12 #define VENDOR_V_23 0x13 +struct esdhc_clk_fixup { + /* SD speed modes */ + long ds; + long hs; + long sdr12; + long sdr25; + long sdr50; + long sdr104; + long ddr50; + /* MMC speed modes */ + long mmc_ds; + long mmc_hs; + long hs200; + long ddr52; +}; + +static struct esdhc_clk_fixup ls1021a_esdhc_clk = { + .mmc_hs = 46500000, + .hs = 46500000, +}; + +static struct esdhc_clk_fixup ls1046a_esdhc_clk = { + .sdr104 = 167000000, + .hs200 = 167000000, +}; + +static struct esdhc_clk_fixup ls1012a_esdhc_clk = { + .sdr104 = 125000000, + .hs200 = 125000000, +}; + +static struct esdhc_clk_fixup p1010_esdhc_clk = { + .ds = 20000000, + .hs = 40000000, + .mmc_ds = 20000000, + .mmc_hs = 42000000, +}; + +static struct soc_device_attribute soc_esdhc_clk_fixup[] = { + { .family = "QorIQ LS1021A", .data = &ls1021a_esdhc_clk}, + { .family = "QorIQ LS1046A", .data = &ls1046a_esdhc_clk}, + { .family = "QorIQ LS1012A", .data = &ls1012a_esdhc_clk}, + { .family = "QorIQ P1010", .data = &p1010_esdhc_clk}, + {}, +}; + struct sdhci_esdhc { u8 vendor_ver; u8 spec_ver; bool quirk_incorrect_hostver; unsigned int peripheral_clock; + const struct esdhc_clk_fixup *clk_fixup; }; /** @@ -485,6 +532,14 @@ static void esdhc_clock_enable(struct sdhci_host *host, bool enable) } } +static long esdhc_clock_fixup(long clock, long clock_standard, long fixup) +{ + if (!fixup) + return clock; + + return (clock == clock_standard) ? fixup : clock; +} + static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); @@ -492,6 +547,7 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) int pre_div = 1; int div = 1; ktime_t timeout; + long fixup; u32 temp; host->mmc->actual_clock = 0; @@ -505,26 +561,31 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) if (esdhc->vendor_ver < VENDOR_V_23) pre_div = 2; - /* - * Limit SD clock to 167MHz for ls1046a according to its datasheet - */ - if (clock > 167000000 && - of_find_compatible_node(NULL, NULL, "fsl,ls1046a-esdhc")) - clock = 167000000; - - /* - * Limit SD clock to 125MHz for ls1012a according to its datasheet - */ - if (clock > 125000000 && - of_find_compatible_node(NULL, NULL, "fsl,ls1012a-esdhc")) - clock = 125000000; - - /* Workaround to reduce the clock frequency for p1010 esdhc */ - if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { - if (clock > 20000000) - clock -= 5000000; - if (clock > 40000000) - clock -= 5000000; + switch (host->mmc->ios.timing) { + case MMC_TIMING_LEGACY: + fixup = esdhc->clk_fixup->ds; + clock = esdhc_clock_fixup(clock, FULL_SPEED_MAX_DTR, fixup); + fixup = esdhc->clk_fixup->mmc_ds; + clock = esdhc_clock_fixup(clock, MMC_HIGH_26_MAX_DTR, fixup); + break; + case MMC_TIMING_SD_HS: + fixup = esdhc->clk_fixup->hs; + clock = esdhc_clock_fixup(clock, HIGH_SPEED_MAX_DTR, fixup); + break; + case MMC_TIMING_MMC_HS: + fixup = esdhc->clk_fixup->mmc_hs; + clock = esdhc_clock_fixup(clock, MMC_HIGH_52_MAX_DTR, fixup); + break; + case MMC_TIMING_UHS_SDR104: + fixup = esdhc->clk_fixup->sdr104; + clock = esdhc_clock_fixup(clock, UHS_SDR104_MAX_DTR, fixup); + break; + case MMC_TIMING_MMC_HS200: + fixup = esdhc->clk_fixup->hs200; + clock = esdhc_clock_fixup(clock, MMC_HS200_MAX_DTR, fixup); + break; + default: + break; } temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); @@ -783,6 +844,7 @@ static SIMPLE_DEV_PM_OPS(esdhc_of_dev_pm_ops, static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) { + const struct soc_device_attribute *matches; struct sdhci_pltfm_host *pltfm_host; struct sdhci_esdhc *esdhc; struct device_node *np; @@ -802,6 +864,9 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) else esdhc->quirk_incorrect_hostver = false; + matches = soc_device_match(soc_esdhc_clk_fixup); + if (matches) + esdhc->clk_fixup = matches->data; np = pdev->dev.of_node; clk = of_clk_get(np, 0); if (!IS_ERR(clk)) { -- 1.7.1 -- 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