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


Reply via email to