]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
iio: dac: ds4424: convert to regmap
authorOleksij Rempel <o.rempel@pengutronix.de>
Tue, 10 Feb 2026 13:51:08 +0000 (14:51 +0100)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sun, 22 Mar 2026 12:44:23 +0000 (12:44 +0000)
Refactor the driver to use the regmap API.

Replace the driver-specific mutex and manual shadow buffers with the
standard regmap infrastructure for locking and caching.

This ensures the cache is populated from hardware at probe, preventing
state desynchronization (e.g. across suspend/resume).

Define access tables to validate the different register maps of DS44x2
and DS44x4.

Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
Reviewed-by: Sander Vanheule <sander@svanheule.net>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@intel.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/dac/Kconfig
drivers/iio/dac/ds4424.c

index db9f5c711b3df90641f017652fbbef594cc1627d..cd4870b654153e91c3c44860be43d231ee3b5519 100644 (file)
@@ -408,6 +408,7 @@ config DPOT_DAC
 config DS4424
        tristate "Maxim Integrated DS4422/DS4424 DAC driver"
        depends on I2C
+       select REGMAP_I2C
        help
          If you say yes here you get support for Maxim chips DS4422, DS4424.
 
index 4eff052c2b6195283b31428c14a07f76323c8338..ee53614301c6471f8469ed91e0706091bc2eb547 100644 (file)
@@ -5,14 +5,17 @@
  * Copyright (C) 2017 Maxim Integrated
  */
 
+#include <linux/array_size.h>
 #include <linux/bits.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/regmap.h>
 #include <linux/regulator/consumer.h>
 #include <linux/time64.h>
+#include <linux/types.h>
 
 #include <linux/iio/driver.h>
 #include <linux/iio/iio.h>
@@ -66,11 +69,8 @@ static const struct ds4424_chip_info ds4424_info = {
 };
 
 struct ds4424_data {
-       struct i2c_client *client;
-       struct mutex lock;
-       uint8_t save[DS4424_MAX_DAC_CHANNELS];
+       struct regmap *regmap;
        struct regulator *vcc_reg;
-       uint8_t raw[DS4424_MAX_DAC_CHANNELS];
        const struct ds4424_chip_info *chip_info;
 };
 
@@ -81,41 +81,72 @@ static const struct iio_chan_spec ds4424_channels[] = {
        DS4424_CHANNEL(3),
 };
 
-static int ds4424_get_value(struct iio_dev *indio_dev,
-                            int *val, int channel)
-{
-       struct ds4424_data *data = iio_priv(indio_dev);
-       int ret;
+static const struct regmap_range ds44x2_ranges[] = {
+       regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(1)),
+};
 
-       mutex_lock(&data->lock);
-       ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel));
-       if (ret < 0)
-               goto fail;
+static const struct regmap_range ds44x4_ranges[] = {
+       regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(3)),
+};
 
-       *val = ret;
+static const struct regmap_access_table ds44x2_table = {
+       .yes_ranges = ds44x2_ranges,
+       .n_yes_ranges = ARRAY_SIZE(ds44x2_ranges),
+};
 
-fail:
-       mutex_unlock(&data->lock);
-       return ret;
-}
+static const struct regmap_access_table ds44x4_table = {
+       .yes_ranges = ds44x4_ranges,
+       .n_yes_ranges = ARRAY_SIZE(ds44x4_ranges),
+};
 
