Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

iio: dac: ds4424: convert to regmap

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>

authored by

Oleksij Rempel and committed by
Jonathan Cameron
cfeae3ce 8d68801a

+93 -75
+1
drivers/iio/dac/Kconfig
··· 408 408 config DS4424 409 409 tristate "Maxim Integrated DS4422/DS4424 DAC driver" 410 410 depends on I2C 411 + select REGMAP_I2C 411 412 help 412 413 If you say yes here you get support for Maxim chips DS4422, DS4424. 413 414
+92 -75
drivers/iio/dac/ds4424.c
··· 5 5 * Copyright (C) 2017 Maxim Integrated 6 6 */ 7 7 8 + #include <linux/array_size.h> 8 9 #include <linux/bits.h> 9 10 #include <linux/delay.h> 10 11 #include <linux/err.h> 11 12 #include <linux/i2c.h> 12 13 #include <linux/kernel.h> 13 14 #include <linux/module.h> 15 + #include <linux/regmap.h> 14 16 #include <linux/regulator/consumer.h> 15 17 #include <linux/time64.h> 18 + #include <linux/types.h> 16 19 17 20 #include <linux/iio/driver.h> 18 21 #include <linux/iio/iio.h> ··· 69 66 }; 70 67 71 68 struct ds4424_data { 72 - struct i2c_client *client; 73 - struct mutex lock; 74 - uint8_t save[DS4424_MAX_DAC_CHANNELS]; 69 + struct regmap *regmap; 75 70 struct regulator *vcc_reg; 76 - uint8_t raw[DS4424_MAX_DAC_CHANNELS]; 77 71 const struct ds4424_chip_info *chip_info; 78 72 }; 79 73 ··· 81 81 DS4424_CHANNEL(3), 82 82 }; 83 83 84 - static int ds4424_get_value(struct iio_dev *indio_dev, 85 - int *val, int channel) 84 + static const struct regmap_range ds44x2_ranges[] = { 85 + regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(1)), 86 + }; 87 + 88 + static const struct regmap_range ds44x4_ranges[] = { 89 + regmap_reg_range(DS4424_DAC_ADDR(0), DS4424_DAC_ADDR(3)), 90 + }; 91 + 92 + static const struct regmap_access_table ds44x2_table = { 93 + .yes_ranges = ds44x2_ranges, 94 + .n_yes_ranges = ARRAY_SIZE(ds44x2_ranges), 95 + }; 96 + 97 + static const struct regmap_access_table ds44x4_table = { 98 + .yes_ranges = ds44x4_ranges, 99 + .n_yes_ranges = ARRAY_SIZE(ds44x4_ranges), 100 + }; 101 + 102 + static const struct regmap_config ds44x2_regmap_config = { 103 + .reg_bits = 8, 104 + .val_bits = 8, 105 + .cache_type = REGCACHE_MAPLE, 106 + .max_register = DS4424_DAC_ADDR(1), 107 + .rd_table = &ds44x2_table, 108 + .wr_table = &ds44x2_table, 109 + }; 110 + 111 + static const struct regmap_config ds44x4_regmap_config = { 112 + .reg_bits = 8, 113 + .val_bits = 8, 114 + .cache_type = REGCACHE_MAPLE, 115 + .max_register = DS4424_DAC_ADDR(3), 116 + .rd_table = &ds44x4_table, 117 + .wr_table = &ds44x4_table, 118 + }; 119 + 120 + static int ds4424_init_regmap(struct i2c_client *client, 121 + struct iio_dev *indio_dev) 86 122 { 87 123 struct ds4424_data *data = iio_priv(indio_dev); 124 + const struct regmap_config *regmap_config; 125 + u8 vals[DS4424_MAX_DAC_CHANNELS]; 88 126 int ret; 89 127 90 - mutex_lock(&data->lock); 91 - ret = i2c_smbus_read_byte_data(data->client, DS4424_DAC_ADDR(channel)); 92 - if (ret < 0) 93 - goto fail; 128 + if (indio_dev->num_channels == DS4424_MAX_DAC_CHANNELS) 129 + regmap_config = &ds44x4_regmap_config; 130 + else 131 + regmap_config = &ds44x2_regmap_config; 94 132 95 - *val = ret; 133 + data->regmap = devm_regmap_init_i2c(client, regmap_config); 134 + if (IS_ERR(data->regmap)) 135 + return dev_err_probe(&client->dev, PTR_ERR(data->regmap), 136 + "Failed to init regmap.\n"); 96 137 97 - fail: 98 - mutex_unlock(&data->lock); 99 - return ret; 100 - } 138 + /* 139 + * Prime the cache with the bootloader's configuration. 140 + * regmap_bulk_read() will automatically populate the cache with 141 + * the values read from the hardware. 142 + */ 143 + ret = regmap_bulk_read(data->regmap, DS4424_DAC_ADDR(0), vals, 144 + indio_dev->num_channels); 145 + if (ret) 146 + return dev_err_probe(&client->dev, ret, 147 + "Failed to read hardware values\n"); 101 148 102 - static int ds4424_set_value(struct iio_dev *indio_dev, 103 - int val, struct iio_chan_spec const *chan) 104 - { 105 - struct ds4424_data *data = iio_priv(indio_dev); 106 - int ret; 107 - 108 - mutex_lock(&data->lock); 109 - ret = i2c_smbus_write_byte_data(data->client, 110 - DS4424_DAC_ADDR(chan->channel), val); 111 - if (ret < 0) 112 - goto fail; 113 - 114 - data->raw[chan->channel] = val; 115 - 116 - fail: 117 - mutex_unlock(&data->lock); 118 - return ret; 149 + return 0; 119 150 } 120 151 121 152 static int ds4424_read_raw(struct iio_dev *indio_dev, ··· 154 123 int *val, int *val2, long mask) 155 124 { 156 125 struct ds4424_data *data = iio_priv(indio_dev); 157 - int ret, regval; 126 + unsigned int regval; 127 + int ret; 158 128 159 129 switch (mask) { 160 130 case IIO_CHAN_INFO_RAW: 161 - ret = ds4424_get_value(indio_dev, &regval, chan->channel); 131 + ret = regmap_read(data->regmap, DS4424_DAC_ADDR(chan->channel), 132 + &regval); 162 133 if (ret < 0) { 163 134 dev_err_ratelimited(indio_dev->dev.parent, 164 135 "Failed to read channel %d: %pe\n", ··· 203 170 if (val > 0) 204 171 abs_val |= DS4424_DAC_SOURCE; 205 172 206 - return ds4424_set_value(indio_dev, abs_val, chan); 173 + return regmap_write(data->regmap, DS4424_DAC_ADDR(chan->channel), 174 + abs_val); 207 175 208 176 default: 209 177 return -EINVAL; 210 178 } 211 179 } 212 180 213 - static int ds4424_verify_chip(struct iio_dev *indio_dev) 214 - { 215 - int ret, val; 216 - 217 - ret = ds4424_get_value(indio_dev, &val, 0); 218 - if (ret < 0) 219 - dev_err(&indio_dev->dev, 220 - "%s failed. ret: %d\n", __func__, ret); 221 - 222 - return ret; 223 - } 224 - 225 181 static int ds4424_suspend(struct device *dev) 226 182 { 227 - struct i2c_client *client = to_i2c_client(dev); 228 - struct iio_dev *indio_dev = i2c_get_clientdata(client); 183 + struct iio_dev *indio_dev = dev_get_drvdata(dev); 229 184 struct ds4424_data *data = iio_priv(indio_dev); 230 - int ret = 0; 231 - int i; 185 + u8 zero_buf[DS4424_MAX_DAC_CHANNELS] = { }; 186 + int ret; 232 187 233 - for (i = 0; i < indio_dev->num_channels; i++) { 234 - data->save[i] = data->raw[i]; 235 - ret = ds4424_set_value(indio_dev, 0, 236 - &indio_dev->channels[i]); 237 - if (ret < 0) 238 - return ret; 188 + /* Disable all outputs, bypass cache so the '0' isn't saved */ 189 + regcache_cache_bypass(data->regmap, true); 190 + ret = regmap_bulk_write(data->regmap, DS4424_DAC_ADDR(0), 191 + zero_buf, indio_dev->num_channels); 192 + regcache_cache_bypass(data->regmap, false); 193 + if (ret) { 194 + dev_err(dev, "Failed to zero outputs: %pe\n", ERR_PTR(ret)); 195 + return ret; 239 196 } 240 - return ret; 197 + 198 + regcache_cache_only(data->regmap, true); 199 + regcache_mark_dirty(data->regmap); 200 + 201 + return 0; 241 202 } 242 203 243 204 static int ds4424_resume(struct device *dev) 244 205 { 245 - struct i2c_client *client = to_i2c_client(dev); 246 - struct iio_dev *indio_dev = i2c_get_clientdata(client); 206 + struct iio_dev *indio_dev = dev_get_drvdata(dev); 247 207 struct ds4424_data *data = iio_priv(indio_dev); 248 - int ret = 0; 249 - int i; 250 208 251 - for (i = 0; i < indio_dev->num_channels; i++) { 252 - ret = ds4424_set_value(indio_dev, data->save[i], 253 - &indio_dev->channels[i]); 254 - if (ret < 0) 255 - return ret; 256 - } 257 - return ret; 209 + regcache_cache_only(data->regmap, false); 210 + return regcache_sync(data->regmap); 258 211 } 259 212 260 213 static DEFINE_SIMPLE_DEV_PM_OPS(ds4424_pm_ops, ds4424_suspend, ds4424_resume); ··· 267 248 268 249 data = iio_priv(indio_dev); 269 250 i2c_set_clientdata(client, indio_dev); 270 - data->client = client; 271 251 indio_dev->name = chip_info->name; 272 252 data->chip_info = chip_info; 273 253 ··· 275 257 return dev_err_probe(&client->dev, PTR_ERR(data->vcc_reg), 276 258 "Failed to get vcc-supply regulator.\n"); 277 259 278 - mutex_init(&data->lock); 279 260 ret = regulator_enable(data->vcc_reg); 280 261 if (ret < 0) { 281 262 dev_err(&client->dev, ··· 289 272 */ 290 273 fsleep(1 * USEC_PER_MSEC); 291 274 292 - ret = ds4424_verify_chip(indio_dev); 293 - if (ret < 0) 294 - goto fail; 295 - 296 275 indio_dev->num_channels = chip_info->num_channels; 297 276 indio_dev->channels = ds4424_channels; 298 277 indio_dev->modes = INDIO_DIRECT_MODE; 299 278 indio_dev->info = &ds4424_iio_info; 279 + 280 + ret = ds4424_init_regmap(client, indio_dev); 281 + if (ret) 282 + goto fail; 300 283 301 284 ret = iio_device_register(indio_dev); 302 285 if (ret < 0) {