mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Kurt Borja <kuurtb@gmail.com>
To: Jonathan Cameron <jic23@kernel.org>,
	Rob Herring <robh@kernel.org>,
	 Krzysztof Kozlowski <krzk+dt@kernel.org>,
	 Conor Dooley <conor+dt@kernel.org>,
	Linus Walleij <linusw@kernel.org>,
	 Bartosz Golaszewski <brgl@kernel.org>
Cc: "David Lechner" <dlechner@baylibre.com>,
	"Nuno Sá" <nuno.sa@analog.com>,
	"Andy Shevchenko" <andy@kernel.org>,
	linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-gpio@vger.kernel.org,
	"Kurt Borja" <kuurtb@gmail.com>,
	"Jonathan Cameron" <jic23@kernel.org>
Subject: [PATCH 2/5] iio: adc: Add ti-ads1262 driver
Date: Fri, 12 Jun 2026 17:46:20 -0500	[thread overview]
Message-ID: <20260612-ads126x-v1-2-894c788d03ed@gmail.com> (raw)
In-Reply-To: <20260612-ads126x-v1-0-894c788d03ed@gmail.com>

Add ti-ads1262 driver for TI ADS1262 and ADS1263 ADCs with initial
support for the following features:

  - Power management
  - IIO direct and buffer modes
  - Channel hot-reloading
  - Internal or external oscillator
  - Internal or external voltage reference
  - Filter configuration
  - Sensor bias configuration
  - IDAC configuration
  - Level-shift voltage configuration
  - Auxiliary ADC interoperability considerations

Signed-off-by: Kurt Borja <kuurtb@gmail.com>
---
 MAINTAINERS                  |    1 +
 drivers/iio/adc/Kconfig      |   13 +
 drivers/iio/adc/Makefile     |    1 +
 drivers/iio/adc/ti-ads1262.c | 1816 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1831 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9379699d99c6..b874add5c924 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26674,6 +26674,7 @@ L:	linux-iio@vger.kernel.org
 S:	Maintained
 F:	Documentation/devicetree/bindings/iio/adc/ti,ads1262.yaml
 F:	Documentation/devicetree/bindings/iio/adc/ti,ads1263-adc2.yaml
+F:	drivers/iio/adc/ti-ads1262.c
 
 TI ADS7924 ADC DRIVER
 M:	Hugo Villeneuve <hvilleneuve@dimonoff.com>
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index a3a93a47b43d..b6c35d0c88ed 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1796,6 +1796,19 @@ config TI_ADS124S08
 	  This driver can also be built as a module. If so, the module will be
 	  called ti-ads124s08.
 
+config TI_ADS1262
+	tristate "Texas Instruments ADS1262"
+	depends on SPI && GPIOLIB
+	select REGMAP
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
+	help
+	  If you say yes here you get support for Texas Instruments ADS1262 and
+	  ADS1263 ADC chips.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called ti-ads1262.
+
 config TI_ADS1298
 	tristate "Texas Instruments ADS1298"
 	depends on SPI
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 707dd708912f..e0653820081e 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -154,6 +154,7 @@ 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_ADS1262) += ti-ads1262.o
 obj-$(CONFIG_TI_ADS1298) += ti-ads1298.o
 obj-$(CONFIG_TI_ADS131E08) += ti-ads131e08.o
 obj-$(CONFIG_TI_ADS131M02) += ti-ads131m02.o
