]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mmc: sdhci-esdhc-imx: restore pinctrl before restoring ios timing on resume
authorLuke Wang <ziniu.wang_1@nxp.com>
Wed, 15 Jul 2026 07:18:14 +0000 (15:18 +0800)
committerUlf Hansson <ulfh@kernel.org>
Wed, 15 Jul 2026 08:59:36 +0000 (10:59 +0200)
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")
Acked-by: Adrian Hunter <adrian.hunter@intel.com>
Reviewed-by: Haibo Chen <haibo.chen@nxp.com>
Signed-off-by: Luke Wang <ziniu.wang_1@nxp.com>
Cc: stable@vger.kernel.org
Signed-off-by: Ulf Hansson <ulfh@kernel.org>
drivers/mmc/host/sdhci-esdhc-imx.c

index ead4685d621a739d5e443d05ff2e841befecacd1..a54da5757acc1e67ffccfa6543543500516acf37 100644 (file)
@@ -2115,6 +2115,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);