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: adc: ti-ads7924: add Texas Instruments ADS7924 driver

The Texas Instruments ADS7924 is a 4 channels, 12-bit analog to
digital converter (ADC) with an I2C interface.

Datasheet: https://www.ti.com/lit/gpn/ads7924
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
Link: https://lore.kernel.org/r/20230115170623.3680647-2-hugo@hugovil.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Hugo Villeneuve and committed by
Jonathan Cameron
4d82b2f9 d354a2ee

+493
+7
MAINTAINERS
··· 20776 20776 S: Odd Fixes 20777 20777 F: drivers/gpio/gpio-thunderx.c 20778 20778 20779 + TI ADS7924 ADC DRIVER 20780 + M: Hugo Villeneuve <hvilleneuve@dimonoff.com> 20781 + L: linux-iio@vger.kernel.org 20782 + S: Supported 20783 + F: Documentation/devicetree/bindings/iio/adc/ti,ads7924.yaml 20784 + F: drivers/iio/adc/ti-ads7924.c 20785 + 20779 20786 TI AM437X VPFE DRIVER 20780 20787 M: "Lad, Prabhakar" <prabhakar.csengg@gmail.com> 20781 20788 L: linux-media@vger.kernel.org
+11
drivers/iio/adc/Kconfig
··· 1208 1208 This driver can also be built as a module. If so, the module will be 1209 1209 called ti-ads1015. 1210 1210 1211 + config TI_ADS7924 1212 + tristate "Texas Instruments ADS7924 ADC" 1213 + depends on I2C 1214 + select REGMAP_I2C 1215 + help 1216 + If you say yes here you get support for Texas Instruments ADS7924 1217 + 4 channels, 12-bit I2C ADC chip. 1218 + 1219 + This driver can also be built as a module. If so, the module will be 1220 + called ti-ads7924. 1221 + 1211 1222 config TI_ADS7950 1212 1223 tristate "Texas Instruments ADS7950 ADC driver" 1213 1224 depends on SPI && GPIOLIB
+1
drivers/iio/adc/Makefile
··· 107 107 obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o 108 108 obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o 109 109 obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o 110 + obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o 110 111 obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o 111 112 obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o 112 113 obj-$(CONFIG_TI_ADS8688) += ti-ads8688.o
+474
drivers/iio/adc/ti-ads7924.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * IIO driver for Texas Instruments ADS7924 ADC, 12-bit, 4-Channels, I2C 4 + * 5 + * Author: Hugo Villeneuve <hvilleneuve@dimonoff.com> 6 + * Copyright 2022 DimOnOff 7 + * 8 + * based on iio/adc/ti-ads1015.c 9 + * Copyright (c) 2016, Intel Corporation. 10 + * 11 + * Datasheet: https://www.ti.com/lit/gpn/ads7924 12 + */ 13 + 14 + #include <linux/bitfield.h> 15 + #include <linux/delay.h> 16 + #include <linux/gpio/consumer.h> 17 + #include <linux/init.h> 18 + #include <linux/irq.h> 19 + #include <linux/i2c.h> 20 + #include <linux/module.h> 21 + #include <linux/mutex.h> 22 + #include <linux/regmap.h> 23 + #include <linux/regulator/consumer.h> 24 + 25 + #include <linux/iio/iio.h> 26 + #include <linux/iio/types.h> 27 + 28 + #define ADS7924_CHANNELS 4 29 + #define ADS7924_BITS 12 30 + #define ADS7924_DATA_SHIFT 4 31 + 32 + /* Registers. */ 33 + #define ADS7924_MODECNTRL_REG 0x00 34 + #define ADS7924_INTCNTRL_REG 0x01 35 + #define ADS7924_DATA0_U_REG 0x02 36 + #define ADS7924_DATA0_L_REG 0x03 37 + #define ADS7924_DATA1_U_REG 0x04 38 + #define ADS7924_DATA1_L_REG 0x05 39 + #define ADS7924_DATA2_U_REG 0x06 40 + #define ADS7924_DATA2_L_REG 0x07 41 + #define ADS7924_DATA3_U_REG 0x08 42 + #define ADS7924_DATA3_L_REG 0x09 43 + #define ADS7924_ULR0_REG 0x0A 44 + #define ADS7924_LLR0_REG 0x0B 45 + #define ADS7924_ULR1_REG 0x0C 46 + #define ADS7924_LLR1_REG 0x0D 47 + #define ADS7924_ULR2_REG 0x0E 48 + #define ADS7924_LLR2_REG 0x0F 49 + #define ADS7924_ULR3_REG 0x10 50 + #define ADS7924_LLR3_REG 0x11 51 + #define ADS7924_INTCONFIG_REG 0x12 52 + #define ADS7924_SLPCONFIG_REG 0x13 53 + #define ADS7924_ACQCONFIG_REG 0x14 54 + #define ADS7924_PWRCONFIG_REG 0x15 55 + #define ADS7924_RESET_REG 0x16 56 + 57 + /* 58 + * Register address INC bit: when set to '1', the register address is 59 + * automatically incremented after every register read which allows convenient 60 + * reading of multiple registers. Set INC to '0' when reading a single register. 61 + */ 62 + #define ADS7924_AUTO_INCREMENT_BIT BIT(7) 63 + 64 + #define ADS7924_MODECNTRL_MODE_MASK GENMASK(7, 2) 65 + 66 + #define ADS7924_MODECNTRL_SEL_MASK GENMASK(1, 0) 67 + 68 + #define ADS7924_CFG_INTPOL_BIT 1 69 + #define ADS7924_CFG_INTTRIG_BIT 0 70 + 71 + #define ADS7924_CFG_INTPOL_MASK BIT(ADS7924_CFG_INTPOL_BIT) 72 + #define ADS7924_CFG_INTTRIG_MASK BIT(ADS7924_CFG_INTTRIG_BIT) 73 + 74 + /* Interrupt pin polarity */ 75 + #define ADS7924_CFG_INTPOL_LOW 0 76 + #define ADS7924_CFG_INTPOL_HIGH 1 77 + 78 + /* Interrupt pin signaling */ 79 + #define ADS7924_CFG_INTTRIG_LEVEL 0 80 + #define ADS7924_CFG_INTTRIG_EDGE 1 81 + 82 + /* Mode control values */ 83 + #define ADS7924_MODECNTRL_IDLE 0x00 84 + #define ADS7924_MODECNTRL_AWAKE 0x20 85 + #define ADS7924_MODECNTRL_MANUAL_SINGLE 0x30 86 + #define ADS7924_MODECNTRL_MANUAL_SCAN 0x32 87 + #define ADS7924_MODECNTRL_AUTO_SINGLE 0x31 88 + #define ADS7924_MODECNTRL_AUTO_SCAN 0x33 89 + #define ADS7924_MODECNTRL_AUTO_SINGLE_SLEEP 0x39 90 + #define ADS7924_MODECNTRL_AUTO_SCAN_SLEEP 0x3B 91 + #define ADS7924_MODECNTRL_AUTO_BURST_SLEEP 0x3F 92 + 93 + #define ADS7924_ACQTIME_MASK GENMASK(4, 0) 94 + 95 + #define ADS7924_PWRUPTIME_MASK GENMASK(4, 0) 96 + 97 + /* 98 + * The power-up time is allowed to elapse whenever the device has been shutdown 99 + * in idle mode. Power-up time can allow external circuits, such as an 100 + * operational amplifier, between the MUXOUT and ADCIN pins to turn on. 101 + * The nominal time programmed by the PUTIME[4:0] register bits is given by: 102 + * t PU = PWRUPTIME[4:0] × 2 μs 103 + * If a power-up time is not required, set the bits to '0' to effectively bypass. 104 + */ 105 + #define ADS7924_PWRUPTIME_US 0 /* Bypass (0us). */ 106 + 107 + /* 108 + * Acquisition Time according to ACQTIME[4:0] register bits. 109 + * The Acquisition Time is given by: 110 + * t ACQ = (ACQTIME[4:0] × 2 μs) + 6 μs 111 + * Using default value of 0 for ACQTIME[4:0] results in a minimum acquisition 112 + * time of 6us. 113 + */ 114 + #define ADS7924_ACQTIME_US 6 115 + 116 + /* The conversion time is always 4μs and cannot be programmed by the user. */ 117 + #define ADS7924_CONVTIME_US 4 118 + 119 + #define ADS7924_TOTAL_CONVTIME_US (ADS7924_PWRUPTIME_US + ADS7924_ACQTIME_US + \ 120 + ADS7924_CONVTIME_US) 121 + 122 + #define ADS7924_V_CHAN(_chan, _addr) { \ 123 + .type = IIO_VOLTAGE, \ 124 + .indexed = 1, \ 125 + .channel = _chan, \ 126 + .address = _addr, \ 127 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 128 + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 129 + .datasheet_name = "AIN"#_chan, \ 130 + } 131 + 132 + struct ads7924_data { 133 + struct device *dev; 134 + struct regmap *regmap; 135 + struct regulator *vref_reg; 136 + 137 + /* GPIO descriptor for device hard-reset pin. */ 138 + struct gpio_desc *reset_gpio; 139 + 140 + /* 141 + * Protects ADC ops, e.g: concurrent sysfs/buffered 142 + * data reads, configuration updates 143 + */ 144 + struct mutex lock; 145 + 146 + /* 147 + * Set to true when the ADC is switched to the continuous-conversion 148 + * mode and exits from a power-down state. This flag is used to avoid 149 + * getting the stale result from the conversion register. 150 + */ 151 + bool conv_invalid; 152 + }; 153 + 154 + static bool ads7924_is_writeable_reg(struct device *dev, unsigned int reg) 155 + { 156 + switch (reg) { 157 + case ADS7924_MODECNTRL_REG: 158 + case ADS7924_INTCNTRL_REG: 159 + case ADS7924_ULR0_REG: 160 + case ADS7924_LLR0_REG: 161 + case ADS7924_ULR1_REG: 162 + case ADS7924_LLR1_REG: 163 + case ADS7924_ULR2_REG: 164 + case ADS7924_LLR2_REG: 165 + case ADS7924_ULR3_REG: 166 + case ADS7924_LLR3_REG: 167 + case ADS7924_INTCONFIG_REG: 168 + case ADS7924_SLPCONFIG_REG: 169 + case ADS7924_ACQCONFIG_REG: 170 + case ADS7924_PWRCONFIG_REG: 171 + case ADS7924_RESET_REG: 172 + return true; 173 + default: 174 + return false; 175 + } 176 + } 177 + 178 + static const struct regmap_config ads7924_regmap_config = { 179 + .reg_bits = 8, 180 + .val_bits = 8, 181 + .max_register = ADS7924_RESET_REG, 182 + .writeable_reg = ads7924_is_writeable_reg, 183 + }; 184 + 185 + static const struct iio_chan_spec ads7924_channels[] = { 186 + ADS7924_V_CHAN(0, ADS7924_DATA0_U_REG), 187 + ADS7924_V_CHAN(1, ADS7924_DATA1_U_REG), 188 + ADS7924_V_CHAN(2, ADS7924_DATA2_U_REG), 189 + ADS7924_V_CHAN(3, ADS7924_DATA3_U_REG), 190 + }; 191 + 192 + static int ads7924_get_adc_result(struct ads7924_data *data, 193 + struct iio_chan_spec const *chan, int *val) 194 + { 195 + int ret; 196 + __be16 be_val; 197 + 198 + if (chan->channel < 0 || chan->channel >= ADS7924_CHANNELS) 199 + return -EINVAL; 200 + 201 + if (data->conv_invalid) { 202 + int conv_time; 203 + 204 + conv_time = ADS7924_TOTAL_CONVTIME_US; 205 + /* Allow 10% for internal clock inaccuracy. */ 206 + conv_time += conv_time / 10; 207 + usleep_range(conv_time, conv_time + 1); 208 + data->conv_invalid = false; 209 + } 210 + 211 + ret = regmap_raw_read(data->regmap, ADS7924_AUTO_INCREMENT_BIT | 212 + chan->address, &be_val, sizeof(be_val)); 213 + if (ret) 214 + return ret; 215 + 216 + *val = be16_to_cpu(be_val) >> ADS7924_DATA_SHIFT; 217 + 218 + return 0; 219 + } 220 + 221 + static int ads7924_read_raw(struct iio_dev *indio_dev, 222 + struct iio_chan_spec const *chan, int *val, 223 + int *val2, long mask) 224 + { 225 + int ret, vref_uv; 226 + struct ads7924_data *data = iio_priv(indio_dev); 227 + 228 + switch (mask) { 229 + case IIO_CHAN_INFO_RAW: 230 + mutex_lock(&data->lock); 231 + ret = ads7924_get_adc_result(data, chan, val); 232 + mutex_unlock(&data->lock); 233 + if (ret < 0) 234 + return ret; 235 + 236 + return IIO_VAL_INT; 237 + case IIO_CHAN_INFO_SCALE: 238 + vref_uv = regulator_get_voltage(data->vref_reg); 239 + if (vref_uv < 0) 240 + return vref_uv; 241 + 242 + *val = vref_uv / 1000; /* Convert reg voltage to mV */ 243 + *val2 = ADS7924_BITS; 244 + return IIO_VAL_FRACTIONAL_LOG2; 245 + default: 246 + return -EINVAL; 247 + } 248 + } 249 + 250 + static const struct iio_info ads7924_info = { 251 + .read_raw = ads7924_read_raw, 252 + }; 253 + 254 + static int ads7924_get_channels_config(struct i2c_client *client, 255 + struct iio_dev *indio_dev) 256 + { 257 + struct ads7924_data *priv = iio_priv(indio_dev); 258 + struct device *dev = priv->dev; 259 + struct fwnode_handle *node; 260 + int num_channels = 0; 261 + 262 + device_for_each_child_node(dev, node) { 263 + u32 pval; 264 + unsigned int channel; 265 + 266 + if (fwnode_property_read_u32(node, "reg", &pval)) { 267 + dev_err(dev, "invalid reg on %pfw\n", node); 268 + continue; 269 + } 270 + 271 + channel = pval; 272 + if (channel >= ADS7924_CHANNELS) { 273 + dev_err(dev, "invalid channel index %d on %pfw\n", 274 + channel, node); 275 + continue; 276 + } 277 + 278 + num_channels++; 279 + } 280 + 281 + if (!num_channels) 282 + return -EINVAL; 283 + 284 + return 0; 285 + } 286 + 287 + static int ads7924_set_conv_mode(struct ads7924_data *data, int mode) 288 + { 289 + int ret; 290 + unsigned int mode_field; 291 + struct device *dev = data->dev; 292 + 293 + /* 294 + * When switching between modes, be sure to first select the Awake mode 295 + * and then switch to the desired mode. This procedure ensures the 296 + * internal control logic is properly synchronized. 297 + */ 298 + if (mode != ADS7924_MODECNTRL_IDLE) { 299 + mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK, 300 + ADS7924_MODECNTRL_AWAKE); 301 + 302 + ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG, 303 + ADS7924_MODECNTRL_MODE_MASK, 304 + mode_field); 305 + if (ret) { 306 + dev_err(dev, "failed to set awake mode (%pe)\n", 307 + ERR_PTR(ret)); 308 + return ret; 309 + } 310 + } 311 + 312 + mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK, mode); 313 + 314 + ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG, 315 + ADS7924_MODECNTRL_MODE_MASK, mode_field); 316 + if (ret) 317 + dev_err(dev, "failed to set mode %d (%pe)\n", mode, 318 + ERR_PTR(ret)); 319 + 320 + return ret; 321 + } 322 + 323 + static int ads7924_reset(struct iio_dev *indio_dev) 324 + { 325 + struct ads7924_data *data = iio_priv(indio_dev); 326 + 327 + if (data->reset_gpio) { 328 + gpiod_set_value(data->reset_gpio, 1); /* Assert. */ 329 + /* Educated guess: assert time not specified in datasheet... */ 330 + mdelay(100); 331 + gpiod_set_value(data->reset_gpio, 0); /* Deassert. */ 332 + return 0; 333 + } 334 + 335 + /* 336 + * A write of 10101010 to this register will generate a 337 + * software reset of the ADS7924. 338 + */ 339 + return regmap_write(data->regmap, ADS7924_RESET_REG, 0b10101010); 340 + }; 341 + 342 + static void ads7924_reg_disable(void *data) 343 + { 344 + regulator_disable(data); 345 + } 346 + 347 + static void ads7924_set_idle_mode(void *data) 348 + { 349 + ads7924_set_conv_mode(data, ADS7924_MODECNTRL_IDLE); 350 + } 351 + 352 + static int ads7924_probe(struct i2c_client *client) 353 + { 354 + struct iio_dev *indio_dev; 355 + struct ads7924_data *data; 356 + struct device *dev = &client->dev; 357 + int ret; 358 + 359 + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 360 + if (!indio_dev) 361 + return dev_err_probe(dev, -ENOMEM, 362 + "failed to allocate iio device\n"); 363 + 364 + data = iio_priv(indio_dev); 365 + 366 + data->dev = dev; 367 + 368 + /* Initialize the reset GPIO as output with an initial value of 0. */ 369 + data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 370 + if (IS_ERR(data->reset_gpio)) 371 + return dev_err_probe(dev, PTR_ERR(data->reset_gpio), 372 + "failed to get request reset GPIO\n"); 373 + 374 + mutex_init(&data->lock); 375 + 376 + indio_dev->name = "ads7924"; 377 + indio_dev->modes = INDIO_DIRECT_MODE; 378 + 379 + indio_dev->channels = ads7924_channels; 380 + indio_dev->num_channels = ARRAY_SIZE(ads7924_channels); 381 + indio_dev->info = &ads7924_info; 382 + 383 + ret = ads7924_get_channels_config(client, indio_dev); 384 + if (ret < 0) 385 + return dev_err_probe(dev, ret, 386 + "failed to get channels configuration\n"); 387 + 388 + data->regmap = devm_regmap_init_i2c(client, &ads7924_regmap_config); 389 + if (IS_ERR(data->regmap)) 390 + return dev_err_probe(dev, PTR_ERR(data->regmap), 391 + "failed to init regmap\n"); 392 + 393 + data->vref_reg = devm_regulator_get(dev, "vref"); 394 + if (IS_ERR(data->vref_reg)) 395 + return dev_err_probe(dev, PTR_ERR(data->vref_reg), 396 + "failed to get vref regulator\n"); 397 + 398 + ret = regulator_enable(data->vref_reg); 399 + if (ret) 400 + return dev_err_probe(dev, ret, 401 + "failed to enable regulator\n"); 402 + 403 + ret = devm_add_action_or_reset(dev, ads7924_reg_disable, data->vref_reg); 404 + if (ret) 405 + return dev_err_probe(dev, ret, 406 + "failed to add regulator disable action\n"); 407 + 408 + ret = ads7924_reset(indio_dev); 409 + if (ret < 0) 410 + return dev_err_probe(dev, ret, 411 + "failed to reset device\n"); 412 + 413 + ret = ads7924_set_conv_mode(data, ADS7924_MODECNTRL_AUTO_SCAN); 414 + if (ret) 415 + return dev_err_probe(dev, ret, 416 + "failed to set conversion mode\n"); 417 + 418 + ret = devm_add_action_or_reset(dev, ads7924_set_idle_mode, data); 419 + if (ret) 420 + return dev_err_probe(dev, ret, 421 + "failed to add idle mode action\n"); 422 + 423 + /* Use minimum signal acquire time. */ 424 + ret = regmap_update_bits(data->regmap, ADS7924_ACQCONFIG_REG, 425 + ADS7924_ACQTIME_MASK, 426 + FIELD_PREP(ADS7924_ACQTIME_MASK, 0)); 427 + if (ret < 0) 428 + return dev_err_probe(dev, ret, 429 + "failed to configure signal acquire time\n"); 430 + 431 + /* Disable power-up time. */ 432 + ret = regmap_update_bits(data->regmap, ADS7924_PWRCONFIG_REG, 433 + ADS7924_PWRUPTIME_MASK, 434 + FIELD_PREP(ADS7924_PWRUPTIME_MASK, 0)); 435 + if (ret < 0) 436 + return dev_err_probe(dev, ret, 437 + "failed to configure power-up time\n"); 438 + 439 + data->conv_invalid = true; 440 + 441 + ret = devm_iio_device_register(dev, indio_dev); 442 + if (ret < 0) 443 + return dev_err_probe(dev, ret, 444 + "failed to register IIO device\n"); 445 + 446 + return 0; 447 + } 448 + 449 + static const struct i2c_device_id ads7924_id[] = { 450 + { "ads7924", 0 }, 451 + {} 452 + }; 453 + MODULE_DEVICE_TABLE(i2c, ads7924_id); 454 + 455 + static const struct of_device_id ads7924_of_match[] = { 456 + { .compatible = "ti,ads7924", }, 457 + {} 458 + }; 459 + MODULE_DEVICE_TABLE(of, ads7924_of_match); 460 + 461 + static struct i2c_driver ads7924_driver = { 462 + .driver = { 463 + .name = "ads7924", 464 + .of_match_table = ads7924_of_match, 465 + }, 466 + .probe_new = ads7924_probe, 467 + .id_table = ads7924_id, 468 + }; 469 + 470 + module_i2c_driver(ads7924_driver); 471 + 472 + MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@dimonoff.com>"); 473 + MODULE_DESCRIPTION("Texas Instruments ADS7924 ADC I2C driver"); 474 + MODULE_LICENSE("GPL");