162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * IIO driver for Texas Instruments ADS7924 ADC, 12-bit, 4-Channels, I2C 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Author: Hugo Villeneuve <hvilleneuve@dimonoff.com> 662306a36Sopenharmony_ci * Copyright 2022 DimOnOff 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * based on iio/adc/ti-ads1015.c 962306a36Sopenharmony_ci * Copyright (c) 2016, Intel Corporation. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Datasheet: https://www.ti.com/lit/gpn/ads7924 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/bitfield.h> 1562306a36Sopenharmony_ci#include <linux/delay.h> 1662306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/irq.h> 1962306a36Sopenharmony_ci#include <linux/i2c.h> 2062306a36Sopenharmony_ci#include <linux/module.h> 2162306a36Sopenharmony_ci#include <linux/mutex.h> 2262306a36Sopenharmony_ci#include <linux/regmap.h> 2362306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <linux/iio/iio.h> 2662306a36Sopenharmony_ci#include <linux/iio/types.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define ADS7924_CHANNELS 4 2962306a36Sopenharmony_ci#define ADS7924_BITS 12 3062306a36Sopenharmony_ci#define ADS7924_DATA_SHIFT 4 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci/* Registers. */ 3362306a36Sopenharmony_ci#define ADS7924_MODECNTRL_REG 0x00 3462306a36Sopenharmony_ci#define ADS7924_INTCNTRL_REG 0x01 3562306a36Sopenharmony_ci#define ADS7924_DATA0_U_REG 0x02 3662306a36Sopenharmony_ci#define ADS7924_DATA0_L_REG 0x03 3762306a36Sopenharmony_ci#define ADS7924_DATA1_U_REG 0x04 3862306a36Sopenharmony_ci#define ADS7924_DATA1_L_REG 0x05 3962306a36Sopenharmony_ci#define ADS7924_DATA2_U_REG 0x06 4062306a36Sopenharmony_ci#define ADS7924_DATA2_L_REG 0x07 4162306a36Sopenharmony_ci#define ADS7924_DATA3_U_REG 0x08 4262306a36Sopenharmony_ci#define ADS7924_DATA3_L_REG 0x09 4362306a36Sopenharmony_ci#define ADS7924_ULR0_REG 0x0A 4462306a36Sopenharmony_ci#define ADS7924_LLR0_REG 0x0B 4562306a36Sopenharmony_ci#define ADS7924_ULR1_REG 0x0C 4662306a36Sopenharmony_ci#define ADS7924_LLR1_REG 0x0D 4762306a36Sopenharmony_ci#define ADS7924_ULR2_REG 0x0E 4862306a36Sopenharmony_ci#define ADS7924_LLR2_REG 0x0F 4962306a36Sopenharmony_ci#define ADS7924_ULR3_REG 0x10 5062306a36Sopenharmony_ci#define ADS7924_LLR3_REG 0x11 5162306a36Sopenharmony_ci#define ADS7924_INTCONFIG_REG 0x12 5262306a36Sopenharmony_ci#define ADS7924_SLPCONFIG_REG 0x13 5362306a36Sopenharmony_ci#define ADS7924_ACQCONFIG_REG 0x14 5462306a36Sopenharmony_ci#define ADS7924_PWRCONFIG_REG 0x15 5562306a36Sopenharmony_ci#define ADS7924_RESET_REG 0x16 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * Register address INC bit: when set to '1', the register address is 5962306a36Sopenharmony_ci * automatically incremented after every register read which allows convenient 6062306a36Sopenharmony_ci * reading of multiple registers. Set INC to '0' when reading a single register. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci#define ADS7924_AUTO_INCREMENT_BIT BIT(7) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define ADS7924_MODECNTRL_MODE_MASK GENMASK(7, 2) 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci#define ADS7924_MODECNTRL_SEL_MASK GENMASK(1, 0) 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define ADS7924_CFG_INTPOL_BIT 1 6962306a36Sopenharmony_ci#define ADS7924_CFG_INTTRIG_BIT 0 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define ADS7924_CFG_INTPOL_MASK BIT(ADS7924_CFG_INTPOL_BIT) 7262306a36Sopenharmony_ci#define ADS7924_CFG_INTTRIG_MASK BIT(ADS7924_CFG_INTTRIG_BIT) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci/* Interrupt pin polarity */ 7562306a36Sopenharmony_ci#define ADS7924_CFG_INTPOL_LOW 0 7662306a36Sopenharmony_ci#define ADS7924_CFG_INTPOL_HIGH 1 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Interrupt pin signaling */ 7962306a36Sopenharmony_ci#define ADS7924_CFG_INTTRIG_LEVEL 0 8062306a36Sopenharmony_ci#define ADS7924_CFG_INTTRIG_EDGE 1 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* Mode control values */ 8362306a36Sopenharmony_ci#define ADS7924_MODECNTRL_IDLE 0x00 8462306a36Sopenharmony_ci#define ADS7924_MODECNTRL_AWAKE 0x20 8562306a36Sopenharmony_ci#define ADS7924_MODECNTRL_MANUAL_SINGLE 0x30 8662306a36Sopenharmony_ci#define ADS7924_MODECNTRL_MANUAL_SCAN 0x32 8762306a36Sopenharmony_ci#define ADS7924_MODECNTRL_AUTO_SINGLE 0x31 8862306a36Sopenharmony_ci#define ADS7924_MODECNTRL_AUTO_SCAN 0x33 8962306a36Sopenharmony_ci#define ADS7924_MODECNTRL_AUTO_SINGLE_SLEEP 0x39 9062306a36Sopenharmony_ci#define ADS7924_MODECNTRL_AUTO_SCAN_SLEEP 0x3B 9162306a36Sopenharmony_ci#define ADS7924_MODECNTRL_AUTO_BURST_SLEEP 0x3F 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci#define ADS7924_ACQTIME_MASK GENMASK(4, 0) 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define ADS7924_PWRUPTIME_MASK GENMASK(4, 0) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/* 9862306a36Sopenharmony_ci * The power-up time is allowed to elapse whenever the device has been shutdown 9962306a36Sopenharmony_ci * in idle mode. Power-up time can allow external circuits, such as an 10062306a36Sopenharmony_ci * operational amplifier, between the MUXOUT and ADCIN pins to turn on. 10162306a36Sopenharmony_ci * The nominal time programmed by the PUTIME[4:0] register bits is given by: 10262306a36Sopenharmony_ci * t PU = PWRUPTIME[4:0] × 2 μs 10362306a36Sopenharmony_ci * If a power-up time is not required, set the bits to '0' to effectively bypass. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ci#define ADS7924_PWRUPTIME_US 0 /* Bypass (0us). */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* 10862306a36Sopenharmony_ci * Acquisition Time according to ACQTIME[4:0] register bits. 10962306a36Sopenharmony_ci * The Acquisition Time is given by: 11062306a36Sopenharmony_ci * t ACQ = (ACQTIME[4:0] × 2 μs) + 6 μs 11162306a36Sopenharmony_ci * Using default value of 0 for ACQTIME[4:0] results in a minimum acquisition 11262306a36Sopenharmony_ci * time of 6us. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci#define ADS7924_ACQTIME_US 6 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci/* The conversion time is always 4μs and cannot be programmed by the user. */ 11762306a36Sopenharmony_ci#define ADS7924_CONVTIME_US 4 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#define ADS7924_TOTAL_CONVTIME_US (ADS7924_PWRUPTIME_US + ADS7924_ACQTIME_US + \ 12062306a36Sopenharmony_ci ADS7924_CONVTIME_US) 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#define ADS7924_V_CHAN(_chan, _addr) { \ 12362306a36Sopenharmony_ci .type = IIO_VOLTAGE, \ 12462306a36Sopenharmony_ci .indexed = 1, \ 12562306a36Sopenharmony_ci .channel = _chan, \ 12662306a36Sopenharmony_ci .address = _addr, \ 12762306a36Sopenharmony_ci .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 12862306a36Sopenharmony_ci .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ 12962306a36Sopenharmony_ci .datasheet_name = "AIN"#_chan, \ 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistruct ads7924_data { 13362306a36Sopenharmony_ci struct device *dev; 13462306a36Sopenharmony_ci struct regmap *regmap; 13562306a36Sopenharmony_ci struct regulator *vref_reg; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* GPIO descriptor for device hard-reset pin. */ 13862306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci /* 14162306a36Sopenharmony_ci * Protects ADC ops, e.g: concurrent sysfs/buffered 14262306a36Sopenharmony_ci * data reads, configuration updates 14362306a36Sopenharmony_ci */ 14462306a36Sopenharmony_ci struct mutex lock; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * Set to true when the ADC is switched to the continuous-conversion 14862306a36Sopenharmony_ci * mode and exits from a power-down state. This flag is used to avoid 14962306a36Sopenharmony_ci * getting the stale result from the conversion register. 15062306a36Sopenharmony_ci */ 15162306a36Sopenharmony_ci bool conv_invalid; 15262306a36Sopenharmony_ci}; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic bool ads7924_is_writeable_reg(struct device *dev, unsigned int reg) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci switch (reg) { 15762306a36Sopenharmony_ci case ADS7924_MODECNTRL_REG: 15862306a36Sopenharmony_ci case ADS7924_INTCNTRL_REG: 15962306a36Sopenharmony_ci case ADS7924_ULR0_REG: 16062306a36Sopenharmony_ci case ADS7924_LLR0_REG: 16162306a36Sopenharmony_ci case ADS7924_ULR1_REG: 16262306a36Sopenharmony_ci case ADS7924_LLR1_REG: 16362306a36Sopenharmony_ci case ADS7924_ULR2_REG: 16462306a36Sopenharmony_ci case ADS7924_LLR2_REG: 16562306a36Sopenharmony_ci case ADS7924_ULR3_REG: 16662306a36Sopenharmony_ci case ADS7924_LLR3_REG: 16762306a36Sopenharmony_ci case ADS7924_INTCONFIG_REG: 16862306a36Sopenharmony_ci case ADS7924_SLPCONFIG_REG: 16962306a36Sopenharmony_ci case ADS7924_ACQCONFIG_REG: 17062306a36Sopenharmony_ci case ADS7924_PWRCONFIG_REG: 17162306a36Sopenharmony_ci case ADS7924_RESET_REG: 17262306a36Sopenharmony_ci return true; 17362306a36Sopenharmony_ci default: 17462306a36Sopenharmony_ci return false; 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_cistatic const struct regmap_config ads7924_regmap_config = { 17962306a36Sopenharmony_ci .reg_bits = 8, 18062306a36Sopenharmony_ci .val_bits = 8, 18162306a36Sopenharmony_ci .max_register = ADS7924_RESET_REG, 18262306a36Sopenharmony_ci .writeable_reg = ads7924_is_writeable_reg, 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistatic const struct iio_chan_spec ads7924_channels[] = { 18662306a36Sopenharmony_ci ADS7924_V_CHAN(0, ADS7924_DATA0_U_REG), 18762306a36Sopenharmony_ci ADS7924_V_CHAN(1, ADS7924_DATA1_U_REG), 18862306a36Sopenharmony_ci ADS7924_V_CHAN(2, ADS7924_DATA2_U_REG), 18962306a36Sopenharmony_ci ADS7924_V_CHAN(3, ADS7924_DATA3_U_REG), 19062306a36Sopenharmony_ci}; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int ads7924_get_adc_result(struct ads7924_data *data, 19362306a36Sopenharmony_ci struct iio_chan_spec const *chan, int *val) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci int ret; 19662306a36Sopenharmony_ci __be16 be_val; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (chan->channel < 0 || chan->channel >= ADS7924_CHANNELS) 19962306a36Sopenharmony_ci return -EINVAL; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci if (data->conv_invalid) { 20262306a36Sopenharmony_ci int conv_time; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci conv_time = ADS7924_TOTAL_CONVTIME_US; 20562306a36Sopenharmony_ci /* Allow 10% for internal clock inaccuracy. */ 20662306a36Sopenharmony_ci conv_time += conv_time / 10; 20762306a36Sopenharmony_ci usleep_range(conv_time, conv_time + 1); 20862306a36Sopenharmony_ci data->conv_invalid = false; 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci ret = regmap_raw_read(data->regmap, ADS7924_AUTO_INCREMENT_BIT | 21262306a36Sopenharmony_ci chan->address, &be_val, sizeof(be_val)); 21362306a36Sopenharmony_ci if (ret) 21462306a36Sopenharmony_ci return ret; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci *val = be16_to_cpu(be_val) >> ADS7924_DATA_SHIFT; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int ads7924_read_raw(struct iio_dev *indio_dev, 22262306a36Sopenharmony_ci struct iio_chan_spec const *chan, int *val, 22362306a36Sopenharmony_ci int *val2, long mask) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci int ret, vref_uv; 22662306a36Sopenharmony_ci struct ads7924_data *data = iio_priv(indio_dev); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci switch (mask) { 22962306a36Sopenharmony_ci case IIO_CHAN_INFO_RAW: 23062306a36Sopenharmony_ci mutex_lock(&data->lock); 23162306a36Sopenharmony_ci ret = ads7924_get_adc_result(data, chan, val); 23262306a36Sopenharmony_ci mutex_unlock(&data->lock); 23362306a36Sopenharmony_ci if (ret < 0) 23462306a36Sopenharmony_ci return ret; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return IIO_VAL_INT; 23762306a36Sopenharmony_ci case IIO_CHAN_INFO_SCALE: 23862306a36Sopenharmony_ci vref_uv = regulator_get_voltage(data->vref_reg); 23962306a36Sopenharmony_ci if (vref_uv < 0) 24062306a36Sopenharmony_ci return vref_uv; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci *val = vref_uv / 1000; /* Convert reg voltage to mV */ 24362306a36Sopenharmony_ci *val2 = ADS7924_BITS; 24462306a36Sopenharmony_ci return IIO_VAL_FRACTIONAL_LOG2; 24562306a36Sopenharmony_ci default: 24662306a36Sopenharmony_ci return -EINVAL; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic const struct iio_info ads7924_info = { 25162306a36Sopenharmony_ci .read_raw = ads7924_read_raw, 25262306a36Sopenharmony_ci}; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic int ads7924_get_channels_config(struct i2c_client *client, 25562306a36Sopenharmony_ci struct iio_dev *indio_dev) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct ads7924_data *priv = iio_priv(indio_dev); 25862306a36Sopenharmony_ci struct device *dev = priv->dev; 25962306a36Sopenharmony_ci struct fwnode_handle *node; 26062306a36Sopenharmony_ci int num_channels = 0; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci device_for_each_child_node(dev, node) { 26362306a36Sopenharmony_ci u32 pval; 26462306a36Sopenharmony_ci unsigned int channel; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (fwnode_property_read_u32(node, "reg", &pval)) { 26762306a36Sopenharmony_ci dev_err(dev, "invalid reg on %pfw\n", node); 26862306a36Sopenharmony_ci continue; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci channel = pval; 27262306a36Sopenharmony_ci if (channel >= ADS7924_CHANNELS) { 27362306a36Sopenharmony_ci dev_err(dev, "invalid channel index %d on %pfw\n", 27462306a36Sopenharmony_ci channel, node); 27562306a36Sopenharmony_ci continue; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci num_channels++; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci if (!num_channels) 28262306a36Sopenharmony_ci return -EINVAL; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return 0; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic int ads7924_set_conv_mode(struct ads7924_data *data, int mode) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci int ret; 29062306a36Sopenharmony_ci unsigned int mode_field; 29162306a36Sopenharmony_ci struct device *dev = data->dev; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * When switching between modes, be sure to first select the Awake mode 29562306a36Sopenharmony_ci * and then switch to the desired mode. This procedure ensures the 29662306a36Sopenharmony_ci * internal control logic is properly synchronized. 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci if (mode != ADS7924_MODECNTRL_IDLE) { 29962306a36Sopenharmony_ci mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK, 30062306a36Sopenharmony_ci ADS7924_MODECNTRL_AWAKE); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG, 30362306a36Sopenharmony_ci ADS7924_MODECNTRL_MODE_MASK, 30462306a36Sopenharmony_ci mode_field); 30562306a36Sopenharmony_ci if (ret) { 30662306a36Sopenharmony_ci dev_err(dev, "failed to set awake mode (%pe)\n", 30762306a36Sopenharmony_ci ERR_PTR(ret)); 30862306a36Sopenharmony_ci return ret; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci mode_field = FIELD_PREP(ADS7924_MODECNTRL_MODE_MASK, mode); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, ADS7924_MODECNTRL_REG, 31562306a36Sopenharmony_ci ADS7924_MODECNTRL_MODE_MASK, mode_field); 31662306a36Sopenharmony_ci if (ret) 31762306a36Sopenharmony_ci dev_err(dev, "failed to set mode %d (%pe)\n", mode, 31862306a36Sopenharmony_ci ERR_PTR(ret)); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return ret; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int ads7924_reset(struct iio_dev *indio_dev) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci struct ads7924_data *data = iio_priv(indio_dev); 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (data->reset_gpio) { 32862306a36Sopenharmony_ci gpiod_set_value(data->reset_gpio, 1); /* Assert. */ 32962306a36Sopenharmony_ci /* Educated guess: assert time not specified in datasheet... */ 33062306a36Sopenharmony_ci mdelay(100); 33162306a36Sopenharmony_ci gpiod_set_value(data->reset_gpio, 0); /* Deassert. */ 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* 33662306a36Sopenharmony_ci * A write of 10101010 to this register will generate a 33762306a36Sopenharmony_ci * software reset of the ADS7924. 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ci return regmap_write(data->regmap, ADS7924_RESET_REG, 0b10101010); 34062306a36Sopenharmony_ci}; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic void ads7924_reg_disable(void *data) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci regulator_disable(data); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void ads7924_set_idle_mode(void *data) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci ads7924_set_conv_mode(data, ADS7924_MODECNTRL_IDLE); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic int ads7924_probe(struct i2c_client *client) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct iio_dev *indio_dev; 35562306a36Sopenharmony_ci struct ads7924_data *data; 35662306a36Sopenharmony_ci struct device *dev = &client->dev; 35762306a36Sopenharmony_ci int ret; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); 36062306a36Sopenharmony_ci if (!indio_dev) 36162306a36Sopenharmony_ci return dev_err_probe(dev, -ENOMEM, 36262306a36Sopenharmony_ci "failed to allocate iio device\n"); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci data = iio_priv(indio_dev); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci data->dev = dev; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* Initialize the reset GPIO as output with an initial value of 0. */ 36962306a36Sopenharmony_ci data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 37062306a36Sopenharmony_ci if (IS_ERR(data->reset_gpio)) 37162306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(data->reset_gpio), 37262306a36Sopenharmony_ci "failed to get request reset GPIO\n"); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci mutex_init(&data->lock); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci indio_dev->name = "ads7924"; 37762306a36Sopenharmony_ci indio_dev->modes = INDIO_DIRECT_MODE; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci indio_dev->channels = ads7924_channels; 38062306a36Sopenharmony_ci indio_dev->num_channels = ARRAY_SIZE(ads7924_channels); 38162306a36Sopenharmony_ci indio_dev->info = &ads7924_info; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci ret = ads7924_get_channels_config(client, indio_dev); 38462306a36Sopenharmony_ci if (ret < 0) 38562306a36Sopenharmony_ci return dev_err_probe(dev, ret, 38662306a36Sopenharmony_ci "failed to get channels configuration\n"); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci data->regmap = devm_regmap_init_i2c(client, &ads7924_regmap_config); 38962306a36Sopenharmony_ci if (IS_ERR(data->regmap)) 39062306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(data->regmap), 39162306a36Sopenharmony_ci "failed to init regmap\n"); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci data->vref_reg = devm_regulator_get(dev, "vref"); 39462306a36Sopenharmony_ci if (IS_ERR(data->vref_reg)) 39562306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(data->vref_reg), 39662306a36Sopenharmony_ci "failed to get vref regulator\n"); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci ret = regulator_enable(data->vref_reg); 39962306a36Sopenharmony_ci if (ret) 40062306a36Sopenharmony_ci return dev_err_probe(dev, ret, 40162306a36Sopenharmony_ci "failed to enable regulator\n"); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, ads7924_reg_disable, data->vref_reg); 40462306a36Sopenharmony_ci if (ret) 40562306a36Sopenharmony_ci return dev_err_probe(dev, ret, 40662306a36Sopenharmony_ci "failed to add regulator disable action\n"); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci ret = ads7924_reset(indio_dev); 40962306a36Sopenharmony_ci if (ret < 0) 41062306a36Sopenharmony_ci return dev_err_probe(dev, ret, 41162306a36Sopenharmony_ci "failed to reset device\n"); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci ret = ads7924_set_conv_mode(data, ADS7924_MODECNTRL_AUTO_SCAN); 41462306a36Sopenharmony_ci if (ret) 41562306a36Sopenharmony_ci return dev_err_probe(dev, ret, 41662306a36Sopenharmony_ci "failed to set conversion mode\n"); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, ads7924_set_idle_mode, data); 41962306a36Sopenharmony_ci if (ret) 42062306a36Sopenharmony_ci return dev_err_probe(dev, ret, 42162306a36Sopenharmony_ci "failed to add idle mode action\n"); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* Use minimum signal acquire time. */ 42462306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, ADS7924_ACQCONFIG_REG, 42562306a36Sopenharmony_ci ADS7924_ACQTIME_MASK, 42662306a36Sopenharmony_ci FIELD_PREP(ADS7924_ACQTIME_MASK, 0)); 42762306a36Sopenharmony_ci if (ret < 0) 42862306a36Sopenharmony_ci return dev_err_probe(dev, ret, 42962306a36Sopenharmony_ci "failed to configure signal acquire time\n"); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci /* Disable power-up time. */ 43262306a36Sopenharmony_ci ret = regmap_update_bits(data->regmap, ADS7924_PWRCONFIG_REG, 43362306a36Sopenharmony_ci ADS7924_PWRUPTIME_MASK, 43462306a36Sopenharmony_ci FIELD_PREP(ADS7924_PWRUPTIME_MASK, 0)); 43562306a36Sopenharmony_ci if (ret < 0) 43662306a36Sopenharmony_ci return dev_err_probe(dev, ret, 43762306a36Sopenharmony_ci "failed to configure power-up time\n"); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci data->conv_invalid = true; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci ret = devm_iio_device_register(dev, indio_dev); 44262306a36Sopenharmony_ci if (ret < 0) 44362306a36Sopenharmony_ci return dev_err_probe(dev, ret, 44462306a36Sopenharmony_ci "failed to register IIO device\n"); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci return 0; 44762306a36Sopenharmony_ci} 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_cistatic const struct i2c_device_id ads7924_id[] = { 45062306a36Sopenharmony_ci { "ads7924", 0 }, 45162306a36Sopenharmony_ci {} 45262306a36Sopenharmony_ci}; 45362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ads7924_id); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic const struct of_device_id ads7924_of_match[] = { 45662306a36Sopenharmony_ci { .compatible = "ti,ads7924", }, 45762306a36Sopenharmony_ci {} 45862306a36Sopenharmony_ci}; 45962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ads7924_of_match); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_cistatic struct i2c_driver ads7924_driver = { 46262306a36Sopenharmony_ci .driver = { 46362306a36Sopenharmony_ci .name = "ads7924", 46462306a36Sopenharmony_ci .of_match_table = ads7924_of_match, 46562306a36Sopenharmony_ci }, 46662306a36Sopenharmony_ci .probe = ads7924_probe, 46762306a36Sopenharmony_ci .id_table = ads7924_id, 46862306a36Sopenharmony_ci}; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_cimodule_i2c_driver(ads7924_driver); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ciMODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@dimonoff.com>"); 47362306a36Sopenharmony_ciMODULE_DESCRIPTION("Texas Instruments ADS7924 ADC I2C driver"); 47462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 475