iio: adc: add max11410 adc driver
authorIbrahim Tilki <Ibrahim.Tilki@analog.com>
Mon, 3 Oct 2022 10:59:01 +0000 (13:59 +0300)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Wed, 23 Nov 2022 19:43:59 +0000 (19:43 +0000)
Adding support for max11410 24-bit, 1.9ksps delta-sigma adc which
has 3 differential reference and 10 differential channel inputs.
Inputs and references can be buffered internally. Inputs can also
be amplified with internal PGA.

Device has four digital filter modes: FIR50/60, FIR50, FIR60 and SINC4.
FIR 50Hz and 60Hz rejections can be enabled/disabled separately.
Digital filter selection affects sampling frequency range so driver
has to consider the configured filter when configuring sampling frequency.

Signed-off-by: Ibrahim Tilki <Ibrahim.Tilki@analog.com>
Link: https://lore.kernel.org/r/20221003105903.229-2-Ibrahim.Tilki@analog.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/max11410.c [new file with mode: 0644]

index 791612ca601207b58baf709068741845aee46132..544986fd456de1a7a82d05e07aacae6586009f01 100644 (file)
@@ -667,6 +667,19 @@ config MAX11205
          To compile this driver as a module, choose M here: the module will be
          called max11205.
 
+config MAX11410
+       tristate "Analog Devices MAX11410 ADC driver"
+       depends on SPI
+       select REGMAP_SPI
+       select IIO_BUFFER
+       select IIO_TRIGGER
+       select IIO_TRIGGERED_BUFFER
+       help
+         Say yes here to build support for Analog Devices MAX11410 ADCs.
+
+         To compile this driver as a module, choose M here: the module will be
+         called max11410.
+
 config MAX1241
        tristate "Maxim max1241 ADC driver"
        depends on SPI_MASTER
index 46caba7a010c9e1974032dee2dbdd534562bf9ff..4d803413425c4b8f879f58d07dcd2669151ff51a 100644 (file)
@@ -62,6 +62,7 @@ obj-$(CONFIG_MAX1027) += max1027.o
 obj-$(CONFIG_MAX11100) += max11100.o
 obj-$(CONFIG_MAX1118) += max1118.o
 obj-$(CONFIG_MAX11205) += max11205.o
+obj-$(CONFIG_MAX11410) += max11410.o
 obj-$(CONFIG_MAX1241) += max1241.o
 obj-$(CONFIG_MAX1363) += max1363.o
 obj-$(CONFIG_MAX9611) += max9611.o
