[PATCH v3 3/7] mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing on resume
From: ziniu . wang_1
Date: Mon Jun 29 2026 - 05:32:16 EST
From: Luke Wang <ziniu.wang_1@xxxxxxx>
SDIO devices such as WiFi may keep power during suspend, so the MMC
core skips full card re-initialization on resume and directly restores
the host controller's ios timing to match the card. For DDR mode,
pm_runtime_force_resume() sets DDR_EN before the pin configuration is
restored from sleep state.
This is related to the SoC IP integration: switching pinctrl setting
(changing alt from GPIO to USDHC) impacts the internal loopback path.
If pinctrl configures the pad to GPIO function, once DDR_EN is set, the
DLL delay will be fixed based on the GPIO function loopback path. When
the pinctrl is later changed to USDHC function, the internal loopback
path changes, making the original fixed sample point no longer suitable
for the current loopback path. This causes persistent read CRC errors on
subsequent data transfers.
SD/eMMC running in DDR mode are unaffected as they are fully
re-initialized from legacy timing after resume.
Fix this by restoring the pinctrl state based on current timing mode
using esdhc_change_pinstate() before pm_runtime_force_resume(). This
ensures the correct pin configuration (e.g., 100/200MHz for UHS modes)
is applied before DDR_EN is set. Only restore for non-wakeup devices
since wakeup devices kept their active pin state during suspend.
Fixes: 676a83855614 ("mmc: host: sdhci-esdhc-imx: refactor the system PM logic")
Signed-off-by: Luke Wang <ziniu.wang_1@xxxxxxx>
---
drivers/mmc/host/sdhci-esdhc-imx.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index a944351dbcdf..7fcaecdd4ec6 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -2114,6 +2114,12 @@ static int sdhci_esdhc_resume(struct device *dev)
struct pltfm_imx_data *imx_data = sdhci_pltfm_priv(pltfm_host);
int ret;
+ if (!device_may_wakeup(dev)) {
+ ret = esdhc_change_pinstate(host, host->timing);
+ if (ret)
+ dev_warn(dev, "Failed to restore pinctrl state\n");
+ }
+
pm_runtime_force_resume(dev);
ret = mmc_gpio_set_cd_wake(host->mmc, false);
--
2.34.1