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

iio: potentiometer: Add driver support for AD5110

The AD5110/AD5112/AD5114 provide a nonvolatile solution
for 128-/64-/32-position adjustment applications, offering
guaranteed low resistor tolerance errors of ±8% and up to
±6 mA current density.

Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/AD5110_5112_5114.pdf
Signed-off-by: Mugilraj Dhavachelvan <dmugil2000@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20210814175607.48399-3-dmugil2000@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Mugilraj Dhavachelvan and committed by
Jonathan Cameron
d03a74bf 88b6509b

+361
+6
MAINTAINERS
··· 459 459 W: https://parisc.wiki.kernel.org/index.php/AD1889 460 460 F: sound/pci/ad1889.* 461 461 462 + AD5110 ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER 463 + M: Mugilraj Dhavachelvan <dmugil2000@gmail.com> 464 + L: linux-iio@vger.kernel.org 465 + S: Supported 466 + F: drivers/iio/potentiometer/ad5110.c 467 + 462 468 AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER 463 469 M: Michael Hennerich <michael.hennerich@analog.com> 464 470 S: Supported
+10
drivers/iio/potentiometer/Kconfig
··· 6 6 7 7 menu "Digital potentiometers" 8 8 9 + config AD5110 10 + tristate "Analog Devices AD5110 and similar Digital Potentiometer driver" 11 + depends on I2C 12 + help 13 + Say yes here to build support for the Analog Devices AD5110, AD5112 14 + and AD5114 digital potentiometer chip. 15 + 16 + To compile this driver as a module, choose M here: the 17 + module will be called ad5110. 18 + 9 19 config AD5272 10 20 tristate "Analog Devices AD5272 and similar Digital Potentiometer driver" 11 21 depends on I2C
+1
drivers/iio/potentiometer/Makefile
··· 4 4 # 5 5 6 6 # When adding new entries keep the list in alphabetical order 7 + obj-$(CONFIG_AD5110) += ad5110.o 7 8 obj-$(CONFIG_AD5272) += ad5272.o 8 9 obj-$(CONFIG_DS1803) += ds1803.o 9 10 obj-$(CONFIG_MAX5432) += max5432.o
+344
drivers/iio/potentiometer/ad5110.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + /* 3 + * Analog Devices AD5110 digital potentiometer driver 4 + * 5 + * Copyright (C) 2021 Mugilraj Dhavachelvan <dmugil2000@gmail.com> 6 + * 7 + * Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/AD5110_5112_5114.pdf 8 + */ 9 + 10 + #include <linux/bitfield.h> 11 + #include <linux/delay.h> 12 + #include <linux/device.h> 13 + #include <linux/i2c.h> 14 + #include <linux/module.h> 15 + 16 + #include <linux/iio/iio.h> 17 + #include <linux/iio/sysfs.h> 18 + 19 + /* AD5110 commands */ 20 + #define AD5110_EEPROM_WR 1 21 + #define AD5110_RDAC_WR 2 22 + #define AD5110_SHUTDOWN 3 23 + #define AD5110_RESET 4 24 + #define AD5110_RDAC_RD 5 25 + #define AD5110_EEPROM_RD 6 26 + 27 + /* AD5110_EEPROM_RD data */ 28 + #define AD5110_WIPER_POS 0 29 + #define AD5110_RESISTOR_TOL 1 30 + 31 + #define AD5110_WIPER_RESISTANCE 70 32 + 33 + struct ad5110_cfg { 34 + int max_pos; 35 + int kohms; 36 + int shift; 37 + }; 38 + 39 + enum ad5110_type { 40 + AD5110_10, 41 + AD5110_80, 42 + AD5112_05, 43 + AD5112_10, 44 + AD5112_80, 45 + AD5114_10, 46 + AD5114_80, 47 + }; 48 + 49 + static const struct ad5110_cfg ad5110_cfg[] = { 50 + [AD5110_10] = { .max_pos = 128, .kohms = 10 }, 51 + [AD5110_80] = { .max_pos = 128, .kohms = 80 }, 52 + [AD5112_05] = { .max_pos = 64, .kohms = 5, .shift = 1 }, 53 + [AD5112_10] = { .max_pos = 64, .kohms = 10, .shift = 1 }, 54 + [AD5112_80] = { .max_pos = 64, .kohms = 80, .shift = 1 }, 55 + [AD5114_10] = { .max_pos = 32, .kohms = 10, .shift = 2 }, 56 + [AD5114_80] = { .max_pos = 32, .kohms = 80, .shift = 2 }, 57 + }; 58 + 59 + struct ad5110_data { 60 + struct i2c_client *client; 61 + s16 tol; /* resistor tolerance */ 62 + bool enable; 63 + struct mutex lock; 64 + const struct ad5110_cfg *cfg; 65 + /* 66 + * DMA (thus cache coherency maintenance) requires the 67 + * transfer buffers to live in their own cache lines. 68 + */ 69 + u8 buf[2] ____cacheline_aligned; 70 + }; 71 + 72 + static const struct iio_chan_spec ad5110_channels[] = { 73 + { 74 + .type = IIO_RESISTANCE, 75 + .output = 1, 76 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_OFFSET) | 77 + BIT(IIO_CHAN_INFO_SCALE) | BIT(IIO_CHAN_INFO_ENABLE), 78 + }, 79 + }; 80 + 81 + static int ad5110_read(struct ad5110_data *data, u8 cmd, int *val) 82 + { 83 + int ret; 84 + 85 + mutex_lock(&data->lock); 86 + data->buf[0] = cmd; 87 + data->buf[1] = *val; 88 + 89 + ret = i2c_master_send_dmasafe(data->client, data->buf, sizeof(data->buf)); 90 + if (ret < 0) { 91 + goto error; 92 + } else if (ret != sizeof(data->buf)) { 93 + ret = -EIO; 94 + goto error; 95 + } 96 + 97 + ret = i2c_master_recv_dmasafe(data->client, data->buf, 1); 98 + if (ret < 0) { 99 + goto error; 100 + } else if (ret != 1) { 101 + ret = -EIO; 102 + goto error; 103 + } 104 + 105 + *val = data->buf[0]; 106 + ret = 0; 107 + 108 + error: 109 + mutex_unlock(&data->lock); 110 + return ret; 111 + } 112 + 113 + static int ad5110_write(struct ad5110_data *data, u8 cmd, u8 val) 114 + { 115 + int ret; 116 + 117 + mutex_lock(&data->lock); 118 + data->buf[0] = cmd; 119 + data->buf[1] = val; 120 + 121 + ret = i2c_master_send_dmasafe(data->client, data->buf, sizeof(data->buf)); 122 + if (ret < 0) { 123 + goto error; 124 + } else if (ret != sizeof(data->buf)) { 125 + ret = -EIO; 126 + goto error; 127 + } 128 + 129 + ret = 0; 130 + 131 + error: 132 + mutex_unlock(&data->lock); 133 + return ret; 134 + } 135 + 136 + static int ad5110_resistor_tol(struct ad5110_data *data, u8 cmd, int val) 137 + { 138 + int ret; 139 + 140 + ret = ad5110_read(data, cmd, &val); 141 + if (ret) 142 + return ret; 143 + 144 + data->tol = data->cfg->kohms * (val & GENMASK(6, 0)) * 10 / 8; 145 + if (!(val & BIT(7))) 146 + data->tol *= -1; 147 + 148 + return 0; 149 + } 150 + 151 + static ssize_t store_eeprom_show(struct device *dev, 152 + struct device_attribute *attr, 153 + char *buf) 154 + { 155 + struct iio_dev *indio_dev = dev_to_iio_dev(dev); 156 + struct ad5110_data *data = iio_priv(indio_dev); 157 + int val = AD5110_WIPER_POS; 158 + int ret; 159 + 160 + ret = ad5110_read(data, AD5110_EEPROM_RD, &val); 161 + if (ret) 162 + return ret; 163 + 164 + val = val >> data->cfg->shift; 165 + return iio_format_value(buf, IIO_VAL_INT, 1, &val); 166 + } 167 + 168 + static ssize_t store_eeprom_store(struct device *dev, 169 + struct device_attribute *attr, 170 + const char *buf, size_t len) 171 + { 172 + struct iio_dev *indio_dev = dev_to_iio_dev(dev); 173 + struct ad5110_data *data = iio_priv(indio_dev); 174 + int ret; 175 + 176 + ret = ad5110_write(data, AD5110_EEPROM_WR, 0); 177 + if (ret) { 178 + dev_err(&data->client->dev, "RDAC to EEPROM write failed\n"); 179 + return ret; 180 + } 181 + 182 + /* The storing of EEPROM data takes approximately 18 ms. */ 183 + msleep(20); 184 + 185 + return len; 186 + } 187 + 188 + static IIO_DEVICE_ATTR_RW(store_eeprom, 0); 189 + 190 + static struct attribute *ad5110_attributes[] = { 191 + &iio_dev_attr_store_eeprom.dev_attr.attr, 192 + NULL 193 + }; 194 + 195 + static const struct attribute_group ad5110_attribute_group = { 196 + .attrs = ad5110_attributes, 197 + }; 198 + 199 + static int ad5110_read_raw(struct iio_dev *indio_dev, 200 + struct iio_chan_spec const *chan, 201 + int *val, int *val2, long mask) 202 + { 203 + struct ad5110_data *data = iio_priv(indio_dev); 204 + int ret; 205 + 206 + switch (mask) { 207 + case IIO_CHAN_INFO_RAW: 208 + ret = ad5110_read(data, AD5110_RDAC_RD, val); 209 + if (ret) 210 + return ret; 211 + 212 + *val = *val >> data->cfg->shift; 213 + return IIO_VAL_INT; 214 + case IIO_CHAN_INFO_OFFSET: 215 + *val = AD5110_WIPER_RESISTANCE * data->cfg->max_pos; 216 + *val2 = 1000 * data->cfg->kohms + data->tol; 217 + return IIO_VAL_FRACTIONAL; 218 + case IIO_CHAN_INFO_SCALE: 219 + *val = 1000 * data->cfg->kohms + data->tol; 220 + *val2 = data->cfg->max_pos; 221 + return IIO_VAL_FRACTIONAL; 222 + case IIO_CHAN_INFO_ENABLE: 223 + *val = data->enable; 224 + return IIO_VAL_INT; 225 + default: 226 + return -EINVAL; 227 + } 228 + } 229 + 230 + static int ad5110_write_raw(struct iio_dev *indio_dev, 231 + struct iio_chan_spec const *chan, 232 + int val, int val2, long mask) 233 + { 234 + struct ad5110_data *data = iio_priv(indio_dev); 235 + int ret; 236 + 237 + switch (mask) { 238 + case IIO_CHAN_INFO_RAW: 239 + if (val > data->cfg->max_pos || val < 0) 240 + return -EINVAL; 241 + 242 + return ad5110_write(data, AD5110_RDAC_WR, val << data->cfg->shift); 243 + case IIO_CHAN_INFO_ENABLE: 244 + if (val < 0 || val > 1) 245 + return -EINVAL; 246 + if (data->enable == val) 247 + return 0; 248 + ret = ad5110_write(data, AD5110_SHUTDOWN, val ? 0 : 1); 249 + if (ret) 250 + return ret; 251 + data->enable = val; 252 + return 0; 253 + default: 254 + return -EINVAL; 255 + } 256 + } 257 + 258 + static const struct iio_info ad5110_info = { 259 + .read_raw = ad5110_read_raw, 260 + .write_raw = ad5110_write_raw, 261 + .attrs = &ad5110_attribute_group, 262 + }; 263 + 264 + #define AD5110_COMPATIBLE(of_compatible, cfg) { \ 265 + .compatible = of_compatible, \ 266 + .data = &ad5110_cfg[cfg], \ 267 + } 268 + 269 + static const struct of_device_id ad5110_of_match[] = { 270 + AD5110_COMPATIBLE("adi,ad5110-10", AD5110_10), 271 + AD5110_COMPATIBLE("adi,ad5110-80", AD5110_80), 272 + AD5110_COMPATIBLE("adi,ad5112-05", AD5112_05), 273 + AD5110_COMPATIBLE("adi,ad5112-10", AD5112_10), 274 + AD5110_COMPATIBLE("adi,ad5112-80", AD5112_80), 275 + AD5110_COMPATIBLE("adi,ad5114-10", AD5114_10), 276 + AD5110_COMPATIBLE("adi,ad5114-80", AD5114_80), 277 + { } 278 + }; 279 + MODULE_DEVICE_TABLE(of, ad5110_of_match); 280 + 281 + static const struct i2c_device_id ad5110_id[] = { 282 + { "ad5110-10", AD5110_10 }, 283 + { "ad5110-80", AD5110_80 }, 284 + { "ad5112-05", AD5112_05 }, 285 + { "ad5112-10", AD5112_10 }, 286 + { "ad5112-80", AD5112_80 }, 287 + { "ad5114-10", AD5114_10 }, 288 + { "ad5114-80", AD5114_80 }, 289 + { } 290 + }; 291 + MODULE_DEVICE_TABLE(i2c, ad5110_id); 292 + 293 + static int ad5110_probe(struct i2c_client *client) 294 + { 295 + struct device *dev = &client->dev; 296 + struct iio_dev *indio_dev; 297 + struct ad5110_data *data; 298 + int ret; 299 + 300 + indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); 301 + if (!indio_dev) 302 + return -ENOMEM; 303 + 304 + data = iio_priv(indio_dev); 305 + data->client = client; 306 + mutex_init(&data->lock); 307 + data->enable = 1; 308 + data->cfg = device_get_match_data(dev); 309 + 310 + /* refresh RDAC register with EEPROM */ 311 + ret = ad5110_write(data, AD5110_RESET, 0); 312 + if (ret) { 313 + dev_err(dev, "Refresh RDAC with EEPROM failed\n"); 314 + return ret; 315 + } 316 + 317 + ret = ad5110_resistor_tol(data, AD5110_EEPROM_RD, AD5110_RESISTOR_TOL); 318 + if (ret) { 319 + dev_err(dev, "Read resistor tolerance failed\n"); 320 + return ret; 321 + } 322 + 323 + indio_dev->modes = INDIO_DIRECT_MODE; 324 + indio_dev->info = &ad5110_info; 325 + indio_dev->channels = ad5110_channels; 326 + indio_dev->num_channels = ARRAY_SIZE(ad5110_channels); 327 + indio_dev->name = client->name; 328 + 329 + return devm_iio_device_register(dev, indio_dev); 330 + } 331 + 332 + static struct i2c_driver ad5110_driver = { 333 + .driver = { 334 + .name = "ad5110", 335 + .of_match_table = ad5110_of_match, 336 + }, 337 + .probe_new = ad5110_probe, 338 + .id_table = ad5110_id, 339 + }; 340 + module_i2c_driver(ad5110_driver); 341 + 342 + MODULE_AUTHOR("Mugilraj Dhavachelvan <dmugil2000@gmail.com>"); 343 + MODULE_DESCRIPTION("AD5110 digital potentiometer"); 344 + MODULE_LICENSE("GPL v2");