-static int ds4424_set_value(struct iio_dev *indio_dev,
-                            int val, struct iio_chan_spec const *chan)
+static const struct regmap_config ds44x2_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_MAPLE,
+       .max_register = DS4424_DAC_ADDR(1),
+       .rd_table = &ds44x2_table,
+       .wr_table = &ds44x2_table,
+};
+
+static const struct regmap_config ds44x4_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_MAPLE,
+       .max_register = DS4424_DAC_ADDR(3),
+       .rd_table = &ds44x4_table,
+       .wr_table = &ds44x4_table,
+};
+
+static int ds4424_init_regmap(struct i2c_client *client,
+                             struct iio_dev *indio_dev)
 {
        struct ds4424_data *data = iio_priv(indio_dev);
+       const struct regmap_config *regmap_config;
+       u8 vals[DS4424_MAX_DAC_CHANNELS];
        int ret;
 
-       mutex_lock(&data->lock);
-       ret = i2c_smbus_write_byte_data(data->client,
-                       DS4424_DAC_ADDR(chan->channel), val);
-       if (ret < 0)
-               goto fail;
+       if (indio_dev->num_channels == DS4424_MAX_DAC_CHANNELS)
+               regmap_config = &ds44x4_regmap_config;
+       else
+               regmap_config = &ds44x2_regmap_config;
 
-       data->raw[chan->channel] = val;
+       data->regmap = devm_regmap_init_i2c(client, regmap_config);
+       if (IS_ERR(data->regmap))
+               return dev_err_probe(&client->dev, PTR_ERR(data->regmap),
+                                    "Failed to init regmap.\n");
 
-fail:
-       mutex_unlock(&data->lock);
-       return ret;
+       /*
+        * Prime the cache with the bootloader's configuration.
+        * regmap_bulk_read() will automatically populate the cache with
+        * the values read from the hardware.
+        */
+       ret = regmap_bulk_read(data->regmap, DS4424_DAC_ADDR(0), vals,
+                              indio_dev->num_channels);
+       if (ret)
+               return dev_err_probe(&client->dev, ret,
+                                    "Failed to read hardware values\n");
+
+       return 0;
 }
 
 static int ds4424_read_raw(struct iio_dev *indio_dev,
@@ -123,11 +154,13 @@ static int ds4424_read_raw(struct iio_dev *indio_dev,
                           int *val, int *val2, long mask)
 {
        struct ds4424_data *data = iio_priv(indio_dev);
-       int ret, regval;
+       unsigned int regval;
+       int ret;
 
        switch (mask) {
        case IIO_CHAN_INFO_RAW:
-               ret = ds4424_get_value(indio_dev, &regval, chan->channel);
+               ret = regmap_read(data->regmap, DS4424_DAC_ADDR(chan->channel),
+                                 &regval);
                if (ret < 0) {
                        dev_err_ratelimited(indio_dev->dev.parent,
                                            "Failed to read channel %d: %pe\n",
@@ -170,58 +203,44 @@ static int ds4424_write_raw(struct iio_dev *indio_dev,
                if (val > 0)
                        abs_val |= DS4424_DAC_SOURCE;
 
-               return ds4424_set_value(indio_dev, abs_val, chan);
+               return regmap_write(data->regmap, DS4424_DAC_ADDR(chan->channel),
+                                   abs_val);
 
        default:
                return -EINVAL;
        }
 }
 
-static int ds4424_verify_chip(struct iio_dev *indio_dev)
-{
-       int ret, val;
-
-       ret = ds4424_get_value(indio_dev, &val, 0);
-       if (ret < 0)
-               dev_err(&indio_dev->dev,
-                               "%s failed. ret: %d\n", __func__, ret);
-
-       return ret;
-}
-
 static int ds4424_suspend(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct ds4424_data *data = iio_priv(indio_dev);
-       int ret = 0;
-       int i;
-
-       for (i = 0; i < indio_dev->num_channels; i++) {
-               data->save[i] = data->raw[i];
-               ret = ds4424_set_value(indio_dev, 0,
-                               &indio_dev->channels[i]);
-               if (ret < 0)
-                       return ret;
+       u8 zero_buf[DS4424_MAX_DAC_CHANNELS] = { };
+       int ret;
+
+       /* Disable all outputs, bypass cache so the '0' isn't saved */
+       regcache_cache_bypass(data->regmap, true);
+       ret = regmap_bulk_write(data->regmap, DS4424_DAC_ADDR(0),
+                               zero_buf, indio_dev->num_channels);
+       regcache_cache_bypass(data->regmap, false);
+       if (ret) {
+               dev_err(dev, "Failed to zero outputs: %pe\n", ERR_PTR(ret));
+               return ret;
        }
-       return ret;
+
+       regcache_cache_only(data->regmap, true);
+       regcache_mark_dirty(data->regmap);
+
+       return 0;
 }
 
 static int ds4424_resume(struct device *dev)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct iio_dev *indio_dev = i2c_get_clientdata(client);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
        struct ds4424_data *data = iio_priv(indio_dev);
-       int ret = 0;
-       int i;
 
-       for (i = 0; i < indio_dev->num_channels; i++) {
-               ret = ds4424_set_value(indio_dev, data->save[i],
-                               &indio_dev->channels[i]);
-               if (ret < 0)
-                       return ret;
-       }
-       return ret;
+       regcache_cache_only(data->regmap, false);
+       return regcache_sync(data->regmap);
 }
 
 static DEFINE_SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume);
@@ -248,7 +267,6 @@ static int ds4424_probe(struct i2c_client *client)
 
        data = iio_priv(indio_dev);
        i2c_set_clientdata(client, indio_dev);
-       data->client = client;
        indio_dev->name = chip_info->name;
        data->chip_info = chip_info;
 
@@ -257,7 +275,6 @@ static int ds4424_probe(struct i2c_client *client)
                return dev_err_probe(&client->dev, PTR_ERR(data->vcc_reg),
                                     "Failed to get vcc-supply regulator.\n");
 
-       mutex_init(&data->lock);
        ret = regulator_enable(data->vcc_reg);
        if (ret < 0) {
                dev_err(&client->dev,
@@ -272,15 +289,15 @@ static int ds4424_probe(struct i2c_client *client)
         */
        fsleep(1 * USEC_PER_MSEC);
 
-       ret = ds4424_verify_chip(indio_dev);
-       if (ret < 0)
-               goto fail;
-
        indio_dev->num_channels = chip_info->num_channels;
        indio_dev->channels = ds4424_channels;
        indio_dev->modes = INDIO_DIRECT_MODE;
        indio_dev->info = &ds4424_iio_info;
 
+       ret = ds4424_init_regmap(client, indio_dev);
+       if (ret)
+               goto fail;
+
        ret = iio_device_register(indio_dev);
        if (ret < 0) {
                dev_err(&client->dev,