iio: adc: meson_saradc: Better handle BL30 not releasing the hardware
authorUwe Kleine-König <u.kleine-koenig@pengutronix.de>
Sun, 19 Feb 2023 20:44:39 +0000 (21:44 +0100)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sat, 11 Mar 2023 12:18:28 +0000 (12:18 +0000)
meson_sar_adc_lock() might return an error if BL30 doesn't release its
lock on the hardware. Just returning early from .remove() is wrong
however as this keeps the clocks and regulators on which is never
cleaned up later.

Given the BL30 not giving up its lock is a strong hint for broken
behaviour, and there is nothing we can do about that: Just clean up
ignoring the fact that we're not holding the lock.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Reviewed-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
Link: https://lore.kernel.org/r/20230219204439.1641640-1-u.kleine-koenig@pengutronix.de
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/adc/meson_saradc.c

index 85b6826..18937a2 100644 (file)
@@ -957,14 +957,18 @@ err_lock:
        return ret;
 }
 
-static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
+static void meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
 {
        struct meson_sar_adc_priv *priv = iio_priv(indio_dev);
        int ret;
 
+       /*
+        * If taking the lock fails we have to assume that BL30 is broken. The
+        * best we can do then is to release the resources anyhow.
+        */
        ret = meson_sar_adc_lock(indio_dev);
        if (ret)
-               return ret;
+               dev_err(indio_dev->dev.parent, "Failed to lock ADC (%pE)\n", ERR_PTR(ret));
 
        clk_disable_unprepare(priv->adc_clk);
 
@@ -977,9 +981,8 @@ static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev)
 
        regulator_disable(priv->vref);
 
-       meson_sar_adc_unlock(indio_dev);
-
-       return 0;
+       if (!ret)
+               meson_sar_adc_unlock(indio_dev);
 }
 
 static irqreturn_t meson_sar_adc_irq(int irq, void *data)
@@ -1283,14 +1286,18 @@ static int meson_sar_adc_remove(struct platform_device *pdev)
 
        iio_device_unregister(indio_dev);
 
-       return meson_sar_adc_hw_disable(indio_dev);
+       meson_sar_adc_hw_disable(indio_dev);
+
+       return 0;
 }
 
 static int meson_sar_adc_suspend(struct device *dev)
 {
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
-       return meson_sar_adc_hw_disable(indio_dev);
+       meson_sar_adc_hw_disable(indio_dev);
+
+       return 0;
 }
 
 static int meson_sar_adc_resume(struct device *dev)