diff mbox series

[v2] mmc: pwrseq_simple: add support for one reset control

Message ID 20241017131957.1171323-1-catalin.popescu@leica-geosystems.com (mailing list archive)
State New
Headers show
Series [v2] mmc: pwrseq_simple: add support for one reset control | expand

Commit Message

POPESCU Catalin Oct. 17, 2024, 1:19 p.m. UTC
Reset controls being refcounted, they allow to share gpios across
drivers. Right now, reset framework and reset-gpio driver supports only
one reset gpio, so add support for one single reset control. If more
than one reset gpio is configured in the device tree, then fallback to
classic gpio control.

Signed-off-by: Catalin Popescu <catalin.popescu@leica-geosystems.com>
---
v2:
 - drop DT bindings patch
 - use reset control with 1 reset gpio and fallback to gpio with
   multiple reset gpios
---
 drivers/mmc/core/pwrseq_simple.c | 44 +++++++++++++++++++++++++-------
 1 file changed, 35 insertions(+), 9 deletions(-)


base-commit: 58ca61c1a866bfdaa5e19fb19a2416764f847d75
prerequisite-patch-id: 0000000000000000000000000000000000000000

Comments

Ulf Hansson Oct. 25, 2024, 2:51 p.m. UTC | #1
On Thu, 17 Oct 2024 at 15:20, Catalin Popescu
<catalin.popescu@leica-geosystems.com> wrote:
>
> Reset controls being refcounted, they allow to share gpios across
> drivers. Right now, reset framework and reset-gpio driver supports only
> one reset gpio, so add support for one single reset control. If more
> than one reset gpio is configured in the device tree, then fallback to
> classic gpio control.
>
> Signed-off-by: Catalin Popescu <catalin.popescu@leica-geosystems.com>

Applied for next, thanks!

Kind regards
Uffe


> ---
> v2:
>  - drop DT bindings patch
>  - use reset control with 1 reset gpio and fallback to gpio with
>    multiple reset gpios
> ---
>  drivers/mmc/core/pwrseq_simple.c | 44 +++++++++++++++++++++++++-------
>  1 file changed, 35 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
> index 9e016b0746f5..24e4e63a5dc8 100644
> --- a/drivers/mmc/core/pwrseq_simple.c
> +++ b/drivers/mmc/core/pwrseq_simple.c
> @@ -17,6 +17,8 @@
>  #include <linux/gpio/consumer.h>
>  #include <linux/delay.h>
>  #include <linux/property.h>
> +#include <linux/of.h>
> +#include <linux/reset.h>
>
>  #include <linux/mmc/host.h>
>
> @@ -29,6 +31,8 @@ struct mmc_pwrseq_simple {
>         u32 power_off_delay_us;
>         struct clk *ext_clk;
>         struct gpio_descs *reset_gpios;
> +       struct reset_control *reset_ctrl;
> +       bool use_reset;
>  };
>
>  #define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq)
> @@ -67,14 +71,21 @@ static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
>                 pwrseq->clk_enabled = true;
>         }
>
> -       mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
> +       if (pwrseq->use_reset) {
> +               reset_control_deassert(pwrseq->reset_ctrl);
> +               reset_control_assert(pwrseq->reset_ctrl);
> +       } else
> +               mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
>  }
>
>  static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
>  {
>         struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
>
> -       mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
> +       if (pwrseq->use_reset)
> +               reset_control_deassert(pwrseq->reset_ctrl);
> +       else
> +               mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
>
>         if (pwrseq->post_power_on_delay_ms)
>                 msleep(pwrseq->post_power_on_delay_ms);
> @@ -84,7 +95,10 @@ static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
>  {
>         struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
>
> -       mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
> +       if (pwrseq->use_reset)
> +               reset_control_assert(pwrseq->reset_ctrl);
> +       else
> +               mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
>
>         if (pwrseq->power_off_delay_us)
>                 usleep_range(pwrseq->power_off_delay_us,
> @@ -112,6 +126,7 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
>  {
>         struct mmc_pwrseq_simple *pwrseq;
>         struct device *dev = &pdev->dev;
> +       int ngpio;
>
>         pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
>         if (!pwrseq)
> @@ -121,12 +136,23 @@ static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
>         if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT)
>                 return dev_err_probe(dev, PTR_ERR(pwrseq->ext_clk), "external clock not ready\n");
>
> -       pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset",
> -                                                       GPIOD_OUT_HIGH);
> -       if (IS_ERR(pwrseq->reset_gpios) &&
> -           PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
> -           PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
> -               return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios), "reset GPIOs not ready\n");
> +       ngpio = of_count_phandle_with_args(dev->of_node, "reset-gpios", "#gpio-cells");
> +       if (ngpio == 1)
> +               pwrseq->use_reset = true;
> +
> +       if (pwrseq->use_reset) {
> +               pwrseq->reset_ctrl = devm_reset_control_get_optional_shared(dev, NULL);
> +               if (IS_ERR(pwrseq->reset_ctrl))
> +                       return dev_err_probe(dev, PTR_ERR(pwrseq->reset_ctrl),
> +                                            "reset control not ready\n");
> +       } else {
> +               pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
> +               if (IS_ERR(pwrseq->reset_gpios) &&
> +                   PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
> +                   PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
> +                       return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios),
> +                                            "reset GPIOs not ready\n");
> +               }
>         }
>
>         device_property_read_u32(dev, "post-power-on-delay-ms",
>
> base-commit: 58ca61c1a866bfdaa5e19fb19a2416764f847d75
> prerequisite-patch-id: 0000000000000000000000000000000000000000
> --
> 2.34.1
>
diff mbox series

Patch

diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
index 9e016b0746f5..24e4e63a5dc8 100644
--- a/drivers/mmc/core/pwrseq_simple.c
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -17,6 +17,8 @@ 
 #include <linux/gpio/consumer.h>
 #include <linux/delay.h>
 #include <linux/property.h>
+#include <linux/of.h>
+#include <linux/reset.h>
 
 #include <linux/mmc/host.h>
 
@@ -29,6 +31,8 @@  struct mmc_pwrseq_simple {
 	u32 power_off_delay_us;
 	struct clk *ext_clk;
 	struct gpio_descs *reset_gpios;
+	struct reset_control *reset_ctrl;
+	bool use_reset;
 };
 
 #define to_pwrseq_simple(p) container_of(p, struct mmc_pwrseq_simple, pwrseq)
@@ -67,14 +71,21 @@  static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
 		pwrseq->clk_enabled = true;
 	}
 
