devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs
@ 2025-02-13 15:58 Tobias Sperling via B4 Relay
  2025-02-13 15:58 ` [PATCH v4 1/2] dt-bindings: iio: adc: Introduce ADS7138 Tobias Sperling via B4 Relay
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Tobias Sperling via B4 Relay @ 2025-02-13 15:58 UTC (permalink / raw)
  To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Tobias Sperling, Liam Girdwood,
	Mark Brown
  Cc: linux-iio, devicetree, linux-kernel, Krzysztof Kozlowski

This patch series adds support for Texas Instruments ADS7128 and
ADS7138, which are 12-bit, 8 channel analog-to-digital converters (ADCs)
with build-in digital window comparator (DWC), using the I2C interface.

The driver exposes the interfaces to read the raw values, as well as the
minimum and maximum value for each channel. In addition several settings
can be configured, like the DWC, sampling frequency or an averaging
filter/oversampling. Interrupts triggered by the DWC, if configured, are
then exposed as IIO events.

ADS7128 differs in the addition of further hardware features, like a
root-mean-square (RMS) and a zero-crossing-detect (ZCD) module, which
are not yet supported by the driver.

Regarding the I2C interface the chips using opcodes to define the way
how the registeres are accessed, like single or multiple register(s)
read/write or setting/clearing only bits.

---
Changes in v4:
- dt-bindings: make avdd-supply mandatory.
- Replace wildcard names with ads7138 or ADS7138 respectively.
- Improve code style (add comments, indentation, placing of brackets,
  helper struct for dev)
- Rename _setclear_bit() and use it for single writes.
- Use DEFINE_RUNTIME_DEV_PM_OPS.
- Make avdd mandatory and verify it's not a stub.
- Link to v3: https://lore.kernel.org/r/20250206-adc_ml-v3-0-1d0bd3483aa2@softing.com

Changes in v3:
- Make interrupt optional.
- Replace SET_RUNTIME_PM_OPS() with RUNTIME_PM_OPS() to prevent warning.
- Rework read_avail for sampling frequency to show each frequency only
  once.
- Use IIO_CHAN_INFO_PEAK and IIO_CHAN_INFO_TROUGH instead of ext_info.
- Link to v2: https://lore.kernel.org/r/20250203-adc_ml-v2-0-8a597660c395@softing.com

Changes in v2:
- Improved commit messages.
- dt-bindings: drop info about what driver supports, make 'avdd-supply'
  optional.
- General rework of driver regarding indentation and code style.
- General code improvements to make code shorter and improve
  readability, like remove 'goto's, order of declarations, ...
- Use kernel macros and functions, like FIELD_*, guard(), ...
- Rework i2c functions to return 0 in case of success and use
  i2c_master_send() if possible.
- Use struct for chip data instead of enum.
- Add comment to what the lock is used for and make sure it's used in
  these cases.
- Use read_avail of iio_info and extend to return also the available
  values for OSR.
- Rework to only accept values of the availability list.
- Use devm_* if possible and therefore drop 'remove' callback.
- Rebase to kernel 6.13 and adjust to API changes.
- Link to v1:
  https://lore.kernel.org/r/20241122-adc_ml-v1-0-0769f2e1bbc1@softing.com

Changes in v1 (to patch series without b4):
- dt-bindings: Extended description

Signed-off-by: Tobias Sperling <tobias.sperling@softing.com>

---
Tobias Sperling (2):
      dt-bindings: iio: adc: Introduce ADS7138
      iio: adc: Add driver for ADS7128 / ADS7138

 .../devicetree/bindings/iio/adc/ti,ads7138.yaml    |  63 ++
 drivers/iio/adc/Kconfig                            |  10 +
 drivers/iio/adc/Makefile                           |   1 +
 drivers/iio/adc/ti-ads7138.c                       | 749 +++++++++++++++++++++
 4 files changed, 823 insertions(+)
---
base-commit: 05dbaf8dd8bf537d4b4eb3115ab42a5fb40ff1f5
change-id: 20241122-adc_ml-d1ce86e85b2c

Best regards,
-- 
Tobias Sperling <tobias.sperling@softing.com>



^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v4 1/2] dt-bindings: iio: adc: Introduce ADS7138
  2025-02-13 15:58 [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs Tobias Sperling via B4 Relay
@ 2025-02-13 15:58 ` Tobias Sperling via B4 Relay
  2025-02-13 15:58 ` [PATCH v4 2/2] iio: adc: Add driver for ADS7128 / ADS7138 Tobias Sperling via B4 Relay
  2025-02-16 15:54 ` [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs Jonathan Cameron
  2 siblings, 0 replies; 6+ messages in thread
From: Tobias Sperling via B4 Relay @ 2025-02-13 15:58 UTC (permalink / raw)
  To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Tobias Sperling, Liam Girdwood,
	Mark Brown
  Cc: linux-iio, devicetree, linux-kernel, Krzysztof Kozlowski

From: Tobias Sperling <tobias.sperling@softing.com>

Add documentation for the driver of ADS7128 and ADS7138 12-bit, 8-channel
analog-to-digital converters. These ADCs have a wide operating range and
a wide feature set. Communication is based on the I2C interface.
ADS7128 differs in the addition of further hardware features, like a
root-mean-square (RMS) and a zero-crossing-detect (ZCD) module.

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Signed-off-by: Tobias Sperling <tobias.sperling@softing.com>
---
 .../devicetree/bindings/iio/adc/ti,ads7138.yaml    | 63 ++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads7138.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads7138.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..a51893e207d4047fe915e87c4be9caa732c45465
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/ti,ads7138.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/ti,ads7138.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments ADS7128/ADS7138 analog-to-digital converter (ADC)
+
+maintainers:
+  - Tobias Sperling <tobias.sperling@softing.com>
+
+description: |
+  The ADS7128 and ADS7138 chips are 12-bit, 8 channel analog-to-digital
+  converters (ADC) with build-in digital window comparator (DWC), using the
+  I2C interface.
+  ADS7128 differs in the addition of further hardware features, like a
+  root-mean-square (RMS) and a zero-crossing-detect (ZCD) module.
+
+  Datasheets:
+    https://www.ti.com/product/ADS7128
+    https://www.ti.com/product/ADS7138
+
+properties:
+  compatible:
+    enum:
+      - ti,ads7128
+      - ti,ads7138
+
+  reg:
+    maxItems: 1
+
+  avdd-supply:
+    description:
+      The regulator used as analog supply voltage as well as reference voltage.
+
+  interrupts:
+    description:
+      Interrupt on ALERT pin, triggers on low level.
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - avdd-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        adc@10 {
+            compatible = "ti,ads7138";
+            reg = <0x10>;
+            avdd-supply = <&reg_stb_3v3>;
+            interrupt-parent = <&gpio2>;
+            interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+        };
+    };
+...

