[PATCH v2 22/30] mci: imx-esdhc: select different pinctrl state depending on frequency
Ahmad Fatoum
a.fatoum at pengutronix.de
Wed May 7 01:22:01 PDT 2025
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.fatoum at 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 3871f85ea6d6..18a5750ed0ed 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;
}
@@ -355,6 +392,13 @@ static void fsl_esdhc_probe_dt(struct device *dev, struct fsl_esdhc_host *host)
boarddata->tuning_start_tap = ESDHC_TUNING_START_TAP_DEFAULT;
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)
@@ -417,6 +461,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
More information about the barebox
mailing list