Convert the driver to use the device-managed versions of
iio_device_register(), iio_triggered_buffer_setup(), and mutex_init().
Use devm_add_action_or_reset() to ensure that the VCC and VREF
regulators are disabled safely and in the correct order during
driver teardown or probe failure.
Because all resources (buffer, regulators, IRQs, IIO device, mutex)
are now fully managed by the devm core, the unwinding order is
guaranteed to be correct (reverse order of allocation). We can now
safely remove all manual error handling goto labels in ad799x_probe()
and delete the ad799x_remove() function entirely.
This eliminates boilerplate code and prevents potential resource leaks.
Suggested-by: Jonathan Cameron <jic23@kernel.org>
Suggested-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Archit Anant <architanant5@gmail.com>
---
drivers/iio/adc/ad799x.c | 66 ++++++++++++++++------------------------
1 file changed, 27 insertions(+), 39 deletions(-)
diff --git a/drivers/iio/adc/ad799x.c b/drivers/iio/adc/ad799x.c
index 3cf7850357ab..c12bd7ed4dd7 100644
--- a/drivers/iio/adc/ad799x.c
+++ b/drivers/iio/adc/ad799x.c
@@ -774,6 +774,11 @@ static const struct ad799x_chip_info ad799x_chip_info_tbl[] = {
},
};
+static void ad799x_reg_disable(void *reg)
+{
+ regulator_disable(reg);
+}
+
static int ad799x_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -808,15 +813,19 @@ static int ad799x_probe(struct i2c_client *client)
if (ret)
return ret;
+ ret = devm_add_action_or_reset(dev, ad799x_reg_disable, st->reg);
+ if (ret)
+ return ret;
+
/* check if an external reference is supplied */
if (chip_info->has_vref) {
st->vref = devm_regulator_get_optional(dev, "vref");
ret = PTR_ERR_OR_ZERO(st->vref);
- if (ret) {
- if (ret != -ENODEV)
- goto error_disable_reg;
+ if (ret == -ENODEV) {
st->vref = NULL;
dev_info(dev, "Using VCC reference voltage\n");
+ } else if (ret) {
+ return ret;
}
if (st->vref) {
@@ -824,10 +833,15 @@ static int ad799x_probe(struct i2c_client *client)
extra_config |= AD7991_REF_SEL;
ret = regulator_enable(st->vref);
if (ret)
- goto error_disable_reg;
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, ad799x_reg_disable, st->vref);
+ if (ret)
+ return ret;
+
ret = regulator_get_voltage(st->vref);
if (ret < 0)
- goto error_disable_vref;
+ return ret;
st->vref_uV = ret;
}
}
@@ -835,7 +849,7 @@ static int ad799x_probe(struct i2c_client *client)
if (!st->vref) {
ret = regulator_get_voltage(st->reg);
if (ret < 0)
- goto error_disable_reg;
+ return ret;
st->vref_uV = ret;
}
@@ -850,12 +864,12 @@ static int ad799x_probe(struct i2c_client *client)
ret = ad799x_update_config(st, st->chip_config->default_config | extra_config);
if (ret)
- goto error_disable_vref;
+ return ret;
- ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
&ad799x_trigger_handler, NULL);
if (ret)
- goto error_disable_vref;
+ return ret;
if (client->irq > 0) {
ret = devm_request_threaded_irq(dev,
@@ -867,39 +881,14 @@ static int ad799x_probe(struct i2c_client *client)
client->name,
indio_dev);
if (ret)
- goto error_cleanup_ring;
+ return ret;
}
- mutex_init(&st->lock);
-
- ret = iio_device_register(indio_dev);
+ ret = devm_mutex_init(dev, &st->lock);
if (ret)
- goto error_cleanup_ring;
-
- return 0;
-
-error_cleanup_ring:
- iio_triggered_buffer_cleanup(indio_dev);
-error_disable_vref:
- if (st->vref)
- regulator_disable(st->vref);
-error_disable_reg:
- regulator_disable(st->reg);
-
- return ret;
-}
-
-static void ad799x_remove(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct ad799x_state *st = iio_priv(indio_dev);
-
- iio_device_unregister(indio_dev);
+ return ret;
- iio_triggered_buffer_cleanup(indio_dev);
- if (st->vref)
- regulator_disable(st->vref);
- regulator_disable(st->reg);
+ return devm_iio_device_register(dev, indio_dev);
}
static int ad799x_suspend(struct device *dev)
@@ -969,7 +958,6 @@ static struct i2c_driver ad799x_driver = {
.pm = pm_sleep_ptr(&ad799x_pm_ops),
},
.probe = ad799x_probe,
- .remove = ad799x_remove,
.id_table = ad799x_id,
};
module_i2c_driver(ad799x_driver);
--
2.39.5
On Thu, Mar 26, 2026 at 11:35:29PM +0530, Archit Anant wrote: > Convert the driver to use the device-managed versions of > iio_device_register(), iio_triggered_buffer_setup(), and mutex_init(). > > Use devm_add_action_or_reset() to ensure that the VCC and VREF > regulators are disabled safely and in the correct order during > driver teardown or probe failure. > > Because all resources (buffer, regulators, IRQs, IIO device, mutex) > are now fully managed by the devm core, the unwinding order is > guaranteed to be correct (reverse order of allocation). We can now > safely remove all manual error handling goto labels in ad799x_probe() > and delete the ad799x_remove() function entirely. > > This eliminates boilerplate code and prevents potential resource leaks. ... > - mutex_init(&st->lock); > - > - ret = iio_device_register(indio_dev); > + ret = devm_mutex_init(dev, &st->lock); Looking at how far from the start of probe this is done, it's prone to problems. What we need is to decouple this change and move mutex to be enabled before any interrupts or other async events may happen. > if (ret) > - goto error_cleanup_ring; > - > - return 0; > - > -error_cleanup_ring: > - iio_triggered_buffer_cleanup(indio_dev); > -error_disable_vref: > - if (st->vref) > - regulator_disable(st->vref); > -error_disable_reg: > - regulator_disable(st->reg); > - > - return ret; > -} -- With Best Regards, Andy Shevchenko
On Fri, Mar 27, 2026 at 12:45 AM Andy Shevchenko <andriy.shevchenko@intel.com> wrote: > > On Thu, Mar 26, 2026 at 11:35:29PM +0530, Archit Anant wrote: > > Convert the driver to use the device-managed versions of > > iio_device_register(), iio_triggered_buffer_setup(), and mutex_init(). > > > > Use devm_add_action_or_reset() to ensure that the VCC and VREF > > regulators are disabled safely and in the correct order during > > driver teardown or probe failure. > > > > Because all resources (buffer, regulators, IRQs, IIO device, mutex) > > are now fully managed by the devm core, the unwinding order is > > guaranteed to be correct (reverse order of allocation). We can now > > safely remove all manual error handling goto labels in ad799x_probe() > > and delete the ad799x_remove() function entirely. > > > > This eliminates boilerplate code and prevents potential resource leaks. > > ... > > > - mutex_init(&st->lock); > > - > > - ret = iio_device_register(indio_dev); > > + ret = devm_mutex_init(dev, &st->lock); > > Looking at how far from the start of probe this is done, it's prone to problems. > What we need is to decouple this change and move mutex to be enabled before any > interrupts or other async events may happen. > I understand how this can cause issues; I'll move the mutex lock up in probe before any interrupts or other async events can occur and send a new revision. > > if (ret) > > - goto error_cleanup_ring; > > - > > - return 0; > > - > > -error_cleanup_ring: > > - iio_triggered_buffer_cleanup(indio_dev); > > -error_disable_vref: > > - if (st->vref) > > - regulator_disable(st->vref); > > -error_disable_reg: > > - regulator_disable(st->reg); > > - > > - return ret; > > -} > > > -- > With Best Regards, > Andy Shevchenko > > -- Sincerely, Archit Anant
© 2016 - 2026 Red Hat, Inc.