diff --git a/drivers/iio/adc/ti-ads1262.c b/drivers/iio/adc/ti-ads1262.c
new file mode 100644
index 000000000000..fd1911cf65ac
--- /dev/null
+++ b/drivers/iio/adc/ti-ads1262.c
@@ -0,0 +1,1816 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Texas Instruments ADS1262 ADC driver
+ *
+ * Copyright (C) 2025 Kurt Borja <kuurtb@gmail.com>
+ */
+
+#include <linux/array_size.h>
+#include <linux/align.h>
+#include <linux/bitfield.h>
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/cleanup.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/compiler_attributes.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/lockdep.h>
+#include <linux/math.h>
+#include <linux/math64.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/overflow.h>
+#include <linux/property.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <asm/byteorder.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+/* Commands */
+#define ADS1262_OPCODE_NOP			0x00
+#define ADS1262_OPCODE_RESET			0x06
+#define ADS1262_OPCODE_START1			0x08
+#define ADS1262_OPCODE_STOP1			0x0A
+#define ADS1262_OPCODE_START2			0x0C
+#define ADS1262_OPCODE_STOP2			0x0E
+#define ADS1262_OPCODE_RDATA1			0x12
+#define ADS1262_OPCODE_RDATA2			0x14
+#define ADS1262_OPCODE_SYOCAL1			0x16
+#define ADS1262_OPCODE_SYGCAL1			0x17
+#define ADS1262_OPCODE_SFOCAL1			0x19
+#define ADS1262_OPCODE_SYOCAL2			0x1B
+#define ADS1262_OPCODE_SYGCAL2			0x1C
+#define ADS1262_OPCODE_SFOCAL2			0x1E
+#define ADS1262_OPCODE_RREG			0x20
+#define ADS1262_OPCODE_WREG			0x40
+
+/* Registers */
+#define ADS1262_ID_REG				0x00
+#define ADS1262_POWER_REG			0x01
+#define ADS1262_INTERFACE_REG			0x02
+#define ADS1262_MODE0_REG			0x03
+#define ADS1262_MODE1_REG			0x04
+#define ADS1262_MODE2_REG			0x05
+#define ADS1262_INPMUX_REG			0x06
+#define ADS1262_OFCAL0_REG			0x07
+#define ADS1262_OFCAL1_REG			0x08
+#define ADS1262_OFCAL2_REG			0x09
+#define ADS1262_FSCAL0_REG			0x0A
+#define ADS1262_FSCAL1_REG			0x0B
+#define ADS1262_FSCAL2_REG			0x0C
+#define ADS1262_IDACMUX_REG			0x0D
+#define ADS1262_IDACMAG_REG			0x0E
+#define ADS1262_REFMUX_REG			0x0F
+#define ADS1262_TDACP_REG			0x10
+#define ADS1262_TDACN_REG			0x11
+#define ADS1262_GPIOCON_REG			0x12
+#define ADS1262_GPIODIR_REG			0x13
+#define ADS1262_GPIODAT_REG			0x14
+#define ADS1262_ADC2CFG_REG			0x15
+#define ADS1262_ADC2MUX_REG			0x16
+#define ADS1262_ADC2OFC0_REG			0x17
+#define ADS1262_ADC2OFC1_REG			0x18
+#define ADS1262_ADC2FSC0_REG			0x19
+#define ADS1262_ADC2FSC1_REG			0x1A
+#define ADS1262_REG_COUNT			0x1B
+
+/* ID fields */
+#define ADS1262_DEV_ID_MASK			GENMASK(7, 5)
+#define ADS1262_REV_ID_MASK			GENMASK(4, 0)
+
+/* POWER fields */
+#define ADS1262_POWER_RESET_MASK		BIT(4)
+#define ADS1262_POWER_VBIAS_MASK		BIT(1)
+#define ADS1262_POWER_INTREF_MASK		BIT(0)
+
+/* INTERFACE fields */
+#define ADS1262_INTERFACE_TIMEOUT_MASK		BIT(3)
+#define ADS1262_INTERFACE_STATUS_MASK		BIT(2)
+#define ADS1262_INTERFACE_CRC_MASK		GENMASK(1, 0)
+
+/* MODE0 fields */
+#define ADS1262_MODE0_REFREV_MASK		BIT(7)
+#define ADS1262_MODE0_RUNMODE_MASK		BIT(6)
+#define ADS1262_MODE0_IDAC_ROT_MASK		BIT(5)
+#define ADS1262_MODE0_CHOP_MASK			BIT(4)
+#define ADS1262_MODE0_DELAY_MASK		GENMASK(3, 0)
+
+/* MODE1 fields */
+#define ADS1262_MODE1_FILTER_MASK		GENMASK(7, 5)
+#define ADS1262_MODE1_SBADC_MASK		BIT(4)
+#define ADS1262_MODE1_SBPOL_MASK		BIT(3)
+#define ADS1262_MODE1_SBMAG_MASK		GENMASK(2, 0)
+
+/* MODE2 fields */
+#define ADS1262_MODE2_BYPASS_MASK		BIT(7)
+#define ADS1262_MODE2_GAIN_MASK			GENMASK(6, 4)
+#define ADS1262_MODE2_DR_MASK			GENMASK(3, 0)
+
+/* INPMUX fields */
+#define ADS1262_INPMUX_MUXP_MASK		GENMASK(7, 4)
+#define ADS1262_INPMUX_MUXN_MASK		GENMASK(3, 0)
+
+/* IDACMUX fields */
+#define ADS1262_IDACMUX_MUX2_MASK		GENMASK(7, 4)
+#define ADS1262_IDACMUX_MUX1_MASK		GENMASK(3, 0)
+
+/* IDACMAG fields */
+#define ADS1262_IDACMAG_MAG2_MASK		GENMASK(7, 4)
+#define ADS1262_IDACMAG_MAG1_MASK		GENMASK(3, 0)
+
+/* REFMUX fields */
+#define ADS1262_REFMUX_RMUXP_MASK		GENMASK(5, 3)
+#define ADS1262_REFMUX_RMUXN_MASK		GENMASK(2, 0)
+
+/* TDACP fields */
+#define ADS1262_TDACP_OUTP_MASK			BIT(7)
+#define ADS1262_TDACP_MAGP_MASK			GENMASK(4, 0)
+
+/* TDACN fields */
+#define ADS1262_TDACN_OUTN_MASK			BIT(7)
+#define ADS1262_TDACN_MAGN_MASK			GENMASK(4, 0)
+
+/* ADC2CFG fields */
+#define ADS1262_ADC2CFG_DR2_MASK		GENMASK(7, 6)
+#define ADS1262_ADC2CFG_REF2_MASK		GENMASK(5, 3)
+#define ADS1262_ADC2CFG_GAIN2_MASK		GENMASK(2, 0)
+
+/* ADC2MUX fields */
+#define ADS1262_ADC2MUX_MUXP2_MASK		GENMASK(7, 4)
+#define ADS1262_ADC2MUX_MUXN2_MASK		GENMASK(3, 0)
+
+/* ID DEV_ID constants */
+#define ADS1262_DEV_ID_ADS1262			0
+#define ADS1262_DEV_ID_ADS1263			1
+
+/* MODE0 RUNMODE constants */
+#define ADS1262_RUNMODE_CONTINUOUS		0
+#define ADS1262_RUNMODE_PULSE			1
+
+/* MODE1 FILTER constants */
+#define ADS1262_FILTER_SINC1			0
+#define ADS1262_FILTER_SINC2			1
+#define ADS1262_FILTER_SINC3			2
+#define ADS1262_FILTER_SINC4			3
+#define ADS1262_FILTER_FIR			4
+
+/* MODE1 SENSOR BIAS constants */
+#define ADS1262_SBADC_COUNT			2
+#define ADS1262_SBPOL_COUNT			2
+#define ADS1262_SBMAG_COUNT			7
+
+/* MODE2 DATA RATE constants */
+#define ADS1262_DR_2_5_SPS			0
+#define ADS1262_DR_5_SPS			1
+#define ADS1262_DR_10_SPS			2
+#define ADS1262_DR_16_6_SPS			3
+#define ADS1262_DR_20_SPS			4
+#define ADS1262_DR_50_SPS			5
+#define ADS1262_DR_60_SPS			6
+#define ADS1262_DR_100_SPS			7
+#define ADS1262_DR_400_SPS			8
+#define ADS1262_DR_1200_SPS			9
+#define ADS1262_DR_2400_SPS			10
+#define ADS1262_DR_4800_SPS			11
+#define ADS1262_DR_7200_SPS			12
+#define ADS1262_DR_14400_SPS			13
+#define ADS1262_DR_19200_SPS			14
+#define ADS1262_DR_38400_SPS			15
+
+/* INPMUX constants */
+#define ADS1262_INPMUX_AINCOM			10
+#define ADS1262_INPMUX_TEMP			11
+#define ADS1262_INPMUX_AVDD			12
+#define ADS1262_INPMUX_DVDD			13
+#define ADS1262_INPMUX_TDAC			14
+#define ADS1262_INPMUX_FLOAT			15
+
+/* IDACMUX constants */
+#define ADS1262_IDACMUX_NO_CONN			11
+#define ADS1262_IDACMUX_COUNT			12
+
+/* IDACMAG constants */
+#define ADS1262_IDACMAG_OFF			0
+#define ADS1262_IDACMAG_COUNT			11
+
+/* REFMUX constants */
+#define ADS1262_RMUX_INTER			0
+#define ADS1262_RMUX_AIN0_AIN1			1
+#define ADS1262_RMUX_AIN2_AIN3			2
+#define ADS1262_RMUX_AIN4_AIN5			3
+#define ADS1262_RMUX_AVDD_AVSS			4
+#define ADS1262_RMUX_COUNT			5
+
+struct ads1262_channel {
+	/* MODE0 */
+	u8 conv_delay:4;
+	u8 chop_mode:1;
+	u8 idac_rot_mode:1;
+	u8 runmode:1;
+	u8 rev_vref_pol:1;
+
+	/* MODE1 */
+	u8 sbias_magnitude:3;
+	u8 sbias_polarity:1;
+	u8 sbias_connection:1;
+	u8 filter:3;
+
+	/* MODE2 */
+	u8 data_rate:4;
+	u8 gain:3;
+	u8 pga_bypass:1;
+
+	/* INPMUX */
+	u8 negative_input:4;
+	u8 positive_input:4;
+};
+
+struct ads1262 {
+	struct spi_device *spi;
+	struct regmap *regmap;
+	struct iio_dev *indio_dev;
+	struct iio_trigger *trig;
+	struct gpio_desc *reset_gpiod;
+	struct gpio_desc *start_gpiod;
+
+	void *scan_buffer;
+	size_t scan_sz;
+
+	/* Protects channel state */
+	struct mutex chan_lock;
+	u32 vref_uV;
+	unsigned int num_channels;
+	struct ads1262_channel *channels;
+	struct completion drdy;
+	struct spi_message msg;
+	struct spi_transfer xfer;
+
+	/* Protects transfer buffers and concurrent SPI transfers */
+	struct mutex xfer_lock;
+
+	u8 tx[6] __aligned(IIO_DMA_MINALIGN);
+	union {
+		u8 rx[6];
+		struct {
+			__be32 data;
+		} __packed shift_reg;
+		struct {
+			u8 dummy;
+			__be32 data;
+		} __packed holding_reg;
+	};
+};
+
+static const int ads1262_data_rate_avail[][2] = {
+	[ADS1262_DR_2_5_SPS]	= { 2,		500000 },
+	[ADS1262_DR_5_SPS]	= { 5,		0 },
+	[ADS1262_DR_10_SPS]	= { 10,		0 },
+	[ADS1262_DR_16_6_SPS]	= { 16,		666667 },
+	[ADS1262_DR_20_SPS]	= { 20,		0 },
+	[ADS1262_DR_50_SPS]	= { 50,		0 },
+	[ADS1262_DR_60_SPS]	= { 60,		0 },
+	[ADS1262_DR_100_SPS]	= { 100,	0 },
+	[ADS1262_DR_400_SPS]	= { 400,	0 },
+	[ADS1262_DR_1200_SPS]	= { 1200,	0 },
+	[ADS1262_DR_2400_SPS]	= { 2400,	0 },
+	[ADS1262_DR_4800_SPS]	= { 4800,	0 },
+	[ADS1262_DR_7200_SPS]	= { 7200,	0 },
+	[ADS1262_DR_14400_SPS]	= { 14400,	0 },
+	[ADS1262_DR_19200_SPS]	= { 19200,	0 },
+	[ADS1262_DR_38400_SPS]	= { 38400,	0 },
+};
+
+static const int ads1262_conv_delay_avail[][2] = {
+	{ 0, 0 },
+	{ 0, 8700 },
+	{ 0, 17000 },
+	{ 0, 35000 },
+	{ 0, 69000 },
+	{ 0, 139000 },
+	{ 0, 278000 },
+	{ 0, 555000 },
+	{ 0, 1100000 },
+	{ 0, 2200000 },
+	{ 0, 4400000 },
+	{ 0, 8800000 },
+};
+
+static const int ads1262_pga_gain_avail[] = {
+	1, 2, 4, 8, 16, 32
+};
+
+static int ads1262_dev_power_on(struct ads1262 *st)
+{
+	int ret;
+
+	ret = gpiod_set_value_cansleep(st->reset_gpiod, 0);
+	if (ret)
+		return ret;
+
+	fsleep(9 * USEC_PER_MSEC);
+
+	return 0;
+}
+
+static int ads1262_dev_power_off(struct ads1262 *st)
+{
+	int ret;
+
+	ret = gpiod_set_value_cansleep(st->reset_gpiod, 1);
+	if (ret)
+		return ret;
+
+	fsleep(9 * USEC_PER_MSEC);
+
+	return 0;
+}
+
+static int ads1262_dev_cmd(struct ads1262 *st, u8 opcode)
+{
+	guard(mutex)(&st->xfer_lock);
+
+	st->tx[0] = opcode;
+
+	return spi_write(st->spi, &st->tx[0], sizeof(st->tx[0]));
+}
+
+static int ads1262_dev_read_data_command(struct ads1262 *st, u8 cmd,
+					 __be32 *val)
+{
+	int ret;
+
+	guard(mutex)(&st->xfer_lock);
+
+	memset(st->tx, 0, sizeof(st->tx));
+	st->tx[0] = cmd;
+
+	ret = spi_sync(st->spi, &st->msg);
+	if (ret)
+		return ret;
+
+	*val = st->holding_reg.data;
+
+	return 0;
+}
+
+static int ads1262_dev_read_data_direct(struct ads1262 *st, __be32 *val)
+{
+	int ret;
+
+	/*
+	 * If reading data from the shift register, we should already be holding
+	 * the xfer_lock because all SPI activity is forbidden between the START
+	 * command and the actual data retrieval.
+	 */
+	lockdep_assert_held(&st->xfer_lock);
+
+	memset(st->tx, 0, sizeof(st->tx));
+	ret = spi_sync(st->spi, &st->msg);
+	if (ret)
+		return ret;
+
+	*val = st->shift_reg.data;
+
+	return 0;
+}
+
+static int ads1262_dev_reset(struct ads1262 *st)
+{
+	int ret;
+
+	if (st->reset_gpiod)
+		ret = gpiod_set_value_cansleep(st->reset_gpiod, 1);
+	else
+		ret = ads1262_dev_cmd(st, ADS1262_OPCODE_RESET);
+	if (ret)
+		return ret;
+
+	fsleep(1);
+
+	if (st->reset_gpiod) {
+		ret = gpiod_set_value_cansleep(st->reset_gpiod, 0);
+		fsleep(1);
+	}
+
+	return ret;
+}
+
+static int ads1262_dev_start(struct ads1262 *st)
+{
+	int ret;
+
+	if (st->start_gpiod)
+		ret = gpiod_set_value_cansleep(st->start_gpiod, 1);
+	else
+		ret = ads1262_dev_cmd(st, ADS1262_OPCODE_START1);
+
+	return ret;
+}
+
+static int ads1262_dev_stop(struct ads1262 *st)
+{
+	int ret;
+
+	if (st->start_gpiod)
+		ret = gpiod_set_value_cansleep(st->start_gpiod, 0);
+	else
+		ret = ads1262_dev_cmd(st, ADS1262_OPCODE_STOP1);
+
+	return ret;
+}
+
+static int ads1262_dev_start_one(struct ads1262 *st, u8 runmode)
+{
+	int ret;
+
+	ret = ads1262_dev_start(st);
+	if (ret)
+		return ret;
+
+	if (runmode == ADS1262_RUNMODE_CONTINUOUS)
+		return ads1262_dev_stop(st);
+
+	return 0;
+}
+
+static void ads1262_wait_for_conversion(struct ads1262 *st)
+{
+	reinit_completion(&st->drdy);
+
+	/*
+	 * The first conversion latency is affected by the channel's data rate,
+	 * filter, the configurable conversion delay and whether chop mode
+	 * and/or IDAC rotation mode are enabled.
+	 *
+	 * The worst possible latency is calculated by taking the lowest data
+	 * rate (2.5 SPS) and the sinc4 filter. This gives a latency of 1600 ms
+	 * (Table 9-13). Then add the slowest configurable conversion delay
+	 * (9 ms) and multiply by 4 to account for chop and IDAC rotation modes
+	 * (Equation 20).
+	 *
+	 * Final result is 4 * (1600 ms + 9 ms) = 6436.
+	 */
+	wait_for_completion_timeout(&st->drdy, msecs_to_jiffies(6436));
+}
+
+static void ads1262_channel_set_runmode(struct ads1262 *st,
+					struct ads1262_channel *chan,
+					u8 runmode)
+{
+	guard(mutex)(&st->chan_lock);
+	chan->runmode = runmode;
+}
+
+static int ads1262_channel_enable_and_read(struct ads1262 *st,
+					   struct ads1262_channel *chan,
+					   __be32 *val)
+{
+	int ret;
+
+	lockdep_assert_held(&st->xfer_lock);
+
+	/*
+	 * Prepare the transfer buffer to do bulk register write
+	 * (Section 9.5.6).
+	 */
+	st->tx[0] = ADS1262_MODE0_REG | ADS1262_OPCODE_WREG;
+	st->tx[1] = sizeof(*chan) - 1;
+
+	/*
+	 * The ads1262_channel struct can be written directly to the chip's
+	 * configuration registers (MODE0, MODE1, MODE2, INPMUX) in a single
+	 * transfer, so it's necessary to assert it's size (4 bytes).
+	 */
+	static_assert(sizeof(*chan) == 4);
+	mutex_lock(&st->chan_lock);
+	memcpy(&st->tx[2], chan, sizeof(*chan));
+	mutex_unlock(&st->chan_lock);
+
+	ret = spi_sync(st->spi, &st->msg);
+	if (ret)
+		return ret;
+
+	/*
+	 * If new data is ready, it's shifted out on the same transfer.
+	 * (Section 9.4.7.1)
+	 */
+	if (val)
+		*val = st->shift_reg.data;
+
+	return 0;
+}
+
+static int ads1262_channel_enable(struct ads1262 *st,
+				  struct ads1262_channel *chan)
+{
+	guard(mutex)(&st->xfer_lock);
+
+	return ads1262_channel_enable_and_read(st, chan, NULL);
+}
+
+static int ads1262_channel_hot_reload(struct ads1262 *st,
+				      const struct iio_chan_spec *chan)
+{
+	unsigned int weight;
+	unsigned long i;
+	int ret;
+
+	/*
+	 * Hot reloading is only required on buffer mode and if only one channel
+	 * is enabled.
+	 */
+	if (!iio_device_try_claim_buffer_mode(st->indio_dev))
+		return 0;
+
+	weight = bitmap_weight(st->indio_dev->active_scan_mask,
+			       iio_get_masklength(st->indio_dev));
+	if (weight != 1) {
+		iio_device_release_direct(st->indio_dev);
+		return 0;
+	}
+
+	i = find_first_bit(st->indio_dev->active_scan_mask,
+			   iio_get_masklength(st->indio_dev));
+	if (i != chan->scan_index) {
+		iio_device_release_direct(st->indio_dev);
+		return 0;
+	}
+
+	/*
+	 * The device automatically hot reloads the channel after writing to
+	 * the configuration registers.
+	 */
+	ret = ads1262_channel_enable(st, &st->channels[chan->scan_index]);
+
+	iio_device_release_direct(st->indio_dev);
+
+	return ret;
+}
+
+static int ads1262_channel_read(struct ads1262 *st,
+				struct ads1262_channel *chan_data,
+				__be32 *val)
+{
+	struct device *dev = &st->spi->dev;
+	u8 runmode;
+	int ret;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+		return -ENXIO;
+
+	IIO_DEV_ACQUIRE_DIRECT_MODE(st->indio_dev, claim);
+	if (IIO_DEV_ACQUIRE_FAILED(claim))
+		return -EBUSY;
+
+	/*
+	 * When a channel has chop mode or IDAC rotation mode, the first
+	 * conversion is always withheld so the datasheet suggests using the
+	 * CONTINUOUS mode and briefly starting and stopping conversions to
+	 * achieve the same effect (Section 9.4.1.2).
+	 */
+	if (chan_data->chop_mode || chan_data->idac_rot_mode)
+		runmode = ADS1262_RUNMODE_CONTINUOUS;
+	else
+		runmode = ADS1262_RUNMODE_PULSE;
+
+	ads1262_channel_set_runmode(st, chan_data, runmode);
+
+	ret = ads1262_channel_enable(st, chan_data);
+	if (ret)
+		return ret;
+
+	ret = ads1262_dev_start_one(st, runmode);
+	if (ret)
+		return ret;
+
+	ads1262_wait_for_conversion(st);
+
+	return ads1262_dev_read_data_command(st, ADS1262_OPCODE_RDATA1, val);
+}
+
+static int ads1262_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan, int *val,
+			    int *val2, long mask)
+{
+	struct ads1262 *st = iio_priv(indio_dev);
+	struct ads1262_channel *chan_data;
+	u8 mode, realbits;
+	__be32 raw;
+	u32 cnv;
+	int ret;
+
+	chan_data = &st->channels[chan->scan_index];
+	realbits = chan->scan_type.realbits;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ads1262_channel_read(st, chan_data, &raw);
+		if (ret)
+			return ret;
+
+		cnv = be32_to_cpu(raw);
+		*val = sign_extend32(cnv, realbits - 1);
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		u64 divd, divr, tmp, rem;
+
+		mutex_lock(&st->chan_lock);
+		divd = st->vref_uV;
+		divr = BIT_ULL(chan_data->gain + realbits - 1) * 1000;
+		mutex_unlock(&st->chan_lock);
+
+		tmp = div64_u64(divd * 1000000000ULL, divr);
+		*val = div64_u64_rem(tmp, 1000000000ULL, &rem);
+		*val2 = rem;
+
+		return IIO_VAL_INT_PLUS_NANO;
+
+	case IIO_CHAN_INFO_HARDWAREGAIN:
+		mutex_lock(&st->chan_lock);
+		*val = ads1262_pga_gain_avail[chan_data->gain];
+		mutex_unlock(&st->chan_lock);
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		mutex_lock(&st->chan_lock);
+		mode = chan_data->data_rate;
+		mutex_unlock(&st->chan_lock);
+
+		*val = ads1262_data_rate_avail[mode][0];
+		*val2 = ads1262_data_rate_avail[mode][1];
+		return IIO_VAL_INT_PLUS_MICRO;
+
+	case IIO_CHAN_INFO_CONVDELAY:
+		mutex_lock(&st->chan_lock);
+		mode = chan_data->conv_delay;
+		mutex_unlock(&st->chan_lock);
+
+		*val = ads1262_conv_delay_avail[mode][0];
+		*val2 = ads1262_conv_delay_avail[mode][1];
+		return IIO_VAL_INT_PLUS_NANO;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int ads1262_read_avail(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan, const int **vals,
+			      int *type, int *length, long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		*type = IIO_VAL_INT_PLUS_MICRO;
+		*vals = (const int *)ads1262_data_rate_avail;
+		*length = ARRAY_SIZE(ads1262_data_rate_avail) * 2;
+		return IIO_AVAIL_LIST;
+
+	case IIO_CHAN_INFO_HARDWAREGAIN:
+		*type = IIO_VAL_INT;
+		*vals = ads1262_pga_gain_avail;
+		*length = ARRAY_SIZE(ads1262_pga_gain_avail);
+		return IIO_AVAIL_LIST;
+
+	case IIO_CHAN_INFO_CONVDELAY:
+		*type = IIO_VAL_INT_PLUS_NANO;
+		*vals = (const int *)ads1262_conv_delay_avail;
+		*length = ARRAY_SIZE(ads1262_conv_delay_avail) * 2;
+		return IIO_AVAIL_LIST;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int ads1262_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan, int val,
+			     int val2, long mask)
+{
+	struct ads1262 *st = iio_priv(indio_dev);
+	struct ads1262_channel *chan_data;
+	unsigned int i;
+
+	chan_data = &st->channels[chan->scan_index];
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		for (i = 0; i < ARRAY_SIZE(ads1262_data_rate_avail); i++) {
+			if (val == ads1262_data_rate_avail[i][0] &&
+			    val2 == ads1262_data_rate_avail[i][1])
+				break;
+		}
+		if (i == ARRAY_SIZE(ads1262_data_rate_avail))
+			return -EINVAL;
+
+		mutex_lock(&st->chan_lock);
+		chan_data->data_rate = i;
+		mutex_unlock(&st->chan_lock);
+
+		break;
+
+	case IIO_CHAN_INFO_HARDWAREGAIN:
+		for (i = 0; i < ARRAY_SIZE(ads1262_pga_gain_avail); i++) {
+			if (val == ads1262_pga_gain_avail[i])
+				break;
+		}
+		if (i == ARRAY_SIZE(ads1262_pga_gain_avail))
+			return -EINVAL;
+
+		mutex_lock(&st->chan_lock);
+		chan_data->gain = i;
+		mutex_unlock(&st->chan_lock);
+
+		break;
+
+	case IIO_CHAN_INFO_CONVDELAY:
+		for (i = 0; i < ARRAY_SIZE(ads1262_conv_delay_avail); i++) {
+			if (val == ads1262_conv_delay_avail[i][0] &&
+			    val2 == ads1262_conv_delay_avail[i][1])
+				break;
+		}
+		if (i == ARRAY_SIZE(ads1262_conv_delay_avail))
+			return -EINVAL;
+
+		mutex_lock(&st->chan_lock);
+		chan_data->conv_delay = i;
+		mutex_unlock(&st->chan_lock);
+
+		break;
+
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return ads1262_channel_hot_reload(st, chan);
+}
+
+static int ads1262_write_raw_get_fmt(struct iio_dev *indio_dev,
+				     struct iio_chan_spec const *chan, long mask)
+{
+	switch (mask) {
+	case IIO_CHAN_INFO_CONVDELAY:
+		return IIO_VAL_INT_PLUS_NANO;
+	default:
+		return IIO_VAL_INT_PLUS_MICRO;
+	}
+}
+
+static int ads1262_debugfs_reg_access(struct iio_dev *indio_dev, unsigned int reg,
+				      unsigned int writeval, unsigned int *readval)
+{
+	struct ads1262 *st = iio_priv(indio_dev);
+	struct device *dev = &st->spi->dev;
+
+	PM_RUNTIME_ACQUIRE_AUTOSUSPEND(dev, pm);
+	if (PM_RUNTIME_ACQUIRE_ERR(&pm))
+		return -ENXIO;
+
+	if (readval)
+		return regmap_read_bypassed(st->regmap, reg, readval);
+
+	return regmap_write(st->regmap, reg, writeval);
+}
+
+static const struct iio_info ads1262_iio_info = {
+	.read_raw = ads1262_read_raw,
+	.read_avail = ads1262_read_avail,
+	.write_raw = ads1262_write_raw,
+	.write_raw_get_fmt = ads1262_write_raw_get_fmt,
+	.debugfs_reg_access = ads1262_debugfs_reg_access,
+};
+
+static int ads1262_get_filter_type(struct iio_dev *indio_dev,
+				   const struct iio_chan_spec *chan)
+{
+	struct ads1262 *st = iio_priv(indio_dev);
+	struct ads1262_channel *chan_data;
+
+	guard(mutex)(&st->chan_lock);
+
+	chan_data = &st->channels[chan->scan_index];
+	return chan_data->filter;
+}
+
+static int ads1262_set_filter_type(struct iio_dev *indio_dev,
+				   const struct iio_chan_spec *chan,
+				   unsigned int val)
+{
+	struct ads1262 *st = iio_priv(indio_dev);
+	struct ads1262_channel *chan_data;
+
+	/* Can't guard() the lock here to avoid deadlock when hot reloading */
+	mutex_lock(&st->chan_lock);
+	chan_data = &st->channels[chan->scan_index];
+	chan_data->filter = val;
+	mutex_unlock(&st->chan_lock);
+
+	return ads1262_channel_hot_reload(st, chan);
+}
+
+static const char * const ads1262_filter_type_labels[] = {
+	[ADS1262_FILTER_SINC1] = "sinc1",
+	[ADS1262_FILTER_SINC2] = "sinc2",
+	[ADS1262_FILTER_SINC3] = "sinc3",
+	[ADS1262_FILTER_SINC4] = "sinc4",
+	[ADS1262_FILTER_FIR] = "fir",
+};
+
+static const struct iio_enum ads1262_filter_type_enum = {
+	.items = ads1262_filter_type_labels,
+	.num_items = ARRAY_SIZE(ads1262_filter_type_labels),
+	.get = ads1262_get_filter_type,
+	.set = ads1262_set_filter_type,
+};
+
+static const struct iio_chan_spec_ext_info ads1262_ext_info[] = {
+	IIO_ENUM("filter_type", IIO_SEPARATE, &ads1262_filter_type_enum),
+	IIO_ENUM_AVAILABLE("filter_type", IIO_SHARED_BY_TYPE,
+			   &ads1262_filter_type_enum),
+	{ }
+};
+
+static const struct iio_chan_spec ads1262_iio_voltage_template = {
+	.type = IIO_VOLTAGE,
+	.indexed = true,
+	.scan_type = {
+		.format = IIO_SCAN_FORMAT_SIGNED_INT,
+		.realbits = 32,
+		.storagebits = 32,
+		.endianness = IIO_BE,
+	},
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+			      BIT(IIO_CHAN_INFO_SCALE) |
+			      BIT(IIO_CHAN_INFO_HARDWAREGAIN) |
+			      BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+			      BIT(IIO_CHAN_INFO_CONVDELAY),
+	.info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_HARDWAREGAIN) |
+					     BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+					     BIT(IIO_CHAN_INFO_CONVDELAY),
+	.ext_info = ads1262_ext_info,
+};
+
+static irqreturn_t ads1262_irq_handler(int irq, void *dev_id)
+{
+	struct ads1262 *st = dev_id;
+
+	if (iio_buffer_enabled(st->indio_dev))
+		iio_trigger_poll(st->trig);
+
+	complete(&st->drdy);
+
+	return IRQ_HANDLED;
+}
+
+static int ads1262_buffer_preenable(struct iio_dev *indio_dev)
+{
+	struct ads1262 *st = iio_priv(indio_dev);
+	struct device *dev = &st->spi->dev;
+	unsigned int weight;
+	unsigned long i;
+	int ret;
+
+	weight = bitmap_weight(indio_dev->active_scan_mask,
+			       iio_get_masklength(indio_dev));
+	st->scan_sz = ALIGN(sizeof(__be32) * weight, sizeof(s64));
+	st->scan_sz += sizeof(s64);
+	st->scan_buffer = kzalloc(st->scan_sz, GFP_KERNEL);
+	if (!st->scan_buffer)
+		return -ENOMEM;
+
+	ret = spi_optimize_message(st->spi, &st->msg);
+	if (ret)
+		goto out_state_cleanup;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		goto out_unoptimize_message;
+
+	iio_for_each_active_channel(indio_dev, i)
+		ads1262_channel_set_runmode(st, &st->channels[i],
+					    ADS1262_RUNMODE_CONTINUOUS);
+
+	if (weight == 1) {
+		i = find_first_bit(indio_dev->active_scan_mask,
+				   iio_get_masklength(indio_dev));
+		ret = ads1262_channel_enable(st, &st->channels[i]);
+		if (ret)
+			goto out_runtime_autosuspend;
+	}
+
+	ret = ads1262_dev_start(st);
+	if (ret)
+		goto out_runtime_autosuspend;
+
+	return 0;
+
+out_runtime_autosuspend:
+	pm_runtime_put_autosuspend(dev);
+
+out_unoptimize_message:
+	spi_unoptimize_message(&st->msg);
+
+out_state_cleanup:
+	kfree(st->scan_buffer);
+	st->scan_buffer = NULL;
+	st->scan_sz = 0;
+
+	return ret;
+}
+
+static int ads1262_buffer_postdisable(struct iio_dev *indio_dev)
+{
+	struct ads1262 *st = iio_priv(indio_dev);
+	struct device *dev = &st->spi->dev;
+
+	ads1262_dev_stop(st);
+	pm_runtime_put_autosuspend(dev);
+	spi_unoptimize_message(&st->msg);
+	kfree(st->scan_buffer);
+	st->scan_buffer = NULL;
+	st->scan_sz = 0;
+
+	return 0;
+}
+
+static bool ads1262_validate_scan_mask(struct iio_dev *indio_dev,
+				       const unsigned long *scan_mask)
+{
+	struct ads1262 *st = iio_priv(indio_dev);
+	struct device *dev = &st->spi->dev;
+
+	if (iio_trigger_using_own(indio_dev)) {
+		dev_err(dev, "The %s trigger only supports one active channel\n",
+			st->trig->name);
+		return iio_validate_scan_mask_onehot(indio_dev, scan_mask);
+	}
+
+	return true;
+}
+
+static const struct iio_buffer_setup_ops ads1262_buffer_ops = {
+	.preenable = ads1262_buffer_preenable,
+	.postdisable = ads1262_buffer_postdisable,
+	.validate_scan_mask = ads1262_validate_scan_mask,
+};
+
+static int ads1262_fill_buffer_one(struct ads1262 *st)
+{
+	__be32 *scan_buffer = st->scan_buffer;
+
+	/*
+	 * When only one channel is enabled, we can't really avoid SPI activity
+	 * from happening when the auxiliary ADC is in use, thus we have to read
+	 * from the data-holding register (Section 9.4.7.2).
+	 */
+	return ads1262_dev_read_data_command(st, ADS1262_OPCODE_RDATA1,
+					     scan_buffer);
+}
+
+static int ads1262_fill_buffer_mult(struct ads1262 *st)
+{
+	__be32 val, *scan_buffer = st->scan_buffer;
+	unsigned int chan;
+	int i = -1;
+	int ret;
+
+	/*
+	 * This routine enables and reads channels in a full-duplex fashion.
+	 *
+	 * When a channel is enabled, the previous conversion is clocked out of
+	 * the shift data register on the same transfer (Section 9.4.7.1). This
+	 * allows for low latency software sequencing but forbids any SPI
+	 * activity happen in between or data corruption may occur, hence the
+	 * need to take the xfer_lock for the whole operation.
+	 */
+
+	guard(mutex)(&st->xfer_lock);
+
+	iio_for_each_active_channel(st->indio_dev, chan) {
+		ret = ads1262_channel_enable_and_read(st, &st->channels[chan],
+						      &val);
+		if (ret)
+			return ret;
+
+		if (i > -1)
+			scan_buffer[i] = val;
+		i++;
+
+		ads1262_wait_for_conversion(st);
+	}
+
+	return ads1262_dev_read_data_direct(st, &scan_buffer[i]);
+}
+
+static irqreturn_t ads1262_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *indio_dev = pf->indio_dev;
+	struct ads1262 *st = iio_priv(indio_dev);
+	s64 ts = pf->timestamp;
+	unsigned int weight;
+	int ret;
+
+	weight = bitmap_weight(indio_dev->active_scan_mask,
+			       iio_get_masklength(indio_dev));
+
+	memset(st->scan_buffer, 0, st->scan_sz);
+
+	if (weight == 1)
+		ret = ads1262_fill_buffer_one(st);
+	else
+		ret = ads1262_fill_buffer_mult(st);
+	if (ret)
+		goto out_notify_done;
+
+	iio_push_to_buffers_with_ts(indio_dev, st->scan_buffer,
+				    st->scan_sz, ts);
+
+out_notify_done:
+	iio_trigger_notify_done(indio_dev->trig);
+
+	return IRQ_HANDLED;
+}
+
+static int ads1262_parse_channel_data(struct ads1262 *st,
+				      struct ads1262_channel *chan_data,
+				      struct fwnode_handle *node)
+{
+	struct device *dev = &st->spi->dev;
+	const char *propname;
+	u32 val;
+	int ret;
+
+	if (fwnode_property_present(node, "ti,pga-bypass"))
+		chan_data->pga_bypass = true;
+
+	if (fwnode_property_present(node, "ti,rev-vref-pol"))
+		chan_data->rev_vref_pol = true;
+
+	if (fwnode_property_present(node, "ti,chop-mode"))
+		chan_data->chop_mode = true;
+
+	if (fwnode_property_present(node, "ti,idac-rotation-mode"))
+		chan_data->idac_rot_mode = true;
+
+	propname = "ti,sbias-connection";
+	if (fwnode_property_present(node, propname)) {
+		ret = fwnode_property_read_u32(node, propname, &val);
+		if (ret)
+			goto err_property_read;
+		if (val >= ADS1262_SBADC_COUNT) {
+			ret = -ERANGE;
+			goto err_property_read;
+		}
+
+		chan_data->sbias_connection = val;
+	}
+
+	propname = "ti,sbias-polarity";
+	if (fwnode_property_present(node, propname)) {
+		ret = fwnode_property_read_u32(node, propname, &val);
+		if (ret)
+			goto err_property_read;
+		if (val >= ADS1262_SBPOL_COUNT) {
+			ret = -ERANGE;
+			goto err_property_read;
+		}
+
+		chan_data->sbias_polarity = val;
+	}
+
+	propname = "ti,sbias-magnitude";
+	if (fwnode_property_present(node, propname)) {
+		ret = fwnode_property_read_u32(node, propname, &val);
+		if (ret)
+			goto err_property_read;
+		if (val >= ADS1262_SBMAG_COUNT) {
+			ret = -ERANGE;
+			goto err_property_read;
+		}
+
+		chan_data->sbias_magnitude = val;
+	}
+
+	return 0;
+
+err_property_read:
+	return dev_err_probe(dev, ret, "%s: Failed to read property %s\n",
+			     fwnode_get_name(node), propname);
+}
+
+static int ads1262_parse_channel_node(struct ads1262 *st,
+				      struct iio_chan_spec *chan,
+				      struct ads1262_channel *chan_data,
+				      struct fwnode_handle *node)
+{
+	struct device *dev = &st->spi->dev;
+	const char *propname;
+	u32 pins[2];
+	int ret;
+
+	propname = "diff-channels";
+	ret = fwnode_property_read_u32_array(node, propname, pins,
+					     ARRAY_SIZE(pins));
+	if (ret)
+		return dev_err_probe(dev, ret, "%s: Failed to read %s\n",
+				     fwnode_get_name(node), propname);
+
+	if (pins[0] > ADS1262_INPMUX_FLOAT)
+		return dev_err_probe(dev, -ENXIO,
+				     "%s: positive input %u not in range\n",
+				     fwnode_get_name(node), pins[0]);
+
+	if (pins[1] > ADS1262_INPMUX_FLOAT)
+		return dev_err_probe(dev, -ENXIO,
+				     "%s: negative input %u not in range\n",
+				     fwnode_get_name(node), pins[1]);
+
+	chan->channel = pins[0];
+	chan->channel2 = pins[1];
+	chan->differential = true;
+
+	chan_data->positive_input = pins[0];
+	chan_data->negative_input = pins[1];
+
+	/* Only non-zero default values are data rate and filter */
+	chan_data->data_rate = ADS1262_DR_20_SPS;
+	chan_data->filter = ADS1262_FILTER_FIR;
+
+	return ads1262_parse_channel_data(st, chan_data, node);
+}
+
+static int ads1262_parse_channels(struct iio_dev *indio_dev)
+{
+	struct ads1262 *st = iio_priv(indio_dev);
+	struct iio_chan_spec *channels, *chan;
+	struct device *dev = &st->spi->dev;
+	struct ads1262_channel *chan_data;
+	unsigned int num_channels;
+	u32 ch_reg;
+	int ret;
+
+	num_channels = device_get_named_child_node_count(dev, "channel");
+	if (!num_channels)
+		return dev_err_probe(dev, -ENXIO,
+				     "No 'channel' nodes configured\n");
+
+	st->num_channels = num_channels;
+	st->channels = devm_kcalloc(dev, num_channels, sizeof(*st->channels),
+				    GFP_KERNEL);
+	if (!st->channels)
+		return -ENOMEM;
+
+	/* Account for the timestamp channel */
+	num_channels++;
+	channels = devm_kcalloc(dev, num_channels, sizeof(*channels),
+				GFP_KERNEL);
+	if (!channels)
+		return -ENOMEM;
+
+	chan = channels;
+	device_for_each_named_child_node_scoped(dev, node, "channel") {
+		ret = fwnode_property_read_u32(node, "reg", &ch_reg);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "%s: Failed to read channel reg\n",
+					     fwnode_get_name(node));
+
+		/* Last channel is reserved for timestamp */
+		if (ch_reg >= num_channels - 1)
+			return dev_err_probe(dev, -EINVAL,
+					     "%s: reg %u out of range\n",
+					     fwnode_get_name(node), ch_reg);
+
+		*chan = ads1262_iio_voltage_template;
+		chan->scan_index = ch_reg;
+		chan_data = &st->channels[ch_reg];
+		ret = ads1262_parse_channel_node(st, chan++, chan_data, node);
+		if (ret)
+			return ret;
+	}
+
+	*chan = (struct iio_chan_spec)IIO_CHAN_SOFT_TIMESTAMP(num_channels - 1);
+
+	indio_dev->num_channels = num_channels;
+	indio_dev->channels = channels;
+
+	return 0;
+}
+
+static int ads1262_read_chip_name(struct ads1262 *st, char **name)
+{
+	struct device *dev = &st->spi->dev;
+	u8 dev_id;
+	unsigned int val;
+	int ret;
+
+	ret = regmap_read(st->regmap, ADS1262_ID_REG, &val);
+	if (ret)
+		return ret;
+
+	dev_id = FIELD_GET(ADS1262_DEV_ID_MASK, val);
+
+	switch (dev_id) {
+	case ADS1262_DEV_ID_ADS1262:
+		*name = "ads1262";
+		break;
+	case ADS1262_DEV_ID_ADS1263:
+		*name = "ads1263";
+		break;
+	default:
+		*name = "ads1262";
+		dev_dbg(dev, "Failed to identify device with ID 0x%x\n", val);
+	}
+
+	return 0;
+}
+
+static int ads1262_parse_idac_pins(struct ads1262 *st, u32 *pins,
+				   unsigned int num_pins)
+{
+	struct device *dev = &st->spi->dev;
+	char propname[10];
+	u32 val;
+	int ret;
+
+	for (unsigned int i = 0; i < num_pins; i++) {
+		scnprintf(propname, sizeof(propname), "idac%d-pin", i + 1);
+		if (!device_property_present(dev, propname)) {
+			pins[i] = ADS1262_IDACMUX_NO_CONN;
+			continue;
+		}
+
+		ret = device_property_read_u32(dev, propname, &val);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "Failed to read property %s\n",
+					     propname);
+		if (val < ADS1262_IDACMUX_COUNT)
+			return dev_err_probe(dev, -EINVAL,
+					     "%s: Pin number out of range %d\n",
+					     propname, val);
+
+		pins[i] = val;
+	}
+
+	return 0;
+}
+
+static int ads1262_parse_idac_mags(struct ads1262 *st, u32 *mags,
+				   unsigned int num_mags)
+{
+	static const u32 idac_microamps[] = {
+		0, 50, 100, 250, 500, 750, 1000, 1500, 2000, 2500, 3000
+	};
+	struct device *dev = &st->spi->dev;
+	unsigned int mode;
+	char propname[15];
+	u32 val;
+	int ret;
+
+	for (unsigned int i = 0; i < num_mags; i++) {
+		scnprintf(propname, sizeof(propname), "idac%d-microamp", i + 1);
+		if (!device_property_present(dev, propname)) {
+			mags[i] = ADS1262_IDACMAG_OFF;
+			continue;
+		}
+
+		ret = device_property_read_u32(dev, propname, &val);
+		if (ret)
+			return dev_err_probe(dev, ret,
+					     "Failed to read property %s\n",
+					     propname);
+
+		for (mode = 0; mode < ARRAY_SIZE(idac_microamps); i++) {
+			if (val == idac_microamps[mode])
+				break;
+		}
+		if (mode == ARRAY_SIZE(idac_microamps))
+			return dev_err_probe(dev, -EINVAL,
+					     "%s: Invalid value %d\n",
+					     propname, val);
+
+		mags[i] = mode;
+	}
+
+	return 0;
+}
+
+static int ads1262_dev_configure(struct ads1262 *st)
+{
+	struct device *dev = &st->spi->dev;
+	u32 idac_pins[2], idac_mags[2];
+	u8 val;
+	int ret;
+
+	ret = ads1262_dev_reset(st);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to reset device\n");
+
+	ret = regmap_update_bits(st->regmap, ADS1262_INTERFACE_REG,
+				 ADS1262_INTERFACE_STATUS_MASK |
+				 ADS1262_INTERFACE_CRC_MASK, 0);
+	if (ret)
+		return ret;
+
+	if (device_property_present(dev, "ti,vbias")) {
+		ret = regmap_update_bits(st->regmap, ADS1262_POWER_REG,
+					 ADS1262_POWER_VBIAS_MASK,
+					 ADS1262_POWER_VBIAS_MASK);
+		if (ret)
+			return ret;
+	}
+
+	ret = ads1262_parse_idac_pins(st, idac_pins, ARRAY_SIZE(idac_pins));
+	if (ret)
+		return ret;
+
+	ret = ads1262_parse_idac_mags(st, idac_mags, ARRAY_SIZE(idac_mags));
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(ADS1262_IDACMUX_MUX1_MASK, idac_pins[0]);
+	val |= FIELD_PREP(ADS1262_IDACMUX_MUX2_MASK, idac_pins[1]);
+
+	ret = regmap_update_bits(st->regmap, ADS1262_IDACMUX_REG,
+				 ADS1262_IDACMUX_MUX1_MASK |
+				 ADS1262_IDACMUX_MUX2_MASK, val);
+	if (ret)
+		return ret;
+
+	val = FIELD_PREP(ADS1262_IDACMAG_MAG1_MASK, idac_mags[0]);
+	val |= FIELD_PREP(ADS1262_IDACMAG_MAG2_MASK, idac_mags[1]);
+
+	return regmap_update_bits(st->regmap, ADS1262_IDACMAG_REG,
+				  ADS1262_IDACMAG_MAG1_MASK |
+				  ADS1262_IDACMAG_MAG2_MASK, val);
+}
+
+static int ads1262_gpio_setup(struct ads1262 *st)
+{
+	struct device *dev = &st->spi->dev;
+	struct gpio_desc *gpiod;
+	const char *con_id;
+
+	con_id = "start";
+	gpiod = devm_gpiod_get_optional(dev, con_id, GPIOD_OUT_LOW);
+	if (IS_ERR(gpiod))
+		return dev_err_probe(dev, PTR_ERR(gpiod),
+				     "Failed to get %s GPIO\n", con_id);
+	st->start_gpiod = gpiod;
+
+	con_id = "reset";
+	gpiod = devm_gpiod_get_optional(dev, con_id, GPIOD_OUT_HIGH);
+	if (IS_ERR(gpiod))
+		return dev_err_probe(dev, PTR_ERR(gpiod),
+				     "Failed to get %s GPIO\n", con_id);
+	st->reset_gpiod = gpiod;
+
+	return 0;
+}
+
+static int ads1262_clk_setup(struct ads1262 *st)
+{
+	struct device *dev = &st->spi->dev;
+	struct clk *clk;
+	int ret;
+
+	clk = devm_clk_get_optional_enabled(dev, NULL);
+	if (IS_ERR(clk))
+		return dev_err_probe(dev, PTR_ERR(clk),
+				     "Failed to get external clock\n");
+
+	/*
+	 * The nominal clock frequency as indicated by the datasheet is
+	 * 7372800.
+	 */
+	ret = clk_set_rate(clk, 7372800);
+	if (ret)
+		return dev_err_probe(dev, PTR_ERR(clk),
+				     "Failed to set the nominal clock frequency.\n");
+
+	return 0;
+}
+
+static int ads1262_regulator_setup(struct ads1262 *st)
+{
+	struct device *dev = &st->spi->dev;
+	const char *reg_id, *prop;
+	u32 mux[2] = {};
+	int val, ret;
+
+	reg_id = "dvdd";
+	ret = devm_regulator_get_enable(dev, reg_id);
+	if (ret)
+		goto err_regulator_get;
+
+	reg_id = "avdd";
+	ret = devm_regulator_get_enable(dev, reg_id);
+	if (ret)
+		goto err_regulator_get;
+
+	prop = "ti,neg-refmux";
+	device_property_read_u32(dev, prop, &mux[0]);
+	if (mux[0] >= ADS1262_RMUX_COUNT)
+		return dev_err_probe(dev, -ENXIO, " %s out of range\n", prop);
+
+	prop = "ti,pos-refmux";
+	device_property_read_u32(dev, prop, &mux[1]);
+	if (mux[1] >= ADS1262_RMUX_COUNT)
+		return dev_err_probe(dev, -ENXIO, " %s out of range\n", prop);
+
+	if (mux[0] == ADS1262_RMUX_INTER && mux[1] == ADS1262_RMUX_INTER) {
+		/* The internal voltage reference is 2.5 V */
+		st->vref_uV = 2500000;
+		return 0;
+	}
+
+	val = FIELD_PREP(ADS1262_REFMUX_RMUXN_MASK, mux[0]);
+	val |= FIELD_PREP(ADS1262_REFMUX_RMUXP_MASK, mux[1]);
+	ret = regmap_update_bits(st->regmap, ADS1262_REFMUX_REG,
+				 ADS1262_REFMUX_RMUXN_MASK |
+				 ADS1262_REFMUX_RMUXP_MASK, val);
+	if (ret)
+		return ret;
+
+	reg_id = "vref";
+	st->vref_uV = devm_regulator_get_enable_read_voltage(dev, reg_id);
+	if (st->vref_uV < 0)
+		goto err_regulator_get;
+
+	return 0;
+
+err_regulator_get:
+	return dev_err_probe(dev, ret, "Failed to get regulator %s\n", reg_id);
+}
+
+static int ads1262_spi_message_setup(struct ads1262 *st)
+{
+	st->xfer.tx_buf = st->tx;
+	st->xfer.rx_buf = st->rx;
+	st->xfer.len = sizeof(st->tx);
+	spi_message_init_with_transfers(&st->msg, &st->xfer, 1);
+
+	return 0;
+}
+
+static const struct regmap_range ads1262_read_write_range[] = {
+	regmap_reg_range(ADS1262_ID_REG, ADS1262_ADC2FSC1_REG),
+};
+
+static const struct regmap_range ads1262_read_only_range[] = {
+	regmap_reg_range(ADS1262_ID_REG, ADS1262_ID_REG),
+};
+
+static const struct regmap_range ads1262_volatile_range[] = {
+	/*
+	 * The channel configuration registers (MODE0, MODE1, MODE2, INPMUX) are
+	 * not actually volatile. However, we bypass the regmap API when
+	 * writing to these registers for optimization reasons.
+	 */
+	regmap_reg_range(ADS1262_MODE0_REG, ADS1262_INPMUX_REG),
+	regmap_reg_range(ADS1262_GPIODAT_REG, ADS1262_GPIODAT_REG),
+};
+
+static const struct regmap_access_table ads1262_wr_table = {
+	.yes_ranges = ads1262_read_write_range,
+	.n_yes_ranges = ARRAY_SIZE(ads1262_read_write_range),
+	.no_ranges = ads1262_read_only_range,
+	.n_no_ranges = ARRAY_SIZE(ads1262_read_only_range),
+};
+
+static const struct regmap_access_table ads1262_rd_table = {
+	.yes_ranges = ads1262_read_write_range,
+	.n_yes_ranges = ARRAY_SIZE(ads1262_read_write_range),
+};
+
+static const struct regmap_access_table ads1262_volatile_table = {
+	.yes_ranges = ads1262_volatile_range,
+	.n_yes_ranges = ARRAY_SIZE(ads1262_volatile_range),
+};
+
+static const struct reg_default ads1262_reg_defaults[] = {
+	{ ADS1262_POWER_REG,		0x11 },
+	{ ADS1262_INTERFACE_REG,	0x05 },
+	{ ADS1262_MODE0_REG,		0x00 },
+	{ ADS1262_MODE1_REG,		0x80 },
+	{ ADS1262_MODE2_REG,		0x04 },
+	{ ADS1262_INPMUX_REG,		0x01 },
+	{ ADS1262_OFCAL0_REG,		0x00 },
+	{ ADS1262_OFCAL1_REG,		0x00 },
+	{ ADS1262_OFCAL2_REG,		0x00 },
+	{ ADS1262_FSCAL0_REG,		0x00 },
+	{ ADS1262_FSCAL1_REG,		0x00 },
+	{ ADS1262_FSCAL2_REG,		0x40 },
+	{ ADS1262_IDACMUX_REG,		0xBB },
+	{ ADS1262_IDACMAG_REG,		0x00 },
+	{ ADS1262_REFMUX_REG,		0x00 },
+	{ ADS1262_TDACP_REG,		0x00 },
+	{ ADS1262_TDACN_REG,		0x00 },
+	{ ADS1262_GPIOCON_REG,		0x00 },
+	{ ADS1262_GPIODIR_REG,		0x00 },
+	{ ADS1262_GPIODAT_REG,		0x00 },
+	{ ADS1262_ADC2CFG_REG,		0x00 },
+	{ ADS1262_ADC2MUX_REG,		0x01 },
+	{ ADS1262_ADC2OFC0_REG,		0x00 },
+	{ ADS1262_ADC2OFC1_REG,		0x00 },
+	{ ADS1262_ADC2FSC0_REG,		0x00 },
+	{ ADS1262_ADC2FSC1_REG,		0x40 },
+};
+
+static const struct regmap_config ads1262_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.wr_table = &ads1262_wr_table,
+	.rd_table = &ads1262_rd_table,
+	.volatile_table = &ads1262_volatile_table,
+	.reg_defaults = ads1262_reg_defaults,
+	.num_reg_defaults = ARRAY_SIZE(ads1262_reg_defaults),
+	.max_register = ADS1262_ADC2FSC1_REG,
+	.read_flag_mask = ADS1262_OPCODE_RREG,
+	.write_flag_mask = ADS1262_OPCODE_WREG,
+	.can_sleep = true,
+	.cache_type = REGCACHE_MAPLE,
+};
+
+static int ads1262_regmap_read(void *context, const void *reg_buf,
+			       size_t reg_size, void *val_buf, size_t val_size)
+{
+	struct ads1262 *st = context;
+	struct spi_transfer xfer[3] = {
+		{
+			.tx_buf = reg_buf,
+			.len = reg_size,
+		},
+		{
+			.tx_buf = &st->tx[0],
+			.len = sizeof(st->tx[0]),
+		},
+		{
+			.rx_buf = val_buf,
+			.len = val_size,
+		},
+	};
+
+	/*
+	 * It's necessary to lock the xfer_lock for the entirety of the
+	 * operation.
+	 *
+	 * Not only because the tx buffer is shared with conversion read
+	 * transfers, but also because some of these routines require no serial
+	 * activity happen between the DRDY signal and the actual read operation
+	 * (Section 9.4.7.1).
+	 *
+	 * The latter is specially important if the chip supports a second
+	 * auxiliary ADC (Section 9.3.15).
+	 */
+	guard(mutex)(&st->xfer_lock);
+
+	/*
+	 * The register read operation (RREG) allows bulk reading registers and
+	 * has the following structure (Section 9.5):
+	 *
+	 * Byte 1: ADS1262_OPCODE_RREG | REG
+	 * Byte 2: Number of registers minus 1
+	 * Byte 3+: Register data (MISO)
+	 */
+	st->tx[0] = val_size - 1;
+
+	return spi_sync_transfer(st->spi, xfer, ARRAY_SIZE(xfer));
+}
+
+static int ads1262_regmap_gather_write(void *context, const void *reg_buf,
+				       size_t reg_size, const void *val_buf,
+				       size_t val_size)
+{
+	struct ads1262 *st = context;
+	struct spi_transfer xfer[3] = {
+		{
+			.tx_buf = reg_buf,
+			.len = reg_size,
+		},
+		{
+			.tx_buf = &st->tx[0],
+			.len = sizeof(st->tx[0]),
+		},
+		{
+			.tx_buf = val_buf,
+			.len = val_size,
+		},
+	};
+
+	/*
+	 * It's necessary to lock the xfer_lock for the entirety of the
+	 * operation.
+	 *
+	 * Not only because the tx buffer is shared with conversion read
+	 * transfers, but also because some of these routines require no serial
+	 * activity happen between the DRDY signal and the actual read operation
+	 * (Section 9.4.7.1).
+	 *
+	 * The latter is specially important if the chip supports a second
+	 * auxiliary ADC (Section 9.3.15).
+	 */
+	guard(mutex)(&st->xfer_lock);
+
+	/*
+	 * The register write operation (WREG) allows bulk writing registers
+	 * and has the following structure (Section 9.5):
+	 *
+	 * Byte 1: ADS1262_OPCODE_WREG | REG
+	 * Byte 2: Number of registers minus 1
+	 * Byte 3+: Register data (MOSI)
+	 */
+	st->tx[0] = val_size - 1;
+
+	return spi_sync_transfer(st->spi, xfer, ARRAY_SIZE(xfer));
+}
+
+static int ads1262_regmap_write(void *context, const void *data, size_t count)
+{
+	return ads1262_regmap_gather_write(context, data, 1, data + 1,
+					   count - 1);
+}
+
+static const struct regmap_bus ads1262_regmap_bus = {
+	.read = ads1262_regmap_read,
+	.gather_write = ads1262_regmap_gather_write,
+	.write = ads1262_regmap_write,
+	.reg_format_endian_default = REGMAP_ENDIAN_BIG,
+	.val_format_endian_default = REGMAP_ENDIAN_BIG,
+};
+
+static int ads1262_spi_probe(struct spi_device *spi)
+{
+	struct device *dev = &spi->dev;
+	struct iio_dev *indio_dev;
+	struct ads1262 *st;
+	char *name;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*st));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	st = iio_priv(indio_dev);
+	st->spi = spi;
+	st->indio_dev = indio_dev;
+	init_completion(&st->drdy);
+	dev_set_drvdata(dev, st);
+
+	ret = devm_mutex_init(dev, &st->chan_lock);
+	if (ret)
+		return ret;
+	ret = devm_mutex_init(dev, &st->xfer_lock);
+	if (ret)
+		return ret;
+
+	st->regmap = devm_regmap_init(dev, &ads1262_regmap_bus, st,
+				      &ads1262_regmap_config);
+	if (IS_ERR(st->regmap))
+		return PTR_ERR(st->regmap);
+
+	ret = ads1262_spi_message_setup(st);
+	if (ret)
+		return ret;
+
+	ret = ads1262_regulator_setup(st);
+	if (ret)
+		return ret;
+
+	ret = ads1262_clk_setup(st);
+	if (ret)
+		return ret;
+
+	ret = ads1262_gpio_setup(st);
+	if (ret)
+		return ret;
+
+	ret = ads1262_dev_configure(st);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to configure device\n");
+
+	ret = ads1262_read_chip_name(st, &name);
+	if (ret)
+		return ret;
+
+	indio_dev->name = name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &ads1262_iio_info;
+	ret = ads1262_parse_channels(indio_dev);
+	if (ret)
+		return ret;
+
+	ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+					      iio_pollfunc_store_time,
+					      ads1262_trigger_handler,
+					      &ads1262_buffer_ops);
+	if (ret)
+		return ret;
+
+	if (spi->irq > 0) {
+		st->trig = devm_iio_trigger_alloc(dev, "%s-dev%d-drdy", name,
+						  iio_device_id(indio_dev));
+		if (!st->trig)
+			return -ENOMEM;
+		iio_trigger_set_drvdata(st->trig, st);
+		ret = devm_iio_trigger_register(dev, st->trig);
+		if (ret)
+			return ret;
+
+		ret = devm_request_irq(dev, spi->irq, ads1262_irq_handler,
+				       IRQF_NO_THREAD, name, st);
+		if (ret)
+			return ret;
+	}
+
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_set_autosuspend_delay(dev, 10000);
+	pm_runtime_set_active(dev);
+	ret = devm_pm_runtime_enable(dev);
+	if (ret)
+		return ret;
+
+	return devm_iio_device_register(dev, indio_dev);
+}
+
+static int ads1262_runtime_suspend(struct device *dev)
+{
+	struct ads1262 *st = dev_get_drvdata(dev);
+
+	if (!st->reset_gpiod)
+		return 0;
+
+	regcache_cache_only(st->regmap, true);
+
+	return ads1262_dev_power_off(st);
+}
+
+static int ads1262_runtime_resume(struct device *dev)
+{
+	struct ads1262 *st = dev_get_drvdata(dev);
+	int ret;
+
+	if (!st->reset_gpiod)
+		return 0;
+
+	ret = ads1262_dev_power_on(st);
+	if (ret)
+		return ret;
+
+	regcache_cache_only(st->regmap, false);
+	regcache_mark_dirty(st->regmap);
+
+	return regcache_sync(st->regmap);
+}
+
+DEFINE_RUNTIME_DEV_PM_OPS(ads1262_runtime_pm, ads1262_runtime_suspend,
+			  ads1262_runtime_resume, NULL);
+
+static const struct of_device_id ads1262_of_match[] = {
+	{ .compatible = "ti,ads1262" },
+	{ .compatible = "ti,ads1263" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ads1262_of_match);
+
+static const struct spi_device_id ads1262_spi_match[] = {
+	{ "ads1262" },
+	{ "ads1263" },
+	{ }
+};
+MODULE_DEVICE_TABLE(spi, ads1262_spi_match);
+
+static struct spi_driver ads1262_spi_driver = {
+	.driver = {
+		.name = "ads1262",
+		.of_match_table = ads1262_of_match,
+		.pm = pm_ptr(&ads1262_runtime_pm),
+	},
+	.probe = ads1262_spi_probe,
+	.id_table = ads1262_spi_match,
+};
+module_spi_driver(ads1262_spi_driver);
+
+MODULE_DESCRIPTION("Texas Instruments ADS1262 ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kurt Borja <kuurtb@gmail.com>");

-- 
2.54.0


  parent reply	other threads:[~2026-06-12 22:47 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-12 22:46 [PATCH 0/5] iio: adc: Add TI ADS126X ADC family support Kurt Borja
2026-06-12 22:46 ` [PATCH 1/5] dt-bindings: iio: adc: Add TI ADS126x ADC family Kurt Borja
2026-06-13 18:54   ` Krzysztof Kozlowski
2026-06-14 20:53     ` Kurt Borja
2026-06-14 21:37       ` David Lechner
2026-06-14 21:57         ` Kurt Borja
2026-06-15  0:06           ` David Lechner
2026-06-15  4:34       ` Krzysztof Kozlowski
2026-06-15  4:40         ` Kurt Borja
2026-06-12 22:46 ` Kurt Borja [this message]
2026-06-13 13:45   ` [PATCH 2/5] iio: adc: Add ti-ads1262 driver Jonathan Cameron
2026-06-13 14:06     ` Jonathan Cameron
2026-06-14 20:27     ` Kurt Borja
2026-06-21 14:25       ` Jonathan Cameron
2026-06-13 18:59   ` Krzysztof Kozlowski
2026-06-14 13:39     ` Jonathan Cameron
2026-06-15  4:33       ` Krzysztof Kozlowski
2026-06-15  4:42         ` Kurt Borja
2026-06-14 20:56     ` Kurt Borja
2026-06-15  4:30       ` Krzysztof Kozlowski
2026-06-21 14:33         ` Jonathan Cameron
2026-06-22  0:18           ` Kurt Borja
2026-06-22  9:47             ` Jonathan Cameron
2026-06-22 16:42               ` David Lechner
2026-06-12 22:46 ` [PATCH 3/5] iio: adc: ti-ads1262: Add GPIO controller support Kurt Borja
2026-06-13  6:23   ` Kurt Borja
2026-06-12 22:46 ` [PATCH 4/5] iio: adc: ti-ads1262: Add calibration support Kurt Borja
2026-06-13 13:50   ` Jonathan Cameron
2026-06-14 20:31     ` Kurt Borja
2026-06-12 22:46 ` [PATCH 5/5] iio: adc: Add ti-ads1263-adc2 driver Kurt Borja
2026-06-13 14:10   ` Jonathan Cameron
2026-06-14 20:43     ` Kurt Borja
2026-06-21 14:41       ` Jonathan Cameron
2026-06-12 23:50 ` [PATCH 0/5] iio: adc: Add TI ADS126X ADC family support David Lechner
2026-06-13  0:06   ` Kurt Borja

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260612-ads126x-v1-2-894c788d03ed@gmail.com \
    --to=kuurtb@gmail.com \
    --cc=andy@kernel.org \
    --cc=brgl@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dlechner@baylibre.com \
    --cc=jic23@kernel.org \
    --cc=krzk+dt@kernel.org \
    --cc=linusw@kernel.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nuno.sa@analog.com \
    --cc=robh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®