-- 
2.34.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v4 2/2] iio: adc: Add driver for ADS7128 / ADS7138
  2025-02-13 15:58 [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs Tobias Sperling via B4 Relay
  2025-02-13 15:58 ` [PATCH v4 1/2] dt-bindings: iio: adc: Introduce ADS7138 Tobias Sperling via B4 Relay
@ 2025-02-13 15:58 ` Tobias Sperling via B4 Relay
  2025-02-16 15:54 ` [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs Jonathan Cameron
  2 siblings, 0 replies; 6+ messages in thread
From: Tobias Sperling via B4 Relay @ 2025-02-13 15:58 UTC (permalink / raw)
  To: Jonathan Cameron, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Tobias Sperling, Liam Girdwood,
	Mark Brown
  Cc: linux-iio, devicetree, linux-kernel

From: Tobias Sperling <tobias.sperling@softing.com>

Add driver for ADS7128 and ADS7138 12-bit, 8-channel analog-to-digital
converters. These ADCs have a wide operating range and a wide feature
set. Communication is based on the I2C interface.
ADS7128 differs in the addition of further hardware features, like a
root-mean-square (RMS) and a zero-crossing-detect (ZCD) module.

Signed-off-by: Tobias Sperling <tobias.sperling@softing.com>
---
 drivers/iio/adc/Kconfig      |  10 +
 drivers/iio/adc/Makefile     |   1 +
 drivers/iio/adc/ti-ads7138.c | 749 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 760 insertions(+)

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 849c90203071a77ec7d94cec06d4378ece44440b..c43277305a126c498f97e843c05747fddb705e9a 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -1467,6 +1467,16 @@ config TI_ADS1119
          This driver can also be built as a module. If so, the module will be
          called ti-ads1119.
 
+config TI_ADS7138
+	tristate "Texas Instruments ADS7128 and ADS7138 ADC driver"
+	depends on I2C
+	help
+	  If you say yes here you get support for Texas Instruments ADS7128 and
+	  ADS7138 8-channel A/D converters with 12-bit resolution.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called ti-ads7138.
+
 config TI_ADS7924
 	tristate "Texas Instruments ADS7924 ADC"
 	depends on I2C
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index ee19afba62b7fe0a68309c16f3581d98c5b8f653..1e71d8eb6406b92e5d8e99d556c38858a8b9b640 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -133,6 +133,7 @@ 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_ADS7138) += ti-ads7138.o
 obj-$(CONFIG_TI_ADS7924) += ti-ads7924.o
 obj-$(CONFIG_TI_ADS7950) += ti-ads7950.o
 obj-$(CONFIG_TI_ADS8344) += ti-ads8344.o
diff --git a/drivers/iio/adc/ti-ads7138.c b/drivers/iio/adc/ti-ads7138.c
new file mode 100644
index 0000000000000000000000000000000000000000..ee5c1b8e3a8e47e3475d4b4cc276931a51996547
--- /dev/null
+++ b/drivers/iio/adc/ti-ads7138.c
@@ -0,0 +1,749 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * ADS7138 - Texas Instruments Analog-to-Digital Converter
+ */
+
+#include <linux/bitfield.h>
+#include <linux/cleanup.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <linux/unaligned.h>
+
+#include <linux/iio/events.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/types.h>
+
+/*
+ * Always assume 16 bits resolution as HW registers are aligned like that and
+ * with enabled oversampling/averaging it actually corresponds to 16 bits.
+ */
+#define ADS7138_RES_BITS		16
+
+/* ADS7138 operation codes */
+#define ADS7138_OPCODE_SINGLE_WRITE	0x08
+#define ADS7138_OPCODE_SET_BIT		0x18
+#define ADS7138_OPCODE_CLEAR_BIT	0x20
+#define ADS7138_OPCODE_BLOCK_WRITE	0x28
+#define ADS7138_OPCODE_BLOCK_READ	0x30
+
+/* ADS7138 registers */
+#define ADS7138_REG_GENERAL_CFG		0x01
+#define ADS7138_REG_OSR_CFG		0x03
+#define ADS7138_REG_OPMODE_CFG		0x04
+#define ADS7138_REG_SEQUENCE_CFG	0x10
+#define ADS7138_REG_AUTO_SEQ_CH_SEL	0x12
+#define ADS7138_REG_ALERT_CH_SEL	0x14
+#define ADS7138_REG_EVENT_FLAG		0x18
+#define ADS7138_REG_EVENT_HIGH_FLAG	0x1A
+#define ADS7138_REG_EVENT_LOW_FLAG	0x1C
+#define ADS7138_REG_HIGH_TH_HYS_CH(x)	((x) * 4 + 0x20)
+#define ADS7138_REG_LOW_TH_CNT_CH(x)	((x) * 4 + 0x22)
+#define ADS7138_REG_MAX_LSB_CH(x)	((x) * 2 + 0x60)
+#define ADS7138_REG_MIN_LSB_CH(x)	((x) * 2 + 0x80)
+#define ADS7138_REG_RECENT_LSB_CH(x)	((x) * 2 + 0xA0)
+
+#define ADS7138_GENERAL_CFG_RST		BIT(0)
+#define ADS7138_GENERAL_CFG_DWC_EN	BIT(4)
+#define ADS7138_GENERAL_CFG_STATS_EN	BIT(5)
+#define ADS7138_OSR_CFG_MASK		GENMASK(2, 0)
+#define ADS7138_OPMODE_CFG_CONV_MODE	BIT(5)
+#define ADS7138_OPMODE_CFG_FREQ_MASK	GENMASK(4, 0)
+#define ADS7138_SEQUENCE_CFG_SEQ_MODE	BIT(0)
+#define ADS7138_SEQUENCE_CFG_SEQ_START	BIT(4)
+#define ADS7138_THRESHOLD_LSB_MASK	GENMASK(7, 4)
+
+enum ads7138_modes {
+	ADS7138_MODE_MANUAL,
+	ADS7138_MODE_AUTO,
+};
+
+struct ads7138_chip_data {
+	const char *name;
+	const int channel_num;
+};
+
+struct ads7138_data {
+	/* Protects RMW access to the I2C interface */
+	struct mutex lock;
+	struct i2c_client *client;
+	struct regulator *vref_regu;
+	const struct ads7138_chip_data *chip_data;
+};
+
+/*
+ * 2D array of available sampling frequencies and the corresponding register
+ * values. Structured like this to be easily usable in read_avail function.
+ */
+static const int ads7138_samp_freqs_bits[2][26] = {
+	{
+		163, 244, 326, 488, 651, 977, 1302, 1953,
+		2604, 3906, 5208, 7813, 10417, 15625, 20833, 31250,
+		41667, 62500, 83333, 125000, 166667, 250000, 333333, 500000,
+		666667, 1000000
+	}, {
+		0x1f, 0x1e, 0x1d, 0x1c, 0x1b, 0x1a, 0x19, 0x18,
+		0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
+		/* Here is a hole, due to duplicate frequencies */
+		0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02,
+		0x01, 0x00
+	}
+};
+
+static const int ads7138_oversampling_ratios[] = {
+	1, 2, 4, 8, 16, 32, 64, 128
+};
+
+static int ads7138_i2c_write_block(const struct i2c_client *client, u8 reg,
+				   u8 *values, u8 length)
+{
+	int ret;
+	int len = length + 2; /* "+ 2" for OPCODE and reg */
+
+	u8 *buf __free(kfree) = kmalloc(len, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf[0] = ADS7138_OPCODE_BLOCK_WRITE;
+	buf[1] = reg;
+	memcpy(&buf[2], values, length);
+
+	ret = i2c_master_send(client, buf, len);
+	if (ret < 0)
+		return ret;
+	if (ret != len)
+		return -EIO;
+
+	return 0;
+}
+
+static int ads7138_i2c_write_with_opcode(const struct i2c_client *client,
+					 u8 reg, u8 regval, u8 opcode)
+{
+	u8 buf[3] = { opcode, reg, regval };
+	int ret;
+
+	ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
+	if (ret < 0)
+		return ret;
+	if (ret != ARRAY_SIZE(buf))
+		return -EIO;
+
+	return 0;
+}
+
+static int ads7138_i2c_write(const struct i2c_client *client, u8 reg, u8 value)
+{
+	return ads7138_i2c_write_with_opcode(client, reg, value,
+					     ADS7138_OPCODE_SINGLE_WRITE);
+}
+
+static int ads7138_i2c_set_bit(const struct i2c_client *client, u8 reg, u8 bits)
+{
+	return ads7138_i2c_write_with_opcode(client, reg, bits,
+					     ADS7138_OPCODE_SET_BIT);
+}
+
+static int ads7138_i2c_clear_bit(const struct i2c_client *client, u8 reg, u8 bits)
+{
+	return ads7138_i2c_write_with_opcode(client, reg, bits,
+					     ADS7138_OPCODE_CLEAR_BIT);
+}
+
+static int ads7138_i2c_read_block(const struct i2c_client *client, u8 reg,
+				  u8 *out_values, u8 length)
+{
+	u8 buf[2] = { ADS7138_OPCODE_BLOCK_READ, reg };
+	int ret;
+	struct i2c_msg msgs[] = {
+		{
+			.addr = client->addr,
+			.len = ARRAY_SIZE(buf),
+			.buf = buf,
+		},
+		{
+			.addr = client->addr,
+			.flags = I2C_M_RD,
+			.len = length,
+			.buf = out_values,
+		},
+	};
+
+	ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+	if (ret != ARRAY_SIZE(msgs))
+		return -EIO;
+
+	return 0;
+}
+
+static int ads7138_i2c_read(const struct i2c_client *client, u8 reg)
+{
+	u8 value;
+	int ret;
+
+	ret = ads7138_i2c_read_block(client, reg, &value, sizeof(value));
+	if (ret)
+		return ret;
+	return value;
+}
+
+static int ads7138_freq_to_bits(int freq)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ads7138_samp_freqs_bits[0]); i++)
+		if (freq == ads7138_samp_freqs_bits[0][i])
+			return ads7138_samp_freqs_bits[1][i];
+
+	return -EINVAL;
+}
+
+static int ads7138_bits_to_freq(int bits)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ads7138_samp_freqs_bits[1]); i++)
+		if (bits == ads7138_samp_freqs_bits[1][i])
+			return ads7138_samp_freqs_bits[0][i];
+
+	return -EINVAL;
+}
+
+static int ads7138_osr_to_bits(int osr)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ads7138_oversampling_ratios); i++)
+		if (osr == ads7138_oversampling_ratios[i])
+			return i;
+
+	return -EINVAL;
+}
+
+static int ads7138_read_raw(struct iio_dev *indio_dev,
+			    struct iio_chan_spec const *chan, int *val,
+			    int *val2, long mask)
+{
+	struct ads7138_data *data = iio_priv(indio_dev);
+	int ret, vref, bits;
+	u8 values[2];
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		ret = ads7138_i2c_read_block(data->client,
+					     ADS7138_REG_RECENT_LSB_CH(chan->channel),
+					     values, ARRAY_SIZE(values));
+		if (ret)
+			return ret;
+
+		*val = get_unaligned_le16(values);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_PEAK:
+		ret = ads7138_i2c_read_block(data->client,
+					     ADS7138_REG_MAX_LSB_CH(chan->channel),
+					     values, ARRAY_SIZE(values));
+		if (ret)
+			return ret;
+
+		*val = get_unaligned_le16(values);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_TROUGH:
+		ret = ads7138_i2c_read_block(data->client,
+					     ADS7138_REG_MIN_LSB_CH(chan->channel),
+					     values, ARRAY_SIZE(values));
+		if (ret)
+			return ret;
+
+		*val = get_unaligned_le16(values);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		ret = ads7138_i2c_read(data->client, ADS7138_REG_OPMODE_CFG);
+		if (ret < 0)
+			return ret;
+
+		bits = FIELD_GET(ADS7138_OPMODE_CFG_FREQ_MASK, ret);
+		*val = ads7138_bits_to_freq(bits);
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		vref = regulator_get_voltage(data->vref_regu);
+		if (vref < 0)
+			return vref;
+		*val = vref / 1000;
+		*val2 = ADS7138_RES_BITS;
+		return IIO_VAL_FRACTIONAL_LOG2;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		ret = ads7138_i2c_read(data->client, ADS7138_REG_OSR_CFG);
+		if (ret < 0)
+			return ret;
+
+		bits = FIELD_GET(ADS7138_OSR_CFG_MASK, ret);
+		*val = ads7138_oversampling_ratios[bits];
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ads7138_write_raw(struct iio_dev *indio_dev,
+			     struct iio_chan_spec const *chan, int val,
+			     int val2, long mask)
+{
+	struct ads7138_data *data = iio_priv(indio_dev);
+	int bits, ret;
+	u8 value;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SAMP_FREQ: {
+		bits = ads7138_freq_to_bits(val);
+		if (bits < 0)
+			return bits;
+
+		guard(mutex)(&data->lock);
+		ret = ads7138_i2c_read(data->client, ADS7138_REG_OPMODE_CFG);
+		if (ret < 0)
+			return ret;
+
+		value = ret & ~ADS7138_OPMODE_CFG_FREQ_MASK;
+		value |= FIELD_PREP(ADS7138_OPMODE_CFG_FREQ_MASK, bits);
+		return ads7138_i2c_write(data->client, ADS7138_REG_OPMODE_CFG,
+					 value);
+	}
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		bits = ads7138_osr_to_bits(val);
+		if (bits < 0)
+			return bits;
+
+		return ads7138_i2c_write(data->client, ADS7138_REG_OSR_CFG,
+					 bits);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ads7138_read_event(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)
+{
+	struct ads7138_data *data = iio_priv(indio_dev);
+	u8 reg, values[2];
+	int ret;
+
+	switch (info) {
+	case IIO_EV_INFO_VALUE:
+		reg = (dir == IIO_EV_DIR_RISING) ?
+			ADS7138_REG_HIGH_TH_HYS_CH(chan->channel) :
+			ADS7138_REG_LOW_TH_CNT_CH(chan->channel);
+		ret = ads7138_i2c_read_block(data->client, reg, values,
+					     ARRAY_SIZE(values));
+		if (ret)
+			return ret;
+
+		*val = ((values[1] << 4) | (values[0] >> 4));
+		return IIO_VAL_INT;
+	case IIO_EV_INFO_HYSTERESIS:
+		ret = ads7138_i2c_read(data->client,
+				       ADS7138_REG_HIGH_TH_HYS_CH(chan->channel));
+		if (ret < 0)
+			return ret;
+
+		*val = ret & ~ADS7138_THRESHOLD_LSB_MASK;
+		return IIO_VAL_INT;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ads7138_write_event(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)
+{
+	struct ads7138_data *data = iio_priv(indio_dev);
+	u8 reg, values[2];
+	int ret;
+
+	switch (info) {
+	case IIO_EV_INFO_VALUE: {
+		if (val >= BIT(12) || val < 0)
+			return -EINVAL;
+
+		reg = (dir == IIO_EV_DIR_RISING) ?
+			ADS7138_REG_HIGH_TH_HYS_CH(chan->channel) :
+			ADS7138_REG_LOW_TH_CNT_CH(chan->channel);
+
+		guard(mutex)(&data->lock);
+		ret = ads7138_i2c_read(data->client, reg);
+		if (ret < 0)
+			return ret;
+
+		values[0] = ret & ~ADS7138_THRESHOLD_LSB_MASK;
+		values[0] |= FIELD_PREP(ADS7138_THRESHOLD_LSB_MASK, val);
+		values[1] = (val >> 4);
+		return ads7138_i2c_write_block(data->client, reg, values,
+					       ARRAY_SIZE(values));
+	}
+	case IIO_EV_INFO_HYSTERESIS: {
+		if (val >= BIT(4) || val < 0)
+			return -EINVAL;
+
+		reg = ADS7138_REG_HIGH_TH_HYS_CH(chan->channel);
+
+		guard(mutex)(&data->lock);
+		ret = ads7138_i2c_read(data->client, reg);
+		if (ret < 0)
+			return ret;
+
+		values[0] = val & ~ADS7138_THRESHOLD_LSB_MASK;
+		values[0] |= FIELD_PREP(ADS7138_THRESHOLD_LSB_MASK, ret >> 4);
+		return ads7138_i2c_write(data->client, reg, values[0]);
+	}
+	default:
+		return -EINVAL;
+	}
+}
+
+static int ads7138_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 ads7138_data *data = iio_priv(indio_dev);
+	int ret;
+
+	if (dir != IIO_EV_DIR_EITHER)
+		return -EINVAL;
+
+	ret = ads7138_i2c_read(data->client, ADS7138_REG_ALERT_CH_SEL);
+	if (ret < 0)
+		return ret;
+
+	return (ret & BIT(chan->channel)) ? 1 : 0;
+}
+
+static int ads7138_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)
+{
+	struct ads7138_data *data = iio_priv(indio_dev);
+
+	if (dir != IIO_EV_DIR_EITHER)
+		return -EINVAL;
+
+	if (state)
+		return ads7138_i2c_set_bit(data->client,
+					   ADS7138_REG_ALERT_CH_SEL,
+					   BIT(chan->channel));
+	else
+		return ads7138_i2c_clear_bit(data->client,
+					     ADS7138_REG_ALERT_CH_SEL,
+					     BIT(chan->channel));
+}
+
+static int ads7138_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:
+		*vals = ads7138_samp_freqs_bits[0];
+		*length = ARRAY_SIZE(ads7138_samp_freqs_bits[0]);
+		*type = IIO_VAL_INT;
+
+		return IIO_AVAIL_LIST;
+	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+		*vals = ads7138_oversampling_ratios;
+		*length = ARRAY_SIZE(ads7138_oversampling_ratios);
+		*type = IIO_VAL_INT;
+
+		return IIO_AVAIL_LIST;
+	default:
+		return -EINVAL;
+	}
+}
+
+static const struct iio_info ti_ads7138_info = {
+	.read_raw = &ads7138_read_raw,
+	.read_avail = &ads7138_read_avail,
+	.write_raw = &ads7138_write_raw,
+	.read_event_value = &ads7138_read_event,
+	.write_event_value = &ads7138_write_event,
+	.read_event_config = &ads7138_read_event_config,
+	.write_event_config = &ads7138_write_event_config,
+};
+
+static const struct iio_event_spec ads7138_events[] = {
+	{
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_RISING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE)
+	}, {
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_FALLING,
+		.mask_separate = BIT(IIO_EV_INFO_VALUE),
+	}, {
+		.type = IIO_EV_TYPE_THRESH,
+		.dir = IIO_EV_DIR_EITHER,
+		.mask_separate = BIT(IIO_EV_INFO_HYSTERESIS) |
+				 BIT(IIO_EV_INFO_ENABLE),
+	},
+};
+
+#define ADS7138_V_CHAN(_chan) {						\
+	.type = IIO_VOLTAGE,						\
+	.indexed = 1,							\
+	.channel = _chan,						\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
+			      BIT(IIO_CHAN_INFO_PEAK) |			\
+			      BIT(IIO_CHAN_INFO_TROUGH),		\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ) |	\
+				    BIT(IIO_CHAN_INFO_SCALE) |		\
+				    BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), \
+	.info_mask_shared_by_type_available =				\
+				BIT(IIO_CHAN_INFO_SAMP_FREQ) |		\
+				BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),	\
+	.datasheet_name = "AIN"#_chan,					\
+	.event_spec = ads7138_events,					\
+	.num_event_specs = ARRAY_SIZE(ads7138_events),			\
+}
+
+static const struct iio_chan_spec ads7138_channels[] = {
+	ADS7138_V_CHAN(0),
+	ADS7138_V_CHAN(1),
+	ADS7138_V_CHAN(2),
+	ADS7138_V_CHAN(3),
+	ADS7138_V_CHAN(4),
+	ADS7138_V_CHAN(5),
+	ADS7138_V_CHAN(6),
+	ADS7138_V_CHAN(7),
+};
+
+static irqreturn_t ads7138_event_handler(int irq, void *priv)
+{
+	struct iio_dev *indio_dev = priv;
+	struct ads7138_data *data = iio_priv(indio_dev);
+	struct device *dev = &data->client->dev;
+	u8 i, events_high, events_low;
+	u64 code;
+	int ret;
+
+	/* Check if interrupt was trigger by us */
+	ret = ads7138_i2c_read(data->client, ADS7138_REG_EVENT_FLAG);
+	if (ret <= 0)
+		return IRQ_NONE;
+
+	ret = ads7138_i2c_read(data->client, ADS7138_REG_EVENT_HIGH_FLAG);
+	if (ret < 0) {
+		dev_warn(dev, "Failed to read event high flags: %d\n", ret);
+		return IRQ_HANDLED;
+	}
+	events_high = ret;
+
+	ret = ads7138_i2c_read(data->client, ADS7138_REG_EVENT_LOW_FLAG);
+	if (ret < 0) {
+		dev_warn(dev, "Failed to read event low flags: %d\n", ret);
+		return IRQ_HANDLED;
+	}
+	events_low = ret;
+
+	for (i = 0; i < data->chip_data->channel_num; i++) {
+		if (events_high & BIT(i)) {
+			code = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
+						    IIO_EV_TYPE_THRESH,
+						    IIO_EV_DIR_RISING);
+			iio_push_event(indio_dev, code,
+				       iio_get_time_ns(indio_dev));
+		}
+		if (events_low & BIT(i)) {
+			code = IIO_UNMOD_EVENT_CODE(IIO_VOLTAGE, i,
+						    IIO_EV_TYPE_THRESH,
+						    IIO_EV_DIR_FALLING);
+			iio_push_event(indio_dev, code,
+				       iio_get_time_ns(indio_dev));
+		}
+	}
+
+	/* Try to clear all interrupt flags */
+	ret = ads7138_i2c_write(data->client, ADS7138_REG_EVENT_HIGH_FLAG, 0xFF);
+	if (ret)
+		dev_warn(dev, "Failed to clear event high flags: %d\n", ret);
+
+	ret = ads7138_i2c_write(data->client, ADS7138_REG_EVENT_LOW_FLAG, 0xFF);
+	if (ret)
+		dev_warn(dev, "Failed to clear event low flags: %d\n", ret);
+
+	return IRQ_HANDLED;
+}
+
+static int ads7138_set_conv_mode(struct ads7138_data *data,
+				 enum ads7138_modes mode)
+{
+	if (mode == ADS7138_MODE_AUTO)
+		return ads7138_i2c_set_bit(data->client, ADS7138_REG_OPMODE_CFG,
+					   ADS7138_OPMODE_CFG_CONV_MODE);
+	return ads7138_i2c_clear_bit(data->client, ADS7138_REG_OPMODE_CFG,
+				     ADS7138_OPMODE_CFG_CONV_MODE);
+}
+
+static int ads7138_init_hw(struct ads7138_data *data)
+{
+	struct device *dev = &data->client->dev;
+	int ret;
+
+	data->vref_regu = devm_regulator_get(dev, "avdd");
+	if (IS_ERR(data->vref_regu))
+		return dev_err_probe(dev, PTR_ERR(data->vref_regu),
+				     "Failed to get avdd regulator\n");
+
+	ret = regulator_get_voltage(data->vref_regu);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Failed to get avdd voltage\n");
+
+	/* Reset the chip to get a defined starting configuration */
+	ret = ads7138_i2c_set_bit(data->client, ADS7138_REG_GENERAL_CFG,
+				  ADS7138_GENERAL_CFG_RST);
+	if (ret)
+		return ret;
+
+	ret = ads7138_set_conv_mode(data, ADS7138_MODE_AUTO);
+	if (ret)
+		return ret;
+
+	/* Enable statistics and digital window comparator */
+	ret = ads7138_i2c_set_bit(data->client, ADS7138_REG_GENERAL_CFG,
+				  ADS7138_GENERAL_CFG_STATS_EN |
+				  ADS7138_GENERAL_CFG_DWC_EN);
+	if (ret)
+		return ret;
+
+	/* Enable all channels for auto sequencing */
+	ret = ads7138_i2c_set_bit(data->client, ADS7138_REG_AUTO_SEQ_CH_SEL, 0xFF);
+	if (ret)
+		return ret;
+
+	/* Set auto sequence mode and start sequencing */
+	return ads7138_i2c_set_bit(data->client, ADS7138_REG_SEQUENCE_CFG,
+				   ADS7138_SEQUENCE_CFG_SEQ_START |
+				   ADS7138_SEQUENCE_CFG_SEQ_MODE);
+}
+
+static int ads7138_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct iio_dev *indio_dev;
+	struct ads7138_data *data;
+	int ret;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	data->client = client;
+	data->chip_data = i2c_get_match_data(client);
+	if (!data->chip_data)
+		return -ENODEV;
+
+	ret = devm_mutex_init(dev, &data->lock);
+	if (ret)
+		return ret;
+
+	indio_dev->name = data->chip_data->name;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = ads7138_channels;
+	indio_dev->num_channels = ARRAY_SIZE(ads7138_channels);
+	indio_dev->info = &ti_ads7138_info;
+
+	i2c_set_clientdata(client, indio_dev);
+
+	if (client->irq > 0) {
+		ret = devm_request_threaded_irq(dev, client->irq,
+						NULL, ads7138_event_handler,
+						IRQF_TRIGGER_LOW |
+						IRQF_ONESHOT | IRQF_SHARED,
+						client->name, indio_dev);
+		if (ret)
+			return ret;
+	}
+
+	ret = ads7138_init_hw(data);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to initialize device\n");
+
+	ret = devm_iio_device_register(dev, indio_dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to register iio device\n");
+
+	return 0;
+}
+
+static int ads7138_runtime_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct ads7138_data *data = iio_priv(indio_dev);
+
+	return ads7138_set_conv_mode(data, ADS7138_MODE_MANUAL);
+}
+
+static int ads7138_runtime_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = dev_get_drvdata(dev);
+	struct ads7138_data *data = iio_priv(indio_dev);
+
+	return ads7138_set_conv_mode(data, ADS7138_MODE_AUTO);
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(ads7138_pm_ops,
+				 ads7138_runtime_suspend,
+				 ads7138_runtime_resume,
+				 NULL);
+
+static const struct ads7138_chip_data ads7128_data = {
+	.name = "ads7128",
+	.channel_num = 8,
+};
+
+static const struct ads7138_chip_data ads7138_data = {
+	.name = "ads7138",
+	.channel_num = 8,
+};
+
+static const struct of_device_id ads7138_of_match[] = {
+	{ .compatible = "ti,ads7128", .data = &ads7128_data },
+	{ .compatible = "ti,ads7138", .data = &ads7138_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, ads7138_of_match);
+
+static const struct i2c_device_id ads7138_device_ids[] = {
+	{ "ads7128", (kernel_ulong_t)&ads7128_data },
+	{ "ads7138", (kernel_ulong_t)&ads7138_data },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, ads7138_device_ids);
+
+static struct i2c_driver ads7138_driver = {
+	.driver = {
+		.name = "ads7138",
+		.of_match_table = ads7138_of_match,
+		.pm = pm_ptr(&ads7138_pm_ops),
+	},
+	.id_table = ads7138_device_ids,
+	.probe = ads7138_probe,
+};
+module_i2c_driver(ads7138_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Tobias Sperling <tobias.sperling@softing.com>");
+MODULE_DESCRIPTION("Driver for TI ADS7138 ADCs");

-- 
2.34.1



^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs
  2025-02-13 15:58 [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs Tobias Sperling via B4 Relay
  2025-02-13 15:58 ` [PATCH v4 1/2] dt-bindings: iio: adc: Introduce ADS7138 Tobias Sperling via B4 Relay
  2025-02-13 15:58 ` [PATCH v4 2/2] iio: adc: Add driver for ADS7128 / ADS7138 Tobias Sperling via B4 Relay
@ 2025-02-16 15:54 ` Jonathan Cameron
  2025-02-17 14:56   ` Sperling, Tobias
  2 siblings, 1 reply; 6+ messages in thread
From: Jonathan Cameron @ 2025-02-16 15:54 UTC (permalink / raw)
  To: Tobias Sperling via B4 Relay
  Cc: tobias.sperling, Lars-Peter Clausen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Liam Girdwood, Mark Brown,
	linux-iio, devicetree, linux-kernel, Krzysztof Kozlowski

On Thu, 13 Feb 2025 16:58:56 +0100
Tobias Sperling via B4 Relay <devnull+tobias.sperling.softing.com@kernel.org> wrote:

> This patch series adds support for Texas Instruments ADS7128 and
> ADS7138, which are 12-bit, 8 channel analog-to-digital converters (ADCs)
> with build-in digital window comparator (DWC), using the I2C interface.
> 
> The driver exposes the interfaces to read the raw values, as well as the
> minimum and maximum value for each channel. In addition several settings
> can be configured, like the DWC, sampling frequency or an averaging
> filter/oversampling. Interrupts triggered by the DWC, if configured, are
> then exposed as IIO events.
> 
> ADS7128 differs in the addition of further hardware features, like a
> root-mean-square (RMS) and a zero-crossing-detect (ZCD) module, which
> are not yet supported by the driver.
> 
> Regarding the I2C interface the chips using opcodes to define the way
> how the registeres are accessed, like single or multiple register(s)
> read/write or setting/clearing only bits.
LGTM. Applied to the togreg branch of iio.git and pushed out initially
as testing for 0-day to take a look at it.

I did notice whilst applying that the Kconfig ordering for these TI parts
has gotten scrambled. So at some point we should clean that up and
bring them back into alphanumeric order!

Jonathan

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs
  2025-02-16 15:54 ` [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs Jonathan Cameron
@ 2025-02-17 14:56   ` Sperling, Tobias
  2025-02-22 11:53     ` Jonathan Cameron
  0 siblings, 1 reply; 6+ messages in thread
From: Sperling, Tobias @ 2025-02-17 14:56 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Lars-Peter Clausen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Liam Girdwood, Mark Brown,
	linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, Krzysztof Kozlowski

> Von: Jonathan Cameron <jic23@kernel.org>
> Gesendet: Sonntag, 16. Februar 2025 16:55
>
> On Thu, 13 Feb 2025 16:58:56 +0100
> Tobias Sperling via B4 Relay <mailto:devnull+tobias.sperling.softing.com@kernel.org>
> wrote:
> 
> > This patch series adds support for Texas Instruments ADS7128 and
> > ADS7138, which are 12-bit, 8 channel analog-to-digital converters (ADCs)
> > with build-in digital window comparator (DWC), using the I2C interface.
> >
> > The driver exposes the interfaces to read the raw values, as well as the
> > minimum and maximum value for each channel. In addition several settings
> > can be configured, like the DWC, sampling frequency or an averaging
> > filter/oversampling. Interrupts triggered by the DWC, if configured, are
> > then exposed as IIO events.
> >
> > ADS7128 differs in the addition of further hardware features, like a
> > root-mean-square (RMS) and a zero-crossing-detect (ZCD) module, which
> > are not yet supported by the driver.
> >
> > Regarding the I2C interface the chips using opcodes to define the way
> > how the registeres are accessed, like single or multiple register(s)
> > read/write or setting/clearing only bits.
> LGTM. Applied to the togreg branch of iio.git and pushed out initially
> as testing for 0-day to take a look at it.
> 
> I did notice whilst applying that the Kconfig ordering for these TI parts
> has gotten scrambled. So at some point we should clean that up and
> bring them back into alphanumeric order!
> 
> Jonathan

Ok, thanks for the info. Then everything is going its way I guess. :)

I can prepare a patch for the ordering. Shall this be based on top
of this patch set or just the master branch?

Tobias

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs
  2025-02-17 14:56   ` Sperling, Tobias
@ 2025-02-22 11:53     ` Jonathan Cameron
  0 siblings, 0 replies; 6+ messages in thread
From: Jonathan Cameron @ 2025-02-22 11:53 UTC (permalink / raw)
  To: Sperling, Tobias
  Cc: Lars-Peter Clausen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Liam Girdwood, Mark Brown,
	linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, Krzysztof Kozlowski

On Mon, 17 Feb 2025 14:56:53 +0000
"Sperling, Tobias" <Tobias.Sperling@Softing.com> wrote:

> > Von: Jonathan Cameron <jic23@kernel.org>
> > Gesendet: Sonntag, 16. Februar 2025 16:55
> >
> > On Thu, 13 Feb 2025 16:58:56 +0100
> > Tobias Sperling via B4 Relay <mailto:devnull+tobias.sperling.softing.com@kernel.org>
> > wrote:
> >   
> > > This patch series adds support for Texas Instruments ADS7128 and
> > > ADS7138, which are 12-bit, 8 channel analog-to-digital converters (ADCs)
> > > with build-in digital window comparator (DWC), using the I2C interface.
> > >
> > > The driver exposes the interfaces to read the raw values, as well as the
> > > minimum and maximum value for each channel. In addition several settings
> > > can be configured, like the DWC, sampling frequency or an averaging
> > > filter/oversampling. Interrupts triggered by the DWC, if configured, are
> > > then exposed as IIO events.
> > >
> > > ADS7128 differs in the addition of further hardware features, like a
> > > root-mean-square (RMS) and a zero-crossing-detect (ZCD) module, which
> > > are not yet supported by the driver.
> > >
> > > Regarding the I2C interface the chips using opcodes to define the way
> > > how the registeres are accessed, like single or multiple register(s)
> > > read/write or setting/clearing only bits.  
> > LGTM. Applied to the togreg branch of iio.git and pushed out initially
> > as testing for 0-day to take a look at it.
> > 
> > I did notice whilst applying that the Kconfig ordering for these TI parts
> > has gotten scrambled. So at some point we should clean that up and
> > bring them back into alphanumeric order!
> > 
> > Jonathan  
> 
> Ok, thanks for the info. Then everything is going its way I guess. :)
> 
> I can prepare a patch for the ordering. Shall this be based on top
> of this patch set or just the master branch?

This is a rare case where basing on my testing branch is the
best option.  Right now that matches togreg, but I'll probably be
applying some stuff on top today and that might touch this file.

Jonathan
> 
> Tobias


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-02-22 11:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-13 15:58 [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs Tobias Sperling via B4 Relay
2025-02-13 15:58 ` [PATCH v4 1/2] dt-bindings: iio: adc: Introduce ADS7138 Tobias Sperling via B4 Relay
2025-02-13 15:58 ` [PATCH v4 2/2] iio: adc: Add driver for ADS7128 / ADS7138 Tobias Sperling via B4 Relay
2025-02-16 15:54 ` [PATCH v4 0/2] Support for TI ADS7128 and ADS7138 ADCs Jonathan Cameron
2025-02-17 14:56   ` Sperling, Tobias
2025-02-22 11:53     ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).