mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
synced 2025-09-08 15:29:54 +00:00
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:
parent
6dd8a77125
commit
563cf94f93
@ -88,6 +88,7 @@ struct rzg2l_adc {
|
|||||||
struct completion completion;
|
struct completion completion;
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
u16 last_val[RZG2L_ADC_MAX_CHANNELS];
|
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;
|
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 = {
|
static const struct dev_pm_ops rzg2l_adc_pm_ops = {
|
||||||
RUNTIME_PM_OPS(rzg2l_adc_pm_runtime_suspend, rzg2l_adc_pm_runtime_resume, NULL)
|
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 = {
|
static struct platform_driver rzg2l_adc_driver = {
|
||||||
|
Loading…
Reference in New Issue
Block a user