@@ -654,6 +654,19 @@ config MAX1118
To compile this driver as a module, choose M here: the module will be
called max1118.
+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
@@ -61,6 +61,7 @@ obj-$(CONFIG_LTC2497) += ltc2497.o ltc2497-core.o
obj-$(CONFIG_MAX1027) += max1027.o
obj-$(CONFIG_MAX11100) += max11100.o
obj-$(CONFIG_MAX1118) += max1118.o
+obj-$(CONFIG_MAX11410) += max11410.o
obj-$(CONFIG_MAX1241) += max1241.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MAX9611) += max9611.o
new file mode 100644
@@ -0,0 +1,982 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.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>
+#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>
+
+#define REG_CONV_START 0x01
+#define CONV_TYPE_SINGLE 0x00
+#define CONV_TYPE_CONTINUOUS 0x01
+#define REG_CAL_START 0x03
+#define CAL_START_SELF 0x00
+#define CAL_START_PGA 0x01
+#define REG_GP1_CTRL 0x05
+#define GP1_CTRL_INTRB 0xC1
+#define REG_FILTER 0x08
+#define FILTER_RATE_MASK GENMASK(3, 0)
+#define FILTER_LINEF_POS 0x04
+#define FILTER_LINEF_MASK GENMASK(5, 4)
+#define REG_CTRL 0x09
+#define CTRL_REFSEL_MASK GENMASK(2, 0)
+#define CTRL_VREFN_BUF_BIT BIT(3)
+#define CTRL_VREFP_BUF_BIT BIT(4)
+#define CTRL_FORMAT_BIT BIT(5)
+#define CTRL_UNIPOLAR_BIT BIT(6)
+#define REG_MUX_CTRL0 0x0B
+#define REG_PGA 0x0E
+#define PGA_GAIN_MASK GENMASK(2, 0)
+#define PGA_SIG_PATH_POS 0x04
+#define PGA_SIG_PATH_MASK GENMASK(5, 4)
+#define PGA_SIG_PATH_BUFFERED (0x00 << PGA_SIG_PATH_POS)
+#define PGA_SIG_PATH_BYPASS (0x01 << PGA_SIG_PATH_POS)
+#define PGA_SIG_PATH_PGA (0x02 << PGA_SIG_PATH_POS)
+#define REG_DATA0 0x30
+#define REG_STATUS 0x38
+#define STATUS_CONV_READY_BIT BIT(0)
+#define STATUS_CAL_READY_BIT BIT(2)
+
+#define REFSEL_AVDD_AGND 0x07
+#define REFSEL_MAX 0x07
+#define SIG_PATH_MAX 0x02
+#define CHANNEL_INDEX_MAX 0x0A
+#define AINP_AVDD 0x0A
+#define AINN_GND 0x0A
+
+#define CONVERSION_TIMEOUT_MS 2000
+#define CALIB_TIMEOUT_MS 2000
+
+enum max11410_supported_device_ids {
+ ID_MAX11410,
+};
+
+enum max11410_filter {
+ FILTER_FIR5060,
+ FILTER_FIR50,
+ FILTER_FIR60,
+ FILTER_SINC4
+};
+
+static const u8 max11410_sampling_len[] = {
+ [FILTER_FIR5060] = 5,
+ [FILTER_FIR50] = 6,
+ [FILTER_FIR60] = 6,
+ [FILTER_SINC4] = 10
+};
+
+static const int max11410_sampling_rates[4][10][2] = {
+ [FILTER_FIR5060] = {
+ {1, 100000},
+ {2, 100000},
+ {4, 200000},
+ {8, 400000},
+ {16, 800000}
+ },
+ [FILTER_FIR50] = {
+ {1, 300000},
+ {2, 700000},
+ {5, 300000},
+ {10, 700000},
+ {21, 300000},
+ {40}
+ },
+ [FILTER_FIR60] = {
+ {1, 300000},
+ {2, 700000},
+ {5, 300000},
+ {10, 700000},
+ {21, 300000},
+ {40}
+ },
+ [FILTER_SINC4] = {
+ {4},
+ {10},
+ {20},
+ {40},
+ {60},
+ {120},
+ {240},
+ {480},
+ {960},
+ {1920}
+ }
+};
+
+struct max11410_channel_config {
+ u32 settling_time_us;
+ 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 *vref0p;
+ struct regulator *vref1p;
+ struct regulator *vref2p;
+ struct regulator *vref0n;
+ struct regulator *vref1n;
+ struct regulator *vref2n;
+ struct max11410_channel_config *channels;
+};
+
+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_HARDWAREGAIN)
+ | BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 24,
+ .shift = 0,
+ .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 8bit registers */
+ if (max11410_reg_size(reg) == 1)
+ return regmap_write(st->regmap, reg, val);
+
+ return -EINVAL;
+}
+
+static int max11410_read_reg(struct max11410_state *st,
+ unsigned int reg,
+ int *val)
+{
+ u32 data;
+ int ret;
+
+ if (max11410_reg_size(reg) == 3) {
+ ret = regmap_bulk_read(st->regmap, reg, &data, 3);
+ if (!ret)
+ *val = be32_to_cpu(data << 8);
+ return ret;
+ }
+
+ return regmap_read(st->regmap, reg, val);
+}
+
+static struct regulator *max11410_get_vrefp(struct max11410_state *st, u8 refsel)
+{
+ switch (refsel % 4) {
+ case 0:
+ return st->vref0p;
+ case 1:
+ return st->vref1p;
+ case 2:
+ return st->vref2p;
+ case 3:
+ return st->avdd;
+ default:
+ return NULL;
+ }
+}
+
+static struct regulator *max11410_get_vrefn(struct max11410_state *st, u8 refsel)
+{
+ switch (refsel) {
+ case 0:
+ return st->vref0n;
+ case 1:
+ return st->vref1n;
+ case 2:
+ return st->vref2n;
+ default:
+ return NULL;
+ }
+}
+
+static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0x39
+};
+
+static int max11410_sample(struct max11410_state *st, int *sample_raw)
+{
+ int val, ret;
+
+ if (st->spi_dev->irq > 0)
+ reinit_completion(&st->completion);
+
+ /* Start Conversion */
+ ret = max11410_write_reg(st, REG_CONV_START, CONV_TYPE_SINGLE);
+ if (ret)
+ return ret;
+
+ if (st->spi_dev->irq > 0) {
+ /* Wait for interrupt. */
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(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 & STATUS_CONV_READY_BIT),
+ 5000, CONVERSION_TIMEOUT_MS * 1000, true,
+ st, REG_STATUS, &val);
+ if (ret)
+ return ret;
+ }
+
+ /* Read ADC Data */
+ return max11410_read_reg(st, REG_DATA0, sample_raw);
+}
+
+static const char * const config_filter[] = {"fir50/60", "fir50", "fir60", "sinc4"};
+
+static IIO_CONST_ATTR(filter_available, "fir50/60 fir50 fir60 sinc4");
+
+static ssize_t max11410_filter_show(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ int ret;
+ unsigned int val;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct max11410_state *state = iio_priv(indio_dev);
+
+ ret = max11410_read_reg(state, REG_FILTER, &val);
+ if (ret)
+ return ret;
+
+ val = FIELD_GET(FILTER_LINEF_MASK, val);
+
+ if (val >= ARRAY_SIZE(config_filter))
+ return -EINVAL;
+
+ return sysfs_emit(buf, "%s\n", config_filter[val]);
+}
+
+static ssize_t max11410_filter_store(struct device *dev,
+ struct device_attribute *devattr,
+ const char *buf, size_t count)
+{
+ int ret, config;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct max11410_state *state = iio_priv(indio_dev);
+
+ config = sysfs_match_string(config_filter, buf);
+ if (config < 0)
+ return -EINVAL;
+
+ ret = regmap_write_bits(state->regmap, REG_FILTER,
+ FILTER_LINEF_MASK, config << FILTER_LINEF_POS);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static IIO_DEVICE_ATTR(filter, 0644, max11410_filter_show, max11410_filter_store, 0);
+
+static struct attribute *max11410_attributes[] = {
+ &iio_dev_attr_filter.dev_attr.attr,
+ &iio_const_attr_filter_available.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 > CHANNEL_INDEX_MAX || ainn > CHANNEL_INDEX_MAX)
+ return -EINVAL;
+
+ return max11410_write_reg(st, REG_MUX_CTRL0, (ainp << 4) | ainn);
+}
+
+static int max11410_configure_channel(struct max11410_state *st,
+ struct iio_chan_spec const *chan)
+{
+ int ret;
+ struct max11410_channel_config cfg = st->channels[chan->address];
+
+ if (chan->differential)
+ ret = max11410_set_input_mux(st, chan->channel, chan->channel2);
+ else
+ ret = max11410_set_input_mux(st, chan->channel, AINN_GND);
+
+ if (ret)
+ return ret;
+
+ if (cfg.buffered_vrefp)
+ ret = regmap_set_bits(st->regmap, REG_CTRL, CTRL_VREFP_BUF_BIT);
+ else
+ ret = regmap_clear_bits(st->regmap, REG_CTRL, CTRL_VREFP_BUF_BIT);
+
+ if (ret)
+ return ret;
+
+ if (cfg.buffered_vrefn)
+ ret = regmap_set_bits(st->regmap, REG_CTRL, CTRL_VREFN_BUF_BIT);
+ else
+ ret = regmap_clear_bits(st->regmap, REG_CTRL, CTRL_VREFN_BUF_BIT);
+
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, REG_CTRL, CTRL_REFSEL_MASK, cfg.refsel);
+ if (ret)
+ return ret;
+
+ if (cfg.bipolar)
+ ret = regmap_clear_bits(st->regmap, REG_CTRL, CTRL_UNIPOLAR_BIT);
+ else
+ ret = regmap_set_bits(st->regmap, REG_CTRL, CTRL_UNIPOLAR_BIT);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, REG_PGA, PGA_SIG_PATH_MASK,
+ cfg.sig_path << PGA_SIG_PATH_POS);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, REG_PGA, PGA_GAIN_MASK, cfg.gain);
+ if (ret)
+ return ret;
+
+ if (cfg.settling_time_us)
+ fsleep(cfg.settling_time_us);
+
+ return ret;
+}
+
+static int max11410_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ int ret, reg_val, filter, rate;
+ struct regulator *vrefp, *vrefn;
+ struct max11410_state *state = iio_priv(indio_dev);
+ struct max11410_channel_config cfg = state->channels[chan->address];
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ vrefp = max11410_get_vrefp(state, cfg.refsel);
+ if (!vrefp) {
+ /* We should never get here */
+ return -ENODEV;
+ }
+
+ vrefn = max11410_get_vrefn(state, cfg.refsel);
+
+ *val = regulator_get_voltage(vrefp) / 1000;
+
+ if (vrefn)
+ *val -= regulator_get_voltage(vrefn) / 1000;
+
+ if (cfg.bipolar)
+ *val *= 2;
+
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OFFSET:
+ if (cfg.bipolar)
+ *val = -(1 << (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_configure_channel(state, chan);
+
+ if (!ret)
+ ret = max11410_sample(state, ®_val);
+
+ 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_HARDWAREGAIN:
+ *val = 1 << cfg.gain;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(state->regmap, REG_FILTER, ®_val);
+ if (ret)
+ return ret;
+
+ filter = FIELD_GET(FILTER_LINEF_MASK, reg_val);
+
+ rate = reg_val & 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 const int max11410_hwgain_list[] = {1, 2, 4, 8, 16, 32, 64, 128};
+
+static int max11410_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int i, ret, reg_val, filter;
+ struct max11410_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ for (i = 0; i < ARRAY_SIZE(max11410_hwgain_list); ++i) {
+ if (val == max11410_hwgain_list[i])
+ break;
+ }
+
+ if (i == ARRAY_SIZE(max11410_hwgain_list))
+ return -EINVAL;
+
+ st->channels[chan->address].gain = i;
+
+ return 0;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(st->regmap, REG_FILTER, ®_val);
+ if (ret)
+ return ret;
+
+ filter = FIELD_GET(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])
+ return -EINVAL;
+
+ ret = iio_device_claim_direct_mode(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, REG_FILTER, FILTER_RATE_MASK, i);
+
+ 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)
+{
+ int ret, reg_val, filter;
+ struct max11410_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_HARDWAREGAIN:
+ *type = IIO_VAL_INT;
+ *length = ARRAY_SIZE(max11410_hwgain_list);
+ *vals = max11410_hwgain_list;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = regmap_read(st->regmap, REG_FILTER, ®_val);
+ if (ret)
+ return ret;
+
+ filter = FIELD_GET(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;
+ }
+ 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);
+ struct {
+ int data;
+ s64 ts __aligned(8);
+ } scan = {0};
+ int ret;
+
+ ret = max11410_read_reg(st, REG_DATA0, &scan.data);
+ if (!ret)
+ iio_push_to_buffers_with_timestamp(indio_dev, &scan,
+ iio_get_time_ns(indio_dev));
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int max11410_buffer_postenable(struct iio_dev *indio_dev)
+{
+ int scan_ch, ret;
+ struct max11410_state *st = iio_priv(indio_dev);
+
+ /* Configure GPIO1 of MAX11410 as interrupt output. */
+ ret = max11410_write_reg(st, REG_GP1_CTRL, GP1_CTRL_INTRB);
+ if (ret)
+ return ret;
+
+ scan_ch = find_next_bit(indio_dev->active_scan_mask,
+ indio_dev->num_channels, 0);
+
+ ret = max11410_configure_channel(st, &indio_dev->channels[scan_ch]);
+ if (ret)
+ return ret;
+
+ /* Start continuous conversion. */
+ return max11410_write_reg(st, REG_CONV_START, 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, REG_CONV_START, CONV_TYPE_SINGLE);
+}
+
+static bool max11410_validate_scan_mask(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ int i;
+ unsigned int enabled_channels = 0;
+
+ for_each_set_bit(i, scan_mask, indio_dev->num_channels) {
+ ++enabled_channels;
+ }
+
+ return enabled_channels < 2;
+}
+
+static const struct iio_buffer_setup_ops max11410_buffer_ops = {
+ .postenable = &max11410_buffer_postenable,
+ .predisable = &max11410_buffer_predisable,
+ .validate_scan_mask = &max11410_validate_scan_mask
+};
+
+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 *channels;
+ struct fwnode_handle *child;
+ struct max11410_channel_config *cfg;
+ struct device *dev = &st->spi_dev->dev;
+ unsigned int num_ch;
+ u32 inputs[2];
+ u32 reference, sig_path;
+ int chan_idx = 0;
+ int ret;
+ struct iio_chan_spec chanspec = chanspec_template;
+
+ num_ch = device_get_child_node_count(dev);
+ if (num_ch == 0)
+ return dev_err_probe(&indio_dev->dev,
+ -ENODEV,
+ "no channel children\n");
+
+ /* Reserve space for soft timestamp channel */
+ num_ch += 1;
+
+ channels = devm_kzalloc(dev,
+ num_ch * sizeof(struct iio_chan_spec),
+ GFP_KERNEL);
+
+ st->channels = devm_kzalloc(dev,
+ num_ch * sizeof(struct max11410_channel_config),
+ GFP_KERNEL);
+
+ device_for_each_child_node(dev, child) {
+ if (fwnode_property_present(child, "diff-channels")) {
+ ret = fwnode_property_read_u32_array(child,
+ "diff-channels",
+ inputs, 2);
+ if (ret)
+ return ret;
+
+ chanspec.differential = 1;
+ } else {
+ inputs[1] = 0;
+ ret = fwnode_property_read_u32(child, "reg", &inputs[0]);
+ if (ret)
+ return ret;
+
+ chanspec.differential = 0;
+ }
+
+ if (inputs[0] > CHANNEL_INDEX_MAX || inputs[1] > CHANNEL_INDEX_MAX)
+ return dev_err_probe(&indio_dev->dev,
+ -EINVAL,
+ "Invalid channel index for %s, should be less than %d\n",
+ fwnode_get_name(child),
+ CHANNEL_INDEX_MAX + 1);
+
+ cfg = &st->channels[chan_idx];
+
+ ret = fwnode_property_read_u32(child, "adi,reference", &reference);
+ if (!ret) {
+ if (reference > REFSEL_MAX)
+ return dev_err_probe(&indio_dev->dev,
+ -EINVAL,
+ "Invalid adi,reference value for %s, should be less than %d.\n",
+ fwnode_get_name(child),
+ REFSEL_MAX + 1);
+
+ cfg->refsel = reference;
+ } else {
+ cfg->refsel = REFSEL_AVDD_AGND;
+ }
+
+ if (!max11410_get_vrefp(st, cfg->refsel))
+ return dev_err_probe(&indio_dev->dev,
+ -EINVAL,
+ "Invalid VREF configuration for %s, either specify corresponding VREFP regulator or change adi,reference property.\n",
+ fwnode_get_name(child));
+
+ ret = fwnode_property_read_u32(child, "adi,input-mode", &sig_path);
+ if (!ret) {
+ if (sig_path > SIG_PATH_MAX)
+ return dev_err_probe(&indio_dev->dev,
+ -EINVAL,
+ "Invalid adi,input-mode value for %s, should be less than %d.\n",
+ fwnode_get_name(child),
+ SIG_PATH_MAX + 1);
+ cfg->sig_path = sig_path;
+ }
+
+ /* Enable hardwaregain property if input mode is PGA */
+ if (sig_path == (PGA_SIG_PATH_PGA >> PGA_SIG_PATH_POS))
+ __set_bit(IIO_CHAN_INFO_HARDWAREGAIN, &chanspec.info_mask_separate);
+ else
+ __clear_bit(IIO_CHAN_INFO_HARDWAREGAIN, &chanspec.info_mask_separate);
+
+ 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");
+
+ 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)
+{
+ int ret;
+ struct regulator *reg = devm_regulator_get_optional(dev, id);
+
+ if (IS_ERR(reg)) {
+ *vref = NULL;
+ return 0;
+ }
+
+ 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, 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 & STATUS_CAL_READY_BIT),
+ 50000, CALIB_TIMEOUT_MS * 1000, true,
+ st, REG_STATUS, &val);
+}
+
+static int max11410_self_calibrate(struct max11410_state *st)
+{
+ int ret, i;
+
+ ret = regmap_write_bits(st->regmap, REG_FILTER,
+ FILTER_RATE_MASK, FILTER_RATE_MASK);
+ if (ret)
+ return ret;
+
+ ret = max11410_calibrate(st, CAL_START_SELF);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, REG_PGA,
+ PGA_SIG_PATH_MASK, PGA_SIG_PATH_PGA);
+ if (ret)
+ return ret;
+
+ /* PGA calibrations */
+ for (i = 1; i < ARRAY_SIZE(max11410_hwgain_list); ++i) {
+ ret = regmap_write_bits(st->regmap, REG_PGA, PGA_GAIN_MASK, i);
+ if (ret)
+ return ret;
+
+ ret = max11410_calibrate(st, CAL_START_PGA);
+ if (ret)
+ return ret;
+ }
+
+ /* Cleanup */
+ ret = regmap_write_bits(st->regmap, REG_PGA, PGA_GAIN_MASK, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, REG_FILTER, FILTER_RATE_MASK, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_write_bits(st->regmap, REG_PGA,
+ PGA_SIG_PATH_MASK, PGA_SIG_PATH_BUFFERED);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int max11410_probe(struct spi_device *spi)
+{
+ struct max11410_state *st;
+ struct iio_dev *indio_dev;
+ int ret = 0;
+
+ indio_dev = devm_iio_device_alloc(&spi->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 = spi_get_device_id(spi)->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &max11410_info;
+
+ st->regmap = devm_regmap_init_spi(spi, ®map_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->regmap),
+ "regmap initialization failed\n");
+
+ st->avdd = devm_regulator_get(&spi->dev, "avdd");
+ if (IS_ERR(st->avdd))
+ return dev_err_probe(&spi->dev, PTR_ERR(st->avdd),
+ "avdd-supply is required.\n");
+
+ ret = regulator_enable(st->avdd);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&spi->dev, max11410_disable_reg, st->avdd);
+ if (ret)
+ return ret;
+
+ ret = max11410_init_vref(&spi->dev, &st->vref0p, "vref0p");
+ if (ret)
+ return ret;
+
+ ret = max11410_init_vref(&spi->dev, &st->vref1p, "vref1p");
+ if (ret)
+ return ret;
+
+ ret = max11410_init_vref(&spi->dev, &st->vref2p, "vref2p");
+ if (ret)
+ return ret;
+
+ ret = max11410_init_vref(&spi->dev, &st->vref0n, "vref0n");
+ if (ret)
+ return ret;
+
+ ret = max11410_init_vref(&spi->dev, &st->vref1n, "vref1n");
+ if (ret)
+ return ret;
+
+ ret = max11410_init_vref(&spi->dev, &st->vref2n, "vref2n");
+ 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;
+
+ ret = regmap_set_bits(st->regmap, REG_CTRL, CTRL_FORMAT_BIT);
+ if (ret)
+ return ret;
+
+ if (spi->irq > 0) {
+ st->trig = devm_iio_trigger_alloc(&spi->dev, "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->trig)
+ return -ENOMEM;
+
+ ret = devm_iio_trigger_register(&spi->dev, st->trig);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ ret = devm_request_threaded_irq(&spi->dev, spi->irq,
+ NULL,
+ &max11410_interrupt,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "max11410", indio_dev);
+ if (ret)
+ return ret;
+
+ indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
+ ret = devm_iio_triggered_buffer_setup(&spi->dev, indio_dev,
+ NULL,
+ &max11410_trigger_handler,
+ &max11410_buffer_ops);
+ if (ret)
+ return ret;
+
+ ret = max11410_write_reg(st, REG_GP1_CTRL, GP1_CTRL_INTRB);
+ if (ret)
+ return ret;
+ }
+
+ ret = max11410_self_calibrate(st);
+ if (ret)
+ return dev_err_probe(&spi->dev, ret,
+ "cannot perform device self calibration\n");
+
+ return devm_iio_device_register(&spi->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", 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_SOFTDEP("pre: regmap_spi industrialio-triggered-buffer");
+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 v2");