]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
iio: adc: rzg2l_adc: Add suspend/resume support
authorClaudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Fri, 6 Dec 2024 11:13:33 +0000 (13:13 +0200)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Wed, 11 Dec 2024 19:20:44 +0000 (19:20 +0000)
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>
Reviewed-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Link: https://patch.msgid.link/20241206111337.726244-12-claudiu.beznea.uj@bp.renesas.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/adc/rzg2l_adc.c

index d7f65a7b2bb09edb7eb8f789bc9ea8eec42a1d10..ad5c403b0c6750e5080c6eadec579496cf301d5e 100644 (file)
@@ -88,6 +88,7 @@ struct rzg2l_adc {
        struct completion completion;
        struct mutex lock;
        u16 last_val[RZG2L_ADC_MAX_CHANNELS];
+       bool was_rpm_active;
 };
 
 /**
@@ -529,8 +530,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 = {