[PATCH v2 2/2] mmc: host: renesas_sdhi_core: support configuring an optional sdio mux

Josua Mayer posted 2 patches 2 months, 1 week ago
There is a newer version of this series
[PATCH v2 2/2] mmc: host: renesas_sdhi_core: support configuring an optional sdio mux
Posted by Josua Mayer 2 months, 1 week ago
Some hardware designs route sdio signals through a mux to support
multiple devices on a single sdio controller.
In particular SolidRun RZ/G2L/G2LC/V2L System on Module use a mux for
switching between soldered eMMC and an optional microSD on a carrier
board, e.g. for development or provisioning.

SDIO is not well suited for runtime switching between different cards,
however boot-time selection is possible and useful in particular with dt
overlays.

Add support for an optional sdio mux defined in dt and select it during
probe.

Similar functionality already exists in other places, e.g. i2c-omap.

Signed-off-by: Josua Mayer <josua@solid-run.com>
---
 drivers/mmc/host/Kconfig             |  1 +
 drivers/mmc/host/renesas_sdhi.h      |  1 +
 drivers/mmc/host/renesas_sdhi_core.c | 27 ++++++++++++++++++++++++---
 3 files changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 2c963cb6724b9..c01ab7d81a5af 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -707,6 +707,7 @@ config MMC_SDHI
 	depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
 	depends on (RESET_CONTROLLER && REGULATOR) || !OF
 	select MMC_TMIO_CORE
+	select MULTIPLEXER
 	help
 	  This provides support for the SDHI SD/SDIO controller found in
 	  Renesas SuperH, ARM and ARM64 based SoCs
diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
index 084964cecf9d8..9508908d8179f 100644
--- a/drivers/mmc/host/renesas_sdhi.h
+++ b/drivers/mmc/host/renesas_sdhi.h
@@ -97,6 +97,7 @@ struct renesas_sdhi {
 	struct reset_control *rstc;
 	struct tmio_mmc_host *host;
 	struct regulator_dev *rdev;
+	struct mux_state *mux_state;
 };
 
 #define host_to_priv(host) \
diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
index f56fa2cd208dd..c58f412ea2028 100644
--- a/drivers/mmc/host/renesas_sdhi_core.c
+++ b/drivers/mmc/host/renesas_sdhi_core.c
@@ -26,6 +26,7 @@
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/slot-gpio.h>
 #include <linux/module.h>
+#include <linux/mux/consumer.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pinctrl/pinctrl-state.h>
 #include <linux/platform_data/tmio.h>
@@ -1061,6 +1062,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
 	struct regulator_dev *rdev;
 	struct renesas_sdhi_dma *dma_priv;
 	struct device *dev = &pdev->dev;
+	struct device_node *node = pdev->dev.of_node;
 	struct tmio_mmc_host *host;
 	struct renesas_sdhi *priv;
 	int num_irqs, irq, ret, i;
@@ -1115,9 +1117,25 @@ int renesas_sdhi_probe(struct platform_device *pdev,
 						"state_uhs");
 	}
 
+	if (of_property_present(node, "mux-states")) {
+		priv->mux_state = devm_mux_state_get(&pdev->dev, NULL);
+		if (IS_ERR(priv->mux_state)) {
+			ret = PTR_ERR(priv->mux_state);
+			dev_dbg(&pdev->dev, "failed to get SDIO mux: %d\n", ret);
+			return ret;
+		}
+		ret = mux_state_select(priv->mux_state);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to select SDIO mux: %d\n", ret);
+			return ret;
+		}
+	}
+
 	host = tmio_mmc_host_alloc(pdev, mmc_data);
-	if (IS_ERR(host))
-		return PTR_ERR(host);
+	if (IS_ERR(host)) {
+		ret = PTR_ERR(host);
+		goto edselmux;
+	}
 
 	priv->host = host;
 
@@ -1200,7 +1218,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
 
 	ret = renesas_sdhi_clk_enable(host);
 	if (ret)
