summaryrefslogtreecommitdiff
path: root/drivers/iio/adc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/Kconfig43
-rw-r--r--drivers/iio/adc/Makefile3
-rw-r--r--drivers/iio/adc/ad4000.c2
-rw-r--r--drivers/iio/adc/ad4080.c619
-rw-r--r--drivers/iio/adc/ad4170-4.c3027
-rw-r--r--drivers/iio/adc/ad4851.c16
-rw-r--r--drivers/iio/adc/ad7091r5.c2
-rw-r--r--drivers/iio/adc/ad7091r8.c6
-rw-r--r--drivers/iio/adc/ad7124.c36
-rw-r--r--drivers/iio/adc/ad7173.c78
-rw-r--r--drivers/iio/adc/ad7380.c5
-rw-r--r--drivers/iio/adc/ad7405.c253
-rw-r--r--drivers/iio/adc/ad7476.c7
-rw-r--r--drivers/iio/adc/ad7606.c361
-rw-r--r--drivers/iio/adc/ad7606.h22
-rw-r--r--drivers/iio/adc/ad7768-1.c918
-rw-r--r--drivers/iio/adc/ad_sigma_delta.c299
-rw-r--r--drivers/iio/adc/adi-axi-adc.c96
-rw-r--r--drivers/iio/adc/at91_adc.c10
-rw-r--r--drivers/iio/adc/axp20x_adc.c2
-rw-r--r--drivers/iio/adc/dln2-adc.c4
-rw-r--r--drivers/iio/adc/hi8435.c4
-rw-r--r--drivers/iio/adc/max9611.c4
-rw-r--r--drivers/iio/adc/mp2629_adc.c2
-rw-r--r--drivers/iio/adc/mt6359-auxadc.c440
-rw-r--r--drivers/iio/adc/mt6360-adc.c3
-rw-r--r--drivers/iio/adc/qcom-vadc-common.c2
-rw-r--r--drivers/iio/adc/rockchip_saradc.c4
-rw-r--r--drivers/iio/adc/rtq6056.c4
-rw-r--r--drivers/iio/adc/stm32-adc-core.c3
-rw-r--r--drivers/iio/adc/stm32-adc.c9
-rw-r--r--drivers/iio/adc/stm32-dfsdm-adc.c1
-rw-r--r--drivers/iio/adc/stm32-dfsdm-core.c1
-rw-r--r--drivers/iio/adc/ti-ads1015.c4
-rw-r--r--drivers/iio/adc/ti-ads1119.c4
-rw-r--r--drivers/iio/adc/ti-ads131e08.c10
-rw-r--r--drivers/iio/adc/ti-lmp92064.c4
-rw-r--r--drivers/iio/adc/ti-tsc2046.c3
-rw-r--r--drivers/iio/adc/vf610_adc.c5
39 files changed, 5814 insertions, 502 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index ea3ba1397392..6de2abad0197 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -22,7 +22,9 @@ config AB8500_GPADC
config AD_SIGMA_DELTA
tristate
select IIO_BUFFER
+ select IIO_BUFFER_DMAENGINE
select IIO_TRIGGERED_BUFFER
+ select SPI_OFFLOAD
config AD4000
tristate "Analog Devices AD4000 ADC Driver"
@@ -55,6 +57,20 @@ config AD4030
To compile this driver as a module, choose M here: the module will be
called ad4030.
+config AD4080
+ tristate "Analog Devices AD4080 high speed ADC"
+ depends on SPI
+ select REGMAP_SPI
+ select IIO_BACKEND
+ help
+ Say yes here to build support for Analog Devices AD4080
+ high speed, low noise, low distortion, 20-bit, Easy Drive,
+ successive approximation register (SAR) analog-to-digital
+ converter (ADC). Supports iio_backended devices for AD4080.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad4080.
+
config AD4130
tristate "Analog Device AD4130 ADC Driver"
depends on SPI
@@ -70,6 +86,22 @@ config AD4130
To compile this driver as a module, choose M here: the module will be
called ad4130.
+
+config AD4170_4
+ tristate "Analog Device AD4170-4 ADC Driver"
+ depends on SPI
+ select REGMAP_SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ depends on COMMON_CLK
+ depends on GPIOLIB
+ help
+ Say yes here to build support for Analog Devices AD4170-4 SPI analog
+ to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad4170-4.
+
config AD4695
tristate "Analog Device AD4695 ADC Driver"
depends on SPI
@@ -252,6 +284,16 @@ config AD7380
To compile this driver as a module, choose M here: the module will be
called ad7380.
+config AD7405
+ tristate "Analog Device AD7405 ADC Driver"
+ depends on IIO_BACKEND
+ help
+ Say yes here to build support for Analog Devices AD7405, ADUM7701,
+ ADUM7702, ADUM7703 analog to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad7405.
+
config AD7476
tristate "Analog Devices AD7476 1-channel ADCs driver and other similar devices from AD and TI"
depends on SPI
@@ -330,6 +372,7 @@ config AD7766
config AD7768_1
tristate "Analog Devices AD7768-1 ADC driver"
depends on SPI
+ select REGULATOR
select REGMAP_SPI
select IIO_BUFFER
select IIO_TRIGGER
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 09ae6edb2650..1c6ca5fd4b6d 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o
obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o
obj-$(CONFIG_AD4000) += ad4000.o
obj-$(CONFIG_AD4030) += ad4030.o
+obj-$(CONFIG_AD4080) += ad4080.o
obj-$(CONFIG_AD4130) += ad4130.o
+obj-$(CONFIG_AD4170_4) += ad4170-4.o
obj-$(CONFIG_AD4695) += ad4695.o
obj-$(CONFIG_AD4851) += ad4851.o
obj-$(CONFIG_AD7091R) += ad7091r-base.o
@@ -26,6 +28,7 @@ obj-$(CONFIG_AD7291) += ad7291.o
obj-$(CONFIG_AD7292) += ad7292.o
obj-$(CONFIG_AD7298) += ad7298.o
obj-$(CONFIG_AD7380) += ad7380.o
+obj-$(CONFIG_AD7405) += ad7405.o
obj-$(CONFIG_AD7476) += ad7476.o
obj-$(CONFIG_AD7606_IFACE_PARALLEL) += ad7606_par.o
obj-$(CONFIG_AD7606_IFACE_SPI) += ad7606_spi.o
diff --git a/drivers/iio/adc/ad4000.c b/drivers/iio/adc/ad4000.c
index 5609a7845b6f..fd3d79fca785 100644
--- a/drivers/iio/adc/ad4000.c
+++ b/drivers/iio/adc/ad4000.c
@@ -554,7 +554,7 @@ static void ad4000_fill_scale_tbl(struct ad4000_state *st,
val = mult_frac(st->vref_mv, MICRO, st->gain_milli);
/* Would multiply by NANO here but we multiplied by extra MILLI */
- tmp2 = shift_right((u64)val * MICRO, scale_bits);
+ tmp2 = (u64)val * MICRO >> scale_bits;
tmp0 = div_s64_rem(tmp2, NANO, &tmp1);
/* Store scale for when span compression is disabled */
diff --git a/drivers/iio/adc/ad4080.c b/drivers/iio/adc/ad4080.c
new file mode 100644
index 000000000000..6e61787ed321
--- /dev/null
+++ b/drivers/iio/adc/ad4080.c
@@ -0,0 +1,619 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices AD4080 SPI ADC driver
+ *
+ * Copyright 2025 Analog Devices Inc.
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/iio/backend.h>
+#include <linux/iio/iio.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+
+/* Register Definition */
+#define AD4080_REG_INTERFACE_CONFIG_A 0x00
+#define AD4080_REG_INTERFACE_CONFIG_B 0x01
+#define AD4080_REG_DEVICE_CONFIG 0x02
+#define AD4080_REG_CHIP_TYPE 0x03
+#define AD4080_REG_PRODUCT_ID_L 0x04
+#define AD4080_REG_PRODUCT_ID_H 0x05
+#define AD4080_REG_CHIP_GRADE 0x06
+#define AD4080_REG_SCRATCH_PAD 0x0A
+#define AD4080_REG_SPI_REVISION 0x0B
+#define AD4080_REG_VENDOR_L 0x0C
+#define AD4080_REG_VENDOR_H 0x0D
+#define AD4080_REG_STREAM_MODE 0x0E
+#define AD4080_REG_TRANSFER_CONFIG 0x0F
+#define AD4080_REG_INTERFACE_CONFIG_C 0x10
+#define AD4080_REG_INTERFACE_STATUS_A 0x11
+#define AD4080_REG_DEVICE_STATUS 0x14
+#define AD4080_REG_ADC_DATA_INTF_CONFIG_A 0x15
+#define AD4080_REG_ADC_DATA_INTF_CONFIG_B 0x16
+#define AD4080_REG_ADC_DATA_INTF_CONFIG_C 0x17
+#define AD4080_REG_PWR_CTRL 0x18
+#define AD4080_REG_GPIO_CONFIG_A 0x19
+#define AD4080_REG_GPIO_CONFIG_B 0x1A
+#define AD4080_REG_GPIO_CONFIG_C 0x1B
+#define AD4080_REG_GENERAL_CONFIG 0x1C
+#define AD4080_REG_FIFO_WATERMARK_LSB 0x1D
+#define AD4080_REG_FIFO_WATERMARK_MSB 0x1E
+#define AD4080_REG_EVENT_HYSTERESIS_LSB 0x1F
+#define AD4080_REG_EVENT_HYSTERESIS_MSB 0x20
+#define AD4080_REG_EVENT_DETECTION_HI_LSB 0x21
+#define AD4080_REG_EVENT_DETECTION_HI_MSB 0x22
+#define AD4080_REG_EVENT_DETECTION_LO_LSB 0x23
+#define AD4080_REG_EVENT_DETECTION_LO_MSB 0x24
+#define AD4080_REG_OFFSET_LSB 0x25
+#define AD4080_REG_OFFSET_MSB 0x26
+#define AD4080_REG_GAIN_LSB 0x27
+#define AD4080_REG_GAIN_MSB 0x28
+#define AD4080_REG_FILTER_CONFIG 0x29
+
+/* AD4080_REG_INTERFACE_CONFIG_A Bit Definition */
+#define AD4080_INTERFACE_CONFIG_A_SW_RESET (BIT(7) | BIT(0))
+#define AD4080_INTERFACE_CONFIG_A_ADDR_ASC BIT(5)
+#define AD4080_INTERFACE_CONFIG_A_SDO_ENABLE BIT(4)
+
+/* AD4080_REG_INTERFACE_CONFIG_B Bit Definition */
+#define AD4080_INTERFACE_CONFIG_B_SINGLE_INST BIT(7)
+#define AD4080_INTERFACE_CONFIG_B_SHORT_INST BIT(3)
+
+/* AD4080_REG_DEVICE_CONFIG Bit Definition */
+#define AD4080_DEVICE_CONFIG_OPERATING_MODES_MSK GENMASK(1, 0)
+
+/* AD4080_REG_TRANSFER_CONFIG Bit Definition */
+#define AD4080_TRANSFER_CONFIG_KEEP_STREAM_LENGTH_VAL BIT(2)
+
+/* AD4080_REG_INTERFACE_CONFIG_C Bit Definition */
+#define AD4080_INTERFACE_CONFIG_C_STRICT_REG_ACCESS BIT(5)
+
+/* AD4080_REG_ADC_DATA_INTF_CONFIG_A Bit Definition */
+#define AD4080_ADC_DATA_INTF_CONFIG_A_RESERVED_CONFIG_A BIT(6)
+#define AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN BIT(4)
+#define AD4080_ADC_DATA_INTF_CONFIG_A_SPI_LVDS_LANES BIT(2)
+#define AD4080_ADC_DATA_INTF_CONFIG_A_DATA_INTF_MODE BIT(0)
+
+/* AD4080_REG_ADC_DATA_INTF_CONFIG_B Bit Definition */
+#define AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK GENMASK(7, 4)
+#define AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_SELF_CLK_MODE BIT(3)
+#define AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_EN BIT(0)
+
+/* AD4080_REG_ADC_DATA_INTF_CONFIG_C Bit Definition */
+#define AD4080_ADC_DATA_INTF_CONFIG_C_LVDS_VOD_MSK GENMASK(6, 4)
+
+/* AD4080_REG_PWR_CTRL Bit Definition */
+#define AD4080_PWR_CTRL_ANA_DIG_LDO_PD BIT(1)
+#define AD4080_PWR_CTRL_INTF_LDO_PD BIT(0)
+
+/* AD4080_REG_GPIO_CONFIG_A Bit Definition */
+#define AD4080_GPIO_CONFIG_A_GPO_1_EN BIT(1)
+#define AD4080_GPIO_CONFIG_A_GPO_0_EN BIT(0)
+
+/* AD4080_REG_GPIO_CONFIG_B Bit Definition */
+#define AD4080_GPIO_CONFIG_B_GPIO_1_SEL_MSK GENMASK(7, 4)
+#define AD4080_GPIO_CONFIG_B_GPIO_0_SEL_MSK GENMASK(3, 0)
+#define AD4080_GPIO_CONFIG_B_GPIO_SPI_SDO 0
+#define AD4080_GPIO_CONFIG_B_GPIO_FIFO_FULL 1
+#define AD4080_GPIO_CONFIG_B_GPIO_FIFO_READ_DONE 2
+#define AD4080_GPIO_CONFIG_B_GPIO_FILTER_RES_RDY 3
+#define AD4080_GPIO_CONFIG_B_GPIO_H_THRESH 4
+#define AD4080_GPIO_CONFIG_B_GPIO_L_THRESH 5
+#define AD4080_GPIO_CONFIG_B_GPIO_STATUS_ALERT 6
+#define AD4080_GPIO_CONFIG_B_GPIO_GPIO_DATA 7
+#define AD4080_GPIO_CONFIG_B_GPIO_FILTER_SYNC 8
+#define AD4080_GPIO_CONFIG_B_GPIO_EXTERNAL_EVENT 9
+
+/* AD4080_REG_FIFO_CONFIG Bit Definition */
+#define AD4080_FIFO_CONFIG_FIFO_MODE_MSK GENMASK(1, 0)
+
+/* AD4080_REG_FILTER_CONFIG Bit Definition */
+#define AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK GENMASK(6, 3)
+#define AD4080_FILTER_CONFIG_FILTER_SEL_MSK GENMASK(1, 0)
+
+/* Miscellaneous Definitions */
+#define AD4080_SPI_READ BIT(7)
+#define AD4080_CHIP_ID GENMASK(2, 0)
+
+#define AD4080_LVDS_CNV_CLK_CNT_MAX 7
+
+#define AD4080_MAX_SAMP_FREQ 40000000
+#define AD4080_MIN_SAMP_FREQ 1250000
+
+enum ad4080_filter_type {
+ FILTER_NONE,
+ SINC_1,
+ SINC_5,
+ SINC_5_COMP
+};
+
+static const unsigned int ad4080_scale_table[][2] = {
+ { 6000, 0 },
+};
+
+static const char *const ad4080_filter_type_iio_enum[] = {
+ [FILTER_NONE] = "none",
+ [SINC_1] = "sinc1",
+ [SINC_5] = "sinc5",
+ [SINC_5_COMP] = "sinc5+pf1",
+};
+
+static const int ad4080_dec_rate_avail[] = {
+ 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
+};
+
+static const int ad4080_dec_rate_none[] = { 1 };
+
+static const char * const ad4080_power_supplies[] = {
+ "vdd33", "vdd11", "vddldo", "iovdd", "vrefin",
+};
+
+struct ad4080_chip_info {
+ const char *name;
+ unsigned int product_id;
+ int num_scales;
+ const unsigned int (*scale_table)[2];
+ const struct iio_chan_spec *channels;
+ unsigned int num_channels;
+};
+
+struct ad4080_state {
+ struct regmap *regmap;
+ struct iio_backend *back;
+ const struct ad4080_chip_info *info;
+ /*
+ * Synchronize access to members the of driver state, and ensure
+ * atomicity of consecutive regmap operations.
+ */
+ struct mutex lock;
+ unsigned int num_lanes;
+ unsigned int dec_rate;
+ unsigned long clk_rate;
+ enum ad4080_filter_type filter_type;
+ bool lvds_cnv_en;
+};
+
+static const struct regmap_config ad4080_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+ .read_flag_mask = BIT(7),
+ .max_register = 0x29,
+};
+
+static int ad4080_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ad4080_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int ad4080_get_scale(struct ad4080_state *st, int *val, int *val2)
+{
+ unsigned int tmp;
+
+ tmp = (st->info->scale_table[0][0] * 1000000ULL) >>
+ st->info->channels[0].scan_type.realbits;
+ *val = tmp / 1000000;
+ *val2 = tmp % 1000000;
+
+ return IIO_VAL_INT_PLUS_NANO;
+}
+
+static unsigned int ad4080_get_dec_rate(struct iio_dev *dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad4080_state *st = iio_priv(dev);
+ int ret;
+ unsigned int data;
+
+ ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data);
+ if (ret)
+ return ret;
+
+ return 1 << (FIELD_GET(AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK, data) + 1);
+}
+
+static int ad4080_set_dec_rate(struct iio_dev *dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct ad4080_state *st = iio_priv(dev);
+
+ guard(mutex)(&st->lock);
+
+ if ((st->filter_type >= SINC_5 && mode >= 512) || mode < 2)
+ return -EINVAL;
+
+ return regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG,
+ AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK,
+ FIELD_PREP(AD4080_FILTER_CONFIG_SINC_DEC_RATE_MSK,
+ (ilog2(mode) - 1)));
+}
+
+static int ad4080_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long m)
+{
+ struct ad4080_state *st = iio_priv(indio_dev);
+ int dec_rate;
+
+ switch (m) {
+ case IIO_CHAN_INFO_SCALE:
+ return ad4080_get_scale(st, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ dec_rate = ad4080_get_dec_rate(indio_dev, chan);
+ if (dec_rate < 0)
+ return dec_rate;
+ if (st->filter_type == SINC_5_COMP)
+ dec_rate *= 2;
+ if (st->filter_type)
+ *val = DIV_ROUND_CLOSEST(st->clk_rate, dec_rate);
+ else
+ *val = st->clk_rate;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ if (st->filter_type == FILTER_NONE) {
+ *val = 1;
+ } else {
+ *val = ad4080_get_dec_rate(indio_dev, chan);
+ if (*val < 0)
+ return *val;
+ }
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4080_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct ad4080_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ if (st->filter_type == FILTER_NONE && val > 1)
+ return -EINVAL;
+
+ return ad4080_set_dec_rate(indio_dev, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4080_lvds_sync_write(struct ad4080_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+ int ret;
+
+ ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
+ AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN);
+ if (ret)
+ return ret;
+
+ ret = iio_backend_interface_data_align(st->back, 10000);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Data alignment process failed\n");
+
+ dev_dbg(dev, "Success: Pattern correct and Locked!\n");
+ return regmap_clear_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
+ AD4080_ADC_DATA_INTF_CONFIG_A_INTF_CHK_EN);
+}
+
+static int ad4080_get_filter_type(struct iio_dev *dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad4080_state *st = iio_priv(dev);
+ unsigned int data;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD4080_REG_FILTER_CONFIG, &data);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(AD4080_FILTER_CONFIG_FILTER_SEL_MSK, data);
+}
+
+static int ad4080_set_filter_type(struct iio_dev *dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct ad4080_state *st = iio_priv(dev);
+ int dec_rate;
+ int ret;
+
+ guard(mutex)(&st->lock);
+
+ dec_rate = ad4080_get_dec_rate(dev, chan);
+ if (dec_rate < 0)
+ return dec_rate;
+
+ if (mode >= SINC_5 && dec_rate >= 512)
+ return -EINVAL;
+
+ ret = iio_backend_filter_type_set(st->back, mode);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4080_REG_FILTER_CONFIG,
+ AD4080_FILTER_CONFIG_FILTER_SEL_MSK,
+ FIELD_PREP(AD4080_FILTER_CONFIG_FILTER_SEL_MSK,
+ mode));
+ if (ret)
+ return ret;
+
+ st->filter_type = mode;
+
+ return 0;
+}
+
+static int ad4080_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long mask)
+{
+ struct ad4080_state *st = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ switch (st->filter_type) {
+ case FILTER_NONE:
+ *vals = ad4080_dec_rate_none;
+ *length = ARRAY_SIZE(ad4080_dec_rate_none);
+ break;
+ default:
+ *vals = ad4080_dec_rate_avail;
+ *length = st->filter_type >= SINC_5 ?
+ (ARRAY_SIZE(ad4080_dec_rate_avail) - 2) :
+ ARRAY_SIZE(ad4080_dec_rate_avail);
+ break;
+ }
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ad4080_iio_info = {
+ .debugfs_reg_access = ad4080_reg_access,
+ .read_raw = ad4080_read_raw,
+ .write_raw = ad4080_write_raw,
+ .read_avail = ad4080_read_avail,
+};
+
+static const struct iio_enum ad4080_filter_type_enum = {
+ .items = ad4080_filter_type_iio_enum,
+ .num_items = ARRAY_SIZE(ad4080_filter_type_iio_enum),
+ .set = ad4080_set_filter_type,
+ .get = ad4080_get_filter_type,
+};
+
+static struct iio_chan_spec_ext_info ad4080_ext_info[] = {
+ IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad4080_filter_type_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL,
+ &ad4080_filter_type_enum),
+ { }
+};
+
+static const struct iio_chan_spec ad4080_channel = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .ext_info = ad4080_ext_info,
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 20,
+ .storagebits = 32,
+ },
+};
+
+static const struct ad4080_chip_info ad4080_chip_info = {
+ .name = "ad4080",
+ .product_id = AD4080_CHIP_ID,
+ .scale_table = ad4080_scale_table,
+ .num_scales = ARRAY_SIZE(ad4080_scale_table),
+ .num_channels = 1,
+ .channels = &ad4080_channel,
+};
+
+static int ad4080_setup(struct iio_dev *indio_dev)
+{
+ struct ad4080_state *st = iio_priv(indio_dev);
+ struct device *dev = regmap_get_device(st->regmap);
+ unsigned int id;
+ int ret;
+
+ ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A,
+ AD4080_INTERFACE_CONFIG_A_SW_RESET);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4080_REG_INTERFACE_CONFIG_A,
+ AD4080_INTERFACE_CONFIG_A_SDO_ENABLE);
+ if (ret)
+ return ret;
+
+ ret = regmap_read(st->regmap, AD4080_REG_CHIP_TYPE, &id);
+ if (ret)
+ return ret;
+
+ if (id != AD4080_CHIP_ID)
+ dev_info(dev, "Unrecognized CHIP_ID 0x%X\n", id);
+
+ ret = regmap_set_bits(st->regmap, AD4080_REG_GPIO_CONFIG_A,
+ AD4080_GPIO_CONFIG_A_GPO_1_EN);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4080_REG_GPIO_CONFIG_B,
+ FIELD_PREP(AD4080_GPIO_CONFIG_B_GPIO_1_SEL_MSK,
+ AD4080_GPIO_CONFIG_B_GPIO_FILTER_RES_RDY));
+ if (ret)
+ return ret;
+
+ ret = iio_backend_num_lanes_set(st->back, st->num_lanes);
+ if (ret)
+ return ret;
+
+ if (!st->lvds_cnv_en)
+ return 0;
+
+ /* Set maximum LVDS Data Transfer Latency */
+ ret = regmap_update_bits(st->regmap,
+ AD4080_REG_ADC_DATA_INTF_CONFIG_B,
+ AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
+ FIELD_PREP(AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_CLK_CNT_MSK,
+ AD4080_LVDS_CNV_CLK_CNT_MAX));
+ if (ret)
+ return ret;
+
+ if (st->num_lanes > 1) {
+ ret = regmap_set_bits(st->regmap, AD4080_REG_ADC_DATA_INTF_CONFIG_A,
+ AD4080_ADC_DATA_INTF_CONFIG_A_SPI_LVDS_LANES);
+ if (ret)
+ return ret;
+ }
+
+ ret = regmap_set_bits(st->regmap,
+ AD4080_REG_ADC_DATA_INTF_CONFIG_B,
+ AD4080_ADC_DATA_INTF_CONFIG_B_LVDS_CNV_EN);
+ if (ret)
+ return ret;
+
+ return ad4080_lvds_sync_write(st);
+}
+
+static int ad4080_properties_parse(struct ad4080_state *st)
+{
+ struct device *dev = regmap_get_device(st->regmap);
+
+ st->lvds_cnv_en = device_property_read_bool(dev, "adi,lvds-cnv-enable");
+
+ st->num_lanes = 1;
+ device_property_read_u32(dev, "adi,num-lanes", &st->num_lanes);
+ if (!st->num_lanes || st->num_lanes > 2)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid 'adi,num-lanes' value: %u",
+ st->num_lanes);
+
+ return 0;
+}
+
+static int ad4080_probe(struct spi_device *spi)
+{
+ struct iio_dev *indio_dev;
+ struct device *dev = &spi->dev;
+ struct ad4080_state *st;
+ struct clk *clk;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ ret = devm_regulator_bulk_get_enable(dev,
+ ARRAY_SIZE(ad4080_power_supplies),
+ ad4080_power_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to get and enable supplies\n");
+
+ st->regmap = devm_regmap_init_spi(spi, &ad4080_regmap_config);
+ if (IS_ERR(st->regmap))
+ return PTR_ERR(st->regmap);
+
+ st->info = spi_get_device_match_data(spi);
+ if (!st->info)
+ return -ENODEV;
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ indio_dev->name = st->info->name;
+ indio_dev->channels = st->info->channels;
+ indio_dev->num_channels = st->info->num_channels;
+ indio_dev->info = &ad4080_iio_info;
+
+ ret = ad4080_properties_parse(st);
+ if (ret)
+ return ret;
+
+ clk = devm_clk_get_enabled(&spi->dev, "cnv");
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ st->clk_rate = clk_get_rate(clk);
+
+ st->back = devm_iio_backend_get(dev, NULL);
+ if (IS_ERR(st->back))
+ return PTR_ERR(st->back);
+
+ ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_backend_enable(dev, st->back);
+ if (ret)
+ return ret;
+
+ ret = ad4080_setup(indio_dev);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const struct spi_device_id ad4080_id[] = {
+ { "ad4080", (kernel_ulong_t)&ad4080_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad4080_id);
+
+static const struct of_device_id ad4080_of_match[] = {
+ { .compatible = "adi,ad4080", &ad4080_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad4080_of_match);
+
+static struct spi_driver ad4080_driver = {
+ .driver = {
+ .name = "ad4080",
+ .of_match_table = ad4080_of_match,
+ },
+ .probe = ad4080_probe,
+ .id_table = ad4080_id,
+};
+module_spi_driver(ad4080_driver);
+
+MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com");
+MODULE_DESCRIPTION("Analog Devices AD4080");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_BACKEND");
diff --git a/drivers/iio/adc/ad4170-4.c b/drivers/iio/adc/ad4170-4.c
new file mode 100644
index 000000000000..6cd84d6fb08b
--- /dev/null
+++ b/drivers/iio/adc/ad4170-4.c
@@ -0,0 +1,3027 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Analog Devices AD4170-4 ADC driver
+ *
+ * Copyright (C) 2025 Analog Devices, Inc.
+ * Author: Ana-Maria Cusco <ana-maria.cusco@analog.com>
+ * Author: Marcelo Schmitt <marcelo.schmitt@analog.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+#include <linux/util_macros.h>
+
+/*
+ * AD4170 registers
+ * Multibyte register addresses point to the most significant byte which is the
+ * address to use to get the most significant byte first (address accessed is
+ * decremented by one for each data byte)
+ *
+ * Each register address define follows the AD4170_<REG_NAME>_REG format.
+ * Each mask follows the AD4170_<REG_NAME>_<FIELD_NAME> format.
+ * E.g. AD4170_PIN_MUXING_DIG_AUX1_CTRL_MSK is for accessing DIG_AUX1_CTRL field
+ * of PIN_MUXING_REG.
+ * Each constant follows the AD4170_<REG_NAME>_<FIELD_NAME>_<FUNCTION> format.
+ * E.g. AD4170_PIN_MUXING_DIG_AUX1_DISABLED is the value written to
+ * DIG_AUX1_CTRL field of PIN_MUXING register to disable DIG_AUX1 pin.
+ * Some register names and register field names are shortened versions of
+ * their datasheet counterpart names to provide better code readability.
+ */
+#define AD4170_CONFIG_A_REG 0x00
+#define AD4170_DATA_24B_REG 0x1E
+#define AD4170_PIN_MUXING_REG 0x69
+#define AD4170_CLOCK_CTRL_REG 0x6B
+#define AD4170_ADC_CTRL_REG 0x71
+#define AD4170_CHAN_EN_REG 0x79
+#define AD4170_CHAN_SETUP_REG(x) (0x81 + 4 * (x))
+#define AD4170_CHAN_MAP_REG(x) (0x83 + 4 * (x))
+#define AD4170_MISC_REG(x) (0xC1 + 14 * (x))
+#define AD4170_AFE_REG(x) (0xC3 + 14 * (x))
+#define AD4170_FILTER_REG(x) (0xC5 + 14 * (x))
+#define AD4170_FILTER_FS_REG(x) (0xC7 + 14 * (x))
+#define AD4170_OFFSET_REG(x) (0xCA + 14 * (x))
+#define AD4170_GAIN_REG(x) (0xCD + 14 * (x))
+#define AD4170_V_BIAS_REG 0x135
+#define AD4170_CURRENT_SRC_REG(x) (0x139 + 2 * (x))
+#define AD4170_GPIO_MODE_REG 0x191
+#define AD4170_GPIO_OUTPUT_REG 0x193
+#define AD4170_GPIO_INPUT_REG 0x195
+#define AD4170_ADC_CTRL_CONT_READ_EXIT_REG 0x200 /* virtual reg */
+
+#define AD4170_REG_READ_MASK BIT(14)
+
+/* AD4170_CONFIG_A_REG - INTERFACE_CONFIG_A REGISTER */
+#define AD4170_SW_RESET_MSK (BIT(7) | BIT(0))
+
+/* AD4170_PIN_MUXING_REG */
+#define AD4170_PIN_MUXING_DIG_AUX1_CTRL_MSK GENMASK(5, 4)
+
+/* AD4170_CLOCK_CTRL_REG */
+#define AD4170_CLOCK_CTRL_CLOCKSEL_MSK GENMASK(1, 0)
+
+/* AD4170_ADC_CTRL_REG */
+#define AD4170_ADC_CTRL_MULTI_DATA_REG_SEL_MSK BIT(7)
+#define AD4170_ADC_CTRL_CONT_READ_MSK GENMASK(5, 4)
+#define AD4170_ADC_CTRL_MODE_MSK GENMASK(3, 0)
+
+/* AD4170_CHAN_EN_REG */
+#define AD4170_CHAN_EN(ch) BIT(ch)
+
+/* AD4170_CHAN_SETUP_REG */
+#define AD4170_CHAN_SETUP_SETUP_MSK GENMASK(2, 0)
+
+/* AD4170_CHAN_MAP_REG */
+#define AD4170_CHAN_MAP_AINP_MSK GENMASK(12, 8)
+#define AD4170_CHAN_MAP_AINM_MSK GENMASK(4, 0)
+
+/* AD4170_MISC_REG */
+#define AD4170_MISC_CHOP_IEXC_MSK GENMASK(15, 14)
+#define AD4170_MISC_CHOP_ADC_MSK GENMASK(9, 8)
+
+/* AD4170_AFE_REG */
+#define AD4170_AFE_REF_BUF_M_MSK GENMASK(11, 10)
+#define AD4170_AFE_REF_BUF_P_MSK GENMASK(9, 8)
+#define AD4170_AFE_REF_SELECT_MSK GENMASK(6, 5)
+#define AD4170_AFE_BIPOLAR_MSK BIT(4)
+#define AD4170_AFE_PGA_GAIN_MSK GENMASK(3, 0)
+
+/* AD4170_FILTER_REG */
+#define AD4170_FILTER_FILTER_TYPE_MSK GENMASK(3, 0)
+
+/* AD4170_CURRENT_SRC_REG */
+#define AD4170_CURRENT_SRC_I_OUT_PIN_MSK GENMASK(12, 8)
+#define AD4170_CURRENT_SRC_I_OUT_VAL_MSK GENMASK(2, 0)
+
+/* AD4170_GPIO_MODE_REG */
+#define AD4170_GPIO_MODE_GPIO0_MSK GENMASK(1, 0)
+#define AD4170_GPIO_MODE_GPIO1_MSK GENMASK(3, 2)
+#define AD4170_GPIO_MODE_GPIO2_MSK GENMASK(5, 4)
+#define AD4170_GPIO_MODE_GPIO3_MSK GENMASK(7, 6)
+
+/* AD4170_GPIO_OUTPUT_REG */
+#define AD4170_GPIO_OUTPUT_GPIO_MSK(x) BIT(x)
+
+/* AD4170 register constants */
+
+/* AD4170_CLOCK_CTRL_REG constants */
+#define AD4170_CLOCK_CTRL_CLOCKSEL_INT 0x0
+#define AD4170_CLOCK_CTRL_CLOCKSEL_INT_OUT 0x1
+#define AD4170_CLOCK_CTRL_CLOCKSEL_EXT 0x2
+#define AD4170_CLOCK_CTRL_CLOCKSEL_EXT_XTAL 0x3
+
+/* AD4170_CHAN_MAP_REG constants */
+#define AD4170_CHAN_MAP_AIN(x) (x)
+#define AD4170_CHAN_MAP_TEMP_SENSOR 17
+#define AD4170_CHAN_MAP_AVDD_AVSS_P 18
+#define AD4170_CHAN_MAP_AVDD_AVSS_N 18
+#define AD4170_CHAN_MAP_IOVDD_DGND_P 19
+#define AD4170_CHAN_MAP_IOVDD_DGND_N 19
+#define AD4170_CHAN_MAP_AVSS 23
+#define AD4170_CHAN_MAP_DGND 24
+#define AD4170_CHAN_MAP_REFIN1_P 25
+#define AD4170_CHAN_MAP_REFIN1_N 26
+#define AD4170_CHAN_MAP_REFIN2_P 27
+#define AD4170_CHAN_MAP_REFIN2_N 28
+#define AD4170_CHAN_MAP_REFOUT 29
+
+/* AD4170_MISC_REG constants */
+#define AD4170_MISC_CHOP_IEXC_PAIR1 0x1
+#define AD4170_MISC_CHOP_IEXC_PAIR2 0x2
+#define AD4170_MISC_CHOP_IEXC_BOTH 0x3
+
+/* AD4170_PIN_MUXING_REG constants */
+#define AD4170_PIN_MUXING_DIG_AUX1_DISABLED 0x0
+#define AD4170_PIN_MUXING_DIG_AUX1_RDY 0x1
+
+/* AD4170_ADC_CTRL_REG constants */
+#define AD4170_ADC_CTRL_MODE_CONT 0x0
+#define AD4170_ADC_CTRL_MODE_SINGLE 0x4
+#define AD4170_ADC_CTRL_MODE_IDLE 0x7
+
+#define AD4170_ADC_CTRL_CONT_READ_DISABLE 0x0
+#define AD4170_ADC_CTRL_CONT_READ_ENABLE 0x1
+
+/* AD4170_FILTER_REG constants */
+#define AD4170_FILTER_FILTER_TYPE_SINC5_AVG 0x0
+#define AD4170_FILTER_FILTER_TYPE_SINC5 0x4
+#define AD4170_FILTER_FILTER_TYPE_SINC3 0x6
+
+/* AD4170_CURRENT_SRC_REG constants */
+#define AD4170_CURRENT_SRC_I_OUT_PIN_AIN(x) (x)
+#define AD4170_CURRENT_SRC_I_OUT_PIN_GPIO(x) ((x) + 17)
+
+/* AD4170_GPIO_MODE_REG constants */
+#define AD4170_GPIO_MODE_GPIO_INPUT 1
+#define AD4170_GPIO_MODE_GPIO_OUTPUT 2
+
+/* Device properties and auxiliary constants */
+
+#define AD4170_NUM_ANALOG_PINS 9
+#define AD4170_NUM_GPIO_PINS 4
+#define AD4170_MAX_ADC_CHANNELS 16
+#define AD4170_MAX_IIO_CHANNELS (AD4170_MAX_ADC_CHANNELS + 1)
+#define AD4170_MAX_ANALOG_PINS 8
+#define AD4170_MAX_SETUPS 8
+#define AD4170_INVALID_SETUP 9
+#define AD4170_SPI_INST_PHASE_LEN 2
+#define AD4170_SPI_MAX_XFER_LEN 6
+#define AD4170_NUM_CURRENT_SRC 4
+#define AD4170_DEFAULT_SAMP_RATE (125 * HZ_PER_KHZ)
+
+#define AD4170_INT_REF_2_5V 2500000
+
+/* Internal and external clock properties */
+#define AD4170_INT_CLOCK_16MHZ (16 * HZ_PER_MHZ)
+#define AD4170_EXT_CLOCK_MHZ_MIN (1 * HZ_PER_MHZ)
+#define AD4170_EXT_CLOCK_MHZ_MAX (17 * HZ_PER_MHZ)
+
+#define AD4170_NUM_PGA_OPTIONS 10
+
+/* Digital filter properties */
+#define AD4170_SINC3_MIN_FS 4
+#define AD4170_SINC3_MAX_FS 65532
+#define AD4170_SINC5_MIN_FS 1
+#define AD4170_SINC5_MAX_FS 256
+
+#define AD4170_GAIN_REG_DEFAULT 0x555555
+
+#define AD4170_ADC_CTRL_CONT_READ_EXIT 0xA5
+
+/* Analog pin functions */
+#define AD4170_PIN_UNASSIGNED 0x00
+#define AD4170_PIN_ANALOG_IN 0x01
+#define AD4170_PIN_CURRENT_OUT 0x02
+#define AD4170_PIN_VBIAS 0x04
+
+/* GPIO pin functions */
+#define AD4170_GPIO_UNASSIGNED 0x00
+#define AD4170_GPIO_AC_EXCITATION 0x02
+#define AD4170_GPIO_OUTPUT 0x04
+
+/* Current source */
+#define AD4170_CURRENT_SRC_DISABLED 0xFF
+
+static const unsigned int ad4170_reg_size[] = {
+ [AD4170_CONFIG_A_REG] = 1,
+ [AD4170_DATA_24B_REG] = 3,
+ [AD4170_PIN_MUXING_REG] = 2,
+ [AD4170_CLOCK_CTRL_REG] = 2,
+ [AD4170_ADC_CTRL_REG] = 2,
+ [AD4170_CHAN_EN_REG] = 2,
+ /*
+ * CHANNEL_SETUP and CHANNEL_MAP register are all 2 byte size each and
+ * their addresses are interleaved such that we have CHANNEL_SETUP0
+ * address followed by CHANNEL_MAP0 address, followed by CHANNEL_SETUP1,
+ * and so on until CHANNEL_MAP15.
+ * Thus, initialize the register size for them only once.
+ */
+ [AD4170_CHAN_SETUP_REG(0) ... AD4170_CHAN_MAP_REG(AD4170_MAX_ADC_CHANNELS - 1)] = 2,
+ /*
+ * MISC, AFE, FILTER, FILTER_FS, OFFSET, and GAIN register addresses are
+ * also interleaved but MISC, AFE, FILTER, FILTER_FS, OFFSET are 16-bit
+ * while OFFSET, GAIN are 24-bit registers so we can't init them all to
+ * the same size.
+ */
+ [AD4170_MISC_REG(0) ... AD4170_FILTER_FS_REG(0)] = 2,
+ [AD4170_MISC_REG(1) ... AD4170_FILTER_FS_REG(1)] = 2,
+ [AD4170_MISC_REG(2) ... AD4170_FILTER_FS_REG(2)] = 2,
+ [AD4170_MISC_REG(3) ... AD4170_FILTER_FS_REG(3)] = 2,
+ [AD4170_MISC_REG(4) ... AD4170_FILTER_FS_REG(4)] = 2,
+ [AD4170_MISC_REG(5) ... AD4170_FILTER_FS_REG(5)] = 2,
+ [AD4170_MISC_REG(6) ... AD4170_FILTER_FS_REG(6)] = 2,
+ [AD4170_MISC_REG(7) ... AD4170_FILTER_FS_REG(7)] = 2,
+ [AD4170_OFFSET_REG(0) ... AD4170_GAIN_REG(0)] = 3,
+ [AD4170_OFFSET_REG(1) ... AD4170_GAIN_REG(1)] = 3,
+ [AD4170_OFFSET_REG(2) ... AD4170_GAIN_REG(2)] = 3,
+ [AD4170_OFFSET_REG(3) ... AD4170_GAIN_REG(3)] = 3,
+ [AD4170_OFFSET_REG(4) ... AD4170_GAIN_REG(4)] = 3,
+ [AD4170_OFFSET_REG(5) ... AD4170_GAIN_REG(5)] = 3,
+ [AD4170_OFFSET_REG(6) ... AD4170_GAIN_REG(6)] = 3,
+ [AD4170_OFFSET_REG(7) ... AD4170_GAIN_REG(7)] = 3,
+ [AD4170_V_BIAS_REG] = 2,
+ [AD4170_CURRENT_SRC_REG(0) ... AD4170_CURRENT_SRC_REG(3)] = 2,
+ [AD4170_GPIO_MODE_REG] = 2,
+ [AD4170_GPIO_OUTPUT_REG] = 2,
+ [AD4170_GPIO_INPUT_REG] = 2,
+ [AD4170_ADC_CTRL_CONT_READ_EXIT_REG] = 0,
+};
+
+enum ad4170_ref_buf {
+ AD4170_REF_BUF_PRE, /* Pre-charge referrence buffer */
+ AD4170_REF_BUF_FULL, /* Full referrence buffering */
+ AD4170_REF_BUF_BYPASS, /* Bypass referrence buffering */
+};
+
+/* maps adi,positive/negative-reference-buffer property values to enum */
+static const char * const ad4170_ref_buf_str[] = {
+ [AD4170_REF_BUF_PRE] = "precharge",
+ [AD4170_REF_BUF_FULL] = "full",
+ [AD4170_REF_BUF_BYPASS] = "disabled",
+};
+
+enum ad4170_ref_select {
+ AD4170_REF_REFIN1,
+ AD4170_REF_REFIN2,
+ AD4170_REF_REFOUT,
+ AD4170_REF_AVDD,
+};
+
+enum ad4170_filter_type {
+ AD4170_SINC5_AVG,
+ AD4170_SINC5,
+ AD4170_SINC3,
+};
+
+enum ad4170_regulator {
+ AD4170_AVDD_SUP,
+ AD4170_AVSS_SUP,
+ AD4170_IOVDD_SUP,
+ AD4170_REFIN1P_SUP,
+ AD4170_REFIN1N_SUP,
+ AD4170_REFIN2P_SUP,
+ AD4170_REFIN2N_SUP,
+ AD4170_MAX_SUP,
+};
+
+static const char *const ad4170_clk_sel[] = {
+ "ext-clk", "xtal",
+};
+
+enum ad4170_int_pin_sel {
+ AD4170_INT_PIN_SDO,
+ AD4170_INT_PIN_DIG_AUX1,
+};
+
+static const char * const ad4170_int_pin_names[] = {
+ [AD4170_INT_PIN_SDO] = "sdo",
+ [AD4170_INT_PIN_DIG_AUX1] = "dig_aux1",
+};
+
+static const unsigned int ad4170_sinc3_filt_fs_tbl[] = {
+ 4, 8, 12, 16, 20, 40, 48, 80, /* 0 - 7 */
+ 100, 256, 500, 1000, 5000, 8332, 10000, 25000, /* 8 - 15 */
+ 50000, 65532, /* 16 - 17 */
+};
+
+#define AD4170_MAX_FS_TBL_SIZE ARRAY_SIZE(ad4170_sinc3_filt_fs_tbl)
+
+static const unsigned int ad4170_sinc5_filt_fs_tbl[] = {
+ 1, 2, 4, 8, 12, 16, 20, 40, 48, 80, 100, 256,
+};
+
+static const unsigned int ad4170_iout_pin_tbl[] = {
+ AD4170_CURRENT_SRC_I_OUT_PIN_AIN(0),
+ AD4170_CURRENT_SRC_I_OUT_PIN_AIN(1),
+ AD4170_CURRENT_SRC_I_OUT_PIN_AIN(2),
+ AD4170_CURRENT_SRC_I_OUT_PIN_AIN(3),
+ AD4170_CURRENT_SRC_I_OUT_PIN_AIN(4),
+ AD4170_CURRENT_SRC_I_OUT_PIN_AIN(5),
+ AD4170_CURRENT_SRC_I_OUT_PIN_AIN(6),
+ AD4170_CURRENT_SRC_I_OUT_PIN_AIN(7),
+ AD4170_CURRENT_SRC_I_OUT_PIN_AIN(8),
+ AD4170_CURRENT_SRC_I_OUT_PIN_GPIO(0),
+ AD4170_CURRENT_SRC_I_OUT_PIN_GPIO(1),
+ AD4170_CURRENT_SRC_I_OUT_PIN_GPIO(2),
+ AD4170_CURRENT_SRC_I_OUT_PIN_GPIO(3),
+};
+
+static const unsigned int ad4170_iout_current_ua_tbl[] = {
+ 0, 10, 50, 100, 250, 500, 1000, 1500,
+};
+
+enum ad4170_sensor_enum {
+ AD4170_ADC_SENSOR = 0,
+ AD4170_WEIGH_SCALE_SENSOR = 1,
+ AD4170_RTD_SENSOR = 2,
+ AD4170_THERMOCOUPLE_SENSOR = 3,
+};
+
+/* maps adi,sensor-type property value to enum */
+static const char * const ad4170_sensor_type[] = {
+ [AD4170_ADC_SENSOR] = "adc",
+ [AD4170_WEIGH_SCALE_SENSOR] = "weighscale",
+ [AD4170_RTD_SENSOR] = "rtd",
+ [AD4170_THERMOCOUPLE_SENSOR] = "thermocouple",
+};
+
+struct ad4170_chip_info {
+ const char *name;
+};
+
+static const struct ad4170_chip_info ad4170_chip_info = {
+ .name = "ad4170-4",
+};
+
+static const struct ad4170_chip_info ad4190_chip_info = {
+ .name = "ad4190-4",
+};
+
+static const struct ad4170_chip_info ad4195_chip_info = {
+ .name = "ad4195-4",
+};
+
+/*
+ * There are 8 of each MISC, AFE, FILTER, FILTER_FS, OFFSET, and GAIN
+ * configuration registers. That is, there are 8 miscellaneous registers, MISC0
+ * to MISC7. Each MISC register is associated with a setup; MISCN is associated
+ * with setup number N. The other 5 above mentioned types of registers have
+ * analogous structure. A setup is a set of those registers. For example,
+ * setup 1 comprises of MISC1, AFE1, FILTER1, FILTER_FS1, OFFSET1, and GAIN1
+ * registers. Also, there are 16 CHANNEL_SETUP registers (CHANNEL_SETUP0 to
+ * CHANNEL_SETUP15). Each channel setup is associated with one of the 8 possible
+ * setups. Thus, AD4170 can support up to 16 channels but, since there are only
+ * 8 available setups, channels must share settings if more than 8 channels are
+ * configured.
+ *
+ * If this struct is modified, ad4170_setup_eq() will probably need to be
+ * updated too.
+ */
+struct ad4170_setup {
+ u16 misc;
+ u16 afe;
+ u16 filter;
+ u16 filter_fs;
+ u32 offset; /* For calibration purposes */
+ u32 gain; /* For calibration purposes */
+};
+
+struct ad4170_setup_info {
+ struct ad4170_setup setup;
+ unsigned int enabled_channels;
+ unsigned int channels;
+};
+
+struct ad4170_chan_info {
+ unsigned int input_range_uv;
+ unsigned int setup_num; /* Index to access state setup_infos array */
+ struct ad4170_setup setup; /* cached setup */
+ int offset_tbl[10];
+ u32 scale_tbl[10][2];
+ bool initialized;
+ bool enabled;
+};
+
+static const char * const ad4170_filt_names[] = {
+ [AD4170_SINC5_AVG] = "sinc5+avg",
+ [AD4170_SINC5] = "sinc5",
+ [AD4170_SINC3] = "sinc3",
+};
+
+struct ad4170_state {
+ struct mutex lock; /* Protect read-modify-write and multi write sequences */
+ int vrefs_uv[AD4170_MAX_SUP];
+ u32 mclk_hz;
+ struct ad4170_setup_info setup_infos[AD4170_MAX_SETUPS];
+ struct ad4170_chan_info chan_infos[AD4170_MAX_ADC_CHANNELS];
+ struct completion completion;
+ struct iio_chan_spec chans[AD4170_MAX_IIO_CHANNELS];
+ struct spi_device *spi;
+ struct regmap *regmap;
+ int sps_tbl[ARRAY_SIZE(ad4170_filt_names)][AD4170_MAX_FS_TBL_SIZE][2];
+ __be32 bounce_buffer[AD4170_MAX_ADC_CHANNELS];
+ struct spi_message msg;
+ struct spi_transfer xfer;
+ struct iio_trigger *trig;
+ struct clk_hw int_clk_hw;
+ unsigned int clock_ctrl;
+ unsigned int pins_fn[AD4170_NUM_ANALOG_PINS];
+ int gpio_fn[AD4170_NUM_GPIO_PINS];
+ unsigned int cur_src_pins[AD4170_NUM_CURRENT_SRC];
+ struct gpio_chip gpiochip;
+ /*
+ * DMA (thus cache coherency maintenance) requires the transfer buffers
+ * to live in their own cache lines.
+ */
+ u8 rx_buf[4] __aligned(IIO_DMA_MINALIGN);
+};
+
+static void ad4170_fill_sps_tbl(struct ad4170_state *st)
+{
+ unsigned int tmp0, tmp1, i;
+
+ /*
+ * The ODR can be calculated the same way for sinc5+avg, sinc5, and
+ * sinc3 filter types with the exception that sinc5 filter has a
+ * narrowed range of allowed FILTER_FS values.
+ */
+ for (i = 0; i < ARRAY_SIZE(ad4170_sinc3_filt_fs_tbl); i++) {
+ tmp0 = div_u64_rem(st->mclk_hz, 32 * ad4170_sinc3_filt_fs_tbl[i],
+ &tmp1);
+ tmp1 = mult_frac(tmp1, MICRO, 32 * ad4170_sinc3_filt_fs_tbl[i]);
+ /* Fill sinc5+avg filter SPS table */
+ st->sps_tbl[AD4170_SINC5_AVG][i][0] = tmp0; /* Integer part */
+ st->sps_tbl[AD4170_SINC5_AVG][i][1] = tmp1; /* Fractional part */
+
+ /* Fill sinc3 filter SPS table */
+ st->sps_tbl[AD4170_SINC3][i][0] = tmp0; /* Integer part */
+ st->sps_tbl[AD4170_SINC3][i][1] = tmp1; /* Fractional part */
+ }
+ /* Sinc5 filter ODR doesn't use all FILTER_FS bits */
+ for (i = 0; i < ARRAY_SIZE(ad4170_sinc5_filt_fs_tbl); i++) {
+ tmp0 = div_u64_rem(st->mclk_hz, 32 * ad4170_sinc5_filt_fs_tbl[i],
+ &tmp1);
+ tmp1 = mult_frac(tmp1, MICRO, 32 * ad4170_sinc5_filt_fs_tbl[i]);
+ /* Fill sinc5 filter SPS table */
+ st->sps_tbl[AD4170_SINC5][i][0] = tmp0; /* Integer part */
+ st->sps_tbl[AD4170_SINC5][i][1] = tmp1; /* Fractional part */
+ }
+}
+
+static int ad4170_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int ad4170_get_reg_size(struct ad4170_state *st, unsigned int reg,
+ unsigned int *size)
+{
+ if (reg >= ARRAY_SIZE(ad4170_reg_size))
+ return -EINVAL;
+
+ *size = ad4170_reg_size[reg];
+
+ return 0;
+}
+
+static int ad4170_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct ad4170_state *st = context;
+ u8 tx_buf[AD4170_SPI_MAX_XFER_LEN];
+ unsigned int size;
+ int ret;
+
+ ret = ad4170_get_reg_size(st, reg, &size);
+ if (ret)
+ return ret;
+
+ put_unaligned_be16(reg, tx_buf);
+ switch (size) {
+ case 3:
+ put_unaligned_be24(val, &tx_buf[AD4170_SPI_INST_PHASE_LEN]);
+ break;
+ case 2:
+ put_unaligned_be16(val, &tx_buf[AD4170_SPI_INST_PHASE_LEN]);
+ break;
+ case 1:
+ tx_buf[AD4170_SPI_INST_PHASE_LEN] = val;
+ break;
+ case 0:
+ /* Write continuous read exit code */
+ tx_buf[0] = AD4170_ADC_CTRL_CONT_READ_EXIT;
+ return spi_write_then_read(st->spi, tx_buf, 1, NULL, 0);
+ default:
+ return -EINVAL;
+ }
+
+ return spi_write_then_read(st->spi, tx_buf,
+ AD4170_SPI_INST_PHASE_LEN + size, NULL, 0);
+}
+
+static int ad4170_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct ad4170_state *st = context;
+ u8 tx_buf[AD4170_SPI_INST_PHASE_LEN];
+ unsigned int size;
+ int ret;
+
+ put_unaligned_be16(AD4170_REG_READ_MASK | reg, tx_buf);
+
+ ret = ad4170_get_reg_size(st, reg, &size);
+ if (ret)
+ return ret;
+
+ ret = spi_write_then_read(st->spi, tx_buf, ARRAY_SIZE(tx_buf),
+ st->rx_buf, size);
+ if (ret)
+ return ret;
+
+ switch (size) {
+ case 3:
+ *val = get_unaligned_be24(st->rx_buf);
+ return 0;
+ case 2:
+ *val = get_unaligned_be16(st->rx_buf);
+ return 0;
+ case 1:
+ *val = st->rx_buf[0];
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct regmap_config ad4170_regmap_config = {
+ .reg_read = ad4170_reg_read,
+ .reg_write = ad4170_reg_write,
+};
+
+static bool ad4170_setup_eq(struct ad4170_setup *a, struct ad4170_setup *b)
+{
+ if (a->misc != b->misc ||
+ a->afe != b->afe ||
+ a->filter != b->filter ||
+ a->filter_fs != b->filter_fs ||
+ a->offset != b->offset ||
+ a->gain != b->gain)
+ return false;
+
+ return true;
+}
+
+static int ad4170_find_setup(struct ad4170_state *st,
+ struct ad4170_setup *target_setup,
+ unsigned int *setup_num, bool *overwrite)
+{
+ unsigned int i;
+
+ *setup_num = AD4170_INVALID_SETUP;
+ *overwrite = false;
+
+ for (i = 0; i < AD4170_MAX_SETUPS; i++) {
+ struct ad4170_setup_info *setup_info = &st->setup_infos[i];
+
+ /* Immediately accept a matching setup. */
+ if (ad4170_setup_eq(target_setup, &setup_info->setup)) {
+ *setup_num = i;
+ return 0;
+ }
+
+ /* Ignore all setups which are used by enabled channels. */
+ if (setup_info->enabled_channels)
+ continue;
+
+ /* Find the least used slot. */
+ if (*setup_num == AD4170_INVALID_SETUP ||
+ setup_info->channels < st->setup_infos[*setup_num].channels)
+ *setup_num = i;
+ }
+
+ if (*setup_num == AD4170_INVALID_SETUP)
+ return -EINVAL;
+
+ *overwrite = true;
+ return 0;
+}
+
+static void ad4170_unlink_channel(struct ad4170_state *st, unsigned int channel)
+{
+ struct ad4170_chan_info *chan_info = &st->chan_infos[channel];
+ struct ad4170_setup_info *setup_info = &st->setup_infos[chan_info->setup_num];
+
+ chan_info->setup_num = AD4170_INVALID_SETUP;
+ setup_info->channels--;
+}
+
+static int ad4170_unlink_setup(struct ad4170_state *st, unsigned int setup_num)
+{
+ unsigned int i;
+
+ for (i = 0; i < AD4170_MAX_ADC_CHANNELS; i++) {
+ struct ad4170_chan_info *chan_info = &st->chan_infos[i];
+
+ if (!chan_info->initialized || chan_info->setup_num != setup_num)
+ continue;
+
+ ad4170_unlink_channel(st, i);
+ }
+ return 0;
+}
+
+static int ad4170_link_channel_setup(struct ad4170_state *st,
+ unsigned int chan_addr,
+ unsigned int setup_num)
+{
+ struct ad4170_setup_info *setup_info = &st->setup_infos[setup_num];
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan_addr];
+ int ret;
+
+ ret = regmap_update_bits(st->regmap, AD4170_CHAN_SETUP_REG(chan_addr),
+ AD4170_CHAN_SETUP_SETUP_MSK,
+ FIELD_PREP(AD4170_CHAN_SETUP_SETUP_MSK, setup_num));
+ if (ret)
+ return ret;
+
+ chan_info->setup_num = setup_num;
+ setup_info->channels++;
+ return 0;
+}
+
+static int ad4170_write_setup(struct ad4170_state *st, unsigned int setup_num,
+ struct ad4170_setup *setup)
+{
+ int ret;
+
+ /*
+ * It is recommended to place the ADC in standby mode or idle mode to
+ * write to OFFSET and GAIN registers.
+ */
+ ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
+ AD4170_ADC_CTRL_MODE_MSK,
+ FIELD_PREP(AD4170_ADC_CTRL_MODE_MSK,
+ AD4170_ADC_CTRL_MODE_IDLE));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4170_MISC_REG(setup_num), setup->misc);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4170_AFE_REG(setup_num), setup->afe);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4170_FILTER_REG(setup_num),
+ setup->filter);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4170_FILTER_FS_REG(setup_num),
+ setup->filter_fs);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4170_OFFSET_REG(setup_num),
+ setup->offset);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4170_GAIN_REG(setup_num), setup->gain);
+ if (ret)
+ return ret;
+
+ memcpy(&st->setup_infos[setup_num].setup, setup, sizeof(*setup));
+ return 0;
+}
+
+static int ad4170_write_channel_setup(struct ad4170_state *st,
+ unsigned int chan_addr, bool on_enable)
+{
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan_addr];
+ bool overwrite;
+ int setup_num;
+ int ret;
+
+ /*
+ * Similar to AD4130 driver, the following cases need to be handled.
+ *
+ * 1. Enabled and linked channel with setup changes:
+ * - Find a setup. If not possible, return error.
+ * - Unlink channel from current setup.
+ * - If the setup found has only disabled channels linked to it,
+ * unlink all channels, and write the new setup to it.
+ * - Link channel to new setup.
+ *
+ * 2. Soon to be enabled and unlinked channel:
+ * - Find a setup. If not possible, return error.
+ * - If the setup found has only disabled channels linked to it,
+ * unlink all channels, and write the new setup to it.
+ * - Link channel to the setup.
+ *
+ * 3. Disabled and linked channel with setup changes:
+ * - Unlink channel from current setup.
+ *
+ * 4. Soon to be enabled and linked channel:
+ * 5. Disabled and unlinked channel with setup changes:
+ * - Do nothing.
+ */
+
+ /* Cases 3, 4, and 5 */
+ if (chan_info->setup_num != AD4170_INVALID_SETUP) {
+ /* Case 4 */
+ if (on_enable)
+ return 0;
+
+ /* Case 3 */
+ if (!chan_info->enabled) {
+ ad4170_unlink_channel(st, chan_addr);
+ return 0;
+ }
+ } else if (!on_enable && !chan_info->enabled) {
+ /* Case 5 */
+ return 0;
+ }
+
+ /* Cases 1 & 2 */
+ ret = ad4170_find_setup(st, &chan_info->setup, &setup_num, &overwrite);
+ if (ret)
+ return ret;
+
+ if (chan_info->setup_num != AD4170_INVALID_SETUP)
+ /* Case 1 */
+ ad4170_unlink_channel(st, chan_addr);
+
+ if (overwrite) {
+ ret = ad4170_unlink_setup(st, setup_num);
+ if (ret)
+ return ret;
+
+ ret = ad4170_write_setup(st, setup_num, &chan_info->setup);
+ if (ret)
+ return ret;
+ }
+
+ return ad4170_link_channel_setup(st, chan_addr, setup_num);
+}
+
+static int ad4170_set_channel_enable(struct ad4170_state *st,
+ unsigned int chan_addr, bool status)
+{
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan_addr];
+ struct ad4170_setup_info *setup_info;
+ int ret;
+
+ if (chan_info->enabled == status)
+ return 0;
+
+ if (status) {
+ ret = ad4170_write_channel_setup(st, chan_addr, true);
+ if (ret)
+ return ret;
+ }
+
+ setup_info = &st->setup_infos[chan_info->setup_num];
+
+ ret = regmap_update_bits(st->regmap, AD4170_CHAN_EN_REG,
+ AD4170_CHAN_EN(chan_addr),
+ status ? AD4170_CHAN_EN(chan_addr) : 0);
+ if (ret)
+ return ret;
+
+ setup_info->enabled_channels += status ? 1 : -1;
+ chan_info->enabled = status;
+ return 0;
+}
+
+static int __ad4170_get_filter_type(unsigned int filter)
+{
+ u16 f_conf = FIELD_GET(AD4170_FILTER_FILTER_TYPE_MSK, filter);
+
+ switch (f_conf) {
+ case AD4170_FILTER_FILTER_TYPE_SINC5_AVG:
+ return AD4170_SINC5_AVG;
+ case AD4170_FILTER_FILTER_TYPE_SINC5:
+ return AD4170_SINC5;
+ case AD4170_FILTER_FILTER_TYPE_SINC3:
+ return AD4170_SINC3;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4170_set_filter_type(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ unsigned int val)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address];
+ struct ad4170_setup *setup = &chan_info->setup;
+ unsigned int filter_type_conf;
+ int ret;
+
+ switch (val) {
+ case AD4170_SINC5_AVG:
+ filter_type_conf = AD4170_FILTER_FILTER_TYPE_SINC5_AVG;
+ break;
+ case AD4170_SINC5:
+ filter_type_conf = AD4170_FILTER_FILTER_TYPE_SINC5;
+ break;
+ case AD4170_SINC3:
+ filter_type_conf = AD4170_FILTER_FILTER_TYPE_SINC3;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * The filters provide the same ODR for a given filter_fs value but
+ * there are different minimum and maximum filter_fs limits for each
+ * filter. The filter_fs value will be adjusted if the current filter_fs
+ * is out of the limits of the just requested filter. Since the
+ * filter_fs value affects the ODR (sampling_frequency), changing the
+ * filter may lead to a change in the sampling frequency.
+ */
+ scoped_guard(mutex, &st->lock) {
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ if (val == AD4170_SINC5_AVG || val == AD4170_SINC3)
+ setup->filter_fs = clamp(val, AD4170_SINC3_MIN_FS,
+ AD4170_SINC3_MAX_FS);
+ else
+ setup->filter_fs = clamp(val, AD4170_SINC5_MIN_FS,
+ AD4170_SINC5_MAX_FS);
+
+ setup->filter &= ~AD4170_FILTER_FILTER_TYPE_MSK;
+ setup->filter |= FIELD_PREP(AD4170_FILTER_FILTER_TYPE_MSK,
+ filter_type_conf);
+
+ ret = ad4170_write_channel_setup(st, chan->address, false);
+ iio_device_release_direct(indio_dev);
+ }
+
+ return ret;
+}
+
+static int ad4170_get_filter_type(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address];
+ struct ad4170_setup *setup = &chan_info->setup;
+
+ return __ad4170_get_filter_type(setup->filter);
+}
+
+static const struct iio_enum ad4170_filter_type_enum = {
+ .items = ad4170_filt_names,
+ .num_items = ARRAY_SIZE(ad4170_filt_names),
+ .get = ad4170_get_filter_type,
+ .set = ad4170_set_filter_type,
+};
+
+static const struct iio_chan_spec_ext_info ad4170_filter_type_ext_info[] = {
+ IIO_ENUM("filter_type", IIO_SEPARATE, &ad4170_filter_type_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_TYPE,
+ &ad4170_filter_type_enum),
+ { }
+};
+
+static const struct iio_chan_spec ad4170_channel_template = {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .differential = 1,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .ext_info = ad4170_filter_type_ext_info,
+ .scan_type = {
+ .realbits = 24,
+ .storagebits = 32,
+ .shift = 8,
+ .endianness = IIO_BE,
+ },
+};
+
+static const struct iio_chan_spec ad4170_temp_channel_template = {
+ .type = IIO_TEMP,
+ .indexed = 0,
+ .channel = 17,
+ .channel2 = 17,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_separate_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .scan_type = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ .shift = 8,
+ .endianness = IIO_BE,
+ },
+};
+
+/*
+ * Receives the number of a multiplexed AD4170 input (ain_n), and stores the
+ * voltage (in µV) of the specified input into ain_voltage. If the input number
+ * is a ordinary analog input (AIN0 to AIN8), stores zero into ain_voltage.
+ * If a voltage regulator required by a special input is unavailable, return
+ * error code. Return 0 on success.
+ */
+static int ad4170_get_ain_voltage_uv(struct ad4170_state *st, int ain_n,
+ int *ain_voltage)
+{
+ struct device *dev = &st->spi->dev;
+ int v_diff;
+
+ *ain_voltage = 0;
+ /*
+ * The voltage bias (vbias) sets the common-mode voltage of the channel
+ * to (AVDD + AVSS)/2. If provided, AVSS supply provides the magnitude
+ * (absolute value) of the negative voltage supplied to the AVSS pin.
+ * So, we do AVDD - AVSS to compute the DC voltage generated by the bias
+ * voltage generator.
+ */
+ if (st->pins_fn[ain_n] & AD4170_PIN_VBIAS) {
+ int v_diff = st->vrefs_uv[AD4170_AVDD_SUP] - st->vrefs_uv[AD4170_AVSS_SUP];
+ *ain_voltage = v_diff / 2;
+ return 0;
+ }
+
+ if (ain_n <= AD4170_CHAN_MAP_TEMP_SENSOR)
+ return 0;
+
+ switch (ain_n) {
+ case AD4170_CHAN_MAP_AVDD_AVSS_N:
+ v_diff = st->vrefs_uv[AD4170_AVDD_SUP] - st->vrefs_uv[AD4170_AVSS_SUP];
+ *ain_voltage = v_diff / 5;
+ return 0;
+ case AD4170_CHAN_MAP_IOVDD_DGND_N:
+ *ain_voltage = st->vrefs_uv[AD4170_IOVDD_SUP] / 5;
+ return 0;
+ case AD4170_CHAN_MAP_AVSS:
+ *ain_voltage = st->vrefs_uv[AD4170_AVSS_SUP];
+ return 0;
+ case AD4170_CHAN_MAP_DGND:
+ *ain_voltage = 0;
+ return 0;
+ case AD4170_CHAN_MAP_REFIN1_P:
+ if (st->vrefs_uv[AD4170_REFIN1P_SUP] == -ENODEV)
+ return dev_err_probe(dev, -ENODEV,
+ "input set to REFIN+ but ref not provided\n");
+
+ *ain_voltage = st->vrefs_uv[AD4170_REFIN1P_SUP];
+ return 0;
+ case AD4170_CHAN_MAP_REFIN1_N:
+ if (st->vrefs_uv[AD4170_REFIN1N_SUP] == -ENODEV)
+ return dev_err_probe(dev, -ENODEV,
+ "input set to REFIN- but ref not provided\n");
+
+ *ain_voltage = st->vrefs_uv[AD4170_REFIN1N_SUP];
+ return 0;
+ case AD4170_CHAN_MAP_REFIN2_P:
+ if (st->vrefs_uv[AD4170_REFIN2P_SUP] == -ENODEV)
+ return dev_err_probe(dev, -ENODEV,
+ "input set to REFIN2+ but ref not provided\n");
+
+ *ain_voltage = st->vrefs_uv[AD4170_REFIN2P_SUP];
+ return 0;
+ case AD4170_CHAN_MAP_REFIN2_N:
+ if (st->vrefs_uv[AD4170_REFIN2N_SUP] == -ENODEV)
+ return dev_err_probe(dev, -ENODEV,
+ "input set to REFIN2- but ref not provided\n");
+
+ *ain_voltage = st->vrefs_uv[AD4170_REFIN2N_SUP];
+ return 0;
+ case AD4170_CHAN_MAP_REFOUT:
+ /* REFOUT is 2.5V relative to AVSS so take that into account */
+ *ain_voltage = st->vrefs_uv[AD4170_AVSS_SUP] + AD4170_INT_REF_2_5V;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4170_validate_analog_input(struct ad4170_state *st, int pin)
+{
+ if (pin <= AD4170_MAX_ANALOG_PINS) {
+ if (st->pins_fn[pin] & AD4170_PIN_CURRENT_OUT)
+ return dev_err_probe(&st->spi->dev, -EINVAL,
+ "Pin %d already used with fn %u.\n",
+ pin, st->pins_fn[pin]);
+
+ st->pins_fn[pin] |= AD4170_PIN_ANALOG_IN;
+ }
+ return 0;
+}
+
+static int ad4170_validate_channel_input(struct ad4170_state *st, int pin, bool com)
+{
+ /* Check common-mode input pin is mapped to a special input. */
+ if (com && (pin < AD4170_CHAN_MAP_AVDD_AVSS_P || pin > AD4170_CHAN_MAP_REFOUT))
+ return dev_err_probe(&st->spi->dev, -EINVAL,
+ "Invalid common-mode input pin number. %d\n",
+ pin);
+
+ /* Check differential input pin is mapped to a analog input pin. */
+ if (!com && pin > AD4170_MAX_ANALOG_PINS)
+ return dev_err_probe(&st->spi->dev, -EINVAL,
+ "Invalid analog input pin number. %d\n",
+ pin);
+
+ return ad4170_validate_analog_input(st, pin);
+}
+
+/*
+ * Verifies whether the channel input configuration is valid by checking the
+ * input numbers.
+ * Returns 0 on valid channel input configuration. -EINVAL otherwise.
+ */
+static int ad4170_validate_channel(struct ad4170_state *st,
+ struct iio_chan_spec const *chan)
+{
+ int ret;
+
+ ret = ad4170_validate_channel_input(st, chan->channel, false);
+ if (ret)
+ return ret;
+
+ return ad4170_validate_channel_input(st, chan->channel2,
+ !chan->differential);
+}
+
+/*
+ * Verifies whether the channel configuration is valid by checking the provided
+ * input type, polarity, and voltage references result in a sane input range.
+ * Returns negative error code on failure.
+ */
+static int ad4170_get_input_range(struct ad4170_state *st,
+ struct iio_chan_spec const *chan,
+ unsigned int ch_reg, unsigned int ref_sel)
+{
+ bool bipolar = chan->scan_type.sign == 's';
+ struct device *dev = &st->spi->dev;
+ int refp, refn, ain_voltage, ret;
+
+ switch (ref_sel) {
+ case AD4170_REF_REFIN1:
+ if (st->vrefs_uv[AD4170_REFIN1P_SUP] == -ENODEV ||
+ st->vrefs_uv[AD4170_REFIN1N_SUP] == -ENODEV)
+ return dev_err_probe(dev, -ENODEV,
+ "REFIN± selected but not provided\n");
+
+ refp = st->vrefs_uv[AD4170_REFIN1P_SUP];
+ refn = st->vrefs_uv[AD4170_REFIN1N_SUP];
+ break;
+ case AD4170_REF_REFIN2:
+ if (st->vrefs_uv[AD4170_REFIN2P_SUP] == -ENODEV ||
+ st->vrefs_uv[AD4170_REFIN2N_SUP] == -ENODEV)
+ return dev_err_probe(dev, -ENODEV,
+ "REFIN2± selected but not provided\n");
+
+ refp = st->vrefs_uv[AD4170_REFIN2P_SUP];
+ refn = st->vrefs_uv[AD4170_REFIN2N_SUP];
+ break;
+ case AD4170_REF_AVDD:
+ refp = st->vrefs_uv[AD4170_AVDD_SUP];
+ refn = st->vrefs_uv[AD4170_AVSS_SUP];
+ break;
+ case AD4170_REF_REFOUT:
+ /* REFOUT is 2.5 V relative to AVSS */
+ refp = st->vrefs_uv[AD4170_AVSS_SUP] + AD4170_INT_REF_2_5V;
+ refn = st->vrefs_uv[AD4170_AVSS_SUP];
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Find out the analog input range from the channel type, polarity, and
+ * voltage reference selection.
+ * AD4170 channels are either differential or pseudo-differential.
+ * Diff input voltage range: −VREF/gain to +VREF/gain (datasheet page 6)
+ * Pseudo-diff input voltage range: 0 to VREF/gain (datasheet page 6)
+ */
+ if (chan->differential) {
+ if (!bipolar)
+ return dev_err_probe(dev, -EINVAL,
+ "Channel %u differential unipolar\n",
+ ch_reg);
+
+ /*
+ * Differential bipolar channel.
+ * avss-supply is never above 0V.
+ * Assuming refin1n-supply not above 0V.
+ * Assuming refin2n-supply not above 0V.
+ */
+ return refp + abs(refn);
+ }
+ /*
+ * Some configurations can lead to invalid setups.
+ * For example, if AVSS = -2.5V, REF_SELECT set to REFOUT (REFOUT/AVSS),
+ * and pseudo-diff channel configuration set, then the input range
+ * should go from 0V to +VREF (single-ended - datasheet pg 10), but
+ * REFOUT/AVSS range would be -2.5V to 0V.
+ * Check the positive reference is higher than 0V for pseudo-diff
+ * channels.
+ * Note that at this point in the code, refp can only be >= 0 since all
+ * error codes from reading the regulator voltage have been checked
+ * either at ad4170_regulator_setup() or above in this function.
+ */
+ if (refp == 0)
+ return dev_err_probe(dev, -EINVAL,
+ "REF+ == GND for pseudo-diff chan %u\n",
+ ch_reg);
+
+ if (bipolar)
+ return refp;
+
+ /*
+ * Pseudo-differential unipolar channel.
+ * Input expected to swing from IN- to +VREF.
+ */
+ ret = ad4170_get_ain_voltage_uv(st, chan->channel2, &ain_voltage);
+ if (ret)
+ return ret;
+
+ if (refp - ain_voltage <= 0)
+ return dev_err_probe(dev, -EINVAL,
+ "Negative input >= REF+ for pseudo-diff chan %u\n",
+ ch_reg);
+
+ return refp - ain_voltage;
+}
+
+static int __ad4170_read_sample(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ unsigned long settling_time_ms;
+ int ret;
+
+ reinit_completion(&st->completion);
+ ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
+ AD4170_ADC_CTRL_MODE_MSK,
+ FIELD_PREP(AD4170_ADC_CTRL_MODE_MSK,
+ AD4170_ADC_CTRL_MODE_SINGLE));
+ if (ret)
+ return ret;
+
+ /*
+ * When a channel is manually selected by the user, the ADC needs an
+ * extra time to provide the first stable conversion. The ADC settling
+ * time depends on the filter type, filter frequency, and ADC clock
+ * frequency (see datasheet page 53). The maximum settling time among
+ * all filter configurations is 6291164 / fCLK. Use that formula to wait
+ * for sufficient time whatever the filter configuration may be.
+ */
+ settling_time_ms = DIV_ROUND_UP(6291164 * MILLI, st->mclk_hz);
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(settling_time_ms));
+ if (!ret)
+ dev_dbg(&st->spi->dev,
+ "No Data Ready signal. Reading after delay.\n");
+
+ ret = regmap_read(st->regmap, AD4170_DATA_24B_REG, val);
+ if (ret)
+ return ret;
+
+ if (chan->scan_type.sign == 's')
+ *val = sign_extend32(*val, chan->scan_type.realbits - 1);
+
+ return 0;
+}
+
+static int ad4170_read_sample(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ int ret, ret2;
+
+ /*
+ * The ADC sequences through all enabled channels. That can lead to
+ * incorrect channel being sampled if a previous read would have left a
+ * different channel enabled. Thus, always enable and disable the
+ * channel on single-shot read.
+ */
+ ret = ad4170_set_channel_enable(st, chan->address, true);
+ if (ret)
+ return ret;
+
+ ret = __ad4170_read_sample(indio_dev, chan, val);
+ if (ret) {
+ dev_err(dev, "failed to read sample: %d\n", ret);
+
+ ret2 = ad4170_set_channel_enable(st, chan->address, false);
+ if (ret2)
+ dev_err(dev, "failed to disable channel: %d\n", ret2);
+
+ return ret;
+ }
+
+ ret = ad4170_set_channel_enable(st, chan->address, false);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+}
+
+static int ad4170_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address];
+ struct ad4170_setup *setup = &chan_info->setup;
+ enum ad4170_filter_type f_type;
+ unsigned int pga, fs_idx;
+ int ret;
+
+ guard(mutex)(&st->lock);
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = ad4170_read_sample(indio_dev, chan, val);
+ iio_device_release_direct(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_SCALE:
+ pga = FIELD_GET(AD4170_AFE_PGA_GAIN_MSK, setup->afe);
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ *val = chan_info->scale_tbl[pga][0];
+ *val2 = chan_info->scale_tbl[pga][1];
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_TEMP:
+ /*
+ * The scale_tbl converts output codes to mV units so
+ * multiply by MILLI to make the factor convert to µV.
+ * Then, apply the temperature sensor change sensitivity
+ * of 477 μV/K. Finally, multiply the result by MILLI
+ * again to comply with milli degrees Celsius IIO ABI.
+ */
+ *val = 0;
+ *val2 = DIV_ROUND_CLOSEST(chan_info->scale_tbl[pga][1] * MILLI, 477) *
+ MILLI;
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_OFFSET:
+ pga = FIELD_GET(AD4170_AFE_PGA_GAIN_MSK, setup->afe);
+ *val = chan_info->offset_tbl[pga];
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ f_type = __ad4170_get_filter_type(setup->filter);
+ switch (f_type) {
+ case AD4170_SINC5_AVG:
+ case AD4170_SINC3:
+ fs_idx = find_closest(setup->filter_fs,
+ ad4170_sinc3_filt_fs_tbl,
+ ARRAY_SIZE(ad4170_sinc3_filt_fs_tbl));
+ *val = st->sps_tbl[f_type][fs_idx][0];
+ *val2 = st->sps_tbl[f_type][fs_idx][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+ case AD4170_SINC5:
+ fs_idx = find_closest(setup->filter_fs,
+ ad4170_sinc5_filt_fs_tbl,
+ ARRAY_SIZE(ad4170_sinc5_filt_fs_tbl));
+ *val = st->sps_tbl[f_type][fs_idx][0];
+ *val2 = st->sps_tbl[f_type][fs_idx][1];
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *val = setup->offset;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ *val = setup->gain;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4170_fill_scale_tbl(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address];
+ struct device *dev = &st->spi->dev;
+ int bipolar = chan->scan_type.sign == 's' ? 1 : 0;
+ int precision_bits = chan->scan_type.realbits;
+ int pga, ainm_voltage, ret;
+ unsigned long long offset;
+
+ ainm_voltage = 0;
+ ret = ad4170_get_ain_voltage_uv(st, chan->channel2, &ainm_voltage);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to fill scale table\n");
+
+ for (pga = 0; pga < AD4170_NUM_PGA_OPTIONS; pga++) {
+ u64 nv;
+ unsigned int lshift, rshift;
+
+ /*
+ * The PGA options are numbered from 0 to 9, with option 0 being
+ * a gain of 2^0 (no actual gain), and 7 meaning a gain of 2^7.
+ * Option 8, though, sets a gain of 0.5, so the input signal can
+ * be attenuated by 2 rather than amplified. Option 9, allows
+ * the signal to bypass the PGA circuitry (no gain).
+ *
+ * The scale factor to get ADC output codes to values in mV
+ * units is given by:
+ * _scale = (input_range / gain) / 2^precision
+ * AD4170 gain is a power of 2 so the above can be written as
+ * _scale = input_range / 2^(precision + gain)
+ * Keep the input range in µV to avoid truncating the less
+ * significant bits when right shifting it so to preserve scale
+ * precision.
+ */
+ nv = (u64)chan_info->input_range_uv * NANO;
+ lshift = !!(pga & BIT(3)); /* handle PGA options 8 and 9 */
+ rshift = precision_bits - bipolar + (pga & GENMASK(2, 0)) - lshift;
+ chan_info->scale_tbl[pga][0] = 0;
+ chan_info->scale_tbl[pga][1] = div_u64(nv >> rshift, MILLI);
+
+ /*
+ * If the negative input is not at GND, the conversion result
+ * (which is relative to IN-) will be offset by the level at IN-.
+ * Use the scale factor the other way around to go from a known
+ * voltage to the corresponding ADC output code.
+ * With that, we are able to get to what would be the output
+ * code for the voltage at the negative input.
+ * If the negative input is not fixed, there is no offset.
+ */
+ offset = ((unsigned long long)abs(ainm_voltage)) * MICRO;
+ offset = DIV_ROUND_CLOSEST_ULL(offset, chan_info->scale_tbl[pga][1]);
+
+ /*
+ * After divided by the scale, offset will always fit into 31
+ * bits. For _raw + _offset to be relative to GND, the value
+ * provided as _offset is of opposite sign than the real offset.
+ */
+ if (ainm_voltage > 0)
+ chan_info->offset_tbl[pga] = -(int)(offset);
+ else
+ chan_info->offset_tbl[pga] = (int)(offset);
+ }
+ return 0;
+}
+
+static int ad4170_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address];
+ enum ad4170_filter_type f_type;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (int *)chan_info->scale_tbl;
+ *length = ARRAY_SIZE(chan_info->scale_tbl) * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *type = IIO_VAL_INT_PLUS_MICRO;
+ f_type = ad4170_get_filter_type(indio_dev, chan);
+ switch (f_type) {
+ case AD4170_SINC5_AVG:
+ case AD4170_SINC3:
+ /* Read sps_tbl here to ensure in bounds array access */
+ *vals = (int *)st->sps_tbl[f_type];
+ *length = ARRAY_SIZE(ad4170_sinc3_filt_fs_tbl) * 2;
+ return IIO_AVAIL_LIST;
+ case AD4170_SINC5:
+ /* Read sps_tbl here to ensure in bounds array access */
+ *vals = (int *)st->sps_tbl[f_type];
+ *length = ARRAY_SIZE(ad4170_sinc5_filt_fs_tbl) * 2;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4170_set_pga(struct ad4170_state *st,
+ struct iio_chan_spec const *chan, int val, int val2)
+{
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address];
+ struct ad4170_setup *setup = &chan_info->setup;
+ unsigned int pga;
+
+ for (pga = 0; pga < AD4170_NUM_PGA_OPTIONS; pga++) {
+ if (val == chan_info->scale_tbl[pga][0] &&
+ val2 == chan_info->scale_tbl[pga][1])
+ break;
+ }
+
+ if (pga == AD4170_NUM_PGA_OPTIONS)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ setup->afe &= ~AD4170_AFE_PGA_GAIN_MSK;
+ setup->afe |= FIELD_PREP(AD4170_AFE_PGA_GAIN_MSK, pga);
+
+ return ad4170_write_channel_setup(st, chan->address, false);
+}
+
+static int ad4170_set_channel_freq(struct ad4170_state *st,
+ struct iio_chan_spec const *chan, int val,
+ int val2)
+{
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address];
+ struct ad4170_setup *setup = &chan_info->setup;
+ enum ad4170_filter_type f_type = __ad4170_get_filter_type(setup->filter);
+ unsigned int filt_fs_tbl_size, i;
+
+ switch (f_type) {
+ case AD4170_SINC5_AVG:
+ case AD4170_SINC3:
+ filt_fs_tbl_size = ARRAY_SIZE(ad4170_sinc3_filt_fs_tbl);
+ break;
+ case AD4170_SINC5:
+ filt_fs_tbl_size = ARRAY_SIZE(ad4170_sinc5_filt_fs_tbl);
+ break;
+ }
+
+ for (i = 0; i < filt_fs_tbl_size; i++) {
+ if (st->sps_tbl[f_type][i][0] == val &&
+ st->sps_tbl[f_type][i][1] == val2)
+ break;
+ }
+ if (i == filt_fs_tbl_size)
+ return -EINVAL;
+
+ guard(mutex)(&st->lock);
+ if (f_type == AD4170_SINC5)
+ setup->filter_fs = ad4170_sinc5_filt_fs_tbl[i];
+ else
+ setup->filter_fs = ad4170_sinc3_filt_fs_tbl[i];
+
+ return ad4170_write_channel_setup(st, chan->address, false);
+}
+
+static int ad4170_set_calib_offset(struct ad4170_state *st,
+ struct iio_chan_spec const *chan, int val)
+{
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address];
+ struct ad4170_setup *setup = &chan_info->setup;
+
+ guard(mutex)(&st->lock);
+ setup->offset = val;
+
+ return ad4170_write_channel_setup(st, chan->address, false);
+}
+
+static int ad4170_set_calib_gain(struct ad4170_state *st,
+ struct iio_chan_spec const *chan, int val)
+{
+ struct ad4170_chan_info *chan_info = &st->chan_infos[chan->address];
+ struct ad4170_setup *setup = &chan_info->setup;
+
+ guard(mutex)(&st->lock);
+ setup->gain = val;
+
+ return ad4170_write_channel_setup(st, chan->address, false);
+}
+
+static int __ad4170_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long info)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ return ad4170_set_pga(st, chan, val, val2);
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad4170_set_channel_freq(st, chan, val, val2);
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return ad4170_set_calib_offset(st, chan, val);
+ case IIO_CHAN_INFO_CALIBSCALE:
+ return ad4170_set_calib_gain(st, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4170_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long info)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = __ad4170_write_raw(indio_dev, chan, val, val2, info);
+ iio_device_release_direct(indio_dev);
+ return ret;
+}
+
+static int ad4170_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ case IIO_CHAN_INFO_CALIBSCALE:
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4170_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *active_scan_mask)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ unsigned int chan_index;
+ int ret;
+
+ iio_for_each_active_channel(indio_dev, chan_index) {
+ ret = ad4170_set_channel_enable(st, chan_index, true);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static const struct iio_info ad4170_info = {
+ .read_raw = ad4170_read_raw,
+ .read_avail = ad4170_read_avail,
+ .write_raw = ad4170_write_raw,
+ .write_raw_get_fmt = ad4170_write_raw_get_fmt,
+ .update_scan_mode = ad4170_update_scan_mode,
+ .debugfs_reg_access = ad4170_debugfs_reg_access,
+};
+
+static int ad4170_soft_reset(struct ad4170_state *st)
+{
+ int ret;
+
+ ret = regmap_write(st->regmap, AD4170_CONFIG_A_REG,
+ AD4170_SW_RESET_MSK);
+ if (ret)
+ return ret;
+
+ /* AD4170-4 requires 1 ms between reset and any register access. */
+ fsleep(1 * USEC_PER_MSEC);
+
+ return 0;
+}
+
+static int ad4170_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct iio_dev *indio_dev = gpiochip_get_data(gc);
+ struct ad4170_state *st = iio_priv(indio_dev);
+ unsigned int val;
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_read(st->regmap, AD4170_GPIO_MODE_REG, &val);
+ if (ret)
+ goto err_release;
+
+ /*
+ * If the GPIO is configured as an input, read the current value from
+ * AD4170_GPIO_INPUT_REG. Otherwise, read the input value from
+ * AD4170_GPIO_OUTPUT_REG.
+ */
+ if (val & BIT(offset * 2))
+ ret = regmap_read(st->regmap, AD4170_GPIO_INPUT_REG, &val);
+ else
+ ret = regmap_read(st->regmap, AD4170_GPIO_OUTPUT_REG, &val);
+ if (ret)
+ goto err_release;
+
+ ret = !!(val & BIT(offset));
+err_release:
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad4170_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct iio_dev *indio_dev = gpiochip_get_data(gc);
+ struct ad4170_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_assign_bits(st->regmap, AD4170_GPIO_OUTPUT_REG,
+ BIT(offset), !!value);
+
+ iio_device_release_direct(indio_dev);
+ return ret;
+}
+
+static int ad4170_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ struct iio_dev *indio_dev = gpiochip_get_data(gc);
+ struct ad4170_state *st = iio_priv(indio_dev);
+ unsigned int val;
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_read(st->regmap, AD4170_GPIO_MODE_REG, &val);
+ if (ret)
+ goto err_release;
+
+ if (val & BIT(offset * 2 + 1))
+ ret = GPIO_LINE_DIRECTION_OUT;
+ else
+ ret = GPIO_LINE_DIRECTION_IN;
+
+err_release:
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad4170_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
+{
+ struct iio_dev *indio_dev = gpiochip_get_data(gc);
+ struct ad4170_state *st = iio_priv(indio_dev);
+ unsigned long gpio_mask;
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ switch (offset) {
+ case 0:
+ gpio_mask = AD4170_GPIO_MODE_GPIO0_MSK;
+ break;
+ case 1:
+ gpio_mask = AD4170_GPIO_MODE_GPIO1_MSK;
+ break;
+ case 2:
+ gpio_mask = AD4170_GPIO_MODE_GPIO2_MSK;
+ break;
+ case 3:
+ gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_release;
+ }
+ ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask,
+ AD4170_GPIO_MODE_GPIO_INPUT << (2 * offset));
+
+err_release:
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad4170_gpio_direction_output(struct gpio_chip *gc,
+ unsigned int offset, int value)
+{
+ struct iio_dev *indio_dev = gpiochip_get_data(gc);
+ struct ad4170_state *st = iio_priv(indio_dev);
+ unsigned long gpio_mask;
+ int ret;
+
+ ret = ad4170_gpio_set(gc, offset, value);
+ if (ret)
+ return ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ switch (offset) {
+ case 0:
+ gpio_mask = AD4170_GPIO_MODE_GPIO0_MSK;
+ break;
+ case 1:
+ gpio_mask = AD4170_GPIO_MODE_GPIO1_MSK;
+ break;
+ case 2:
+ gpio_mask = AD4170_GPIO_MODE_GPIO2_MSK;
+ break;
+ case 3:
+ gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err_release;
+ }
+ ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask,
+ AD4170_GPIO_MODE_GPIO_OUTPUT << (2 * offset));
+
+err_release:
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad4170_gpio_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ struct ad4170_state *st = gpiochip_get_data(gc);
+ unsigned int i;
+
+ /* Only expose GPIOs that were not assigned any other function. */
+ for (i = 0; i < ngpios; i++) {
+ bool valid = st->gpio_fn[i] == AD4170_GPIO_UNASSIGNED;
+
+ __assign_bit(i, valid_mask, valid);
+ }
+
+ return 0;
+}
+
+static int ad4170_gpio_init(struct iio_dev *indio_dev)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+
+ st->gpiochip.label = "ad4170_gpios";
+ st->gpiochip.base = -1;
+ st->gpiochip.ngpio = AD4170_NUM_GPIO_PINS;
+ st->gpiochip.parent = &st->spi->dev;
+ st->gpiochip.can_sleep = true;
+ st->gpiochip.init_valid_mask = ad4170_gpio_init_valid_mask;
+ st->gpiochip.get_direction = ad4170_gpio_get_direction;
+ st->gpiochip.direction_input = ad4170_gpio_direction_input;
+ st->gpiochip.direction_output = ad4170_gpio_direction_output;
+ st->gpiochip.get = ad4170_gpio_get;
+ st->gpiochip.set_rv = ad4170_gpio_set;
+ st->gpiochip.owner = THIS_MODULE;
+
+ return devm_gpiochip_add_data(&st->spi->dev, &st->gpiochip, indio_dev);
+}
+
+static int ad4170_validate_excitation_pin(struct ad4170_state *st, u32 pin)
+{
+ struct device *dev = &st->spi->dev;
+ unsigned int i;
+
+ /* Check the pin number is valid */
+ for (i = 0; i < ARRAY_SIZE(ad4170_iout_pin_tbl); i++)
+ if (ad4170_iout_pin_tbl[i] == pin)
+ break;
+
+ if (i == ARRAY_SIZE(ad4170_iout_pin_tbl))
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid excitation pin: %u\n",
+ pin);
+
+ /* Check the pin is available */
+ if (pin <= AD4170_MAX_ANALOG_PINS) {
+ if (st->pins_fn[pin] != AD4170_PIN_UNASSIGNED)
+ return dev_err_probe(dev, -EINVAL,
+ "Pin %u already used with fn %u\n",
+ pin, st->pins_fn[pin]);
+
+ st->pins_fn[pin] |= AD4170_PIN_CURRENT_OUT;
+ } else {
+ unsigned int gpio = pin - AD4170_CURRENT_SRC_I_OUT_PIN_GPIO(0);
+
+ if (st->gpio_fn[gpio] != AD4170_GPIO_UNASSIGNED)
+ return dev_err_probe(dev, -EINVAL,
+ "GPIO %u already used with fn %u\n",
+ gpio, st->gpio_fn[gpio]);
+
+ st->gpio_fn[gpio] |= AD4170_GPIO_AC_EXCITATION;
+ }
+
+ return 0;
+}
+
+static int ad4170_validate_excitation_pins(struct ad4170_state *st,
+ u32 *exc_pins, int num_exc_pins)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < num_exc_pins; i++) {
+ ret = ad4170_validate_excitation_pin(st, exc_pins[i]);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static const char *const ad4170_i_out_pin_dt_props[] = {
+ "adi,excitation-pin-0",
+ "adi,excitation-pin-1",
+ "adi,excitation-pin-2",
+ "adi,excitation-pin-3",
+};
+
+static const char *const ad4170_i_out_val_dt_props[] = {
+ "adi,excitation-current-0-microamp",
+ "adi,excitation-current-1-microamp",
+ "adi,excitation-current-2-microamp",
+ "adi,excitation-current-3-microamp",
+};
+
+/*
+ * Parses firmware data describing output current source setup. There are 4
+ * excitation currents (IOUT0 to IOUT3) that can be configured independently.
+ * Excitation currents are added if they are output on the same pin.
+ */
+static int ad4170_parse_exc_current(struct ad4170_state *st,
+ struct fwnode_handle *child,
+ unsigned int *exc_pins,
+ unsigned int *exc_curs,
+ unsigned int *num_exc_pins)
+{
+ struct device *dev = &st->spi->dev;
+ unsigned int num_pins, i, j;
+ u32 pin, val;
+ int ret;
+
+ num_pins = 0;
+ for (i = 0; i < AD4170_NUM_CURRENT_SRC; i++) {
+ /* Parse excitation current output pin properties. */
+ pin = AD4170_CURRENT_SRC_I_OUT_PIN_AIN(0);
+ ret = fwnode_property_read_u32(child, ad4170_i_out_pin_dt_props[i],
+ &pin);
+ if (ret)
+ continue;
+
+ exc_pins[num_pins] = pin;
+
+ /* Parse excitation current value properties. */
+ val = ad4170_iout_current_ua_tbl[0];
+ fwnode_property_read_u32(child,
+ ad4170_i_out_val_dt_props[i], &val);
+
+ for (j = 0; j < ARRAY_SIZE(ad4170_iout_current_ua_tbl); j++)
+ if (ad4170_iout_current_ua_tbl[j] == val)
+ break;
+
+ if (j == ARRAY_SIZE(ad4170_iout_current_ua_tbl))
+ return dev_err_probe(dev, -EINVAL, "Invalid %s: %uuA\n",
+ ad4170_i_out_val_dt_props[i], val);
+
+ exc_curs[num_pins] = j;
+ num_pins++;
+ }
+ *num_exc_pins = num_pins;
+
+ return 0;
+}
+
+static int ad4170_setup_current_src(struct ad4170_state *st,
+ struct fwnode_handle *child,
+ struct ad4170_setup *setup, u32 *exc_pins,
+ unsigned int *exc_curs, int num_exc_pins,
+ bool ac_excited)
+{
+ unsigned int exc_cur_pair, i, j;
+ int ret;
+
+ for (i = 0; i < num_exc_pins; i++) {
+ unsigned int exc_cur = exc_curs[i];
+ unsigned int pin = exc_pins[i];
+ unsigned int current_src = 0;
+
+ for (j = 0; j < AD4170_NUM_CURRENT_SRC; j++)
+ if (st->cur_src_pins[j] == AD4170_CURRENT_SRC_DISABLED)
+ break;
+
+ if (j == AD4170_NUM_CURRENT_SRC)
+ return dev_err_probe(&st->spi->dev, -EINVAL,
+ "Too many excitation current sources\n");
+
+ current_src |= FIELD_PREP(AD4170_CURRENT_SRC_I_OUT_PIN_MSK, pin);
+ current_src |= FIELD_PREP(AD4170_CURRENT_SRC_I_OUT_VAL_MSK, exc_cur);
+ st->cur_src_pins[j] = pin;
+ ret = regmap_write(st->regmap, AD4170_CURRENT_SRC_REG(j),
+ current_src);
+ if (ret)
+ return ret;
+ }
+
+ if (!ac_excited)
+ return 0;
+
+ if (num_exc_pins < 2)
+ return dev_err_probe(&st->spi->dev, -EINVAL,
+ "Current chopping requested but only one pin provided: %u\n",
+ exc_pins[0]);
+
+ /*
+ * Two use cases to handle here:
+ * - 2 pairs of excitation currents;
+ * - 1 pair of excitation currents.
+ */
+ if (num_exc_pins == 4) {
+ for (i = 0; i < AD4170_NUM_CURRENT_SRC; i++)
+ if (st->cur_src_pins[i] != exc_pins[i])
+ return dev_err_probe(&st->spi->dev, -EINVAL,
+ "Unable to use 4 exc pins\n");
+ } else {
+ /*
+ * Excitation current chopping is configured in pairs. Current
+ * sources IOUT0 and IOUT1 form pair 1, IOUT2 and IOUT3 make up
+ * pair 2. So, if current chopping was requested, check if the
+ * first end of the first pair of excitation currents is
+ * available. Try the next pair if IOUT0 has already been
+ * configured for another channel.
+ */
+ i = st->cur_src_pins[0] == exc_pins[0] ? 0 : 2;
+
+ if (st->cur_src_pins[i] != exc_pins[0] ||
+ st->cur_src_pins[i + 1] != exc_pins[1])
+ return dev_err_probe(&st->spi->dev, -EINVAL,
+ "Failed to setup current chopping\n");
+
+ st->cur_src_pins[i] = exc_pins[0];
+ st->cur_src_pins[i + 1] = exc_pins[1];
+
+ if (i == 0)
+ exc_cur_pair = AD4170_MISC_CHOP_IEXC_PAIR1;
+ else
+ exc_cur_pair = AD4170_MISC_CHOP_IEXC_PAIR2;
+ }
+
+ /*
+ * Configure excitation current chopping.
+ * Chop both pairs if using four excitation pins.
+ */
+ setup->misc |= FIELD_PREP(AD4170_MISC_CHOP_IEXC_MSK,
+ num_exc_pins == 2 ?
+ exc_cur_pair :
+ AD4170_MISC_CHOP_IEXC_BOTH);
+
+ return 0;
+}
+
+static int ad4170_setup_bridge(struct ad4170_state *st,
+ struct fwnode_handle *child,
+ struct ad4170_setup *setup, u32 *exc_pins,
+ unsigned int *exc_curs, int num_exc_pins,
+ bool ac_excited)
+{
+ unsigned long gpio_mask;
+ unsigned int i;
+ int ret;
+
+ /*
+ * If a specific current is provided through
+ * adi,excitation-current-n-microamp, set excitation pins provided
+ * through adi,excitation-pin-n to excite the bridge circuit.
+ */
+ for (i = 0; i < num_exc_pins; i++)
+ if (exc_curs[i] > 0)
+ return ad4170_setup_current_src(st, child, setup, exc_pins,
+ exc_curs, num_exc_pins,
+ ac_excited);
+
+ /*
+ * Else, use predefined ACX1, ACX1 negated, ACX2, ACX2 negated signals
+ * to AC excite the bridge. Those signals are output on GPIO2, GPIO0,
+ * GPIO3, and GPIO1, respectively. If only two pins are specified for AC
+ * excitation, use ACX1 and ACX2 (GPIO2 and GPIO3).
+ *
+ * Also, to avoid any short-circuit condition when more than one channel
+ * is enabled, set GPIO2 and GPIO0 high, and set GPIO1 and GPIO3 low to
+ * DC excite the bridge whenever a channel without AC excitation is
+ * selected. That is needed because GPIO pins are controlled by the next
+ * highest priority GPIO function when a channel doesn't enable AC
+ * excitation. See datasheet Figure 113 Weigh Scale (AC Excitation) for
+ * the reference circuit diagram.
+ */
+ if (num_exc_pins == 2) {
+ setup->misc |= FIELD_PREP(AD4170_MISC_CHOP_ADC_MSK, 0x3);
+
+ gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK | AD4170_GPIO_MODE_GPIO2_MSK;
+ ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask,
+ FIELD_PREP(AD4170_GPIO_MODE_GPIO3_MSK,
+ AD4170_GPIO_MODE_GPIO_OUTPUT) |
+ FIELD_PREP(AD4170_GPIO_MODE_GPIO2_MSK,
+ AD4170_GPIO_MODE_GPIO_OUTPUT));
+ if (ret)
+ return ret;
+
+ /*
+ * Set GPIO2 high and GPIO3 low to DC excite the bridge when
+ * a different channel is selected.
+ */
+ gpio_mask = AD4170_GPIO_OUTPUT_GPIO_MSK(3) |
+ AD4170_GPIO_OUTPUT_GPIO_MSK(2);
+ ret = regmap_update_bits(st->regmap, AD4170_GPIO_OUTPUT_REG, gpio_mask,
+ FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(3), 0) |
+ FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(2), 1));
+ if (ret)
+ return ret;
+
+ st->gpio_fn[3] |= AD4170_GPIO_OUTPUT;
+ st->gpio_fn[2] |= AD4170_GPIO_OUTPUT;
+ } else {
+ setup->misc |= FIELD_PREP(AD4170_MISC_CHOP_ADC_MSK, 0x2);
+
+ gpio_mask = AD4170_GPIO_MODE_GPIO3_MSK | AD4170_GPIO_MODE_GPIO2_MSK |
+ AD4170_GPIO_MODE_GPIO1_MSK | AD4170_GPIO_MODE_GPIO0_MSK;
+ ret = regmap_update_bits(st->regmap, AD4170_GPIO_MODE_REG, gpio_mask,
+ FIELD_PREP(AD4170_GPIO_MODE_GPIO3_MSK,
+ AD4170_GPIO_MODE_GPIO_OUTPUT) |
+ FIELD_PREP(AD4170_GPIO_MODE_GPIO2_MSK,
+ AD4170_GPIO_MODE_GPIO_OUTPUT) |
+ FIELD_PREP(AD4170_GPIO_MODE_GPIO1_MSK,
+ AD4170_GPIO_MODE_GPIO_OUTPUT) |
+ FIELD_PREP(AD4170_GPIO_MODE_GPIO0_MSK,
+ AD4170_GPIO_MODE_GPIO_OUTPUT));
+ if (ret)
+ return ret;
+
+ /*
+ * Set GPIO2 and GPIO0 high, and set GPIO1 and GPIO3 low to DC
+ * excite the bridge when a different channel is selected.
+ */
+ gpio_mask = AD4170_GPIO_OUTPUT_GPIO_MSK(3) |
+ AD4170_GPIO_OUTPUT_GPIO_MSK(2) |
+ AD4170_GPIO_OUTPUT_GPIO_MSK(1) |
+ AD4170_GPIO_OUTPUT_GPIO_MSK(0);
+ ret = regmap_update_bits(st->regmap, AD4170_GPIO_OUTPUT_REG, gpio_mask,
+ FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(3), 0) |
+ FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(2), 1) |
+ FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(1), 0) |
+ FIELD_PREP(AD4170_GPIO_OUTPUT_GPIO_MSK(0), 1));
+ if (ret)
+ return ret;
+
+ st->gpio_fn[3] |= AD4170_GPIO_OUTPUT;
+ st->gpio_fn[2] |= AD4170_GPIO_OUTPUT;
+ st->gpio_fn[1] |= AD4170_GPIO_OUTPUT;
+ st->gpio_fn[0] |= AD4170_GPIO_OUTPUT;
+ }
+
+ return 0;
+}
+
+static int ad4170_setup_rtd(struct ad4170_state *st,
+ struct fwnode_handle *child,
+ struct ad4170_setup *setup, u32 *exc_pins,
+ unsigned int *exc_curs, int num_exc_pins, bool ac_excited)
+{
+ return ad4170_setup_current_src(st, child, setup, exc_pins,
+ exc_curs, num_exc_pins, ac_excited);
+}
+
+static int ad4170_parse_external_sensor(struct ad4170_state *st,
+ struct fwnode_handle *child,
+ struct ad4170_setup *setup,
+ struct iio_chan_spec *chan,
+ unsigned int s_type)
+{
+ unsigned int num_exc_pins, reg_val;
+ struct device *dev = &st->spi->dev;
+ u32 pins[2], exc_pins[4], exc_curs[4];
+ bool ac_excited;
+ int ret;
+
+ ret = fwnode_property_read_u32_array(child, "diff-channels", pins,
+ ARRAY_SIZE(pins));
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read sensor diff-channels\n");
+
+ chan->differential = true;
+ chan->channel = pins[0];
+ chan->channel2 = pins[1];
+
+ ret = ad4170_parse_exc_current(st, child, exc_pins, exc_curs, &num_exc_pins);
+ if (ret)
+ return ret;
+
+ /* The external sensor may not need excitation from the ADC chip. */
+ if (num_exc_pins == 0)
+ return 0;
+
+ ret = ad4170_validate_excitation_pins(st, exc_pins, num_exc_pins);
+ if (ret)
+ return ret;
+
+ ac_excited = fwnode_property_read_bool(child, "adi,excitation-ac");
+
+ if (s_type == AD4170_THERMOCOUPLE_SENSOR) {
+ if (st->pins_fn[chan->channel2] & AD4170_PIN_VBIAS) {
+ reg_val = BIT(chan->channel2);
+ ret = regmap_write(st->regmap, AD4170_V_BIAS_REG, reg_val);
+ if (ret)
+ dev_err_probe(dev, ret, "Failed to set vbias\n");
+ }
+ }
+ if (s_type == AD4170_WEIGH_SCALE_SENSOR)
+ ret = ad4170_setup_bridge(st, child, setup, exc_pins, exc_curs,
+ num_exc_pins, ac_excited);
+ else
+ ret = ad4170_setup_rtd(st, child, setup, exc_pins, exc_curs,
+ num_exc_pins, ac_excited);
+
+ return ret;
+}
+
+static int ad4170_parse_reference(struct ad4170_state *st,
+ struct fwnode_handle *child,
+ struct ad4170_setup *setup)
+{
+ struct device *dev = &st->spi->dev;
+ const char *propname;
+ u32 aux;
+ int ret;
+
+ /* Optional positive reference buffering */
+ propname = "adi,positive-reference-buffer";
+ ret = device_property_match_property_string(dev, propname,
+ ad4170_ref_buf_str,
+ ARRAY_SIZE(ad4170_ref_buf_str));
+
+ /* Default to full precharge buffer enabled. */
+ setup->afe |= FIELD_PREP(AD4170_AFE_REF_BUF_P_MSK,
+ ret >= 0 ? ret : AD4170_REF_BUF_FULL);
+
+ /* Optional negative reference buffering */
+ propname = "adi,negative-reference-buffer";
+ ret = device_property_match_property_string(dev, propname,
+ ad4170_ref_buf_str,
+ ARRAY_SIZE(ad4170_ref_buf_str));
+
+ /* Default to full precharge buffer enabled. */
+ setup->afe |= FIELD_PREP(AD4170_AFE_REF_BUF_M_MSK,
+ ret >= 0 ? ret : AD4170_REF_BUF_FULL);
+
+ /* Optional voltage reference selection */
+ propname = "adi,reference-select";
+ aux = AD4170_REF_REFOUT; /* Default reference selection. */
+ fwnode_property_read_u32(child, propname, &aux);
+ if (aux > AD4170_REF_AVDD)
+ return dev_err_probe(dev, -EINVAL, "Invalid %s: %u\n",
+ propname, aux);
+
+ setup->afe |= FIELD_PREP(AD4170_AFE_REF_SELECT_MSK, aux);
+
+ return 0;
+}
+
+static int ad4170_parse_adc_channel_type(struct device *dev,
+ struct fwnode_handle *child,
+ struct iio_chan_spec *chan)
+{
+ const char *propname, *propname2;
+ int ret, ret2;
+ u32 pins[2];
+
+ propname = "single-channel";
+ propname2 = "diff-channels";
+ if (!fwnode_property_present(child, propname) &&
+ !fwnode_property_present(child, propname2))
+ return dev_err_probe(dev, -EINVAL,
+ "Channel must define one of %s or %s.\n",
+ propname, propname2);
+
+ /* Parse differential channel configuration */
+ ret = fwnode_property_read_u32_array(child, propname2, pins,
+ ARRAY_SIZE(pins));
+ if (!ret) {
+ chan->differential = true;
+ chan->channel = pins[0];
+ chan->channel2 = pins[1];
+ return 0;
+ }
+ /* Failed to parse diff chan so try pseudo-diff chan props */
+
+ propname2 = "common-mode-channel";
+ if (fwnode_property_present(child, propname) &&
+ !fwnode_property_present(child, propname2))
+ return dev_err_probe(dev, -EINVAL,
+ "When %s is defined, %s must be defined too\n",
+ propname, propname2);
+
+ /* Parse pseudo-differential channel configuration */
+ ret = fwnode_property_read_u32(child, propname, &pins[0]);
+ ret2 = fwnode_property_read_u32(child, propname2, &pins[1]);
+
+ if (!ret && !ret2) {
+ chan->differential = false;
+ chan->channel = pins[0];
+ chan->channel2 = pins[1];
+ return 0;
+ }
+ return dev_err_probe(dev, -EINVAL,
+ "Failed to parse channel %lu input. %d, %d\n",
+ chan->address, ret, ret2);
+}
+
+static int ad4170_parse_channel_node(struct iio_dev *indio_dev,
+ struct fwnode_handle *child,
+ unsigned int chan_num)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ unsigned int s_type = AD4170_ADC_SENSOR;
+ struct device *dev = &st->spi->dev;
+ struct ad4170_chan_info *chan_info;
+ struct ad4170_setup *setup;
+ struct iio_chan_spec *chan;
+ unsigned int ref_select;
+ unsigned int ch_reg;
+ bool bipolar;
+ int ret;
+
+ ret = fwnode_property_read_u32(child, "reg", &ch_reg);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to read channel reg\n");
+
+ if (ch_reg >= AD4170_MAX_ADC_CHANNELS)
+ return dev_err_probe(dev, -EINVAL,
+ "Channel idx greater than no of channels\n");
+
+ chan = &st->chans[chan_num];
+ *chan = ad4170_channel_template;
+
+ chan->address = ch_reg;
+ chan->scan_index = ch_reg;
+ chan_info = &st->chan_infos[chan->address];
+
+ chan_info->setup_num = AD4170_INVALID_SETUP;
+ chan_info->initialized = true;
+
+ setup = &chan_info->setup;
+ ret = ad4170_parse_reference(st, child, setup);
+ if (ret)
+ return ret;
+
+ ret = fwnode_property_match_property_string(child, "adi,sensor-type",
+ ad4170_sensor_type,
+ ARRAY_SIZE(ad4170_sensor_type));
+
+ /* Default to conventional ADC channel if sensor type not present */
+ s_type = ret < 0 ? AD4170_ADC_SENSOR : ret;
+ switch (s_type) {
+ case AD4170_ADC_SENSOR:
+ ret = ad4170_parse_adc_channel_type(dev, child, chan);
+ if (ret)
+ return ret;
+
+ break;
+ case AD4170_WEIGH_SCALE_SENSOR:
+ case AD4170_THERMOCOUPLE_SENSOR:
+ case AD4170_RTD_SENSOR:
+ ret = ad4170_parse_external_sensor(st, child, setup, chan, s_type);
+ if (ret)
+ return ret;
+
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ bipolar = fwnode_property_read_bool(child, "bipolar");
+ setup->afe |= FIELD_PREP(AD4170_AFE_BIPOLAR_MSK, bipolar);
+ if (bipolar)
+ chan->scan_type.sign = 's';
+ else
+ chan->scan_type.sign = 'u';
+
+ ret = ad4170_validate_channel(st, chan);
+ if (ret)
+ return ret;
+
+ ref_select = FIELD_GET(AD4170_AFE_REF_SELECT_MSK, setup->afe);
+ ret = ad4170_get_input_range(st, chan, ch_reg, ref_select);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Invalid input config\n");
+
+ chan_info->input_range_uv = ret;
+ return 0;
+}
+
+static int ad4170_parse_channels(struct iio_dev *indio_dev)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ unsigned int num_channels;
+ unsigned int chan_num;
+ int ret;
+
+ num_channels = device_get_child_node_count(dev);
+
+ if (num_channels > AD4170_MAX_ADC_CHANNELS)
+ return dev_err_probe(dev, -EINVAL, "Too many channels\n");
+
+ /* Add one for temperature */
+ num_channels = min(num_channels + 1, AD4170_MAX_ADC_CHANNELS);
+
+ chan_num = 0;
+ device_for_each_child_node_scoped(dev, child) {
+ ret = ad4170_parse_channel_node(indio_dev, child, chan_num++);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Add internal temperature sensor channel if the maximum number of
+ * channels has not been reached.
+ */
+ if (num_channels < AD4170_MAX_ADC_CHANNELS) {
+ struct ad4170_setup *setup = &st->chan_infos[chan_num].setup;
+
+ st->chans[chan_num] = ad4170_temp_channel_template;
+ st->chans[chan_num].address = chan_num;
+ st->chans[chan_num].scan_index = chan_num;
+
+ st->chan_infos[chan_num].setup_num = AD4170_INVALID_SETUP;
+ st->chan_infos[chan_num].initialized = true;
+
+ setup->afe |= FIELD_PREP(AD4170_AFE_REF_SELECT_MSK,
+ AD4170_REF_AVDD);
+
+ ret = ad4170_get_input_range(st, &st->chans[chan_num], chan_num,
+ AD4170_REF_AVDD);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Invalid input config\n");
+
+ st->chan_infos[chan_num].input_range_uv = ret;
+ chan_num++;
+ }
+
+ /* Add timestamp channel */
+ struct iio_chan_spec ts_chan = IIO_CHAN_SOFT_TIMESTAMP(chan_num);
+
+ st->chans[chan_num] = ts_chan;
+ num_channels = num_channels + 1;
+
+ indio_dev->num_channels = num_channels;
+ indio_dev->channels = st->chans;
+
+ return 0;
+}
+
+static struct ad4170_state *clk_hw_to_ad4170(struct clk_hw *hw)
+{
+ return container_of(hw, struct ad4170_state, int_clk_hw);
+}
+
+static unsigned long ad4170_sel_clk(struct ad4170_state *st,
+ unsigned int clk_sel)
+{
+ st->clock_ctrl &= ~AD4170_CLOCK_CTRL_CLOCKSEL_MSK;
+ st->clock_ctrl |= FIELD_PREP(AD4170_CLOCK_CTRL_CLOCKSEL_MSK, clk_sel);
+ return regmap_write(st->regmap, AD4170_CLOCK_CTRL_REG, st->clock_ctrl);
+}
+
+static unsigned long ad4170_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return AD4170_INT_CLOCK_16MHZ;
+}
+
+static int ad4170_clk_output_is_enabled(struct clk_hw *hw)
+{
+ struct ad4170_state *st = clk_hw_to_ad4170(hw);
+ u32 clk_sel;
+
+ clk_sel = FIELD_GET(AD4170_CLOCK_CTRL_CLOCKSEL_MSK, st->clock_ctrl);
+ return clk_sel == AD4170_CLOCK_CTRL_CLOCKSEL_INT_OUT;
+}
+
+static int ad4170_clk_output_prepare(struct clk_hw *hw)
+{
+ struct ad4170_state *st = clk_hw_to_ad4170(hw);
+
+ return ad4170_sel_clk(st, AD4170_CLOCK_CTRL_CLOCKSEL_INT_OUT);
+}
+
+static void ad4170_clk_output_unprepare(struct clk_hw *hw)
+{
+ struct ad4170_state *st = clk_hw_to_ad4170(hw);
+
+ ad4170_sel_clk(st, AD4170_CLOCK_CTRL_CLOCKSEL_INT);
+}
+
+static const struct clk_ops ad4170_int_clk_ops = {
+ .recalc_rate = ad4170_clk_recalc_rate,
+ .is_enabled = ad4170_clk_output_is_enabled,
+ .prepare = ad4170_clk_output_prepare,
+ .unprepare = ad4170_clk_output_unprepare,
+};
+
+static int ad4170_register_clk_provider(struct iio_dev *indio_dev)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct device *dev = indio_dev->dev.parent;
+ struct clk_init_data init = {};
+ int ret;
+
+ if (device_property_read_string(dev, "clock-output-names", &init.name)) {
+ init.name = devm_kasprintf(dev, GFP_KERNEL, "%pfw",
+ dev_fwnode(dev));
+ if (!init.name)
+ return -ENOMEM;
+ }
+
+ init.ops = &ad4170_int_clk_ops;
+
+ st->int_clk_hw.init = &init;
+ ret = devm_clk_hw_register(dev, &st->int_clk_hw);
+ if (ret)
+ return ret;
+
+ return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &st->int_clk_hw);
+}
+
+static int ad4170_clock_select(struct iio_dev *indio_dev)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ struct clk *ext_clk;
+ int ret;
+
+ ext_clk = devm_clk_get_optional_enabled(dev, NULL);
+ if (IS_ERR(ext_clk))
+ return dev_err_probe(dev, PTR_ERR(ext_clk),
+ "Failed to get external clock\n");
+
+ if (!ext_clk) {
+ /* Use internal clock reference */
+ st->mclk_hz = AD4170_INT_CLOCK_16MHZ;
+ st->clock_ctrl |= FIELD_PREP(AD4170_CLOCK_CTRL_CLOCKSEL_MSK,
+ AD4170_CLOCK_CTRL_CLOCKSEL_INT_OUT);
+
+ if (!device_property_present(&st->spi->dev, "#clock-cells"))
+ return 0;
+
+ return ad4170_register_clk_provider(indio_dev);
+ }
+
+ /* Read optional clock-names prop to specify the external clock type */
+ ret = device_property_match_property_string(dev, "clock-names",
+ ad4170_clk_sel,
+ ARRAY_SIZE(ad4170_clk_sel));
+
+ ret = ret < 0 ? 0 : ret; /* Default to external clock if no clock-names */
+ st->clock_ctrl |= FIELD_PREP(AD4170_CLOCK_CTRL_CLOCKSEL_MSK,
+ AD4170_CLOCK_CTRL_CLOCKSEL_EXT + ret);
+
+ st->mclk_hz = clk_get_rate(ext_clk);
+ if (st->mclk_hz < AD4170_EXT_CLOCK_MHZ_MIN ||
+ st->mclk_hz > AD4170_EXT_CLOCK_MHZ_MAX) {
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid external clock frequency %u\n",
+ st->mclk_hz);
+ }
+
+ return 0;
+}
+
+static int ad4170_parse_firmware(struct iio_dev *indio_dev)
+{
+ unsigned int vbias_pins[AD4170_MAX_ANALOG_PINS];
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ unsigned int num_vbias_pins;
+ int reg_data, ret;
+ u32 int_pin_sel;
+ unsigned int i;
+
+ ret = ad4170_clock_select(indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to setup device clock\n");
+
+ ret = regmap_write(st->regmap, AD4170_CLOCK_CTRL_REG, st->clock_ctrl);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < AD4170_NUM_CURRENT_SRC; i++)
+ st->cur_src_pins[i] = AD4170_CURRENT_SRC_DISABLED;
+
+ /* On power on, device defaults to using SDO pin for data ready signal */
+ int_pin_sel = AD4170_INT_PIN_SDO;
+ ret = device_property_match_property_string(dev, "interrupt-names",
+ ad4170_int_pin_names,
+ ARRAY_SIZE(ad4170_int_pin_names));
+ if (ret >= 0)
+ int_pin_sel = ret;
+
+ reg_data = FIELD_PREP(AD4170_PIN_MUXING_DIG_AUX1_CTRL_MSK,
+ int_pin_sel == AD4170_INT_PIN_DIG_AUX1 ?
+ AD4170_PIN_MUXING_DIG_AUX1_RDY :
+ AD4170_PIN_MUXING_DIG_AUX1_DISABLED);
+
+ ret = regmap_update_bits(st->regmap, AD4170_PIN_MUXING_REG,
+ AD4170_PIN_MUXING_DIG_AUX1_CTRL_MSK, reg_data);
+ if (ret)
+ return ret;
+
+ ret = device_property_count_u32(dev, "adi,vbias-pins");
+ if (ret > 0) {
+ if (ret > AD4170_MAX_ANALOG_PINS)
+ return dev_err_probe(dev, -EINVAL,
+ "Too many vbias pins %u\n", ret);
+
+ num_vbias_pins = ret;
+
+ ret = device_property_read_u32_array(dev, "adi,vbias-pins",
+ vbias_pins,
+ num_vbias_pins);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to read vbias pins\n");
+
+ for (i = 0; i < num_vbias_pins; i++)
+ st->pins_fn[vbias_pins[i]] |= AD4170_PIN_VBIAS;
+ }
+
+ ret = ad4170_parse_channels(indio_dev);
+ if (ret)
+ return ret;
+
+ /* Only create a GPIO chip if flagged for it */
+ if (device_property_read_bool(dev, "gpio-controller")) {
+ ret = ad4170_gpio_init(indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ad4170_initial_config(struct iio_dev *indio_dev)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ unsigned int i;
+ int ret;
+
+ ad4170_fill_sps_tbl(st);
+
+ ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
+ AD4170_ADC_CTRL_MODE_MSK,
+ FIELD_PREP(AD4170_ADC_CTRL_MODE_MSK,
+ AD4170_ADC_CTRL_MODE_IDLE));
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set ADC mode to idle\n");
+
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ struct ad4170_chan_info *chan_info;
+ struct iio_chan_spec const *chan;
+ struct ad4170_setup *setup;
+ unsigned int val;
+
+ chan = &indio_dev->channels[i];
+ if (chan->type == IIO_TIMESTAMP)
+ continue;
+
+ chan_info = &st->chan_infos[chan->address];
+
+ setup = &chan_info->setup;
+ setup->gain = AD4170_GAIN_REG_DEFAULT;
+ ret = ad4170_write_channel_setup(st, chan->address, false);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to write channel setup\n");
+
+ val = FIELD_PREP(AD4170_CHAN_MAP_AINP_MSK, chan->channel) |
+ FIELD_PREP(AD4170_CHAN_MAP_AINM_MSK, chan->channel2);
+
+ ret = regmap_write(st->regmap, AD4170_CHAN_MAP_REG(i), val);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to write CHAN_MAP_REG\n");
+
+ ret = ad4170_set_channel_freq(st, chan,
+ AD4170_DEFAULT_SAMP_RATE, 0);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to set channel freq\n");
+
+ ret = ad4170_fill_scale_tbl(indio_dev, chan);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to fill scale tbl\n");
+ }
+
+ /* Disable all channels to avoid reading from unexpected channel */
+ ret = regmap_write(st->regmap, AD4170_CHAN_EN_REG, 0);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to disable channels\n");
+
+ /*
+ * Configure channels to share the same data output register, i.e. data
+ * can be read from the same register address regardless of channel
+ * number.
+ */
+ return regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
+ AD4170_ADC_CTRL_MULTI_DATA_REG_SEL_MSK,
+ AD4170_ADC_CTRL_MULTI_DATA_REG_SEL_MSK);
+}
+
+static int ad4170_prepare_spi_message(struct ad4170_state *st)
+{
+ /*
+ * Continuous data register read is enabled on buffer postenable so
+ * no instruction phase is needed meaning we don't need to send the
+ * register address to read data. Transfer only needs the read buffer.
+ */
+ st->xfer.rx_buf = &st->rx_buf;
+ st->xfer.len = BITS_TO_BYTES(ad4170_channel_template.scan_type.realbits);
+
+ spi_message_init_with_transfers(&st->msg, &st->xfer, 1);
+
+ return devm_spi_optimize_message(&st->spi->dev, st->spi, &st->msg);
+}
+
+static int ad4170_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
+ AD4170_ADC_CTRL_MODE_MSK,
+ FIELD_PREP(AD4170_ADC_CTRL_MODE_MSK,
+ AD4170_ADC_CTRL_MODE_CONT));
+ if (ret)
+ return ret;
+
+ /*
+ * This enables continuous read of the ADC data register. The ADC must
+ * be in continuous conversion mode.
+ */
+ return regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
+ AD4170_ADC_CTRL_CONT_READ_MSK,
+ FIELD_PREP(AD4170_ADC_CTRL_CONT_READ_MSK,
+ AD4170_ADC_CTRL_CONT_READ_ENABLE));
+}
+
+static int ad4170_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ unsigned int i;
+ int ret;
+
+ /*
+ * Use a high register address (virtual register) to request a write of
+ * 0xA5 to the ADC during the first 8 SCLKs of the ADC data read cycle,
+ * thus exiting continuous read.
+ */
+ ret = regmap_write(st->regmap, AD4170_ADC_CTRL_CONT_READ_EXIT_REG, 0);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
+ AD4170_ADC_CTRL_CONT_READ_MSK,
+ FIELD_PREP(AD4170_ADC_CTRL_CONT_READ_MSK,
+ AD4170_ADC_CTRL_CONT_READ_DISABLE));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4170_ADC_CTRL_REG,
+ AD4170_ADC_CTRL_MODE_MSK,
+ FIELD_PREP(AD4170_ADC_CTRL_MODE_MSK,
+ AD4170_ADC_CTRL_MODE_IDLE));
+ if (ret)
+ return ret;
+
+ /*
+ * The ADC sequences through all the enabled channels (see datasheet
+ * page 95). That can lead to incorrect channel being read if a
+ * single-shot read (or buffered read with different active_scan_mask)
+ * is done after buffer disable. Disable all channels so only requested
+ * channels will be read.
+ */
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ if (indio_dev->channels[i].type == IIO_TIMESTAMP)
+ continue;
+
+ ret = ad4170_set_channel_enable(st, i, false);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static bool ad4170_validate_scan_mask(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ unsigned int masklength = iio_get_masklength(indio_dev);
+ unsigned int enabled;
+
+ /*
+ * The channel sequencer cycles through the enabled channels in
+ * sequential order, from channel 0 to channel 15, bypassing disabled
+ * channels. When more than one channel is enabled, channel 0 must
+ * always be enabled. See datasheet channel_en register description at
+ * page 95.
+ */
+ enabled = bitmap_weight(scan_mask, masklength);
+ if (enabled > 1)
+ return test_bit(0, scan_mask);
+
+ return enabled == 1;
+}
+
+static const struct iio_buffer_setup_ops ad4170_buffer_ops = {
+ .postenable = ad4170_buffer_postenable,
+ .predisable = ad4170_buffer_predisable,
+ .validate_scan_mask = ad4170_validate_scan_mask,
+};
+
+static irqreturn_t ad4170_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad4170_state *st = iio_priv(indio_dev);
+ unsigned int chan_index;
+ unsigned int i = 0;
+ int ret;
+
+ iio_for_each_active_channel(indio_dev, chan_index) {
+ ret = spi_sync(st->spi, &st->msg);
+ if (ret)
+ goto err_out;
+
+ memcpy(&st->bounce_buffer[i++], st->rx_buf, ARRAY_SIZE(st->rx_buf));
+ }
+
+ iio_push_to_buffers_with_ts(indio_dev, st->bounce_buffer,
+ sizeof(st->bounce_buffer),
+ iio_get_time_ns(indio_dev));
+err_out:
+ iio_trigger_notify_done(indio_dev->trig);
+ return IRQ_HANDLED;
+}
+
+static const struct iio_trigger_ops ad4170_trigger_ops = {
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static irqreturn_t ad4170_irq_handler(int irq, void *dev_id)
+{
+ struct iio_dev *indio_dev = dev_id;
+ struct ad4170_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev))
+ iio_trigger_poll(st->trig);
+ else
+ complete(&st->completion);
+
+ return IRQ_HANDLED;
+};
+
+static int ad4170_trigger_setup(struct iio_dev *indio_dev)
+{
+ struct ad4170_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->spi->dev;
+ int ret;
+
+ st->trig = devm_iio_trigger_alloc(dev, "%s-trig%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->trig)
+ return -ENOMEM;
+
+ st->trig->ops = &ad4170_trigger_ops;
+
+ iio_trigger_set_drvdata(st->trig, indio_dev);
+ ret = devm_iio_trigger_register(dev, st->trig);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register trigger\n");
+
+ indio_dev->trig = iio_trigger_get(st->trig);
+
+ return 0;
+}
+
+static int ad4170_regulator_setup(struct ad4170_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ int ret;
+
+ /* Required regulators */
+ ret = devm_regulator_get_enable_read_voltage(dev, "avdd");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get AVDD voltage.\n");
+
+ st->vrefs_uv[AD4170_AVDD_SUP] = ret;
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "iovdd");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get IOVDD voltage.\n");
+
+ st->vrefs_uv[AD4170_IOVDD_SUP] = ret;
+
+ /* Optional regulators */
+ ret = devm_regulator_get_enable_read_voltage(dev, "avss");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get AVSS voltage.\n");
+
+ /*
+ * Assume AVSS at GND (0V) if not provided.
+ * REVISIT: AVSS is never above system ground level (i.e. AVSS is either
+ * GND or a negative voltage). But we currently don't have support for
+ * reading negative voltages with the regulator framework. So, the
+ * current AD4170 support reads a positive value from the regulator,
+ * then inverts sign to make that negative.
+ */
+ st->vrefs_uv[AD4170_AVSS_SUP] = ret == -ENODEV ? 0 : -ret;
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin1p");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get REFIN+ voltage.\n");
+
+ st->vrefs_uv[AD4170_REFIN1P_SUP] = ret;
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin1n");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get REFIN- voltage.\n");
+
+ /*
+ * Negative supplies are assumed to provide negative voltage.
+ * REVISIT when support for negative regulator voltage read be available
+ * in the regulator framework.
+ */
+ st->vrefs_uv[AD4170_REFIN1N_SUP] = ret == -ENODEV ? -ENODEV : -ret;
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin2p");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get REFIN2+ voltage.\n");
+
+ st->vrefs_uv[AD4170_REFIN2P_SUP] = ret;
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin2n");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "Failed to get REFIN2- voltage.\n");
+
+ /*
+ * Negative supplies are assumed to provide negative voltage.
+ * REVISIT when support for negative regulator voltage read be available
+ * in the regulator framework.
+ */
+ st->vrefs_uv[AD4170_REFIN2N_SUP] = ret == -ENODEV ? -ENODEV : -ret;
+
+ return 0;
+}
+
+static int ad4170_probe(struct spi_device *spi)
+{
+ const struct ad4170_chip_info *chip;
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ad4170_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+
+ ret = devm_mutex_init(dev, &st->lock);
+ if (ret)
+ return ret;
+
+ chip = spi_get_device_match_data(spi);
+ if (!chip)
+ return -EINVAL;
+
+ indio_dev->name = chip->name;
+ indio_dev->info = &ad4170_info;
+
+ st->regmap = devm_regmap_init(dev, NULL, st, &ad4170_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "Failed to initialize regmap\n");
+
+ ret = ad4170_regulator_setup(st);
+ if (ret)
+ return ret;
+
+ ret = ad4170_soft_reset(st);
+ if (ret)
+ return ret;
+
+ ret = ad4170_parse_firmware(indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to parse firmware\n");
+
+ ret = ad4170_initial_config(indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to setup device\n");
+
+ init_completion(&st->completion);
+
+ if (spi->irq) {
+ ret = devm_request_irq(dev, spi->irq, &ad4170_irq_handler,
+ IRQF_ONESHOT, indio_dev->name, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad4170_trigger_setup(indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ ret = ad4170_prepare_spi_message(st);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to prepare SPI message\n");
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
+ &ad4170_trigger_handler,
+ &ad4170_buffer_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to setup read buffer\n");
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct spi_device_id ad4170_id_table[] = {
+ { "ad4170-4", (kernel_ulong_t)&ad4170_chip_info },
+ { "ad4190-4", (kernel_ulong_t)&ad4190_chip_info },
+ { "ad4195-4", (kernel_ulong_t)&ad4195_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad4170_id_table);
+
+static const struct of_device_id ad4170_of_match[] = {
+ { .compatible = "adi,ad4170-4", .data = &ad4170_chip_info },
+ { .compatible = "adi,ad4190-4", .data = &ad4190_chip_info },
+ { .compatible = "adi,ad4195-4", .data = &ad4195_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad4170_of_match);
+
+static struct spi_driver ad4170_driver = {
+ .driver = {
+ .name = "ad4170-4",
+ .of_match_table = ad4170_of_match,
+ },
+ .probe = ad4170_probe,
+ .id_table = ad4170_id_table,
+};
+module_spi_driver(ad4170_driver);
+
+MODULE_AUTHOR("Ana-Maria Cusco <ana-maria.cusco@analog.com>");
+MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD4170 SPI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ad4851.c b/drivers/iio/adc/ad4851.c
index f1d2e2896f2a..1ad77f2a4580 100644
--- a/drivers/iio/adc/ad4851.c
+++ b/drivers/iio/adc/ad4851.c
@@ -294,7 +294,6 @@ static int ad4851_scale_fill(struct iio_dev *indio_dev)
}
static int ad4851_set_oversampling_ratio(struct iio_dev *indio_dev,
- const struct iio_chan_spec *chan,
unsigned int osr)
{
struct ad4851_state *st = iio_priv(indio_dev);
@@ -321,7 +320,8 @@ static int ad4851_set_oversampling_ratio(struct iio_dev *indio_dev,
return ret;
}
- ret = iio_backend_oversampling_ratio_set(st->back, osr);
+ /* Channel is ignored by the backend being used here */
+ ret = iio_backend_oversampling_ratio_set(st->back, 0, osr);
if (ret)
return ret;
@@ -444,10 +444,12 @@ static int ad4851_setup(struct ad4851_state *st)
if (ret)
return ret;
- ret = regmap_write(st->regmap, AD4851_REG_INTERFACE_CONFIG_A,
- AD4851_SDO_ENABLE);
- if (ret)
- return ret;
+ if (!(st->spi->mode & SPI_3WIRE)) {
+ ret = regmap_write(st->regmap, AD4851_REG_INTERFACE_CONFIG_A,
+ AD4851_SDO_ENABLE);
+ if (ret)
+ return ret;
+ }
ret = regmap_read(st->regmap, AD4851_REG_PRODUCT_ID_L, &product_id);
if (ret)
@@ -831,7 +833,7 @@ static int ad4851_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_CALIBBIAS:
return ad4851_set_calibbias(st, chan->channel, val);
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
- return ad4851_set_oversampling_ratio(indio_dev, chan, val);
+ return ad4851_set_oversampling_ratio(indio_dev, val);
default:
return -EINVAL;
}
diff --git a/drivers/iio/adc/ad7091r5.c b/drivers/iio/adc/ad7091r5.c
index b472b9498fd1..bd4877268689 100644
--- a/drivers/iio/adc/ad7091r5.c
+++ b/drivers/iio/adc/ad7091r5.c
@@ -92,7 +92,7 @@ static void ad7091r5_regmap_init(struct ad7091r_state *st,
st->map = devm_regmap_init_i2c(i2c, regmap_conf);
}
-static struct ad7091r_init_info ad7091r5_init_info = {
+static const struct ad7091r_init_info ad7091r5_init_info = {
.info_irq = &ad7091r5_chip_info_irq,
.info_no_irq = &ad7091r5_chip_info_noirq,
.regmap_config = &ad7091r_regmap_config,
diff --git a/drivers/iio/adc/ad7091r8.c b/drivers/iio/adc/ad7091r8.c
index cebade4c2d49..e93b8bb60e8e 100644
--- a/drivers/iio/adc/ad7091r8.c
+++ b/drivers/iio/adc/ad7091r8.c
@@ -206,14 +206,14 @@ static int ad7091r8_gpio_setup(struct ad7091r_state *st)
return 0;
}
-static struct ad7091r_init_info ad7091r2_init_info = {
+static const struct ad7091r_init_info ad7091r2_init_info = {
.info_no_irq = &ad7091r8_infos[AD7091R2_INFO],
.regmap_config = &ad7091r2_reg_conf,
.init_adc_regmap = &ad7091r8_regmap_init,
.setup = &ad7091r8_gpio_setup
};
-static struct ad7091r_init_info ad7091r4_init_info = {
+static const struct ad7091r_init_info ad7091r4_init_info = {
.info_no_irq = &ad7091r8_infos[AD7091R4_INFO],
.info_irq = &ad7091r8_infos[AD7091R4_INFO_IRQ],
.regmap_config = &ad7091r4_reg_conf,
@@ -221,7 +221,7 @@ static struct ad7091r_init_info ad7091r4_init_info = {
.setup = &ad7091r8_gpio_setup
};
-static struct ad7091r_init_info ad7091r8_init_info = {
+static const struct ad7091r_init_info ad7091r8_init_info = {
.info_no_irq = &ad7091r8_infos[AD7091R8_INFO],
.info_irq = &ad7091r8_infos[AD7091R8_INFO_IRQ],
.regmap_config = &ad7091r8_reg_conf,
diff --git a/drivers/iio/adc/ad7124.c b/drivers/iio/adc/ad7124.c
index 92596f15e797..9808df2e9242 100644
--- a/drivers/iio/adc/ad7124.c
+++ b/drivers/iio/adc/ad7124.c
@@ -94,11 +94,6 @@
/* AD7124 input sources */
-enum ad7124_ids {
- ID_AD7124_4,
- ID_AD7124_8,
-};
-
enum ad7124_ref_sel {
AD7124_REFIN1,
AD7124_REFIN2,
@@ -193,17 +188,16 @@ struct ad7124_state {
DECLARE_KFIFO(live_cfgs_fifo, struct ad7124_channel_config *, AD7124_MAX_CONFIGS);
};
-static struct ad7124_chip_info ad7124_chip_info_tbl[] = {
- [ID_AD7124_4] = {
- .name = "ad7124-4",
- .chip_id = AD7124_ID_DEVICE_ID_AD7124_4,
- .num_inputs = 8,
- },
- [ID_AD7124_8] = {
- .name = "ad7124-8",
- .chip_id = AD7124_ID_DEVICE_ID_AD7124_8,
- .num_inputs = 16,
- },
+static const struct ad7124_chip_info ad7124_4_chip_info = {
+ .name = "ad7124-4",
+ .chip_id = AD7124_ID_DEVICE_ID_AD7124_4,
+ .num_inputs = 8,
+};
+
+static const struct ad7124_chip_info ad7124_8_chip_info = {
+ .name = "ad7124-8",
+ .chip_id = AD7124_ID_DEVICE_ID_AD7124_8,
+ .num_inputs = 16,
};
static int ad7124_find_closest_match(const int *array,
@@ -1341,17 +1335,15 @@ static int ad7124_probe(struct spi_device *spi)
}
static const struct of_device_id ad7124_of_match[] = {
- { .compatible = "adi,ad7124-4",
- .data = &ad7124_chip_info_tbl[ID_AD7124_4], },
- { .compatible = "adi,ad7124-8",
- .data = &ad7124_chip_info_tbl[ID_AD7124_8], },
+ { .compatible = "adi,ad7124-4", .data = &ad7124_4_chip_info },
+ { .compatible = "adi,ad7124-8", .data = &ad7124_8_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad7124_of_match);
static const struct spi_device_id ad71124_ids[] = {
- { "ad7124-4", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_4] },
- { "ad7124-8", (kernel_ulong_t)&ad7124_chip_info_tbl[ID_AD7124_8] },
+ { "ad7124-4", (kernel_ulong_t)&ad7124_4_chip_info },
+ { "ad7124-8", (kernel_ulong_t)&ad7124_8_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad71124_ids);
diff --git a/drivers/iio/adc/ad7173.c b/drivers/iio/adc/ad7173.c
index b3e6bd2a55d7..4413207be28f 100644
--- a/drivers/iio/adc/ad7173.c
+++ b/drivers/iio/adc/ad7173.c
@@ -228,7 +228,6 @@ struct ad7173_state {
struct ida cfg_slots_status;
unsigned long long config_usage_counter;
unsigned long long *config_cnts;
- struct clk *ext_clk;
struct clk_hw int_clk_hw;
struct regmap *reg_gpiocon_regmap;
struct gpio_regmap *gpio_regmap;
@@ -319,7 +318,7 @@ static int ad7173_set_syscalib_mode(struct iio_dev *indio_dev,
{
struct ad7173_state *st = iio_priv(indio_dev);
- st->channels[chan->channel].syscalib_mode = mode;
+ st->channels[chan->address].syscalib_mode = mode;
return 0;
}
@@ -329,7 +328,7 @@ static int ad7173_get_syscalib_mode(struct iio_dev *indio_dev,
{
struct ad7173_state *st = iio_priv(indio_dev);
- return st->channels[chan->channel].syscalib_mode;
+ return st->channels[chan->address].syscalib_mode;
}
static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev,
@@ -348,7 +347,7 @@ static ssize_t ad7173_write_syscalib(struct iio_dev *indio_dev,
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
- mode = st->channels[chan->channel].syscalib_mode;
+ mode = st->channels[chan->address].syscalib_mode;
if (sys_calib) {
if (mode == AD7173_SYSCALIB_ZERO_SCALE)
ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_SYS_ZERO,
@@ -392,13 +391,12 @@ static int ad7173_calibrate_all(struct ad7173_state *st, struct iio_dev *indio_d
if (indio_dev->channels[i].type != IIO_VOLTAGE)
continue;
- ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, st->channels[i].ain);
+ ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_ZERO, i);
if (ret < 0)
return ret;
if (st->info->has_internal_fs_calibration) {
- ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL,
- st->channels[i].ain);
+ ret = ad_sd_calibrate(&st->sd, AD7173_MODE_CAL_INT_FULL, i);
if (ret < 0)
return ret;
}
@@ -772,10 +770,26 @@ static const struct ad_sigma_delta_info ad7173_sigma_delta_info_8_slots = {
.num_slots = 8,
};
+static const struct ad_sigma_delta_info ad7173_sigma_delta_info_16_slots = {
+ .set_channel = ad7173_set_channel,
+ .append_status = ad7173_append_status,
+ .disable_all = ad7173_disable_all,
+ .disable_one = ad7173_disable_one,
+ .set_mode = ad7173_set_mode,
+ .has_registers = true,
+ .has_named_irqs = true,
+ .addr_shift = 0,
+ .read_mask = BIT(6),
+ .status_ch_mask = GENMASK(3, 0),
+ .data_reg = AD7173_REG_DATA,
+ .num_resetclks = 64,
+ .num_slots = 16,
+};
+
static const struct ad7173_device_info ad4111_device_info = {
.name = "ad4111",
.id = AD4111_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_16_slots,
.num_voltage_in_div = 8,
.num_channels = 16,
.num_configs = 8,
@@ -797,7 +811,7 @@ static const struct ad7173_device_info ad4111_device_info = {
static const struct ad7173_device_info ad4112_device_info = {
.name = "ad4112",
.id = AD4112_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_16_slots,
.num_voltage_in_div = 8,
.num_channels = 16,
.num_configs = 8,
@@ -818,7 +832,7 @@ static const struct ad7173_device_info ad4112_device_info = {
static const struct ad7173_device_info ad4113_device_info = {
.name = "ad4113",
.id = AD4113_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_16_slots,
.num_voltage_in_div = 8,
.num_channels = 16,
.num_configs = 8,
@@ -837,7 +851,7 @@ static const struct ad7173_device_info ad4113_device_info = {
static const struct ad7173_device_info ad4114_device_info = {
.name = "ad4114",
.id = AD4114_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_16_slots,
.num_voltage_in_div = 16,
.num_channels = 16,
.num_configs = 8,
@@ -856,7 +870,7 @@ static const struct ad7173_device_info ad4114_device_info = {
static const struct ad7173_device_info ad4115_device_info = {
.name = "ad4115",
.id = AD4115_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_16_slots,
.num_voltage_in_div = 16,
.num_channels = 16,
.num_configs = 8,
@@ -875,7 +889,7 @@ static const struct ad7173_device_info ad4115_device_info = {
static const struct ad7173_device_info ad4116_device_info = {
.name = "ad4116",
.id = AD4116_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_16_slots,
.num_voltage_in_div = 11,
.num_channels = 16,
.num_configs = 8,
@@ -894,7 +908,7 @@ static const struct ad7173_device_info ad4116_device_info = {
static const struct ad7173_device_info ad7172_2_device_info = {
.name = "ad7172-2",
.id = AD7172_2_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_4_slots,
.num_voltage_in = 5,
.num_channels = 4,
.num_configs = 4,
@@ -927,7 +941,7 @@ static const struct ad7173_device_info ad7172_4_device_info = {
static const struct ad7173_device_info ad7173_8_device_info = {
.name = "ad7173-8",
.id = AD7173_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_16_slots,
.num_voltage_in = 17,
.num_channels = 16,
.num_configs = 8,
@@ -944,7 +958,7 @@ static const struct ad7173_device_info ad7173_8_device_info = {
static const struct ad7173_device_info ad7175_2_device_info = {
.name = "ad7175-2",
.id = AD7175_2_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_4_slots,
.num_voltage_in = 5,
.num_channels = 4,
.num_configs = 4,
@@ -961,7 +975,7 @@ static const struct ad7173_device_info ad7175_2_device_info = {
static const struct ad7173_device_info ad7175_8_device_info = {
.name = "ad7175-8",
.id = AD7175_8_ID,
- .sd_info = &ad7173_sigma_delta_info_8_slots,
+ .sd_info = &ad7173_sigma_delta_info_16_slots,
.num_voltage_in = 17,
.num_channels = 16,
.num_configs = 8,
@@ -1344,11 +1358,6 @@ static void ad7173_disable_regulators(void *data)
regulator_bulk_disable(ARRAY_SIZE(st->regulators), st->regulators);
}
-static void ad7173_clk_disable_unprepare(void *clk)
-{
- clk_disable_unprepare(clk);
-}
-
static unsigned long ad7173_sel_clk(struct ad7173_state *st,
unsigned int clk_sel)
{
@@ -1580,6 +1589,7 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
chan_st_priv->cfg.bipolar = false;
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
chan_st_priv->cfg.ref_sel = AD7173_SETUP_REF_SEL_INT_REF;
+ chan_st_priv->cfg.odr = st->info->odr_start_value;
chan_st_priv->cfg.openwire_comp_chan = -1;
st->adc_mode |= AD7173_ADC_MODE_REF_EN;
if (st->info->data_reg_only_16bit)
@@ -1646,7 +1656,7 @@ static int ad7173_fw_parse_channel_config(struct iio_dev *indio_dev)
chan->scan_index = chan_index;
chan->channel = ain[0];
chan_st_priv->cfg.input_buf = st->info->has_input_buf;
- chan_st_priv->cfg.odr = 0;
+ chan_st_priv->cfg.odr = st->info->odr_start_value;
chan_st_priv->cfg.openwire_comp_chan = -1;
chan_st_priv->cfg.bipolar = fwnode_property_read_bool(child, "bipolar");
@@ -1718,22 +1728,14 @@ static int ad7173_fw_parse_device_config(struct iio_dev *indio_dev)
AD7173_ADC_MODE_CLOCKSEL_INT);
ad7173_register_clk_provider(indio_dev);
} else {
+ struct clk *clk;
+
st->adc_mode |= FIELD_PREP(AD7173_ADC_MODE_CLOCKSEL_MASK,
AD7173_ADC_MODE_CLOCKSEL_EXT + ret);
- st->ext_clk = devm_clk_get(dev, ad7173_clk_sel[ret]);
- if (IS_ERR(st->ext_clk))
- return dev_err_probe(dev, PTR_ERR(st->ext_clk),
+ clk = devm_clk_get_enabled(dev, ad7173_clk_sel[ret]);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk),
"Failed to get external clock\n");
-
- ret = clk_prepare_enable(st->ext_clk);
- if (ret)
- return dev_err_probe(dev, ret,
- "Failed to enable external clock\n");
-
- ret = devm_add_action_or_reset(dev, ad7173_clk_disable_unprepare,
- st->ext_clk);
- if (ret)
- return ret;
}
return ad7173_fw_parse_channel_config(indio_dev);
@@ -1765,7 +1767,9 @@ static int ad7173_probe(struct spi_device *spi)
indio_dev->info = &ad7173_info;
spi->mode = SPI_MODE_3;
- spi_setup(spi);
+ ret = spi_setup(spi);
+ if (ret)
+ return ret;
ret = ad_sd_init(&st->sd, indio_dev, spi, st->info->sd_info);
if (ret)
diff --git a/drivers/iio/adc/ad7380.c b/drivers/iio/adc/ad7380.c
index cabf5511d116..6f7034b6c266 100644
--- a/drivers/iio/adc/ad7380.c
+++ b/drivers/iio/adc/ad7380.c
@@ -1165,7 +1165,6 @@ static int ad7380_init_offload_msg(struct ad7380_state *st,
struct spi_transfer *xfer = &st->offload_xfer;
struct device *dev = &st->spi->dev;
const struct iio_scan_type *scan_type;
- int oversampling_ratio;
int ret;
scan_type = iio_get_current_scan_type(indio_dev,
@@ -1195,10 +1194,6 @@ static int ad7380_init_offload_msg(struct ad7380_state *st,
}
}
- ret = ad7380_get_osr(st, &oversampling_ratio);
- if (ret)
- return ret;
-
xfer->bits_per_word = scan_type->realbits;
xfer->offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
xfer->len = AD7380_SPI_BYTES(scan_type) * st->chip_info->num_simult_channels;
diff --git a/drivers/iio/adc/ad7405.c b/drivers/iio/adc/ad7405.c
new file mode 100644
index 000000000000..9adf85a732ce
--- /dev/null
+++ b/drivers/iio/adc/ad7405.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices AD7405 driver
+ *
+ * Copyright 2025 Analog Devices Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/util_macros.h>
+
+#include <linux/iio/backend.h>
+#include <linux/iio/iio.h>
+
+static const unsigned int ad7405_dec_rates_range[] = {
+ 32, 1, 4096,
+};
+
+struct ad7405_chip_info {
+ const char *name;
+ const unsigned int full_scale_mv;
+};
+
+struct ad7405_state {
+ struct iio_backend *back;
+ const struct ad7405_chip_info *info;
+ unsigned int ref_frequency;
+ unsigned int dec_rate;
+};
+
+static int ad7405_set_dec_rate(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int dec_rate)
+{
+ struct ad7405_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (dec_rate > 4096 || dec_rate < 32)
+ return -EINVAL;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = iio_backend_oversampling_ratio_set(st->back, chan->scan_index, dec_rate);
+ iio_device_release_direct(indio_dev);
+
+ if (ret < 0)
+ return ret;
+
+ st->dec_rate = dec_rate;
+
+ return 0;
+}
+
+static int ad7405_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan, int *val,
+ int *val2, long info)
+{
+ struct ad7405_state *st = iio_priv(indio_dev);
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ *val = st->info->full_scale_mv;
+ *val2 = indio_dev->channels[0].scan_type.realbits - 1;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = st->dec_rate;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = DIV_ROUND_CLOSEST_ULL(st->ref_frequency, st->dec_rate);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_OFFSET:
+ *val = -(1 << (indio_dev->channels[0].scan_type.realbits - 1));
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7405_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ if (val < 0)
+ return -EINVAL;
+ return ad7405_set_dec_rate(indio_dev, chan, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad7405_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = ad7405_dec_rates_range;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_info ad7405_iio_info = {
+ .read_raw = &ad7405_read_raw,
+ .write_raw = &ad7405_write_raw,
+ .read_avail = &ad7405_read_avail,
+};
+
+static const struct iio_chan_spec ad7405_channel = {
+ .type = IIO_VOLTAGE,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_OFFSET),
+ .info_mask_shared_by_all = IIO_CHAN_INFO_SAMP_FREQ |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all_available =
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .indexed = 1,
+ .channel = 0,
+ .channel2 = 1,
+ .differential = 1,
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 'u',
+ .realbits = 16,
+ .storagebits = 16,
+ },
+};
+
+static const struct ad7405_chip_info ad7405_chip_info = {
+ .name = "ad7405",
+ .full_scale_mv = 320,
+};
+
+static const struct ad7405_chip_info adum7701_chip_info = {
+ .name = "adum7701",
+ .full_scale_mv = 320,
+};
+
+static const struct ad7405_chip_info adum7702_chip_info = {
+ .name = "adum7702",
+ .full_scale_mv = 64,
+};
+
+static const struct ad7405_chip_info adum7703_chip_info = {
+ .name = "adum7703",
+ .full_scale_mv = 320,
+};
+
+static const char * const ad7405_power_supplies[] = {
+ "vdd1", "vdd2",
+};
+
+static int ad7405_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct ad7405_state *st;
+ struct clk *clk;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+
+ st->info = device_get_match_data(dev);
+ if (!st->info)
+ return dev_err_probe(dev, -EINVAL, "no chip info\n");
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad7405_power_supplies),
+ ad7405_power_supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get and enable supplies");
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(clk))
+ return PTR_ERR(clk);
+
+ st->ref_frequency = clk_get_rate(clk);
+ if (!st->ref_frequency)
+ return -EINVAL;
+
+ indio_dev->name = st->info->name;
+ indio_dev->channels = &ad7405_channel;
+ indio_dev->num_channels = 1;
+ indio_dev->info = &ad7405_iio_info;
+
+ st->back = devm_iio_backend_get(dev, NULL);
+ if (IS_ERR(st->back))
+ return dev_err_probe(dev, PTR_ERR(st->back),
+ "failed to get IIO backend");
+
+ ret = iio_backend_chan_enable(st->back, 0);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_backend_request_buffer(dev, st->back, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_backend_enable(dev, st->back);
+ if (ret)
+ return ret;
+
+ /*
+ * Set 256 decimation rate. The default value in the AXI_ADC register
+ * is 0, so we set the register with a decimation rate value that is
+ * functional for all parts.
+ */
+ ret = ad7405_set_dec_rate(indio_dev, &indio_dev->channels[0], 256);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ad7405_of_match[] = {
+ { .compatible = "adi,ad7405", .data = &ad7405_chip_info, },
+ { .compatible = "adi,adum7701", .data = &adum7701_chip_info, },
+ { .compatible = "adi,adum7702", .data = &adum7702_chip_info, },
+ { .compatible = "adi,adum7703", .data = &adum7703_chip_info, },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad7405_of_match);
+
+static struct platform_driver ad7405_driver = {
+ .driver = {
+ .name = "ad7405",
+ .of_match_table = ad7405_of_match,
+ },
+ .probe = ad7405_probe,
+};
+module_platform_driver(ad7405_driver);
+
+MODULE_AUTHOR("Dragos Bogdan <dragos.bogdan@analog.com>");
+MODULE_AUTHOR("Pop Ioan Daniel <pop.ioan-daniel@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD7405 driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_BACKEND");
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index ddb607ac1860..aea734aa06bd 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -435,6 +435,13 @@ static const struct spi_device_id ad7476_id[] = {
{ "ads7866", ID_ADS7866 },
{ "ads7867", ID_ADS7867 },
{ "ads7868", ID_ADS7868 },
+ /*
+ * The ROHM BU79100G is identical to the TI's ADS7866 from the software
+ * point of view. The binding document mandates the ADS7866 to be
+ * marked as a fallback for the BU79100G, but we still need the SPI ID
+ * here to make the module loading work.
+ */
+ { "bu79100g", ID_ADS7866 },
{ "ltc2314-14", ID_LTC2314_14 },
{ }
};
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index 185243dee86e..d9271894f091 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -33,6 +33,10 @@
#include "ad7606.h"
+#define AD7606_CALIB_GAIN_MIN 0
+#define AD7606_CALIB_GAIN_STEP 1024
+#define AD7606_CALIB_GAIN_MAX (63 * AD7606_CALIB_GAIN_STEP)
+
/*
* Scales are computed as 5000/32768 and 10000/32768 respectively,
* so that when applied to the raw values they provide mV values.
@@ -95,6 +99,22 @@ static const unsigned int ad7616_oversampling_avail[8] = {
1, 2, 4, 8, 16, 32, 64, 128,
};
+static const int ad7606_calib_offset_avail[3] = {
+ -128, 1, 127,
+};
+
+static const int ad7606c_18bit_calib_offset_avail[3] = {
+ -512, 4, 508,
+};
+
+static const int ad7606b_calib_phase_avail[][2] = {
+ { 0, 0 }, { 0, 1250 }, { 0, 318750 },
+};
+
+static const int ad7606c_calib_phase_avail[][2] = {
+ { 0, 0 }, { 0, 1000 }, { 0, 255000 },
+};
+
static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan);
static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
@@ -164,6 +184,9 @@ const struct ad7606_chip_info ad7606b_info = {
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_gain_avail = true,
+ .calib_offset_avail = ad7606_calib_offset_avail,
+ .calib_phase_avail = ad7606b_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606");
@@ -177,6 +200,9 @@ const struct ad7606_chip_info ad7606c_16_info = {
.scale_setup_cb = ad7606c_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_gain_avail = true,
+ .calib_offset_avail = ad7606_calib_offset_avail,
+ .calib_phase_avail = ad7606c_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606");
@@ -226,6 +252,9 @@ const struct ad7606_chip_info ad7606c_18_info = {
.scale_setup_cb = ad7606c_18bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_gain_avail = true,
+ .calib_offset_avail = ad7606c_18bit_calib_offset_avail,
+ .calib_phase_avail = ad7606c_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606");
@@ -261,21 +290,21 @@ static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
if (!st->sw_mode_en) {
/* tied to logic low, analog input range is +/- 5V */
- cs->range = 0;
- cs->scale_avail = ad7606_16bit_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7606_16bit_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
return 0;
}
/* Scale of 0.076293 is only available in sw mode */
/* After reset, in software mode, ±10 V is set by default */
- cs->range = 2;
- cs->scale_avail = ad7606_16bit_sw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail);
+ ci->range = 2;
+ ci->scale_avail = ad7606_16bit_sw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail);
return 0;
}
@@ -284,6 +313,7 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
bool *bipolar, bool *differential)
{
struct ad7606_state *st = iio_priv(indio_dev);
+ struct ad7606_chan_info *ci;
unsigned int num_channels = st->chip_info->num_adc_channels;
struct device *dev = st->dev;
int ret;
@@ -297,15 +327,13 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
ret = fwnode_property_read_u32(child, "reg", &reg);
if (ret)
- continue;
+ return ret;
/* channel number (here) is from 1 to num_channels */
- if (reg < 1 || reg > num_channels) {
- dev_warn(dev,
- "Invalid channel number (ignoring): %d\n", reg);
- continue;
- }
+ if (reg < 1 || reg > num_channels)
+ return -EINVAL;
+ /* Loop until we are in the right channel. */
if (reg != (ch + 1))
continue;
@@ -329,6 +357,14 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
return -EINVAL;
}
+ ci = &st->chan_info[reg - 1];
+
+ ci->r_gain = 0;
+ ret = fwnode_property_read_u32(child, "adi,rfilter-ohms",
+ &ci->r_gain);
+ if (ret == 0 && ci->r_gain > AD7606_CALIB_GAIN_MAX)
+ return -EINVAL;
+
return 0;
}
@@ -339,14 +375,14 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
bool bipolar, differential;
int ret;
if (!st->sw_mode_en) {
- cs->range = 0;
- cs->scale_avail = ad7606_18bit_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7606_18bit_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
return 0;
}
@@ -356,12 +392,12 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
return ret;
if (differential) {
- cs->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_18bit_differential_bipolar_scale_avail);
/* Bipolar differential ranges start at 8 (b1000) */
- cs->reg_offset = 8;
- cs->range = 1;
+ ci->reg_offset = 8;
+ ci->range = 1;
chan->differential = 1;
chan->channel2 = chan->channel;
@@ -371,23 +407,23 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
chan->differential = 0;
if (bipolar) {
- cs->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_18bit_single_ended_bipolar_scale_avail);
/* Bipolar single-ended ranges start at 0 (b0000) */
- cs->reg_offset = 0;
- cs->range = 3;
+ ci->reg_offset = 0;
+ ci->range = 3;
chan->scan_type.sign = 's';
return 0;
}
- cs->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_18bit_single_ended_unipolar_scale_avail);
/* Unipolar single-ended ranges start at 5 (b0101) */
- cs->reg_offset = 5;
- cs->range = 1;
+ ci->reg_offset = 5;
+ ci->range = 1;
chan->scan_type.sign = 'u';
return 0;
@@ -397,14 +433,14 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
bool bipolar, differential;
int ret;
if (!st->sw_mode_en) {
- cs->range = 0;
- cs->scale_avail = ad7606_16bit_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7606_16bit_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
return 0;
}
@@ -414,12 +450,12 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
return ret;
if (differential) {
- cs->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_16bit_differential_bipolar_scale_avail);
/* Bipolar differential ranges start at 8 (b1000) */
- cs->reg_offset = 8;
- cs->range = 1;
+ ci->reg_offset = 8;
+ ci->range = 1;
chan->differential = 1;
chan->channel2 = chan->channel;
chan->scan_type.sign = 's';
@@ -430,23 +466,23 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
chan->differential = 0;
if (bipolar) {
- cs->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_16bit_single_ended_bipolar_scale_avail);
/* Bipolar single-ended ranges start at 0 (b0000) */
- cs->reg_offset = 0;
- cs->range = 3;
+ ci->reg_offset = 0;
+ ci->range = 3;
chan->scan_type.sign = 's';
return 0;
}
- cs->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_16bit_single_ended_unipolar_scale_avail);
/* Unipolar single-ended ranges start at 5 (b0101) */
- cs->reg_offset = 5;
- cs->range = 1;
+ ci->reg_offset = 5;
+ ci->range = 1;
chan->scan_type.sign = 'u';
return 0;
@@ -456,11 +492,11 @@ static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
- cs->range = 0;
- cs->scale_avail = ad7607_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7607_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail);
return 0;
}
@@ -468,11 +504,11 @@ static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
- cs->range = 0;
- cs->scale_avail = ad7606_18bit_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7606_18bit_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
return 0;
}
@@ -480,11 +516,11 @@ static int ad7609_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
- cs->range = 0;
- cs->scale_avail = ad7609_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7609_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail);
return 0;
}
@@ -681,6 +717,40 @@ error_ret:
return ret;
}
+static int ad7606_get_calib_offset(struct ad7606_state *st, int ch, int *val)
+{
+ int ret;
+
+ ret = st->bops->reg_read(st, AD7606_CALIB_OFFSET(ch));
+ if (ret < 0)
+ return ret;
+
+ *val = st->chip_info->calib_offset_avail[0] +
+ ret * st->chip_info->calib_offset_avail[1];
+
+ return 0;
+}
+
+static int ad7606_get_calib_phase(struct ad7606_state *st, int ch, int *val,
+ int *val2)
+{
+ int ret;
+
+ ret = st->bops->reg_read(st, AD7606_CALIB_PHASE(ch));
+ if (ret < 0)
+ return ret;
+
+ *val = 0;
+
+ /*
+ * ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs.
+ * ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs.
+ */
+ *val2 = ret * st->chip_info->calib_phase_avail[1][1];
+
+ return 0;
+}
+
static int ad7606_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
@@ -689,7 +759,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
{
int ret, ch = 0;
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs;
+ struct ad7606_chan_info *ci;
struct pwm_state cnvst_pwm_state;
switch (m) {
@@ -704,9 +774,9 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
ch = chan->scan_index;
- cs = &st->chan_scales[ch];
- *val = cs->scale_avail[cs->range][0];
- *val2 = cs->scale_avail[cs->range][1];
+ ci = &st->chan_info[ch];
+ *val = ci->scale_avail[ci->range][0];
+ *val2 = ci->scale_avail[ci->range][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = st->oversampling;
@@ -715,6 +785,22 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
*val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period);
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ad7606_get_calib_offset(st, chan->scan_index, val);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CONVDELAY:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ad7606_get_calib_phase(st, chan->scan_index, val, val2);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT_PLUS_NANO;
}
return -EINVAL;
}
@@ -725,12 +811,12 @@ static ssize_t in_voltage_scale_available_show(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[0];
- const unsigned int (*vals)[2] = cs->scale_avail;
+ struct ad7606_chan_info *ci = &st->chan_info[0];
+ const unsigned int (*vals)[2] = ci->scale_avail;
unsigned int i;
size_t len = 0;
- for (i = 0; i < cs->num_scales; i++)
+ for (i = 0; i < ci->num_scales; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
vals[i][0], vals[i][1]);
buf[len - 1] = '\n';
@@ -765,6 +851,64 @@ static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val)
return 0;
}
+static int ad7606_set_calib_offset(struct ad7606_state *st, int ch, int val)
+{
+ int start_val, step_val, stop_val;
+ int offset;
+
+ start_val = st->chip_info->calib_offset_avail[0];
+ step_val = st->chip_info->calib_offset_avail[1];
+ stop_val = st->chip_info->calib_offset_avail[2];
+
+ if (val < start_val || val > stop_val)
+ return -EINVAL;
+
+ offset = (val - start_val) / step_val;
+
+ return st->bops->reg_write(st, AD7606_CALIB_OFFSET(ch), offset);
+}
+
+static int ad7606_set_calib_phase(struct ad7606_state *st, int ch, int val,
+ int val2)
+{
+ int wreg, start_ns, step_ns, stop_ns;
+
+ if (val != 0)
+ return -EINVAL;
+
+ start_ns = st->chip_info->calib_phase_avail[0][1];
+ step_ns = st->chip_info->calib_phase_avail[1][1];
+ stop_ns = st->chip_info->calib_phase_avail[2][1];
+
+ /*
+ * ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs.
+ * ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs.
+ */
+ if (val2 < start_ns || val2 > stop_ns)
+ return -EINVAL;
+
+ wreg = val2 / step_ns;
+
+ return st->bops->reg_write(st, AD7606_CALIB_PHASE(ch), wreg);
+}
+
+static int ad7606_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CONVDELAY:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
static int ad7606_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
@@ -773,7 +917,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned int scale_avail_uv[AD760X_MAX_SCALES];
- struct ad7606_chan_scale *cs;
+ struct ad7606_chan_info *ci;
int i, ret, ch = 0;
guard(mutex)(&st->lock);
@@ -782,21 +926,21 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
ch = chan->scan_index;
- cs = &st->chan_scales[ch];
- for (i = 0; i < cs->num_scales; i++) {
- scale_avail_uv[i] = cs->scale_avail[i][0] * MICRO +
- cs->scale_avail[i][1];
+ ci = &st->chan_info[ch];
+ for (i = 0; i < ci->num_scales; i++) {
+ scale_avail_uv[i] = ci->scale_avail[i][0] * MICRO +
+ ci->scale_avail[i][1];
}
val = (val * MICRO) + val2;
- i = find_closest(val, scale_avail_uv, cs->num_scales);
+ i = find_closest(val, scale_avail_uv, ci->num_scales);
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
- ret = st->write_scale(indio_dev, ch, i + cs->reg_offset);
+ ret = st->write_scale(indio_dev, ch, i + ci->reg_offset);
iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
- cs->range = i;
+ ci->range = i;
return 0;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
@@ -818,6 +962,18 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
if (val < 0 && val2 != 0)
return -EINVAL;
return ad7606_set_sampling_freq(st, val);
+ case IIO_CHAN_INFO_CALIBBIAS:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ad7606_set_calib_offset(st, chan->scan_index, val);
+ iio_device_release_direct(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_CONVDELAY:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ad7606_set_calib_phase(st, chan->scan_index, val, val2);
+ iio_device_release_direct(indio_dev);
+ return ret;
default:
return -EINVAL;
}
@@ -975,7 +1131,7 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
long info)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs;
+ struct ad7606_chan_info *ci;
unsigned int ch = 0;
switch (info) {
@@ -990,12 +1146,20 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
if (st->sw_mode_en)
ch = chan->scan_index;
- cs = &st->chan_scales[ch];
- *vals = (int *)cs->scale_avail;
- *length = cs->num_scales * 2;
+ ci = &st->chan_info[ch];
+ *vals = (int *)ci->scale_avail;
+ *length = ci->num_scales * 2;
*type = IIO_VAL_INT_PLUS_MICRO;
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *vals = st->chip_info->calib_offset_avail;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ case IIO_CHAN_INFO_CONVDELAY:
+ *vals = (const int *)st->chip_info->calib_phase_avail;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_RANGE;
}
return -EINVAL;
}
@@ -1058,6 +1222,7 @@ static const struct iio_info ad7606_info_sw_mode = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.read_avail = &ad7606_read_avail,
+ .write_raw_get_fmt = ad7606_write_raw_get_fmt,
.debugfs_reg_access = &ad7606_reg_access,
.validate_trigger = &ad7606_validate_trigger,
.update_scan_mode = &ad7606_update_scan_mode,
@@ -1203,6 +1368,23 @@ static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev)
return st->bops->sw_mode_config(indio_dev);
}
+static int ad7606_set_gain_calib(struct ad7606_state *st)
+{
+ struct ad7606_chan_info *ci;
+ int i, ret;
+
+ for (i = 0; i < st->chip_info->num_adc_channels; i++) {
+ ci = &st->chan_info[i];
+ ret = st->bops->reg_write(st, AD7606_CALIB_GAIN(i),
+ DIV_ROUND_CLOSEST(ci->r_gain,
+ AD7606_CALIB_GAIN_STEP));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int ad7606_probe_channels(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
@@ -1250,6 +1432,15 @@ static int ad7606_probe_channels(struct iio_dev *indio_dev)
chan->info_mask_separate_available |=
BIT(IIO_CHAN_INFO_SCALE);
+ if (st->chip_info->calib_offset_avail) {
+ chan->info_mask_separate |=
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_CONVDELAY);
+ chan->info_mask_separate_available |=
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_CONVDELAY);
+ }
+
/*
* All chips with software mode support oversampling,
* so we skip the oversampling_available check. And the
@@ -1330,6 +1521,16 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
return dev_err_probe(dev, ret,
"Failed to enable specified AVcc supply\n");
+ ret = devm_regulator_get_enable(dev, "vdrive");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable Vdrive supply\n");
+
+ ret = devm_regulator_get_enable_optional(dev, "refin");
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(dev, ret,
+ "Failed to enable REFIN supply\n");
+
st->chip_info = chip_info;
if (st->chip_info->oversampling_num) {
@@ -1462,6 +1663,12 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
st->chip_info->sw_setup_cb(indio_dev);
}
+ if (st->sw_mode_en && st->chip_info->calib_gain_avail) {
+ ret = ad7606_set_gain_calib(st);
+ if (ret)
+ return ret;
+ }
+
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(ad7606_probe, "IIO_AD7606");
@@ -1487,7 +1694,7 @@ static int ad7606_resume(struct device *dev)
struct ad7606_state *st = iio_priv(indio_dev);
if (st->gpio_standby) {
- gpiod_set_value(st->gpio_range, st->chan_scales[0].range);
+ gpiod_set_value(st->gpio_range, st->chan_info[0].range);
gpiod_set_value(st->gpio_standby, 1);
ad7606_reset(st);
}
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index 441e62c521bc..2951bb731354 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -40,6 +40,11 @@
#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1))
#define AD7606_OS_MODE 0x08
+#define AD7606_CALIB_GAIN(ch) (0x09 + (ch))
+#define AD7606_CALIB_GAIN_MASK GENMASK(5, 0)
+#define AD7606_CALIB_OFFSET(ch) (0x11 + (ch))
+#define AD7606_CALIB_PHASE(ch) (0x19 + (ch))
+
struct ad7606_state;
typedef int (*ad7606_scale_setup_cb_t)(struct iio_dev *indio_dev,
@@ -61,6 +66,9 @@ typedef int (*ad7606_sw_setup_cb_t)(struct iio_dev *indio_dev);
* @init_delay_ms: required delay in milliseconds for initialization
* after a restart
* @offload_storagebits: storage bits used by the offload hw implementation
+ * @calib_gain_avail: chip supports gain calibration
+ * @calib_offset_avail: pointer to offset calibration range/limits array
+ * @calib_phase_avail: pointer to phase calibration range/limits array
*/
struct ad7606_chip_info {
unsigned int max_samplerate;
@@ -74,22 +82,28 @@ struct ad7606_chip_info {
bool os_req_reset;
unsigned long init_delay_ms;
u8 offload_storagebits;
+ bool calib_gain_avail;
+ const int *calib_offset_avail;
+ const int (*calib_phase_avail)[2];
};
/**
- * struct ad7606_chan_scale - channel scale configuration
+ * struct ad7606_chan_info - channel configuration
* @scale_avail: pointer to the array which stores the available scales
* @num_scales: number of elements stored in the scale_avail array
* @range: voltage range selection, selects which scale to apply
* @reg_offset: offset for the register value, to be applied when
* writing the value of 'range' to the register value
+ * @r_gain: gain resistor value in ohms, to be set to match the
+ * external r_filter value
*/
-struct ad7606_chan_scale {
+struct ad7606_chan_info {
#define AD760X_MAX_SCALES 16
const unsigned int (*scale_avail)[2];
unsigned int num_scales;
unsigned int range;
unsigned int reg_offset;
+ unsigned int r_gain;
};
/**
@@ -97,7 +111,7 @@ struct ad7606_chan_scale {
* @dev: pointer to kernel device
* @chip_info: entry in the table of chips that describes this device
* @bops: bus operations (SPI or parallel)
- * @chan_scales: scale configuration for channels
+ * @chan_info: scale configuration for channels
* @oversampling: oversampling selection
* @cnvst_pwm: pointer to the PWM device connected to the cnvst pin
* @base_address: address from where to read data in parallel operation
@@ -128,7 +142,7 @@ struct ad7606_state {
struct device *dev;
const struct ad7606_chip_info *chip_info;
const struct ad7606_bus_ops *bops;
- struct ad7606_chan_scale chan_scales[AD760X_MAX_CHANNELS];
+ struct ad7606_chan_info chan_info[AD760X_MAX_CHANNELS];
unsigned int oversampling;
struct pwm_device *cnvst_pwm;
void __iomem *base_address;
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index 51134023534a..a2e061f0cb08 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -11,13 +11,19 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
+#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
+#include <linux/minmax.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
+#include <linux/regulator/driver.h>
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+#include <linux/util_macros.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
@@ -26,6 +32,8 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/iio/trigger_consumer.h>
+#include <dt-bindings/iio/adc/adi,ad7768-1.h>
+
/* AD7768 registers definition */
#define AD7768_REG_CHIP_TYPE 0x3
#define AD7768_REG_PROD_ID_L 0x4
@@ -73,6 +81,7 @@
#define AD7768_PWR_PWRMODE(x) FIELD_PREP(AD7768_PWR_PWRMODE_MSK, x)
/* AD7768_REG_DIGITAL_FILTER */
+#define AD7768_DIG_FIL_EN_60HZ_REJ BIT(7)
#define AD7768_DIG_FIL_FIL_MSK GENMASK(6, 4)
#define AD7768_DIG_FIL_FIL(x) FIELD_PREP(AD7768_DIG_FIL_FIL_MSK, x)
#define AD7768_DIG_FIL_DEC_MSK GENMASK(2, 0)
@@ -82,6 +91,26 @@
#define AD7768_CONV_MODE_MSK GENMASK(2, 0)
#define AD7768_CONV_MODE(x) FIELD_PREP(AD7768_CONV_MODE_MSK, x)
+/* AD7768_REG_ANALOG2 */
+#define AD7768_REG_ANALOG2_VCM_MSK GENMASK(2, 0)
+#define AD7768_REG_ANALOG2_VCM(x) FIELD_PREP(AD7768_REG_ANALOG2_VCM_MSK, (x))
+
+/* AD7768_REG_GPIO_CONTROL */
+#define AD7768_GPIO_UNIVERSAL_EN BIT(7)
+#define AD7768_GPIO_CONTROL_MSK GENMASK(3, 0)
+
+/* AD7768_REG_GPIO_WRITE */
+#define AD7768_GPIO_WRITE_MSK GENMASK(3, 0)
+
+/* AD7768_REG_GPIO_READ */
+#define AD7768_GPIO_READ_MSK GENMASK(3, 0)
+
+#define AD7768_VCM_OFF 0x07
+
+#define AD7768_TRIGGER_SOURCE_SYNC_IDX 0
+
+#define AD7768_MAX_CHANNELS 1
+
enum ad7768_conv_mode {
AD7768_CONTINUOUS,
AD7768_ONE_SHOT,
@@ -103,54 +132,84 @@ enum ad7768_mclk_div {
AD7768_MCLK_DIV_2
};
-enum ad7768_dec_rate {
- AD7768_DEC_RATE_32 = 0,
- AD7768_DEC_RATE_64 = 1,
- AD7768_DEC_RATE_128 = 2,
- AD7768_DEC_RATE_256 = 3,
- AD7768_DEC_RATE_512 = 4,
- AD7768_DEC_RATE_1024 = 5,
- AD7768_DEC_RATE_8 = 9,
- AD7768_DEC_RATE_16 = 10
+enum ad7768_filter_type {
+ AD7768_FILTER_SINC5,
+ AD7768_FILTER_SINC3,
+ AD7768_FILTER_WIDEBAND,
+ AD7768_FILTER_SINC3_REJ60,
};
-struct ad7768_clk_configuration {
- enum ad7768_mclk_div mclk_div;
- enum ad7768_dec_rate dec_rate;
- unsigned int clk_div;
- enum ad7768_pwrmode pwrmode;
+enum ad7768_filter_regval {
+ AD7768_FILTER_REGVAL_SINC5 = 0,
+ AD7768_FILTER_REGVAL_SINC5_X8 = 1,
+ AD7768_FILTER_REGVAL_SINC5_X16 = 2,
+ AD7768_FILTER_REGVAL_SINC3 = 3,
+ AD7768_FILTER_REGVAL_WIDEBAND = 4,
+ AD7768_FILTER_REGVAL_SINC3_REJ60 = 11,
};
-static const struct ad7768_clk_configuration ad7768_clk_config[] = {
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_8, 16, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_16, 32, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_32, 64, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_64, 128, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_2, AD7768_DEC_RATE_128, 256, AD7768_FAST_MODE },
- { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_128, 512, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_256, 1024, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_512, 2048, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_4, AD7768_DEC_RATE_1024, 4096, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_8, AD7768_DEC_RATE_1024, 8192, AD7768_MED_MODE },
- { AD7768_MCLK_DIV_16, AD7768_DEC_RATE_1024, 16384, AD7768_ECO_MODE },
+enum ad7768_scan_type {
+ AD7768_SCAN_TYPE_NORMAL,
+ AD7768_SCAN_TYPE_HIGH_SPEED,
};
-static const struct iio_chan_spec ad7768_channels[] = {
- {
- .type = IIO_VOLTAGE,
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
- .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
- .indexed = 1,
- .channel = 0,
- .scan_index = 0,
- .scan_type = {
- .sign = 's',
- .realbits = 24,
- .storagebits = 32,
- .shift = 8,
- .endianness = IIO_BE,
- },
+/* -3dB cutoff frequency multipliers (relative to ODR) for each filter type. */
+static const int ad7768_filter_3db_odr_multiplier[] = {
+ [AD7768_FILTER_SINC5] = 204, /* 0.204 */
+ [AD7768_FILTER_SINC3] = 262, /* 0.2617 */
+ [AD7768_FILTER_SINC3_REJ60] = 262, /* 0.2617 */
+ [AD7768_FILTER_WIDEBAND] = 433, /* 0.433 */
+};
+
+static const int ad7768_mclk_div_rates[] = {
+ 16, 8, 4, 2,
+};
+
+static const int ad7768_dec_rate_values[8] = {
+ 8, 16, 32, 64, 128, 256, 512, 1024,
+};
+
+/* Decimation rate range for sinc3 filter */
+static const int ad7768_sinc3_dec_rate_range[3] = {
+ 32, 32, 163840,
+};
+
+/*
+ * The AD7768-1 supports three primary filter types:
+ * Sinc5, Sinc3, and Wideband.
+ * However, the filter register values can also encode additional parameters
+ * such as decimation rates and 60Hz rejection. This utility array separates
+ * the filter type from these parameters.
+ */
+static const int ad7768_filter_regval_to_type[] = {
+ [AD7768_FILTER_REGVAL_SINC5] = AD7768_FILTER_SINC5,
+ [AD7768_FILTER_REGVAL_SINC5_X8] = AD7768_FILTER_SINC5,
+ [AD7768_FILTER_REGVAL_SINC5_X16] = AD7768_FILTER_SINC5,
+ [AD7768_FILTER_REGVAL_SINC3] = AD7768_FILTER_SINC3,
+ [AD7768_FILTER_REGVAL_WIDEBAND] = AD7768_FILTER_WIDEBAND,
+ [AD7768_FILTER_REGVAL_SINC3_REJ60] = AD7768_FILTER_SINC3_REJ60,
+};
+
+static const char * const ad7768_filter_enum[] = {
+ [AD7768_FILTER_SINC5] = "sinc5",
+ [AD7768_FILTER_SINC3] = "sinc3",
+ [AD7768_FILTER_WIDEBAND] = "wideband",
+ [AD7768_FILTER_SINC3_REJ60] = "sinc3+rej60",
+};
+
+static const struct iio_scan_type ad7768_scan_type[] = {
+ [AD7768_SCAN_TYPE_NORMAL] = {
+ .sign = 's',
+ .realbits = 24,
+ .storagebits = 32,
+ .shift = 8,
+ .endianness = IIO_BE,
+ },
+ [AD7768_SCAN_TYPE_HIGH_SPEED] = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
},
};
@@ -159,14 +218,23 @@ struct ad7768_state {
struct regmap *regmap;
struct regmap *regmap24;
struct regulator *vref;
+ struct regulator_dev *vcm_rdev;
+ unsigned int vcm_output_sel;
struct clk *mclk;
unsigned int mclk_freq;
+ unsigned int mclk_div;
+ unsigned int oversampling_ratio;
+ enum ad7768_filter_type filter_type;
unsigned int samp_freq;
+ unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_mclk_div_rates)];
+ unsigned int samp_freq_avail_len;
struct completion completion;
struct iio_trigger *trig;
struct gpio_desc *gpio_sync_in;
struct gpio_desc *gpio_reset;
- const char *labels[ARRAY_SIZE(ad7768_channels)];
+ const char *labels[AD7768_MAX_CHANNELS];
+ struct gpio_chip gpiochip;
+ bool en_spi_sync;
/*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
@@ -252,6 +320,63 @@ static const struct regmap_config ad7768_regmap24_config = {
.max_register = AD7768_REG24_COEFF_DATA,
};
+static int ad7768_send_sync_pulse(struct ad7768_state *st)
+{
+ if (st->en_spi_sync)
+ return regmap_write(st->regmap, AD7768_REG_SYNC_RESET, 0x00);
+
+ /*
+ * The datasheet specifies a minimum SYNC_IN pulse width of 1.5 × Tmclk,
+ * where Tmclk is the MCLK period. The supported MCLK frequencies range
+ * from 0.6 MHz to 17 MHz, which corresponds to a minimum SYNC_IN pulse
+ * width of approximately 2.5 µs in the worst-case scenario (0.6 MHz).
+ *
+ * Add a delay to ensure the pulse width is always sufficient to
+ * trigger synchronization.
+ */
+ gpiod_set_value_cansleep(st->gpio_sync_in, 1);
+ fsleep(3);
+ gpiod_set_value_cansleep(st->gpio_sync_in, 0);
+
+ return 0;
+}
+
+static void ad7768_fill_samp_freq_tbl(struct ad7768_state *st)
+{
+ unsigned int i, samp_freq_avail, freq_filtered;
+ unsigned int len = 0;
+
+ freq_filtered = DIV_ROUND_CLOSEST(st->mclk_freq, st->oversampling_ratio);
+ for (i = 0; i < ARRAY_SIZE(ad7768_mclk_div_rates); i++) {
+ samp_freq_avail = DIV_ROUND_CLOSEST(freq_filtered, ad7768_mclk_div_rates[i]);
+ /* Sampling frequency cannot be lower than the minimum of 50 SPS */
+ if (samp_freq_avail < 50)
+ continue;
+
+ st->samp_freq_avail[len++] = samp_freq_avail;
+ }
+
+ st->samp_freq_avail_len = len;
+}
+
+static int ad7768_set_mclk_div(struct ad7768_state *st, unsigned int mclk_div)
+{
+ unsigned int mclk_div_value;
+
+ mclk_div_value = AD7768_PWR_MCLK_DIV(mclk_div);
+ /*
+ * Set power mode based on mclk_div value.
+ * ECO_MODE is only recommended for MCLK_DIV = 16.
+ */
+ mclk_div_value |= mclk_div > AD7768_MCLK_DIV_16 ?
+ AD7768_PWR_PWRMODE(AD7768_FAST_MODE) :
+ AD7768_PWR_PWRMODE(AD7768_ECO_MODE);
+
+ return regmap_update_bits(st->regmap, AD7768_REG_POWER_CLOCK,
+ AD7768_PWR_MCLK_DIV_MSK | AD7768_PWR_PWRMODE_MSK,
+ mclk_div_value);
+}
+
static int ad7768_set_mode(struct ad7768_state *st,
enum ad7768_conv_mode mode)
{
@@ -280,6 +405,15 @@ static int ad7768_scan_direct(struct iio_dev *indio_dev)
return ret;
/*
+ * When the decimation rate is set to x8, the ADC data precision is
+ * reduced from 24 bits to 16 bits. Since the AD7768_REG_ADC_DATA
+ * register provides 24-bit data, the precision is reduced by
+ * right-shifting the read value by 8 bits.
+ */
+ if (st->oversampling_ratio == 8)
+ readval >>= 8;
+
+ /*
* Any SPI configuration of the AD7768-1 can only be
* performed in continuous conversion mode.
*/
@@ -323,96 +457,330 @@ static int ad7768_reg_access(struct iio_dev *indio_dev,
return ret;
}
-static int ad7768_set_dig_fil(struct ad7768_state *st,
- enum ad7768_dec_rate dec_rate)
+static int ad7768_set_sinc3_dec_rate(struct ad7768_state *st,
+ unsigned int dec_rate)
{
- unsigned int mode;
+ unsigned int max_dec_rate;
+ u8 dec_rate_reg[2];
+ u16 regval;
int ret;
- if (dec_rate == AD7768_DEC_RATE_8 || dec_rate == AD7768_DEC_RATE_16)
- mode = AD7768_DIG_FIL_FIL(dec_rate);
- else
- mode = AD7768_DIG_FIL_DEC_RATE(dec_rate);
+ /*
+ * Maximum dec_rate is limited by the MCLK_DIV value and by the ODR.
+ * The edge case is for MCLK_DIV = 2, ODR = 50 SPS.
+ * max_dec_rate <= MCLK / (2 * 50)
+ */
+ max_dec_rate = st->mclk_freq / 100;
+ dec_rate = clamp(dec_rate, 32, max_dec_rate);
+ /*
+ * Calculate the equivalent value to sinc3 decimation ratio
+ * to be written on the SINC3_DEC_RATE register:
+ * Value = (DEC_RATE / 32) - 1
+ */
+ dec_rate = DIV_ROUND_UP(dec_rate, 32) - 1;
- ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, mode);
- if (ret < 0)
+ /*
+ * The SINC3_DEC_RATE value is a 13-bit value split across two
+ * registers: MSB [12:8] and LSB [7:0]. Prepare the 13-bit value using
+ * FIELD_PREP() and store it with the right endianness in dec_rate_reg.
+ */
+ regval = FIELD_PREP(GENMASK(12, 0), dec_rate);
+ put_unaligned_be16(regval, dec_rate_reg);
+ ret = regmap_bulk_write(st->regmap, AD7768_REG_SINC3_DEC_RATE_MSB,
+ dec_rate_reg, 2);
+ if (ret)
return ret;
- /* A sync-in pulse is required every time the filter dec rate changes */
- gpiod_set_value(st->gpio_sync_in, 1);
- gpiod_set_value(st->gpio_sync_in, 0);
+ st->oversampling_ratio = (dec_rate + 1) * 32;
return 0;
}
-static int ad7768_set_freq(struct ad7768_state *st,
- unsigned int freq)
+static int ad7768_configure_dig_fil(struct iio_dev *dev,
+ enum ad7768_filter_type filter_type,
+ unsigned int dec_rate)
{
- unsigned int diff_new, diff_old, pwr_mode, i, idx;
- int res, ret;
+ struct ad7768_state *st = iio_priv(dev);
+ unsigned int dec_rate_idx, dig_filter_regval;
+ int ret;
- diff_old = U32_MAX;
- idx = 0;
+ switch (filter_type) {
+ case AD7768_FILTER_SINC3:
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3);
+ break;
+ case AD7768_FILTER_SINC3_REJ60:
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC3) |
+ AD7768_DIG_FIL_EN_60HZ_REJ;
+ break;
+ case AD7768_FILTER_WIDEBAND:
+ /* Skip decimations 8 and 16, not supported by the wideband filter */
+ dec_rate_idx = find_closest(dec_rate, &ad7768_dec_rate_values[2],
+ ARRAY_SIZE(ad7768_dec_rate_values) - 2);
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_WIDEBAND) |
+ AD7768_DIG_FIL_DEC_RATE(dec_rate_idx);
+ /* Correct the index offset */
+ dec_rate_idx += 2;
+ break;
+ case AD7768_FILTER_SINC5:
+ dec_rate_idx = find_closest(dec_rate, ad7768_dec_rate_values,
+ ARRAY_SIZE(ad7768_dec_rate_values));
- res = DIV_ROUND_CLOSEST(st->mclk_freq, freq);
+ /*
+ * Decimations 8 (idx 0) and 16 (idx 1) are set in the
+ * FILTER[6:4] field. The other decimations are set in the
+ * DEC_RATE[2:0] field, and the idx needs to be offsetted by two.
+ */
+ if (dec_rate_idx == 0)
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X8);
+ else if (dec_rate_idx == 1)
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5_X16);
+ else
+ dig_filter_regval = AD7768_DIG_FIL_FIL(AD7768_FILTER_REGVAL_SINC5) |
+ AD7768_DIG_FIL_DEC_RATE(dec_rate_idx - 2);
+ break;
+ }
- /* Find the closest match for the desired sampling frequency */
- for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) {
- diff_new = abs(res - ad7768_clk_config[i].clk_div);
- if (diff_new < diff_old) {
- diff_old = diff_new;
- idx = i;
- }
+ ret = regmap_write(st->regmap, AD7768_REG_DIGITAL_FILTER, dig_filter_regval);
+ if (ret)
+ return ret;
+
+ st->filter_type = filter_type;
+ /*
+ * The decimation for SINC3 filters are configured in different
+ * registers.
+ */
+ if (filter_type == AD7768_FILTER_SINC3 ||
+ filter_type == AD7768_FILTER_SINC3_REJ60) {
+ ret = ad7768_set_sinc3_dec_rate(st, dec_rate);
+ if (ret)
+ return ret;
+ } else {
+ st->oversampling_ratio = ad7768_dec_rate_values[dec_rate_idx];
}
+ ad7768_fill_samp_freq_tbl(st);
+
+ /* A sync-in pulse is required after every configuration change */
+ return ad7768_send_sync_pulse(st);
+}
+
+static int ad7768_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
+{
+ struct iio_dev *indio_dev = gpiochip_get_data(chip);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_clear_bits(st->regmap, AD7768_REG_GPIO_CONTROL,
+ BIT(offset));
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad7768_gpio_direction_output(struct gpio_chip *chip,
+ unsigned int offset, int value)
+{
+ struct iio_dev *indio_dev = gpiochip_get_data(chip);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_set_bits(st->regmap, AD7768_REG_GPIO_CONTROL,
+ BIT(offset));
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad7768_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct iio_dev *indio_dev = gpiochip_get_data(chip);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ unsigned int val;
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &val);
+ if (ret)
+ goto err_release;
+
/*
- * Set both the mclk_div and pwrmode with a single write to the
- * POWER_CLOCK register
+ * If the GPIO is configured as an output, read the current value from
+ * AD7768_REG_GPIO_WRITE. Otherwise, read the input value from
+ * AD7768_REG_GPIO_READ.
*/
- pwr_mode = AD7768_PWR_MCLK_DIV(ad7768_clk_config[idx].mclk_div) |
- AD7768_PWR_PWRMODE(ad7768_clk_config[idx].pwrmode);
- ret = regmap_write(st->regmap, AD7768_REG_POWER_CLOCK, pwr_mode);
- if (ret < 0)
+ if (val & BIT(offset))
+ ret = regmap_read(st->regmap, AD7768_REG_GPIO_WRITE, &val);
+ else
+ ret = regmap_read(st->regmap, AD7768_REG_GPIO_READ, &val);
+ if (ret)
+ goto err_release;
+
+ ret = !!(val & BIT(offset));
+err_release:
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad7768_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
+{
+ struct iio_dev *indio_dev = gpiochip_get_data(chip);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ unsigned int val;
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_read(st->regmap, AD7768_REG_GPIO_CONTROL, &val);
+ if (ret)
+ goto err_release;
+
+ if (val & BIT(offset))
+ ret = regmap_assign_bits(st->regmap, AD7768_REG_GPIO_WRITE,
+ BIT(offset), value);
+
+err_release:
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad7768_gpio_init(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = regmap_write(st->regmap, AD7768_REG_GPIO_CONTROL,
+ AD7768_GPIO_UNIVERSAL_EN);
+ if (ret)
return ret;
- ret = ad7768_set_dig_fil(st, ad7768_clk_config[idx].dec_rate);
- if (ret < 0)
+ st->gpiochip = (struct gpio_chip) {
+ .label = "ad7768_1_gpios",
+ .base = -1,
+ .ngpio = 4,
+ .parent = &st->spi->dev,
+ .can_sleep = true,
+ .direction_input = ad7768_gpio_direction_input,
+ .direction_output = ad7768_gpio_direction_output,
+ .get = ad7768_gpio_get,
+ .set_rv = ad7768_gpio_set,
+ .owner = THIS_MODULE,
+ };
+
+ return devm_gpiochip_add_data(&st->spi->dev, &st->gpiochip, indio_dev);
+}
+
+static int ad7768_set_freq(struct ad7768_state *st,
+ unsigned int freq)
+{
+ unsigned int idx, mclk_div;
+ int ret;
+
+ freq = clamp(freq, 50, 1024000);
+ if (freq == 0)
+ return -EINVAL;
+
+ mclk_div = DIV_ROUND_CLOSEST(st->mclk_freq, freq * st->oversampling_ratio);
+ /* Find the closest match for the desired sampling frequency */
+ idx = find_closest_descending(mclk_div, ad7768_mclk_div_rates,
+ ARRAY_SIZE(ad7768_mclk_div_rates));
+ /* Set both the mclk_div and pwrmode */
+ ret = ad7768_set_mclk_div(st, idx);
+ if (ret)
return ret;
st->samp_freq = DIV_ROUND_CLOSEST(st->mclk_freq,
- ad7768_clk_config[idx].clk_div);
+ ad7768_mclk_div_rates[idx] * st->oversampling_ratio);
- return 0;
+ /* A sync-in pulse is required after every configuration change */
+ return ad7768_send_sync_pulse(st);
}
-static ssize_t ad7768_sampling_freq_avail(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static int ad7768_set_filter_type_attr(struct iio_dev *dev,
+ const struct iio_chan_spec *chan,
+ unsigned int filter)
{
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct ad7768_state *st = iio_priv(indio_dev);
- unsigned int freq;
- int i, len = 0;
+ struct ad7768_state *st = iio_priv(dev);
+ int ret;
- for (i = 0; i < ARRAY_SIZE(ad7768_clk_config); i++) {
- freq = DIV_ROUND_CLOSEST(st->mclk_freq,
- ad7768_clk_config[i].clk_div);
- len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", freq);
- }
+ ret = ad7768_configure_dig_fil(dev, filter, st->oversampling_ratio);
+ if (ret)
+ return ret;
+
+ /* Update sampling frequency */
+ return ad7768_set_freq(st, st->samp_freq);
+}
+
+static int ad7768_get_filter_type_attr(struct iio_dev *dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad7768_state *st = iio_priv(dev);
+ int ret;
+ unsigned int mode, mask;
- buf[len - 1] = '\n';
+ ret = regmap_read(st->regmap, AD7768_REG_DIGITAL_FILTER, &mode);
+ if (ret)
+ return ret;
- return len;
+ mask = AD7768_DIG_FIL_EN_60HZ_REJ | AD7768_DIG_FIL_FIL_MSK;
+ /* From the register value, get the corresponding filter type */
+ return ad7768_filter_regval_to_type[FIELD_GET(mask, mode)];
}
-static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(ad7768_sampling_freq_avail);
+static const struct iio_enum ad7768_filter_type_iio_enum = {
+ .items = ad7768_filter_enum,
+ .num_items = ARRAY_SIZE(ad7768_filter_enum),
+ .set = ad7768_set_filter_type_attr,
+ .get = ad7768_get_filter_type_attr,
+};
+
+static const struct iio_chan_spec_ext_info ad7768_ext_info[] = {
+ IIO_ENUM("filter_type", IIO_SHARED_BY_ALL, &ad7768_filter_type_iio_enum),
+ IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_ALL, &ad7768_filter_type_iio_enum),
+ { }
+};
+
+static const struct iio_chan_spec ad7768_channels[] = {
+ {
+ .type = IIO_VOLTAGE,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .ext_info = ad7768_ext_info,
+ .indexed = 1,
+ .channel = 0,
+ .scan_index = 0,
+ .has_ext_scan_type = 1,
+ .ext_scan_type = ad7768_scan_type,
+ .num_ext_scan_type = ARRAY_SIZE(ad7768_scan_type),
+ },
+};
static int ad7768_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long info)
{
struct ad7768_state *st = iio_priv(indio_dev);
- int scale_uv, ret;
+ const struct iio_scan_type *scan_type;
+ int scale_uv, ret, temp;
+
+ scan_type = iio_get_current_scan_type(indio_dev, chan);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
switch (info) {
case IIO_CHAN_INFO_RAW:
@@ -424,7 +792,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
- *val = sign_extend32(ret, chan->scan_type.realbits - 1);
+ *val = sign_extend32(ret, scan_type->realbits - 1);
return IIO_VAL_INT;
@@ -434,7 +802,7 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
return scale_uv;
*val = (scale_uv * 2) / 1000;
- *val2 = chan->scan_type.realbits;
+ *val2 = scan_type->realbits;
return IIO_VAL_FRACTIONAL_LOG2;
@@ -442,25 +810,96 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
*val = st->samp_freq;
return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *val = st->oversampling_ratio;
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
+ temp = st->samp_freq * ad7768_filter_3db_odr_multiplier[st->filter_type];
+ *val = DIV_ROUND_CLOSEST(temp, MILLI);
+
+ return IIO_VAL_INT;
}
return -EINVAL;
}
-static int ad7768_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long info)
+static int ad7768_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length,
+ long info)
{
struct ad7768_state *st = iio_priv(indio_dev);
+ unsigned int shift;
+
+ switch (info) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ /*
+ * Sinc3 filter allows a wider range of OSR values, so show
+ * the available values in range format.
+ */
+ if (st->filter_type == AD7768_FILTER_SINC3 ||
+ st->filter_type == AD7768_FILTER_SINC3_REJ60) {
+ *vals = (int *)ad7768_sinc3_dec_rate_range;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ }
+
+ shift = st->filter_type == AD7768_FILTER_SINC5 ? 0 : 2;
+ *vals = (int *)&ad7768_dec_rate_values[shift];
+ *length = ARRAY_SIZE(ad7768_dec_rate_values) - shift;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *vals = (int *)st->samp_freq_avail;
+ *length = st->samp_freq_avail_len;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int __ad7768_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
switch (info) {
case IIO_CHAN_INFO_SAMP_FREQ:
return ad7768_set_freq(st, val);
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ ret = ad7768_configure_dig_fil(indio_dev, st->filter_type, val);
+ if (ret)
+ return ret;
+
+ /* Update sampling frequency */
+ return ad7768_set_freq(st, st->samp_freq);
default:
return -EINVAL;
}
}
+static int ad7768_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long info)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = __ad7768_write_raw(indio_dev, chan, val, val2, info);
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
static int ad7768_read_label(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, char *label)
{
@@ -469,25 +908,97 @@ static int ad7768_read_label(struct iio_dev *indio_dev,
return sprintf(label, "%s\n", st->labels[chan->channel]);
}
-static struct attribute *ad7768_attributes[] = {
- &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
- NULL
-};
+static int ad7768_get_current_scan_type(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
-static const struct attribute_group ad7768_group = {
- .attrs = ad7768_attributes,
-};
+ return st->oversampling_ratio == 8 ?
+ AD7768_SCAN_TYPE_HIGH_SPEED : AD7768_SCAN_TYPE_NORMAL;
+}
static const struct iio_info ad7768_info = {
- .attrs = &ad7768_group,
.read_raw = &ad7768_read_raw,
+ .read_avail = &ad7768_read_avail,
.write_raw = &ad7768_write_raw,
.read_label = ad7768_read_label,
+ .get_current_scan_type = &ad7768_get_current_scan_type,
.debugfs_reg_access = &ad7768_reg_access,
};
-static int ad7768_setup(struct ad7768_state *st)
+static struct fwnode_handle *
+ad7768_fwnode_find_reference_args(const struct fwnode_handle *fwnode,
+ const char *name, const char *nargs_prop,
+ unsigned int nargs, unsigned int index,
+ struct fwnode_reference_args *args)
+{
+ int ret;
+
+ ret = fwnode_property_get_reference_args(fwnode, name, nargs_prop,
+ nargs, index, args);
+ return ret ? ERR_PTR(ret) : args->fwnode;
+}
+
+static int ad7768_trigger_sources_sync_setup(struct device *dev,
+ struct fwnode_handle *fwnode,
+ struct ad7768_state *st)
+{
+ struct fwnode_reference_args args;
+
+ struct fwnode_handle *ref __free(fwnode_handle) =
+ ad7768_fwnode_find_reference_args(fwnode, "trigger-sources",
+ "#trigger-source-cells", 0,
+ AD7768_TRIGGER_SOURCE_SYNC_IDX,
+ &args);
+ if (IS_ERR(ref))
+ return PTR_ERR(ref);
+
+ ref = args.fwnode;
+ /* First, try getting the GPIO trigger source */
+ if (fwnode_device_is_compatible(ref, "gpio-trigger")) {
+ st->gpio_sync_in = devm_fwnode_gpiod_get_index(dev, ref, NULL, 0,
+ GPIOD_OUT_LOW,
+ "sync-in");
+ return PTR_ERR_OR_ZERO(st->gpio_sync_in);
+ }
+
+ /*
+ * TODO: Support the other cases when we have a trigger subsystem
+ * to reliably handle other types of devices as trigger sources.
+ *
+ * For now, return an error message. For self triggering, omit the
+ * trigger-sources property.
+ */
+ return dev_err_probe(dev, -EOPNOTSUPP, "Invalid synchronization trigger source\n");
+}
+
+static int ad7768_trigger_sources_get_sync(struct device *dev,
+ struct ad7768_state *st)
{
+ struct fwnode_handle *fwnode = dev_fwnode(dev);
+
+ /*
+ * The AD7768-1 allows two primary methods for driving the SYNC_IN pin
+ * to synchronize one or more devices:
+ * 1. Using an external GPIO.
+ * 2. Using a SPI command, where the SYNC_OUT pin generates a
+ * synchronization pulse that drives the SYNC_IN pin.
+ */
+ if (fwnode_property_present(fwnode, "trigger-sources"))
+ return ad7768_trigger_sources_sync_setup(dev, fwnode, st);
+
+ /*
+ * In the absence of trigger-sources property, enable self
+ * synchronization over SPI (SYNC_OUT).
+ */
+ st->en_spi_sync = true;
+
+ return 0;
+}
+
+static int ad7768_setup(struct iio_dev *indio_dev)
+{
+ struct ad7768_state *st = iio_priv(indio_dev);
int ret;
st->gpio_reset = devm_gpiod_get_optional(&st->spi->dev, "reset",
@@ -515,11 +1026,37 @@ static int ad7768_setup(struct ad7768_state *st)
return ret;
}
- st->gpio_sync_in = devm_gpiod_get(&st->spi->dev, "adi,sync-in",
- GPIOD_OUT_LOW);
+ /* For backwards compatibility, try the adi,sync-in-gpios property */
+ st->gpio_sync_in = devm_gpiod_get_optional(&st->spi->dev, "adi,sync-in",
+ GPIOD_OUT_LOW);
if (IS_ERR(st->gpio_sync_in))
return PTR_ERR(st->gpio_sync_in);
+ /*
+ * If the synchronization is not defined by adi,sync-in-gpios, try the
+ * trigger-sources.
+ */
+ if (!st->gpio_sync_in) {
+ ret = ad7768_trigger_sources_get_sync(&st->spi->dev, st);
+ if (ret)
+ return ret;
+ }
+
+ /* Only create a Chip GPIO if flagged for it */
+ if (device_property_read_bool(&st->spi->dev, "gpio-controller")) {
+ ret = ad7768_gpio_init(indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Set Default Digital Filter configuration:
+ * SINC5 filter with x32 Decimation rate
+ */
+ ret = ad7768_configure_dig_fil(indio_dev, AD7768_FILTER_SINC5, 32);
+ if (ret)
+ return ret;
+
/* Set the default sampling frequency to 32000 kSPS */
return ad7768_set_freq(st, 32000);
}
@@ -529,9 +1066,15 @@ static irqreturn_t ad7768_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7768_state *st = iio_priv(indio_dev);
+ const struct iio_scan_type *scan_type;
int ret;
- ret = spi_read(st->spi, &st->data.scan.chan, 3);
+ scan_type = iio_get_current_scan_type(indio_dev, &indio_dev->channels[0]);
+ if (IS_ERR(scan_type))
+ goto out;
+
+ ret = spi_read(st->spi, &st->data.scan.chan,
+ BITS_TO_BYTES(scan_type->realbits));
if (ret < 0)
goto out;
@@ -647,6 +1190,150 @@ static int ad7768_triggered_buffer_alloc(struct iio_dev *indio_dev)
&ad7768_buffer_ops);
}
+static int ad7768_vcm_enable(struct regulator_dev *rdev)
+{
+ struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret, regval;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ /* To enable, set the last selected output */
+ regval = AD7768_REG_ANALOG2_VCM(st->vcm_output_sel + 1);
+ ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
+ AD7768_REG_ANALOG2_VCM_MSK, regval);
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad7768_vcm_disable(struct regulator_dev *rdev)
+{
+ struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
+ AD7768_REG_ANALOG2_VCM_MSK, AD7768_VCM_OFF);
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int ad7768_vcm_is_enabled(struct regulator_dev *rdev)
+{
+ struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret, val;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_read(st->regmap, AD7768_REG_ANALOG2, &val);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+
+ return FIELD_GET(AD7768_REG_ANALOG2_VCM_MSK, val) != AD7768_VCM_OFF;
+}
+
+static int ad7768_set_voltage_sel(struct regulator_dev *rdev,
+ unsigned int selector)
+{
+ unsigned int regval = AD7768_REG_ANALOG2_VCM(selector + 1);
+ struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
+ AD7768_REG_ANALOG2_VCM_MSK, regval);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+
+ st->vcm_output_sel = selector;
+
+ return 0;
+}
+
+static int ad7768_get_voltage_sel(struct regulator_dev *rdev)
+{
+ struct iio_dev *indio_dev = rdev_get_drvdata(rdev);
+ struct ad7768_state *st = iio_priv(indio_dev);
+ int ret, val;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = regmap_read(st->regmap, AD7768_REG_ANALOG2, &val);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+
+ val = FIELD_GET(AD7768_REG_ANALOG2_VCM_MSK, val);
+
+ return clamp(val, 1, rdev->desc->n_voltages) - 1;
+}
+
+static const struct regulator_ops vcm_regulator_ops = {
+ .enable = ad7768_vcm_enable,
+ .disable = ad7768_vcm_disable,
+ .is_enabled = ad7768_vcm_is_enabled,
+ .list_voltage = regulator_list_voltage_table,
+ .set_voltage_sel = ad7768_set_voltage_sel,
+ .get_voltage_sel = ad7768_get_voltage_sel,
+};
+
+static const unsigned int vcm_voltage_table[] = {
+ 2500000,
+ 2050000,
+ 1650000,
+ 1900000,
+ 1100000,
+ 900000,
+};
+
+static const struct regulator_desc vcm_desc = {
+ .name = "ad7768-1-vcm",
+ .of_match = "vcm-output",
+ .regulators_node = "regulators",
+ .n_voltages = ARRAY_SIZE(vcm_voltage_table),
+ .volt_table = vcm_voltage_table,
+ .ops = &vcm_regulator_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+};
+
+static int ad7768_register_regulators(struct device *dev, struct ad7768_state *st,
+ struct iio_dev *indio_dev)
+{
+ struct regulator_config config = {
+ .dev = dev,
+ .driver_data = indio_dev,
+ };
+ int ret;
+
+ /* Disable the regulator before registering it */
+ ret = regmap_update_bits(st->regmap, AD7768_REG_ANALOG2,
+ AD7768_REG_ANALOG2_VCM_MSK, AD7768_VCM_OFF);
+ if (ret)
+ return ret;
+
+ st->vcm_rdev = devm_regulator_register(dev, &vcm_desc, &config);
+ if (IS_ERR(st->vcm_rdev))
+ return dev_err_probe(dev, PTR_ERR(st->vcm_rdev),
+ "failed to register VCM regulator\n");
+
+ return 0;
+}
+
static int ad7768_probe(struct spi_device *spi)
{
struct ad7768_state *st;
@@ -711,7 +1398,12 @@ static int ad7768_probe(struct spi_device *spi)
indio_dev->info = &ad7768_info;
indio_dev->modes = INDIO_DIRECT_MODE;
- ret = ad7768_setup(st);
+ /* Register VCM output regulator */
+ ret = ad7768_register_regulators(&spi->dev, st, indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad7768_setup(indio_dev);
if (ret < 0) {
dev_err(&spi->dev, "AD7768 setup failed\n");
return ret;
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 4c5f8d29a559..7852884703b0 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -7,24 +7,33 @@
*/
#include <linux/align.h>
-#include <linux/interrupt.h>
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/completion.h>
#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/spi/spi.h>
#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/find.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/spi/offload/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/sysfs.h>
+#include <linux/iio/adc/ad_sigma_delta.h>
+#include <linux/iio/buffer-dmaengine.h>
#include <linux/iio/buffer.h>
-#include <linux/iio/trigger.h>
+#include <linux/iio/iio.h>
#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/trigger.h>
#include <linux/iio/triggered_buffer.h>
-#include <linux/iio/adc/ad_sigma_delta.h>
-
-#include <linux/unaligned.h>
-
#define AD_SD_COMM_CHAN_MASK 0x3
@@ -40,7 +49,7 @@
* @sigma_delta: The sigma delta device
* @comm: New value for the communications register
*/
-void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm)
+void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, u8 comm)
{
/* Some variants use the lower two bits of the communications register
* to select the channel */
@@ -61,7 +70,7 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_set_comm, "IIO_AD_SIGMA_DELTA");
int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
unsigned int size, unsigned int val)
{
- uint8_t *data = sigma_delta->tx_buf;
+ u8 *data = sigma_delta->tx_buf;
struct spi_transfer t = {
.tx_buf = data,
.len = size + 1,
@@ -100,10 +109,18 @@ int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg,
}
EXPORT_SYMBOL_NS_GPL(ad_sd_write_reg, "IIO_AD_SIGMA_DELTA");
+static void ad_sd_set_read_reg_addr(struct ad_sigma_delta *sigma_delta, u8 reg,
+ u8 *data)
+{
+ data[0] = reg << sigma_delta->info->addr_shift;
+ data[0] |= sigma_delta->info->read_mask;
+ data[0] |= sigma_delta->comm;
+}
+
static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
- unsigned int reg, unsigned int size, uint8_t *val)
+ unsigned int reg, unsigned int size, u8 *val)
{
- uint8_t *data = sigma_delta->tx_buf;
+ u8 *data = sigma_delta->tx_buf;
int ret;
struct spi_transfer t[] = {
{
@@ -120,9 +137,7 @@ static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta,
spi_message_init(&m);
if (sigma_delta->info->has_registers) {
- data[0] = reg << sigma_delta->info->addr_shift;
- data[0] |= sigma_delta->info->read_mask;
- data[0] |= sigma_delta->comm;
+ ad_sd_set_read_reg_addr(sigma_delta, reg, data);
spi_message_add_tail(&t[0], &m);
}
spi_message_add_tail(&t[1], &m);
@@ -187,11 +202,11 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_read_reg, "IIO_AD_SIGMA_DELTA");
int ad_sd_reset(struct ad_sigma_delta *sigma_delta)
{
unsigned int reset_length = sigma_delta->info->num_resetclks;
- uint8_t *buf;
unsigned int size;
+ u8 *buf;
int ret;
- size = DIV_ROUND_UP(reset_length, 8);
+ size = BITS_TO_BYTES(reset_length);
buf = kcalloc(size, sizeof(*buf), GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -281,9 +296,7 @@ static int ad_sigma_delta_clear_pending_event(struct ad_sigma_delta *sigma_delta
if (sigma_delta->info->has_registers) {
unsigned int data_reg = sigma_delta->info->data_reg ?: AD_SD_REG_DATA;
- data[0] = data_reg << sigma_delta->info->addr_shift;
- data[0] |= sigma_delta->info->read_mask;
- data[0] |= sigma_delta->comm;
+ ad_sd_set_read_reg_addr(sigma_delta, data_reg, data);
t[0].tx_buf = data;
spi_message_add_tail(&t[0], &m);
}
@@ -420,7 +433,7 @@ int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev,
data_reg = AD_SD_REG_DATA;
ret = ad_sd_read_reg(sigma_delta, data_reg,
- DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8),
+ BITS_TO_BYTES(chan->scan_type.realbits + chan->scan_type.shift),
&raw_sample);
out:
@@ -454,9 +467,10 @@ EXPORT_SYMBOL_NS_GPL(ad_sigma_delta_single_conversion, "IIO_AD_SIGMA_DELTA");
static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
- unsigned int i, slot, samples_buf_size;
- unsigned int channel;
- uint8_t *samples_buf;
+ const struct iio_scan_type *scan_type = &indio_dev->channels[0].scan_type;
+ struct spi_transfer *xfer = sigma_delta->sample_xfer;
+ unsigned int i, slot, channel;
+ u8 *samples_buf;
int ret;
if (sigma_delta->num_slots == 1) {
@@ -483,20 +497,55 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
sigma_delta->active_slots = slot;
sigma_delta->current_slot = 0;
- if (sigma_delta->active_slots > 1) {
- ret = ad_sigma_delta_append_status(sigma_delta, true);
- if (ret)
- return ret;
+ if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
+ xfer[1].offload_flags = SPI_OFFLOAD_XFER_RX_STREAM;
+ xfer[1].bits_per_word = scan_type->realbits;
+ xfer[1].len = spi_bpw_to_bytes(scan_type->realbits);
+ } else {
+ unsigned int samples_buf_size, scan_size;
+
+ if (sigma_delta->active_slots > 1) {
+ ret = ad_sigma_delta_append_status(sigma_delta, true);
+ if (ret)
+ return ret;
+ }
+
+ samples_buf_size =
+ ALIGN(slot * BITS_TO_BYTES(scan_type->storagebits),
+ sizeof(s64));
+ samples_buf_size += sizeof(s64);
+ samples_buf = devm_krealloc(&sigma_delta->spi->dev,
+ sigma_delta->samples_buf,
+ samples_buf_size, GFP_KERNEL);
+ if (!samples_buf)
+ return -ENOMEM;
+
+ sigma_delta->samples_buf = samples_buf;
+ scan_size = BITS_TO_BYTES(scan_type->realbits + scan_type->shift);
+ /* For 24-bit data, there is an extra byte of padding. */
+ xfer[1].rx_buf = &sigma_delta->rx_buf[scan_size == 3 ? 1 : 0];
+ xfer[1].len = scan_size + (sigma_delta->status_appended ? 1 : 0);
}
+ xfer[1].cs_change = 1;
- samples_buf_size = ALIGN(slot * indio_dev->channels[0].scan_type.storagebits, 8);
- samples_buf_size += sizeof(int64_t);
- samples_buf = devm_krealloc(&sigma_delta->spi->dev, sigma_delta->samples_buf,
- samples_buf_size, GFP_KERNEL);
- if (!samples_buf)
- return -ENOMEM;
+ if (sigma_delta->info->has_registers) {
+ xfer[0].tx_buf = &sigma_delta->sample_addr;
+ xfer[0].len = 1;
+
+ ad_sd_set_read_reg_addr(sigma_delta,
+ sigma_delta->info->data_reg ?: AD_SD_REG_DATA,
+ &sigma_delta->sample_addr);
+ spi_message_init_with_transfers(&sigma_delta->sample_msg, xfer, 2);
+ } else {
+ spi_message_init_with_transfers(&sigma_delta->sample_msg,
+ &xfer[1], 1);
+ }
- sigma_delta->samples_buf = samples_buf;
+ sigma_delta->sample_msg.offload = sigma_delta->offload;
+
+ ret = spi_optimize_message(sigma_delta->spi, &sigma_delta->sample_msg);
+ if (ret)
+ return ret;
spi_bus_lock(sigma_delta->spi->controller);
sigma_delta->bus_locked = true;
@@ -510,24 +559,42 @@ static int ad_sd_buffer_postenable(struct iio_dev *indio_dev)
if (ret)
goto err_unlock;
- ad_sd_enable_irq(sigma_delta);
+ if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
+ struct spi_offload_trigger_config config = {
+ .type = SPI_OFFLOAD_TRIGGER_DATA_READY,
+ };
+
+ ret = spi_offload_trigger_enable(sigma_delta->offload,
+ sigma_delta->offload_trigger,
+ &config);
+ if (ret)
+ goto err_unlock;
+ } else {
+ ad_sd_enable_irq(sigma_delta);
+ }
return 0;
err_unlock:
spi_bus_unlock(sigma_delta->spi->controller);
+ spi_unoptimize_message(&sigma_delta->sample_msg);
return ret;
}
-static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
+static int ad_sd_buffer_predisable(struct iio_dev *indio_dev)
{
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
- reinit_completion(&sigma_delta->completion);
- wait_for_completion_timeout(&sigma_delta->completion, HZ);
+ if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
+ spi_offload_trigger_disable(sigma_delta->offload,
+ sigma_delta->offload_trigger);
+ } else {
+ reinit_completion(&sigma_delta->completion);
+ wait_for_completion_timeout(&sigma_delta->completion, HZ);
- ad_sd_disable_irq(sigma_delta);
+ ad_sd_disable_irq(sigma_delta);
+ }
sigma_delta->keep_cs_asserted = false;
ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE);
@@ -537,61 +604,32 @@ static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev)
ad_sigma_delta_disable_all(sigma_delta);
sigma_delta->bus_locked = false;
- return spi_bus_unlock(sigma_delta->spi->controller);
+ spi_bus_unlock(sigma_delta->spi->controller);
+ spi_unoptimize_message(&sigma_delta->sample_msg);
+
+ return 0;
}
static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
+ const struct iio_scan_type *scan_type = &indio_dev->channels[0].scan_type;
struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev);
- uint8_t *data = sigma_delta->rx_buf;
- unsigned int transfer_size;
+ u8 *data = sigma_delta->rx_buf;
unsigned int sample_size;
unsigned int sample_pos;
unsigned int status_pos;
unsigned int reg_size;
- unsigned int data_reg;
-
- reg_size = indio_dev->channels[0].scan_type.realbits +
- indio_dev->channels[0].scan_type.shift;
- reg_size = DIV_ROUND_UP(reg_size, 8);
-
- if (sigma_delta->info->data_reg != 0)
- data_reg = sigma_delta->info->data_reg;
- else
- data_reg = AD_SD_REG_DATA;
-
- /* Status word will be appended to the sample during transfer */
- if (sigma_delta->status_appended)
- transfer_size = reg_size + 1;
- else
- transfer_size = reg_size;
-
- switch (reg_size) {
- case 4:
- case 2:
- case 1:
- status_pos = reg_size;
- ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[0]);
- break;
- case 3:
- /*
- * Data array after transfer will look like (if status is appended):
- * data[] = { [0][sample][sample][sample][status] }
- * Keeping the first byte 0 shifts the status position by 1 byte to the right.
- */
- status_pos = reg_size + 1;
+ int ret;
- /* We store 24 bit samples in a 32 bit word. Keep the upper
- * byte set to zero. */
- ad_sd_read_reg_raw(sigma_delta, data_reg, transfer_size, &data[1]);
- break;
+ reg_size = BITS_TO_BYTES(scan_type->realbits + scan_type->shift);
+ /* For 24-bit data, there is an extra byte of padding. */
+ status_pos = reg_size + (reg_size == 3 ? 1 : 0);
- default:
- dev_err_ratelimited(&indio_dev->dev, "Unsupported reg_size: %u\n", reg_size);
+ ret = spi_sync_locked(sigma_delta->spi, &sigma_delta->sample_msg);
+ if (ret)
goto irq_handled;
- }
/*
* For devices sampling only one channel at
@@ -617,7 +655,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
}
}
- sample_size = indio_dev->channels[0].scan_type.storagebits / 8;
+ sample_size = BITS_TO_BYTES(scan_type->storagebits);
sample_pos = sample_size * sigma_delta->current_slot;
memcpy(&sigma_delta->samples_buf[sample_pos], data, sample_size);
sigma_delta->current_slot++;
@@ -644,7 +682,7 @@ static bool ad_sd_validate_scan_mask(struct iio_dev *indio_dev, const unsigned l
static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = {
.postenable = &ad_sd_buffer_postenable,
- .postdisable = &ad_sd_buffer_postdisable,
+ .predisable = &ad_sd_buffer_predisable,
.validate_scan_mask = &ad_sd_validate_scan_mask,
};
@@ -671,7 +709,8 @@ static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private)
if ((!sigma_delta->rdy_gpiod || gpiod_get_value(sigma_delta->rdy_gpiod)) &&
ad_sd_disable_irq(sigma_delta)) {
complete(&sigma_delta->completion);
- iio_trigger_poll(sigma_delta->trig);
+ if (sigma_delta->trig)
+ iio_trigger_poll(sigma_delta->trig);
return IRQ_HANDLED;
}
@@ -704,17 +743,6 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de
unsigned long irq_flags = irq_get_trigger_type(sigma_delta->irq_line);
int ret;
- if (dev != &sigma_delta->spi->dev) {
- dev_err(dev, "Trigger parent should be '%s', got '%s'\n",
- dev_name(dev), dev_name(&sigma_delta->spi->dev));
- return -EFAULT;
- }
-
- sigma_delta->trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
- iio_device_id(indio_dev));
- if (sigma_delta->trig == NULL)
- return -ENOMEM;
-
init_completion(&sigma_delta->completion);
sigma_delta->irq_dis = true;
@@ -734,14 +762,33 @@ static int devm_ad_sd_probe_trigger(struct device *dev, struct iio_dev *indio_de
if (ret)
return ret;
- iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
+ if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
+ sigma_delta->offload_trigger =
+ devm_spi_offload_trigger_get(dev, sigma_delta->offload,
+ SPI_OFFLOAD_TRIGGER_DATA_READY);
+ if (IS_ERR(sigma_delta->offload_trigger))
+ return dev_err_probe(dev, PTR_ERR(sigma_delta->offload_trigger),
+ "Failed to get SPI offload trigger\n");
+ } else {
+ if (dev != &sigma_delta->spi->dev)
+ return dev_err_probe(dev, -EFAULT,
+ "Trigger parent should be '%s', got '%s'\n",
+ dev_name(dev), dev_name(&sigma_delta->spi->dev));
- ret = devm_iio_trigger_register(dev, sigma_delta->trig);
- if (ret)
- return ret;
+ sigma_delta->trig = devm_iio_trigger_alloc(dev, "%s-dev%d",
+ indio_dev->name, iio_device_id(indio_dev));
+ if (!sigma_delta->trig)
+ return -ENOMEM;
- /* select default trigger */
- indio_dev->trig = iio_trigger_get(sigma_delta->trig);
+ iio_trigger_set_drvdata(sigma_delta->trig, sigma_delta);
+
+ ret = devm_iio_trigger_register(dev, sigma_delta->trig);
+ if (ret)
+ return ret;
+
+ /* select default trigger */
+ indio_dev->trig = iio_trigger_get(sigma_delta->trig);
+ }
return 0;
}
@@ -761,12 +808,29 @@ int devm_ad_sd_setup_buffer_and_trigger(struct device *dev, struct iio_dev *indi
if (!sigma_delta->slots)
return -ENOMEM;
- ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
- &iio_pollfunc_store_time,
- &ad_sd_trigger_handler,
- &ad_sd_buffer_setup_ops);
- if (ret)
- return ret;
+ if (ad_sigma_delta_has_spi_offload(sigma_delta)) {
+ struct dma_chan *rx_dma;
+
+ rx_dma = devm_spi_offload_rx_stream_request_dma_chan(dev,
+ sigma_delta->offload);
+ if (IS_ERR(rx_dma))
+ return dev_err_probe(dev, PTR_ERR(rx_dma),
+ "Failed to get RX DMA channel\n");
+
+ ret = devm_iio_dmaengine_buffer_setup_with_handle(dev, indio_dev,
+ rx_dma, IIO_BUFFER_DIRECTION_IN);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot setup DMA buffer\n");
+
+ indio_dev->setup_ops = &ad_sd_buffer_setup_ops;
+ } else {
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &ad_sd_trigger_handler,
+ &ad_sd_buffer_setup_ops);
+ if (ret)
+ return ret;
+ }
return devm_ad_sd_probe_trigger(dev, indio_dev);
}
@@ -829,6 +893,20 @@ int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev,
return sigma_delta->irq_line;
}
+ if (info->supports_spi_offload) {
+ struct spi_offload_config offload_config = {
+ .capability_flags = SPI_OFFLOAD_CAP_TRIGGER |
+ SPI_OFFLOAD_CAP_RX_STREAM_DMA,
+ };
+ int ret;
+
+ sigma_delta->offload = devm_spi_offload_get(&spi->dev, spi,
+ &offload_config);
+ ret = PTR_ERR_OR_ZERO(sigma_delta->offload);
+ if (ret && ret != -ENODEV)
+ return dev_err_probe(&spi->dev, ret, "Failed to get SPI offload\n");
+ }
+
iio_device_set_drvdata(indio_dev, sigma_delta);
return 0;
@@ -838,3 +916,4 @@ EXPORT_SYMBOL_NS_GPL(ad_sd_init, "IIO_AD_SIGMA_DELTA");
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs");
MODULE_LICENSE("GPL v2");
+MODULE_IMPORT_NS("IIO_DMAENGINE_BUFFER");
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index 2dbaa0b5b3d6..4b7c472a088b 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -44,6 +44,8 @@
#define ADI_AXI_ADC_REG_CONFIG_CMOS_OR_LVDS_N BIT(7)
#define ADI_AXI_ADC_REG_CTRL 0x0044
+#define ADI_AXI_ADC_CTRL_NUM_LANES_MSK GENMASK(12, 8)
+#define ADI_AXI_ADC_CTRL_SYNC_MSK BIT(3)
#define ADI_AXI_ADC_CTRL_DDR_EDGESEL_MASK BIT(1)
#define ADI_AXI_ADC_REG_CNTRL_3 0x004c
@@ -52,6 +54,10 @@
#define AXI_AD485X_PACKET_FORMAT_20BIT 0x0
#define AXI_AD485X_PACKET_FORMAT_24BIT 0x1
#define AXI_AD485X_PACKET_FORMAT_32BIT 0x2
+#define AXI_AD408X_CNTRL_3_FILTER_EN_MSK BIT(0)
+
+#define ADI_AXI_ADC_REG_SYNC_STATUS 0x0068
+#define ADI_AXI_ADC_SYNC_STATUS_ADC_SYNC_MSK BIT(0)
#define ADI_AXI_ADC_REG_DRP_STATUS 0x0074
#define ADI_AXI_ADC_DRP_LOCKED BIT(17)
@@ -80,6 +86,9 @@
#define ADI_AXI_ADC_REG_CHAN_CTRL_3(c) (0x0418 + (c) * 0x40)
#define ADI_AXI_ADC_CHAN_PN_SEL_MASK GENMASK(19, 16)
+#define ADI_AXI_ADC_REG_CHAN_USR_CTRL_2(c) (0x0424 + (c) * 0x40)
+#define ADI_AXI_ADC_CHAN_USR_CTRL_2_DEC_RATE_N_MASK GENMASK(15, 0)
+
/* IO Delays */
#define ADI_AXI_ADC_REG_DELAY(l) (0x0800 + (l) * 0x4)
#define AXI_ADC_DELAY_CTRL_MASK GENMASK(4, 0)
@@ -242,6 +251,19 @@ static int axi_adc_test_pattern_set(struct iio_backend *back,
}
}
+static int axi_adc_oversampling_ratio_set(struct iio_backend *back,
+ unsigned int chan,
+ unsigned int rate)
+{
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+
+ return regmap_update_bits(st->regmap,
+ ADI_AXI_ADC_REG_CHAN_USR_CTRL_2(chan),
+ ADI_AXI_ADC_CHAN_USR_CTRL_2_DEC_RATE_N_MASK,
+ FIELD_PREP(ADI_AXI_ADC_CHAN_USR_CTRL_2_DEC_RATE_N_MASK,
+ rate));
+}
+
static int axi_adc_read_chan_status(struct adi_axi_adc_state *st, unsigned int chan,
unsigned int *status)
{
@@ -381,7 +403,8 @@ static int axi_adc_ad485x_data_size_set(struct iio_backend *back,
}
static int axi_adc_ad485x_oversampling_ratio_set(struct iio_backend *back,
- unsigned int ratio)
+ unsigned int chan,
+ unsigned int ratio)
{
struct adi_axi_adc_state *st = iio_backend_get_priv(back);
@@ -402,6 +425,50 @@ static int axi_adc_ad485x_oversampling_ratio_set(struct iio_backend *back,
}
}
+static int axi_adc_ad408x_filter_type_set(struct iio_backend *back,
+ enum iio_backend_filter_type type)
+{
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+
+ if (type)
+ return regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3,
+ AXI_AD408X_CNTRL_3_FILTER_EN_MSK);
+
+ return regmap_clear_bits(st->regmap, ADI_AXI_ADC_REG_CNTRL_3,
+ AXI_AD408X_CNTRL_3_FILTER_EN_MSK);
+}
+
+static int axi_adc_ad408x_interface_data_align(struct iio_backend *back,
+ u32 timeout_us)
+{
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+ u32 val;
+ int ret;
+
+ ret = regmap_set_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
+ ADI_AXI_ADC_CTRL_SYNC_MSK);
+ if (ret)
+ return ret;
+
+ return regmap_read_poll_timeout(st->regmap, ADI_AXI_ADC_REG_SYNC_STATUS,
+ val,
+ FIELD_GET(ADI_AXI_ADC_SYNC_STATUS_ADC_SYNC_MSK, val),
+ 1, timeout_us);
+}
+
+static int axi_adc_num_lanes_set(struct iio_backend *back,
+ unsigned int num_lanes)
+{
+ struct adi_axi_adc_state *st = iio_backend_get_priv(back);
+
+ if (!num_lanes)
+ return -EINVAL;
+
+ return regmap_update_bits(st->regmap, ADI_AXI_ADC_REG_CTRL,
+ ADI_AXI_ADC_CTRL_NUM_LANES_MSK,
+ FIELD_PREP(ADI_AXI_ADC_CTRL_NUM_LANES_MSK, num_lanes));
+}
+
static struct iio_buffer *axi_adc_request_buffer(struct iio_backend *back,
struct iio_dev *indio_dev)
{
@@ -551,6 +618,7 @@ static const struct iio_backend_ops adi_axi_adc_ops = {
.test_pattern_set = axi_adc_test_pattern_set,
.chan_status = axi_adc_chan_status,
.interface_type_get = axi_adc_interface_type_get,
+ .oversampling_ratio_set = axi_adc_oversampling_ratio_set,
.debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access),
.debugfs_print_chan_status = iio_backend_debugfs_ptr(axi_adc_debugfs_print_chan_status),
};
@@ -584,6 +652,26 @@ static const struct iio_backend_info axi_ad485x = {
.ops = &adi_ad485x_ops,
};
+static const struct iio_backend_ops adi_ad408x_ops = {
+ .enable = axi_adc_enable,
+ .disable = axi_adc_disable,
+ .chan_enable = axi_adc_chan_enable,
+ .chan_disable = axi_adc_chan_disable,
+ .request_buffer = axi_adc_request_buffer,
+ .free_buffer = axi_adc_free_buffer,
+ .data_sample_trigger = axi_adc_data_sample_trigger,
+ .filter_type_set = axi_adc_ad408x_filter_type_set,
+ .interface_data_align = axi_adc_ad408x_interface_data_align,
+ .num_lanes_set = axi_adc_num_lanes_set,
+ .debugfs_reg_access = iio_backend_debugfs_ptr(axi_adc_reg_access),
+ .debugfs_print_chan_status = iio_backend_debugfs_ptr(axi_adc_debugfs_print_chan_status),
+};
+
+static const struct iio_backend_info axi_ad408x = {
+ .name = "axi-ad408x",
+ .ops = &adi_ad408x_ops,
+};
+
static int adi_axi_adc_probe(struct platform_device *pdev)
{
struct adi_axi_adc_state *st;
@@ -699,9 +787,15 @@ static const struct axi_adc_info adc_ad7606 = {
.has_child_nodes = true,
};
+static const struct axi_adc_info adi_axi_ad408x = {
+ .version = ADI_AXI_PCORE_VER(10, 0, 'a'),
+ .backend_info = &axi_ad408x,
+};
+
/* Match table for of_platform binding */
static const struct of_device_id adi_axi_adc_of_match[] = {
{ .compatible = "adi,axi-adc-10.0.a", .data = &adc_generic },
+ { .compatible = "adi,axi-ad408x", .data = &adi_axi_ad408x },
{ .compatible = "adi,axi-ad485x", .data = &adi_axi_ad485x },
{ .compatible = "adi,axi-ad7606x", .data = &adc_ad7606 },
{ }
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 5927756b749a..920dd9ffd27a 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -1226,7 +1226,7 @@ static const struct at91_adc_trigger at91sam9260_triggers[] = {
{ .name = "external", .value = 0xd, .is_external = true },
};
-static struct at91_adc_caps at91sam9260_caps = {
+static const struct at91_adc_caps at91sam9260_caps = {
.calc_startup_ticks = calc_startup_ticks_9260,
.num_channels = 4,
.low_res_bits = 8,
@@ -1250,7 +1250,7 @@ static const struct at91_adc_trigger at91sam9x5_triggers[] = {
{ .name = "continuous", .value = 0x6 },
};
-static struct at91_adc_caps at91sam9rl_caps = {
+static const struct at91_adc_caps at91sam9rl_caps = {
.has_ts = true,
.calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */
.num_channels = 6,
@@ -1268,7 +1268,7 @@ static struct at91_adc_caps at91sam9rl_caps = {
.trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
};
-static struct at91_adc_caps at91sam9g45_caps = {
+static const struct at91_adc_caps at91sam9g45_caps = {
.has_ts = true,
.calc_startup_ticks = calc_startup_ticks_9260, /* same as 9260 */
.num_channels = 8,
@@ -1286,7 +1286,7 @@ static struct at91_adc_caps at91sam9g45_caps = {
.trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
};
-static struct at91_adc_caps at91sam9x5_caps = {
+static const struct at91_adc_caps at91sam9x5_caps = {
.has_ts = true,
.has_tsmr = true,
.ts_filter_average = 3,
@@ -1308,7 +1308,7 @@ static struct at91_adc_caps at91sam9x5_caps = {
.trigger_number = ARRAY_SIZE(at91sam9x5_triggers),
};
-static struct at91_adc_caps sama5d3_caps = {
+static const struct at91_adc_caps sama5d3_caps = {
.has_ts = true,
.has_tsmr = true,
.ts_filter_average = 3,
diff --git a/drivers/iio/adc/axp20x_adc.c b/drivers/iio/adc/axp20x_adc.c
index 1b49325ec1ce..f9a60e8b05cb 100644
--- a/drivers/iio/adc/axp20x_adc.c
+++ b/drivers/iio/adc/axp20x_adc.c
@@ -173,7 +173,7 @@ static const struct iio_map axp22x_maps[] = {
{ }
};
-static struct iio_map axp717_maps[] = {
+static const struct iio_map axp717_maps[] = {
{
.consumer_dev_name = "axp20x-usb-power-supply",
.consumer_channel = "vbus_v",
diff --git a/drivers/iio/adc/dln2-adc.c b/drivers/iio/adc/dln2-adc.c
index 9dbd2c87938c..5aea7644780f 100644
--- a/drivers/iio/adc/dln2-adc.c
+++ b/drivers/iio/adc/dln2-adc.c
@@ -467,7 +467,7 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p)
struct {
__le16 values[DLN2_ADC_MAX_CHANNELS];
aligned_s64 timestamp_space;
- } data;
+ } data = { };
struct dln2_adc_get_all_vals dev_data;
struct dln2_adc *dln2 = iio_priv(indio_dev);
const struct dln2_adc_demux_table *t;
@@ -479,8 +479,6 @@ static irqreturn_t dln2_adc_trigger_h(int irq, void *p)
if (ret < 0)
goto done;
- memset(&data, 0, sizeof(data));
-
/* Demux operation */
for (i = 0; i < dln2->demux_count; ++i) {
t = &dln2->demux[i];
diff --git a/drivers/iio/adc/hi8435.c b/drivers/iio/adc/hi8435.c
index b4562aae8477..86c10ea7ded4 100644
--- a/drivers/iio/adc/hi8435.c
+++ b/drivers/iio/adc/hi8435.c
@@ -19,8 +19,6 @@
#include <linux/spi/spi.h>
#include <linux/gpio/consumer.h>
-#define DRV_NAME "hi8435"
-
/* Register offsets for HI-8435 */
#define HI8435_CTRL_REG 0x02
#define HI8435_PSEN_REG 0x04
@@ -536,7 +534,7 @@ MODULE_DEVICE_TABLE(spi, hi8435_id);
static struct spi_driver hi8435_driver = {
.driver = {
- .name = DRV_NAME,
+ .name = "hi8435",
.of_match_table = hi8435_dt_ids,
},
.probe = hi8435_probe,
diff --git a/drivers/iio/adc/max9611.c b/drivers/iio/adc/max9611.c
index 14fe42fc4b7d..826566d7a85e 100644
--- a/drivers/iio/adc/max9611.c
+++ b/drivers/iio/adc/max9611.c
@@ -25,8 +25,6 @@
#include <linux/mod_devicetable.h>
#include <linux/property.h>
-#define DRIVER_NAME "max9611"
-
/* max9611 register addresses */
#define MAX9611_REG_CSA_DATA 0x00
#define MAX9611_REG_RS_DATA 0x02
@@ -553,7 +551,7 @@ static int max9611_probe(struct i2c_client *client)
static struct i2c_driver max9611_driver = {
.driver = {
- .name = DRIVER_NAME,
+ .name = "max9611",
.of_match_table = max9611_of_table,
},
.probe = max9611_probe,
diff --git a/drivers/iio/adc/mp2629_adc.c b/drivers/iio/adc/mp2629_adc.c
index 1cb043b17437..5a1d516f8dad 100644
--- a/drivers/iio/adc/mp2629_adc.c
+++ b/drivers/iio/adc/mp2629_adc.c
@@ -44,7 +44,7 @@ struct mp2629_adc {
struct device *dev;
};
-static struct iio_chan_spec mp2629_channels[] = {
+static const struct iio_chan_spec mp2629_channels[] = {
MP2629_ADC_CHAN(BATT_VOLT, IIO_VOLTAGE),
MP2629_ADC_CHAN(SYSTEM_VOLT, IIO_VOLTAGE),
MP2629_ADC_CHAN(INPUT_VOLT, IIO_VOLTAGE),
diff --git a/drivers/iio/adc/mt6359-auxadc.c b/drivers/iio/adc/mt6359-auxadc.c
index eecf88b05c6f..f426a289e867 100644
--- a/drivers/iio/adc/mt6359-auxadc.c
+++ b/drivers/iio/adc/mt6359-auxadc.c
@@ -7,6 +7,7 @@
* Author: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
+#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
@@ -24,11 +25,11 @@
#include <dt-bindings/iio/adc/mediatek,mt6357-auxadc.h>
#include <dt-bindings/iio/adc/mediatek,mt6358-auxadc.h>
#include <dt-bindings/iio/adc/mediatek,mt6359-auxadc.h>
+#include <dt-bindings/iio/adc/mediatek,mt6363-auxadc.h>
#define AUXADC_AVG_TIME_US 10
#define AUXADC_POLL_DELAY_US 100
#define AUXADC_TIMEOUT_US 32000
-#define AUXADC_VOLT_FULL 1800
#define IMP_STOP_DELAY_US 150
#define IMP_POLL_DELAY_US 1000
@@ -46,6 +47,12 @@
#define MT6359_IMP0_CONV_EN BIT(0)
#define MT6359_IMP1_IRQ_RDY BIT(15)
+#define MT6363_EXT_CHAN_MASK GENMASK(2, 0)
+#define MT6363_EXT_PURES_MASK GENMASK(4, 3)
+ #define MT6363_PULLUP_RES_100K 0
+ #define MT6363_PULLUP_RES_30K 1
+ #define MT6363_PULLUP_RES_OPEN 3
+
enum mtk_pmic_auxadc_regs {
PMIC_AUXADC_ADC0,
PMIC_AUXADC_DCM_CON,
@@ -54,6 +61,8 @@ enum mtk_pmic_auxadc_regs {
PMIC_AUXADC_IMP3,
PMIC_AUXADC_RQST0,
PMIC_AUXADC_RQST1,
+ PMIC_AUXADC_RQST3,
+ PMIC_AUXADC_SDMADC_CON0,
PMIC_HK_TOP_WKEY,
PMIC_HK_TOP_RST_CON0,
PMIC_FGADC_R_CON0,
@@ -75,7 +84,16 @@ enum mtk_pmic_auxadc_channels {
PMIC_AUXADC_CHAN_TSX_TEMP,
PMIC_AUXADC_CHAN_HPOFS_CAL,
PMIC_AUXADC_CHAN_DCXO_TEMP,
+ PMIC_AUXADC_CHAN_VTREF,
PMIC_AUXADC_CHAN_VBIF,
+ PMIC_AUXADC_CHAN_VSYSSNS,
+ PMIC_AUXADC_CHAN_VIN1,
+ PMIC_AUXADC_CHAN_VIN2,
+ PMIC_AUXADC_CHAN_VIN3,
+ PMIC_AUXADC_CHAN_VIN4,
+ PMIC_AUXADC_CHAN_VIN5,
+ PMIC_AUXADC_CHAN_VIN6,
+ PMIC_AUXADC_CHAN_VIN7,
PMIC_AUXADC_CHAN_IBAT,
PMIC_AUXADC_CHAN_VBAT,
PMIC_AUXADC_CHAN_MAX
@@ -101,12 +119,22 @@ struct mt6359_auxadc {
* struct mtk_pmic_auxadc_chan - PMIC AUXADC channel data
* @req_idx: Request register number
* @req_mask: Bitmask to activate a channel
+ * @rdy_idx: Readiness register number
+ * @rdy_mask: Bitmask to determine channel readiness
+ * @ext_sel_idx: PMIC GPIO channel register number
+ * @ext_sel_ch: PMIC GPIO number
+ * @ext_sel_pu: PMIC GPIO channel pullup resistor selector
* @num_samples: Number of AUXADC samples for averaging
* @r_ratio: Resistance ratio fractional
*/
struct mtk_pmic_auxadc_chan {
u8 req_idx;
u16 req_mask;
+ u8 rdy_idx;
+ u16 rdy_mask;
+ s8 ext_sel_idx;
+ u8 ext_sel_ch;
+ u8 ext_sel_pu;
u16 num_samples;
struct u8_fract r_ratio;
};
@@ -119,7 +147,10 @@ struct mtk_pmic_auxadc_chan {
* @desc: PMIC AUXADC channel data
* @regs: List of PMIC specific registers
* @sec_unlock_key: Security unlock key for HK_TOP writes
+ * @vref_mV: AUXADC Reference Voltage (VREF) in millivolts
* @imp_adc_num: ADC channel for battery impedance readings
+ * @is_spmi: Defines whether this PMIC communicates over SPMI
+ * @no_reset: If true, this PMIC does not support ADC reset
* @read_imp: Callback to read impedance channels
*/
struct mtk_pmic_auxadc_info {
@@ -129,18 +160,34 @@ struct mtk_pmic_auxadc_info {
const struct mtk_pmic_auxadc_chan *desc;
const u16 *regs;
u16 sec_unlock_key;
+ u32 vref_mV;
u8 imp_adc_num;
- int (*read_imp)(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat);
+ bool is_spmi;
+ bool no_reset;
+ int (*read_imp)(struct mt6359_auxadc *adc_dev,
+ const struct iio_chan_spec *chan, int *vbat, int *ibat);
};
-#define MTK_PMIC_ADC_CHAN(_ch_idx, _req_idx, _req_bit, _samples, _rnum, _rdiv) \
+#define MTK_PMIC_ADC_EXT_CHAN(_ch_idx, _req_idx, _req_bit, _rdy_idx, _rdy_bit, \
+ _ext_sel_idx, _ext_sel_ch, _ext_sel_pu, \
+ _samples, _rnum, _rdiv) \
[PMIC_AUXADC_CHAN_##_ch_idx] = { \
.req_idx = _req_idx, \
.req_mask = BIT(_req_bit), \
+ .rdy_idx = _rdy_idx, \
+ .rdy_mask = BIT(_rdy_bit), \
+ .ext_sel_idx = _ext_sel_idx, \
+ .ext_sel_ch = _ext_sel_ch, \
+ .ext_sel_pu = _ext_sel_pu, \
.num_samples = _samples, \
.r_ratio = { _rnum, _rdiv } \
}
+#define MTK_PMIC_ADC_CHAN(_ch_idx, _req_idx, _req_bit, _rdy_idx, _rdy_bit, \
+ _samples, _rnum, _rdiv) \
+ MTK_PMIC_ADC_EXT_CHAN(_ch_idx, _req_idx, _req_bit, _rdy_idx, _rdy_bit, \
+ -1, 0, 0, _samples, _rnum, _rdiv)
+
#define MTK_PMIC_IIO_CHAN(_model, _name, _ch_idx, _adc_idx, _nbits, _ch_type) \
{ \
.type = _ch_type, \
@@ -177,21 +224,21 @@ static const struct iio_chan_spec mt6357_auxadc_channels[] = {
};
static const struct mtk_pmic_auxadc_chan mt6357_auxadc_ch_desc[] = {
- MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
- MTK_PMIC_ADC_CHAN(ISENSE, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
- MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
- MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
- MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
- MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 5, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 6, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
+ MTK_PMIC_ADC_CHAN(ISENSE, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
+ MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP0, 8, 128, 1, 1),
+ MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP0, 8, 256, 1, 1),
+ MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, PMIC_AUXADC_IMP0, 8, 16, 1, 1),
+ MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 5, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 6, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
/* Battery impedance channels */
- MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 3, 1),
+ MTK_PMIC_ADC_CHAN(VBAT, 0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
};
static const u16 mt6357_auxadc_regs[] = {
@@ -224,22 +271,22 @@ static const struct iio_chan_spec mt6358_auxadc_channels[] = {
};
static const struct mtk_pmic_auxadc_chan mt6358_auxadc_ch_desc[] = {
- MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 3, 1),
- MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 2, 1),
- MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2),
- MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
- MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
- MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
- MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 2, 1),
- MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 128, 3, 1),
+ MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP0, 8, 8, 2, 1),
+ MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, PMIC_AUXADC_IMP0, 8, 8, 3, 2),
+ MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP0, 8, 128, 1, 1),
+ MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP0, 8, 256, 1, 1),
+ MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, PMIC_AUXADC_IMP0, 8, 16, 1, 1),
+ MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, PMIC_AUXADC_IMP0, 8, 8, 2, 1),
+ MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, PMIC_AUXADC_IMP0, 8, 8, 1, 1),
/* Battery impedance channels */
- MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2),
+ MTK_PMIC_ADC_CHAN(VBAT, 0, 0, PMIC_AUXADC_IMP0, 8, 128, 7, 2),
};
static const u16 mt6358_auxadc_regs[] = {
@@ -272,22 +319,22 @@ static const struct iio_chan_spec mt6359_auxadc_channels[] = {
};
static const struct mtk_pmic_auxadc_chan mt6359_auxadc_ch_desc[] = {
- MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, 128, 7, 2),
- MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, 8, 5, 2),
- MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, 8, 3, 2),
- MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, 128, 1, 1),
- MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, 256, 1, 1),
- MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, 16, 1, 1),
- MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, 8, 5, 2),
- MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, 8, 1, 1),
- MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
+ MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_IMP1, 15, 8, 5, 2),
+ MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(ACCDET, PMIC_AUXADC_RQST0, 5, PMIC_AUXADC_IMP1, 15 ,8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VDCXO, PMIC_AUXADC_RQST0, 6, PMIC_AUXADC_IMP1, 15, 8, 3, 2),
+ MTK_PMIC_ADC_CHAN(TSX_TEMP, PMIC_AUXADC_RQST0, 7, PMIC_AUXADC_IMP1, 15, 128, 1, 1),
+ MTK_PMIC_ADC_CHAN(HPOFS_CAL, PMIC_AUXADC_RQST0, 9, PMIC_AUXADC_IMP1, 15, 256, 1, 1),
+ MTK_PMIC_ADC_CHAN(DCXO_TEMP, PMIC_AUXADC_RQST0, 10, PMIC_AUXADC_IMP1, 15, 16, 1, 1),
+ MTK_PMIC_ADC_CHAN(VBIF, PMIC_AUXADC_RQST0, 11, PMIC_AUXADC_IMP1, 15, 8, 5, 2),
+ MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST1, 8, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST1, 9, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
+ MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST1, 10, PMIC_AUXADC_IMP1, 15, 8, 1, 1),
/* Battery impedance channels */
- MTK_PMIC_ADC_CHAN(VBAT, 0, 0, 128, 7, 2),
- MTK_PMIC_ADC_CHAN(IBAT, 0, 0, 128, 7, 2),
+ MTK_PMIC_ADC_CHAN(VBAT, 0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
+ MTK_PMIC_ADC_CHAN(IBAT, 0, 0, PMIC_AUXADC_IMP1, 15, 128, 7, 2),
};
static const u16 mt6359_auxadc_regs[] = {
@@ -302,6 +349,107 @@ static const u16 mt6359_auxadc_regs[] = {
[PMIC_AUXADC_IMP3] = 0x120e,
};
+static const struct iio_chan_spec mt6363_auxadc_channels[] = {
+ MTK_PMIC_IIO_CHAN(MT6363, bat_adc, BATADC, 0, 15, IIO_RESISTANCE),
+ MTK_PMIC_IIO_CHAN(MT6363, cdt_v, VCDT, 2, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6363, batt_temp, BAT_TEMP, 3, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6363, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6363, sys_sns_v, VSYSSNS, 6, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, tref_v, VTREF, 11, 12, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6363, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6363, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP),
+
+ /* For VIN, ADC12 holds the result depending on which GPIO was activated */
+ MTK_PMIC_IIO_CHAN(MT6363, in1_v, VIN1, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in2_v, VIN2, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in3_v, VIN3, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in4_v, VIN4, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in5_v, VIN5, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in6_v, VIN6, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in7_v, VIN7, 45, 15, IIO_VOLTAGE),
+};
+
+static const struct mtk_pmic_auxadc_chan mt6363_auxadc_ch_desc[] = {
+ MTK_PMIC_ADC_CHAN(BATADC, PMIC_AUXADC_RQST0, 0, PMIC_AUXADC_ADC0, 15, 64, 4, 1),
+ MTK_PMIC_ADC_CHAN(VCDT, PMIC_AUXADC_RQST0, 2, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
+ MTK_PMIC_ADC_CHAN(BAT_TEMP, PMIC_AUXADC_RQST0, 3, PMIC_AUXADC_ADC0, 15, 32, 3, 2),
+ MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
+ MTK_PMIC_ADC_CHAN(VSYSSNS, PMIC_AUXADC_RQST1, 6, PMIC_AUXADC_ADC0, 15, 64, 3, 1),
+ MTK_PMIC_ADC_CHAN(VTREF, PMIC_AUXADC_RQST1, 3, PMIC_AUXADC_ADC0, 15, 32, 3, 2),
+ MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST3, 0, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
+ MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST3, 1, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
+ MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST3, 2, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
+
+ MTK_PMIC_ADC_EXT_CHAN(VIN1,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 1, MT6363_PULLUP_RES_100K, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN2,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 2, MT6363_PULLUP_RES_100K, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN3,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 3, MT6363_PULLUP_RES_100K, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN4,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 4, MT6363_PULLUP_RES_100K, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN5,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 5, MT6363_PULLUP_RES_100K, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN6,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 6, MT6363_PULLUP_RES_100K, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN7,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 7, MT6363_PULLUP_RES_100K, 32, 1, 1),
+};
+
+static const u16 mt6363_auxadc_regs[] = {
+ [PMIC_AUXADC_RQST0] = 0x1108,
+ [PMIC_AUXADC_RQST1] = 0x1109,
+ [PMIC_AUXADC_RQST3] = 0x110c,
+ [PMIC_AUXADC_ADC0] = 0x1088,
+ [PMIC_AUXADC_IMP0] = 0x1208,
+ [PMIC_AUXADC_IMP1] = 0x1209,
+};
+
+static const struct iio_chan_spec mt6373_auxadc_channels[] = {
+ MTK_PMIC_IIO_CHAN(MT6363, chip_temp, CHIP_TEMP, 4, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6363, vcore_temp, VCORE_TEMP, 38, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6363, vproc_temp, VPROC_TEMP, 39, 12, IIO_TEMP),
+ MTK_PMIC_IIO_CHAN(MT6363, vgpu_temp, VGPU_TEMP, 40, 12, IIO_TEMP),
+
+ /* For VIN, ADC12 holds the result depending on which GPIO was activated */
+ MTK_PMIC_IIO_CHAN(MT6363, in1_v, VIN1, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in2_v, VIN2, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in3_v, VIN3, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in4_v, VIN4, 45, 15, IIO_VOLTAGE),
+ MTK_PMIC_IIO_CHAN(MT6363, in5_v, VIN5, 45, 15, IIO_VOLTAGE),
+};
+
+static const struct mtk_pmic_auxadc_chan mt6373_auxadc_ch_desc[] = {
+ MTK_PMIC_ADC_CHAN(CHIP_TEMP, PMIC_AUXADC_RQST0, 4, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
+ MTK_PMIC_ADC_CHAN(VCORE_TEMP, PMIC_AUXADC_RQST3, 0, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
+ MTK_PMIC_ADC_CHAN(VPROC_TEMP, PMIC_AUXADC_RQST3, 1, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
+ MTK_PMIC_ADC_CHAN(VGPU_TEMP, PMIC_AUXADC_RQST3, 2, PMIC_AUXADC_ADC0, 15, 32, 1, 1),
+
+ MTK_PMIC_ADC_EXT_CHAN(VIN1,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 1, MT6363_PULLUP_RES_30K, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN2,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 2, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN3,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 3, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN4,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 4, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
+ MTK_PMIC_ADC_EXT_CHAN(VIN5,
+ PMIC_AUXADC_RQST1, 4, PMIC_AUXADC_ADC0, 15,
+ PMIC_AUXADC_SDMADC_CON0, 5, MT6363_PULLUP_RES_OPEN, 32, 1, 1),
+};
+
static void mt6358_stop_imp_conv(struct mt6359_auxadc *adc_dev)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
@@ -313,9 +461,10 @@ static void mt6358_stop_imp_conv(struct mt6359_auxadc *adc_dev)
regmap_clear_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
}
-static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev)
+static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev, const struct iio_chan_spec *chan)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
struct regmap *regmap = adc_dev->regmap;
u32 val;
int ret;
@@ -323,8 +472,8 @@ static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev)
regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_DCM_CON], MT6358_DCM_CK_SW_EN);
regmap_set_bits(regmap, cinfo->regs[PMIC_AUXADC_IMP1], MT6358_IMP1_AUTOREPEAT_EN);
- ret = regmap_read_poll_timeout(adc_dev->regmap, cinfo->regs[PMIC_AUXADC_IMP0],
- val, val & MT6358_IMP0_IRQ_RDY,
+ ret = regmap_read_poll_timeout(regmap, cinfo->regs[desc->rdy_idx],
+ val, val & desc->rdy_mask,
IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);
if (ret) {
mt6358_stop_imp_conv(adc_dev);
@@ -334,7 +483,8 @@ static int mt6358_start_imp_conv(struct mt6359_auxadc *adc_dev)
return 0;
}
-static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
+static int mt6358_read_imp(struct mt6359_auxadc *adc_dev,
+ const struct iio_chan_spec *chan, int *vbat, int *ibat)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
struct regmap *regmap = adc_dev->regmap;
@@ -342,7 +492,7 @@ static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
u32 val_v;
int ret;
- ret = mt6358_start_imp_conv(adc_dev);
+ ret = mt6358_start_imp_conv(adc_dev, chan);
if (ret)
return ret;
@@ -359,17 +509,19 @@ static int mt6358_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
return 0;
}
-static int mt6359_read_imp(struct mt6359_auxadc *adc_dev, int *vbat, int *ibat)
+static int mt6359_read_imp(struct mt6359_auxadc *adc_dev,
+ const struct iio_chan_spec *chan, int *vbat, int *ibat)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
struct regmap *regmap = adc_dev->regmap;
u32 val, val_v, val_i;
int ret;
/* Start conversion */
regmap_write(regmap, cinfo->regs[PMIC_AUXADC_IMP0], MT6359_IMP0_CONV_EN);
- ret = regmap_read_poll_timeout(regmap, cinfo->regs[PMIC_AUXADC_IMP1],
- val, val & MT6359_IMP1_IRQ_RDY,
+ ret = regmap_read_poll_timeout(regmap, cinfo->regs[desc->rdy_idx],
+ val, val & desc->rdy_mask,
IMP_POLL_DELAY_US, AUXADC_TIMEOUT_US);
/* Stop conversion regardless of the result */
@@ -404,6 +556,7 @@ static const struct mtk_pmic_auxadc_info mt6357_chip_info = {
.regs = mt6357_auxadc_regs,
.imp_adc_num = MT6357_IMP_ADC_NUM,
.read_imp = mt6358_read_imp,
+ .vref_mV = 1800,
};
static const struct mtk_pmic_auxadc_info mt6358_chip_info = {
@@ -414,6 +567,7 @@ static const struct mtk_pmic_auxadc_info mt6358_chip_info = {
.regs = mt6358_auxadc_regs,
.imp_adc_num = MT6358_IMP_ADC_NUM,
.read_imp = mt6358_read_imp,
+ .vref_mV = 1800,
};
static const struct mtk_pmic_auxadc_info mt6359_chip_info = {
@@ -424,6 +578,29 @@ static const struct mtk_pmic_auxadc_info mt6359_chip_info = {
.regs = mt6359_auxadc_regs,
.sec_unlock_key = 0x6359,
.read_imp = mt6359_read_imp,
+ .vref_mV = 1800,
+};
+
+static const struct mtk_pmic_auxadc_info mt6363_chip_info = {
+ .model_name = "MT6363",
+ .channels = mt6363_auxadc_channels,
+ .num_channels = ARRAY_SIZE(mt6363_auxadc_channels),
+ .desc = mt6363_auxadc_ch_desc,
+ .regs = mt6363_auxadc_regs,
+ .is_spmi = true,
+ .no_reset = true,
+ .vref_mV = 1840,
+};
+
+static const struct mtk_pmic_auxadc_info mt6373_chip_info = {
+ .model_name = "MT6373",
+ .channels = mt6373_auxadc_channels,
+ .num_channels = ARRAY_SIZE(mt6373_auxadc_channels),
+ .desc = mt6373_auxadc_ch_desc,
+ .regs = mt6363_auxadc_regs,
+ .is_spmi = true,
+ .no_reset = true,
+ .vref_mV = 1840,
};
static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev)
@@ -431,6 +608,10 @@ static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev)
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
struct regmap *regmap = adc_dev->regmap;
+ /* Some PMICs do not support reset */
+ if (cinfo->no_reset)
+ return;
+
/* Unlock HK_TOP writes */
if (cinfo->sec_unlock_key)
regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], cinfo->sec_unlock_key);
@@ -446,13 +627,29 @@ static void mt6359_auxadc_reset(struct mt6359_auxadc *adc_dev)
regmap_write(regmap, cinfo->regs[PMIC_HK_TOP_WKEY], 0);
}
-static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev,
- const struct iio_chan_spec *chan, int *out)
+/**
+ * mt6359_auxadc_sample_adc_val() - Start ADC channel sampling and read value
+ * @adc_dev: Main driver structure
+ * @chan: IIO Channel spec for requested ADC
+ * @out: Preallocated variable to store the value read from HW
+ *
+ * This function starts the sampling for an ADC channel, waits until all
+ * of the samples are averaged and then reads the value from the HW.
+ *
+ * Note that the caller must stop the ADC sampling on its own, as this
+ * function *never* stops it.
+ *
+ * Return:
+ * Negative number for error;
+ * Upon success returns zero and writes the read value to *out.
+ */
+static int mt6359_auxadc_sample_adc_val(struct mt6359_auxadc *adc_dev,
+ const struct iio_chan_spec *chan, u32 *out)
{
const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
struct regmap *regmap = adc_dev->regmap;
- u32 val;
+ u32 reg, rdy_mask, val, lval;
int ret;
/* Request to start sampling for ADC channel */
@@ -463,16 +660,95 @@ static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev,
/* Wait until all samples are averaged */
fsleep(desc->num_samples * AUXADC_AVG_TIME_US);
- ret = regmap_read_poll_timeout(regmap,
- cinfo->regs[PMIC_AUXADC_ADC0] + (chan->address << 1),
- val, val & PMIC_AUXADC_RDY_BIT,
+ reg = cinfo->regs[PMIC_AUXADC_ADC0] + (chan->address << 1);
+ rdy_mask = PMIC_AUXADC_RDY_BIT;
+
+ /*
+ * Even though for both PWRAP and SPMI cases the ADC HW signals that
+ * the data is ready by setting AUXADC_RDY_BIT, for SPMI the register
+ * read is only 8 bits long: for this case, the check has to be done
+ * on the ADC(x)_H register (high bits) and the rdy_mask needs to be
+ * shifted to the right by the same 8 bits.
+ */
+ if (cinfo->is_spmi) {
+ rdy_mask >>= 8;
+ reg += 1;
+ }
+
+ ret = regmap_read_poll_timeout(regmap, reg, val, val & rdy_mask,
AUXADC_POLL_DELAY_US, AUXADC_TIMEOUT_US);
+ if (ret) {
+ dev_dbg(adc_dev->dev, "ADC read timeout for chan %lu\n", chan->address);
+ return ret;
+ }
+
+ if (cinfo->is_spmi) {
+ ret = regmap_read(regmap, reg - 1, &lval);
+ if (ret)
+ return ret;
+
+ val = (val << 8) | lval;
+ }
+
+ *out = val;
+ return 0;
+}
+
+static int mt6359_auxadc_read_adc(struct mt6359_auxadc *adc_dev,
+ const struct iio_chan_spec *chan, int *out)
+{
+ const struct mtk_pmic_auxadc_info *cinfo = adc_dev->chip_info;
+ const struct mtk_pmic_auxadc_chan *desc = &cinfo->desc[chan->scan_index];
+ struct regmap *regmap = adc_dev->regmap;
+ int ret, adc_stop_err;
+ u8 ext_sel;
+ u32 val;
+
+ if (desc->ext_sel_idx >= 0) {
+ ext_sel = FIELD_PREP(MT6363_EXT_PURES_MASK, desc->ext_sel_pu);
+ ext_sel |= FIELD_PREP(MT6363_EXT_CHAN_MASK, desc->ext_sel_ch);
+
+ ret = regmap_update_bits(regmap, cinfo->regs[desc->ext_sel_idx],
+ MT6363_EXT_PURES_MASK | MT6363_EXT_CHAN_MASK,
+ ext_sel);
+ if (ret)
+ return ret;
+ }
+
+ /*
+ * Get sampled value, then stop sampling unconditionally; the gathered
+ * value is good regardless of if the ADC could be stopped.
+ *
+ * Note that if the ADC cannot be stopped but sampling was ok, this
+ * function will not return any error, but will set the timed_out
+ * status: this is not critical, as the ADC may auto recover and auto
+ * stop after some time (depending on the PMIC model); if not, the next
+ * read attempt will return -ETIMEDOUT and, for models that support it,
+ * reset will be triggered.
+ */
+ ret = mt6359_auxadc_sample_adc_val(adc_dev, chan, &val);
+
+ adc_stop_err = regmap_write(regmap, cinfo->regs[desc->req_idx], 0);
+ if (adc_stop_err) {
+ dev_warn(adc_dev->dev, "Could not stop the ADC: %d\n,", adc_stop_err);
+ adc_dev->timed_out = true;
+ }
+
+ /* If any sampling error occurred, the retrieved value is invalid */
if (ret)
return ret;
- /* Stop sampling */
- regmap_write(regmap, cinfo->regs[desc->req_idx], 0);
+ /* ...and deactivate the ADC GPIO if previously done */
+ if (desc->ext_sel_idx >= 0) {
+ ext_sel = FIELD_PREP(MT6363_EXT_PURES_MASK, MT6363_PULLUP_RES_OPEN);
+
+ ret = regmap_update_bits(regmap, cinfo->regs[desc->ext_sel_idx],
+ MT6363_EXT_PURES_MASK, ext_sel);
+ if (ret)
+ return ret;
+ }
+ /* Everything went fine, give back the ADC reading */
*out = val & GENMASK(chan->scan_type.realbits - 1, 0);
return 0;
}
@@ -493,7 +769,7 @@ static int mt6359_auxadc_read_raw(struct iio_dev *indio_dev,
int ret;
if (mask == IIO_CHAN_INFO_SCALE) {
- *val = desc->r_ratio.numerator * AUXADC_VOLT_FULL;
+ *val = desc->r_ratio.numerator * cinfo->vref_mV;
if (desc->r_ratio.denominator > 1) {
*val2 = desc->r_ratio.denominator;
@@ -506,10 +782,16 @@ static int mt6359_auxadc_read_raw(struct iio_dev *indio_dev,
scoped_guard(mutex, &adc_dev->lock) {
switch (chan->scan_index) {
case PMIC_AUXADC_CHAN_IBAT:
- ret = adc_dev->chip_info->read_imp(adc_dev, NULL, val);
+ if (!adc_dev->chip_info->read_imp)
+ return -EOPNOTSUPP;
+
+ ret = adc_dev->chip_info->read_imp(adc_dev, chan, NULL, val);
break;
case PMIC_AUXADC_CHAN_VBAT:
- ret = adc_dev->chip_info->read_imp(adc_dev, val, NULL);
+ if (!adc_dev->chip_info->read_imp)
+ return -EOPNOTSUPP;
+
+ ret = adc_dev->chip_info->read_imp(adc_dev, chan, val, NULL);
break;
default:
ret = mt6359_auxadc_read_adc(adc_dev, chan, val);
@@ -543,15 +825,36 @@ static const struct iio_info mt6359_auxadc_iio_info = {
static int mt6359_auxadc_probe(struct platform_device *pdev)
{
+ const struct mtk_pmic_auxadc_info *chip_info;
struct device *dev = &pdev->dev;
- struct device *mt6397_mfd_dev = dev->parent;
+ struct device *mfd_dev = dev->parent;
struct mt6359_auxadc *adc_dev;
struct iio_dev *indio_dev;
+ struct device *regmap_dev;
struct regmap *regmap;
int ret;
+ chip_info = device_get_match_data(dev);
+ if (!chip_info)
+ return -EINVAL;
+ /*
+ * The regmap for this device has to be acquired differently for
+ * SoC PMIC Wrapper and SPMI PMIC cases:
+ *
+ * If this is under SPMI, the regmap comes from the direct parent of
+ * this driver: this_device->parent(mfd).
+ * ... or ...
+ * If this is under the SoC PMIC Wrapper, the regmap comes from the
+ * parent of the MT6397 MFD: this_device->parent(mfd)->parent(pwrap)
+ */
+ if (chip_info->is_spmi)
+ regmap_dev = mfd_dev;
+ else
+ regmap_dev = mfd_dev->parent;
+
+
/* Regmap is from SoC PMIC Wrapper, parent of the mt6397 MFD */
- regmap = dev_get_regmap(mt6397_mfd_dev->parent, NULL);
+ regmap = dev_get_regmap(regmap_dev, NULL);
if (!regmap)
return dev_err_probe(dev, -ENODEV, "Failed to get regmap\n");
@@ -562,10 +865,7 @@ static int mt6359_auxadc_probe(struct platform_device *pdev)
adc_dev = iio_priv(indio_dev);
adc_dev->regmap = regmap;
adc_dev->dev = dev;
-
- adc_dev->chip_info = device_get_match_data(dev);
- if (!adc_dev->chip_info)
- return -EINVAL;
+ adc_dev->chip_info = chip_info;
mutex_init(&adc_dev->lock);
@@ -588,6 +888,8 @@ static const struct of_device_id mt6359_auxadc_of_match[] = {
{ .compatible = "mediatek,mt6357-auxadc", .data = &mt6357_chip_info },
{ .compatible = "mediatek,mt6358-auxadc", .data = &mt6358_chip_info },
{ .compatible = "mediatek,mt6359-auxadc", .data = &mt6359_chip_info },
+ { .compatible = "mediatek,mt6363-auxadc", .data = &mt6363_chip_info },
+ { .compatible = "mediatek,mt6373-auxadc", .data = &mt6373_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, mt6359_auxadc_of_match);
diff --git a/drivers/iio/adc/mt6360-adc.c b/drivers/iio/adc/mt6360-adc.c
index f8e98b6fa7e9..69b3569c90e5 100644
--- a/drivers/iio/adc/mt6360-adc.c
+++ b/drivers/iio/adc/mt6360-adc.c
@@ -264,10 +264,9 @@ static irqreturn_t mt6360_adc_trigger_handler(int irq, void *p)
struct {
u16 values[MT6360_CHAN_MAX];
aligned_s64 timestamp;
- } data;
+ } data = { };
int i = 0, bit, val, ret;
- memset(&data, 0, sizeof(data));
iio_for_each_active_channel(indio_dev, bit) {
ret = mt6360_adc_read_channel(mad, bit, &val);
if (ret < 0) {
diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c
index d5209f32adb3..b03cf584b165 100644
--- a/drivers/iio/adc/qcom-vadc-common.c
+++ b/drivers/iio/adc/qcom-vadc-common.c
@@ -330,7 +330,7 @@ static int qcom_vadc7_scale_hw_calib_die_temp(
const struct adc5_data *data,
u16 adc_code, int *result_mdec);
-static struct qcom_adc5_scale_type scale_adc5_fn[] = {
+static const struct qcom_adc5_scale_type scale_adc5_fn[] = {
[SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt},
[SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm},
[SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm},
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 325e3747a134..bd62daea0a3e 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -404,12 +404,10 @@ static irqreturn_t rockchip_saradc_trigger_handler(int irq, void *p)
struct {
u16 values[SARADC_MAX_CHANNELS];
aligned_s64 timestamp;
- } data;
+ } data = { };
int ret;
int i, j = 0;
- memset(&data, 0, sizeof(data));
-
mutex_lock(&info->lock);
iio_for_each_active_channel(i_dev, i) {
diff --git a/drivers/iio/adc/rtq6056.c b/drivers/iio/adc/rtq6056.c
index 6ff47415a222..ad9738228b7f 100644
--- a/drivers/iio/adc/rtq6056.c
+++ b/drivers/iio/adc/rtq6056.c
@@ -645,12 +645,10 @@ static irqreturn_t rtq6056_buffer_trigger_handler(int irq, void *p)
struct {
u16 vals[RTQ6056_MAX_CHANNEL];
aligned_s64 timestamp;
- } data;
+ } data = { };
unsigned int raw;
int i = 0, bit, ret;
- memset(&data, 0, sizeof(data));
-
pm_runtime_get_sync(dev);
iio_for_each_active_channel(indio_dev, bit) {
diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
index 21c04a98b3b6..3d800762c5fc 100644
--- a/drivers/iio/adc/stm32-adc-core.c
+++ b/drivers/iio/adc/stm32-adc-core.c
@@ -407,7 +407,6 @@ static const struct irq_domain_ops stm32_adc_domain_ops = {
static int stm32_adc_irq_probe(struct platform_device *pdev,
struct stm32_adc_priv *priv)
{
- struct device_node *np = pdev->dev.of_node;
unsigned int i;
/*
@@ -421,7 +420,7 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
return priv->irq[i];
}
- priv->domain = irq_domain_create_simple(of_fwnode_handle(np),
+ priv->domain = irq_domain_create_simple(dev_fwnode(&pdev->dev),
STM32_ADC_MAX_ADCS, 0,
&stm32_adc_domain_ops,
priv);
diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
index e84babf43385..b9f93116e114 100644
--- a/drivers/iio/adc/stm32-adc.c
+++ b/drivers/iio/adc/stm32-adc.c
@@ -216,7 +216,7 @@ struct stm32_adc;
struct stm32_adc_cfg {
const struct stm32_adc_regspec *regs;
const struct stm32_adc_info *adc_info;
- struct stm32_adc_trig_info *trigs;
+ const struct stm32_adc_trig_info *trigs;
bool clk_required;
bool has_vregready;
bool has_boostmode;
@@ -383,7 +383,7 @@ static const struct stm32_adc_regs stm32f4_sq[STM32_ADC_MAX_SQ + 1] = {
};
/* STM32F4 external trigger sources for all instances */
-static struct stm32_adc_trig_info stm32f4_adc_trigs[] = {
+static const struct stm32_adc_trig_info stm32f4_adc_trigs[] = {
{ TIM1_CH1, STM32_EXT0 },
{ TIM1_CH2, STM32_EXT1 },
{ TIM1_CH3, STM32_EXT2 },
@@ -473,7 +473,7 @@ static const struct stm32_adc_regs stm32h7_sq[STM32_ADC_MAX_SQ + 1] = {
};
/* STM32H7 external trigger sources for all instances */
-static struct stm32_adc_trig_info stm32h7_adc_trigs[] = {
+static const struct stm32_adc_trig_info stm32h7_adc_trigs[] = {
{ TIM1_CH1, STM32_EXT0 },
{ TIM1_CH2, STM32_EXT1 },
{ TIM1_CH3, STM32_EXT2 },
@@ -2470,7 +2470,7 @@ static int stm32_adc_chan_fw_init(struct iio_dev *indio_dev, bool timestamping)
static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
{
struct stm32_adc *adc = iio_priv(indio_dev);
- struct dma_slave_config config;
+ struct dma_slave_config config = { };
int ret;
adc->dma_chan = dma_request_chan(dev, "rx");
@@ -2494,7 +2494,6 @@ static int stm32_adc_dma_request(struct device *dev, struct iio_dev *indio_dev)
}
/* Configure DMA channel to read data register */
- memset(&config, 0, sizeof(config));
config.src_addr = (dma_addr_t)adc->common->phys_base;
config.src_addr += adc->offset + adc->cfg->regs->dr;
config.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
index f583924eb16b..c2d21eecafe7 100644
--- a/drivers/iio/adc/stm32-dfsdm-adc.c
+++ b/drivers/iio/adc/stm32-dfsdm-adc.c
@@ -8,6 +8,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/export.h>
#include <linux/iio/adc/stm32-dfsdm-adc.h>
#include <linux/iio/backend.h>
#include <linux/iio/buffer.h>
diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c
index 041dc9ebc048..47e2d1338e9e 100644
--- a/drivers/iio/adc/stm32-dfsdm-core.c
+++ b/drivers/iio/adc/stm32-dfsdm-core.c
@@ -8,6 +8,7 @@
#include <linux/bitfield.h>
#include <linux/clk.h>
+#include <linux/export.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/interrupt.h>
diff --git a/drivers/iio/adc/ti-ads1015.c b/drivers/iio/adc/ti-ads1015.c
index 21181cc3bd85..48549d617e5f 100644
--- a/drivers/iio/adc/ti-ads1015.c
+++ b/drivers/iio/adc/ti-ads1015.c
@@ -450,11 +450,9 @@ static irqreturn_t ads1015_trigger_handler(int irq, void *p)
struct {
s16 chan;
aligned_s64 timestamp;
- } scan;
+ } scan = { };
int chan, ret, res;
- memset(&scan, 0, sizeof(scan));
-
mutex_lock(&data->lock);
chan = find_first_bit(indio_dev->active_scan_mask,
iio_get_masklength(indio_dev));
diff --git a/drivers/iio/adc/ti-ads1119.c b/drivers/iio/adc/ti-ads1119.c
index d280c949cf47..d2f86e1ec656 100644
--- a/drivers/iio/adc/ti-ads1119.c
+++ b/drivers/iio/adc/ti-ads1119.c
@@ -507,12 +507,10 @@ static irqreturn_t ads1119_trigger_handler(int irq, void *private)
struct {
s16 sample;
aligned_s64 timestamp;
- } scan;
+ } scan = { };
unsigned int index;
int ret;
- memset(&scan, 0, sizeof(scan));
-
if (!iio_trigger_using_own(indio_dev)) {
index = find_first_bit(indio_dev->active_scan_mask,
iio_get_masklength(indio_dev));
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index 085f0d6fb39e..b18f30d3fdbe 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -625,7 +625,7 @@ static irqreturn_t ads131e08_trigger_handler(int irq, void *private)
* 16 bits of data into the buffer.
*/
unsigned int num_bytes = ADS131E08_NUM_DATA_BYTES(st->data_rate);
- u8 tweek_offset = num_bytes == 2 ? 1 : 0;
+ u8 tweak_offset = num_bytes == 2 ? 1 : 0;
if (iio_trigger_using_own(indio_dev))
ret = ads131e08_read_data(st, st->readback_len);
@@ -640,25 +640,25 @@ static irqreturn_t ads131e08_trigger_handler(int irq, void *private)
dest = st->tmp_buf.data + i * ADS131E08_NUM_STORAGE_BYTES;
/*
- * Tweek offset is 0:
+ * Tweak offset is 0:
* +---+---+---+---+
* |D0 |D1 |D2 | X | (3 data bytes)
* +---+---+---+---+
* a+0 a+1 a+2 a+3
*
- * Tweek offset is 1:
+ * Tweak offset is 1:
* +---+---+---+---+
* |P0 |D0 |D1 | X | (one padding byte and 2 data bytes)
* +---+---+---+---+
* a+0 a+1 a+2 a+3
*/
- memcpy(dest + tweek_offset, src, num_bytes);
+ memcpy(dest + tweak_offset, src, num_bytes);
/*
* Data conversion from 16 bits of data to 24 bits of data
* is done by sign extension (properly filling padding byte).
*/
- if (tweek_offset)
+ if (tweak_offset)
*dest = *src & BIT(7) ? 0xff : 0x00;
i++;
diff --git a/drivers/iio/adc/ti-lmp92064.c b/drivers/iio/adc/ti-lmp92064.c
index 3f375c1f586c..7e57006a8a12 100644
--- a/drivers/iio/adc/ti-lmp92064.c
+++ b/drivers/iio/adc/ti-lmp92064.c
@@ -200,11 +200,9 @@ static irqreturn_t lmp92064_trigger_handler(int irq, void *p)
struct {
u16 values[2];
aligned_s64 timestamp;
- } data;
+ } data = { };
int ret;
- memset(&data, 0, sizeof(data));
-
ret = lmp92064_read_meas(priv, data.values);
if (ret)
goto err;
diff --git a/drivers/iio/adc/ti-tsc2046.c b/drivers/iio/adc/ti-tsc2046.c
index c2d2aada6772..74471f08662e 100644
--- a/drivers/iio/adc/ti-tsc2046.c
+++ b/drivers/iio/adc/ti-tsc2046.c
@@ -276,7 +276,7 @@ static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx,
struct tsc2046_adc_ch_cfg *ch = &priv->ch_cfg[ch_idx];
unsigned int val, val_normalized = 0;
int ret, i, count_skip = 0, max_count;
- struct spi_transfer xfer;
+ struct spi_transfer xfer = { };
struct spi_message msg;
u8 cmd;
@@ -314,7 +314,6 @@ static int tsc2046_adc_read_one(struct tsc2046_adc_priv *priv, int ch_idx,
/* automatically power down on last sample */
tx_buf[i].cmd = tsc2046_adc_get_cmd(priv, ch_idx, false);
- memset(&xfer, 0, sizeof(xfer));
xfer.tx_buf = tx_buf;
xfer.rx_buf = rx_buf;
xfer.len = sizeof(*tx_buf) * max_count;
diff --git a/drivers/iio/adc/vf610_adc.c b/drivers/iio/adc/vf610_adc.c
index 6404b015234a..1b3b1843a801 100644
--- a/drivers/iio/adc/vf610_adc.c
+++ b/drivers/iio/adc/vf610_adc.c
@@ -28,9 +28,6 @@
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
-/* This will be the driver name the kernel reports */
-#define DRIVER_NAME "vf610-adc"
-
/* Vybrid/IMX ADC registers */
#define VF610_REG_ADC_HC0 0x00
#define VF610_REG_ADC_HC1 0x04
@@ -952,7 +949,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(vf610_adc_pm_ops, vf610_adc_suspend,
static struct platform_driver vf610_adc_driver = {
.probe = vf610_adc_probe,
.driver = {
- .name = DRIVER_NAME,
+ .name = "vf610-adc",
.of_match_table = vf610_adc_match,
.pm = pm_sleep_ptr(&vf610_adc_pm_ops),
},