diff --git a/drivers/iio/adc/max11410.c b/drivers/iio/adc/max11410.c
new file mode 100644 (file)
index 0000000..8cd5663
--- /dev/null
@@ -0,0 +1,1050 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MAX11410 SPI ADC driver
+ *
+ * Copyright 2022 Analog Devices Inc.
+ */
+#include <asm-generic/unaligned.h>
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+#define MAX11410_REG_CONV_START        0x01
+#define                MAX11410_CONV_TYPE_SINGLE       0x00
+#define                MAX11410_CONV_TYPE_CONTINUOUS   0x01
+#define MAX11410_REG_CAL_START 0x03
+#define                MAX11410_CAL_START_SELF         0x00
+#define                MAX11410_CAL_START_PGA          0x01
+#define MAX11410_REG_GPIO_CTRL(ch)             ((ch) ? 0x05 : 0x04)
+#define                MAX11410_GPIO_INTRB             0xC1
+#define MAX11410_REG_FILTER    0x08
+#define                MAX11410_FILTER_RATE_MASK       GENMASK(3, 0)
+#define                MAX11410_FILTER_RATE_MAX        0x0F
+#define                MAX11410_FILTER_LINEF_MASK      GENMASK(5, 4)
+#define                MAX11410_FILTER_50HZ            BIT(5)
+#define                MAX11410_FILTER_60HZ            BIT(4)
+#define MAX11410_REG_CTRL      0x09
+#define                MAX11410_CTRL_REFSEL_MASK       GENMASK(2, 0)
+#define                MAX11410_CTRL_VREFN_BUF_BIT     BIT(3)
+#define                MAX11410_CTRL_VREFP_BUF_BIT     BIT(4)
+#define                MAX11410_CTRL_FORMAT_BIT        BIT(5)
+#define                MAX11410_CTRL_UNIPOLAR_BIT      BIT(6)
+#define MAX11410_REG_MUX_CTRL0 0x0B
+#define MAX11410_REG_PGA       0x0E
+#define                MAX11410_PGA_GAIN_MASK          GENMASK(2, 0)
+#define                MAX11410_PGA_SIG_PATH_MASK      GENMASK(5, 4)
+#define                MAX11410_PGA_SIG_PATH_BUFFERED  0x00
+#define                MAX11410_PGA_SIG_PATH_BYPASS    0x01
+#define                MAX11410_PGA_SIG_PATH_PGA       0x02
+#define MAX11410_REG_DATA0     0x30
+#define MAX11410_REG_STATUS    0x38
+#define                MAX11410_STATUS_CONV_READY_BIT  BIT(0)
+#define                MAX11410_STATUS_CAL_READY_BIT   BIT(2)
+
+#define MAX11410_REFSEL_AVDD_AGND      0x03
+#define MAX11410_REFSEL_MAX            0x06
+#define MAX11410_SIG_PATH_MAX          0x02
+#define MAX11410_CHANNEL_INDEX_MAX     0x0A
+#define MAX11410_AINP_AVDD     0x0A
+#define MAX11410_AINN_GND      0x0A
+
+#define MAX11410_CONVERSION_TIMEOUT_MS 2000
+#define MAX11410_CALIB_TIMEOUT_MS      2000
+
+#define MAX11410_SCALE_AVAIL_SIZE      8
+
+enum max11410_filter {
+       MAX11410_FILTER_FIR5060,
+       MAX11410_FILTER_FIR50,
+       MAX11410_FILTER_FIR60,
+       MAX11410_FILTER_SINC4,
+};
+
+static const u8 max11410_sampling_len[] = {
+       [MAX11410_FILTER_FIR5060] = 5,
+       [MAX11410_FILTER_FIR50] = 6,
+       [MAX11410_FILTER_FIR60] = 6,
+       [MAX11410_FILTER_SINC4] = 10,
+};
+
+static const int max11410_sampling_rates[4][10][2] = {
+       [MAX11410_FILTER_FIR5060] = {
+               { 1, 100000 },
+               { 2, 100000 },
+               { 4, 200000 },
+               { 8, 400000 },
+               { 16, 800000 }
+       },
+       [MAX11410_FILTER_FIR50] = {
+               { 1, 300000 },
+               { 2, 700000 },
+               { 5, 300000 },
+               { 10, 700000 },
+               { 21, 300000 },
+               { 40 }
+       },
+       [MAX11410_FILTER_FIR60] = {
+               { 1, 300000 },
+               { 2, 700000 },
+               { 5, 300000 },
+               { 10, 700000 },
+               { 21, 300000 },
+               { 40 }
+       },
+       [MAX11410_FILTER_SINC4] = {
+               { 4 },
+               { 10 },
+               { 20 },
+               { 40 },
+               { 60 },
+               { 120 },
+               { 240 },
+               { 480 },
+               { 960 },
+               { 1920 }
+       }
+};
+
+struct max11410_channel_config {
+       u32 settling_time_us;
+       u32 *scale_avail;
+       u8 refsel;
+       u8 sig_path;
+       u8 gain;
+       bool bipolar;
+       bool buffered_vrefp;
+       bool buffered_vrefn;
+};
+
+struct max11410_state {
+       struct spi_device *spi_dev;
+       struct iio_trigger *trig;
+       struct completion completion;
+       struct mutex lock; /* Prevent changing channel config during sampling */
+       struct regmap *regmap;
+       struct regulator *avdd;
+       struct regulator *vrefp[3];
+       struct regulator *vrefn[3];
+       struct max11410_channel_config *channels;
+       int irq;
+       struct {
+               u32 data __aligned(IIO_DMA_MINALIGN);
+               s64 ts __aligned(8);
+       } scan;
+};
+
+static const struct iio_chan_spec chanspec_template = {
+       .type = IIO_VOLTAGE,
+       .indexed = 1,
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+                             BIT(IIO_CHAN_INFO_SCALE) |
+                             BIT(IIO_CHAN_INFO_OFFSET),
+       .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+       .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+       .scan_type = {
+               .sign = 's',
+               .realbits = 24,
+               .storagebits = 32,
+               .endianness = IIO_LE,
+       },
+};
+
+static unsigned int max11410_reg_size(unsigned int reg)
+{
+       /* Registers from 0x00 to 0x10 are 1 byte, the rest are 3 bytes long. */
+       return reg <= 0x10 ? 1 : 3;
+}
+
+static int max11410_write_reg(struct max11410_state *st, unsigned int reg,
+                             unsigned int val)
+{
+       /* This driver only needs to write 8-bit registers */
+       if (max11410_reg_size(reg) != 1)
+               return -EINVAL;
+
+       return regmap_write(st->regmap, reg, val);
+}
+
+static int max11410_read_reg(struct max11410_state *st, unsigned int reg,
+                            int *val)
+{
+       int ret;
+
+       if (max11410_reg_size(reg) == 3) {
+               ret = regmap_bulk_read(st->regmap, reg, &st->scan.data, 3);
+               if (ret)
+                       return ret;
+
+               *val = get_unaligned_be24(&st->scan.data);
+               return 0;
+       }
+
+       return regmap_read(st->regmap, reg, val);
+}
+
+static struct regulator *max11410_get_vrefp(struct max11410_state *st,
+                                           u8 refsel)
+{
+       refsel = refsel % 4;
+       if (refsel == 3)
+               return st->avdd;
+
+       return st->vrefp[refsel];
+}
+
+static struct regulator *max11410_get_vrefn(struct max11410_state *st,
+                                           u8 refsel)
+{
+       if (refsel > 2)
+               return NULL;
+
+       return st->vrefn[refsel];
+}
+
+static const struct regmap_config regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0x39,
+};
+
+static ssize_t max11410_notch_en_show(struct device *dev,
+                                     struct device_attribute *devattr,
+                                     char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct max11410_state *state = iio_priv(indio_dev);
+       struct iio_dev_attr *iio_attr = to_iio_dev_attr(devattr);
+       unsigned int val;
+       int ret;
+
+       ret = max11410_read_reg(state, MAX11410_REG_FILTER, &val);
+       if (ret)
+               return ret;
+
+       switch (iio_attr->address) {
+       case 0:
+               val = !FIELD_GET(MAX11410_FILTER_50HZ, val);
+               break;
+       case 1:
+               val = !FIELD_GET(MAX11410_FILTER_60HZ, val);
+               break;
+       case 2:
+               val = FIELD_GET(MAX11410_FILTER_LINEF_MASK, val) == 3;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return sysfs_emit(buf, "%d\n", val);
+}
+
+static ssize_t max11410_notch_en_store(struct device *dev,
+                                      struct device_attribute *devattr,
+                                      const char *buf, size_t count)
+{
+       struct iio_dev_attr *iio_attr = to_iio_dev_attr(devattr);
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct max11410_state *state = iio_priv(indio_dev);
+       unsigned int filter_bits;
+       bool enable;
+       int ret;
+
+       ret = kstrtobool(buf, &enable);
+       if (ret)
+               return ret;
+
+       switch (iio_attr->address) {
+       case 0:
+               filter_bits = MAX11410_FILTER_50HZ;
+               break;
+       case 1:
+               filter_bits = MAX11410_FILTER_60HZ;
+               break;
+       case 2:
+       default:
+               filter_bits = MAX11410_FILTER_50HZ | MAX11410_FILTER_60HZ;
+               enable = !enable;
+               break;
+       }
+
+       if (enable)
+               ret = regmap_clear_bits(state->regmap, MAX11410_REG_FILTER,
+                                       filter_bits);
+       else
+               ret = regmap_set_bits(state->regmap, MAX11410_REG_FILTER,
+                                     filter_bits);
+
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static ssize_t in_voltage_filter2_notch_center_show(struct device *dev,
+                                                   struct device_attribute *devattr,
+                                                   char *buf)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct max11410_state *state = iio_priv(indio_dev);
+       int ret, reg, rate, filter;
+
+       ret = regmap_read(state->regmap, MAX11410_REG_FILTER, &reg);
+       if (ret)
+               return ret;
+
+       rate = FIELD_GET(MAX11410_FILTER_RATE_MASK, reg);
+       rate = clamp_val(rate, 0,
+                        max11410_sampling_len[MAX11410_FILTER_SINC4] - 1);
+       filter = max11410_sampling_rates[MAX11410_FILTER_SINC4][rate][0];
+
+       return sysfs_emit(buf, "%d\n", filter);
+}
+
+static IIO_CONST_ATTR(in_voltage_filter0_notch_center, "50");
+static IIO_CONST_ATTR(in_voltage_filter1_notch_center, "60");
+static IIO_DEVICE_ATTR_RO(in_voltage_filter2_notch_center, 2);
+
+static IIO_DEVICE_ATTR(in_voltage_filter0_notch_en, 0644,
+                      max11410_notch_en_show, max11410_notch_en_store, 0);
+static IIO_DEVICE_ATTR(in_voltage_filter1_notch_en, 0644,
+                      max11410_notch_en_show, max11410_notch_en_store, 1);
+static IIO_DEVICE_ATTR(in_voltage_filter2_notch_en, 0644,
+                      max11410_notch_en_show, max11410_notch_en_store, 2);
+
+static struct attribute *max11410_attributes[] = {
+       &iio_const_attr_in_voltage_filter0_notch_center.dev_attr.attr,
+       &iio_const_attr_in_voltage_filter1_notch_center.dev_attr.attr,
+       &iio_dev_attr_in_voltage_filter2_notch_center.dev_attr.attr,
+       &iio_dev_attr_in_voltage_filter0_notch_en.dev_attr.attr,
+       &iio_dev_attr_in_voltage_filter1_notch_en.dev_attr.attr,
+       &iio_dev_attr_in_voltage_filter2_notch_en.dev_attr.attr,
+       NULL
+};
+
+static const struct attribute_group max11410_attribute_group = {
+       .attrs = max11410_attributes,
+};
+
+static int max11410_set_input_mux(struct max11410_state *st, u8 ainp, u8 ainn)
+{
+       if (ainp > MAX11410_CHANNEL_INDEX_MAX ||
+           ainn > MAX11410_CHANNEL_INDEX_MAX)
+               return -EINVAL;
+
+       return max11410_write_reg(st, MAX11410_REG_MUX_CTRL0,
+                                 (ainp << 4) | ainn);
+}
+
+static int max11410_configure_channel(struct max11410_state *st,
+                                     struct iio_chan_spec const *chan)
+{
+       struct max11410_channel_config cfg = st->channels[chan->address];
+       unsigned int regval;
+       int ret;
+
+       if (chan->differential)
+               ret = max11410_set_input_mux(st, chan->channel, chan->channel2);
+       else
+               ret = max11410_set_input_mux(st, chan->channel,
+                                            MAX11410_AINN_GND);
+
+       if (ret)
+               return ret;
+
+       regval = FIELD_PREP(MAX11410_CTRL_VREFP_BUF_BIT, cfg.buffered_vrefp) |
+                FIELD_PREP(MAX11410_CTRL_VREFN_BUF_BIT, cfg.buffered_vrefn) |
+                FIELD_PREP(MAX11410_CTRL_REFSEL_MASK, cfg.refsel) |
+                FIELD_PREP(MAX11410_CTRL_UNIPOLAR_BIT, cfg.bipolar ? 0 : 1);
+       ret = regmap_update_bits(st->regmap, MAX11410_REG_CTRL,
+                                MAX11410_CTRL_REFSEL_MASK |
+                                MAX11410_CTRL_VREFN_BUF_BIT |
+                                MAX11410_CTRL_VREFN_BUF_BIT |
+                                MAX11410_CTRL_UNIPOLAR_BIT, regval);
+       if (ret)
+               return ret;
+
+       regval = FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK, cfg.sig_path) |
+                FIELD_PREP(MAX11410_PGA_GAIN_MASK, cfg.gain);
+       ret = regmap_write(st->regmap, MAX11410_REG_PGA, regval);
+       if (ret)
+               return ret;
+
+       if (cfg.settling_time_us)
+               fsleep(cfg.settling_time_us);
+
+       return 0;
+}
+
+static int max11410_sample(struct max11410_state *st, int *sample_raw,
+                          struct iio_chan_spec const *chan)
+{
+       int val, ret;
+
+       ret = max11410_configure_channel(st, chan);
+       if (ret)
+               return ret;
+
+       if (st->irq > 0)
+               reinit_completion(&st->completion);
+
+       /* Start Conversion */
+       ret = max11410_write_reg(st, MAX11410_REG_CONV_START,
+                                MAX11410_CONV_TYPE_SINGLE);
+       if (ret)
+               return ret;
+
+       if (st->irq > 0) {
+               /* Wait for an interrupt. */
+               ret = wait_for_completion_timeout(&st->completion,
+                                                 msecs_to_jiffies(MAX11410_CONVERSION_TIMEOUT_MS));
+               if (!ret)
+                       return -ETIMEDOUT;
+       } else {
+               /* Wait for status register Conversion Ready flag */
+               ret = read_poll_timeout(max11410_read_reg, ret,
+                                       ret || (val & MAX11410_STATUS_CONV_READY_BIT),
+                                       5000, MAX11410_CONVERSION_TIMEOUT_MS * 1000,
+                                       true, st, MAX11410_REG_STATUS, &val);
+               if (ret)
+                       return ret;
+       }
+
+       /* Read ADC Data */
+       return max11410_read_reg(st, MAX11410_REG_DATA0, sample_raw);
+}
+
+static int max11410_get_scale(struct max11410_state *state,
+                             struct max11410_channel_config cfg)
+{
+       struct regulator *vrefp, *vrefn;
+       int scale;
+
+       vrefp = max11410_get_vrefp(state, cfg.refsel);
+
+       scale = regulator_get_voltage(vrefp) / 1000;
+       vrefn = max11410_get_vrefn(state, cfg.refsel);
+       if (vrefn)
+               scale -= regulator_get_voltage(vrefn) / 1000;
+
+       if (cfg.bipolar)
+               scale *= 2;
+
+       return scale >> cfg.gain;
+}
+
+static int max11410_read_raw(struct iio_dev *indio_dev,
+                            struct iio_chan_spec const *chan,
+                            int *val, int *val2, long info)
+{
+       struct max11410_state *state = iio_priv(indio_dev);
+       struct max11410_channel_config cfg = state->channels[chan->address];
+       int ret, reg_val, filter, rate;
+
+       switch (info) {
+       case IIO_CHAN_INFO_SCALE:
+               *val = max11410_get_scale(state, cfg);
+               *val2 = chan->scan_type.realbits;
+               return IIO_VAL_FRACTIONAL_LOG2;
+       case IIO_CHAN_INFO_OFFSET:
+               if (cfg.bipolar)
+                       *val = -BIT(chan->scan_type.realbits - 1);
+               else
+                       *val = 0;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_RAW:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               mutex_lock(&state->lock);
+
+               ret = max11410_sample(state, &reg_val, chan);
+
+               mutex_unlock(&state->lock);
+
+               iio_device_release_direct_mode(indio_dev);
+
+               if (ret)
+                       return ret;
+
+               *val = reg_val;
+
+               return IIO_VAL_INT;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = regmap_read(state->regmap, MAX11410_REG_FILTER, &reg_val);
+               if (ret)
+                       return ret;
+
+               filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+               rate = reg_val & MAX11410_FILTER_RATE_MASK;
+               if (rate >= max11410_sampling_len[filter])
+                       rate = max11410_sampling_len[filter] - 1;
+
+               *val = max11410_sampling_rates[filter][rate][0];
+               *val2 = max11410_sampling_rates[filter][rate][1];
+
+               return IIO_VAL_INT_PLUS_MICRO;
+       }
+       return -EINVAL;
+}
+
+static int max11410_write_raw(struct iio_dev *indio_dev,
+                             struct iio_chan_spec const *chan,
+                             int val, int val2, long mask)
+{
+       struct max11410_state *st = iio_priv(indio_dev);
+       int i, ret, reg_val, filter, gain;
+       u32 *scale_avail;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_SCALE:
+               scale_avail = st->channels[chan->address].scale_avail;
+               if (!scale_avail)
+                       return -EOPNOTSUPP;
+
+               /* Accept values in range 0.000001 <= scale < 1.000000 */
+               if (val != 0 || val2 == 0)
+                       return -EINVAL;
+
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               /* Convert from INT_PLUS_MICRO to FRACTIONAL_LOG2 */
+               val2 = val2 * DIV_ROUND_CLOSEST(BIT(24), 1000000);
+               val2 = DIV_ROUND_CLOSEST(scale_avail[0], val2);
+               gain = order_base_2(val2);
+
+               st->channels[chan->address].gain = clamp_val(gain, 0, 7);
+
+               iio_device_release_direct_mode(indio_dev);
+
+               return 0;
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = iio_device_claim_direct_mode(indio_dev);
+               if (ret)
+                       return ret;
+
+               mutex_lock(&st->lock);
+
+               ret = regmap_read(st->regmap, MAX11410_REG_FILTER, &reg_val);
+               if (ret)
+                       goto out;
+
+               filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+
+               for (i = 0; i < max11410_sampling_len[filter]; ++i) {
+                       if (val == max11410_sampling_rates[filter][i][0] &&
+                           val2 == max11410_sampling_rates[filter][i][1])
+                               break;
+               }
+               if (i == max11410_sampling_len[filter]) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+                                       MAX11410_FILTER_RATE_MASK, i);
+
+out:
+               mutex_unlock(&st->lock);
+               iio_device_release_direct_mode(indio_dev);
+
+               return ret;
+       default:
+               return -EINVAL;
+       }
+}
+
+static int max11410_read_avail(struct iio_dev *indio_dev,
+                              struct iio_chan_spec const *chan,
+                              const int **vals, int *type, int *length,
+                              long info)
+{
+       struct max11410_state *st = iio_priv(indio_dev);
+       struct max11410_channel_config cfg;
+       int ret, reg_val, filter;
+
+       switch (info) {
+       case IIO_CHAN_INFO_SAMP_FREQ:
+               ret = regmap_read(st->regmap, MAX11410_REG_FILTER, &reg_val);
+               if (ret)
+                       return ret;
+
+               filter = FIELD_GET(MAX11410_FILTER_LINEF_MASK, reg_val);
+
+               *vals = (const int *)max11410_sampling_rates[filter];
+               *length = max11410_sampling_len[filter] * 2;
+               *type = IIO_VAL_INT_PLUS_MICRO;
+
+               return IIO_AVAIL_LIST;
+       case IIO_CHAN_INFO_SCALE:
+               cfg = st->channels[chan->address];
+
+               if (!cfg.scale_avail)
+                       return -EINVAL;
+
+               *vals = cfg.scale_avail;
+               *length = MAX11410_SCALE_AVAIL_SIZE * 2;
+               *type = IIO_VAL_FRACTIONAL_LOG2;
+
+               return IIO_AVAIL_LIST;
+       }
+       return -EINVAL;
+}
+
+static const struct iio_info max11410_info = {
+       .read_raw = max11410_read_raw,
+       .write_raw = max11410_write_raw,
+       .read_avail = max11410_read_avail,
+       .attrs = &max11410_attribute_group,
+};
+
+static irqreturn_t max11410_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct max11410_state *st = iio_priv(indio_dev);
+       int ret;
+
+       ret = max11410_read_reg(st, MAX11410_REG_DATA0, &st->scan.data);
+       if (ret) {
+               dev_err(&indio_dev->dev, "cannot read data\n");
+               goto out;
+       }
+
+       iio_push_to_buffers_with_timestamp(indio_dev, &st->scan,
+                                          iio_get_time_ns(indio_dev));
+
+out:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
+static int max11410_buffer_postenable(struct iio_dev *indio_dev)
+{
+       struct max11410_state *st = iio_priv(indio_dev);
+       int scan_ch, ret;
+
+       scan_ch = ffs(*indio_dev->active_scan_mask) - 1;
+
+       ret = max11410_configure_channel(st, &indio_dev->channels[scan_ch]);
+       if (ret)
+               return ret;
+
+       /* Start continuous conversion. */
+       return max11410_write_reg(st, MAX11410_REG_CONV_START,
+                                 MAX11410_CONV_TYPE_CONTINUOUS);
+}
+
+static int max11410_buffer_predisable(struct iio_dev *indio_dev)
+{
+       struct max11410_state *st = iio_priv(indio_dev);
+
+       /* Stop continuous conversion. */
+       return max11410_write_reg(st, MAX11410_REG_CONV_START,
+                                 MAX11410_CONV_TYPE_SINGLE);
+}
+
+static const struct iio_buffer_setup_ops max11410_buffer_ops = {
+       .postenable = &max11410_buffer_postenable,
+       .predisable = &max11410_buffer_predisable,
+       .validate_scan_mask = &iio_validate_scan_mask_onehot,
+};
+
+static const struct iio_trigger_ops max11410_trigger_ops = {
+       .validate_device = iio_trigger_validate_own_device,
+};
+
+static irqreturn_t max11410_interrupt(int irq, void *dev_id)
+{
+       struct iio_dev *indio_dev = dev_id;
+       struct max11410_state *st = iio_priv(indio_dev);
+
+       if (iio_buffer_enabled(indio_dev))
+               iio_trigger_poll_chained(st->trig);
+       else
+               complete(&st->completion);
+
+       return IRQ_HANDLED;
+};
+
+static int max11410_parse_channels(struct max11410_state *st,
+                                  struct iio_dev *indio_dev)
+{
+       struct iio_chan_spec chanspec = chanspec_template;
+       struct device *dev = &st->spi_dev->dev;
+       struct max11410_channel_config *cfg;
+       struct iio_chan_spec *channels;
+       struct fwnode_handle *child;
+       u32 reference, sig_path;
+       const char *node_name;
+       u32 inputs[2], scale;
+       unsigned int num_ch;
+       int chan_idx = 0;
+       int ret, i;
+
+       num_ch = device_get_child_node_count(dev);
+       if (num_ch == 0)
+               return dev_err_probe(&indio_dev->dev, -ENODEV,
+                                    "FW has no channels defined\n");
+
+       /* Reserve space for soft timestamp channel */
+       num_ch++;
+       channels = devm_kcalloc(dev, num_ch, sizeof(*channels), GFP_KERNEL);
+       if (!channels)
+               return -ENOMEM;
+
+       st->channels = devm_kcalloc(dev, num_ch, sizeof(*st->channels),
+                                   GFP_KERNEL);
+       if (!st->channels)
+               return -ENOMEM;
+
+       device_for_each_child_node(dev, child) {
+               node_name = fwnode_get_name(child);
+               if (fwnode_property_present(child, "diff-channels")) {
+                       ret = fwnode_property_read_u32_array(child,
+                                                            "diff-channels",
+                                                            inputs,
+                                                            ARRAY_SIZE(inputs));
+
+                       chanspec.differential = 1;
+               } else {
+                       ret = fwnode_property_read_u32(child, "reg", &inputs[0]);
+
+                       inputs[1] = 0;
+                       chanspec.differential = 0;
+               }
+               if (ret) {
+                       fwnode_handle_put(child);
+                       return ret;
+               }
+
+               if (inputs[0] > MAX11410_CHANNEL_INDEX_MAX ||
+                   inputs[1] > MAX11410_CHANNEL_INDEX_MAX) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(&indio_dev->dev, -EINVAL,
+                                            "Invalid channel index for %s, should be less than %d\n",
+                                            node_name,
+                                            MAX11410_CHANNEL_INDEX_MAX + 1);
+               }
+
+               cfg = &st->channels[chan_idx];
+
+               reference = MAX11410_REFSEL_AVDD_AGND;
+               fwnode_property_read_u32(child, "adi,reference", &reference);
+               if (reference > MAX11410_REFSEL_MAX) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(&indio_dev->dev, -EINVAL,
+                                            "Invalid adi,reference value for %s, should be less than %d.\n",
+                                            node_name, MAX11410_REFSEL_MAX + 1);
+               }
+
+               if (!max11410_get_vrefp(st, reference) ||
+                   (!max11410_get_vrefn(st, reference) && reference <= 2)) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(&indio_dev->dev, -EINVAL,
+                                            "Invalid VREF configuration for %s, either specify corresponding VREF regulators or change adi,reference property.\n",
+                                            node_name);
+               }
+
+               sig_path = MAX11410_PGA_SIG_PATH_BUFFERED;
+               fwnode_property_read_u32(child, "adi,input-mode", &sig_path);
+               if (sig_path > MAX11410_SIG_PATH_MAX) {
+                       fwnode_handle_put(child);
+                       return dev_err_probe(&indio_dev->dev, -EINVAL,
+                                            "Invalid adi,input-mode value for %s, should be less than %d.\n",
+                                            node_name, MAX11410_SIG_PATH_MAX + 1);
+               }
+
+               fwnode_property_read_u32(child, "settling-time-us",
+                                        &cfg->settling_time_us);
+               cfg->bipolar = fwnode_property_read_bool(child, "bipolar");
+               cfg->buffered_vrefp = fwnode_property_read_bool(child, "adi,buffered-vrefp");
+               cfg->buffered_vrefn = fwnode_property_read_bool(child, "adi,buffered-vrefn");
+               cfg->refsel = reference;
+               cfg->sig_path = sig_path;
+               cfg->gain = 0;
+
+               /* Enable scale_available property if input mode is PGA */
+               if (sig_path == MAX11410_PGA_SIG_PATH_PGA) {
+                       __set_bit(IIO_CHAN_INFO_SCALE,
+                                 &chanspec.info_mask_separate_available);
+                       cfg->scale_avail = devm_kcalloc(dev, MAX11410_SCALE_AVAIL_SIZE * 2,
+                                                       sizeof(*cfg->scale_avail),
+                                                       GFP_KERNEL);
+                       if (!cfg->scale_avail) {
+                               fwnode_handle_put(child);
+                               return -ENOMEM;
+                       }
+
+                       scale = max11410_get_scale(st, *cfg);
+                       for (i = 0; i < MAX11410_SCALE_AVAIL_SIZE; i++) {
+                               cfg->scale_avail[2 * i] = scale >> i;
+                               cfg->scale_avail[2 * i + 1] = chanspec.scan_type.realbits;
+                       }
+               } else {
+                       __clear_bit(IIO_CHAN_INFO_SCALE,
+                                   &chanspec.info_mask_separate_available);
+               }
+
+               chanspec.address = chan_idx;
+               chanspec.scan_index = chan_idx;
+               chanspec.channel = inputs[0];
+               chanspec.channel2 = inputs[1];
+
+               channels[chan_idx] = chanspec;
+               chan_idx++;
+       }
+
+       channels[chan_idx] = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(chan_idx);
+
+       indio_dev->num_channels = chan_idx + 1;
+       indio_dev->channels = channels;
+
+       return 0;
+}
+
+static void max11410_disable_reg(void *reg)
+{
+       regulator_disable(reg);
+}
+
+static int max11410_init_vref(struct device *dev,
+                             struct regulator **vref,
+                             const char *id)
+{
+       struct regulator *reg;
+       int ret;
+
+       reg = devm_regulator_get_optional(dev, id);
+       if (PTR_ERR(reg) == -ENODEV) {
+               *vref = NULL;
+               return 0;
+       } else if (IS_ERR(reg)) {
+               return PTR_ERR(reg);
+       }
+       ret = regulator_enable(reg);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "Failed to enable regulator %s\n", id);
+
+       *vref = reg;
+       return devm_add_action_or_reset(dev, max11410_disable_reg, reg);
+}
+
+static int max11410_calibrate(struct max11410_state *st, u32 cal_type)
+{
+       int ret, val;
+
+       ret = max11410_write_reg(st, MAX11410_REG_CAL_START, cal_type);
+       if (ret)
+               return ret;
+
+       /* Wait for status register Calibration Ready flag */
+       return read_poll_timeout(max11410_read_reg, ret,
+                                ret || (val & MAX11410_STATUS_CAL_READY_BIT),
+                                50000, MAX11410_CALIB_TIMEOUT_MS * 1000, true,
+                                st, MAX11410_REG_STATUS, &val);
+}
+
+static int max11410_self_calibrate(struct max11410_state *st)
+{
+       int ret, i;
+
+       ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+                               MAX11410_FILTER_RATE_MASK,
+                               FIELD_PREP(MAX11410_FILTER_RATE_MASK,
+                                          MAX11410_FILTER_RATE_MAX));
+       if (ret)
+               return ret;
+
+       ret = max11410_calibrate(st, MAX11410_CAL_START_SELF);
+       if (ret)
+               return ret;
+
+       ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+                               MAX11410_PGA_SIG_PATH_MASK,
+                               FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK,
+                                          MAX11410_PGA_SIG_PATH_PGA));
+       if (ret)
+               return ret;
+
+       /* PGA calibrations */
+       for (i = 1; i < 8; ++i) {
+               ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+                                       MAX11410_PGA_GAIN_MASK, i);
+               if (ret)
+                       return ret;
+
+               ret = max11410_calibrate(st, MAX11410_CAL_START_PGA);
+               if (ret)
+                       return ret;
+       }
+
+       /* Cleanup */
+       ret = regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+                               MAX11410_PGA_GAIN_MASK, 0);
+       if (ret)
+               return ret;
+
+       ret = regmap_write_bits(st->regmap, MAX11410_REG_FILTER,
+                               MAX11410_FILTER_RATE_MASK, 0);
+       if (ret)
+               return ret;
+
+       return regmap_write_bits(st->regmap, MAX11410_REG_PGA,
+                                MAX11410_PGA_SIG_PATH_MASK,
+                                FIELD_PREP(MAX11410_PGA_SIG_PATH_MASK,
+                                           MAX11410_PGA_SIG_PATH_BUFFERED));
+}
+
+static int max11410_probe(struct spi_device *spi)
+{
+       const char *vrefp_regs[] = { "vref0p", "vref1p", "vref2p" };
+       const char *vrefn_regs[] = { "vref0n", "vref1n", "vref2n" };
+       struct device *dev = &spi->dev;
+       struct max11410_state *st;
+       struct iio_dev *indio_dev;
+       int ret, irqs[2];
+       int i;
+
+       indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+       if (!indio_dev)
+               return -ENOMEM;
+
+       st = iio_priv(indio_dev);
+       st->spi_dev = spi;
+       init_completion(&st->completion);
+       mutex_init(&st->lock);
+
+       indio_dev->name = "max11410";
+       indio_dev->modes = INDIO_DIRECT_MODE;
+       indio_dev->info = &max11410_info;
+
+       st->regmap = devm_regmap_init_spi(spi, &regmap_config);
+       if (IS_ERR(st->regmap))
+               return dev_err_probe(dev, PTR_ERR(st->regmap),
+                                    "regmap initialization failed\n");
+
+       ret = max11410_init_vref(dev, &st->avdd, "avdd");
+       if (ret)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(vrefp_regs); i++) {
+               ret = max11410_init_vref(dev, &st->vrefp[i], vrefp_regs[i]);
+               if (ret)
+                       return ret;
+
+               ret = max11410_init_vref(dev, &st->vrefn[i], vrefn_regs[i]);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * Regulators must be configured before parsing channels for
+        * validating "adi,reference" property of each channel.
+        */
+       ret = max11410_parse_channels(st, indio_dev);
+       if (ret)
+               return ret;
+
+       irqs[0] = fwnode_irq_get_byname(dev_fwnode(dev), "gpio0");
+       irqs[1] = fwnode_irq_get_byname(dev_fwnode(dev), "gpio1");
+
+       if (irqs[0] > 0) {
+               st->irq = irqs[0];
+               ret = regmap_write(st->regmap, MAX11410_REG_GPIO_CTRL(0),
+                                  MAX11410_GPIO_INTRB);
+       } else if (irqs[1] > 0) {
+               st->irq = irqs[1];
+               ret = regmap_write(st->regmap, MAX11410_REG_GPIO_CTRL(1),
+                                  MAX11410_GPIO_INTRB);
+       } else if (spi->irq > 0) {
+               return dev_err_probe(dev, -ENODEV,
+                                    "no interrupt name specified");
+       }
+
+       if (ret)
+               return ret;
+
+       ret = regmap_set_bits(st->regmap, MAX11410_REG_CTRL,
+                             MAX11410_CTRL_FORMAT_BIT);
+       if (ret)
+               return ret;
+
+       ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+                                             &max11410_trigger_handler,
+                                             &max11410_buffer_ops);
+       if (ret)
+               return ret;
+
+       if (st->irq > 0) {
+               st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+                                                 indio_dev->name,
+                                                 iio_device_id(indio_dev));
+               if (!st->trig)
+                       return -ENOMEM;
+
+               st->trig->ops = &max11410_trigger_ops;
+               ret = devm_iio_trigger_register(dev, st->trig);
+               if (ret)
+                       return ret;
+
+               ret = devm_request_threaded_irq(dev, st->irq, NULL,
+                                               &max11410_interrupt,
+                                               IRQF_ONESHOT, "max11410",
+                                               indio_dev);
+               if (ret)
+                       return ret;
+       }
+
+       ret = max11410_self_calibrate(st);
+       if (ret)
+               return dev_err_probe(dev, ret,
+                                    "cannot perform device self calibration\n");
+
+       return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id max11410_spi_of_id[] = {
+       { .compatible = "adi,max11410" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, max11410_spi_of_id);
+
+static const struct spi_device_id max11410_id[] = {
+       { "max11410" },
+       { }
+};
+MODULE_DEVICE_TABLE(spi, max11410_id);
+
+static struct spi_driver max11410_driver = {
+       .driver = {
+               .name   = "max11410",
+               .of_match_table = max11410_spi_of_id,
+       },
+       .probe          = max11410_probe,
+       .id_table       = max11410_id,
+};
+module_spi_driver(max11410_driver);
+
+MODULE_AUTHOR("David Jung <David.Jung@analog.com>");
+MODULE_AUTHOR("Ibrahim Tilki <Ibrahim.Tilki@analog.com>");
+MODULE_DESCRIPTION("Analog Devices MAX11410 ADC");
+MODULE_LICENSE("GPL");