-		return ret;
+		goto edselmux;
 
 	rcfg.of_node = of_get_available_child_by_name(dev->of_node, "vqmmc-regulator");
 	if (rcfg.of_node) {
@@ -1304,6 +1322,9 @@ int renesas_sdhi_probe(struct platform_device *pdev,
 
 edisclk:
 	renesas_sdhi_clk_disable(host);
+edselmux:
+	if (priv->mux_state)
+		mux_state_deselect(priv->mux_state);
 	return ret;
 }
 EXPORT_SYMBOL_GPL(renesas_sdhi_probe);

-- 
2.51.0
Re: [PATCH v2 2/2] mmc: host: renesas_sdhi_core: support configuring an optional sdio mux
Posted by Rob Herring 2 months ago
On Mon, Dec 01, 2025 at 01:31:11PM +0100, Josua Mayer wrote:
> Some hardware designs route sdio signals through a mux to support
> multiple devices on a single sdio controller.
> In particular SolidRun RZ/G2L/G2LC/V2L System on Module use a mux for
> switching between soldered eMMC and an optional microSD on a carrier
> board, e.g. for development or provisioning.
> 
> SDIO is not well suited for runtime switching between different cards,
> however boot-time selection is possible and useful in particular with dt
> overlays.
> 
> Add support for an optional sdio mux defined in dt and select it during
> probe.
> 
> Similar functionality already exists in other places, e.g. i2c-omap.
> 
> Signed-off-by: Josua Mayer <josua@solid-run.com>
> ---
>  drivers/mmc/host/Kconfig             |  1 +
>  drivers/mmc/host/renesas_sdhi.h      |  1 +
>  drivers/mmc/host/renesas_sdhi_core.c | 27 ++++++++++++++++++++++++---
>  3 files changed, 26 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 2c963cb6724b9..c01ab7d81a5af 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -707,6 +707,7 @@ config MMC_SDHI
>  	depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
>  	depends on (RESET_CONTROLLER && REGULATOR) || !OF
>  	select MMC_TMIO_CORE
> +	select MULTIPLEXER
>  	help
>  	  This provides support for the SDHI SD/SDIO controller found in
>  	  Renesas SuperH, ARM and ARM64 based SoCs
> diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
> index 084964cecf9d8..9508908d8179f 100644
> --- a/drivers/mmc/host/renesas_sdhi.h
> +++ b/drivers/mmc/host/renesas_sdhi.h
> @@ -97,6 +97,7 @@ struct renesas_sdhi {
>  	struct reset_control *rstc;
>  	struct tmio_mmc_host *host;
>  	struct regulator_dev *rdev;
> +	struct mux_state *mux_state;
>  };
>  
>  #define host_to_priv(host) \
> diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
> index f56fa2cd208dd..c58f412ea2028 100644
> --- a/drivers/mmc/host/renesas_sdhi_core.c
> +++ b/drivers/mmc/host/renesas_sdhi_core.c
> @@ -26,6 +26,7 @@
>  #include <linux/mmc/mmc.h>
>  #include <linux/mmc/slot-gpio.h>
>  #include <linux/module.h>
> +#include <linux/mux/consumer.h>
>  #include <linux/pinctrl/consumer.h>
>  #include <linux/pinctrl/pinctrl-state.h>
>  #include <linux/platform_data/tmio.h>
> @@ -1061,6 +1062,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
>  	struct regulator_dev *rdev;
>  	struct renesas_sdhi_dma *dma_priv;
>  	struct device *dev = &pdev->dev;
> +	struct device_node *node = pdev->dev.of_node;
>  	struct tmio_mmc_host *host;
>  	struct renesas_sdhi *priv;
>  	int num_irqs, irq, ret, i;
> @@ -1115,9 +1117,25 @@ int renesas_sdhi_probe(struct platform_device *pdev,
>  						"state_uhs");
>  	}
>  
> +	if (of_property_present(node, "mux-states")) {
> +		priv->mux_state = devm_mux_state_get(&pdev->dev, NULL);

These 2 lines are really just devm_mux_state_get_optional(). Add it if 
it doesn't exist.

> +		if (IS_ERR(priv->mux_state)) {
> +			ret = PTR_ERR(priv->mux_state);
> +			dev_dbg(&pdev->dev, "failed to get SDIO mux: %d\n", ret);
> +			return ret;
> +		}
> +		ret = mux_state_select(priv->mux_state);
> +		if (ret) {
> +			dev_err(&pdev->dev, "failed to select SDIO mux: %d\n", ret);

Is there a case where mux_state_select() failing is not an error? If 
not, mux_state_select() should do the printing.

> +			return ret;
> +		}
> +	}
Re: [PATCH v2 2/2] mmc: host: renesas_sdhi_core: support configuring an optional sdio mux
Posted by Josua Mayer 2 months ago
Am 08.12.25 um 02:24 schrieb Rob Herring:
> On Mon, Dec 01, 2025 at 01:31:11PM +0100, Josua Mayer wrote:
>> Some hardware designs route sdio signals through a mux to support
>> multiple devices on a single sdio controller.
>> In particular SolidRun RZ/G2L/G2LC/V2L System on Module use a mux for
>> switching between soldered eMMC and an optional microSD on a carrier
>> board, e.g. for development or provisioning.
>>
>> SDIO is not well suited for runtime switching between different cards,
>> however boot-time selection is possible and useful in particular with dt
>> overlays.
>>
>> Add support for an optional sdio mux defined in dt and select it during
>> probe.
>>
>> Similar functionality already exists in other places, e.g. i2c-omap.
>>
>> Signed-off-by: Josua Mayer <josua@solid-run.com>
>> ---
>>  drivers/mmc/host/Kconfig             |  1 +
>>  drivers/mmc/host/renesas_sdhi.h      |  1 +
>>  drivers/mmc/host/renesas_sdhi_core.c | 27 ++++++++++++++++++++++++---
>>  3 files changed, 26 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
>> index 2c963cb6724b9..c01ab7d81a5af 100644
>> --- a/drivers/mmc/host/Kconfig
>> +++ b/drivers/mmc/host/Kconfig
>> @@ -707,6 +707,7 @@ config MMC_SDHI
>>  	depends on SUPERH || ARCH_RENESAS || COMPILE_TEST
>>  	depends on (RESET_CONTROLLER && REGULATOR) || !OF
>>  	select MMC_TMIO_CORE
>> +	select MULTIPLEXER
>>  	help
>>  	  This provides support for the SDHI SD/SDIO controller found in
>>  	  Renesas SuperH, ARM and ARM64 based SoCs
>> diff --git a/drivers/mmc/host/renesas_sdhi.h b/drivers/mmc/host/renesas_sdhi.h
>> index 084964cecf9d8..9508908d8179f 100644
>> --- a/drivers/mmc/host/renesas_sdhi.h
>> +++ b/drivers/mmc/host/renesas_sdhi.h
>> @@ -97,6 +97,7 @@ struct renesas_sdhi {
>>  	struct reset_control *rstc;
>>  	struct tmio_mmc_host *host;
>>  	struct regulator_dev *rdev;
>> +	struct mux_state *mux_state;
>>  };
>>  
>>  #define host_to_priv(host) \
>> diff --git a/drivers/mmc/host/renesas_sdhi_core.c b/drivers/mmc/host/renesas_sdhi_core.c
>> index f56fa2cd208dd..c58f412ea2028 100644
>> --- a/drivers/mmc/host/renesas_sdhi_core.c
>> +++ b/drivers/mmc/host/renesas_sdhi_core.c
>> @@ -26,6 +26,7 @@
>>  #include <linux/mmc/mmc.h>
>>  #include <linux/mmc/slot-gpio.h>
>>  #include <linux/module.h>
>> +#include <linux/mux/consumer.h>
>>  #include <linux/pinctrl/consumer.h>
>>  #include <linux/pinctrl/pinctrl-state.h>
>>  #include <linux/platform_data/tmio.h>
>> @@ -1061,6 +1062,7 @@ int renesas_sdhi_probe(struct platform_device *pdev,
>>  	struct regulator_dev *rdev;
>>  	struct renesas_sdhi_dma *dma_priv;
>>  	struct device *dev = &pdev->dev;
>> +	struct device_node *node = pdev->dev.of_node;
>>  	struct tmio_mmc_host *host;
>>  	struct renesas_sdhi *priv;
>>  	int num_irqs, irq, ret, i;
>> @@ -1115,9 +1117,25 @@ int renesas_sdhi_probe(struct platform_device *pdev,
>>  						"state_uhs");
>>  	}
>>  
>> +	if (of_property_present(node, "mux-states")) {
>> +		priv->mux_state = devm_mux_state_get(&pdev->dev, NULL);
> These 2 lines are really just devm_mux_state_get_optional(). Add it if 
> it doesn't exist.
Other drivers have so far avoided introducing a general helper for this.
Notably drivers/phy/phy-can-transceiver.c has already implemented
its own version of devm_mux_state_get_optional.
>
>> +		if (IS_ERR(priv->mux_state)) {
>> +			ret = PTR_ERR(priv->mux_state);
>> +			dev_dbg(&pdev->dev, "failed to get SDIO mux: %d\n", ret);
>> +			return ret;
>> +		}
>> +		ret = mux_state_select(priv->mux_state);
>> +		if (ret) {
>> +			dev_err(&pdev->dev, "failed to select SDIO mux: %d\n", ret);
> Is there a case where mux_state_select() failing is not an error?
I suppose it is always an error.
> If 
> not, mux_state_select() should do the printing.

Possibly. Except when it is EDEFER.

Inside driver we would use dev_err_probe in this case.
Should helpers do the same?

>
>> +			return ret;
>> +		}
>> +	}