iio: adc: rzg2l_adc: Add suspend/resume support

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>
This commit is contained in:
Claudiu Beznea 2024-12-06 13:13:33 +02:00 committed by Jonathan Cameron
parent 6dd8a77125
commit 563cf94f93

View 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 = {