Commit 563cf94f authored by Claudiu Beznea's avatar Claudiu Beznea Committed by Jonathan Cameron
Browse files

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: default avatarClaudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
Reviewed-by: default avatarLad 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: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 6dd8a771
Loading
Loading
Loading
Loading
+70 −0
Original line number Diff line number Diff line
@@ -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 = {