Like done before for the card side, we need to adjust drive strength on the host as well with higher data rates. For i.MX, this is done via speed-specific pincontrol groups, so implement this binding.
Signed-off-by: Ahmad Fatoum <a.fat...@pengutronix.de> --- drivers/mci/imx-esdhc.c | 48 +++++++++++++++++++++++++++++++++++++++++ drivers/mci/imx-esdhc.h | 3 +++ 2 files changed, 51 insertions(+) diff --git a/drivers/mci/imx-esdhc.c b/drivers/mci/imx-esdhc.c index 5f427a1898b7..751b3703e579 100644 --- a/drivers/mci/imx-esdhc.c +++ b/drivers/mci/imx-esdhc.c @@ -14,6 +14,7 @@ #include <of.h> #include <malloc.h> #include <mci.h> +#include <linux/pinctrl/consumer.h> #include <clock.h> #include <io.h> #include <linux/clk.h> @@ -56,6 +57,9 @@ #define ESDHC_TUNING_STEP_MASK 0x00070000 #define ESDHC_TUNING_STEP_SHIFT 16 +/* pinctrl state */ +#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" +#define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz" #define to_fsl_esdhc(mci) container_of(mci, struct fsl_esdhc_host, mci) @@ -133,6 +137,37 @@ static void set_sysctl(struct mci_host *mci, u32 clock, bool ddr) 10 * MSECOND); } +static int esdhc_change_pinstate(struct fsl_esdhc_host *host, + unsigned int uhs) +{ + struct pinctrl_state *pinctrl; + + dev_dbg(host->dev, "change pinctrl state for uhs %d\n", uhs); + + if (IS_ERR(host->pinctrl) || + IS_ERR(host->pins_100mhz) || + IS_ERR(host->pins_200mhz)) + return -EINVAL; + + switch (uhs) { + case MMC_TIMING_UHS_SDR50: + case MMC_TIMING_UHS_DDR50: + pinctrl = host->pins_100mhz; + break; + case MMC_TIMING_UHS_SDR104: + case MMC_TIMING_MMC_HS200: + case MMC_TIMING_MMC_HS400: + pinctrl = host->pins_200mhz; + break; + default: + /* back to default state for other legacy timing */ + return pinctrl_select_state_default(host->dev); + } + + return pinctrl_select_state(host->pinctrl, pinctrl); +} + + static void usdhc_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing) { u32 mixctrl; @@ -159,6 +194,8 @@ static void usdhc_set_timing(struct fsl_esdhc_host *host, enum mci_timing timing sdhci_write32(&host->sdhci, IMX_SDHCI_MIXCTRL, mixctrl); } + esdhc_change_pinstate(host, timing); + host->sdhci.timing = timing; } @@ -366,6 +403,13 @@ static void fsl_esdhc_probe_dt(struct device *dev, struct fsl_esdhc_host *host) &boarddata->tuning_start_tap); if (of_property_read_u32(np, "fsl,delay-line", &boarddata->delay_line)) boarddata->delay_line = 0; + + if (esdhc_is_usdhc(host) && !IS_ERR(host->pinctrl)) { + host->pins_100mhz = pinctrl_lookup_state(host->pinctrl, + ESDHC_PINCTRL_STATE_100MHZ); + host->pins_200mhz = pinctrl_lookup_state(host->pinctrl, + ESDHC_PINCTRL_STATE_200MHZ); + } } static int fsl_esdhc_probe(struct device *dev) @@ -428,6 +472,10 @@ static int fsl_esdhc_probe(struct device *dev) mci_of_parse(&host->mci); + host->pinctrl = pinctrl_get(dev); + if (IS_ERR(host->pinctrl)) + dev_warn(host->dev, "could not get pinctrl\n"); + fsl_esdhc_probe_dt(dev, host); ret = mci_register(&host->mci); diff --git a/drivers/mci/imx-esdhc.h b/drivers/mci/imx-esdhc.h index 569986c1bf0e..e24d76d0c687 100644 --- a/drivers/mci/imx-esdhc.h +++ b/drivers/mci/imx-esdhc.h @@ -153,6 +153,9 @@ struct fsl_esdhc_host { struct mci_host mci; struct clk *clk; struct device *dev; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_100mhz; + struct pinctrl_state *pins_200mhz; const struct esdhc_soc_data *socdata; struct esdhc_platform_data boarddata; u32 last_cmd; -- 2.39.5