-	mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
+	if (pwrseq->use_reset) {
+		reset_control_deassert(pwrseq->reset_ctrl);
+		reset_control_assert(pwrseq->reset_ctrl);
+	} else
+		mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
 }
 
 static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
 {
 	struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
 
-	mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
+	if (pwrseq->use_reset)
+		reset_control_deassert(pwrseq->reset_ctrl);
+	else
+		mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
 
 	if (pwrseq->post_power_on_delay_ms)
 		msleep(pwrseq->post_power_on_delay_ms);
@@ -84,7 +95,10 @@  static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
 {
 	struct mmc_pwrseq_simple *pwrseq = to_pwrseq_simple(host->pwrseq);
 
-	mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
+	if (pwrseq->use_reset)
+		reset_control_assert(pwrseq->reset_ctrl);
+	else
+		mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
 
 	if (pwrseq->power_off_delay_us)
 		usleep_range(pwrseq->power_off_delay_us,
@@ -112,6 +126,7 @@  static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
 {
 	struct mmc_pwrseq_simple *pwrseq;
 	struct device *dev = &pdev->dev;
+	int ngpio;
 
 	pwrseq = devm_kzalloc(dev, sizeof(*pwrseq), GFP_KERNEL);
 	if (!pwrseq)
@@ -121,12 +136,23 @@  static int mmc_pwrseq_simple_probe(struct platform_device *pdev)
 	if (IS_ERR(pwrseq->ext_clk) && PTR_ERR(pwrseq->ext_clk) != -ENOENT)
 		return dev_err_probe(dev, PTR_ERR(pwrseq->ext_clk), "external clock not ready\n");
 
-	pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset",
-							GPIOD_OUT_HIGH);
-	if (IS_ERR(pwrseq->reset_gpios) &&
-	    PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
-	    PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
-		return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios), "reset GPIOs not ready\n");
+	ngpio = of_count_phandle_with_args(dev->of_node, "reset-gpios", "#gpio-cells");
+	if (ngpio == 1)
+		pwrseq->use_reset = true;
+
+	if (pwrseq->use_reset) {
+		pwrseq->reset_ctrl = devm_reset_control_get_optional_shared(dev, NULL);
+		if (IS_ERR(pwrseq->reset_ctrl))
+			return dev_err_probe(dev, PTR_ERR(pwrseq->reset_ctrl),
+					     "reset control not ready\n");
+	} else {
+		pwrseq->reset_gpios = devm_gpiod_get_array(dev, "reset", GPIOD_OUT_HIGH);
+		if (IS_ERR(pwrseq->reset_gpios) &&
+		    PTR_ERR(pwrseq->reset_gpios) != -ENOENT &&
+		    PTR_ERR(pwrseq->reset_gpios) != -ENOSYS) {
+			return dev_err_probe(dev, PTR_ERR(pwrseq->reset_gpios),
+					     "reset GPIOs not ready\n");
+		}
 	}
 
 	device_property_read_u32(dev, "post-power-on-delay-ms",