On Fri, 3 Jan 2025 at 15:00, Claudiu <claudiu.beznea@xxxxxxxxx> wrote: > > From: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> > > On all systems where the rzg2l_adc driver is used, the ADC clocks are part > of a PM domain. The code that implements the PM domains support is in > drivers/clk/renesas/rzg2l-cpg.c, the functions of interest for this commit > being rzg2l_cpg_attach_dev() and rzg2l_cpg_deattach_dev(). The PM > domains support is registered with GENPD_FLAG_PM_CLK which, according to > the documentation, instructs genpd to use the PM clk framework while > powering on/off attached devices. > > During probe, the ADC device is attached to the PM domain > controlling the ADC clocks. Similarly, during removal, the ADC device is > detached from the PM domain. > > The detachment call stack is as follows: > > device_driver_detach() -> > device_release_driver_internal() -> > __device_release_driver() -> > device_remove() -> > platform_remove() -> > dev_pm_domain_detach() > > During driver unbind, after the ADC device is detached from its PM domain, > the device_unbind_cleanup() function is called, which subsequently invokes > devres_release_all(). This function handles devres resource cleanup. > > If runtime PM is enabled via devm_pm_runtime_enable(), the cleanup process > triggers the action or reset function for disabling runtime PM. This > function is pm_runtime_disable_action(), which leads to the following call > stack of interest when called: > > pm_runtime_disable_action() -> > pm_runtime_dont_use_autosuspend() -> > __pm_runtime_use_autosuspend() -> > update_autosuspend() -> > rpm_idle() > > The rpm_idle() function attempts to runtime resume the ADC device. However, > at the point it is called, the ADC device is no longer part of the PM > domain (which manages the ADC clocks). Since the rzg2l_adc runtime PM > APIs directly modifies hardware registers, the > rzg2l_adc_pm_runtime_resume() function is invoked without the ADC clocks > being enabled. This is because the PM domain no longer resumes along with > the ADC device. As a result, this leads to system aborts. > > Drop the devres API for runtime PM enable. > > Fixes: 89ee8174e8c8 ("iio: adc: rzg2l_adc: Simplify the runtime PM code") > Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@xxxxxxxxxxxxxx> Reviewed-by: Ulf Hansson <ulf.hansson@xxxxxxxxxx> Kind regards Uffe > --- > drivers/iio/adc/rzg2l_adc.c | 33 ++++++++++++++++++++++++--------- > 1 file changed, 24 insertions(+), 9 deletions(-) > > diff --git a/drivers/iio/adc/rzg2l_adc.c b/drivers/iio/adc/rzg2l_adc.c > index 883c167c0670..f12f3daf08cc 100644 > --- a/drivers/iio/adc/rzg2l_adc.c > +++ b/drivers/iio/adc/rzg2l_adc.c > @@ -464,25 +464,26 @@ static int rzg2l_adc_probe(struct platform_device *pdev) > > pm_runtime_set_autosuspend_delay(dev, 300); > pm_runtime_use_autosuspend(dev); > - ret = devm_pm_runtime_enable(dev); > - if (ret) > - return ret; > + pm_runtime_enable(dev); > > platform_set_drvdata(pdev, indio_dev); > > ret = rzg2l_adc_hw_init(dev, adc); > - if (ret) > - return dev_err_probe(&pdev->dev, ret, > - "failed to initialize ADC HW\n"); > + if (ret) { > + dev_err_probe(&pdev->dev, ret, "failed to initialize ADC HW\n"); > + goto rpm_disable; > + } > > irq = platform_get_irq(pdev, 0); > - if (irq < 0) > - return irq; > + if (irq < 0) { > + ret = irq; > + goto rpm_disable; > + } > > ret = devm_request_irq(dev, irq, rzg2l_adc_isr, > 0, dev_name(dev), adc); > if (ret < 0) > - return ret; > + goto rpm_disable; > > init_completion(&adc->completion); > > @@ -493,6 +494,19 @@ static int rzg2l_adc_probe(struct platform_device *pdev) > indio_dev->num_channels = adc->data->num_channels; > > return devm_iio_device_register(dev, indio_dev); > + > +rpm_disable: > + pm_runtime_disable(dev); > + pm_runtime_dont_use_autosuspend(dev); > + return ret; > +} > + > +static void rzg2l_adc_remove(struct platform_device *pdev) > +{ > + struct device *dev = &pdev->dev; > + > + pm_runtime_disable(dev); > + pm_runtime_dont_use_autosuspend(dev); > } > > static const struct rzg2l_adc_hw_params rzg2l_hw_params = { > @@ -614,6 +628,7 @@ static const struct dev_pm_ops rzg2l_adc_pm_ops = { > > static struct platform_driver rzg2l_adc_driver = { > .probe = rzg2l_adc_probe, > + .remove = rzg2l_adc_remove, > .driver = { > .name = DRIVER_NAME, > .of_match_table = rzg2l_adc_match, > -- > 2.43.0 >