diff mbox series

[v2,11/15] iio: adc: rzg2l_adc: Add suspend/resume support

Message ID 20241206111337.726244-12-claudiu.beznea.uj@bp.renesas.com (mailing list archive)
State Accepted
Headers show
Series iio: adc: rzg2l_adc: Add support for RZ/G3S | expand

Commit Message

Claudiu Beznea Dec. 6, 2024, 11:13 a.m. UTC
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The Renesas RZ/G3S SoC features a power-saving mode where power to most of
the SoC components is turned off, including the ADC IP.

Suspend/resume support has been added to the rzg2l_adc driver to restore
functionality after resuming from this power-saving mode. During suspend,
the ADC resets are asserted, and the ADC is powered down. On resume, the
ADC resets are de-asserted, the hardware is re-initialized, and the ADC
power is restored using the runtime PM APIs.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---

Changes in v2:
- none

 drivers/iio/adc/rzg2l_adc.c | 70 +++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

Comments

Lad, Prabhakar Dec. 8, 2024, 9:35 p.m. UTC | #1
On Fri, Dec 6, 2024 at 11:16 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
>
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> The Renesas RZ/G3S SoC features a power-saving mode where power to most of
> the SoC components is turned off, including the ADC IP.
>
> Suspend/resume support has been added to the rzg2l_adc driver to restore
> functionality after resuming from this power-saving mode. During suspend,
> the ADC resets are asserted, and the ADC is powered down. On resume, the
> ADC resets are de-asserted, the hardware is re-initialized, and the ADC
> power is restored using the runtime PM APIs.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> ---
>
> Changes in v2:
> - none
>
>  drivers/iio/adc/rzg2l_adc.c | 70 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 70 insertions(+)
>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Cheers,
Prabhakar

> diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c
> index e8dbc5dfbea1..2a911269a358 100644
> --- a/drivers/iio/adc/rzg2l_adc.c
> +++ b/drivers/iio/adc/rzg2l_adc.c
> @@ -88,6 +88,7 @@ struct rzg2l_adc {
>         struct completion completion;
>         struct mutex lock;
>         u16 last_val[RZG2L_ADC_MAX_CHANNELS];
> +       bool was_rpm_active;
>  };
>
>  /**
> @@ -527,8 +528,77 @@ static int rzg2l_adc_pm_runtime_resume(struct device *dev)
>         return 0;
>  }
>
> +static int rzg2l_adc_suspend(struct device *dev)
> +{
> +       struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +       struct rzg2l_adc *adc = iio_priv(indio_dev);
> +       struct reset_control_bulk_data resets[] = {
> +               { .rstc = adc->presetn },
> +               { .rstc = adc->adrstn },
> +       };
> +       int ret;
> +
> +       if (pm_runtime_suspended(dev)) {
> +               adc->was_rpm_active = false;
> +       } else {
> +               ret = pm_runtime_force_suspend(dev);
> +               if (ret)
> +                       return ret;
> +               adc->was_rpm_active = true;
> +       }
> +
> +       ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
> +       if (ret)
> +               goto rpm_restore;
> +
> +       return 0;
> +
> +rpm_restore:
> +       if (adc->was_rpm_active)
> +               pm_runtime_force_resume(dev);
> +
> +       return ret;
> +}
> +
> +static int rzg2l_adc_resume(struct device *dev)
> +{
> +       struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +       struct rzg2l_adc *adc = iio_priv(indio_dev);
> +       struct reset_control_bulk_data resets[] = {
> +               { .rstc = adc->adrstn },
> +               { .rstc = adc->presetn },
> +       };
> +       int ret;
> +
> +       ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
> +       if (ret)
> +               return ret;
> +
> +       if (adc->was_rpm_active) {
> +               ret = pm_runtime_force_resume(dev);
> +               if (ret)
> +                       goto resets_restore;
> +       }
> +
> +       ret = rzg2l_adc_hw_init(dev, adc);
> +       if (ret)
> +               goto rpm_restore;
> +
> +       return 0;
> +
> +rpm_restore:
> +       if (adc->was_rpm_active) {
> +               pm_runtime_mark_last_busy(dev);
> +               pm_runtime_put_autosuspend(dev);
> +       }
> +resets_restore:
> +       reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
> +       return ret;
> +}
> +
>  static const struct dev_pm_ops rzg2l_adc_pm_ops = {
>         RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, rzg2l_adc_pm_runtime_resume, NULL)
> +       SYSTEM_SLEEP_PM_OPS(rzg2l_adc_suspend, rzg2l_adc_resume)
>  };
>
>  static struct platform_driver rzg2l_adc_driver = {
> --
> 2.39.2
>
>
Jonathan Cameron Dec. 11, 2024, 7:19 p.m. UTC | #2
On Sun, 8 Dec 2024 21:35:50 +0000
"Lad, Prabhakar" <prabhakar.csengg@gmail.com> wrote:

> On Fri, Dec 6, 2024 at 11:16 AM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> >
> > From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >
> > The Renesas RZ/G3S SoC features a power-saving mode where power to most of
> > the SoC components is turned off, including the ADC IP.
> >
> > Suspend/resume support has been added to the rzg2l_adc driver to restore
> > functionality after resuming from this power-saving mode. During suspend,
> > the ADC resets are asserted, and the ADC is powered down. On resume, the
> > ADC resets are de-asserted, the hardware is re-initialized, and the ADC
> > power is restored using the runtime PM APIs.
> >
> > Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > ---
> >
> > Changes in v2:
> > - none
> >
> >  drivers/iio/adc/rzg2l_adc.c | 70 +++++++++++++++++++++++++++++++++++++
> >  1 file changed, 70 insertions(+)
> >  
> Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>

Thanks.  I've updated tags.

Jonathan

> 
> Cheers,
> Prabhakar
> 
> > diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c
> > index e8dbc5dfbea1..2a911269a358 100644
> > --- a/drivers/iio/adc/rzg2l_adc.c
> > +++ b/drivers/iio/adc/rzg2l_adc.c
> > @@ -88,6 +88,7 @@ struct rzg2l_adc {
> >         struct completion completion;
> >         struct mutex lock;
> >         u16 last_val[RZG2L_ADC_MAX_CHANNELS];
> > +       bool was_rpm_active;
> >  };
> >
> >  /**
> > @@ -527,8 +528,77 @@ static int rzg2l_adc_pm_runtime_resume(struct device *dev)
> >         return 0;
> >  }
> >
> > +static int rzg2l_adc_suspend(struct device *dev)
> > +{
> > +       struct iio_dev *indio_dev = dev_get_drvdata(dev);
> > +       struct rzg2l_adc *adc = iio_priv(indio_dev);
> > +       struct reset_control_bulk_data resets[] = {
> > +               { .rstc = adc->presetn },
> > +               { .rstc = adc->adrstn },
> > +       };
> > +       int ret;
> > +
> > +       if (pm_runtime_suspended(dev)) {
> > +               adc->was_rpm_active = false;
> > +       } else {
> > +               ret = pm_runtime_force_suspend(dev);
> > +               if (ret)
> > +                       return ret;
> > +               adc->was_rpm_active = true;
> > +       }
> > +
> > +       ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
> > +       if (ret)
> > +               goto rpm_restore;
> > +
> > +       return 0;
> > +
> > +rpm_restore:
> > +       if (adc->was_rpm_active)
> > +               pm_runtime_force_resume(dev);
> > +
> > +       return ret;
> > +}
> > +
> > +static int rzg2l_adc_resume(struct device *dev)
> > +{
> > +       struct iio_dev *indio_dev = dev_get_drvdata(dev);
> > +       struct rzg2l_adc *adc = iio_priv(indio_dev);
> > +       struct reset_control_bulk_data resets[] = {
> > +               { .rstc = adc->adrstn },
> > +               { .rstc = adc->presetn },
> > +       };
> > +       int ret;
> > +
> > +       ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
> > +       if (ret)
> > +               return ret;
> > +
> > +       if (adc->was_rpm_active) {
> > +               ret = pm_runtime_force_resume(dev);
> > +               if (ret)
> > +                       goto resets_restore;
> > +       }
> > +
> > +       ret = rzg2l_adc_hw_init(dev, adc);
> > +       if (ret)
> > +               goto rpm_restore;
> > +
> > +       return 0;
> > +
> > +rpm_restore:
> > +       if (adc->was_rpm_active) {
> > +               pm_runtime_mark_last_busy(dev);
> > +               pm_runtime_put_autosuspend(dev);
> > +       }
> > +resets_restore:
> > +       reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
> > +       return ret;
> > +}
> > +
> >  static const struct dev_pm_ops rzg2l_adc_pm_ops = {
> >         RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, rzg2l_adc_pm_runtime_resume, NULL)
> > +       SYSTEM_SLEEP_PM_OPS(rzg2l_adc_suspend, rzg2l_adc_resume)
> >  };
> >
> >  static struct platform_driver rzg2l_adc_driver = {
> > --
> > 2.39.2
> >
> >
diff mbox series

Patch

diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c
index e8dbc5dfbea1..2a911269a358 100644
--- a/drivers/iio/adc/rzg2l_adc.c
+++ b/drivers/iio/adc/rzg2l_adc.c
@@ -88,6 +88,7 @@  struct rzg2l_adc {
 	struct completion completion;
 	struct mutex lock;
 	u16 last_val[RZG2L_ADC_MAX_CHANNELS];
+	bool was_rpm_active;
 };
 
 /**
@@ -527,8 +528,77 @@  static int rzg2l_adc_pm_runtime_resume(struct device *dev)
 	return 0;
 }
 
+static int rzg2l_adc_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct rzg2l_adc *adc = iio_priv(indio_dev);
+	struct reset_control_bulk_data resets[] = {
+		{ .rstc = adc->presetn },
+		{ .rstc = adc->adrstn },
+	};
+	int ret;
+
+	if (pm_runtime_suspended(dev)) {
+		adc->was_rpm_active = false;
+	} else {
+		ret = pm_runtime_force_suspend(dev);
+		if (ret)
+			return ret;
+		adc->was_rpm_active = true;
+	}
+
+	ret = reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
+	if (ret)
+		goto rpm_restore;
+
+	return 0;
+
+rpm_restore:
+	if (adc->was_rpm_active)
+		pm_runtime_force_resume(dev);
+
+	return ret;
+}
+
+static int rzg2l_adc_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct rzg2l_adc *adc = iio_priv(indio_dev);
+	struct reset_control_bulk_data resets[] = {
+		{ .rstc = adc->adrstn },
+		{ .rstc = adc->presetn },
+	};
+	int ret;
+
+	ret = reset_control_bulk_deassert(ARRAY_SIZE(resets), resets);
+	if (ret)
+		return ret;
+
+	if (adc->was_rpm_active) {
+		ret = pm_runtime_force_resume(dev);
+		if (ret)
+			goto resets_restore;
+	}
+
+	ret = rzg2l_adc_hw_init(dev, adc);
+	if (ret)
+		goto rpm_restore;
+
+	return 0;
+
+rpm_restore:
+	if (adc->was_rpm_active) {
+		pm_runtime_mark_last_busy(dev);
+		pm_runtime_put_autosuspend(dev);
+	}
+resets_restore:
+	reset_control_bulk_assert(ARRAY_SIZE(resets), resets);
+	return ret;
+}
+
 static const struct dev_pm_ops rzg2l_adc_pm_ops = {
 	RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, rzg2l_adc_pm_runtime_resume, NULL)
+	SYSTEM_SLEEP_PM_OPS(rzg2l_adc_suspend, rzg2l_adc_resume)
 };
 
 static struct platform_driver rzg2l_adc_driver = {