summaryrefslogtreecommitdiff
path: root/drivers/iio/adc
diff options
context:
space:
mode:
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-02-02 17:08:30 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-02-02 17:08:30 +0100
commit9991bbc6d5e8fdfa0b1bcfeebf4637e8fd764bd8 (patch)
tree3f5085832b88f5c26f956103e1dd22dd599920b0 /drivers/iio/adc
parent96657eb5ab7e231f6333a3fbc674c0451f13f7f1 (diff)
parent0713b26190addfa3a774b386c8658952ef9f7faf (diff)
Merge tag 'iio-for-7.0a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio into char-misc-next
Jonathan writes: IIO: New device support, features and cleanup for the 6.20/7.0 cycle. Slightly messier than normal unfortunately due to some conflicts and build config bugs related to I3C drivers. One last minute Kconfig fix right at the top after a linux-next report. I've simplified the Kconfig and made it match other instances in the kernel so that should be safe enough despite short soak time in front of build bots. Merge of an immutable branch from I3C to get some stubs that were missing and caused build issues with dual I2C / I3C drivers. This also brought in a drop of some deprecated interfaces so there is also one patch to update a new driver to not use those. We are having another go at using cleanup.h magic with the IIO mode claim functions after backing out last try at this. This time we have wrappers around the new ACQUIRE() and ACQUIRE_ERR() macros. Having been burnt once, we will be taking it a bit more slowly this time wrt to wide adoption of these! Thanks in particular to Kurt for taking on this core IIO work. New Device Support ================== adi,ad18113 - New driver to support the AD18113 amplifier - an interesting device due to the external bypass paths where we need to describe what gain those paths have in DT. Longer term it will be interesting to see if this simplistic description is enough for real deployments. adi,ad4062 - New driver for the AD4060 and AD4052 SAR ADCs including trigger, event and GPIO controller support. Follow up patch replaced use of some deprecated I3C interfaces prior to the I3C immutable branch merge as that includes dropping them. adi,ad4134 - New driver for the AD4134 24bit 4 channel simultaneous sampling ADC. adi,ad7768-1, - Add support for the ADAQ767-1, ADAQ7768-1 and ADAQ7769-1 ADCs after some rework to enable the driver to support multiple device types. adi,ad9467 - Add support for the similar ad9211 ADC to this existing driver. - Make the selection of 2s comp mode explicit for normal operation and switch to offset binary when entering calibration mode. honeywell,abp2 - New driver to support this huge family (100+) of board mount pressure and temperature sensors. maxim,max22007 - New drier for this 4 channel DAC. memsic,mmc5633 - New driver for this I2C/I3C magnetometer. Follow on patches fixed up issues related to single driver supporting both bus types. microchip,mcp747feb02 - New driver for the Microchip MCP47F(E/V)B(0/1/2)1, MCP47F(E/V)B(0/1/2)2, MCP47F(E/V)B(0/1/2)4 and MCP47F(E/V)B(0/1/2)8 buffered voltage output DACs. nxp,sar-adc - New driver support ADCs found on s32g2 and s32g3 platforms. ti,ads1018 - New drier for the ADS1018 and ADS1118 SPI ADCs. ti,ads131m02 - New driver supporting ADS131M(02/03/04/06/08)24-bit simultaneous sampling ADCs. Features ======== iio-core - New IIO_DEV_ACQUIRE_DIRECT_MODE() / IIO_DEV_ACQUIRE_FAILED() + equivalents for the much rarer case where the mode needs pinning whether or not it is in direct mode. These use the ACQUIRE() / ACQUIRE_ERR() infrastructure underneath to provide both simple checks on whether we got the requested mode and to provide scope based release. Applied in a few initial drivers. adi,ad9467 - Support calibbias control adi,adf4377 - Add support to act as a clock provider. adi,adxl380 - Support low power 1KHz sampling frequency mode. Required rework of how events and filters were configured, plus applying of constraints when in this mode. rf-digital,rfd77402 - Add interrupt support as alternative to polling for completion. st,lsm6dsx - Tap event detection (after considerable driver rework) Cleanup and Minor Fixes ======================= More minor cleanup such as typos, white space etc not called out except where they were applied to a lot of drivers. Various drivers. - Use of dev_err_probe() to cleanup error handling. - Introduce local struct device and struct device_node variables to reduce duplication of getting them from containing structs. - Ensure uses of iio_trigger_generic_data_rdy_poll() set IRQF_NO_THREAD as that function calls non threaded child interrupt handlers. - Replace IRQF_ONESHOT in not thread interrupt handlers with IRQF_NO_THREAD to ensure they run as intended. Drop one unnecessary case. iio-sw-device/trigger. - Constify configs_group_operations structures. iio-buffer-dma / buffer-dma-engine - Use lockdep_assert_held() to replace WARN_ON() to check lock is correctly held. - Make use of cleanup.h magic to simplify various code paths. - Make iio_dma_buffer_init() return void rather than always success. adi,ad7766 - Replace custom interrupt handler with iio_trigger_generic_data_rdy_poll() adi,ad9832 - Drop legacy platform_data support. adi,ade9000 - Add a maintainer entry. adi,adt7316 - Move to EXPORT_GPL_SIMPLE_DEV_PM_OPS() and pm_sleep_ptr() so the compiler can cleanly drop unused pm structures and callbacks. adi,adxl345 - Relax build constraint vs the driver that is in input so both may be built as modules and selection made at runtime. adi,adxl380 - Make sure we don't read tail entries in the hardware fifo if a partial new scan has been written. - Move to a single larger regmap_noinc_read() to read the hardware fifo. aspeed,ast2600 - Add missing interrupts property to DT binding. bosch,bmi270_i2c - Add missing MODULE_DEVICE_TABLE() macros so auto probing of modules can work. bosch,smi330 - Drop duplicate assignment of IIO_TYPE in smi330_read_avail() - Use new common field_get() and field_prep() helpers to replace local version. honeywell,mprls0025pa Fixes delayed to merge window as late in cycle and we didn't want to delay the rest of the series. - Allow Kconfig selection of specific bus sub-drivers rather than tying that to the buses themselves being supported. - Zero spi_transfer structure to avoid chance of unintentionally set fields effecting transfer. - Fix a potential timing violation wrt to the chip select to first clock edge timing. - As recent driver, take risk inherent in dropping interrupt direction from driver as that should be set by firmware. - Fix wrong reported number of data bits for channel. - Fix a pressure channel calculation bug. - Rework to allow embedding the tx buffer in the iio_priv() structure rather than requiring separate allocation. - Move the buffer clearing to the shared core bringing it into affect for SPI as well as I2C. - Stricter checks for status byte. - Greatly simplify the measurement sequence. - Add a copyright entry to reflect Petre's continued work on this driver. intersil,isl29018 - Switch from spritnf to sysfs_emit_at() to make it clear overflow can't occur. invensense,icm42600 - Allow sysfs access to temperature when buffered capture in use as it does not impact other sensor data paths. invensense,itg3200 - Check unused return value in read_raw() callback. men,z188 - Drop now duplicated module alias. rf-digital,rfd77402 - Add DT binding doc and explicit of_device_id table. - Poll for timeout with times as on datasheet, then replace opencoded version with read_poll_timeout(). sensiron,scd4x - Add missing timestamp channel. The code to push it to the buffer was there but there was no way to turn it on. vti,sca3000 - Fix resource leak if iio_device_register() fails. * tag 'iio-for-7.0a' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (144 commits) iio: magn: mmc5633: Fix Kconfig for combination of I3C as module and driver builtin iio: sca3000: Fix a resource leak in sca3000_probe() iio: proximity: rfd77402: Add interrupt handling support iio: proximity: rfd77402: Document device private data structure iio: proximity: rfd77402: Use devm-managed mutex initialization iio: proximity: rfd77402: Use kernel helper for result polling iio: proximity: rfd77402: Align polling timeout with datasheet iio: cros_ec: Allow enabling/disabling calibration mode iio: frequency: ad9523: correct kernel-doc bad line warning iio: buffer: buffer_impl.h: fix kernel-doc warnings iio: gyro: itg3200: Fix unchecked return value in read_raw MAINTAINERS: add entry for ADE9000 driver iio: accel: sca3000: remove unused last_timestamp field iio: accel: adxl372: remove unused int2_bitmask field iio: adc: ad7766: Use iio_trigger_generic_data_rdy_poll() iio: magnetometer: Remove IRQF_ONESHOT iio: Replace IRQF_ONESHOT with IRQF_NO_THREAD iio: Use IRQF_NO_THREAD iio: dac: Add MAX22007 DAC driver support dt-bindings: iio: dac: Add max22007 ...
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/Kconfig60
-rw-r--r--drivers/iio/adc/Makefile5
-rw-r--r--drivers/iio/adc/ad4062.c1609
-rw-r--r--drivers/iio/adc/ad4134.c500
-rw-r--r--drivers/iio/adc/ad4170-4.c2
-rw-r--r--drivers/iio/adc/ad7476.c1
-rw-r--r--drivers/iio/adc/ad7606_spi.c2
-rw-r--r--drivers/iio/adc/ad7766.c10
-rw-r--r--drivers/iio/adc/ad7768-1.c428
-rw-r--r--drivers/iio/adc/ad7779.c2
-rw-r--r--drivers/iio/adc/ad9467.c152
-rw-r--r--drivers/iio/adc/ade9000.c2
-rw-r--r--drivers/iio/adc/adi-axi-adc.c64
-rw-r--r--drivers/iio/adc/aspeed_adc.c49
-rw-r--r--drivers/iio/adc/exynos_adc.c57
-rw-r--r--drivers/iio/adc/mcp3911.c2
-rw-r--r--drivers/iio/adc/men_z188_adc.c1
-rw-r--r--drivers/iio/adc/nxp-sar-adc.c1016
-rw-r--r--drivers/iio/adc/qcom-spmi-rradc.c20
-rw-r--r--drivers/iio/adc/rockchip_saradc.c59
-rw-r--r--drivers/iio/adc/sc27xx_adc.c49
-rw-r--r--drivers/iio/adc/ti-ads1018.c739
-rw-r--r--drivers/iio/adc/ti-ads131e08.c2
-rw-r--r--drivers/iio/adc/ti-ads131m02.c968
24 files changed, 5534 insertions, 265 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 58da8255525e..60038ae8dfc4 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -70,6 +70,19 @@ config AD4030
To compile this driver as a module, choose M here: the module will be
called ad4030.
+config AD4062
+ tristate "Analog Devices AD4062 Driver"
+ depends on I3C
+ select REGMAP_I3C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Analog Devices AD4062 I3C analog
+ to digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad4062.
+
config AD4080
tristate "Analog Devices AD4080 high speed ADC"
depends on SPI
@@ -99,6 +112,17 @@ config AD4130
To compile this driver as a module, choose M here: the module will be
called ad4130.
+config AD4134
+ tristate "Analog Device AD4134 ADC Driver"
+ depends on SPI
+ select REGMAP_SPI
+ select CRC8
+ help
+ Say yes here to build support for Analog Devices AD4134 SPI analog to
+ digital converters (ADC).
+
+ To compile this driver as a module, choose M here: the module will be
+ called ad4134_spi.
config AD4170_4
tristate "Analog Device AD4170-4 ADC Driver"
@@ -387,6 +411,7 @@ config AD7768_1
depends on SPI
select REGULATOR
select REGMAP_SPI
+ select RATIONAL
select IIO_BUFFER
select IIO_TRIGGER
select IIO_TRIGGERED_BUFFER
@@ -1222,6 +1247,18 @@ config NPCM_ADC
This driver can also be built as a module. If so, the module
will be called npcm_adc.
+config NXP_SAR_ADC
+ tristate "NXP S32G SAR-ADC driver"
+ depends on ARCH_S32 || COMPILE_TEST
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for S32G platforms
+ analog-to-digital converter.
+
+ This driver can also be built as a module. If so, the module will be
+ called nxp_sar_adc.
+
config PAC1921
tristate "Microchip Technology PAC1921 driver"
depends on I2C
@@ -1664,6 +1701,18 @@ config TI_ADS1015
This driver can also be built as a module. If so, the module will be
called ti-ads1015.
+config TI_ADS1018
+ tristate "Texas Instruments ADS1018 ADC"
+ depends on SPI
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ If you say yes here you get support for Texas Instruments ADS1018 and
+ ADS1118 ADC chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads1018.
+
config TI_ADS1100
tristate "Texas Instruments ADS1100 and ADS1000 ADC"
depends on I2C
@@ -1722,6 +1771,17 @@ config TI_ADS131E08
This driver can also be built as a module. If so, the module will be
called ti-ads131e08.
+config TI_ADS131M02
+ tristate "Texas Instruments ADS131M02"
+ depends on SPI && REGULATOR
+ select CRC_ITU_T
+ help
+ Say yes here to get support for Texas Instruments ADS131M02, ADS131M03,
+ ADS131M04, ADS131M06 and ADS131M08 chips.
+
+ This driver can also be built as a module. If so, the module will be
+ called ti-ads131m02.
+
config TI_ADS7138
tristate "Texas Instruments ADS7128 and ADS7138 ADC driver"
depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 7cc8f9a12f76..c76550415ff1 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -11,8 +11,10 @@ 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_AD4062) += ad4062.o
obj-$(CONFIG_AD4080) += ad4080.o
obj-$(CONFIG_AD4130) += ad4130.o
+obj-$(CONFIG_AD4134) += ad4134.o
obj-$(CONFIG_AD4170_4) += ad4170-4.o
obj-$(CONFIG_AD4695) += ad4695.o
obj-$(CONFIG_AD4851) += ad4851.o
@@ -108,6 +110,7 @@ obj-$(CONFIG_MXS_LRADC_ADC) += mxs-lradc-adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_NCT7201) += nct7201.o
obj-$(CONFIG_NPCM_ADC) += npcm_adc.o
+obj-$(CONFIG_NXP_SAR_ADC) += nxp-sar-adc.o
obj-$(CONFIG_PAC1921) += pac1921.o
obj-$(CONFIG_PAC1934) += pac1934.o
obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
@@ -145,11 +148,13 @@ obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
obj-$(CONFIG_TI_ADC161S626) += ti-adc161s626.o
obj-$(CONFIG_TI_ADS1015) += ti-ads1015.o
+obj-$(CONFIG_TI_ADS1018) += ti-ads1018.o
obj-$(CONFIG_TI_ADS1100) += ti-ads1100.o
obj-$(CONFIG_TI_ADS1119) += ti-ads1119.o
obj-$(CONFIG_TI_ADS124S08) += ti-ads124s08.o
obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
+obj-$(CONFIG_TI_ADS131M02) += ti-ads131m02.o
obj-$(CONFIG_TI_ADS7138) += ti-ads7138.o
obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o
obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
diff --git a/drivers/iio/adc/ad4062.c b/drivers/iio/adc/ad4062.c
new file mode 100644
index 000000000000..dd4ad32aa6f5
--- /dev/null
+++ b/drivers/iio/adc/ad4062.c
@@ -0,0 +1,1609 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Analog Devices AD4062 I3C ADC driver
+ *
+ * Copyright 2025 Analog Devices Inc.
+ */
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/devm-helpers.h>
+#include <linux/err.h>
+#include <linux/gpio/driver.h>
+#include <linux/i3c/device.h>
+#include <linux/i3c/master.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/math.h>
+#include <linux/minmax.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/units.h>
+#include <linux/unaligned.h>
+#include <linux/util_macros.h>
+
+#define AD4062_REG_INTERFACE_CONFIG_A 0x00
+#define AD4062_REG_DEVICE_CONFIG 0x02
+#define AD4062_REG_DEVICE_CONFIG_POWER_MODE_MSK GENMASK(1, 0)
+#define AD4062_REG_DEVICE_CONFIG_LOW_POWER_MODE 3
+#define AD4062_REG_PROD_ID_1 0x05
+#define AD4062_REG_DEVICE_GRADE 0x06
+#define AD4062_REG_SCRATCH_PAD 0x0A
+#define AD4062_REG_VENDOR_H 0x0D
+#define AD4062_REG_STREAM_MODE 0x0E
+#define AD4062_REG_INTERFACE_STATUS 0x11
+#define AD4062_REG_MODE_SET 0x20
+#define AD4062_REG_MODE_SET_ENTER_ADC BIT(0)
+#define AD4062_REG_ADC_MODES 0x21
+#define AD4062_REG_ADC_MODES_MODE_MSK GENMASK(1, 0)
+#define AD4062_REG_ADC_CONFIG 0x22
+#define AD4062_REG_ADC_CONFIG_REF_EN_MSK BIT(5)
+#define AD4062_REG_ADC_CONFIG_SCALE_EN_MSK BIT(4)
+#define AD4062_REG_AVG_CONFIG 0x23
+#define AD4062_REG_GP_CONF 0x24
+#define AD4062_REG_GP_CONF_MODE_MSK_0 GENMASK(2, 0)
+#define AD4062_REG_GP_CONF_MODE_MSK_1 GENMASK(6, 4)
+#define AD4062_REG_INTR_CONF 0x25
+#define AD4062_REG_INTR_CONF_EN_MSK_0 GENMASK(1, 0)
+#define AD4062_REG_INTR_CONF_EN_MSK_1 GENMASK(5, 4)
+#define AD4062_REG_TIMER_CONFIG 0x27
+#define AD4062_REG_TIMER_CONFIG_FS_MASK GENMASK(7, 4)
+#define AD4062_REG_MAX_LIMIT 0x29
+#define AD4062_REG_MIN_LIMIT 0x2B
+#define AD4062_REG_MAX_HYST 0x2C
+#define AD4062_REG_MIN_HYST 0x2D
+#define AD4062_REG_MON_VAL 0x2F
+#define AD4062_REG_ADC_IBI_EN 0x31
+#define AD4062_REG_ADC_IBI_EN_CONV_TRIGGER BIT(2)
+#define AD4062_REG_ADC_IBI_EN_MAX BIT(1)
+#define AD4062_REG_ADC_IBI_EN_MIN BIT(0)
+#define AD4062_REG_FUSE_CRC 0x40
+#define AD4062_REG_DEVICE_STATUS 0x41
+#define AD4062_REG_DEVICE_STATUS_DEVICE_RESET BIT(6)
+#define AD4062_REG_IBI_STATUS 0x48
+#define AD4062_REG_CONV_READ_LSB 0x50
+#define AD4062_REG_CONV_READ_16BITS 0x51
+#define AD4062_REG_CONV_READ_32BITS 0x53
+#define AD4062_REG_CONV_TRIGGER_16BITS 0x57
+#define AD4062_REG_CONV_TRIGGER_32BITS 0x59
+#define AD4062_REG_CONV_AUTO 0x61
+#define AD4062_MAX_REG AD4062_REG_CONV_AUTO
+
+#define AD4062_MON_VAL_MIDDLE_POINT 0x8000
+
+#define AD4062_I3C_VENDOR 0x0177
+#define AD4062_SOFT_RESET 0x81
+#define AD4060_PROD_ID 0x7A
+#define AD4062_PROD_ID 0x7C
+
+#define AD4062_GP_DISABLED 0x0
+#define AD4062_GP_INTR 0x1
+#define AD4062_GP_DRDY 0x2
+#define AD4062_GP_STATIC_LOW 0x5
+#define AD4062_GP_STATIC_HIGH 0x6
+
+#define AD4062_LIMIT_BITS 12
+
+#define AD4062_INTR_EN_NEITHER 0x0
+#define AD4062_INTR_EN_EITHER 0x3
+
+#define AD4062_TCONV_NS 270
+
+enum ad4062_operation_mode {
+ AD4062_SAMPLE_MODE = 0x0,
+ AD4062_BURST_AVERAGING_MODE = 0x1,
+ AD4062_MONITOR_MODE = 0x3,
+};
+
+struct ad4062_chip_info {
+ const struct iio_chan_spec channels[1];
+ const char *name;
+ u16 prod_id;
+ u16 avg_max;
+};
+
+enum {
+ AD4062_SCAN_TYPE_SAMPLE,
+ AD4062_SCAN_TYPE_BURST_AVG,
+};
+
+static const struct iio_scan_type ad4062_scan_type_12_s[] = {
+ [AD4062_SCAN_TYPE_SAMPLE] = {
+ .sign = 's',
+ .realbits = 12,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ [AD4062_SCAN_TYPE_BURST_AVG] = {
+ .sign = 's',
+ .realbits = 14,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+};
+
+static const struct iio_scan_type ad4062_scan_type_16_s[] = {
+ [AD4062_SCAN_TYPE_SAMPLE] = {
+ .sign = 's',
+ .realbits = 16,
+ .storagebits = 16,
+ .endianness = IIO_BE,
+ },
+ [AD4062_SCAN_TYPE_BURST_AVG] = {
+ .sign = 's',
+ .realbits = 20,
+ .storagebits = 32,
+ .endianness = IIO_BE,
+ },
+};
+
+static const unsigned int ad4062_conversion_freqs[] = {
+ 2000000, 1000000, 300000, 100000, /* 0 - 3 */
+ 33300, 10000, 3000, 500, /* 4 - 7 */
+ 333, 250, 200, 166, /* 8 - 11 */
+ 140, 124, 111, /* 12 - 15 */
+};
+
+struct ad4062_state {
+ const struct ad4062_chip_info *chip;
+ const struct ad4062_bus_ops *ops;
+ enum ad4062_operation_mode mode;
+ struct work_struct trig_conv;
+ struct completion completion;
+ struct iio_trigger *trigger;
+ struct iio_dev *indio_dev;
+ struct i3c_device *i3cdev;
+ struct regmap *regmap;
+ bool wait_event;
+ int vref_uV;
+ unsigned int samp_freqs[ARRAY_SIZE(ad4062_conversion_freqs)];
+ bool gpo_irq[2];
+ u16 sampling_frequency;
+ u16 events_frequency;
+ u8 oversamp_ratio;
+ u8 conv_sizeof;
+ u8 conv_addr;
+ union {
+ __be32 be32;
+ __be16 be16;
+ } buf __aligned(IIO_DMA_MINALIGN);
+};
+
+static const struct regmap_range ad4062_regmap_rd_ranges[] = {
+ regmap_reg_range(AD4062_REG_INTERFACE_CONFIG_A, AD4062_REG_DEVICE_GRADE),
+ regmap_reg_range(AD4062_REG_SCRATCH_PAD, AD4062_REG_INTERFACE_STATUS),
+ regmap_reg_range(AD4062_REG_MODE_SET, AD4062_REG_ADC_IBI_EN),
+ regmap_reg_range(AD4062_REG_FUSE_CRC, AD4062_REG_IBI_STATUS),
+ regmap_reg_range(AD4062_REG_CONV_READ_LSB, AD4062_REG_CONV_AUTO),
+};
+
+static const struct regmap_access_table ad4062_regmap_rd_table = {
+ .yes_ranges = ad4062_regmap_rd_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad4062_regmap_rd_ranges),
+};
+
+static const struct regmap_range ad4062_regmap_wr_ranges[] = {
+ regmap_reg_range(AD4062_REG_INTERFACE_CONFIG_A, AD4062_REG_DEVICE_CONFIG),
+ regmap_reg_range(AD4062_REG_SCRATCH_PAD, AD4062_REG_SCRATCH_PAD),
+ regmap_reg_range(AD4062_REG_STREAM_MODE, AD4062_REG_INTERFACE_STATUS),
+ regmap_reg_range(AD4062_REG_MODE_SET, AD4062_REG_ADC_IBI_EN),
+ regmap_reg_range(AD4062_REG_FUSE_CRC, AD4062_REG_DEVICE_STATUS),
+};
+
+static const struct regmap_access_table ad4062_regmap_wr_table = {
+ .yes_ranges = ad4062_regmap_wr_ranges,
+ .n_yes_ranges = ARRAY_SIZE(ad4062_regmap_wr_ranges),
+};
+
+static const struct iio_event_spec ad4062_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_shared_by_all = BIT(IIO_EV_INFO_ENABLE),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_shared_by_all = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_shared_by_all = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_HYSTERESIS),
+ },
+};
+
+#define AD4062_CHAN(bits) { \
+ .type = IIO_VOLTAGE, \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_CALIBSCALE) | \
+ BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .indexed = 1, \
+ .channel = 0, \
+ .event_spec = ad4062_events, \
+ .num_event_specs = ARRAY_SIZE(ad4062_events), \
+ .has_ext_scan_type = 1, \
+ .ext_scan_type = ad4062_scan_type_##bits##_s, \
+ .num_ext_scan_type = ARRAY_SIZE(ad4062_scan_type_##bits##_s), \
+}
+
+static const struct ad4062_chip_info ad4060_chip_info = {
+ .name = "ad4060",
+ .channels = { AD4062_CHAN(12) },
+ .prod_id = AD4060_PROD_ID,
+ .avg_max = 256,
+};
+
+static const struct ad4062_chip_info ad4062_chip_info = {
+ .name = "ad4062",
+ .channels = { AD4062_CHAN(16) },
+ .prod_id = AD4062_PROD_ID,
+ .avg_max = 4096,
+};
+
+static ssize_t sampling_frequency_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ad4062_state *st = iio_priv(dev_to_iio_dev(dev));
+
+ return sysfs_emit(buf, "%d\n", ad4062_conversion_freqs[st->events_frequency]);
+}
+
+static int sampling_frequency_store_dispatch(struct iio_dev *indio_dev,
+ const char *buf)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ int val, ret;
+
+ if (st->wait_event)
+ return -EBUSY;
+
+ ret = kstrtoint(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ st->events_frequency = find_closest_descending(val, ad4062_conversion_freqs,
+ ARRAY_SIZE(ad4062_conversion_freqs));
+ return 0;
+}
+
+static ssize_t sampling_frequency_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
+{
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = sampling_frequency_store_dispatch(indio_dev, buf);
+ iio_device_release_direct(indio_dev);
+ return ret ?: len;
+}
+
+static IIO_DEVICE_ATTR_RW(sampling_frequency, 0);
+
+static ssize_t sampling_frequency_available_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret = 0;
+
+ for (u8 i = 0; i < ARRAY_SIZE(ad4062_conversion_freqs); i++)
+ ret += sysfs_emit_at(buf, ret, "%d%s", ad4062_conversion_freqs[i],
+ i != (ARRAY_SIZE(ad4062_conversion_freqs) - 1) ? " " : "\n");
+ return ret;
+}
+
+static IIO_DEVICE_ATTR_RO(sampling_frequency_available, 0);
+
+static struct attribute *ad4062_event_attributes[] = {
+ &iio_dev_attr_sampling_frequency.dev_attr.attr,
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group ad4062_event_attribute_group = {
+ .attrs = ad4062_event_attributes,
+};
+
+static int ad4062_set_oversampling_ratio(struct ad4062_state *st, int val, int val2)
+{
+ const u32 _max = st->chip->avg_max;
+ const u32 _min = 1;
+ int ret;
+
+ if (!in_range(val, _min, _max) || val2 != 0)
+ return -EINVAL;
+
+ /* 1 disables oversampling */
+ val = ilog2(val);
+ if (val == 0) {
+ st->mode = AD4062_SAMPLE_MODE;
+ } else {
+ st->mode = AD4062_BURST_AVERAGING_MODE;
+ ret = regmap_write(st->regmap, AD4062_REG_AVG_CONFIG, val - 1);
+ if (ret)
+ return ret;
+ }
+ st->oversamp_ratio = val;
+
+ return 0;
+}
+
+static int ad4062_get_oversampling_ratio(struct ad4062_state *st, int *val)
+{
+ int ret, buf;
+
+ if (st->mode == AD4062_SAMPLE_MODE) {
+ *val = 1;
+ return 0;
+ }
+
+ ret = regmap_read(st->regmap, AD4062_REG_AVG_CONFIG, &buf);
+ if (ret)
+ return ret;
+
+ *val = BIT(buf + 1);
+ return 0;
+}
+
+static int ad4062_calc_sampling_frequency(unsigned int fosc, unsigned int oversamp_ratio)
+{
+ /* From datasheet p.31: (n_avg - 1)/fosc + tconv */
+ u32 n_avg = BIT(oversamp_ratio) - 1;
+ u32 period_ns = NSEC_PER_SEC / fosc;
+
+ /* Result is less than 1 Hz */
+ if (n_avg >= fosc)
+ return 1;
+
+ return NSEC_PER_SEC / (n_avg * period_ns + AD4062_TCONV_NS);
+}
+
+static int ad4062_populate_sampling_frequency(struct ad4062_state *st)
+{
+ for (u8 i = 0; i < ARRAY_SIZE(ad4062_conversion_freqs); i++)
+ st->samp_freqs[i] =
+ ad4062_calc_sampling_frequency(ad4062_conversion_freqs[i],
+ st->oversamp_ratio);
+ return 0;
+}
+
+static int ad4062_get_sampling_frequency(struct ad4062_state *st, int *val)
+{
+ int freq = ad4062_conversion_freqs[st->sampling_frequency];
+
+ *val = ad4062_calc_sampling_frequency(freq, st->oversamp_ratio);
+ return IIO_VAL_INT;
+}
+
+static int ad4062_set_sampling_frequency(struct ad4062_state *st, int val, int val2)
+{
+ int ret;
+
+ if (val2 != 0)
+ return -EINVAL;
+
+ ret = ad4062_populate_sampling_frequency(st);
+ if (ret)
+ return ret;
+
+ st->sampling_frequency =
+ find_closest_descending(val, st->samp_freqs,
+ ARRAY_SIZE(ad4062_conversion_freqs));
+ return 0;
+}
+
+static int ad4062_check_ids(struct ad4062_state *st)
+{
+ struct device *dev = &st->i3cdev->dev;
+ int ret;
+ u16 val;
+
+ ret = regmap_bulk_read(st->regmap, AD4062_REG_PROD_ID_1,
+ &st->buf.be16, sizeof(st->buf.be16));
+ if (ret)
+ return ret;
+
+ val = be16_to_cpu(st->buf.be16);
+ if (val != st->chip->prod_id)
+ dev_warn(dev, "Production ID x%x does not match known values", val);
+
+ ret = regmap_bulk_read(st->regmap, AD4062_REG_VENDOR_H,
+ &st->buf.be16, sizeof(st->buf.be16));
+ if (ret)
+ return ret;
+
+ val = be16_to_cpu(st->buf.be16);
+ if (val != AD4062_I3C_VENDOR) {
+ dev_err(dev, "Vendor ID x%x does not match expected value\n", val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int ad4062_conversion_frequency_set(struct ad4062_state *st, u8 val)
+{
+ return regmap_write(st->regmap, AD4062_REG_TIMER_CONFIG,
+ FIELD_PREP(AD4062_REG_TIMER_CONFIG_FS_MASK, val));
+}
+
+static int ad4062_set_operation_mode(struct ad4062_state *st,
+ enum ad4062_operation_mode mode)
+{
+ const unsigned int samp_freq = mode == AD4062_MONITOR_MODE ?
+ st->events_frequency : st->sampling_frequency;
+ int ret;
+
+ ret = ad4062_conversion_frequency_set(st, samp_freq);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4062_REG_ADC_MODES,
+ AD4062_REG_ADC_MODES_MODE_MSK, mode);
+ if (ret)
+ return ret;
+
+ if (mode == AD4062_MONITOR_MODE) {
+ /* Change address pointer to enter monitor mode */
+ struct i3c_xfer xfer_trigger = {
+ .data.out = &st->conv_addr,
+ .len = sizeof(st->conv_addr),
+ .rnw = false,
+ };
+ st->conv_addr = AD4062_REG_CONV_TRIGGER_32BITS;
+ return i3c_device_do_xfers(st->i3cdev, &xfer_trigger, 1, I3C_SDR);
+ }
+
+ return regmap_write(st->regmap, AD4062_REG_MODE_SET,
+ AD4062_REG_MODE_SET_ENTER_ADC);
+}
+
+static int ad4062_soft_reset(struct ad4062_state *st)
+{
+ u8 val = AD4062_SOFT_RESET;
+ int ret;
+
+ ret = regmap_write(st->regmap, AD4062_REG_INTERFACE_CONFIG_A, val);
+ if (ret)
+ return ret;
+
+ /* Wait AD4062 treset time, datasheet p8 */
+ ndelay(60);
+
+ return 0;
+}
+
+static int ad4062_setup(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+ const bool *ref_sel)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ const struct iio_scan_type *scan_type;
+ int ret;
+
+ scan_type = iio_get_current_scan_type(indio_dev, chan);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
+ ret = regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
+ AD4062_REG_GP_CONF_MODE_MSK_0,
+ FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_0,
+ AD4062_GP_INTR));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
+ AD4062_REG_GP_CONF_MODE_MSK_1,
+ FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_1,
+ AD4062_GP_DRDY));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4062_REG_ADC_CONFIG,
+ AD4062_REG_ADC_CONFIG_REF_EN_MSK,
+ FIELD_PREP(AD4062_REG_ADC_CONFIG_REF_EN_MSK,
+ *ref_sel));
+ if (ret)
+ return ret;
+
+ ret = regmap_write(st->regmap, AD4062_REG_DEVICE_STATUS,
+ AD4062_REG_DEVICE_STATUS_DEVICE_RESET);
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4062_REG_INTR_CONF,
+ AD4062_REG_INTR_CONF_EN_MSK_0,
+ FIELD_PREP(AD4062_REG_INTR_CONF_EN_MSK_0,
+ AD4062_INTR_EN_EITHER));
+ if (ret)
+ return ret;
+
+ ret = regmap_update_bits(st->regmap, AD4062_REG_INTR_CONF,
+ AD4062_REG_INTR_CONF_EN_MSK_1,
+ FIELD_PREP(AD4062_REG_INTR_CONF_EN_MSK_1,
+ AD4062_INTR_EN_NEITHER));
+ if (ret)
+ return ret;
+
+ st->buf.be16 = cpu_to_be16(AD4062_MON_VAL_MIDDLE_POINT);
+ return regmap_bulk_write(st->regmap, AD4062_REG_MON_VAL,
+ &st->buf.be16, sizeof(st->buf.be16));
+}
+
+static irqreturn_t ad4062_irq_handler_thresh(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+
+ iio_push_event(indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ iio_get_time_ns(indio_dev));
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ad4062_irq_handler_drdy(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct ad4062_state *st = iio_priv(indio_dev);
+
+ if (iio_buffer_enabled(indio_dev) && iio_trigger_using_own(indio_dev))
+ iio_trigger_poll(st->trigger);
+ else
+ complete(&st->completion);
+
+ return IRQ_HANDLED;
+}
+
+static void ad4062_ibi_handler(struct i3c_device *i3cdev,
+ const struct i3c_ibi_payload *payload)
+{
+ struct ad4062_state *st = i3cdev_get_drvdata(i3cdev);
+
+ if (st->wait_event) {
+ iio_push_event(st->indio_dev,
+ IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER),
+ iio_get_time_ns(st->indio_dev));
+ return;
+ }
+ if (iio_buffer_enabled(st->indio_dev))
+ iio_trigger_poll_nested(st->trigger);
+ else
+ complete(&st->completion);
+}
+
+static void ad4062_trigger_work(struct work_struct *work)
+{
+ struct ad4062_state *st =
+ container_of(work, struct ad4062_state, trig_conv);
+ int ret;
+
+ /*
+ * Read current conversion, if at reg CONV_READ, stop bit triggers
+ * next sample and does not need writing the address.
+ */
+ struct i3c_xfer xfer_sample = {
+ .data.in = &st->buf.be32,
+ .len = st->conv_sizeof,
+ .rnw = true,
+ };
+ struct i3c_xfer xfer_trigger = {
+ .data.out = &st->conv_addr,
+ .len = sizeof(st->conv_addr),
+ .rnw = false,
+ };
+
+ ret = i3c_device_do_xfers(st->i3cdev, &xfer_sample, 1, I3C_SDR);
+ if (ret)
+ return;
+
+ iio_push_to_buffers_with_ts(st->indio_dev, &st->buf.be32, st->conv_sizeof,
+ iio_get_time_ns(st->indio_dev));
+ if (st->gpo_irq[1])
+ return;
+
+ i3c_device_do_xfers(st->i3cdev, &xfer_trigger, 1, I3C_SDR);
+}
+
+static irqreturn_t ad4062_poll_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ad4062_state *st = iio_priv(indio_dev);
+
+ iio_trigger_notify_done(indio_dev->trig);
+ schedule_work(&st->trig_conv);
+
+ return IRQ_HANDLED;
+}
+
+static void ad4062_disable_ibi(void *data)
+{
+ struct i3c_device *i3cdev = data;
+
+ i3c_device_disable_ibi(i3cdev);
+}
+
+static void ad4062_free_ibi(void *data)
+{
+ struct i3c_device *i3cdev = data;
+
+ i3c_device_free_ibi(i3cdev);
+}
+
+static int ad4062_request_ibi(struct i3c_device *i3cdev)
+{
+ const struct i3c_ibi_setup ibireq = {
+ .max_payload_len = 1,
+ .num_slots = 1,
+ .handler = ad4062_ibi_handler,
+ };
+ int ret;
+
+ ret = i3c_device_request_ibi(i3cdev, &ibireq);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(&i3cdev->dev, ad4062_free_ibi, i3cdev);
+ if (ret)
+ return ret;
+
+ ret = i3c_device_enable_ibi(i3cdev);
+ if (ret)
+ return ret;
+
+ return devm_add_action_or_reset(&i3cdev->dev, ad4062_disable_ibi, i3cdev);
+}
+
+static int ad4062_request_irq(struct iio_dev *indio_dev)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->i3cdev->dev;
+ int ret;
+
+ ret = fwnode_irq_get_byname(dev_fwnode(&st->i3cdev->dev), "gp0");
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ if (ret < 0) {
+ st->gpo_irq[0] = false;
+ ret = regmap_update_bits(st->regmap, AD4062_REG_ADC_IBI_EN,
+ AD4062_REG_ADC_IBI_EN_MAX | AD4062_REG_ADC_IBI_EN_MIN,
+ AD4062_REG_ADC_IBI_EN_MAX | AD4062_REG_ADC_IBI_EN_MIN);
+ if (ret)
+ return ret;
+ } else {
+ st->gpo_irq[0] = true;
+ ret = devm_request_threaded_irq(dev, ret, NULL,
+ ad4062_irq_handler_thresh,
+ IRQF_ONESHOT, indio_dev->name,
+ indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ ret = fwnode_irq_get_byname(dev_fwnode(&st->i3cdev->dev), "gp1");
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ if (ret < 0) {
+ st->gpo_irq[1] = false;
+ return regmap_update_bits(st->regmap, AD4062_REG_ADC_IBI_EN,
+ AD4062_REG_ADC_IBI_EN_CONV_TRIGGER,
+ AD4062_REG_ADC_IBI_EN_CONV_TRIGGER);
+ }
+ st->gpo_irq[1] = true;
+
+ return devm_request_threaded_irq(dev, ret,
+ ad4062_irq_handler_drdy,
+ NULL, IRQF_ONESHOT, indio_dev->name,
+ indio_dev);
+}
+
+static const struct iio_trigger_ops ad4062_trigger_ops = {
+ .validate_device = &iio_trigger_validate_own_device,
+};
+
+static int ad4062_request_trigger(struct iio_dev *indio_dev)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ struct device *dev = &st->i3cdev->dev;
+ int ret;
+
+ st->trigger = devm_iio_trigger_alloc(dev, "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!st->trigger)
+ return -ENOMEM;
+
+ st->trigger->ops = &ad4062_trigger_ops;
+ iio_trigger_set_drvdata(st->trigger, indio_dev);
+
+ ret = devm_iio_trigger_register(dev, st->trigger);
+ if (ret)
+ return ret;
+
+ indio_dev->trig = iio_trigger_get(st->trigger);
+
+ return 0;
+}
+
+static const int ad4062_oversampling_avail[] = {
+ 1, 2, 4, 8, 16, 32, 64, 128, /* 0 - 7 */
+ 256, 512, 1024, 2048, 4096, /* 8 - 12 */
+};
+
+static int ad4062_read_avail(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, const int **vals,
+ int *type, int *len, long mask)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ *vals = ad4062_oversampling_avail;
+ *len = ARRAY_SIZE(ad4062_oversampling_avail);
+ *len -= st->chip->avg_max == 256 ? 4 : 0;
+ *type = IIO_VAL_INT;
+
+ return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = ad4062_populate_sampling_frequency(st);
+ if (ret)
+ return ret;
+ *vals = st->samp_freqs;
+ *len = st->oversamp_ratio ? ARRAY_SIZE(ad4062_conversion_freqs) : 1;
+ *type = IIO_VAL_INT;
+
+ return IIO_AVAIL_LIST;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4062_get_chan_scale(struct iio_dev *indio_dev, int *val, int *val2)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ const struct iio_scan_type *scan_type;
+
+ /*
+ * In burst averaging mode the averaging filter accumulates resulting
+ * in a sample with increased precision.
+ */
+ scan_type = iio_get_current_scan_type(indio_dev, st->chip->channels);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
+
+ *val = (st->vref_uV * 2) / (MICRO / MILLI); /* signed */
+ *val2 = scan_type->realbits - 1;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+}
+
+static int ad4062_get_chan_calibscale(struct ad4062_state *st, int *val, int *val2)
+{
+ int ret;
+
+ ret = regmap_bulk_read(st->regmap, AD4062_REG_MON_VAL,
+ &st->buf.be16, sizeof(st->buf.be16));
+ if (ret)
+ return ret;
+
+ /* From datasheet: code out = code in × mon_val/0x8000 */
+ *val = be16_to_cpu(st->buf.be16) * 2;
+ *val2 = 16;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+}
+
+static int ad4062_set_chan_calibscale(struct ad4062_state *st, int gain_int,
+ int gain_frac)
+{
+ /* Divide numerator and denumerator by known great common divider */
+ const u32 mon_val = AD4062_MON_VAL_MIDDLE_POINT / 64;
+ const u32 micro = MICRO / 64;
+ const u32 gain_fp = gain_int * MICRO + gain_frac;
+ const u32 reg_val = DIV_ROUND_CLOSEST(gain_fp * mon_val, micro);
+ int ret;
+
+ /* Checks if the gain is in range and the value fits the field */
+ if (gain_int < 0 || gain_int > 1 || reg_val > BIT(16) - 1)
+ return -EINVAL;
+
+ st->buf.be16 = cpu_to_be16(reg_val);
+ ret = regmap_bulk_write(st->regmap, AD4062_REG_MON_VAL,
+ &st->buf.be16, sizeof(st->buf.be16));
+ if (ret)
+ return ret;
+
+ /* Enable scale if gain is not equal to one */
+ return regmap_update_bits(st->regmap, AD4062_REG_ADC_CONFIG,
+ AD4062_REG_ADC_CONFIG_SCALE_EN_MSK,
+ FIELD_PREP(AD4062_REG_ADC_CONFIG_SCALE_EN_MSK,
+ !(gain_int == 1 && gain_frac == 0)));
+}
+
+static int ad4062_read_chan_raw(struct ad4062_state *st, int *val)
+{
+ struct i3c_device *i3cdev = st->i3cdev;
+ struct i3c_xfer xfer_trigger = {
+ .data.out = &st->conv_addr,
+ .len = sizeof(st->conv_addr),
+ .rnw = false,
+ };
+ struct i3c_xfer xfer_sample = {
+ .data.in = &st->buf.be32,
+ .len = sizeof(st->buf.be32),
+ .rnw = true,
+ };
+ int ret;
+
+ PM_RUNTIME_ACQUIRE(&st->i3cdev->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ ret = ad4062_set_operation_mode(st, st->mode);
+ if (ret)
+ return ret;
+
+ reinit_completion(&st->completion);
+ /* Change address pointer to trigger conversion */
+ st->conv_addr = AD4062_REG_CONV_TRIGGER_32BITS;
+ ret = i3c_device_do_xfers(i3cdev, &xfer_trigger, 1, I3C_SDR);
+ if (ret)
+ return ret;
+ /*
+ * Single sample read should be used only for oversampling and
+ * sampling frequency pairs that take less than 1 sec.
+ */
+ ret = wait_for_completion_timeout(&st->completion,
+ msecs_to_jiffies(1000));
+ if (!ret)
+ return -ETIMEDOUT;
+
+ ret = i3c_device_do_xfers(i3cdev, &xfer_sample, 1, I3C_SDR);
+ if (ret)
+ return ret;
+ *val = be32_to_cpu(st->buf.be32);
+ return 0;
+}
+
+static int ad4062_read_raw_dispatch(struct ad4062_state *st,
+ int *val, int *val2, long info)
+{
+ if (st->wait_event)
+ return -EBUSY;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ return ad4062_read_chan_raw(st, val);
+
+ case IIO_CHAN_INFO_CALIBSCALE:
+ return ad4062_get_chan_calibscale(st, val, val2);
+
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ return ad4062_get_oversampling_ratio(st, val);
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4062_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ return ad4062_get_chan_scale(indio_dev, val, val2);
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad4062_get_sampling_frequency(st, val);
+ }
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = ad4062_read_raw_dispatch(st, val, val2, info);
+ iio_device_release_direct(indio_dev);
+ return ret ?: IIO_VAL_INT;
+}
+
+static int ad4062_write_raw_dispatch(struct ad4062_state *st, int val, int val2,
+ long info)
+{
+ if (st->wait_event)
+ return -EBUSY;
+
+ switch (info) {
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ return ad4062_set_oversampling_ratio(st, val, val2);
+
+ case IIO_CHAN_INFO_CALIBSCALE:
+ return ad4062_set_chan_calibscale(st, val, val2);
+
+ default:
+ return -EINVAL;
+ }
+};
+
+static int ad4062_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long info)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return ad4062_set_sampling_frequency(st, val, val2);
+ }
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = ad4062_write_raw_dispatch(st, val, val2, info);
+ iio_device_release_direct(indio_dev);
+ return ret;
+}
+
+static int pm_ad4062_monitor_mode_enable(struct ad4062_state *st)
+{
+ int ret;
+
+ PM_RUNTIME_ACQUIRE(&st->i3cdev->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ return ad4062_set_operation_mode(st, AD4062_MONITOR_MODE);
+}
+
+static int ad4062_monitor_mode_enable(struct ad4062_state *st)
+{
+ int ret;
+
+ ret = pm_ad4062_monitor_mode_enable(st);
+ if (ret)
+ return ret;
+
+ pm_runtime_get_noresume(&st->i3cdev->dev);
+ return 0;
+}
+
+static int ad4062_monitor_mode_disable(struct ad4062_state *st)
+{
+ pm_runtime_put_autosuspend(&st->i3cdev->dev);
+ return 0;
+}
+
+static int ad4062_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+
+ return st->wait_event;
+}
+
+static int ad4062_write_event_config_dispatch(struct iio_dev *indio_dev,
+ bool state)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ int ret;
+
+ if (st->wait_event == state)
+ ret = 0;
+ else if (state)
+ ret = ad4062_monitor_mode_enable(st);
+ else
+ ret = ad4062_monitor_mode_disable(st);
+ if (ret)
+ return ret;
+
+ st->wait_event = state;
+ return 0;
+}
+
+static int ad4062_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ bool state)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = ad4062_write_event_config_dispatch(indio_dev, state);
+ iio_device_release_direct(indio_dev);
+ return ret;
+}
+
+static int __ad4062_read_event_info_value(struct ad4062_state *st,
+ enum iio_event_direction dir, int *val)
+{
+ int ret;
+ u8 reg;
+
+ if (dir == IIO_EV_DIR_RISING)
+ reg = AD4062_REG_MAX_LIMIT;
+ else
+ reg = AD4062_REG_MIN_LIMIT;
+
+ ret = regmap_bulk_read(st->regmap, reg, &st->buf.be16,
+ sizeof(st->buf.be16));
+ if (ret)
+ return ret;
+
+ *val = sign_extend32(be16_to_cpu(st->buf.be16), AD4062_LIMIT_BITS - 1);
+
+ return 0;
+}
+
+static int __ad4062_read_event_info_hysteresis(struct ad4062_state *st,
+ enum iio_event_direction dir, int *val)
+{
+ u8 reg;
+
+ if (dir == IIO_EV_DIR_RISING)
+ reg = AD4062_REG_MAX_HYST;
+ else
+ reg = AD4062_REG_MIN_HYST;
+ return regmap_read(st->regmap, reg, val);
+}
+
+static int ad4062_read_event_config_dispatch(struct iio_dev *indio_dev,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int *val)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+
+ if (st->wait_event)
+ return -EBUSY;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return __ad4062_read_event_info_value(st, dir, val);
+ case IIO_EV_INFO_HYSTERESIS:
+ return __ad4062_read_event_info_hysteresis(st, dir, val);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4062_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int *val,
+ int *val2)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = ad4062_read_event_config_dispatch(indio_dev, dir, info, val);
+ iio_device_release_direct(indio_dev);
+ return ret ?: IIO_VAL_INT;
+}
+
+static int __ad4062_write_event_info_value(struct ad4062_state *st,
+ enum iio_event_direction dir, int val)
+{
+ u8 reg;
+
+ if (val != sign_extend32(val, AD4062_LIMIT_BITS - 1))
+ return -EINVAL;
+ if (dir == IIO_EV_DIR_RISING)
+ reg = AD4062_REG_MAX_LIMIT;
+ else
+ reg = AD4062_REG_MIN_LIMIT;
+ st->buf.be16 = cpu_to_be16(val);
+
+ return regmap_bulk_write(st->regmap, reg, &st->buf.be16,
+ sizeof(st->buf.be16));
+}
+
+static int __ad4062_write_event_info_hysteresis(struct ad4062_state *st,
+ enum iio_event_direction dir, int val)
+{
+ u8 reg;
+
+ if (val > BIT(7) - 1)
+ return -EINVAL;
+ if (dir == IIO_EV_DIR_RISING)
+ reg = AD4062_REG_MAX_HYST;
+ else
+ reg = AD4062_REG_MIN_HYST;
+
+ return regmap_write(st->regmap, reg, val);
+}
+
+static int ad4062_write_event_value_dispatch(struct iio_dev *indio_dev,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int val)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+
+ if (st->wait_event)
+ return -EBUSY;
+
+ switch (type) {
+ case IIO_EV_TYPE_THRESH:
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ return __ad4062_write_event_info_value(st, dir, val);
+ case IIO_EV_INFO_HYSTERESIS:
+ return __ad4062_write_event_info_hysteresis(st, dir, val);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4062_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info, int val,
+ int val2)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = ad4062_write_event_value_dispatch(indio_dev, type, dir, info, val);
+ iio_device_release_direct(indio_dev);
+ return ret;
+}
+
+/*
+ * The AD4062 in burst averaging mode increases realbits from 16-bits to
+ * 20-bits, increasing the storagebits from 16-bits to 32-bits.
+ */
+static inline size_t ad4062_sizeof_storagebits(struct ad4062_state *st)
+{
+ const struct iio_scan_type *scan_type =
+ iio_get_current_scan_type(st->indio_dev, st->chip->channels);
+
+ return BITS_TO_BYTES(scan_type->storagebits);
+}
+
+/* Read registers only with realbits (no sign extension bytes) */
+static inline size_t ad4062_get_conv_addr(struct ad4062_state *st, size_t _sizeof)
+{
+ if (st->gpo_irq[1])
+ return _sizeof == sizeof(u32) ? AD4062_REG_CONV_READ_32BITS :
+ AD4062_REG_CONV_READ_16BITS;
+ return _sizeof == sizeof(u32) ? AD4062_REG_CONV_TRIGGER_32BITS :
+ AD4062_REG_CONV_TRIGGER_16BITS;
+}
+
+static int pm_ad4062_triggered_buffer_postenable(struct ad4062_state *st)
+{
+ int ret;
+
+ PM_RUNTIME_ACQUIRE(&st->i3cdev->dev, pm);
+ ret = PM_RUNTIME_ACQUIRE_ERR(&pm);
+ if (ret)
+ return ret;
+
+ if (st->wait_event)
+ return -EBUSY;
+
+ ret = ad4062_set_operation_mode(st, st->mode);
+ if (ret)
+ return ret;
+
+ st->conv_sizeof = ad4062_sizeof_storagebits(st);
+ st->conv_addr = ad4062_get_conv_addr(st, st->conv_sizeof);
+ /* CONV_READ requires read to trigger first sample. */
+ struct i3c_xfer xfer_sample[2] = {
+ {
+ .data.out = &st->conv_addr,
+ .len = sizeof(st->conv_addr),
+ .rnw = false,
+ },
+ {
+ .data.in = &st->buf.be32,
+ .len = sizeof(st->buf.be32),
+ .rnw = true,
+ }
+ };
+
+ return i3c_device_do_xfers(st->i3cdev, xfer_sample,
+ st->gpo_irq[1] ? 2 : 1, I3C_SDR);
+}
+
+static int ad4062_triggered_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+ int ret;
+
+ ret = pm_ad4062_triggered_buffer_postenable(st);
+ if (ret)
+ return ret;
+
+ pm_runtime_get_noresume(&st->i3cdev->dev);
+ return 0;
+}
+
+static int ad4062_triggered_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+
+ pm_runtime_put_autosuspend(&st->i3cdev->dev);
+ return 0;
+}
+
+static const struct iio_buffer_setup_ops ad4062_triggered_buffer_setup_ops = {
+ .postenable = &ad4062_triggered_buffer_postenable,
+ .predisable = &ad4062_triggered_buffer_predisable,
+};
+
+static int ad4062_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+ unsigned int writeval, unsigned int *readval)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+ else
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int ad4062_get_current_scan_type(const struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct ad4062_state *st = iio_priv(indio_dev);
+
+ return st->mode == AD4062_BURST_AVERAGING_MODE ?
+ AD4062_SCAN_TYPE_BURST_AVG :
+ AD4062_SCAN_TYPE_SAMPLE;
+}
+
+static const struct iio_info ad4062_info = {
+ .read_raw = ad4062_read_raw,
+ .write_raw = ad4062_write_raw,
+ .read_avail = ad4062_read_avail,
+ .read_event_config = ad4062_read_event_config,
+ .write_event_config = ad4062_write_event_config,
+ .read_event_value = ad4062_read_event_value,
+ .write_event_value = ad4062_write_event_value,
+ .event_attrs = &ad4062_event_attribute_group,
+ .get_current_scan_type = ad4062_get_current_scan_type,
+ .debugfs_reg_access = ad4062_debugfs_reg_access,
+};
+
+static const struct regmap_config ad4062_regmap_config = {
+ .name = "ad4062",
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = AD4062_MAX_REG,
+ .rd_table = &ad4062_regmap_rd_table,
+ .wr_table = &ad4062_regmap_wr_table,
+ .can_sleep = true,
+};
+
+static int ad4062_regulators_get(struct ad4062_state *st, bool *ref_sel)
+{
+ struct device *dev = &st->i3cdev->dev;
+ int ret;
+
+ ret = devm_regulator_get_enable(dev, "vio");
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable vio voltage\n");
+
+ st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "ref");
+ *ref_sel = st->vref_uV == -ENODEV;
+ if (st->vref_uV < 0 && !*ref_sel)
+ return dev_err_probe(dev, st->vref_uV,
+ "Failed to enable and read ref voltage\n");
+
+ if (*ref_sel) {
+ st->vref_uV = devm_regulator_get_enable_read_voltage(dev, "vdd");
+ if (st->vref_uV < 0)
+ return dev_err_probe(dev, st->vref_uV,
+ "Failed to enable and read vdd voltage\n");
+ } else {
+ ret = devm_regulator_get_enable(dev, "vdd");
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to enable vdd regulator\n");
+ }
+
+ return 0;
+}
+
+static int ad4062_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int ad4062_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct ad4062_state *st = gpiochip_get_data(gc);
+ unsigned int reg_val = value ? AD4062_GP_STATIC_HIGH : AD4062_GP_STATIC_LOW;
+
+ if (offset)
+ return regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
+ AD4062_REG_GP_CONF_MODE_MSK_1,
+ FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_1, reg_val));
+ else
+ return regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
+ AD4062_REG_GP_CONF_MODE_MSK_0,
+ FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_0, reg_val));
+}
+
+static int ad4062_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct ad4062_state *st = gpiochip_get_data(gc);
+ unsigned int reg_val;
+ int ret;
+
+ ret = regmap_read(st->regmap, AD4062_REG_GP_CONF, &reg_val);
+ if (ret)
+ return ret;
+
+ if (offset)
+ reg_val = FIELD_GET(AD4062_REG_GP_CONF_MODE_MSK_1, reg_val);
+ else
+ reg_val = FIELD_GET(AD4062_REG_GP_CONF_MODE_MSK_0, reg_val);
+
+ return reg_val == AD4062_GP_STATIC_HIGH;
+}
+
+static void ad4062_gpio_disable(void *data)
+{
+ struct ad4062_state *st = data;
+ u8 val = FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_0, AD4062_GP_DISABLED) |
+ FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_1, AD4062_GP_DISABLED);
+
+ regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
+ AD4062_REG_GP_CONF_MODE_MSK_1 | AD4062_REG_GP_CONF_MODE_MSK_0,
+ val);
+}
+
+static int ad4062_gpio_init_valid_mask(struct gpio_chip *gc,
+ unsigned long *valid_mask,
+ unsigned int ngpios)
+{
+ struct ad4062_state *st = gpiochip_get_data(gc);
+
+ bitmap_zero(valid_mask, ngpios);
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(st->gpo_irq); i++)
+ __assign_bit(i, valid_mask, !st->gpo_irq[i]);
+
+ return 0;
+}
+
+static int ad4062_gpio_init(struct ad4062_state *st)
+{
+ struct device *dev = &st->i3cdev->dev;
+ struct gpio_chip *gc;
+ u8 val, mask;
+ int ret;
+
+ if (!device_property_read_bool(dev, "gpio-controller"))
+ return 0;
+
+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
+ return -ENOMEM;
+
+ val = 0;
+ mask = 0;
+ if (!st->gpo_irq[0]) {
+ mask |= AD4062_REG_GP_CONF_MODE_MSK_0;
+ val |= FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_0, AD4062_GP_STATIC_LOW);
+ }
+ if (!st->gpo_irq[1]) {
+ mask |= AD4062_REG_GP_CONF_MODE_MSK_1;
+ val |= FIELD_PREP(AD4062_REG_GP_CONF_MODE_MSK_1, AD4062_GP_STATIC_LOW);
+ }
+
+ ret = regmap_update_bits(st->regmap, AD4062_REG_GP_CONF,
+ mask, val);
+ if (ret)
+ return ret;
+
+ ret = devm_add_action_or_reset(dev, ad4062_gpio_disable, st);
+ if (ret)
+ return ret;
+
+ gc->parent = dev;
+ gc->label = st->chip->name;
+ gc->owner = THIS_MODULE;
+ gc->base = -1;
+ gc->ngpio = 2;
+ gc->init_valid_mask = ad4062_gpio_init_valid_mask;
+ gc->get_direction = ad4062_gpio_get_direction;
+ gc->set = ad4062_gpio_set;
+ gc->get = ad4062_gpio_get;
+ gc->can_sleep = true;
+
+ ret = devm_gpiochip_add_data(dev, gc, st);
+ if (ret)
+ return dev_err_probe(dev, ret, "Unable to register GPIO chip\n");
+
+ return 0;
+}
+
+static const struct i3c_device_id ad4062_id_table[] = {
+ I3C_DEVICE(AD4062_I3C_VENDOR, AD4060_PROD_ID, &ad4060_chip_info),
+ I3C_DEVICE(AD4062_I3C_VENDOR, AD4062_PROD_ID, &ad4062_chip_info),
+ { }
+};
+MODULE_DEVICE_TABLE(i3c, ad4062_id_table);
+
+static int ad4062_probe(struct i3c_device *i3cdev)
+{
+ const struct i3c_device_id *id = i3c_device_match_id(i3cdev, ad4062_id_table);
+ const struct ad4062_chip_info *chip = id->data;
+ struct device *dev = &i3cdev->dev;
+ struct iio_dev *indio_dev;
+ struct ad4062_state *st;
+ bool ref_sel;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->i3cdev = i3cdev;
+ i3cdev_set_drvdata(i3cdev, st);
+ init_completion(&st->completion);
+
+ ret = ad4062_regulators_get(st, &ref_sel);
+ if (ret)
+ return ret;
+
+ st->regmap = devm_regmap_init_i3c(i3cdev, &ad4062_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "Failed to initialize regmap\n");
+
+ st->mode = AD4062_SAMPLE_MODE;
+ st->wait_event = false;
+ st->chip = chip;
+ st->sampling_frequency = 0;
+ st->events_frequency = 0;
+ st->oversamp_ratio = 0;
+ st->indio_dev = indio_dev;
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->num_channels = 1;
+ indio_dev->info = &ad4062_info;
+ indio_dev->name = chip->name;
+ indio_dev->channels = chip->channels;
+
+ ret = ad4062_soft_reset(st);
+ if (ret)
+ return dev_err_probe(dev, ret, "AD4062 failed to soft reset\n");
+
+ ret = ad4062_check_ids(st);
+ if (ret)
+ return ret;
+
+ ret = ad4062_setup(indio_dev, indio_dev->channels, &ref_sel);
+ if (ret)
+ return ret;
+
+ ret = ad4062_request_irq(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = ad4062_request_trigger(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(&i3cdev->dev, indio_dev,
+ iio_pollfunc_store_time,
+ ad4062_poll_handler,
+ &ad4062_triggered_buffer_setup_ops);
+ if (ret)
+ return ret;
+
+ pm_runtime_set_active(dev);
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to enable pm_runtime\n");
+
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
+
+ ret = ad4062_request_ibi(i3cdev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request i3c ibi\n");
+
+ ret = ad4062_gpio_init(st);
+ if (ret)
+ return ret;
+
+ ret = devm_work_autocancel(dev, &st->trig_conv, ad4062_trigger_work);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static int ad4062_runtime_suspend(struct device *dev)
+{
+ struct ad4062_state *st = dev_get_drvdata(dev);
+
+ return regmap_write(st->regmap, AD4062_REG_DEVICE_CONFIG,
+ FIELD_PREP(AD4062_REG_DEVICE_CONFIG_POWER_MODE_MSK,
+ AD4062_REG_DEVICE_CONFIG_LOW_POWER_MODE));
+}
+
+static int ad4062_runtime_resume(struct device *dev)
+{
+ struct ad4062_state *st = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_clear_bits(st->regmap, AD4062_REG_DEVICE_CONFIG,
+ AD4062_REG_DEVICE_CONFIG_POWER_MODE_MSK);
+ if (ret)
+ return ret;
+
+ /* Wait device functional blocks to power up */
+ fsleep(3 * USEC_PER_MSEC);
+ return 0;
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(ad4062_pm_ops,
+ ad4062_runtime_suspend, ad4062_runtime_resume, NULL);
+
+static struct i3c_driver ad4062_driver = {
+ .driver = {
+ .name = "ad4062",
+ .pm = pm_ptr(&ad4062_pm_ops),
+ },
+ .probe = ad4062_probe,
+ .id_table = ad4062_id_table,
+};
+module_i3c_driver(ad4062_driver);
+
+MODULE_AUTHOR("Jorge Marques <jorge.marques@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD4062");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/ad4134.c b/drivers/iio/adc/ad4134.c
new file mode 100644
index 000000000000..e42ee328fcbf
--- /dev/null
+++ b/drivers/iio/adc/ad4134.c
@@ -0,0 +1,500 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2026 Analog Devices, Inc.
+ * Author: Marcelo Schmitt <marcelo.schmitt@analog.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/crc8.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+#include <linux/units.h>
+
+#define AD4134_RESET_TIME_US (10 * USEC_PER_SEC)
+
+#define AD4134_REG_READ_MASK BIT(7)
+#define AD4134_SPI_MAX_XFER_LEN 3
+
+#define AD4134_EXT_CLOCK_MHZ (48 * HZ_PER_MHZ)
+
+#define AD4134_NUM_CHANNELS 4
+#define AD4134_CHAN_PRECISION_BITS 24
+
+#define AD4134_IFACE_CONFIG_A_REG 0x00
+#define AD4134_IFACE_CONFIG_B_REG 0x01
+#define AD4134_IFACE_CONFIG_B_SINGLE_INSTR BIT(7)
+
+#define AD4134_DEVICE_CONFIG_REG 0x02
+#define AD4134_DEVICE_CONFIG_POWER_MODE_MASK BIT(0)
+#define AD4134_POWER_MODE_HIGH_PERF 0x1
+
+#define AD4134_SILICON_REV_REG 0x07
+#define AD4134_SCRATCH_PAD_REG 0x0A
+#define AD4134_STREAM_MODE_REG 0x0E
+#define AD4134_SDO_PIN_SRC_SEL_REG 0x10
+#define AD4134_SDO_PIN_SRC_SEL_SDO_SEL_MASK BIT(2)
+
+#define AD4134_DATA_PACKET_CONFIG_REG 0x11
+#define AD4134_DATA_PACKET_CONFIG_FRAME_MASK GENMASK(5, 4)
+#define AD4134_DATA_PACKET_24BIT_FRAME 0x2
+
+#define AD4134_DIG_IF_CFG_REG 0x12
+#define AD4134_DIF_IF_CFG_FORMAT_MASK GENMASK(1, 0)
+#define AD4134_DATA_FORMAT_SINGLE_CH_MODE 0x0
+
+#define AD4134_PW_DOWN_CTRL_REG 0x13
+#define AD4134_DEVICE_STATUS_REG 0x15
+#define AD4134_ODR_VAL_INT_LSB_REG 0x16
+#define AD4134_CH3_OFFSET_MSB_REG 0x3E
+#define AD4134_AIN_OR_ERROR_REG 0x48
+
+/*
+ * AD4134 register map ends at address 0x48 and there is no register for
+ * retrieving ADC sample data. Though, to make use of Linux regmap API both
+ * for register access and sample read, we define one virtual register for each
+ * ADC channel. AD4134_CH_VREG(x) maps a channel number to it's virtual register
+ * address while AD4134_VREG_CH(x) tells which channel given the address.
+ */
+#define AD4134_CH_VREG(x) ((x) + 0x50)
+#define AD4134_VREG_CH(x) ((x) - 0x50)
+
+#define AD4134_SPI_CRC_POLYNOM 0x07
+#define AD4134_SPI_CRC_INIT_VALUE 0xA5
+static unsigned char ad4134_spi_crc_table[CRC8_TABLE_SIZE];
+
+#define AD4134_CHANNEL(_index) { \
+ .type = IIO_VOLTAGE, \
+ .indexed = 1, \
+ .channel = (_index), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+static const struct iio_chan_spec ad4134_chan_set[] = {
+ AD4134_CHANNEL(0),
+ AD4134_CHANNEL(1),
+ AD4134_CHANNEL(2),
+ AD4134_CHANNEL(3),
+};
+
+struct ad4134_state {
+ struct spi_device *spi;
+ struct regmap *regmap;
+ unsigned long sys_clk_hz;
+ struct gpio_desc *odr_gpio;
+ int refin_mv;
+ /*
+ * DMA (thus cache coherency maintenance) requires the transfer buffers
+ * to live in their own cache lines.
+ */
+ u8 rx_buf[AD4134_SPI_MAX_XFER_LEN] __aligned(IIO_DMA_MINALIGN);
+ u8 tx_buf[AD4134_SPI_MAX_XFER_LEN];
+};
+
+static const struct regmap_range ad4134_regmap_rd_range[] = {
+ regmap_reg_range(AD4134_IFACE_CONFIG_A_REG, AD4134_SILICON_REV_REG),
+ regmap_reg_range(AD4134_SCRATCH_PAD_REG, AD4134_PW_DOWN_CTRL_REG),
+ regmap_reg_range(AD4134_DEVICE_STATUS_REG, AD4134_AIN_OR_ERROR_REG),
+ regmap_reg_range(AD4134_CH_VREG(0), AD4134_CH_VREG(AD4134_NUM_CHANNELS)),
+};
+
+static const struct regmap_range ad4134_regmap_wr_range[] = {
+ regmap_reg_range(AD4134_IFACE_CONFIG_A_REG, AD4134_DEVICE_CONFIG_REG),
+ regmap_reg_range(AD4134_SCRATCH_PAD_REG, AD4134_SCRATCH_PAD_REG),
+ regmap_reg_range(AD4134_STREAM_MODE_REG, AD4134_PW_DOWN_CTRL_REG),
+ regmap_reg_range(AD4134_ODR_VAL_INT_LSB_REG, AD4134_CH3_OFFSET_MSB_REG),
+};
+
+static const struct regmap_access_table ad4134_regmap_rd_table = {
+ .yes_ranges = ad4134_regmap_rd_range,
+ .n_yes_ranges = ARRAY_SIZE(ad4134_regmap_rd_range),
+};
+
+static const struct regmap_access_table ad4134_regmap_wr_table = {
+ .yes_ranges = ad4134_regmap_wr_range,
+ .n_yes_ranges = ARRAY_SIZE(ad4134_regmap_wr_range),
+};
+
+static int ad4134_calc_spi_crc(u8 inst, u8 data)
+{
+ u8 buf[] = { inst, data };
+
+ return crc8(ad4134_spi_crc_table, buf, ARRAY_SIZE(buf),
+ AD4134_SPI_CRC_INIT_VALUE);
+}
+
+static void ad4134_prepare_spi_tx_buf(u8 inst, u8 data, u8 *buf)
+{
+ buf[0] = inst;
+ buf[1] = data;
+ buf[2] = ad4134_calc_spi_crc(inst, data);
+}
+
+static int ad4134_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct ad4134_state *st = context;
+ struct spi_transfer xfer = {
+ .tx_buf = st->tx_buf,
+ .rx_buf = st->rx_buf,
+ .len = AD4134_SPI_MAX_XFER_LEN,
+ };
+ int ret;
+
+ ad4134_prepare_spi_tx_buf(reg, val, st->tx_buf);
+
+ ret = spi_sync_transfer(st->spi, &xfer, 1);
+ if (ret)
+ return ret;
+
+ if (st->rx_buf[2] != st->tx_buf[2])
+ dev_dbg(&st->spi->dev, "reg write CRC check failed\n");
+
+ return 0;
+}
+
+static int ad4134_data_read(struct ad4134_state *st, unsigned int reg,
+ unsigned int *val)
+{
+ unsigned int i;
+ int ret;
+
+ /*
+ * To be able to read data from all 4 channels through a single line, we
+ * set DOUTx output format to 0 in the digital interface config register
+ * (0x12). With that, data from all four channels is serialized and
+ * output on DOUT0. During the probe, we also set SDO_PIN_SRC_SEL in
+ * DEVICE_CONFIG_1 register to duplicate DOUT0 on the SDO pin. Combined,
+ * those configurations enable ADC data read through a conventional SPI
+ * interface. Now we read data from all channels but keep only the bits
+ * from the requested one.
+ */
+ for (i = 0; i < ARRAY_SIZE(ad4134_chan_set); i++) {
+ ret = spi_write_then_read(st->spi, NULL, 0, st->rx_buf,
+ BITS_TO_BYTES(AD4134_CHAN_PRECISION_BITS));
+ if (ret)
+ return ret;
+
+ /*
+ * AD4134 has a built-in feature that flags when data transfers
+ * don't run enough clock cycles to read the entire data frame.
+ * Clock out data from all channels to avoid that.
+ */
+ if (i == AD4134_VREG_CH(reg))
+ *val = get_unaligned_be24(st->rx_buf);
+ }
+
+ return 0;
+}
+
+static int ad4134_register_read(struct ad4134_state *st, unsigned int reg,
+ unsigned int *val)
+{
+ struct spi_transfer xfer = {
+ .tx_buf = st->tx_buf,
+ .rx_buf = st->rx_buf,
+ .len = AD4134_SPI_MAX_XFER_LEN,
+ };
+ unsigned int inst;
+ int ret;
+
+ inst = AD4134_REG_READ_MASK | reg;
+ ad4134_prepare_spi_tx_buf(inst, 0, st->tx_buf);
+
+ ret = spi_sync_transfer(st->spi, &xfer, 1);
+ if (ret)
+ return ret;
+
+ *val = st->rx_buf[1];
+
+ /* Check CRC */
+ if (st->rx_buf[2] != st->tx_buf[2])
+ dev_dbg(&st->spi->dev, "reg read CRC check failed\n");
+
+ return 0;
+}
+
+static int ad4134_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct ad4134_state *st = context;
+
+ if (reg >= AD4134_CH_VREG(0))
+ return ad4134_data_read(st, reg, val);
+
+ return ad4134_register_read(st, reg, val);
+}
+
+static const struct regmap_config ad4134_regmap_config = {
+ .reg_read = ad4134_reg_read,
+ .reg_write = ad4134_reg_write,
+ .rd_table = &ad4134_regmap_rd_table,
+ .wr_table = &ad4134_regmap_wr_table,
+ .max_register = AD4134_CH_VREG(ARRAY_SIZE(ad4134_chan_set)),
+};
+
+static int ad4134_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long info)
+{
+ struct ad4134_state *st = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_CHAN_INFO_RAW:
+ gpiod_set_value_cansleep(st->odr_gpio, 1);
+ /*
+ * For slave mode gated DCLK (data sheet page 11), the minimum
+ * ODR high time is 3 * tDIGCLK. The internal digital clock
+ * period is tDIGCLK = 1/fDIGCLK = 2/fSYSCLK.
+ * The System clock frequency (fSYSCLK) is typically 48 MHz.
+ * Thus, ODR high time = 3 * (2 / (48 * HZ_PER_MHZ))
+ * ODR high time = 0.000000125 s = 125 ns
+ * 1 micro second should be more than enough. Not worth it
+ * tweaking for shorter dealy since this is not a fast data path.
+ */
+ fsleep(1);
+ gpiod_set_value_cansleep(st->odr_gpio, 0);
+ ret = regmap_read(st->regmap, AD4134_CH_VREG(chan->channel), val);
+ if (ret)
+ return ret;
+
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = st->refin_mv;
+ *val2 = AD4134_CHAN_PRECISION_BITS - 1;
+
+ return IIO_VAL_FRACTIONAL_LOG2;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ad4134_debugfs_reg_access(struct iio_dev *indio_dev,
+ unsigned int reg, unsigned int writeval,
+ unsigned int *readval)
+{
+ struct ad4134_state *st = iio_priv(indio_dev);
+
+ if (readval)
+ return regmap_read(st->regmap, reg, readval);
+
+ return regmap_write(st->regmap, reg, writeval);
+}
+
+static int ad4134_min_io_mode_setup(struct ad4134_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ int ret;
+
+ st->odr_gpio = devm_gpiod_get(dev, "odr", GPIOD_OUT_LOW);
+ if (IS_ERR(st->odr_gpio))
+ return dev_err_probe(dev, PTR_ERR(st->odr_gpio),
+ "failed to get ODR GPIO\n");
+
+ ret = regmap_update_bits(st->regmap, AD4134_DIG_IF_CFG_REG,
+ AD4134_DIF_IF_CFG_FORMAT_MASK,
+ FIELD_PREP(AD4134_DIF_IF_CFG_FORMAT_MASK,
+ AD4134_DATA_FORMAT_SINGLE_CH_MODE));
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to set single channel mode\n");
+
+ ret = regmap_set_bits(st->regmap, AD4134_SDO_PIN_SRC_SEL_REG,
+ AD4134_SDO_PIN_SRC_SEL_SDO_SEL_MASK);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to set SDO source selection\n");
+
+ return regmap_set_bits(st->regmap, AD4134_IFACE_CONFIG_B_REG,
+ AD4134_IFACE_CONFIG_B_SINGLE_INSTR);
+}
+
+static const struct iio_info ad4134_info = {
+ .read_raw = ad4134_read_raw,
+ .debugfs_reg_access = ad4134_debugfs_reg_access,
+};
+
+static const char * const ad4143_required_regulators[] = {
+ "avdd5", "dvdd5", "iovdd",
+};
+
+static const char * const ad4143_optional_regulators[] = {
+ "avdd1v8", "dvdd1v8", "clkvdd",
+};
+
+static int ad4134_regulator_setup(struct ad4134_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ int ret;
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4143_required_regulators),
+ ad4143_required_regulators);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable power supplies\n");
+
+ /* Required regulator that we need to read the voltage */
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin");
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get REFIN voltage.\n");
+
+ st->refin_mv = ret / (MICRO / MILLI);
+
+ ret = devm_regulator_get_enable_optional(dev, "ldoin");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "failed to enable ldoin supply\n");
+
+ /* If ldoin was provided, then use the use the internal LDO regulators */
+ if (ret == 0)
+ return 0;
+
+ /*
+ * If ldoin is not provided, then avdd1v8, dvdd1v8, and clkvdd are
+ * required.
+ */
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(ad4143_optional_regulators),
+ ad4143_optional_regulators);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable 1V8 power supplies\n");
+
+ return 0;
+}
+
+static int ad4134_clock_select(struct ad4134_state *st)
+{
+ struct device *dev = &st->spi->dev;
+ struct clk *xtal_clk, *clkin_clk;
+
+ /*
+ * AD4134 requires one external clock source and only one external clock
+ * source can be provided at a time. Try to get a crystal provided clock.
+ * If that fails, try to get a CMOS clock.
+ */
+ xtal_clk = devm_clk_get_optional_enabled(dev, "xtal");
+ if (!xtal_clk)
+ xtal_clk = devm_clk_get_optional_enabled(dev, "xtal");
+ if (IS_ERR(xtal_clk))
+ return dev_err_probe(dev, PTR_ERR(xtal_clk),
+ "failed to get xtal\n");
+
+ clkin_clk = devm_clk_get_optional_enabled(dev, "clkin");
+ if (!clkin_clk)
+ clkin_clk = devm_clk_get_optional_enabled(dev, "clkin");
+ if (IS_ERR(clkin_clk))
+ return dev_err_probe(dev, PTR_ERR(clkin_clk),
+ "failed to get clkin\n");
+
+ st->sys_clk_hz = clk_get_rate(xtal_clk) | clk_get_rate(clkin_clk);
+ if (st->sys_clk_hz != AD4134_EXT_CLOCK_MHZ)
+ dev_warn(dev, "invalid external clock frequency %lu\n",
+ st->sys_clk_hz);
+
+ return 0;
+}
+
+static int ad4134_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct reset_control *rst;
+ struct iio_dev *indio_dev;
+ struct ad4134_state *st;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ st = iio_priv(indio_dev);
+ st->spi = spi;
+
+ indio_dev->name = "ad4134";
+ indio_dev->channels = ad4134_chan_set;
+ indio_dev->num_channels = ARRAY_SIZE(ad4134_chan_set);
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &ad4134_info;
+
+ ret = ad4134_regulator_setup(st);
+ if (ret)
+ return ret;
+
+ ret = ad4134_clock_select(st);
+ if (ret)
+ return ret;
+
+ rst = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL);
+ if (IS_ERR(rst))
+ return dev_err_probe(dev, PTR_ERR(rst),
+ "failed to get and deassert reset\n");
+
+ crc8_populate_msb(ad4134_spi_crc_table, AD4134_SPI_CRC_POLYNOM);
+
+ st->regmap = devm_regmap_init(dev, NULL, st, &ad4134_regmap_config);
+ if (IS_ERR(st->regmap))
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
+ "failed to initialize regmap");
+
+ ret = ad4134_min_io_mode_setup(st);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to setup minimum I/O mode\n");
+
+ /* Bump precision to 24-bit */
+ ret = regmap_update_bits(st->regmap, AD4134_DATA_PACKET_CONFIG_REG,
+ AD4134_DATA_PACKET_CONFIG_FRAME_MASK,
+ FIELD_PREP(AD4134_DATA_PACKET_CONFIG_FRAME_MASK,
+ AD4134_DATA_PACKET_24BIT_FRAME));
+ if (ret)
+ return ret;
+
+ /* Set high performance power mode */
+ ret = regmap_update_bits(st->regmap, AD4134_DEVICE_CONFIG_REG,
+ AD4134_DEVICE_CONFIG_POWER_MODE_MASK,
+ FIELD_PREP(AD4134_DEVICE_CONFIG_POWER_MODE_MASK,
+ AD4134_POWER_MODE_HIGH_PERF));
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct spi_device_id ad4134_id[] = {
+ { "ad4134" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ad4134_id);
+
+static const struct of_device_id ad4134_of_match[] = {
+ { .compatible = "adi,ad4134" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ad4134_of_match);
+
+static struct spi_driver ad4134_driver = {
+ .driver = {
+ .name = "ad4134",
+ .of_match_table = ad4134_of_match,
+ },
+ .probe = ad4134_probe,
+ .id_table = ad4134_id,
+};
+module_spi_driver(ad4134_driver);
+
+MODULE_AUTHOR("Marcelo Schmitt <marcelo.schmitt@analog.com>");
+MODULE_DESCRIPTION("Analog Devices AD4134 SPI driver");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("IIO_AD4134");
diff --git a/drivers/iio/adc/ad4170-4.c b/drivers/iio/adc/ad4170-4.c
index efaed92191f1..82205bfae531 100644
--- a/drivers/iio/adc/ad4170-4.c
+++ b/drivers/iio/adc/ad4170-4.c
@@ -2973,7 +2973,7 @@ static int ad4170_probe(struct spi_device *spi)
if (spi->irq) {
ret = devm_request_irq(dev, spi->irq, &ad4170_irq_handler,
- IRQF_ONESHOT, indio_dev->name, indio_dev);
+ IRQF_NO_THREAD, indio_dev->name, indio_dev);
if (ret)
return ret;
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 1bec6657394c..21d3f6aae972 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -16,7 +16,6 @@
#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
-#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/iio/iio.h>
diff --git a/drivers/iio/adc/ad7606_spi.c b/drivers/iio/adc/ad7606_spi.c
index f28e4ca37707..7e17ccbcedd0 100644
--- a/drivers/iio/adc/ad7606_spi.c
+++ b/drivers/iio/adc/ad7606_spi.c
@@ -345,7 +345,7 @@ static int ad7606_spi_update_scan_mode(struct iio_dev *indio_dev,
* has no way of demuxing the data to filter out unwanted
* channels.
*/
- if (bitmap_weight(scan_mask, num_adc_ch) != num_adc_ch)
+ if (!bitmap_full(scan_mask, num_adc_ch))
return -EINVAL;
}
diff --git a/drivers/iio/adc/ad7766.c b/drivers/iio/adc/ad7766.c
index 4d570383ef02..9e4a66477d2d 100644
--- a/drivers/iio/adc/ad7766.c
+++ b/drivers/iio/adc/ad7766.c
@@ -184,12 +184,6 @@ static const struct iio_info ad7766_info = {
.read_raw = &ad7766_read_raw,
};
-static irqreturn_t ad7766_irq(int irq, void *private)
-{
- iio_trigger_poll(private);
- return IRQ_HANDLED;
-}
-
static int ad7766_set_trigger_state(struct iio_trigger *trig, bool enable)
{
struct ad7766 *ad7766 = iio_trigger_get_drvdata(trig);
@@ -260,8 +254,8 @@ static int ad7766_probe(struct spi_device *spi)
* Some platforms might not allow the option to power it down so
* don't enable the interrupt to avoid extra load on the system
*/
- ret = devm_request_irq(&spi->dev, spi->irq, ad7766_irq,
- IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN,
+ ret = devm_request_irq(&spi->dev, spi->irq, iio_trigger_generic_data_rdy_poll,
+ IRQF_TRIGGER_FALLING | IRQF_NO_AUTOEN | IRQF_NO_THREAD,
dev_name(&spi->dev),
ad7766->trig);
if (ret < 0)
diff --git a/drivers/iio/adc/ad7768-1.c b/drivers/iio/adc/ad7768-1.c
index d96802b7847a..fcd8aea7152e 100644
--- a/drivers/iio/adc/ad7768-1.c
+++ b/drivers/iio/adc/ad7768-1.c
@@ -6,6 +6,7 @@
*/
#include <linux/array_size.h>
#include <linux/bitfield.h>
+#include <linux/cleanup.h>
#include <linux/clk.h>
#include <linux/completion.h>
#include <linux/delay.h>
@@ -14,8 +15,12 @@
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
+#include <linux/limits.h>
+#include <linux/math.h>
#include <linux/minmax.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rational.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
@@ -107,10 +112,15 @@
#define AD7768_VCM_OFF 0x07
+#define ADAQ776X_GAIN_MAX_NANO (128 * NANO)
+#define ADAQ776X_MAX_GAIN_MODES 8
+
#define AD7768_TRIGGER_SOURCE_SYNC_IDX 0
#define AD7768_MAX_CHANNELS 1
+#define ADAQ7768_PGA_PINS 3
+
enum ad7768_conv_mode {
AD7768_CONTINUOUS,
AD7768_ONE_SHOT,
@@ -153,6 +163,51 @@ enum ad7768_scan_type {
AD7768_SCAN_TYPE_HIGH_SPEED,
};
+enum {
+ AD7768_PGA_GAIN_0,
+ AD7768_PGA_GAIN_1,
+ AD7768_PGA_GAIN_2,
+ AD7768_PGA_GAIN_3,
+ AD7768_PGA_GAIN_4,
+ AD7768_PGA_GAIN_5,
+ AD7768_PGA_GAIN_6,
+ AD7768_PGA_GAIN_7,
+};
+
+enum {
+ AD7768_AAF_IN1,
+ AD7768_AAF_IN2,
+ AD7768_AAF_IN3,
+};
+
+/* PGA and AAF gains in V/V */
+static const int adaq7768_gains[] = {
+ [AD7768_PGA_GAIN_0] = 325, /* 0.325 */
+ [AD7768_PGA_GAIN_1] = 650, /* 0.650 */
+ [AD7768_PGA_GAIN_2] = 1300, /* 1.300 */
+ [AD7768_PGA_GAIN_3] = 2600, /* 2.600 */
+ [AD7768_PGA_GAIN_4] = 5200, /* 5.200 */
+ [AD7768_PGA_GAIN_5] = 10400, /* 10.400 */
+ [AD7768_PGA_GAIN_6] = 20800, /* 20.800 */
+};
+
+static const int adaq7769_gains[] = {
+ [AD7768_PGA_GAIN_0] = 1000, /* 1.000 */
+ [AD7768_PGA_GAIN_1] = 2000, /* 2.000 */
+ [AD7768_PGA_GAIN_2] = 4000, /* 4.000 */
+ [AD7768_PGA_GAIN_3] = 8000, /* 8.000 */
+ [AD7768_PGA_GAIN_4] = 16000, /* 16.000 */
+ [AD7768_PGA_GAIN_5] = 32000, /* 32.000 */
+ [AD7768_PGA_GAIN_6] = 64000, /* 64.000 */
+ [AD7768_PGA_GAIN_7] = 128000, /* 128.000 */
+};
+
+static const int ad7768_aaf_gains_bp[] = {
+ [AD7768_AAF_IN1] = 10000, /* 1.000 */
+ [AD7768_AAF_IN2] = 3640, /* 0.364 */
+ [AD7768_AAF_IN3] = 1430, /* 0.143 */
+};
+
/* -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 */
@@ -213,6 +268,19 @@ static const struct iio_scan_type ad7768_scan_type[] = {
},
};
+struct ad7768_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channel_spec;
+ int num_channels;
+ const int *pga_gains;
+ int num_pga_modes;
+ int default_pga_mode;
+ int pgia_mode2pin_offset;
+ bool has_pga;
+ bool has_variable_aaf;
+ bool has_vcm_regulator;
+};
+
struct ad7768_state {
struct spi_device *spi;
struct regmap *regmap;
@@ -228,13 +296,19 @@ struct ad7768_state {
unsigned int samp_freq;
unsigned int samp_freq_avail[ARRAY_SIZE(ad7768_mclk_div_rates)];
unsigned int samp_freq_avail_len;
+ unsigned int pga_gain_mode;
+ unsigned int aaf_gain;
+ int scale_tbl[ADAQ776X_MAX_GAIN_MODES][2];
struct completion completion;
struct iio_trigger *trig;
+ struct gpio_descs *pga_gpios;
struct gpio_desc *gpio_sync_in;
struct gpio_desc *gpio_reset;
const char *labels[AD7768_MAX_CHANNELS];
struct gpio_chip gpiochip;
+ const struct ad7768_chip_info *chip;
bool en_spi_sync;
+ struct mutex pga_lock; /* protect device internal state (PGA) */
/*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
@@ -457,6 +531,42 @@ static int ad7768_reg_access(struct iio_dev *indio_dev,
return ret;
}
+static void ad7768_fill_scale_tbl(struct iio_dev *dev)
+{
+ struct ad7768_state *st = iio_priv(dev);
+ const struct iio_scan_type *scan_type;
+ int val, val2, tmp0, tmp1, i;
+ struct u32_fract fract;
+ unsigned long n, d;
+ u64 tmp2;
+
+ scan_type = iio_get_current_scan_type(dev, &dev->channels[0]);
+ if (scan_type->sign == 's')
+ val2 = scan_type->realbits - 1;
+ else
+ val2 = scan_type->realbits;
+
+ for (i = 0; i < st->chip->num_pga_modes; i++) {
+ /* Convert gain to a fraction format */
+ fract.numerator = st->chip->pga_gains[i];
+ fract.denominator = MILLI;
+ if (st->chip->has_variable_aaf) {
+ fract.numerator *= ad7768_aaf_gains_bp[st->aaf_gain];
+ fract.denominator *= PERMYRIAD;
+ }
+
+ rational_best_approximation(fract.numerator, fract.denominator,
+ INT_MAX, INT_MAX, &n, &d);
+
+ val = mult_frac(st->vref_uv, d, n);
+ /* Would multiply by NANO here, but value is already in milli */
+ tmp2 = ((u64)val * MICRO) >> val2;
+ tmp0 = div_u64_rem(tmp2, NANO, &tmp1);
+ st->scale_tbl[i][0] = tmp0; /* Integer part */
+ st->scale_tbl[i][1] = abs(tmp1); /* Fractional part */
+ }
+}
+
static int ad7768_set_sinc3_dec_rate(struct ad7768_state *st,
unsigned int dec_rate)
{
@@ -558,12 +668,66 @@ static int ad7768_configure_dig_fil(struct iio_dev *dev,
st->oversampling_ratio = ad7768_dec_rate_values[dec_rate_idx];
}
+ /* Update scale table: scale values vary according to the precision */
+ ad7768_fill_scale_tbl(dev);
+
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_setup_pga(struct device *dev, struct ad7768_state *st)
+{
+ st->pga_gpios = devm_gpiod_get_array(dev, "pga", GPIOD_OUT_LOW);
+ if (IS_ERR(st->pga_gpios))
+ return dev_err_probe(dev, PTR_ERR(st->pga_gpios),
+ "Failed to get PGA gpios.\n");
+
+ if (st->pga_gpios->ndescs != ADAQ7768_PGA_PINS)
+ return dev_err_probe(dev, -EINVAL,
+ "Expected %d GPIOs for PGA control.\n",
+ ADAQ7768_PGA_PINS);
+ return 0;
+}
+
+static int ad7768_calc_pga_gain(struct ad7768_state *st, int gain_int,
+ int gain_fract, int precision)
+{
+ u64 gain_nano;
+ u32 tmp;
+
+ gain_nano = gain_int * NANO + gain_fract;
+ gain_nano = clamp(gain_nano, 0, ADAQ776X_GAIN_MAX_NANO);
+ tmp = DIV_ROUND_CLOSEST_ULL(gain_nano << precision, NANO);
+ gain_nano = DIV_ROUND_CLOSEST(st->vref_uv, tmp);
+ if (st->chip->has_variable_aaf)
+ gain_nano = DIV_ROUND_CLOSEST_ULL(gain_nano * PERMYRIAD,
+ ad7768_aaf_gains_bp[st->aaf_gain]);
+
+ return find_closest(gain_nano, st->chip->pga_gains,
+ (int)st->chip->num_pga_modes);
+}
+
+static int ad7768_set_pga_gain(struct ad7768_state *st,
+ int gain_mode)
+{
+ int pgia_pins_value = abs(gain_mode - st->chip->pgia_mode2pin_offset);
+ DECLARE_BITMAP(bitmap, ADAQ7768_PGA_PINS) = { };
+ int ret;
+
+ guard(mutex)(&st->pga_lock);
+
+ bitmap_write(bitmap, pgia_pins_value, 0, ADAQ7768_PGA_PINS);
+ ret = gpiod_multi_set_value_cansleep(st->pga_gpios, bitmap);
+ if (ret)
+ return ret;
+
+ st->pga_gain_mode = gain_mode;
+
+ return 0;
+}
+
static int ad7768_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
{
struct iio_dev *indio_dev = gpiochip_get_data(chip);
@@ -735,6 +899,19 @@ static int ad7768_get_filter_type_attr(struct iio_dev *dev,
return ad7768_filter_regval_to_type[FIELD_GET(mask, mode)];
}
+static int ad7768_update_dec_rate(struct iio_dev *dev, unsigned int dec_rate)
+{
+ struct ad7768_state *st = iio_priv(dev);
+ int ret;
+
+ ret = ad7768_configure_dig_fil(dev, st->filter_type, dec_rate);
+ if (ret)
+ return ret;
+
+ /* Update sampling frequency */
+ return ad7768_set_freq(st, st->samp_freq);
+}
+
static const struct iio_enum ad7768_filter_type_iio_enum = {
.items = ad7768_filter_enum,
.num_items = ARRAY_SIZE(ad7768_filter_enum),
@@ -748,24 +925,32 @@ static const struct iio_chan_spec_ext_info ad7768_ext_info[] = {
{ }
};
+#define AD7768_CHAN(_idx, _msk_avail) \
+{ \
+ .type = IIO_VOLTAGE, \
+ .info_mask_separate_available = _msk_avail, \
+ .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 = _idx, \
+ .scan_index = _idx, \
+ .has_ext_scan_type = 1, \
+ .ext_scan_type = ad7768_scan_type, \
+ .num_ext_scan_type = ARRAY_SIZE(ad7768_scan_type), \
+}
+
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),
- },
+ AD7768_CHAN(0, 0),
+};
+
+static const struct iio_chan_spec adaq776x_channels[] = {
+ AD7768_CHAN(0, BIT(IIO_CHAN_INFO_SCALE)),
};
static int ad7768_read_raw(struct iio_dev *indio_dev,
@@ -795,7 +980,19 @@ static int ad7768_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- *val = (st->vref_uv * 2) / 1000;
+ if (st->chip->has_pga) {
+ guard(mutex)(&st->pga_lock);
+
+ *val = st->scale_tbl[st->pga_gain_mode][0];
+ *val2 = st->scale_tbl[st->pga_gain_mode][1];
+ return IIO_VAL_INT_PLUS_NANO;
+ }
+
+ temp = (st->vref_uv * 2) / 1000;
+ if (st->chip->has_variable_aaf)
+ temp = (temp * PERMYRIAD) / ad7768_aaf_gains_bp[st->aaf_gain];
+
+ *val = temp;
*val2 = scan_type->realbits;
return IIO_VAL_FRACTIONAL_LOG2;
@@ -851,31 +1048,24 @@ static int ad7768_read_avail(struct iio_dev *indio_dev,
*length = st->samp_freq_avail_len;
*type = IIO_VAL_INT;
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_SCALE:
+ *vals = (int *)st->scale_tbl;
+ *length = st->chip->num_pga_modes * 2;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ 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)
+static int ad7768_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, long mask)
{
- 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);
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
default:
- return -EINVAL;
+ return IIO_VAL_INT_PLUS_MICRO;
}
}
@@ -883,15 +1073,47 @@ 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);
+ const struct iio_scan_type *scan_type;
int ret;
- if (!iio_device_claim_direct(indio_dev))
- return -EBUSY;
+ scan_type = iio_get_current_scan_type(indio_dev, chan);
+ if (IS_ERR(scan_type))
+ return PTR_ERR(scan_type);
- ret = __ad7768_write_raw(indio_dev, chan, val, val2, info);
- iio_device_release_direct(indio_dev);
+ switch (info) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
- return ret;
+ ret = ad7768_set_freq(st, val);
+ iio_device_release_direct(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = ad7768_update_dec_rate(indio_dev, val);
+ iio_device_release_direct(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_SCALE: {
+ int gain_mode;
+
+ if (!st->chip->has_pga)
+ return -EOPNOTSUPP;
+
+ if (scan_type->sign == 's')
+ gain_mode = ad7768_calc_pga_gain(st, val, val2,
+ scan_type->realbits - 1);
+ else
+ gain_mode = ad7768_calc_pga_gain(st, val, val2,
+ scan_type->realbits);
+
+ return ad7768_set_pga_gain(st, gain_mode);
+ }
+ default:
+ return -EINVAL;
+ }
}
static int ad7768_read_label(struct iio_dev *indio_dev,
@@ -915,6 +1137,7 @@ static const struct iio_info ad7768_info = {
.read_raw = &ad7768_read_raw,
.read_avail = &ad7768_read_avail,
.write_raw = &ad7768_write_raw,
+ .write_raw_get_fmt = &ad7768_write_raw_get_fmt,
.read_label = ad7768_read_label,
.get_current_scan_type = &ad7768_get_current_scan_type,
.debugfs_reg_access = &ad7768_reg_access,
@@ -1298,8 +1521,9 @@ static const struct regulator_desc vcm_desc = {
.owner = THIS_MODULE,
};
-static int ad7768_register_regulators(struct device *dev, struct ad7768_state *st,
- struct iio_dev *indio_dev)
+static int ad7768_register_vcm_regulator(struct device *dev,
+ struct ad7768_state *st,
+ struct iio_dev *indio_dev)
{
struct regulator_config config = {
.dev = dev,
@@ -1321,6 +1545,79 @@ static int ad7768_register_regulators(struct device *dev, struct ad7768_state *s
return 0;
}
+static int ad7768_parse_aaf_gain(struct device *dev, struct ad7768_state *st)
+{
+ u32 val;
+ int ret;
+
+ ret = device_property_read_u32(dev, "adi,aaf-gain-bp", &val);
+ if (ret == -EINVAL) {
+ /* If controllable, use default */
+ if (st->chip->has_variable_aaf)
+ st->aaf_gain = AD7768_AAF_IN1;
+ return 0;
+ }
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get AAF gain value\n");
+
+ if (!st->chip->has_variable_aaf)
+ return dev_err_probe(dev, -EOPNOTSUPP,
+ "AAF gain provided, but not supported for %s\n", st->chip->name);
+
+ switch (val) {
+ case 10000:
+ st->aaf_gain = AD7768_AAF_IN1;
+ break;
+ case 3640:
+ st->aaf_gain = AD7768_AAF_IN2;
+ break;
+ case 1430:
+ st->aaf_gain = AD7768_AAF_IN3;
+ break;
+ default:
+ return dev_err_probe(dev, -EINVAL, "Invalid firmware provided AAF gain\n");
+ }
+
+ return 0;
+}
+
+static const struct ad7768_chip_info ad7768_chip_info = {
+ .name = "ad7768-1",
+ .channel_spec = ad7768_channels,
+ .num_channels = ARRAY_SIZE(ad7768_channels),
+ .has_vcm_regulator = true,
+};
+
+static const struct ad7768_chip_info adaq7767_chip_info = {
+ .name = "adaq7767-1",
+ .channel_spec = ad7768_channels,
+ .num_channels = ARRAY_SIZE(ad7768_channels),
+ .has_variable_aaf = true,
+};
+
+static const struct ad7768_chip_info adaq7768_chip_info = {
+ .name = "adaq7768-1",
+ .channel_spec = adaq776x_channels,
+ .num_channels = ARRAY_SIZE(adaq776x_channels),
+ .pga_gains = adaq7768_gains,
+ .default_pga_mode = AD7768_PGA_GAIN_2,
+ .num_pga_modes = ARRAY_SIZE(adaq7768_gains),
+ .pgia_mode2pin_offset = 6,
+ .has_pga = true,
+};
+
+static const struct ad7768_chip_info adaq7769_chip_info = {
+ .name = "adaq7769-1",
+ .channel_spec = adaq776x_channels,
+ .num_channels = ARRAY_SIZE(adaq776x_channels),
+ .pga_gains = adaq7769_gains,
+ .default_pga_mode = AD7768_PGA_GAIN_0,
+ .num_pga_modes = ARRAY_SIZE(adaq7769_gains),
+ .pgia_mode2pin_offset = 0,
+ .has_pga = true,
+ .has_variable_aaf = true,
+};
+
static int ad7768_probe(struct spi_device *spi)
{
struct ad7768_state *st;
@@ -1347,6 +1644,7 @@ static int ad7768_probe(struct spi_device *spi)
return ret;
}
+ st->chip = spi_get_device_match_data(spi);
st->spi = spi;
st->regmap = devm_regmap_init_spi(spi, &ad7768_regmap_config);
@@ -1371,14 +1669,20 @@ static int ad7768_probe(struct spi_device *spi)
st->mclk_freq = clk_get_rate(st->mclk);
- indio_dev->channels = ad7768_channels;
- indio_dev->num_channels = ARRAY_SIZE(ad7768_channels);
- indio_dev->name = spi_get_device_id(spi)->name;
+ indio_dev->channels = st->chip->channel_spec;
+ indio_dev->num_channels = st->chip->num_channels;
+ indio_dev->name = st->chip->name;
indio_dev->info = &ad7768_info;
indio_dev->modes = INDIO_DIRECT_MODE;
/* Register VCM output regulator */
- ret = ad7768_register_regulators(&spi->dev, st, indio_dev);
+ if (st->chip->has_vcm_regulator) {
+ ret = ad7768_register_vcm_regulator(&spi->dev, st, indio_dev);
+ if (ret)
+ return ret;
+ }
+
+ ret = ad7768_parse_aaf_gain(&spi->dev, st);
if (ret)
return ret;
@@ -1389,14 +1693,26 @@ static int ad7768_probe(struct spi_device *spi)
}
init_completion(&st->completion);
+ ret = devm_mutex_init(&spi->dev, &st->pga_lock);
+ if (ret)
+ return ret;
+
+ if (st->chip->has_pga) {
+ ret = ad7768_setup_pga(&spi->dev, st);
+ if (ret)
+ return ret;
+
+ ret = ad7768_set_pga_gain(st, st->chip->default_pga_mode);
+ if (ret)
+ return ret;
+ }
- ret = ad7768_set_channel_label(indio_dev, ARRAY_SIZE(ad7768_channels));
+ ret = ad7768_set_channel_label(indio_dev, st->chip->num_channels);
if (ret)
return ret;
- ret = devm_request_irq(&spi->dev, spi->irq,
- &ad7768_interrupt,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ ret = devm_request_irq(&spi->dev, spi->irq, &ad7768_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_NO_THREAD,
indio_dev->name, indio_dev);
if (ret)
return ret;
@@ -1409,13 +1725,19 @@ static int ad7768_probe(struct spi_device *spi)
}
static const struct spi_device_id ad7768_id_table[] = {
- { "ad7768-1", 0 },
+ { "ad7768-1", (kernel_ulong_t)&ad7768_chip_info },
+ { "adaq7767-1", (kernel_ulong_t)&adaq7767_chip_info },
+ { "adaq7768-1", (kernel_ulong_t)&adaq7768_chip_info },
+ { "adaq7769-1", (kernel_ulong_t)&adaq7769_chip_info },
{ }
};
MODULE_DEVICE_TABLE(spi, ad7768_id_table);
static const struct of_device_id ad7768_of_match[] = {
- { .compatible = "adi,ad7768-1" },
+ { .compatible = "adi,ad7768-1", .data = &ad7768_chip_info },
+ { .compatible = "adi,adaq7767-1", .data = &adaq7767_chip_info },
+ { .compatible = "adi,adaq7768-1", .data = &adaq7768_chip_info },
+ { .compatible = "adi,adaq7769-1", .data = &adaq7769_chip_info },
{ }
};
MODULE_DEVICE_TABLE(of, ad7768_of_match);
diff --git a/drivers/iio/adc/ad7779.c b/drivers/iio/adc/ad7779.c
index aac5049c9a07..695cc79e78da 100644
--- a/drivers/iio/adc/ad7779.c
+++ b/drivers/iio/adc/ad7779.c
@@ -840,7 +840,7 @@ static int ad7779_setup_without_backend(struct ad7779_state *st, struct iio_dev
iio_trigger_set_drvdata(st->trig, st);
ret = devm_request_irq(dev, st->spi->irq, iio_trigger_generic_data_rdy_poll,
- IRQF_ONESHOT | IRQF_NO_AUTOEN, indio_dev->name,
+ IRQF_NO_THREAD | IRQF_NO_AUTOEN, indio_dev->name,
st->trig);
if (ret)
return dev_err_probe(dev, ret, "request IRQ %d failed\n",
diff --git a/drivers/iio/adc/ad9467.c b/drivers/iio/adc/ad9467.c
index 2d8f8da3671d..022888545580 100644
--- a/drivers/iio/adc/ad9467.c
+++ b/drivers/iio/adc/ad9467.c
@@ -5,29 +5,29 @@
* Copyright 2012-2020 Analog Devices Inc.
*/
+#include <linux/bitfield.h>
#include <linux/bitmap.h>
#include <linux/bitops.h>
#include <linux/cleanup.h>
+#include <linux/clk.h>
#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
+#include <linux/delay.h>
#include <linux/device.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/spi/spi.h>
-#include <linux/seq_file.h>
#include <linux/err.h>
-#include <linux/delay.h>
#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/of.h>
-
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/units.h>
#include <linux/iio/backend.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
-#include <linux/clk.h>
-
/*
* ADI High-Speed ADC common spi interface registers
* See Application-Note AN-877:
@@ -73,6 +73,7 @@
#define AN877_ADC_OUTPUT_MODE_OFFSET_BINARY 0x0
#define AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT 0x1
#define AN877_ADC_OUTPUT_MODE_GRAY_CODE 0x2
+#define AN877_ADC_OUTPUT_MODE_MASK GENMASK(1, 0)
/* AN877_ADC_REG_OUTPUT_PHASE */
#define AN877_ADC_OUTPUT_EVEN_ODD_MODE_EN 0x20
@@ -82,11 +83,19 @@
#define AN877_ADC_DCO_DELAY_ENABLE 0x80
/*
+ * Analog Devices AD9211 10-Bit, 200/250/300 MSPS ADC
+ */
+
+#define CHIPID_AD9211 0x06
+#define AD9211_DEF_OUTPUT_MODE 0x01
+#define AD9211_REG_VREF_MASK GENMASK(4, 0)
+
+/*
* Analog Devices AD9265 16-Bit, 125/105/80 MSPS ADC
*/
#define CHIPID_AD9265 0x64
-#define AD9265_DEF_OUTPUT_MODE 0x40
+#define AD9265_DEF_OUTPUT_MODE 0x41
#define AD9265_REG_VREF_MASK 0xC0
/*
@@ -94,7 +103,7 @@
*/
#define CHIPID_AD9434 0x6A
-#define AD9434_DEF_OUTPUT_MODE 0x00
+#define AD9434_DEF_OUTPUT_MODE 0x01
#define AD9434_REG_VREF_MASK GENMASK(4, 0)
/*
@@ -102,7 +111,7 @@
*/
#define CHIPID_AD9467 0x50
-#define AD9467_DEF_OUTPUT_MODE 0x08
+#define AD9467_DEF_OUTPUT_MODE 0x09
#define AD9467_REG_VREF_MASK 0x0F
/*
@@ -110,6 +119,7 @@
*/
#define CHIPID_AD9643 0x82
+#define AD9643_DEF_OUTPUT_MODE 0x01
#define AD9643_REG_VREF_MASK 0x1F
/*
@@ -117,6 +127,7 @@
*/
#define CHIPID_AD9652 0xC1
+#define AD9652_DEF_OUTPUT_MODE 0x01
#define AD9652_REG_VREF_MASK 0xC0
/*
@@ -124,6 +135,7 @@
*/
#define CHIPID_AD9649 0x6F
+#define AD9649_DEF_OUTPUT_MODE 0x01
#define AD9649_TEST_POINTS 8
#define AD9647_MAX_TEST_POINTS 32
@@ -145,6 +157,7 @@ struct ad9467_chip_info {
unsigned int num_lanes;
unsigned int dco_en;
unsigned int test_points;
+ const int *offset_range;
/* data clock output */
bool has_dco;
bool has_dco_invert;
@@ -234,6 +247,21 @@ static int ad9467_reg_access(struct iio_dev *indio_dev, unsigned int reg,
return 0;
}
+static const int ad9434_offset_range[] = {
+ -128, 1, 127,
+};
+
+static const unsigned int ad9211_scale_table[][2] = {
+ {980, 0x10}, {1000, 0x11}, {1020, 0x12}, {1040, 0x13},
+ {1060, 0x14}, {1080, 0x15}, {1100, 0x16}, {1120, 0x17},
+ {1140, 0x18}, {1160, 0x19}, {1180, 0x1A}, {1190, 0x1B},
+ {1200, 0x1C}, {1210, 0x1D}, {1220, 0x1E}, {1230, 0x1F},
+ {1250, 0x0}, {1270, 0x1}, {1290, 0x2}, {1310, 0x3},
+ {1330, 0x4}, {1350, 0x5}, {1370, 0x6}, {1390, 0x7},
+ {1410, 0x8}, {1430, 0x9}, {1450, 0xA}, {1460, 0xB},
+ {1470, 0xC}, {1480, 0xD}, {1490, 0xE}, {1500, 0xF},
+};
+
static const unsigned int ad9265_scale_table[][2] = {
{1250, 0x00}, {1500, 0x40}, {1750, 0x80}, {2000, 0xC0},
};
@@ -297,8 +325,29 @@ static void __ad9467_get_scale(struct ad9467_state *st, int index,
}, \
}
+static const struct iio_chan_spec ad9211_channels[] = {
+ AD9467_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 0, 10, 's'),
+};
+
static const struct iio_chan_spec ad9434_channels[] = {
- AD9467_CHAN(0, BIT(IIO_CHAN_INFO_SCALE), 0, 12, 's'),
+ {
+ .type = IIO_VOLTAGE,
+ .indexed = 1,
+ .channel = 0,
+ .info_mask_shared_by_type =
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ .info_mask_shared_by_type_available =
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBBIAS),
+ .scan_index = 0,
+ .scan_type = {
+ .sign = 's',
+ .realbits = 12,
+ .storagebits = 16,
+ },
+ },
};
static const struct iio_chan_spec ad9467_channels[] = {
@@ -367,6 +416,24 @@ static const struct ad9467_chip_info ad9434_chip_tbl = {
.default_output_mode = AD9434_DEF_OUTPUT_MODE,
.vref_mask = AD9434_REG_VREF_MASK,
.num_lanes = 6,
+ .offset_range = ad9434_offset_range,
+};
+
+static const struct ad9467_chip_info ad9211_chip_tbl = {
+ .name = "ad9211",
+ .id = CHIPID_AD9211,
+ .max_rate = 300 * HZ_PER_MHZ,
+ .scale_table = ad9211_scale_table,
+ .num_scales = ARRAY_SIZE(ad9211_scale_table),
+ .channels = ad9211_channels,
+ .num_channels = ARRAY_SIZE(ad9211_channels),
+ .test_points = AD9647_MAX_TEST_POINTS,
+ .test_mask = GENMASK(AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE,
+ AN877_ADC_TESTMODE_OFF),
+ .test_mask_len = AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE + 1,
+ .default_output_mode = AD9211_DEF_OUTPUT_MODE,
+ .vref_mask = AD9211_REG_VREF_MASK,
+ .has_dco = true,
};
static const struct ad9467_chip_info ad9265_chip_tbl = {
@@ -399,6 +466,7 @@ static const struct ad9467_chip_info ad9643_chip_tbl = {
.test_mask = BIT(AN877_ADC_TESTMODE_RAMP) |
GENMASK(AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY, AN877_ADC_TESTMODE_OFF),
.test_mask_len = AN877_ADC_TESTMODE_RAMP + 1,
+ .default_output_mode = AD9643_DEF_OUTPUT_MODE,
.vref_mask = AD9643_REG_VREF_MASK,
.has_dco = true,
.has_dco_invert = true,
@@ -417,6 +485,7 @@ static const struct ad9467_chip_info ad9649_chip_tbl = {
.test_mask = GENMASK(AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY,
AN877_ADC_TESTMODE_OFF),
.test_mask_len = AN877_ADC_TESTMODE_MIXED_BIT_FREQUENCY + 1,
+ .default_output_mode = AD9649_DEF_OUTPUT_MODE,
.has_dco = true,
.has_dco_invert = true,
.dco_en = AN877_ADC_DCO_DELAY_ENABLE,
@@ -434,6 +503,7 @@ static const struct ad9467_chip_info ad9652_chip_tbl = {
.test_mask = GENMASK(AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE,
AN877_ADC_TESTMODE_OFF),
.test_mask_len = AN877_ADC_TESTMODE_ONE_ZERO_TOGGLE + 1,
+ .default_output_mode = AD9652_DEF_OUTPUT_MODE,
.vref_mask = AD9652_REG_VREF_MASK,
.has_dco = true,
};
@@ -499,6 +569,33 @@ static int ad9467_set_scale(struct ad9467_state *st, int val, int val2)
return -EINVAL;
}
+static int ad9467_get_offset(struct ad9467_state *st, int *val)
+{
+ int ret;
+
+ ret = ad9467_spi_read(st, AN877_ADC_REG_OFFSET);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+
+ return IIO_VAL_INT;
+}
+
+static int ad9467_set_offset(struct ad9467_state *st, int val)
+{
+ int ret;
+
+ if (val < st->info->offset_range[0] || val > st->info->offset_range[2])
+ return -EINVAL;
+
+ ret = ad9467_spi_write(st, AN877_ADC_REG_OFFSET, val);
+ if (ret < 0)
+ return ret;
+
+ return ad9467_spi_write(st, AN877_ADC_REG_TRANSFER,
+ AN877_ADC_TRANSFER_SYNC);
+}
+
static int ad9467_outputmode_set(struct ad9467_state *st, unsigned int mode)
{
int ret;
@@ -582,10 +679,14 @@ static int ad9467_backend_testmode_off(struct ad9467_state *st,
static int ad9647_calibrate_prepare(struct ad9467_state *st)
{
+ unsigned int cmode;
unsigned int c;
int ret;
- ret = ad9467_outputmode_set(st, st->info->default_output_mode);
+ cmode = st->info->default_output_mode;
+ FIELD_MODIFY(AN877_ADC_OUTPUT_MODE_MASK, &cmode,
+ AN877_ADC_OUTPUT_MODE_OFFSET_BINARY);
+ ret = ad9467_outputmode_set(st, cmode);
if (ret)
return ret;
@@ -689,7 +790,7 @@ static int ad9647_calibrate_stop(struct ad9467_state *st)
return ret;
}
- mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
+ mode = st->info->default_output_mode;
return ad9467_outputmode_set(st, mode);
}
@@ -802,6 +903,8 @@ static int ad9467_read_raw(struct iio_dev *indio_dev,
struct ad9467_state *st = iio_priv(indio_dev);
switch (m) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return ad9467_get_offset(st, val);
case IIO_CHAN_INFO_SCALE:
return ad9467_get_scale(st, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
@@ -836,6 +939,8 @@ static int ad9467_write_raw(struct iio_dev *indio_dev,
int ret;
switch (mask) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return ad9467_set_offset(st, val);
case IIO_CHAN_INFO_SCALE:
return ad9467_set_scale(st, val, val2);
case IIO_CHAN_INFO_SAMP_FREQ:
@@ -874,6 +979,10 @@ static int ad9467_read_avail(struct iio_dev *indio_dev,
const struct ad9467_chip_info *info = st->info;
switch (mask) {
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *type = IIO_VAL_INT;
+ *vals = info->offset_range;
+ return IIO_AVAIL_RANGE;
case IIO_CHAN_INFO_SCALE:
*vals = (const int *)st->scales;
*type = IIO_VAL_INT_PLUS_MICRO;
@@ -1077,12 +1186,17 @@ static ssize_t ad9467_chan_test_mode_write(struct file *file,
if (ret)
return ret;
- out_mode = st->info->default_output_mode | AN877_ADC_OUTPUT_MODE_TWOS_COMPLEMENT;
+ out_mode = st->info->default_output_mode;
ret = ad9467_outputmode_set(st, out_mode);
if (ret)
return ret;
} else {
- ret = ad9467_outputmode_set(st, st->info->default_output_mode);
+ unsigned int cmode;
+
+ cmode = st->info->default_output_mode;
+ FIELD_MODIFY(AN877_ADC_OUTPUT_MODE_MASK, &cmode,
+ AN877_ADC_OUTPUT_MODE_OFFSET_BINARY);
+ ret = ad9467_outputmode_set(st, cmode);
if (ret)
return ret;
@@ -1264,6 +1378,7 @@ static int ad9467_probe(struct spi_device *spi)
}
static const struct of_device_id ad9467_of_match[] = {
+ { .compatible = "adi,ad9211", .data = &ad9211_chip_tbl, },
{ .compatible = "adi,ad9265", .data = &ad9265_chip_tbl, },
{ .compatible = "adi,ad9434", .data = &ad9434_chip_tbl, },
{ .compatible = "adi,ad9467", .data = &ad9467_chip_tbl, },
@@ -1275,6 +1390,7 @@ static const struct of_device_id ad9467_of_match[] = {
MODULE_DEVICE_TABLE(of, ad9467_of_match);
static const struct spi_device_id ad9467_ids[] = {
+ { "ad9211", (kernel_ulong_t)&ad9211_chip_tbl },
{ "ad9265", (kernel_ulong_t)&ad9265_chip_tbl },
{ "ad9434", (kernel_ulong_t)&ad9434_chip_tbl },
{ "ad9467", (kernel_ulong_t)&ad9467_chip_tbl },
diff --git a/drivers/iio/adc/ade9000.c b/drivers/iio/adc/ade9000.c
index 2de8a718d62a..db085dc5e526 100644
--- a/drivers/iio/adc/ade9000.c
+++ b/drivers/iio/adc/ade9000.c
@@ -964,7 +964,7 @@ static irqreturn_t ade9000_dready_thread(int irq, void *data)
struct iio_dev *indio_dev = data;
/* Handle data ready interrupt from C4/EVENT/DREADY pin */
- if (!iio_device_claim_buffer_mode(indio_dev)) {
+ if (iio_device_try_claim_buffer_mode(indio_dev)) {
ade9000_iio_push_buffer(indio_dev);
iio_device_release_buffer_mode(indio_dev);
}
diff --git a/drivers/iio/adc/adi-axi-adc.c b/drivers/iio/adc/adi-axi-adc.c
index 14fa4238c2b9..5f445e0de9ea 100644
--- a/drivers/iio/adc/adi-axi-adc.c
+++ b/drivers/iio/adc/adi-axi-adc.c
@@ -591,17 +591,12 @@ static int axi_adc_create_platform_device(struct adi_axi_adc_state *st,
.size_data = st->info->pdata_sz,
};
struct platform_device *pdev;
- int ret;
pdev = platform_device_register_full(&pi);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
- ret = devm_add_action_or_reset(st->dev, axi_adc_child_remove, pdev);
- if (ret)
- return ret;
-
- return 0;
+ return devm_add_action_or_reset(st->dev, axi_adc_child_remove, pdev);
}
static const struct iio_backend_ops adi_axi_adc_ops = {
@@ -674,13 +669,14 @@ static const struct iio_backend_info axi_ad408x = {
static int adi_axi_adc_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct adi_axi_adc_state *st;
void __iomem *base;
unsigned int ver;
struct clk *clk;
int ret;
- st = devm_kzalloc(&pdev->dev, sizeof(*st), GFP_KERNEL);
+ st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
if (!st)
return -ENOMEM;
@@ -688,20 +684,19 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
- st->dev = &pdev->dev;
- st->regmap = devm_regmap_init_mmio(&pdev->dev, base,
- &axi_adc_regmap_config);
+ st->dev = dev;
+ st->regmap = devm_regmap_init_mmio(dev, base, &axi_adc_regmap_config);
if (IS_ERR(st->regmap))
- return dev_err_probe(&pdev->dev, PTR_ERR(st->regmap),
+ return dev_err_probe(dev, PTR_ERR(st->regmap),
"failed to init register map\n");
- st->info = device_get_match_data(&pdev->dev);
+ st->info = device_get_match_data(dev);
if (!st->info)
return -ENODEV;
- clk = devm_clk_get_enabled(&pdev->dev, NULL);
+ clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(clk))
- return dev_err_probe(&pdev->dev, PTR_ERR(clk),
+ return dev_err_probe(dev, PTR_ERR(clk),
"failed to get clock\n");
/*
@@ -716,47 +711,42 @@ static int adi_axi_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (ADI_AXI_PCORE_VER_MAJOR(ver) !=
- ADI_AXI_PCORE_VER_MAJOR(st->info->version)) {
- dev_err(&pdev->dev,
- "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
- ADI_AXI_PCORE_VER_MAJOR(st->info->version),
- ADI_AXI_PCORE_VER_MINOR(st->info->version),
- ADI_AXI_PCORE_VER_PATCH(st->info->version),
- ADI_AXI_PCORE_VER_MAJOR(ver),
- ADI_AXI_PCORE_VER_MINOR(ver),
- ADI_AXI_PCORE_VER_PATCH(ver));
- return -ENODEV;
- }
-
- ret = devm_iio_backend_register(&pdev->dev, st->info->backend_info, st);
+ if (ADI_AXI_PCORE_VER_MAJOR(ver) != ADI_AXI_PCORE_VER_MAJOR(st->info->version))
+ return dev_err_probe(dev, -ENODEV,
+ "Major version mismatch. Expected %d.%.2d.%c, Reported %d.%.2d.%c\n",
+ ADI_AXI_PCORE_VER_MAJOR(st->info->version),
+ ADI_AXI_PCORE_VER_MINOR(st->info->version),
+ ADI_AXI_PCORE_VER_PATCH(st->info->version),
+ ADI_AXI_PCORE_VER_MAJOR(ver),
+ ADI_AXI_PCORE_VER_MINOR(ver),
+ ADI_AXI_PCORE_VER_PATCH(ver));
+
+ ret = devm_iio_backend_register(dev, st->info->backend_info, st);
if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "failed to register iio backend\n");
+ return dev_err_probe(dev, ret, "failed to register iio backend\n");
- device_for_each_child_node_scoped(&pdev->dev, child) {
+ device_for_each_child_node_scoped(dev, child) {
int val;
if (!st->info->has_child_nodes)
- return dev_err_probe(&pdev->dev, -EINVAL,
+ return dev_err_probe(dev, -EINVAL,
"invalid fdt axi-dac compatible.");
/* Processing only reg 0 node */
ret = fwnode_property_read_u32(child, "reg", &val);
if (ret)
- return dev_err_probe(&pdev->dev, ret,
- "invalid reg property.");
+ return dev_err_probe(dev, ret, "invalid reg property.");
if (val != 0)
- return dev_err_probe(&pdev->dev, -EINVAL,
+ return dev_err_probe(dev, -EINVAL,
"invalid node address.");
ret = axi_adc_create_platform_device(st, child);
if (ret)
- return dev_err_probe(&pdev->dev, -EINVAL,
+ return dev_err_probe(dev, -EINVAL,
"cannot create device.");
}
- dev_info(&pdev->dev, "AXI ADC IP core (%d.%.2d.%c) probed\n",
+ dev_info(dev, "AXI ADC IP core (%d.%.2d.%c) probed\n",
ADI_AXI_PCORE_VER_MAJOR(ver),
ADI_AXI_PCORE_VER_MINOR(ver),
ADI_AXI_PCORE_VER_PATCH(ver));
diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index bf2bfd6bdc41..4be44c524b4d 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -472,16 +472,18 @@ static int aspeed_adc_probe(struct platform_device *pdev)
struct aspeed_adc_data *data;
int ret;
u32 adc_engine_control_reg_val;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev_of_node(dev);
unsigned long scaler_flags = 0;
char clk_name[32], clk_parent_name[32];
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
data = iio_priv(indio_dev);
- data->dev = &pdev->dev;
- data->model_data = of_device_get_match_data(&pdev->dev);
+ data->dev = dev;
+ data->model_data = of_device_get_match_data(dev);
platform_set_drvdata(pdev, indio_dev);
data->base = devm_platform_ioremap_resource(pdev, 0);
@@ -491,16 +493,15 @@ static int aspeed_adc_probe(struct platform_device *pdev)
/* Register ADC clock prescaler with source specified by device tree. */
spin_lock_init(&data->clk_lock);
snprintf(clk_parent_name, ARRAY_SIZE(clk_parent_name), "%s",
- of_clk_get_parent_name(pdev->dev.of_node, 0));
+ of_clk_get_parent_name(np, 0));
snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-fixed-div",
data->model_data->model_name);
- data->fixed_div_clk = clk_hw_register_fixed_factor(
- &pdev->dev, clk_name, clk_parent_name, 0, 1, 2);
+ data->fixed_div_clk = clk_hw_register_fixed_factor(dev, clk_name,
+ clk_parent_name, 0, 1, 2);
if (IS_ERR(data->fixed_div_clk))
return PTR_ERR(data->fixed_div_clk);
- ret = devm_add_action_or_reset(data->dev,
- aspeed_adc_unregister_fixed_divider,
+ ret = devm_add_action_or_reset(dev, aspeed_adc_unregister_fixed_divider,
data->fixed_div_clk);
if (ret)
return ret;
@@ -510,7 +511,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-prescaler",
data->model_data->model_name);
data->clk_prescaler = devm_clk_hw_register_divider(
- &pdev->dev, clk_name, clk_parent_name, 0,
+ dev, clk_name, clk_parent_name, 0,
data->base + ASPEED_REG_CLOCK_CONTROL, 17, 15, 0,
&data->clk_lock);
if (IS_ERR(data->clk_prescaler))
@@ -526,7 +527,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
snprintf(clk_name, ARRAY_SIZE(clk_name), "%s-scaler",
data->model_data->model_name);
data->clk_scaler = devm_clk_hw_register_divider(
- &pdev->dev, clk_name, clk_parent_name, scaler_flags,
+ dev, clk_name, clk_parent_name, scaler_flags,
data->base + ASPEED_REG_CLOCK_CONTROL, 0,
data->model_data->scaler_bit_width,
data->model_data->need_prescaler ? CLK_DIVIDER_ONE_BASED : 0,
@@ -534,16 +535,14 @@ static int aspeed_adc_probe(struct platform_device *pdev)
if (IS_ERR(data->clk_scaler))
return PTR_ERR(data->clk_scaler);
- data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
- if (IS_ERR(data->rst)) {
- dev_err(&pdev->dev,
- "invalid or missing reset controller device tree entry");
- return PTR_ERR(data->rst);
- }
+ data->rst = devm_reset_control_get_shared(dev, NULL);
+ if (IS_ERR(data->rst))
+ return dev_err_probe(dev, PTR_ERR(data->rst),
+ "invalid or missing reset controller device tree entry");
+
reset_control_deassert(data->rst);
- ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,
- data->rst);
+ ret = devm_add_action_or_reset(dev, aspeed_adc_reset_assert, data->rst);
if (ret)
return ret;
@@ -555,7 +554,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
if (ret)
return ret;
- if (of_property_present(data->dev->of_node, "aspeed,battery-sensing")) {
+ if (of_property_present(np, "aspeed,battery-sensing")) {
if (data->model_data->bat_sense_sup) {
data->battery_sensing = 1;
if (readl(data->base + ASPEED_REG_ENGINE_CONTROL) &
@@ -567,15 +566,13 @@ static int aspeed_adc_probe(struct platform_device *pdev)
data->battery_mode_gain.div = 2;
}
} else
- dev_warn(&pdev->dev,
- "Failed to enable battery-sensing mode\n");
+ dev_warn(dev, "Failed to enable battery-sensing mode\n");
}
ret = clk_prepare_enable(data->clk_scaler->clk);
if (ret)
return ret;
- ret = devm_add_action_or_reset(data->dev,
- aspeed_adc_clk_disable_unprepare,
+ ret = devm_add_action_or_reset(dev, aspeed_adc_clk_disable_unprepare,
data->clk_scaler->clk);
if (ret)
return ret;
@@ -593,8 +590,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
writel(adc_engine_control_reg_val,
data->base + ASPEED_REG_ENGINE_CONTROL);
- ret = devm_add_action_or_reset(data->dev, aspeed_adc_power_down,
- data);
+ ret = devm_add_action_or_reset(dev, aspeed_adc_power_down, data);
if (ret)
return ret;
@@ -626,8 +622,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
aspeed_adc_iio_channels;
indio_dev->num_channels = data->model_data->num_channels;
- ret = devm_iio_device_register(data->dev, indio_dev);
- return ret;
+ return devm_iio_device_register(dev, indio_dev);
}
static const struct aspeed_adc_trim_locate ast2500_adc_trim = {
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index f2400897818c..c1a0061b16ca 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -543,22 +543,21 @@ static const struct iio_chan_spec exynos_adc_iio_channels[] = {
static int exynos_adc_probe(struct platform_device *pdev)
{
struct exynos_adc *info = NULL;
+ struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
int ret;
int irq;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct exynos_adc));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(struct exynos_adc));
if (!indio_dev)
return -ENOMEM;
info = iio_priv(indio_dev);
info->data = exynos_adc_get_data(pdev);
- if (!info->data) {
- dev_err(&pdev->dev, "failed getting exynos_adc_data\n");
- return -EINVAL;
- }
+ if (!info->data)
+ return dev_err_probe(dev, -EINVAL, "failed getting exynos_adc_data\n");
info->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(info->regs))
@@ -566,44 +565,34 @@ static int exynos_adc_probe(struct platform_device *pdev)
if (info->data->needs_adc_phy) {
- info->pmu_map = syscon_regmap_lookup_by_phandle(
- pdev->dev.of_node,
- "samsung,syscon-phandle");
- if (IS_ERR(info->pmu_map)) {
- dev_err(&pdev->dev, "syscon regmap lookup failed.\n");
- return PTR_ERR(info->pmu_map);
- }
+ info->pmu_map = syscon_regmap_lookup_by_phandle(np, "samsung,syscon-phandle");
+ if (IS_ERR(info->pmu_map))
+ return dev_err_probe(dev, PTR_ERR(info->pmu_map),
+ "syscon regmap lookup failed.\n");
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
info->irq = irq;
- info->dev = &pdev->dev;
+ info->dev = dev;
init_completion(&info->completion);
- info->clk = devm_clk_get(&pdev->dev, "adc");
- if (IS_ERR(info->clk)) {
- dev_err(&pdev->dev, "failed getting clock, err = %ld\n",
- PTR_ERR(info->clk));
- return PTR_ERR(info->clk);
- }
+ info->clk = devm_clk_get(dev, "adc");
+ if (IS_ERR(info->clk))
+ return dev_err_probe(dev, PTR_ERR(info->clk), "failed getting clock\n");
if (info->data->needs_sclk) {
- info->sclk = devm_clk_get(&pdev->dev, "sclk");
- if (IS_ERR(info->sclk)) {
- dev_err(&pdev->dev,
- "failed getting sclk clock, err = %ld\n",
- PTR_ERR(info->sclk));
- return PTR_ERR(info->sclk);
- }
+ info->sclk = devm_clk_get(dev, "sclk");
+ if (IS_ERR(info->sclk))
+ return dev_err_probe(dev, PTR_ERR(info->sclk),
+ "failed getting sclk clock\n");
}
- info->vdd = devm_regulator_get(&pdev->dev, "vdd");
+ info->vdd = devm_regulator_get(dev, "vdd");
if (IS_ERR(info->vdd))
- return dev_err_probe(&pdev->dev, PTR_ERR(info->vdd),
- "failed getting regulator");
+ return dev_err_probe(dev, PTR_ERR(info->vdd), "failed getting regulator");
ret = regulator_enable(info->vdd);
if (ret)
@@ -619,7 +608,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, indio_dev);
- indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->name = dev_name(dev);
indio_dev->info = &exynos_adc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = exynos_adc_iio_channels;
@@ -627,11 +616,9 @@ static int exynos_adc_probe(struct platform_device *pdev)
mutex_init(&info->lock);
- ret = request_irq(info->irq, exynos_adc_isr,
- 0, dev_name(&pdev->dev), info);
+ ret = request_irq(info->irq, exynos_adc_isr, 0, dev_name(dev), info);
if (ret < 0) {
- dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
- info->irq);
+ dev_err(dev, "failed requesting irq, irq = %d\n", info->irq);
goto err_disable_clk;
}
@@ -644,7 +631,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
if (ret < 0) {
- dev_err(&pdev->dev, "failed adding child nodes\n");
+ dev_err(dev, "failed adding child nodes\n");
goto err_of_populate;
}
diff --git a/drivers/iio/adc/mcp3911.c b/drivers/iio/adc/mcp3911.c
index a6f21791c685..ddc3721f3f68 100644
--- a/drivers/iio/adc/mcp3911.c
+++ b/drivers/iio/adc/mcp3911.c
@@ -815,7 +815,7 @@ static int mcp3911_probe(struct spi_device *spi)
* don't enable the interrupt to avoid extra load on the system.
*/
ret = devm_request_irq(dev, spi->irq, &iio_trigger_generic_data_rdy_poll,
- IRQF_NO_AUTOEN | IRQF_ONESHOT,
+ IRQF_NO_AUTOEN | IRQF_NO_THREAD,
indio_dev->name, adc->trig);
if (ret)
return ret;
diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c
index cf8a8c0412ec..90919d282e7b 100644
--- a/drivers/iio/adc/men_z188_adc.c
+++ b/drivers/iio/adc/men_z188_adc.c
@@ -171,5 +171,4 @@ module_mcb_driver(men_z188_driver);
MODULE_AUTHOR("Johannes Thumshirn <johannes.thumshirn@men.de>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("IIO ADC driver for MEN 16z188 ADC Core");
-MODULE_ALIAS("mcb:16z188");
MODULE_IMPORT_NS("MCB");
diff --git a/drivers/iio/adc/nxp-sar-adc.c b/drivers/iio/adc/nxp-sar-adc.c
new file mode 100644
index 000000000000..9efa883c277d
--- /dev/null
+++ b/drivers/iio/adc/nxp-sar-adc.c
@@ -0,0 +1,1016 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * NXP SAR-ADC driver (adapted from Freescale Vybrid vf610 ADC driver
+ * by Fugang Duan <B38611@freescale.com>)
+ *
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ * Copyright 2017, 2020-2025 NXP
+ * Copyright 2025, Linaro Ltd
+ */
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/circ_buf.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/math64.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+/* SAR ADC registers. */
+#define NXP_SAR_ADC_CDR(__base, __channel) (((__base) + 0x100) + ((__channel) * 0x4))
+
+#define NXP_SAR_ADC_CDR_CDATA_MASK GENMASK(11, 0)
+#define NXP_SAR_ADC_CDR_VALID BIT(19)
+
+/* Main Configuration Register */
+#define NXP_SAR_ADC_MCR(__base) ((__base) + 0x00)
+
+#define NXP_SAR_ADC_MCR_PWDN BIT(0)
+#define NXP_SAR_ADC_MCR_ACKO BIT(5)
+#define NXP_SAR_ADC_MCR_ADCLKSEL BIT(8)
+#define NXP_SAR_ADC_MCR_TSAMP_MASK GENMASK(10, 9)
+#define NXP_SAR_ADC_MCR_NRSMPL_MASK GENMASK(12, 11)
+#define NXP_SAR_ADC_MCR_AVGEN BIT(13)
+#define NXP_SAR_ADC_MCR_CALSTART BIT(14)
+#define NXP_SAR_ADC_MCR_NSTART BIT(24)
+#define NXP_SAR_ADC_MCR_MODE BIT(29)
+#define NXP_SAR_ADC_MCR_OWREN BIT(31)
+
+/* Main Status Register */
+#define NXP_SAR_ADC_MSR(__base) ((__base) + 0x04)
+
+#define NXP_SAR_ADC_MSR_CALBUSY BIT(29)
+#define NXP_SAR_ADC_MSR_CALFAIL BIT(30)
+
+/* Interrupt Status Register */
+#define NXP_SAR_ADC_ISR(__base) ((__base) + 0x10)
+
+#define NXP_SAR_ADC_ISR_ECH BIT(0)
+
+/* Channel Pending Register */
+#define NXP_SAR_ADC_CEOCFR0(__base) ((__base) + 0x14)
+#define NXP_SAR_ADC_CEOCFR1(__base) ((__base) + 0x18)
+
+#define NXP_SAR_ADC_EOC_CH(c) BIT(c)
+
+/* Interrupt Mask Register */
+#define NXP_SAR_ADC_IMR(__base) ((__base) + 0x20)
+
+/* Channel Interrupt Mask Register */
+#define NXP_SAR_ADC_CIMR0(__base) ((__base) + 0x24)
+#define NXP_SAR_ADC_CIMR1(__base) ((__base) + 0x28)
+
+/* DMA Setting Register */
+#define NXP_SAR_ADC_DMAE(__base) ((__base) + 0x40)
+
+#define NXP_SAR_ADC_DMAE_DMAEN BIT(0)
+#define NXP_SAR_ADC_DMAE_DCLR BIT(1)
+
+/* DMA Control register */
+#define NXP_SAR_ADC_DMAR0(__base) ((__base) + 0x44)
+#define NXP_SAR_ADC_DMAR1(__base) ((__base) + 0x48)
+
+/* Conversion Timing Register */
+#define NXP_SAR_ADC_CTR0(__base) ((__base) + 0x94)
+#define NXP_SAR_ADC_CTR1(__base) ((__base) + 0x98)
+
+#define NXP_SAR_ADC_CTR_INPSAMP_MIN 0x08
+#define NXP_SAR_ADC_CTR_INPSAMP_MAX 0xff
+
+/* Normal Conversion Mask Register */
+#define NXP_SAR_ADC_NCMR0(__base) ((__base) + 0xa4)
+#define NXP_SAR_ADC_NCMR1(__base) ((__base) + 0xa8)
+
+/* Normal Conversion Mask Register field define */
+#define NXP_SAR_ADC_CH_MASK GENMASK(7, 0)
+
+/* Other field define */
+#define NXP_SAR_ADC_CONV_TIMEOUT (msecs_to_jiffies(100))
+#define NXP_SAR_ADC_CAL_TIMEOUT_US (100 * USEC_PER_MSEC)
+#define NXP_SAR_ADC_WAIT_US (2 * USEC_PER_MSEC)
+#define NXP_SAR_ADC_RESOLUTION 12
+
+/* Duration of conversion phases */
+#define NXP_SAR_ADC_TPT 2
+#define NXP_SAR_ADC_DP 2
+#define NXP_SAR_ADC_CT ((NXP_SAR_ADC_RESOLUTION + 2) * 4)
+#define NXP_SAR_ADC_CONV_TIME (NXP_SAR_ADC_TPT + NXP_SAR_ADC_CT + NXP_SAR_ADC_DP)
+
+#define NXP_SAR_ADC_NR_CHANNELS 8
+
+#define NXP_PAGE_SIZE SZ_4K
+#define NXP_SAR_ADC_DMA_SAMPLE_SZ DMA_SLAVE_BUSWIDTH_4_BYTES
+#define NXP_SAR_ADC_DMA_BUFF_SZ (NXP_PAGE_SIZE * NXP_SAR_ADC_DMA_SAMPLE_SZ)
+#define NXP_SAR_ADC_DMA_SAMPLE_CNT (NXP_SAR_ADC_DMA_BUFF_SZ / NXP_SAR_ADC_DMA_SAMPLE_SZ)
+
+struct nxp_sar_adc {
+ void __iomem *regs;
+ phys_addr_t regs_phys;
+ u8 current_channel;
+ u8 channels_used;
+ u16 value;
+ u32 vref_mV;
+
+ /* Save and restore context. */
+ u32 inpsamp;
+ u32 pwdn;
+
+ struct clk *clk;
+ struct dma_chan *dma_chan;
+ struct completion completion;
+ struct circ_buf dma_buf;
+
+ dma_addr_t rx_dma_buf;
+ dma_cookie_t cookie;
+
+ /* Protect circular buffers access. */
+ spinlock_t lock;
+
+ /* Array of enabled channels. */
+ u16 buffered_chan[NXP_SAR_ADC_NR_CHANNELS];
+
+ /* Buffer to be filled by the DMA. */
+ IIO_DECLARE_BUFFER_WITH_TS(u16, buffer, NXP_SAR_ADC_NR_CHANNELS);
+};
+
+struct nxp_sar_adc_data {
+ u32 vref_mV;
+ const char *model;
+};
+
+#define ADC_CHAN(_idx, _chan_type) { \
+ .type = (_chan_type), \
+ .indexed = 1, \
+ .channel = (_idx), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = (_idx), \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ }, \
+}
+
+static const struct iio_chan_spec nxp_sar_adc_iio_channels[] = {
+ ADC_CHAN(0, IIO_VOLTAGE),
+ ADC_CHAN(1, IIO_VOLTAGE),
+ ADC_CHAN(2, IIO_VOLTAGE),
+ ADC_CHAN(3, IIO_VOLTAGE),
+ ADC_CHAN(4, IIO_VOLTAGE),
+ ADC_CHAN(5, IIO_VOLTAGE),
+ ADC_CHAN(6, IIO_VOLTAGE),
+ ADC_CHAN(7, IIO_VOLTAGE),
+ /*
+ * The NXP SAR ADC documentation marks the channels 8 to 31 as
+ * "Reserved". Reflect the same in the driver in case new ADC
+ * variants comes with more channels.
+ */
+ IIO_CHAN_SOFT_TIMESTAMP(32),
+};
+
+static void nxp_sar_adc_irq_cfg(struct nxp_sar_adc *info, bool enable)
+{
+ if (enable)
+ writel(NXP_SAR_ADC_ISR_ECH, NXP_SAR_ADC_IMR(info->regs));
+ else
+ writel(0, NXP_SAR_ADC_IMR(info->regs));
+}
+
+static bool nxp_sar_adc_set_enabled(struct nxp_sar_adc *info, bool enable)
+{
+ u32 mcr;
+ bool pwdn;
+
+ mcr = readl(NXP_SAR_ADC_MCR(info->regs));
+
+ /*
+ * Get the current state and return it later. This is used for
+ * suspend/resume to get the power state
+ */
+ pwdn = FIELD_GET(NXP_SAR_ADC_MCR_PWDN, mcr);
+
+ /* When the enabled flag is not set, we set the power down bit */
+ FIELD_MODIFY(NXP_SAR_ADC_MCR_PWDN, &mcr, !enable);
+
+ writel(mcr, NXP_SAR_ADC_MCR(info->regs));
+
+ /*
+ * Ensure there are at least three cycles between the
+ * configuration of NCMR and the setting of NSTART.
+ */
+ if (enable)
+ ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk) * 3));
+
+ return pwdn;
+}
+
+static inline bool nxp_sar_adc_enable(struct nxp_sar_adc *info)
+{
+ return nxp_sar_adc_set_enabled(info, true);
+}
+
+static inline bool nxp_sar_adc_disable(struct nxp_sar_adc *info)
+{
+ return nxp_sar_adc_set_enabled(info, false);
+}
+
+static inline void nxp_sar_adc_calibration_start(void __iomem *base)
+{
+ u32 mcr = readl(NXP_SAR_ADC_MCR(base));
+
+ FIELD_MODIFY(NXP_SAR_ADC_MCR_CALSTART, &mcr, 0x1);
+
+ writel(mcr, NXP_SAR_ADC_MCR(base));
+}
+
+static inline int nxp_sar_adc_calibration_wait(void __iomem *base)
+{
+ u32 msr, ret;
+
+ ret = readl_poll_timeout(NXP_SAR_ADC_MSR(base), msr,
+ !FIELD_GET(NXP_SAR_ADC_MSR_CALBUSY, msr),
+ NXP_SAR_ADC_WAIT_US,
+ NXP_SAR_ADC_CAL_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ if (FIELD_GET(NXP_SAR_ADC_MSR_CALFAIL, msr)) {
+ /*
+ * If the calibration fails, the status register bit must be
+ * cleared.
+ */
+ FIELD_MODIFY(NXP_SAR_ADC_MSR_CALFAIL, &msr, 0x0);
+ writel(msr, NXP_SAR_ADC_MSR(base));
+
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int nxp_sar_adc_calibration(struct nxp_sar_adc *info)
+{
+ int ret;
+
+ /* Calibration works only if the ADC is powered up. */
+ nxp_sar_adc_enable(info);
+
+ /* The calibration operation starts. */
+ nxp_sar_adc_calibration_start(info->regs);
+
+ ret = nxp_sar_adc_calibration_wait(info->regs);
+
+ /*
+ * Calibration works only if the ADC is powered up. However
+ * the calibration is called from the probe function where the
+ * iio is not enabled, so we disable after the calibration.
+ */
+ nxp_sar_adc_disable(info);
+
+ return ret;
+}
+
+static void nxp_sar_adc_conversion_timing_set(struct nxp_sar_adc *info, u32 inpsamp)
+{
+ inpsamp = clamp(inpsamp, NXP_SAR_ADC_CTR_INPSAMP_MIN, NXP_SAR_ADC_CTR_INPSAMP_MAX);
+
+ writel(inpsamp, NXP_SAR_ADC_CTR0(info->regs));
+}
+
+static u32 nxp_sar_adc_conversion_timing_get(struct nxp_sar_adc *info)
+{
+ return readl(NXP_SAR_ADC_CTR0(info->regs));
+}
+
+static void nxp_sar_adc_read_notify(struct nxp_sar_adc *info)
+{
+ writel(NXP_SAR_ADC_CH_MASK, NXP_SAR_ADC_CEOCFR0(info->regs));
+ writel(NXP_SAR_ADC_CH_MASK, NXP_SAR_ADC_CEOCFR1(info->regs));
+}
+
+static int nxp_sar_adc_read_data(struct nxp_sar_adc *info, unsigned int chan)
+{
+ u32 ceocfr, cdr;
+
+ ceocfr = readl(NXP_SAR_ADC_CEOCFR0(info->regs));
+
+ /*
+ * FIELD_GET() can not be used here because EOC_CH is not constant.
+ * TODO: Switch to field_get() when it will be available.
+ */
+ if (!(NXP_SAR_ADC_EOC_CH(chan) & ceocfr))
+ return -EIO;
+
+ cdr = readl(NXP_SAR_ADC_CDR(info->regs, chan));
+ if (!(FIELD_GET(NXP_SAR_ADC_CDR_VALID, cdr)))
+ return -EIO;
+
+ return FIELD_GET(NXP_SAR_ADC_CDR_CDATA_MASK, cdr);
+}
+
+static void nxp_sar_adc_isr_buffer(struct iio_dev *indio_dev)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < info->channels_used; i++) {
+ ret = nxp_sar_adc_read_data(info, info->buffered_chan[i]);
+ if (ret < 0) {
+ nxp_sar_adc_read_notify(info);
+ return;
+ }
+
+ info->buffer[i] = ret;
+ }
+
+ nxp_sar_adc_read_notify(info);
+
+ iio_push_to_buffers_with_ts(indio_dev, info->buffer, sizeof(info->buffer),
+ iio_get_time_ns(indio_dev));
+
+ iio_trigger_notify_done(indio_dev->trig);
+}
+
+static void nxp_sar_adc_isr_read_raw(struct iio_dev *indio_dev)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ int ret;
+
+ ret = nxp_sar_adc_read_data(info, info->current_channel);
+ nxp_sar_adc_read_notify(info);
+ if (ret < 0)
+ return;
+
+ info->value = ret;
+ complete(&info->completion);
+}
+
+static irqreturn_t nxp_sar_adc_isr(int irq, void *dev_id)
+{
+ struct iio_dev *indio_dev = dev_id;
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ int isr;
+
+ isr = readl(NXP_SAR_ADC_ISR(info->regs));
+ if (!(FIELD_GET(NXP_SAR_ADC_ISR_ECH, isr)))
+ return IRQ_NONE;
+
+ if (iio_buffer_enabled(indio_dev))
+ nxp_sar_adc_isr_buffer(indio_dev);
+ else
+ nxp_sar_adc_isr_read_raw(indio_dev);
+
+ writel(NXP_SAR_ADC_ISR_ECH, NXP_SAR_ADC_ISR(info->regs));
+
+ return IRQ_HANDLED;
+}
+
+static void nxp_sar_adc_channels_disable(struct nxp_sar_adc *info, u32 mask)
+{
+ u32 ncmr, cimr;
+
+ ncmr = readl(NXP_SAR_ADC_NCMR0(info->regs));
+ cimr = readl(NXP_SAR_ADC_CIMR0(info->regs));
+
+ /* FIELD_MODIFY() can not be used because the mask is not constant */
+ ncmr &= ~mask;
+ cimr &= ~mask;
+
+ writel(ncmr, NXP_SAR_ADC_NCMR0(info->regs));
+ writel(cimr, NXP_SAR_ADC_CIMR0(info->regs));
+}
+
+static void nxp_sar_adc_channels_enable(struct nxp_sar_adc *info, u32 mask)
+{
+ u32 ncmr, cimr;
+
+ ncmr = readl(NXP_SAR_ADC_NCMR0(info->regs));
+ cimr = readl(NXP_SAR_ADC_CIMR0(info->regs));
+
+ ncmr |= mask;
+ cimr |= mask;
+
+ writel(ncmr, NXP_SAR_ADC_NCMR0(info->regs));
+ writel(cimr, NXP_SAR_ADC_CIMR0(info->regs));
+}
+
+static void nxp_sar_adc_dma_channels_enable(struct nxp_sar_adc *info, u32 mask)
+{
+ u32 dmar;
+
+ dmar = readl(NXP_SAR_ADC_DMAR0(info->regs));
+
+ dmar |= mask;
+
+ writel(dmar, NXP_SAR_ADC_DMAR0(info->regs));
+}
+
+static void nxp_sar_adc_dma_channels_disable(struct nxp_sar_adc *info, u32 mask)
+{
+ u32 dmar;
+
+ dmar = readl(NXP_SAR_ADC_DMAR0(info->regs));
+
+ dmar &= ~mask;
+
+ writel(dmar, NXP_SAR_ADC_DMAR0(info->regs));
+}
+
+static void nxp_sar_adc_dma_cfg(struct nxp_sar_adc *info, bool enable)
+{
+ u32 dmae;
+
+ dmae = readl(NXP_SAR_ADC_DMAE(info->regs));
+
+ FIELD_MODIFY(NXP_SAR_ADC_DMAE_DMAEN, &dmae, enable);
+
+ writel(dmae, NXP_SAR_ADC_DMAE(info->regs));
+}
+
+static void nxp_sar_adc_stop_conversion(struct nxp_sar_adc *info)
+{
+ u32 mcr;
+
+ mcr = readl(NXP_SAR_ADC_MCR(info->regs));
+
+ FIELD_MODIFY(NXP_SAR_ADC_MCR_NSTART, &mcr, 0x0);
+
+ writel(mcr, NXP_SAR_ADC_MCR(info->regs));
+
+ /*
+ * On disable, we have to wait for the transaction to finish.
+ * ADC does not abort the transaction if a chain conversion is
+ * in progress. Wait for the worst case scenario - 80 ADC clk
+ * cycles. The clock rate is 80MHz, this routine is called
+ * only when the capture finishes. The delay will be very
+ * short, usec-ish, which is acceptable in the atomic context.
+ */
+ ndelay(div64_u64(NSEC_PER_SEC, clk_get_rate(info->clk)) * 80);
+}
+
+static int nxp_sar_adc_start_conversion(struct nxp_sar_adc *info, bool raw)
+{
+ u32 mcr;
+
+ mcr = readl(NXP_SAR_ADC_MCR(info->regs));
+
+ FIELD_MODIFY(NXP_SAR_ADC_MCR_NSTART, &mcr, 0x1);
+ FIELD_MODIFY(NXP_SAR_ADC_MCR_MODE, &mcr, raw ? 0 : 1);
+
+ writel(mcr, NXP_SAR_ADC_MCR(info->regs));
+
+ return 0;
+}
+
+static int nxp_sar_adc_read_channel(struct nxp_sar_adc *info, int channel)
+{
+ int ret;
+
+ info->current_channel = channel;
+ nxp_sar_adc_channels_enable(info, BIT(channel));
+ nxp_sar_adc_irq_cfg(info, true);
+ nxp_sar_adc_enable(info);
+
+ reinit_completion(&info->completion);
+ ret = nxp_sar_adc_start_conversion(info, true);
+ if (ret < 0)
+ goto out_disable;
+
+ if (!wait_for_completion_interruptible_timeout(&info->completion,
+ NXP_SAR_ADC_CONV_TIMEOUT))
+ ret = -ETIMEDOUT;
+
+ nxp_sar_adc_stop_conversion(info);
+
+out_disable:
+ nxp_sar_adc_channels_disable(info, BIT(channel));
+ nxp_sar_adc_irq_cfg(info, false);
+ nxp_sar_adc_disable(info);
+
+ return ret;
+}
+
+static int nxp_sar_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ u32 inpsamp;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+
+ ret = nxp_sar_adc_read_channel(info, chan->channel);
+
+ iio_device_release_direct(indio_dev);
+
+ if (ret)
+ return ret;
+
+ *val = info->value;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = info->vref_mV;
+ *val2 = NXP_SAR_ADC_RESOLUTION;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ inpsamp = nxp_sar_adc_conversion_timing_get(info);
+ *val = clk_get_rate(info->clk) / (inpsamp + NXP_SAR_ADC_CONV_TIME);
+ return IIO_VAL_INT;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int nxp_sar_adc_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ u32 inpsamp;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ /*
+ * Configures the sample period duration in terms of the SAR
+ * controller clock. The minimum acceptable value is 8.
+ * Configuring it to a value lower than 8 sets the sample period
+ * to 8 cycles. We read the clock value and divide by the
+ * sampling timing which gives us the number of cycles expected.
+ * The value is 8-bit wide, consequently the max value is 0xFF.
+ */
+ inpsamp = clk_get_rate(info->clk) / val - NXP_SAR_ADC_CONV_TIME;
+ nxp_sar_adc_conversion_timing_set(info, inpsamp);
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static void nxp_sar_adc_dma_cb(void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ struct dma_tx_state state;
+ struct circ_buf *dma_buf;
+ struct device *dev_dma;
+ u32 *dma_samples;
+ s64 timestamp;
+ int idx, ret;
+
+ guard(spinlock_irqsave)(&info->lock);
+
+ dma_buf = &info->dma_buf;
+ dma_samples = (u32 *)dma_buf->buf;
+ dev_dma = info->dma_chan->device->dev;
+
+ /*
+ * DMA in some corner cases might have already be charged for
+ * the next transfer. Potentially there can be a race where
+ * the residue changes while the dma engine updates the
+ * buffer. That could be handled by using the
+ * callback_result() instead of callback() because the residue
+ * will be passed as a parameter to the function. However this
+ * new callback is pretty new and the backend does not update
+ * the residue. So let's stick to the version other drivers do
+ * which has proven running well in production since several
+ * years.
+ */
+ dmaengine_tx_status(info->dma_chan, info->cookie, &state);
+
+ dma_sync_single_for_cpu(dev_dma, info->rx_dma_buf,
+ NXP_SAR_ADC_DMA_BUFF_SZ, DMA_FROM_DEVICE);
+
+ /* Current head position. */
+ dma_buf->head = (NXP_SAR_ADC_DMA_BUFF_SZ - state.residue) /
+ NXP_SAR_ADC_DMA_SAMPLE_SZ;
+
+ /* If everything was transferred, avoid an off by one error. */
+ if (!state.residue)
+ dma_buf->head--;
+
+ /* Something went wrong and nothing transferred. */
+ if (state.residue != NXP_SAR_ADC_DMA_BUFF_SZ) {
+ /* Make sure that head is multiple of info->channels_used. */
+ dma_buf->head -= dma_buf->head % info->channels_used;
+
+ /*
+ * dma_buf->tail != dma_buf->head condition will become false
+ * because dma_buf->tail will be incremented with 1.
+ */
+ while (dma_buf->tail != dma_buf->head) {
+ idx = dma_buf->tail % info->channels_used;
+ info->buffer[idx] = dma_samples[dma_buf->tail];
+ dma_buf->tail = (dma_buf->tail + 1) % NXP_SAR_ADC_DMA_SAMPLE_CNT;
+ if (idx != info->channels_used - 1)
+ continue;
+
+ /*
+ * iio_push_to_buffers_with_ts() should not be
+ * called with dma_samples as parameter. The samples
+ * will be smashed if timestamp is enabled.
+ */
+ timestamp = iio_get_time_ns(indio_dev);
+ ret = iio_push_to_buffers_with_ts(indio_dev, info->buffer,
+ sizeof(info->buffer),
+ timestamp);
+ if (ret < 0 && ret != -EBUSY)
+ dev_err_ratelimited(&indio_dev->dev,
+ "failed to push iio buffer: %d",
+ ret);
+ }
+
+ dma_buf->tail = dma_buf->head;
+ }
+
+ dma_sync_single_for_device(dev_dma, info->rx_dma_buf,
+ NXP_SAR_ADC_DMA_BUFF_SZ, DMA_FROM_DEVICE);
+}
+
+static int nxp_sar_adc_start_cyclic_dma(struct iio_dev *indio_dev)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ struct dma_slave_config config;
+ struct dma_async_tx_descriptor *desc;
+ int ret;
+
+ info->dma_buf.head = 0;
+ info->dma_buf.tail = 0;
+
+ config.direction = DMA_DEV_TO_MEM;
+ config.src_addr_width = NXP_SAR_ADC_DMA_SAMPLE_SZ;
+ config.src_addr = NXP_SAR_ADC_CDR(info->regs_phys, info->buffered_chan[0]);
+ config.src_port_window_size = info->channels_used;
+ config.src_maxburst = info->channels_used;
+ ret = dmaengine_slave_config(info->dma_chan, &config);
+ if (ret < 0)
+ return ret;
+
+ desc = dmaengine_prep_dma_cyclic(info->dma_chan,
+ info->rx_dma_buf,
+ NXP_SAR_ADC_DMA_BUFF_SZ,
+ NXP_SAR_ADC_DMA_BUFF_SZ / 2,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+ if (!desc)
+ return -EINVAL;
+
+ desc->callback = nxp_sar_adc_dma_cb;
+ desc->callback_param = indio_dev;
+ info->cookie = dmaengine_submit(desc);
+ ret = dma_submit_error(info->cookie);
+ if (ret) {
+ dmaengine_terminate_async(info->dma_chan);
+ return ret;
+ }
+
+ dma_async_issue_pending(info->dma_chan);
+
+ return 0;
+}
+
+static void nxp_sar_adc_buffer_software_do_predisable(struct iio_dev *indio_dev)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+
+ /*
+ * The ADC DMAEN bit should be cleared before DMA transaction
+ * is canceled.
+ */
+ nxp_sar_adc_stop_conversion(info);
+ dmaengine_terminate_sync(info->dma_chan);
+ nxp_sar_adc_dma_cfg(info, false);
+ nxp_sar_adc_dma_channels_disable(info, *indio_dev->active_scan_mask);
+
+ dma_release_channel(info->dma_chan);
+}
+
+static int nxp_sar_adc_buffer_software_do_postenable(struct iio_dev *indio_dev)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ int ret;
+
+ nxp_sar_adc_dma_channels_enable(info, *indio_dev->active_scan_mask);
+
+ nxp_sar_adc_dma_cfg(info, true);
+
+ ret = nxp_sar_adc_start_cyclic_dma(indio_dev);
+ if (ret)
+ goto out_dma_channels_disable;
+
+ ret = nxp_sar_adc_start_conversion(info, false);
+ if (ret)
+ goto out_stop_cyclic_dma;
+
+ return 0;
+
+out_stop_cyclic_dma:
+ dmaengine_terminate_sync(info->dma_chan);
+
+out_dma_channels_disable:
+ nxp_sar_adc_dma_cfg(info, false);
+ nxp_sar_adc_dma_channels_disable(info, *indio_dev->active_scan_mask);
+
+ return ret;
+}
+
+static void nxp_sar_adc_buffer_trigger_do_predisable(struct iio_dev *indio_dev)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+
+ nxp_sar_adc_irq_cfg(info, false);
+}
+
+static int nxp_sar_adc_buffer_trigger_do_postenable(struct iio_dev *indio_dev)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+
+ nxp_sar_adc_irq_cfg(info, true);
+
+ return 0;
+}
+
+static int nxp_sar_adc_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ int current_mode = iio_device_get_current_mode(indio_dev);
+ unsigned long channel;
+ int ret;
+
+ info->dma_chan = dma_request_chan(indio_dev->dev.parent, "rx");
+ if (IS_ERR(info->dma_chan))
+ return PTR_ERR(info->dma_chan);
+
+ info->channels_used = 0;
+
+ /*
+ * The SAR-ADC has two groups of channels.
+ *
+ * - Group #0:
+ * * bit 0-7 : channel 0 -> channel 7
+ * * bit 8-31 : reserved
+ *
+ * - Group #32:
+ * * bit 0-7 : Internal
+ * * bit 8-31 : reserved
+ *
+ * The 8 channels from group #0 are used in this driver for
+ * ADC as described when declaring the IIO device and the
+ * mapping is the same. That means the active_scan_mask can be
+ * used directly to write the channel interrupt mask.
+ */
+ nxp_sar_adc_channels_enable(info, *indio_dev->active_scan_mask);
+
+ for_each_set_bit(channel, indio_dev->active_scan_mask, NXP_SAR_ADC_NR_CHANNELS)
+ info->buffered_chan[info->channels_used++] = channel;
+
+ nxp_sar_adc_enable(info);
+
+ if (current_mode == INDIO_BUFFER_SOFTWARE)
+ ret = nxp_sar_adc_buffer_software_do_postenable(indio_dev);
+ else
+ ret = nxp_sar_adc_buffer_trigger_do_postenable(indio_dev);
+ if (ret)
+ goto out_postenable;
+
+ return 0;
+
+out_postenable:
+ nxp_sar_adc_disable(info);
+ nxp_sar_adc_channels_disable(info, *indio_dev->active_scan_mask);
+
+ return ret;
+}
+
+static int nxp_sar_adc_buffer_predisable(struct iio_dev *indio_dev)
+{
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ int currentmode = iio_device_get_current_mode(indio_dev);
+
+ if (currentmode == INDIO_BUFFER_SOFTWARE)
+ nxp_sar_adc_buffer_software_do_predisable(indio_dev);
+ else
+ nxp_sar_adc_buffer_trigger_do_predisable(indio_dev);
+
+ nxp_sar_adc_disable(info);
+
+ nxp_sar_adc_channels_disable(info, *indio_dev->active_scan_mask);
+
+ return 0;
+}
+
+static irqreturn_t nxp_sar_adc_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct nxp_sar_adc *info = iio_priv(indio_dev);
+ int ret;
+
+ ret = nxp_sar_adc_start_conversion(info, true);
+ if (ret < 0)
+ dev_dbg(&indio_dev->dev, "Failed to start conversion\n");
+
+ return IRQ_HANDLED;
+}
+
+static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
+ .postenable = nxp_sar_adc_buffer_postenable,
+ .predisable = nxp_sar_adc_buffer_predisable,
+};
+
+static const struct iio_info nxp_sar_adc_iio_info = {
+ .read_raw = nxp_sar_adc_read_raw,
+ .write_raw = nxp_sar_adc_write_raw,
+};
+
+static int nxp_sar_adc_dma_probe(struct device *dev, struct nxp_sar_adc *info)
+{
+ u8 *rx_buf;
+
+ rx_buf = dmam_alloc_coherent(dev, NXP_SAR_ADC_DMA_BUFF_SZ,
+ &info->rx_dma_buf, GFP_KERNEL);
+ if (!rx_buf)
+ return -ENOMEM;
+
+ info->dma_buf.buf = rx_buf;
+
+ return 0;
+}
+
+/*
+ * The documentation describes the reset values for the registers.
+ * However some registers do not have these values after a reset. It
+ * is not a desirable situation. In some other SoC family
+ * documentation NXP recommends not assuming the default values are
+ * set and to initialize the registers conforming to the documentation
+ * reset information to prevent this situation. Assume the same rule
+ * applies here as there is a discrepancy between what is read from
+ * the registers at reset time and the documentation.
+ */
+static void nxp_sar_adc_set_default_values(struct nxp_sar_adc *info)
+{
+ writel(0x00003901, NXP_SAR_ADC_MCR(info->regs));
+ writel(0x00000001, NXP_SAR_ADC_MSR(info->regs));
+ writel(0x00000014, NXP_SAR_ADC_CTR0(info->regs));
+ writel(0x00000014, NXP_SAR_ADC_CTR1(info->regs));
+ writel(0x00000000, NXP_SAR_ADC_CIMR0(info->regs));
+ writel(0x00000000, NXP_SAR_ADC_CIMR1(info->regs));
+ writel(0x00000000, NXP_SAR_ADC_NCMR0(info->regs));
+ writel(0x00000000, NXP_SAR_ADC_NCMR1(info->regs));
+}
+
+static int nxp_sar_adc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ const struct nxp_sar_adc_data *data = device_get_match_data(dev);
+ struct nxp_sar_adc *info;
+ struct iio_dev *indio_dev;
+ struct resource *mem;
+ int irq, ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+ info->vref_mV = data->vref_mV;
+ spin_lock_init(&info->lock);
+ info->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);
+ if (IS_ERR(info->regs))
+ return dev_err_probe(dev, PTR_ERR(info->regs),
+ "Failed to get and remap resource");
+
+ info->regs_phys = mem->start;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(dev, irq, nxp_sar_adc_isr, 0, dev_name(dev),
+ indio_dev);
+ if (ret < 0)
+ return ret;
+
+ info->clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR(info->clk))
+ return dev_err_probe(dev, PTR_ERR(info->clk),
+ "Failed to get the clock\n");
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ init_completion(&info->completion);
+
+ indio_dev->name = data->model;
+ indio_dev->info = &nxp_sar_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE;
+ indio_dev->channels = nxp_sar_adc_iio_channels;
+ indio_dev->num_channels = ARRAY_SIZE(nxp_sar_adc_iio_channels);
+
+ nxp_sar_adc_set_default_values(info);
+
+ ret = nxp_sar_adc_calibration(info);
+ if (ret)
+ dev_err_probe(dev, ret, "Calibration failed\n");
+
+ ret = nxp_sar_adc_dma_probe(dev, info);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to initialize the DMA\n");
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ &iio_pollfunc_store_time,
+ &nxp_sar_adc_trigger_handler,
+ &iio_triggered_buffer_setup_ops);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Couldn't initialise the buffer\n");
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Couldn't register the device\n");
+
+ return 0;
+}
+
+static int nxp_sar_adc_suspend(struct device *dev)
+{
+ struct nxp_sar_adc *info = iio_priv(dev_get_drvdata(dev));
+
+ info->pwdn = nxp_sar_adc_disable(info);
+ info->inpsamp = nxp_sar_adc_conversion_timing_get(info);
+
+ clk_disable_unprepare(info->clk);
+
+ return 0;
+}
+
+static int nxp_sar_adc_resume(struct device *dev)
+{
+ struct nxp_sar_adc *info = iio_priv(dev_get_drvdata(dev));
+ int ret;
+
+ ret = clk_prepare_enable(info->clk);
+ if (ret)
+ return ret;
+
+ nxp_sar_adc_conversion_timing_set(info, info->inpsamp);
+
+ if (!info->pwdn)
+ nxp_sar_adc_enable(info);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(nxp_sar_adc_pm_ops, nxp_sar_adc_suspend,
+ nxp_sar_adc_resume);
+
+static const struct nxp_sar_adc_data s32g2_sar_adc_data = {
+ .vref_mV = 1800,
+ .model = "s32g2-sar-adc",
+};
+
+static const struct of_device_id nxp_sar_adc_match[] = {
+ { .compatible = "nxp,s32g2-sar-adc", .data = &s32g2_sar_adc_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, nxp_sar_adc_match);
+
+static struct platform_driver nxp_sar_adc_driver = {
+ .probe = nxp_sar_adc_probe,
+ .driver = {
+ .name = "nxp-sar-adc",
+ .of_match_table = nxp_sar_adc_match,
+ .pm = pm_sleep_ptr(&nxp_sar_adc_pm_ops),
+ },
+};
+module_platform_driver(nxp_sar_adc_driver);
+
+MODULE_AUTHOR("NXP");
+MODULE_DESCRIPTION("NXP SAR-ADC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/qcom-spmi-rradc.c b/drivers/iio/adc/qcom-spmi-rradc.c
index b245416bae12..8e75665204d1 100644
--- a/drivers/iio/adc/qcom-spmi-rradc.c
+++ b/drivers/iio/adc/qcom-spmi-rradc.c
@@ -934,20 +934,15 @@ static int rradc_probe(struct platform_device *pdev)
chip = iio_priv(indio_dev);
chip->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!chip->regmap) {
- dev_err(dev, "Couldn't get parent's regmap\n");
- return -EINVAL;
- }
+ if (!chip->regmap)
+ return dev_err_probe(dev, -EINVAL, "Couldn't get parent's regmap\n");
chip->dev = dev;
mutex_init(&chip->conversion_lock);
ret = device_property_read_u32(dev, "reg", &chip->base);
- if (ret < 0) {
- dev_err(chip->dev, "Couldn't find reg address, ret = %d\n",
- ret);
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Couldn't find reg address\n");
batt_id_delay = -1;
ret = device_property_read_u32(dev, "qcom,batt-id-delay-ms",
@@ -975,10 +970,9 @@ static int rradc_probe(struct platform_device *pdev)
/* Get the PMIC revision, we need it to handle some varying coefficients */
chip->pmic = qcom_pmic_get(chip->dev);
- if (IS_ERR(chip->pmic)) {
- dev_err(chip->dev, "Unable to get reference to PMIC device\n");
- return PTR_ERR(chip->pmic);
- }
+ if (IS_ERR(chip->pmic))
+ return dev_err_probe(dev, PTR_ERR(chip->pmic),
+ "Unable to get reference to PMIC device\n");
switch (chip->pmic->subtype) {
case PMI8998_SUBTYPE:
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c
index 6721da0ed7bb..0f0bf2906af0 100644
--- a/drivers/iio/adc/rockchip_saradc.c
+++ b/drivers/iio/adc/rockchip_saradc.c
@@ -456,6 +456,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
{
const struct rockchip_saradc_data *match_data;
struct rockchip_saradc *info = NULL;
+ struct device *dev = &pdev->dev;
struct device_node *np = pdev->dev.of_node;
struct iio_dev *indio_dev = NULL;
int ret;
@@ -464,23 +465,21 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
if (!np)
return -ENODEV;
- indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*info));
if (!indio_dev)
return -ENOMEM;
info = iio_priv(indio_dev);
- match_data = of_device_get_match_data(&pdev->dev);
+ match_data = of_device_get_match_data(dev);
if (!match_data)
- return dev_err_probe(&pdev->dev, -ENODEV,
- "failed to match device\n");
+ return dev_err_probe(dev, -ENODEV, "failed to match device\n");
info->data = match_data;
/* Sanity check for possible later IP variants with more channels */
if (info->data->num_channels > SARADC_MAX_CHANNELS)
- return dev_err_probe(&pdev->dev, -EINVAL,
- "max channels exceeded");
+ return dev_err_probe(dev, -EINVAL, "max channels exceeded");
info->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(info->regs))
@@ -490,12 +489,10 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
* The reset should be an optional property, as it should work
* with old devicetrees as well
*/
- info->reset = devm_reset_control_get_optional_exclusive(&pdev->dev,
- "saradc-apb");
- if (IS_ERR(info->reset)) {
- ret = PTR_ERR(info->reset);
- return dev_err_probe(&pdev->dev, ret, "failed to get saradc-apb\n");
- }
+ info->reset = devm_reset_control_get_optional_exclusive(dev, "saradc-apb");
+ if (IS_ERR(info->reset))
+ return dev_err_probe(dev, PTR_ERR(info->reset),
+ "failed to get saradc-apb\n");
init_completion(&info->completion);
@@ -503,16 +500,14 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr,
+ ret = devm_request_irq(dev, irq, rockchip_saradc_isr,
0, dev_name(&pdev->dev), info);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed requesting irq %d\n", irq);
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed requesting irq %d\n", irq);
- info->vref = devm_regulator_get(&pdev->dev, "vref");
+ info->vref = devm_regulator_get(dev, "vref");
if (IS_ERR(info->vref))
- return dev_err_probe(&pdev->dev, PTR_ERR(info->vref),
+ return dev_err_probe(dev, PTR_ERR(info->vref),
"failed to get regulator\n");
if (info->reset)
@@ -520,11 +515,9 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
ret = regulator_enable(info->vref);
if (ret < 0)
- return dev_err_probe(&pdev->dev, ret,
- "failed to enable vref regulator\n");
+ return dev_err_probe(dev, ret, "failed to enable vref regulator\n");
- ret = devm_add_action_or_reset(&pdev->dev,
- rockchip_saradc_regulator_disable, info);
+ ret = devm_add_action_or_reset(dev, rockchip_saradc_regulator_disable, info);
if (ret)
return ret;
@@ -534,14 +527,13 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
info->uv_vref = ret;
- info->pclk = devm_clk_get_enabled(&pdev->dev, "apb_pclk");
+ info->pclk = devm_clk_get_enabled(dev, "apb_pclk");
if (IS_ERR(info->pclk))
- return dev_err_probe(&pdev->dev, PTR_ERR(info->pclk),
- "failed to get pclk\n");
+ return dev_err_probe(dev, PTR_ERR(info->pclk), "failed to get pclk\n");
- info->clk = devm_clk_get_enabled(&pdev->dev, "saradc");
+ info->clk = devm_clk_get_enabled(dev, "saradc");
if (IS_ERR(info->clk))
- return dev_err_probe(&pdev->dev, PTR_ERR(info->clk),
+ return dev_err_probe(dev, PTR_ERR(info->clk),
"failed to get adc clock\n");
/*
* Use a default value for the converter clock.
@@ -549,18 +541,17 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
*/
ret = clk_set_rate(info->clk, info->data->clk_rate);
if (ret < 0)
- return dev_err_probe(&pdev->dev, ret,
- "failed to set adc clk rate\n");
+ return dev_err_probe(dev, ret, "failed to set adc clk rate\n");
platform_set_drvdata(pdev, indio_dev);
- indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->name = dev_name(dev);
indio_dev->info = &rockchip_saradc_iio_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = info->data->channels;
indio_dev->num_channels = info->data->num_channels;
- ret = devm_iio_triggered_buffer_setup(&indio_dev->dev, indio_dev, NULL,
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL,
rockchip_saradc_trigger_handler,
NULL);
if (ret)
@@ -571,7 +562,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = devm_add_action_or_reset(&pdev->dev,
+ ret = devm_add_action_or_reset(dev,
rockchip_saradc_regulator_unreg_notifier,
info);
if (ret)
@@ -579,7 +570,7 @@ static int rockchip_saradc_probe(struct platform_device *pdev)
mutex_init(&info->lock);
- return devm_iio_device_register(&pdev->dev, indio_dev);
+ return devm_iio_device_register(dev, indio_dev);
}
static int rockchip_saradc_suspend(struct device *dev)
diff --git a/drivers/iio/adc/sc27xx_adc.c b/drivers/iio/adc/sc27xx_adc.c
index 2535c2c3e60b..6209499c5c37 100644
--- a/drivers/iio/adc/sc27xx_adc.c
+++ b/drivers/iio/adc/sc27xx_adc.c
@@ -867,10 +867,8 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
int ret;
pdata = of_device_get_match_data(dev);
- if (!pdata) {
- dev_err(dev, "No matching driver data found\n");
- return -EINVAL;
- }
+ if (!pdata)
+ return dev_err_probe(dev, -EINVAL, "No matching driver data found\n");
indio_dev = devm_iio_device_alloc(dev, sizeof(*sc27xx_data));
if (!indio_dev)
@@ -879,56 +877,43 @@ static int sc27xx_adc_probe(struct platform_device *pdev)
sc27xx_data = iio_priv(indio_dev);
sc27xx_data->regmap = dev_get_regmap(dev->parent, NULL);
- if (!sc27xx_data->regmap) {
- dev_err(dev, "failed to get ADC regmap\n");
- return -ENODEV;
- }
+ if (!sc27xx_data->regmap)
+ return dev_err_probe(dev, -ENODEV, "failed to get ADC regmap\n");
ret = of_property_read_u32(np, "reg", &sc27xx_data->base);
- if (ret) {
- dev_err(dev, "failed to get ADC base address\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to get ADC base address\n");
sc27xx_data->irq = platform_get_irq(pdev, 0);
if (sc27xx_data->irq < 0)
return sc27xx_data->irq;
ret = of_hwspin_lock_get_id(np, 0);
- if (ret < 0) {
- dev_err(dev, "failed to get hwspinlock id\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to get hwspinlock id\n");
sc27xx_data->hwlock = devm_hwspin_lock_request_specific(dev, ret);
- if (!sc27xx_data->hwlock) {
- dev_err(dev, "failed to request hwspinlock\n");
- return -ENXIO;
- }
+ if (!sc27xx_data->hwlock)
+ return dev_err_probe(dev, -ENXIO, "failed to request hwspinlock\n");
sc27xx_data->dev = dev;
if (pdata->set_volref) {
sc27xx_data->volref = devm_regulator_get(dev, "vref");
- if (IS_ERR(sc27xx_data->volref)) {
- ret = PTR_ERR(sc27xx_data->volref);
- return dev_err_probe(dev, ret, "failed to get ADC volref\n");
- }
+ if (IS_ERR(sc27xx_data->volref))
+ return dev_err_probe(dev, PTR_ERR(sc27xx_data->volref),
+ "failed to get ADC volref\n");
}
sc27xx_data->var_data = pdata;
sc27xx_data->var_data->init_scale(sc27xx_data);
ret = sc27xx_adc_enable(sc27xx_data);
- if (ret) {
- dev_err(dev, "failed to enable ADC module\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to enable ADC module\n");
ret = devm_add_action_or_reset(dev, sc27xx_adc_disable, sc27xx_data);
- if (ret) {
- dev_err(dev, "failed to add ADC disable action\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to add ADC disable action\n");
indio_dev->name = dev_name(dev);
indio_dev->modes = INDIO_DIRECT_MODE;
diff --git a/drivers/iio/adc/ti-ads1018.c b/drivers/iio/adc/ti-ads1018.c
new file mode 100644
index 000000000000..6246b3cab71f
--- /dev/null
+++ b/drivers/iio/adc/ti-ads1018.c
@@ -0,0 +1,739 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Texas Instruments ADS1018 ADC driver
+ *
+ * Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/dev_printk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/math.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <asm/byteorder.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>
+
+#define ADS1018_CFG_OS_TRIG BIT(15)
+#define ADS1018_CFG_TS_MODE_EN BIT(4)
+#define ADS1018_CFG_PULL_UP BIT(3)
+#define ADS1018_CFG_NOP BIT(1)
+#define ADS1018_CFG_VALID (ADS1018_CFG_PULL_UP | ADS1018_CFG_NOP)
+
+#define ADS1018_CFG_MUX_MASK GENMASK(14, 12)
+
+#define ADS1018_CFG_PGA_MASK GENMASK(11, 9)
+#define ADS1018_PGA_DEFAULT 2
+
+#define ADS1018_CFG_MODE_MASK BIT(8)
+#define ADS1018_MODE_CONTINUOUS 0
+#define ADS1018_MODE_ONESHOT 1
+
+#define ADS1018_CFG_DRATE_MASK GENMASK(7, 5)
+#define ADS1018_DRATE_DEFAULT 4
+
+#define ADS1018_NUM_PGA_MODES 6
+#define ADS1018_CHANNELS_MAX 10
+
+struct ads1018_chan_data {
+ u8 pga_mode;
+ u8 data_rate_mode;
+};
+
+struct ads1018_chip_info {
+ const char *name;
+ const struct iio_chan_spec *channels;
+ unsigned long num_channels;
+
+ /* IIO_VAL_INT */
+ const u32 *data_rate_mode_to_hz;
+ unsigned long num_data_rate_mode_to_hz;
+
+ /*
+ * Let `res` be the chip's resolution and `fsr` (millivolts) be the
+ * full-scale range corresponding to the PGA mode given by the array
+ * index. Then, the gain is calculated using the following formula:
+ *
+ * gain = |fsr| / 2^(res - 1)
+ *
+ * This value then has to be represented in IIO_VAL_INT_PLUS_NANO
+ * format. For example if:
+ *
+ * gain = 6144 / 2^(16 - 1) = 0.1875
+ *
+ * ...then the formatted value is:
+ *
+ * { 0, 187500000 }
+ */
+ const u32 pga_mode_to_gain[ADS1018_NUM_PGA_MODES][2];
+
+ /* IIO_VAL_INT_PLUS_MICRO */
+ const u32 temp_scale[2];
+};
+
+struct ads1018 {
+ struct spi_device *spi;
+ struct iio_trigger *indio_trig;
+
+ struct gpio_desc *drdy_gpiod;
+ int drdy_irq;
+
+ struct ads1018_chan_data chan_data[ADS1018_CHANNELS_MAX];
+ const struct ads1018_chip_info *chip_info;
+
+ struct spi_message msg_read;
+ struct spi_transfer xfer;
+ __be16 tx_buf[2] __aligned(IIO_DMA_MINALIGN);
+ __be16 rx_buf[2];
+};
+
+#define ADS1018_VOLT_DIFF_CHAN(_index, _chan, _chan2, _realbits) { \
+ .type = IIO_VOLTAGE, \
+ .channel = _chan, \
+ .channel2 = _chan2, \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = _realbits, \
+ .storagebits = 16, \
+ .shift = 16 - _realbits, \
+ .endianness = IIO_BE, \
+ }, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .indexed = true, \
+ .differential = true, \
+}
+
+#define ADS1018_VOLT_CHAN(_index, _chan, _realbits) { \
+ .type = IIO_VOLTAGE, \
+ .channel = _chan, \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = _realbits, \
+ .storagebits = 16, \
+ .shift = 16 - _realbits, \
+ .endianness = IIO_BE, \
+ }, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_type_available = BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .indexed = true, \
+}
+
+#define ADS1018_TEMP_CHAN(_index, _realbits) { \
+ .type = IIO_TEMP, \
+ .scan_index = _index, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = _realbits, \
+ .storagebits = 16, \
+ .shift = 16 - _realbits, \
+ .endianness = IIO_BE, \
+ }, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+}
+
+static const struct iio_chan_spec ads1118_iio_channels[] = {
+ ADS1018_VOLT_DIFF_CHAN(0, 0, 1, 16),
+ ADS1018_VOLT_DIFF_CHAN(1, 0, 3, 16),
+ ADS1018_VOLT_DIFF_CHAN(2, 1, 3, 16),
+ ADS1018_VOLT_DIFF_CHAN(3, 2, 3, 16),
+ ADS1018_VOLT_CHAN(4, 0, 16),
+ ADS1018_VOLT_CHAN(5, 1, 16),
+ ADS1018_VOLT_CHAN(6, 2, 16),
+ ADS1018_VOLT_CHAN(7, 3, 16),
+ ADS1018_TEMP_CHAN(8, 14),
+ IIO_CHAN_SOFT_TIMESTAMP(9),
+};
+
+static const struct iio_chan_spec ads1018_iio_channels[] = {
+ ADS1018_VOLT_DIFF_CHAN(0, 0, 1, 12),
+ ADS1018_VOLT_DIFF_CHAN(1, 0, 3, 12),
+ ADS1018_VOLT_DIFF_CHAN(2, 1, 3, 12),
+ ADS1018_VOLT_DIFF_CHAN(3, 2, 3, 12),
+ ADS1018_VOLT_CHAN(4, 0, 12),
+ ADS1018_VOLT_CHAN(5, 1, 12),
+ ADS1018_VOLT_CHAN(6, 2, 12),
+ ADS1018_VOLT_CHAN(7, 3, 12),
+ ADS1018_TEMP_CHAN(8, 12),
+ IIO_CHAN_SOFT_TIMESTAMP(9),
+};
+
+/**
+ * ads1018_calc_delay - Calculates a suitable delay for a single-shot reading
+ * @hz: Sampling frequency
+ *
+ * Calculates an appropriate delay for a single shot reading given a sampling
+ * frequency.
+ *
+ * Return: Delay in microseconds (Always greater than 0).
+ */
+static u32 ads1018_calc_delay(unsigned int hz)
+{
+ /*
+ * Calculate the worst-case sampling rate by subtracting 10% error
+ * specified in the datasheet...
+ */
+ hz -= DIV_ROUND_UP(hz, 10);
+
+ /* ...Then calculate time per sample in microseconds. */
+ return DIV_ROUND_UP(HZ_PER_MHZ, hz);
+}
+
+/**
+ * ads1018_spi_read_exclusive - Reads a conversion value from the device
+ * @ads1018: Device data
+ * @cnv: ADC Conversion value (optional)
+ * @hold_cs: Keep CS line asserted after the SPI transfer
+ *
+ * Reads the most recent ADC conversion value, without updating the
+ * device's configuration.
+ *
+ * Context: Expects SPI bus *exclusive* use.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int ads1018_spi_read_exclusive(struct ads1018 *ads1018, __be16 *cnv,
+ bool hold_cs)
+{
+ int ret;
+
+ ads1018->xfer.cs_change = hold_cs;
+
+ ret = spi_sync_locked(ads1018->spi, &ads1018->msg_read);
+ if (ret)
+ return ret;
+
+ if (cnv)
+ *cnv = ads1018->rx_buf[0];
+
+ return 0;
+}
+
+/**
+ * ads1018_single_shot - Performs a one-shot reading sequence
+ * @ads1018: Device data
+ * @chan: Channel specification
+ * @cnv: Conversion value
+ *
+ * Writes a new configuration, waits an appropriate delay, then reads the most
+ * recent conversion.
+ *
+ * Context: Expects iio_device_claim_direct() is held.
+ *
+ * Return: 0 on success, negative errno on error.
+ */
+static int ads1018_single_shot(struct ads1018 *ads1018,
+ struct iio_chan_spec const *chan, u16 *cnv)
+{
+ u8 max_drate_mode = ads1018->chip_info->num_data_rate_mode_to_hz - 1;
+ u8 drate = ads1018->chip_info->data_rate_mode_to_hz[max_drate_mode];
+ u8 pga_mode = ads1018->chan_data[chan->scan_index].pga_mode;
+ struct spi_transfer xfer[2] = {
+ {
+ .tx_buf = ads1018->tx_buf,
+ .len = sizeof(ads1018->tx_buf[0]),
+ .delay = {
+ .value = ads1018_calc_delay(drate),
+ .unit = SPI_DELAY_UNIT_USECS,
+ },
+ .cs_change = 1, /* 16-bit mode requires CS de-assert */
+ },
+ {
+ .rx_buf = ads1018->rx_buf,
+ .len = sizeof(ads1018->rx_buf[0]),
+ },
+ };
+ u16 cfg;
+ int ret;
+
+ cfg = ADS1018_CFG_VALID | ADS1018_CFG_OS_TRIG;
+ cfg |= FIELD_PREP(ADS1018_CFG_MUX_MASK, chan->scan_index);
+ cfg |= FIELD_PREP(ADS1018_CFG_PGA_MASK, pga_mode);
+ cfg |= FIELD_PREP(ADS1018_CFG_MODE_MASK, ADS1018_MODE_ONESHOT);
+ cfg |= FIELD_PREP(ADS1018_CFG_DRATE_MASK, max_drate_mode);
+
+ if (chan->type == IIO_TEMP)
+ cfg |= ADS1018_CFG_TS_MODE_EN;
+
+ ads1018->tx_buf[0] = cpu_to_be16(cfg);
+ ret = spi_sync_transfer(ads1018->spi, xfer, ARRAY_SIZE(xfer));
+ if (ret)
+ return ret;
+
+ *cnv = be16_to_cpu(ads1018->rx_buf[0]);
+
+ return 0;
+}
+
+static int
+ads1018_read_raw_direct_mode(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2,
+ long mask)
+{
+ struct ads1018 *ads1018 = iio_priv(indio_dev);
+ const struct ads1018_chip_info *chip_info = ads1018->chip_info;
+ u8 addr = chan->scan_index;
+ u8 pga_mode, drate_mode;
+ u16 cnv;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = ads1018_single_shot(ads1018, chan, &cnv);
+ if (ret)
+ return ret;
+
+ cnv >>= chan->scan_type.shift;
+ *val = sign_extend32(cnv, chan->scan_type.realbits - 1);
+
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ pga_mode = ads1018->chan_data[addr].pga_mode;
+ *val = chip_info->pga_mode_to_gain[pga_mode][0];
+ *val2 = chip_info->pga_mode_to_gain[pga_mode][1];
+ return IIO_VAL_INT_PLUS_NANO;
+
+ case IIO_TEMP:
+ *val = chip_info->temp_scale[0];
+ *val2 = chip_info->temp_scale[1];
+ return IIO_VAL_INT_PLUS_MICRO;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ drate_mode = ads1018->chan_data[addr].data_rate_mode;
+ *val = chip_info->data_rate_mode_to_hz[drate_mode];
+ return IIO_VAL_INT;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+ads1018_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ads1018_read_raw_direct_mode(indio_dev, chan, val, val2, mask);
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int
+ads1018_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+ const int **vals, int *type, int *length, long mask)
+{
+ struct ads1018 *ads1018 = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ *type = IIO_VAL_INT_PLUS_NANO;
+ *vals = (const int *)ads1018->chip_info->pga_mode_to_gain;
+ *length = ADS1018_NUM_PGA_MODES * 2;
+ return IIO_AVAIL_LIST;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *type = IIO_VAL_INT;
+ *vals = ads1018->chip_info->data_rate_mode_to_hz;
+ *length = ads1018->chip_info->num_data_rate_mode_to_hz;
+ return IIO_AVAIL_LIST;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+ads1018_write_raw_direct_mode(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val, int val2,
+ long mask)
+{
+ struct ads1018 *ads1018 = iio_priv(indio_dev);
+ const struct ads1018_chip_info *info = ads1018->chip_info;
+ unsigned int i;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ for (i = 0; i < ADS1018_NUM_PGA_MODES; i++) {
+ if (val == info->pga_mode_to_gain[i][0] &&
+ val2 == info->pga_mode_to_gain[i][1])
+ break;
+ }
+ if (i == ADS1018_NUM_PGA_MODES)
+ return -EINVAL;
+
+ ads1018->chan_data[chan->scan_index].pga_mode = i;
+ return 0;
+
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ for (i = 0; i < info->num_data_rate_mode_to_hz; i++) {
+ if (val == info->data_rate_mode_to_hz[i])
+ break;
+ }
+ if (i == info->num_data_rate_mode_to_hz)
+ return -EINVAL;
+
+ ads1018->chan_data[chan->scan_index].data_rate_mode = i;
+ return 0;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int
+ads1018_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ int ret;
+
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ads1018_write_raw_direct_mode(indio_dev, chan, val, val2, mask);
+ iio_device_release_direct(indio_dev);
+
+ return ret;
+}
+
+static int
+ads1018_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, long mask)
+{
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+}
+
+static const struct iio_info ads1018_iio_info = {
+ .read_raw = ads1018_read_raw,
+ .read_avail = ads1018_read_avail,
+ .write_raw = ads1018_write_raw,
+ .write_raw_get_fmt = ads1018_write_raw_get_fmt,
+};
+
+static void ads1018_set_trigger_enable(struct ads1018 *ads1018)
+{
+ spi_bus_lock(ads1018->spi->controller);
+ ads1018_spi_read_exclusive(ads1018, NULL, true);
+ enable_irq(ads1018->drdy_irq);
+}
+
+static void ads1018_set_trigger_disable(struct ads1018 *ads1018)
+{
+ disable_irq(ads1018->drdy_irq);
+ ads1018_spi_read_exclusive(ads1018, NULL, false);
+ spi_bus_unlock(ads1018->spi->controller);
+}
+
+static int ads1018_set_trigger_state(struct iio_trigger *trig, bool state)
+{
+ struct ads1018 *ads1018 = iio_trigger_get_drvdata(trig);
+
+ /*
+ * We need to lock the SPI bus and tie CS low (hold_cs) to catch
+ * data-ready interrupts, otherwise the MISO line enters a Hi-Z state.
+ */
+
+ if (state)
+ ads1018_set_trigger_enable(ads1018);
+ else
+ ads1018_set_trigger_disable(ads1018);
+
+ return 0;
+}
+
+static const struct iio_trigger_ops ads1018_trigger_ops = {
+ .set_trigger_state = ads1018_set_trigger_state,
+ .validate_device = iio_trigger_validate_own_device,
+};
+
+static int ads1018_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct ads1018 *ads1018 = iio_priv(indio_dev);
+ const struct ads1018_chip_info *chip_info = ads1018->chip_info;
+ unsigned int pga, drate, addr;
+ u16 cfg;
+
+ addr = find_first_bit(indio_dev->active_scan_mask,
+ iio_get_masklength(indio_dev));
+ pga = ads1018->chan_data[addr].pga_mode;
+ drate = ads1018->chan_data[addr].data_rate_mode;
+
+ cfg = ADS1018_CFG_VALID;
+ cfg |= FIELD_PREP(ADS1018_CFG_MUX_MASK, addr);
+ cfg |= FIELD_PREP(ADS1018_CFG_PGA_MASK, pga);
+ cfg |= FIELD_PREP(ADS1018_CFG_MODE_MASK, ADS1018_MODE_CONTINUOUS);
+ cfg |= FIELD_PREP(ADS1018_CFG_DRATE_MASK, drate);
+
+ if (chip_info->channels[addr].type == IIO_TEMP)
+ cfg |= ADS1018_CFG_TS_MODE_EN;
+
+ ads1018->tx_buf[0] = cpu_to_be16(cfg);
+ ads1018->tx_buf[1] = 0;
+
+ return spi_write(ads1018->spi, ads1018->tx_buf, sizeof(ads1018->tx_buf));
+}
+
+static int ads1018_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ struct ads1018 *ads1018 = iio_priv(indio_dev);
+ u16 cfg;
+
+ cfg = ADS1018_CFG_VALID;
+ cfg |= FIELD_PREP(ADS1018_CFG_MODE_MASK, ADS1018_MODE_ONESHOT);
+
+ ads1018->tx_buf[0] = cpu_to_be16(cfg);
+ ads1018->tx_buf[1] = 0;
+
+ return spi_write(ads1018->spi, ads1018->tx_buf, sizeof(ads1018->tx_buf));
+}
+
+static const struct iio_buffer_setup_ops ads1018_buffer_ops = {
+ .preenable = ads1018_buffer_preenable,
+ .postdisable = ads1018_buffer_postdisable,
+ .validate_scan_mask = iio_validate_scan_mask_onehot,
+};
+
+static irqreturn_t ads1018_irq_handler(int irq, void *dev_id)
+{
+ struct ads1018 *ads1018 = dev_id;
+
+ /*
+ * We need to check if the "drdy" pin is actually active or if it's a
+ * pending interrupt triggered by the SPI transfer.
+ */
+ if (!gpiod_get_value(ads1018->drdy_gpiod))
+ return IRQ_HANDLED;
+
+ iio_trigger_poll(ads1018->indio_trig);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t ads1018_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct ads1018 *ads1018 = iio_priv(indio_dev);
+ struct {
+ __be16 conv;
+ aligned_s64 ts;
+ } scan = {};
+ int ret;
+
+ if (iio_trigger_using_own(indio_dev)) {
+ disable_irq(ads1018->drdy_irq);
+ ret = ads1018_spi_read_exclusive(ads1018, &scan.conv, true);
+ enable_irq(ads1018->drdy_irq);
+ } else {
+ ret = spi_read(ads1018->spi, ads1018->rx_buf, sizeof(ads1018->rx_buf));
+ scan.conv = ads1018->rx_buf[0];
+ }
+
+ if (!ret)
+ iio_push_to_buffers_with_ts(indio_dev, &scan, sizeof(scan),
+ pf->timestamp);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int ads1018_trigger_setup(struct iio_dev *indio_dev)
+{
+ struct ads1018 *ads1018 = iio_priv(indio_dev);
+ struct spi_device *spi = ads1018->spi;
+ struct device *dev = &spi->dev;
+ const char *con_id = "drdy";
+ int ret;
+
+ ads1018->drdy_gpiod = devm_gpiod_get_optional(dev, con_id, GPIOD_IN);
+ if (IS_ERR(ads1018->drdy_gpiod))
+ return dev_err_probe(dev, PTR_ERR(ads1018->drdy_gpiod),
+ "Failed to get %s GPIO.\n", con_id);
+
+ /* First try to get IRQ from SPI core, then from GPIO */
+ if (spi->irq > 0)
+ ads1018->drdy_irq = spi->irq;
+ else if (ads1018->drdy_gpiod)
+ ads1018->drdy_irq = gpiod_to_irq(ads1018->drdy_gpiod);
+ if (ads1018->drdy_irq < 0)
+ return dev_err_probe(dev, ads1018->drdy_irq,
+ "Failed to get IRQ from %s GPIO.\n", con_id);
+
+ /* An IRQ line is only an optional requirement for the IIO trigger */
+ if (ads1018->drdy_irq == 0)
+ return 0;
+
+ ads1018->indio_trig = devm_iio_trigger_alloc(dev, "%s-dev%d-%s",
+ indio_dev->name,
+ iio_device_id(indio_dev),
+ con_id);
+ if (!ads1018->indio_trig)
+ return -ENOMEM;
+
+ iio_trigger_set_drvdata(ads1018->indio_trig, ads1018);
+ ads1018->indio_trig->ops = &ads1018_trigger_ops;
+
+ ret = devm_iio_trigger_register(dev, ads1018->indio_trig);
+ if (ret)
+ return ret;
+
+ /*
+ * The "data-ready" IRQ line is shared with the MOSI pin, thus we need
+ * to keep it disabled until we actually request data.
+ */
+ return devm_request_irq(dev, ads1018->drdy_irq, ads1018_irq_handler,
+ IRQF_NO_AUTOEN, ads1018->chip_info->name, ads1018);
+}
+
+static int ads1018_spi_probe(struct spi_device *spi)
+{
+ const struct ads1018_chip_info *info = spi_get_device_match_data(spi);
+ struct device *dev = &spi->dev;
+ struct iio_dev *indio_dev;
+ struct ads1018 *ads1018;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*ads1018));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ ads1018 = iio_priv(indio_dev);
+ ads1018->spi = spi;
+ ads1018->chip_info = info;
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->name = info->name;
+ indio_dev->info = &ads1018_iio_info;
+ indio_dev->channels = info->channels;
+ indio_dev->num_channels = info->num_channels;
+
+ for (unsigned int i = 0; i < ADS1018_CHANNELS_MAX; i++) {
+ ads1018->chan_data[i].data_rate_mode = ADS1018_DRATE_DEFAULT;
+ ads1018->chan_data[i].pga_mode = ADS1018_PGA_DEFAULT;
+ }
+
+ ads1018->xfer.rx_buf = ads1018->rx_buf;
+ ads1018->xfer.len = sizeof(ads1018->rx_buf);
+ spi_message_init_with_transfers(&ads1018->msg_read, &ads1018->xfer, 1);
+
+ ret = ads1018_trigger_setup(indio_dev);
+ if (ret)
+ return ret;
+
+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
+ ads1018_trigger_handler,
+ &ads1018_buffer_ops);
+ if (ret)
+ return ret;
+
+ return devm_iio_device_register(&spi->dev, indio_dev);
+}
+
+static const unsigned int ads1018_data_rate_table[] = {
+ 128, 250, 490, 920, 1600, 2400, 3300,
+};
+
+static const unsigned int ads1118_data_rate_table[] = {
+ 8, 16, 32, 64, 128, 250, 475, 860,
+};
+
+static const struct ads1018_chip_info ads1018_chip_info = {
+ .name = "ads1018",
+ .channels = ads1018_iio_channels,
+ .num_channels = ARRAY_SIZE(ads1018_iio_channels),
+ .data_rate_mode_to_hz = ads1018_data_rate_table,
+ .num_data_rate_mode_to_hz = ARRAY_SIZE(ads1018_data_rate_table),
+ .pga_mode_to_gain = {
+ { 3, 0 }, /* fsr = 6144 mV */
+ { 2, 0 }, /* fsr = 4096 mV */
+ { 1, 0 }, /* fsr = 2048 mV */
+ { 0, 500000000 }, /* fsr = 1024 mV */
+ { 0, 250000000 }, /* fsr = 512 mV */
+ { 0, 125000000 }, /* fsr = 256 mV */
+ },
+ .temp_scale = { 125, 0 },
+};
+
+static const struct ads1018_chip_info ads1118_chip_info = {
+ .name = "ads1118",
+ .channels = ads1118_iio_channels,
+ .num_channels = ARRAY_SIZE(ads1118_iio_channels),
+ .data_rate_mode_to_hz = ads1118_data_rate_table,
+ .num_data_rate_mode_to_hz = ARRAY_SIZE(ads1118_data_rate_table),
+ .pga_mode_to_gain = {
+ { 0, 187500000 }, /* fsr = 6144 mV */
+ { 0, 125000000 }, /* fsr = 4096 mV */
+ { 0, 62500000 }, /* fsr = 2048 mV */
+ { 0, 31250000 }, /* fsr = 1024 mV */
+ { 0, 15625000 }, /* fsr = 512 mV */
+ { 0, 7812500 }, /* fsr = 256 mV */
+ },
+ .temp_scale = { 31, 250000 },
+};
+
+static const struct of_device_id ads1018_of_match[] = {
+ { .compatible = "ti,ads1018", .data = &ads1018_chip_info },
+ { .compatible = "ti,ads1118", .data = &ads1118_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ads1018_of_match);
+
+static const struct spi_device_id ads1018_spi_match[] = {
+ { "ads1018", (kernel_ulong_t)&ads1018_chip_info },
+ { "ads1118", (kernel_ulong_t)&ads1118_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ads1018_spi_match);
+
+static struct spi_driver ads1018_spi_driver = {
+ .driver = {
+ .name = "ads1018",
+ .of_match_table = ads1018_of_match,
+ },
+ .probe = ads1018_spi_probe,
+ .id_table = ads1018_spi_match,
+};
+module_spi_driver(ads1018_spi_driver);
+
+MODULE_DESCRIPTION("Texas Instruments ADS1018 ADC Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kurt Borja <kuurtb@gmail.com>");
diff --git a/drivers/iio/adc/ti-ads131e08.c b/drivers/iio/adc/ti-ads131e08.c
index c9a20024d6b1..a585621b0bc3 100644
--- a/drivers/iio/adc/ti-ads131e08.c
+++ b/drivers/iio/adc/ti-ads131e08.c
@@ -827,7 +827,7 @@ static int ads131e08_probe(struct spi_device *spi)
if (spi->irq) {
ret = devm_request_irq(&spi->dev, spi->irq,
ads131e08_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ IRQF_TRIGGER_FALLING | IRQF_NO_THREAD,
spi->dev.driver->name, indio_dev);
if (ret)
return dev_err_probe(&spi->dev, ret,
diff --git a/drivers/iio/adc/ti-ads131m02.c b/drivers/iio/adc/ti-ads131m02.c
new file mode 100644
index 000000000000..07d63bf62c5f
--- /dev/null
+++ b/drivers/iio/adc/ti-ads131m02.c
@@ -0,0 +1,968 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Driver for Texas Instruments ADS131M02 family ADC chips.
+ *
+ * Copyright (C) 2024 Protonic Holland
+ * Copyright (C) 2025 Oleksij Rempel <kernel@pengutronix.de>, Pengutronix
+ *
+ * Primary Datasheet Reference (used for citations):
+ * ADS131M08 8-Channel, Simultaneously-Sampling, 24-Bit, Delta-Sigma ADC
+ * Document SBAS950B, Revised February 2021
+ * https://www.ti.com/lit/ds/symlink/ads131m08.pdf
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/crc-itu-t.h>
+#include <linux/delay.h>
+#include <linux/dev_printk.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/lockdep.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/spi/spi.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/unaligned.h>
+
+/* Max channels supported by the largest variant in the family (ADS131M08) */
+#define ADS131M_MAX_CHANNELS 8
+
+/* Section 6.7, t_REGACQ (min time after reset) is 5us */
+#define ADS131M_RESET_DELAY_US 5
+
+#define ADS131M_WORD_SIZE_BYTES 3
+#define ADS131M_RESPONSE_WORDS 1
+#define ADS131M_CRC_WORDS 1
+
+/*
+ * SPI Frame word count calculation.
+ * Frame = N channel words + 1 response word + 1 CRC word.
+ * Word size depends on WLENGTH bits in MODE register (Default 24-bit).
+ */
+#define ADS131M_FRAME_WORDS(nch) \
+ ((nch) + ADS131M_RESPONSE_WORDS + ADS131M_CRC_WORDS)
+
+/*
+ * SPI Frame byte size calculation.
+ * Assumes default word size of 24 bits (3 bytes).
+ */
+#define ADS131M_FRAME_BYTES(nch) \
+ (ADS131M_FRAME_WORDS(nch) * ADS131M_WORD_SIZE_BYTES)
+
+/*
+ * Index calculation for the start byte of channel 'x' data within the RX buffer.
+ * Assumes 24-bit words (3 bytes per word).
+ * The received frame starts with the response word (e.g., STATUS register
+ * content when NULL command was sent), followed by data for channels 0 to N-1,
+ * and finally the output CRC word.
+ * Response = index 0..2, Chan0 = index 3..5, Chan1 = index 6..8, ...
+ * Index for ChanX = 3 (response) + x * 3 (channel data size).
+ */
+#define ADS131M_CHANNEL_INDEX(x) \
+ ((x) * ADS131M_WORD_SIZE_BYTES + ADS131M_WORD_SIZE_BYTES)
+
+#define ADS131M_CMD_NULL 0x0000
+#define ADS131M_CMD_RESET 0x0011
+
+#define ADS131M_CMD_ADDR_MASK GENMASK(11, 7)
+#define ADS131M_CMD_NUM_MASK GENMASK(6, 0)
+
+#define ADS131M_CMD_RREG_OP 0xa000
+#define ADS131M_CMD_WREG_OP 0x6000
+
+#define ADS131M_CMD_RREG(a, n) \
+ (ADS131M_CMD_RREG_OP | \
+ FIELD_PREP(ADS131M_CMD_ADDR_MASK, a) | \
+ FIELD_PREP(ADS131M_CMD_NUM_MASK, n))
+#define ADS131M_CMD_WREG(a, n) \
+ (ADS131M_CMD_WREG_OP | \
+ FIELD_PREP(ADS131M_CMD_ADDR_MASK, a) | \
+ FIELD_PREP(ADS131M_CMD_NUM_MASK, n))
+
+/* STATUS Register (0x01h) bit definitions */
+#define ADS131M_STATUS_CRC_ERR BIT(12) /* Input CRC error */
+
+#define ADS131M_REG_MODE 0x02
+#define ADS131M_MODE_RX_CRC_EN BIT(12) /* Enable Input CRC */
+#define ADS131M_MODE_CRC_TYPE_ANSI BIT(11) /* 0 = CCITT, 1 = ANSI */
+#define ADS131M_MODE_RESET_FLAG BIT(10)
+
+#define ADS131M_REG_CLOCK 0x03
+#define ADS131M_CLOCK_XTAL_DIS BIT(7)
+#define ADS131M_CLOCK_EXTREF_EN BIT(6)
+
+/* 1.2V internal reference, in millivolts, for IIO_VAL_FRACTIONAL_LOG2 */
+#define ADS131M_VREF_INTERNAL_mV 1200
+/* 24-bit resolution */
+#define ADS131M_RESOLUTION_BITS 24
+/* Signed data uses (RESOLUTION_BITS - 1) magnitude bits */
+#define ADS131M_CODE_BITS (ADS131M_RESOLUTION_BITS - 1)
+
+/* External ref FSR = Vref * 0.96 */
+#define ADS131M_EXTREF_SCALE_NUM 96
+#define ADS131M_EXTREF_SCALE_DEN 100
+
+struct ads131m_configuration {
+ const struct iio_chan_spec *channels;
+ const char *name;
+ u16 reset_ack;
+ u8 num_channels;
+ u8 supports_extref:1;
+ u8 supports_xtal:1;
+};
+
+struct ads131m_priv {
+ struct iio_dev *indio_dev;
+ struct spi_device *spi;
+ const struct ads131m_configuration *config;
+
+ bool use_external_ref;
+ int scale_val;
+ int scale_val2;
+
+ struct spi_transfer xfer;
+ struct spi_message msg;
+
+ /*
+ * Protects the shared tx_buffer and rx_buffer. More importantly,
+ * this serializes all SPI communication to ensure the atomicity
+ * of multi-cycle command sequences (like WREG, RREG, or RESET).
+ */
+ struct mutex lock;
+
+ /* DMA-safe buffers should be placed at the end of the struct. */
+ u8 tx_buffer[ADS131M_FRAME_BYTES(ADS131M_MAX_CHANNELS)]
+ __aligned(IIO_DMA_MINALIGN);
+ u8 rx_buffer[ADS131M_FRAME_BYTES(ADS131M_MAX_CHANNELS)];
+};
+
+/**
+ * ads131m_tx_frame_unlocked - Sends a command frame with Input CRC
+ * @priv: Device private data structure.
+ * @command: The 16-bit command to send (e.g., NULL, RREG, RESET).
+ *
+ * This function sends a command in Word 0, and its calculated 16-bit
+ * CRC in Word 1, as required when Input CRC is enabled.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_tx_frame_unlocked(struct ads131m_priv *priv, u32 command)
+{
+ struct iio_dev *indio_dev = priv->indio_dev;
+ u16 crc;
+
+ lockdep_assert_held(&priv->lock);
+
+ memset(priv->tx_buffer, 0, ADS131M_FRAME_BYTES(indio_dev->num_channels));
+
+ /* Word 0: 16-bit command, MSB-aligned in 24-bit word */
+ put_unaligned_be16(command, &priv->tx_buffer[0]);
+
+ /* Word 1: Input CRC. Calculated over the 3 bytes of Word 0. */
+ crc = crc_itu_t(0xffff, priv->tx_buffer, 3);
+ put_unaligned_be16(crc, &priv->tx_buffer[3]);
+
+ return spi_sync(priv->spi, &priv->msg);
+}
+
+/**
+ * ads131m_rx_frame_unlocked - Receives a full SPI data frame.
+ * @priv: Device private data structure.
+ *
+ * This function sends a NULL command (with its CRC) to clock out a
+ * full SPI frame from the device (e.g., response + channel data + CRC).
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_rx_frame_unlocked(struct ads131m_priv *priv)
+{
+ return ads131m_tx_frame_unlocked(priv, ADS131M_CMD_NULL);
+}
+
+/**
+ * ads131m_check_status_crc_err - Checks for an Input CRC error.
+ * @priv: Device private data structure.
+ *
+ * Sends a NULL command to fetch the STATUS register and checks the
+ * CRC_ERR bit. This is used to verify the integrity of the previous
+ * command (like RREG or WREG).
+ *
+ * Return: 0 on success, -EIO if CRC_ERR bit is set.
+ */
+static int ads131m_check_status_crc_err(struct ads131m_priv *priv)
+{
+ struct device *dev = &priv->spi->dev;
+ u16 status;
+ int ret;
+
+ lockdep_assert_held(&priv->lock);
+
+ ret = ads131m_rx_frame_unlocked(priv);
+ if (ret < 0) {
+ dev_err_ratelimited(dev,
+ "SPI error on STATUS read for CRC check\n");
+ return ret;
+ }
+
+ status = get_unaligned_be16(&priv->rx_buffer[0]);
+ if (status & ADS131M_STATUS_CRC_ERR) {
+ dev_err_ratelimited(dev,
+ "Input CRC error reported in STATUS = 0x%04x\n",
+ status);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * ads131m_write_reg_unlocked - Writes a single register and verifies the ACK.
+ * @priv: Device private data structure.
+ * @reg: The 8-bit register address.
+ * @val: The 16-bit value to write.
+ *
+ * This function performs the full 3-cycle WREG operation with Input CRC:
+ * 1. (Cycle 1) Sends WREG command, data, and its calculated CRC.
+ * 2. (Cycle 2) Sends NULL+CRC to retrieve the response from Cycle 1.
+ * 3. Verifies the response is the correct ACK for the WREG.
+ * 4. (Cycle 3) Sends NULL+CRC to retrieve STATUS and check for CRC_ERR.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_write_reg_unlocked(struct ads131m_priv *priv, u8 reg, u16 val)
+{
+ struct iio_dev *indio_dev = priv->indio_dev;
+ u16 command, expected_ack, response, crc;
+ struct device *dev = &priv->spi->dev;
+ int ret_crc_err = 0;
+ int ret;
+
+ lockdep_assert_held(&priv->lock);
+
+ command = ADS131M_CMD_WREG(reg, 0); /* n = 0 for 1 register */
+ /*
+ * Per Table 8-11, WREG response is: 010a aaaa ammm mmmm
+ * For 1 reg (n = 0 -> m = 0): 010a aaaa a000 0000 = 0x4000 | (reg << 7)
+ */
+ expected_ack = 0x4000 | (reg << 7);
+
+ /* Cycle 1: Send WREG Command + Data + Input CRC */
+
+ memset(priv->tx_buffer, 0, ADS131M_FRAME_BYTES(indio_dev->num_channels));
+
+ /* Word 0: WREG command, 1 reg (n = 0), MSB-aligned */
+ put_unaligned_be16(command, &priv->tx_buffer[0]);
+
+ /* Word 1: Data, MSB-aligned */
+ put_unaligned_be16(val, &priv->tx_buffer[3]);
+
+ /* Word 2: Input CRC. Calculated over Word 0 (Cmd) and Word 1 (Data). */
+ crc = crc_itu_t(0xffff, priv->tx_buffer, 6);
+ put_unaligned_be16(crc, &priv->tx_buffer[6]);
+
+ /* Ignore the RX buffer (it's from the previous command) */
+ ret = spi_sync(priv->spi, &priv->msg);
+ if (ret < 0) {
+ dev_err_ratelimited(dev, "SPI error on WREG (cycle 1)\n");
+ return ret;
+ }
+
+ /* Cycle 2: Send NULL Command to get the WREG response */
+ ret = ads131m_rx_frame_unlocked(priv);
+ if (ret < 0) {
+ dev_err_ratelimited(dev, "SPI error on WREG ACK (cycle 2)\n");
+ return ret;
+ }
+
+ /*
+ * Response is in the first 2 bytes of the RX buffer
+ * (MSB-aligned 16-bit response)
+ */
+ response = get_unaligned_be16(&priv->rx_buffer[0]);
+ if (response != expected_ack) {
+ dev_err_ratelimited(dev, "WREG(0x%02x) failed, expected ACK 0x%04x, got 0x%04x\n",
+ reg, expected_ack, response);
+ ret_crc_err = -EIO;
+ /*
+ * Don't return yet, still need to do Cycle 3 to clear
+ * any potential CRC_ERR flag from this failed command.
+ */
+ }
+
+ /*
+ * Cycle 3: Check STATUS for Input CRC error.
+ * This is necessary even if ACK was wrong, to clear the CRC_ERR flag.
+ */
+ ret = ads131m_check_status_crc_err(priv);
+ if (ret < 0)
+ return ret;
+
+ return ret_crc_err;
+}
+
+/**
+ * ads131m_read_reg_unlocked - Reads a single register from the device.
+ * @priv: Device private data structure.
+ * @reg: The 8-bit register address.
+ * @val: Pointer to store the 16-bit register value.
+ *
+ * This function performs the full 3-cycle RREG operation with Input CRC:
+ * 1. (Cycle 1) Sends the RREG command + Input CRC.
+ * 2. (Cycle 2) Sends NULL+CRC to retrieve the register data.
+ * 3. (Cycle 3) Sends NULL+CRC to retrieve STATUS and check for CRC_ERR.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_read_reg_unlocked(struct ads131m_priv *priv, u8 reg, u16 *val)
+{
+ struct device *dev = &priv->spi->dev;
+ u16 command;
+ int ret;
+
+ lockdep_assert_held(&priv->lock);
+
+ command = ADS131M_CMD_RREG(reg, 0); /* n=0 for 1 register */
+
+ /*
+ * Cycle 1: Send RREG Command + Input CRC
+ * Ignore the RX buffer (it's from the previous command)
+ */
+ ret = ads131m_tx_frame_unlocked(priv, command);
+ if (ret < 0) {
+ dev_err_ratelimited(dev, "SPI error on RREG (cycle 1)\n");
+ return ret;
+ }
+
+ /* Cycle 2: Send NULL Command to get the register data */
+ ret = ads131m_rx_frame_unlocked(priv);
+ if (ret < 0) {
+ dev_err_ratelimited(dev, "SPI error on RREG data (cycle 2)\n");
+ return ret;
+ }
+
+ /*
+ * Per datasheet, for a single reg read, the response is the data.
+ * It's in the first 2 bytes of the RX buffer (MSB-aligned 16-bit).
+ */
+ *val = get_unaligned_be16(&priv->rx_buffer[0]);
+
+ /*
+ * Cycle 3: Check STATUS for Input CRC error.
+ * The RREG command does not execute if CRC is bad, but we read
+ * STATUS anyway to clear the flag in case it was set.
+ */
+ return ads131m_check_status_crc_err(priv);
+}
+
+/**
+ * ads131m_rmw_reg - Reads, modifies, and writes a single register.
+ * @priv: Device private data structure.
+ * @reg: The 8-bit register address.
+ * @clear: Bitmask of bits to clear.
+ * @set: Bitmask of bits to set.
+ *
+ * This function performs an atomic read-modify-write operation on a register.
+ * It reads the register, applies the clear and set masks, and writes
+ * the new value back if it has changed.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_rmw_reg(struct ads131m_priv *priv, u8 reg, u16 clear, u16 set)
+{
+ u16 old_val, new_val;
+ int ret;
+
+ guard(mutex)(&priv->lock);
+
+ ret = ads131m_read_reg_unlocked(priv, reg, &old_val);
+ if (ret < 0)
+ return ret;
+
+ new_val = (old_val & ~clear) | set;
+ if (new_val == old_val)
+ return 0;
+
+ return ads131m_write_reg_unlocked(priv, reg, new_val);
+}
+
+/**
+ * ads131m_verify_output_crc - Verifies the CRC of the received SPI frame.
+ * @priv: Device private data structure.
+ *
+ * This function calculates the CRC-16-CCITT (Poly 0x1021, Seed 0xFFFF) over
+ * the received response and channel data, and compares it to the CRC word
+ * received at the end of the SPI frame.
+ *
+ * Return: 0 on success, -EIO on CRC mismatch.
+ */
+static int ads131m_verify_output_crc(struct ads131m_priv *priv)
+{
+ struct iio_dev *indio_dev = priv->indio_dev;
+ struct device *dev = &priv->spi->dev;
+ u16 calculated_crc, received_crc;
+ size_t data_len;
+
+ lockdep_assert_held(&priv->lock);
+
+ /*
+ * Frame: [Response][Chan 0]...[Chan N-1][CRC Word]
+ * Data for CRC: [Response][Chan 0]...[Chan N-1]
+ * Data length = (N_channels + 1) * 3 bytes (at 24-bit word size)
+ */
+ data_len = ADS131M_FRAME_BYTES(indio_dev->num_channels) - 3;
+ calculated_crc = crc_itu_t(0xffff, priv->rx_buffer, data_len);
+
+ /*
+ * The received 16-bit CRC is MSB-aligned in the last 24-bit word.
+ * We extract it from the first 2 bytes (BE) of that word.
+ */
+ received_crc = get_unaligned_be16(&priv->rx_buffer[data_len]);
+ if (calculated_crc != received_crc) {
+ dev_err_ratelimited(dev, "Output CRC error. Got %04x, expected %04x\n",
+ received_crc, calculated_crc);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * ads131m_adc_read - Reads channel data, checks input and output CRCs.
+ * @priv: Device private data structure.
+ * @channel: The channel number to read.
+ * @val: Pointer to store the raw 24-bit value.
+ *
+ * This function sends a NULL command (with Input CRC) to retrieve data.
+ * It checks the received STATUS word for any Input CRC errors from the
+ * previous command, and then verifies the Output CRC of the current
+ * data frame.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_adc_read(struct ads131m_priv *priv, u8 channel, s32 *val)
+{
+ struct device *dev = &priv->spi->dev;
+ u16 status;
+ int ret;
+ u8 *buf;
+
+ guard(mutex)(&priv->lock);
+
+ /* Send NULL command + Input CRC, and receive data frame */
+ ret = ads131m_rx_frame_unlocked(priv);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Check STATUS for Input CRC error from the previous command frame.
+ * Note: the STATUS word belongs to the frame before this NULL command.
+ */
+ status = get_unaligned_be16(&priv->rx_buffer[0]);
+ if (status & ADS131M_STATUS_CRC_ERR) {
+ dev_err_ratelimited(dev,
+ "Previous input CRC error reported in STATUS (0x%04x)\n",
+ status);
+ }
+
+ ret = ads131m_verify_output_crc(priv);
+ if (ret < 0)
+ return ret;
+
+ buf = &priv->rx_buffer[ADS131M_CHANNEL_INDEX(channel)];
+ *val = sign_extend32(get_unaligned_be24(buf), ADS131M_CODE_BITS);
+
+ return 0;
+}
+
+static int ads131m_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel,
+ int *val, int *val2, long mask)
+{
+ struct ads131m_priv *priv = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = ads131m_adc_read(priv, channel->channel, val);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = priv->scale_val;
+ *val2 = priv->scale_val2;
+
+ return IIO_VAL_FRACTIONAL;
+ default:
+ return -EINVAL;
+ }
+}
+
+#define ADS131M_VOLTAGE_CHANNEL(num) \
+ { \
+ .type = IIO_VOLTAGE, \
+ .differential = 1, \
+ .indexed = 1, \
+ .channel = (num), \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+ }
+
+static const struct iio_chan_spec ads131m02_channels[] = {
+ ADS131M_VOLTAGE_CHANNEL(0),
+ ADS131M_VOLTAGE_CHANNEL(1),
+};
+
+static const struct iio_chan_spec ads131m03_channels[] = {
+ ADS131M_VOLTAGE_CHANNEL(0),
+ ADS131M_VOLTAGE_CHANNEL(1),
+ ADS131M_VOLTAGE_CHANNEL(2),
+};
+
+static const struct iio_chan_spec ads131m04_channels[] = {
+ ADS131M_VOLTAGE_CHANNEL(0),
+ ADS131M_VOLTAGE_CHANNEL(1),
+ ADS131M_VOLTAGE_CHANNEL(2),
+ ADS131M_VOLTAGE_CHANNEL(3),
+};
+
+static const struct iio_chan_spec ads131m06_channels[] = {
+ ADS131M_VOLTAGE_CHANNEL(0),
+ ADS131M_VOLTAGE_CHANNEL(1),
+ ADS131M_VOLTAGE_CHANNEL(2),
+ ADS131M_VOLTAGE_CHANNEL(3),
+ ADS131M_VOLTAGE_CHANNEL(4),
+ ADS131M_VOLTAGE_CHANNEL(5),
+};
+
+static const struct iio_chan_spec ads131m08_channels[] = {
+ ADS131M_VOLTAGE_CHANNEL(0),
+ ADS131M_VOLTAGE_CHANNEL(1),
+ ADS131M_VOLTAGE_CHANNEL(2),
+ ADS131M_VOLTAGE_CHANNEL(3),
+ ADS131M_VOLTAGE_CHANNEL(4),
+ ADS131M_VOLTAGE_CHANNEL(5),
+ ADS131M_VOLTAGE_CHANNEL(6),
+ ADS131M_VOLTAGE_CHANNEL(7),
+};
+
+static const struct ads131m_configuration ads131m02_config = {
+ .channels = ads131m02_channels,
+ .num_channels = ARRAY_SIZE(ads131m02_channels),
+ .reset_ack = 0xff22,
+ .name = "ads131m02",
+};
+
+static const struct ads131m_configuration ads131m03_config = {
+ .channels = ads131m03_channels,
+ .num_channels = ARRAY_SIZE(ads131m03_channels),
+ .reset_ack = 0xff23,
+ .name = "ads131m03",
+};
+
+static const struct ads131m_configuration ads131m04_config = {
+ .channels = ads131m04_channels,
+ .num_channels = ARRAY_SIZE(ads131m04_channels),
+ .reset_ack = 0xff24,
+ .name = "ads131m04",
+};
+
+static const struct ads131m_configuration ads131m06_config = {
+ .channels = ads131m06_channels,
+ .num_channels = ARRAY_SIZE(ads131m06_channels),
+ .reset_ack = 0xff26,
+ .supports_extref = true,
+ .supports_xtal = true,
+ .name = "ads131m06",
+};
+
+static const struct ads131m_configuration ads131m08_config = {
+ .channels = ads131m08_channels,
+ .num_channels = ARRAY_SIZE(ads131m08_channels),
+ .reset_ack = 0xff28,
+ .supports_extref = true,
+ .supports_xtal = true,
+ .name = "ads131m08",
+};
+
+static const struct iio_info ads131m_info = {
+ .read_raw = ads131m_read_raw,
+};
+
+/*
+ * Prepares the reusable SPI message structure for a full-duplex transfer.
+ * The ADS131M requires sending a command frame while simultaneously
+ * receiving the response/data frame from the previous command cycle.
+ *
+ * This message is optimized for the primary data acquisition workflow:
+ * sending a single-word command (like NULL) and receiving a full data
+ * frame (Response + N*Channels + CRC).
+ *
+ * This message is sized for a full data frame and is reused for all
+ * command/data cycles. The driver does not implement variable-length SPI
+ * messages.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_prepare_message(struct ads131m_priv *priv)
+{
+ struct iio_dev *indio_dev = priv->indio_dev;
+ struct device *dev = &priv->spi->dev;
+ int ret;
+
+ priv->xfer.tx_buf = priv->tx_buffer;
+ priv->xfer.rx_buf = priv->rx_buffer;
+ priv->xfer.len = ADS131M_FRAME_BYTES(indio_dev->num_channels);
+ spi_message_init_with_transfers(&priv->msg, &priv->xfer, 1);
+
+ ret = devm_spi_optimize_message(dev, priv->spi, &priv->msg);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to optimize SPI message\n");
+
+ return 0;
+}
+
+/**
+ * ads131m_hw_reset - Pulses the optional hardware reset.
+ * @priv: Device private data structure.
+ * @rstc: Reset control for the /RESET line.
+ *
+ * Pulses the /RESET line to perform a hardware reset and waits the
+ * required t_REGACQ time for the device to be ready.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_hw_reset(struct ads131m_priv *priv,
+ struct reset_control *rstc)
+{
+ struct device *dev = &priv->spi->dev;
+ int ret;
+
+ /*
+ * Manually pulse the reset line using the framework.
+ * The reset-gpio provider does not implement the .reset op,
+ * so we must use .assert and .deassert.
+ */
+ ret = reset_control_assert(rstc);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to assert reset\n");
+
+ /* Datasheet: Hold /RESET low for > 2 f_CLKIN cycles. 1us is ample. */
+ fsleep(1);
+
+ ret = reset_control_deassert(rstc);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to deassert reset\n");
+
+ /* Wait t_REGACQ (5us) for registers to be accessible */
+ fsleep(ADS131M_RESET_DELAY_US);
+
+ return 0;
+}
+
+/**
+ * ads131m_sw_reset - Issues a software RESET and verifies ACK.
+ * @priv: Device private data structure.
+ *
+ * This function sends a RESET command (with Input CRC), waits t_REGACQ,
+ * reads back the RESET ACK, and then sends a final NULL to check for
+ * any input CRC errors.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_sw_reset(struct ads131m_priv *priv)
+{
+ u16 expected_ack = priv->config->reset_ack;
+ struct device *dev = &priv->spi->dev;
+ u16 response;
+ int ret;
+
+ guard(mutex)(&priv->lock);
+
+ ret = ads131m_tx_frame_unlocked(priv, ADS131M_CMD_RESET);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to send RESET command\n");
+
+ /* Wait t_REGACQ (5us) for device to be ready after reset */
+ fsleep(ADS131M_RESET_DELAY_US);
+
+ /* Cycle 2: Send NULL + CRC to retrieve the response to the RESET */
+ ret = ads131m_rx_frame_unlocked(priv);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to read RESET ACK\n");
+
+ response = get_unaligned_be16(&priv->rx_buffer[0]);
+
+ /* Check against the device-specific ACK value */
+ if (response != expected_ack)
+ return dev_err_probe(dev, -EIO,
+ "RESET ACK mismatch, got 0x%04x, expected 0x%04x\n",
+ response, expected_ack);
+
+ /* Cycle 3: Check STATUS for Input CRC error on the RESET command. */
+ return ads131m_check_status_crc_err(priv);
+}
+
+/**
+ * ads131m_reset - Resets the device using hardware or software.
+ * @priv: Device private data structure.
+ * @rstc: Optional reset control, or NULL for software reset.
+ *
+ * This function performs a hardware reset if supported (rstc provided),
+ * otherwise it issues a software RESET command via SPI.
+ *
+ * Note: The software reset path also validates the device's reset
+ * acknowledgment against the expected ID for the compatible string.
+ * The hardware reset path bypasses this ID check.
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_reset(struct ads131m_priv *priv, struct reset_control *rstc)
+{
+ if (rstc)
+ return ads131m_hw_reset(priv, rstc);
+
+ return ads131m_sw_reset(priv);
+}
+
+static int ads131m_power_init(struct ads131m_priv *priv)
+{
+ static const char * const supply_ids[] = { "avdd", "dvdd" };
+ struct device *dev = &priv->spi->dev;
+ int vref_uV;
+ int ret;
+
+ ret = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(supply_ids), supply_ids);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "failed to enable regulators\n");
+
+ /* Default to Internal 1.2V reference: 1200mV / 2^23 */
+ priv->scale_val = ADS131M_VREF_INTERNAL_mV;
+ priv->scale_val2 = BIT(ADS131M_CODE_BITS);
+
+ if (!priv->config->supports_extref)
+ return 0;
+
+ ret = devm_regulator_get_enable_read_voltage(dev, "refin");
+ if (ret < 0 && ret != -ENODEV)
+ return dev_err_probe(dev, ret, "failed to get refin supply\n");
+
+ if (ret == 0)
+ return dev_err_probe(dev, -EINVAL, "refin supply reports 0V\n");
+
+ if (ret == -ENODEV)
+ return 0;
+
+ vref_uV = ret;
+
+ /*
+ * External reference found: Scale(mV) = (vref_uV * 0.96) / 1000
+ * The denominator is 100 * 2^23 because of the 0.96 factor (96/100).
+ */
+ priv->scale_val = div_s64((s64)vref_uV * ADS131M_EXTREF_SCALE_NUM, 1000);
+ priv->scale_val2 = ADS131M_EXTREF_SCALE_DEN * BIT(ADS131M_CODE_BITS);
+ priv->use_external_ref = true;
+
+ return 0;
+}
+
+/**
+ * ads131m_hw_init - Initialize the ADC hardware.
+ * @priv: Device private data structure.
+ * @rstc: Optional reset control, or NULL for software reset.
+ * @is_xtal: True if 'clock-names' is "xtal", false if "clkin".
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_hw_init(struct ads131m_priv *priv,
+ struct reset_control *rstc, bool is_xtal)
+{
+ struct device *dev = &priv->spi->dev;
+ u16 mode_clear, mode_set;
+ int ret;
+
+ ret = ads131m_reset(priv, rstc);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Configure CLOCK register (0x03) based on DT properties.
+ * This register only needs configuration for 32-pin (M06/M08)
+ * variants, as the configurable bits (XTAL_DIS, EXTREF_EN)
+ * are reserved on 20-pin (M02/M03/M04) variants.
+ */
+ if (priv->config->supports_xtal || priv->config->supports_extref) {
+ u16 clk_set = 0;
+
+ if (priv->config->supports_xtal && !is_xtal)
+ clk_set |= ADS131M_CLOCK_XTAL_DIS;
+
+ if (priv->config->supports_extref && priv->use_external_ref)
+ clk_set |= ADS131M_CLOCK_EXTREF_EN;
+
+ ret = ads131m_rmw_reg(priv, ADS131M_REG_CLOCK,
+ ADS131M_CLOCK_EXTREF_EN | ADS131M_CLOCK_XTAL_DIS,
+ clk_set);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to configure CLOCK register\n");
+ }
+
+ /*
+ * The RESET command sets all registers to default, which means:
+ * 1. The RESET bit (Bit 10) in MODE is set to '1'.
+ * 2. The CRC_TYPE bit (Bit 11) in MODE is '0' (CCITT).
+ * 3. The RX_CRC_EN bit (Bit 12) in MODE is '0' (Disabled).
+ *
+ * We must:
+ * 1. Clear the RESET bit.
+ * 2. Enable Input CRC (RX_CRC_EN).
+ * 3. Explicitly clear the ANSI CRC bit (for certainty).
+ */
+ mode_clear = ADS131M_MODE_CRC_TYPE_ANSI | ADS131M_MODE_RESET_FLAG;
+ mode_set = ADS131M_MODE_RX_CRC_EN;
+
+ ret = ads131m_rmw_reg(priv, ADS131M_REG_MODE, mode_clear, mode_set);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to configure MODE register\n");
+
+ return 0;
+}
+
+/**
+ * ads131m_parse_clock - enable clock and detect "xtal" selection
+ * @priv: Device private data structure.
+ * @is_xtal: result flag (true if "xtal", false if default "clkin")
+ *
+ * Return: 0 on success, or a negative error code.
+ */
+static int ads131m_parse_clock(struct ads131m_priv *priv, bool *is_xtal)
+{
+ struct device *dev = &priv->spi->dev;
+ struct clk *clk;
+ int ret;
+
+ clk = devm_clk_get_enabled(dev, NULL);
+ if (IS_ERR_OR_NULL(clk)) {
+ if (IS_ERR(clk))
+ ret = PTR_ERR(clk);
+ else
+ ret = -ENODEV;
+
+ return dev_err_probe(dev, ret, "clk get enabled failed\n");
+ }
+
+ ret = device_property_match_string(dev, "clock-names", "xtal");
+ if (ret > 0)
+ return dev_err_probe(dev, -EINVAL,
+ "'xtal' must be the only or first clock name");
+
+ if (ret < 0 && ret != -ENODATA)
+ return dev_err_probe(dev, ret,
+ "failed to read 'clock-names' property");
+
+ if (ret == 0 && !priv->config->supports_xtal)
+ return dev_err_probe(dev, -EINVAL,
+ "'xtal' clock not supported on this device");
+
+ *is_xtal = !ret;
+
+ return 0;
+}
+
+static int ads131m_probe(struct spi_device *spi)
+{
+ const struct ads131m_configuration *config;
+ struct device *dev = &spi->dev;
+ struct reset_control *rstc;
+ struct iio_dev *indio_dev;
+ struct ads131m_priv *priv;
+ bool is_xtal;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*priv));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ priv = iio_priv(indio_dev);
+ priv->indio_dev = indio_dev;
+ priv->spi = spi;
+
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &ads131m_info;
+
+ config = spi_get_device_match_data(spi);
+
+ priv->config = config;
+ indio_dev->name = config->name;
+ indio_dev->channels = config->channels;
+ indio_dev->num_channels = config->num_channels;
+
+ rstc = devm_reset_control_get_optional_exclusive(dev, NULL);
+ if (IS_ERR(rstc))
+ return dev_err_probe(dev, PTR_ERR(rstc),
+ "Failed to get reset controller\n");
+
+ ret = devm_mutex_init(dev, &priv->lock);
+ if (ret < 0)
+ return ret;
+
+ ret = ads131m_prepare_message(priv);
+ if (ret < 0)
+ return ret;
+
+ ret = ads131m_power_init(priv);
+ if (ret < 0)
+ return ret;
+
+ /* Power must be applied and stable before the clock is enabled. */
+ ret = ads131m_parse_clock(priv, &is_xtal);
+ if (ret < 0)
+ return ret;
+
+ ret = ads131m_hw_init(priv, rstc, is_xtal);
+ if (ret < 0)
+ return ret;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id ads131m_of_match[] = {
+ { .compatible = "ti,ads131m02", .data = &ads131m02_config },
+ { .compatible = "ti,ads131m03", .data = &ads131m03_config },
+ { .compatible = "ti,ads131m04", .data = &ads131m04_config },
+ { .compatible = "ti,ads131m06", .data = &ads131m06_config },
+ { .compatible = "ti,ads131m08", .data = &ads131m08_config },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ads131m_of_match);
+
+static const struct spi_device_id ads131m_id[] = {
+ { "ads131m02", (kernel_ulong_t)&ads131m02_config },
+ { "ads131m03", (kernel_ulong_t)&ads131m03_config },
+ { "ads131m04", (kernel_ulong_t)&ads131m04_config },
+ { "ads131m06", (kernel_ulong_t)&ads131m06_config },
+ { "ads131m08", (kernel_ulong_t)&ads131m08_config },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ads131m_id);
+
+static struct spi_driver ads131m_driver = {
+ .driver = {
+ .name = "ads131m02",
+ .of_match_table = ads131m_of_match,
+ },
+ .probe = ads131m_probe,
+ .id_table = ads131m_id,
+};
+module_spi_driver(ads131m_driver);
+
+MODULE_AUTHOR("David Jander <david@protonic.nl>");
+MODULE_DESCRIPTION("Texas Instruments ADS131M02 ADC driver");
+MODULE_LICENSE("GPL");