Re: [PATCH v3 2/7] mmc: sdhci-of-k1: add regulator and pinctrl voltage switching support
From: Adrian Hunter <adrian.hunter@intel.com>
Date: 2026-03-17 11:28:28
Also in:
linux-mmc, linux-riscv, lkml, spacemit
On 16/03/2026 16:03, Iker Pedrosa wrote:
quoted hunk ↗ jump to hunk
Add voltage switching infrastructure for UHS-I modes by integrating both regulator framework (for supply voltage control) and pinctrl state switching (for pin drive strength optimization). - Add regulator supply parsing and voltage switching callback - Add optional pinctrl state switching between "default" (3.3V) and "state_uhs" (1.8V) configurations - Enable coordinated voltage and pin configuration changes for UHS modes This provides complete voltage switching support while maintaining backward compatibility when pinctrl states are not defined. Tested-by: Anand Moon <redacted> Signed-off-by: Iker Pedrosa <ikerpedrosam@gmail.com> --- drivers/mmc/host/sdhci-of-k1.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)diff --git a/drivers/mmc/host/sdhci-of-k1.c b/drivers/mmc/host/sdhci-of-k1.c index 0dd06fc19b8574ae1b00f7e5d09b7d4c87d06770..01afdadcf70796704b272ee5a31543afd5e01188 100644 --- a/drivers/mmc/host/sdhci-of-k1.c +++ b/drivers/mmc/host/sdhci-of-k1.c@@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/reset.h> +#include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include "sdhci.h"@@ -71,6 +72,9 @@ struct spacemit_sdhci_host { struct clk *clk_core; struct clk *clk_io; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_default; + struct pinctrl_state *pinctrl_uhs; }; /* All helper functions will update clr/set while preserve rest bits */@@ -219,6 +223,33 @@ static void spacemit_sdhci_pre_hs400_to_hs200(struct mmc_host *mmc) SPACEMIT_SDHC_PHY_CTRL_REG); } +static void spacemit_sdhci_voltage_switch(struct sdhci_host *host) +{ + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct spacemit_sdhci_host *sdhst = sdhci_pltfm_priv(pltfm_host); + struct mmc_ios *ios = &host->mmc->ios; + int ret; + + if (!sdhst->pinctrl) + return; + + if (ios->signal_voltage != MMC_SIGNAL_VOLTAGE_180) { + dev_warn(mmc_dev(host->mmc), "unsupported voltage %d\n", + ios->signal_voltage); + return; + }
In V2, I put "->voltage_switch() is called only for ios->signal_voltage == MMC_SIGNAL_VOLTAGE_180" by which I meant that it does not allow the driver to switch pin state back for 3.3V. So you probably need an approach similar to the original spacemit_sdhci_start_signal_voltage_switch() in: https://lore.kernel.org/linux-mmc/20260302-orangepi-sd-card-uhs-v1-4-89c219973c0c@gmail.com/ (local)
quoted hunk ↗ jump to hunk
+ + if (sdhst->pinctrl_uhs) { + ret = pinctrl_select_state(sdhst->pinctrl, sdhst->pinctrl_uhs); + if (ret) { + dev_warn(mmc_dev(host->mmc), + "failed to select UHS pinctrl state: %d\n", ret); + return; + } + dev_dbg(mmc_dev(host->mmc), "switched to UHS pinctrl state\n"); + } +} + static inline int spacemit_sdhci_get_clocks(struct device *dev, struct sdhci_pltfm_host *pltfm_host) {@@ -252,12 +283,37 @@ static inline int spacemit_sdhci_get_resets(struct device *dev) return 0; } +static inline void spacemit_sdhci_get_pins(struct device *dev, + struct sdhci_pltfm_host *pltfm_host) +{ + struct spacemit_sdhci_host *sdhst = sdhci_pltfm_priv(pltfm_host); + + sdhst->pinctrl = devm_pinctrl_get(dev); + if (IS_ERR(sdhst->pinctrl)) { + sdhst->pinctrl = NULL; + dev_dbg(dev, "pinctrl not available, voltage switching will work without it\n"); + return; + } + + sdhst->pinctrl_default = pinctrl_lookup_state(sdhst->pinctrl, "default"); + if (IS_ERR(sdhst->pinctrl_default)) + sdhst->pinctrl_default = NULL; + + sdhst->pinctrl_uhs = pinctrl_lookup_state(sdhst->pinctrl, "state_uhs"); + if (IS_ERR(sdhst->pinctrl_uhs)) + sdhst->pinctrl_uhs = NULL; + + dev_dbg(dev, "pinctrl setup: default=%p, uhs=%p\n", + sdhst->pinctrl_default, sdhst->pinctrl_uhs); +} + static const struct sdhci_ops spacemit_sdhci_ops = { .get_max_clock = spacemit_sdhci_clk_get_max_clock, .reset = spacemit_sdhci_reset, .set_bus_width = sdhci_set_bus_width, .set_clock = spacemit_sdhci_set_clock, .set_uhs_signaling = spacemit_sdhci_set_uhs_signaling, + .voltage_switch = spacemit_sdhci_voltage_switch, }; static const struct sdhci_pltfm_data spacemit_sdhci_k1_pdata = {@@ -324,6 +380,8 @@ static int spacemit_sdhci_probe(struct platform_device *pdev) host->mmc->caps |= MMC_CAP_NEED_RSP_BUSY; + spacemit_sdhci_get_pins(dev, pltfm_host); + ret = spacemit_sdhci_get_clocks(dev, pltfm_host); if (ret) goto err_pltfm;