diff options
author | yinbo.zhu <yinbo.zhu@nxp.com> | 2018-06-25 10:46:24 +0200 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2018-07-16 11:21:45 +0200 |
commit | 67fdfbdf0115b39b4e9b9d96d240202fa3049b12 (patch) | |
tree | b7e43ba46ef9089757cd61d80f18eb9e2230748c /drivers/mmc | |
parent | mmc: sdhci-of-arasan: Add quirk for unstable clocks (diff) | |
download | linux-67fdfbdf0115b39b4e9b9d96d240202fa3049b12.tar.xz linux-67fdfbdf0115b39b4e9b9d96d240202fa3049b12.zip |
mmc: sdhci-of-esdhc: modify the sd clock in of_match_node way
Convert to use of_match_node 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@nxp.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/host/sdhci-of-esdhc.c | 85 |
1 files changed, 57 insertions, 28 deletions
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 4ffa6b173a21..c9685c6e4395 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -29,11 +29,56 @@ #define VENDOR_V_22 0x12 #define VENDOR_V_23 0x13 +#define MMC_TIMING_NUM (MMC_TIMING_MMC_HS400 + 1) + +struct esdhc_clk_fixup { + const unsigned int sd_dflt_max_clk; + const unsigned int max_clk[MMC_TIMING_NUM]; +}; + +static const struct esdhc_clk_fixup ls1021a_esdhc_clk = { + .sd_dflt_max_clk = 25000000, + .max_clk[MMC_TIMING_MMC_HS] = 46500000, + .max_clk[MMC_TIMING_SD_HS] = 46500000, +}; + +static const struct esdhc_clk_fixup ls1046a_esdhc_clk = { + .sd_dflt_max_clk = 25000000, + .max_clk[MMC_TIMING_UHS_SDR104] = 167000000, + .max_clk[MMC_TIMING_MMC_HS200] = 167000000, +}; + +static const struct esdhc_clk_fixup ls1012a_esdhc_clk = { + .sd_dflt_max_clk = 25000000, + .max_clk[MMC_TIMING_UHS_SDR104] = 125000000, + .max_clk[MMC_TIMING_MMC_HS200] = 125000000, +}; + +static const struct esdhc_clk_fixup p1010_esdhc_clk = { + .sd_dflt_max_clk = 20000000, + .max_clk[MMC_TIMING_LEGACY] = 20000000, + .max_clk[MMC_TIMING_MMC_HS] = 42000000, + .max_clk[MMC_TIMING_SD_HS] = 40000000, +}; + +static const struct of_device_id sdhci_esdhc_of_match[] = { + { .compatible = "fsl,ls1021a-esdhc", .data = &ls1021a_esdhc_clk}, + { .compatible = "fsl,ls1046a-esdhc", .data = &ls1046a_esdhc_clk}, + { .compatible = "fsl,ls1012a-esdhc", .data = &ls1012a_esdhc_clk}, + { .compatible = "fsl,p1010-esdhc", .data = &p1010_esdhc_clk}, + { .compatible = "fsl,mpc8379-esdhc" }, + { .compatible = "fsl,mpc8536-esdhc" }, + { .compatible = "fsl,esdhc" }, + { } +}; +MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match); + struct sdhci_esdhc { u8 vendor_ver; u8 spec_ver; bool quirk_incorrect_hostver; unsigned int peripheral_clock; + const struct esdhc_clk_fixup *clk_fixup; }; /** @@ -492,6 +537,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 = 0; u32 temp; host->mmc->actual_clock = 0; @@ -505,27 +551,14 @@ 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; + if (host->mmc->card && mmc_card_sd(host->mmc->card) && + esdhc->clk_fixup && host->mmc->ios.timing == MMC_TIMING_LEGACY) + fixup = esdhc->clk_fixup->sd_dflt_max_clk; + else if (esdhc->clk_fixup) + fixup = esdhc->clk_fixup->max_clk[host->mmc->ios.timing]; - /* - * 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; - } + if (fixup && clock > fixup) + clock = fixup; temp = sdhci_readl(host, ESDHC_SYSTEM_CONTROL); temp &= ~(ESDHC_CLOCK_SDCLKEN | ESDHC_CLOCK_IPGEN | ESDHC_CLOCK_HCKEN | @@ -783,6 +816,7 @@ static struct soc_device_attribute soc_incorrect_hostver[] = { static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) { + const struct of_device_id *match; struct sdhci_pltfm_host *pltfm_host; struct sdhci_esdhc *esdhc; struct device_node *np; @@ -802,6 +836,9 @@ static void esdhc_init(struct platform_device *pdev, struct sdhci_host *host) else esdhc->quirk_incorrect_hostver = false; + match = of_match_node(sdhci_esdhc_of_match, pdev->dev.of_node); + if (match) + esdhc->clk_fixup = match->data; np = pdev->dev.of_node; clk = of_clk_get(np, 0); if (!IS_ERR(clk)) { @@ -901,14 +938,6 @@ static int sdhci_esdhc_probe(struct platform_device *pdev) return ret; } -static const struct of_device_id sdhci_esdhc_of_match[] = { - { .compatible = "fsl,mpc8379-esdhc" }, - { .compatible = "fsl,mpc8536-esdhc" }, - { .compatible = "fsl,esdhc" }, - { } -}; -MODULE_DEVICE_TABLE(of, sdhci_esdhc_of_match); - static struct platform_driver sdhci_esdhc_driver = { .driver = { .name = "sdhci-esdhc", |