Devicetree
 help / color / mirror / Atom feed
* [PATCH 0/6] iio: adc: ltc2497: add LTC2493 support and line-frequency rejection
@ 2026-10-09  8:43 Andrei Stancovici via B4 Relay
  2026-10-09  8:43 ` [PATCH 1/6] dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support Andrei Stancovici via B4 Relay
                   ` (5 more replies)
  0 siblings, 6 replies; 10+ messages in thread
From: Andrei Stancovici via B4 Relay @ 2026-10-09  8:43 UTC (permalink / raw)
  To: Nuno Sá, Michael Hennerich, Jonathan Cameron, David Lechner,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Liam Beguin
  Cc: linux, linux-iio, devicetree, linux-kernel, Andrei Stancovici

This series adds LTC2493 support to the ltc2497 driver, and adds FA/FB
line-frequency rejection for the LTC2499 and the LTC2493.

It includes:
- the LTC2493 device-tree binding,
- LTC2493 support in the driver: 4 single-ended inputs or 2 differential
  pairs, 24-bit result, same command format as the LTC2499,
- the LTC2493 internal PTAT temperature channel,
- the LTC2493 2x conversion speed mode, exposed via sampling_frequency,
- FA/FB line-frequency rejection (50Hz, 60Hz, or both) exposed via
  filter_mode, implemented in the core and enabled for the LTC2499,
- the same rejection selection enabled for the LTC2493.

The FA/FB patch also widens the conversion-time budget, because 50Hz-only
rejection takes 163.5 ms at 1x and the previous budget was 150 ms; see
that patch for the details.

Validated on a Raspberry Pi 4 running 7.3.0-rc4, over an IIO network
backend, with a DC1010A-A board (LTC2493) and a DC1012A-A board
(LTC2499):
- LTC2493 voltage channels, single-ended and differential,
- LTC2493 temperature raw/scale/offset, with voltage and temperature
  reads interleaved to confirm no sticky PTAT,
- sampling_frequency 1x/2x switching on the LTC2493,
- filter_mode 50Hz/60Hz/both on both parts, with the conversion time
  honoured in each mode,
- pyadi-iio hardware test suites: 41/41 on the LTC2493, 36/36 on the
  LTC2499.

The series was rebased onto the base commit below after those runs. The
rebase left all four touched files byte-identical, so the code posted
here is the code that was tested.

Signed-off-by: Andrei Stancovici <andrei.stancovici@analog.com>
---
Andrei Stancovici (6):
      dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support
      iio: adc: ltc2497: add LTC2493 support
      iio: adc: ltc2497: add LTC2493 internal temperature channel
      iio: adc: ltc2497: add 2x speed mode support for the LTC2493
      iio: adc: ltc2497: add FA/FB line-frequency rejection selection
      iio: adc: ltc2497: enable line-frequency rejection on LTC2493

 .../devicetree/bindings/iio/adc/lltc,ltc2497.yaml  |   7 +
 drivers/iio/adc/ltc2497-core.c                     | 199 +++++++++++++++++----
 drivers/iio/adc/ltc2497.c                          |  61 +++++--
 drivers/iio/adc/ltc2497.h                          |  45 ++++-
 4 files changed, 251 insertions(+), 61 deletions(-)
---
base-commit: a3b3580713f3ac5a32dc2874ee546828977a1d68
change-id: 20261009-submission-ltc2493-support-v1-86449ede432d

Best regards,
--  
Andrei Stancovici <andrei.stancovici@analog.com>



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

* [PATCH 1/6] dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support
  2026-10-09  8:43 [PATCH 0/6] iio: adc: ltc2497: add LTC2493 support and line-frequency rejection Andrei Stancovici via B4 Relay
@ 2026-10-09  8:43 ` Andrei Stancovici via B4 Relay
  2026-10-09 12:06   ` Joshua Crofts
  2026-10-09 14:45   ` Conor Dooley
  2026-10-09  8:43 ` [PATCH 2/6] iio: adc: ltc2497: " Andrei Stancovici via B4 Relay
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 10+ messages in thread
From: Andrei Stancovici via B4 Relay @ 2026-10-09  8:43 UTC (permalink / raw)
  To: Nuno Sá, Michael Hennerich, Jonathan Cameron, David Lechner,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Liam Beguin
  Cc: linux, linux-iio, devicetree, linux-kernel, Andrei Stancovici

From: Andrei Stancovici <andrei.stancovici@analog.com>

The LTC2493 is a 24-bit delta-sigma ADC with 4 single-ended or 2
differential inputs and an I2C interface. Its channel map matches no
part already listed, so it gets its own compatible rather than a
fallback; no new property is needed.

Signed-off-by: Andrei Stancovici <andrei.stancovici@analog.com>
---
 Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml b/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml
index 67445ad2bb3b..4df5aadd1e1d 100644
--- a/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/lltc,ltc2497.yaml
@@ -23,6 +23,12 @@ description: |
 
     https://www.analog.com/media/en/technical-documentation/data-sheets/2309fd.pdf
 
+  LTC2493:
+    24bit ADC supporting up to 4 single ended or 2 differential inputs.
+    I2C interface.
+
+    https://www.analog.com/media/en/technical-documentation/data-sheets/2493fe.pdf
+
   LTC2497:
   LTC2499:
     16bit ADC supporting up to 16 single ended or 8 differential inputs.
@@ -36,6 +42,7 @@ properties:
     enum:
       - lltc,ltc2305
       - lltc,ltc2309
+      - lltc,ltc2493
       - lltc,ltc2497
       - lltc,ltc2499
 

-- 
2.43.0



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

* [PATCH 2/6] iio: adc: ltc2497: add LTC2493 support
  2026-10-09  8:43 [PATCH 0/6] iio: adc: ltc2497: add LTC2493 support and line-frequency rejection Andrei Stancovici via B4 Relay
  2026-10-09  8:43 ` [PATCH 1/6] dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support Andrei Stancovici via B4 Relay
@ 2026-10-09  8:43 ` Andrei Stancovici via B4 Relay
  2026-10-09  8:43 ` [PATCH 3/6] iio: adc: ltc2497: add LTC2493 internal temperature channel Andrei Stancovici via B4 Relay
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Andrei Stancovici via B4 Relay @ 2026-10-09  8:43 UTC (permalink / raw)
  To: Nuno Sá, Michael Hennerich, Jonathan Cameron, David Lechner,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Liam Beguin
  Cc: linux, linux-iio, devicetree, linux-kernel, Andrei Stancovici

From: Andrei Stancovici <andrei.stancovici@analog.com>

The LTC2493 is the 4-channel member of the LTC2499 family: 4 single-ended
inputs or 2 differential pairs, with the same command format and 24-bit
result. Add it with its own channel table.

Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2493fe.pdf
Signed-off-by: Andrei Stancovici <andrei.stancovici@analog.com>
---
 drivers/iio/adc/ltc2497-core.c | 36 ++++++++++++++++++++++++++++--------
 drivers/iio/adc/ltc2497.c      |  8 ++++++++
 drivers/iio/adc/ltc2497.h      |  1 +
 3 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c
index a6e34da83b81..96b365efd1e9 100644
--- a/drivers/iio/adc/ltc2497-core.c
+++ b/drivers/iio/adc/ltc2497-core.c
@@ -347,6 +347,22 @@ static const struct iio_chan_spec _name[] = {                           \
 LTC2497_DEFINE_CHANNELS(ltc2497core_channel, 0);
 LTC2497_DEFINE_CHANNELS(ltc2497core_channel_samp_freq, BIT(IIO_CHAN_INFO_SAMP_FREQ));
 
+/* The LTC2493 has 4 single-ended inputs and 2 differential pairs. */
+#define LTC2493_DEFINE_CHANNELS(_name, _extra_mask)                     \
+static const struct iio_chan_spec _name[] = {                           \
+	LTC2497_CHAN(0, LTC2497_SGL, "CH0", _extra_mask),               \
+	LTC2497_CHAN(1, LTC2497_SGL, "CH1", _extra_mask),               \
+	LTC2497_CHAN(2, LTC2497_SGL, "CH2", _extra_mask),               \
+	LTC2497_CHAN(3, LTC2497_SGL, "CH3", _extra_mask),               \
+	LTC2497_CHAN_DIFF(0, LTC2497_DIFF, _extra_mask),                \
+	LTC2497_CHAN_DIFF(1, LTC2497_DIFF, _extra_mask),                \
+	LTC2497_CHAN_DIFF(0, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+	LTC2497_CHAN_DIFF(1, LTC2497_DIFF | LTC2497_SIGN, _extra_mask), \
+	LTC2497_TEMP_CHANNEL,                                           \
+}
+
+LTC2493_DEFINE_CHANNELS(ltc2493_channel, 0);
+
 static const struct iio_info ltc2497core_info = {
 	.read_raw = ltc2497core_read_raw,
 	.read_avail = ltc2497core_read_avail,
@@ -370,15 +386,19 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
 
 	indio_dev->info = &ltc2497core_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
-	if (ddata->chip_info->has_speed_mode)
-		indio_dev->channels = ltc2497core_channel_samp_freq;
-	else
-		indio_dev->channels = ltc2497core_channel;
-	/* Only the ltc2499 has a temperature channel; it is the last entry. */
-	if (ddata->chip_info->has_temp)
+	if (ddata->chip_info->four_channel) {
+		indio_dev->channels = ltc2493_channel;
+		indio_dev->num_channels = ARRAY_SIZE(ltc2493_channel);
+	} else {
+		if (ddata->chip_info->has_speed_mode)
+			indio_dev->channels = ltc2497core_channel_samp_freq;
+		else
+			indio_dev->channels = ltc2497core_channel;
 		indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel);
-	else
-		indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel) - 1;
+	}
+	/* Only the ltc2499 has a temperature channel; it is the last entry. */
+	if (!ddata->chip_info->has_temp)
+		indio_dev->num_channels--;
 
 	ret = ddata->result_and_measure(ddata, LTC2497_CONFIG_DEFAULT, NULL);
 	if (ret < 0)
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index 15458d4e21a1..ea9dff3c0d73 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -18,6 +18,7 @@
 #include "ltc2497.h"
 
 enum ltc2497_chip_type {
+	TYPE_LTC2493,
 	TYPE_LTC2497,
 	TYPE_LTC2499,
 };
@@ -170,6 +171,11 @@ static void ltc2497_remove(struct i2c_client *client)
 }
 
 static const struct ltc2497_chip_info ltc2497_info[] = {
+	[TYPE_LTC2493] = {
+		.resolution = 24,
+		.name = "ltc2493",
+		.four_channel = true,
+	},
 	[TYPE_LTC2497] = {
 		.resolution = 16,
 		.name = NULL,
@@ -183,6 +189,7 @@ static const struct ltc2497_chip_info ltc2497_info[] = {
 };
 
 static const struct i2c_device_id ltc2497_id[] = {
+	{ .name = "ltc2493", .driver_data = (kernel_ulong_t)&ltc2497_info[TYPE_LTC2493] },
 	{ .name = "ltc2497", .driver_data = (kernel_ulong_t)&ltc2497_info[TYPE_LTC2497] },
 	{ .name = "ltc2499", .driver_data = (kernel_ulong_t)&ltc2497_info[TYPE_LTC2499] },
 	{ }
@@ -190,6 +197,7 @@ static const struct i2c_device_id ltc2497_id[] = {
 MODULE_DEVICE_TABLE(i2c, ltc2497_id);
 
 static const struct of_device_id ltc2497_of_match[] = {
+	{ .compatible = "lltc,ltc2493", .data = &ltc2497_info[TYPE_LTC2493] },
 	{ .compatible = "lltc,ltc2497", .data = &ltc2497_info[TYPE_LTC2497] },
 	{ .compatible = "lltc,ltc2499", .data = &ltc2497_info[TYPE_LTC2499] },
 	{ }
diff --git a/drivers/iio/adc/ltc2497.h b/drivers/iio/adc/ltc2497.h
index cee9a2f50b82..219f7d49854b 100644
--- a/drivers/iio/adc/ltc2497.h
+++ b/drivers/iio/adc/ltc2497.h
@@ -31,6 +31,7 @@ struct ltc2497_chip_info {
 	u32 resolution;
 	bool has_temp;
 	bool has_speed_mode;	/* SPD bit in the 2nd config byte (LTC2499/LTC2493) */
+	bool four_channel;	/* 4 inputs (LTC2493) instead of 16 */
 };
 
 struct ltc2497core_driverdata {

-- 
2.43.0



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

* [PATCH 3/6] iio: adc: ltc2497: add LTC2493 internal temperature channel
  2026-10-09  8:43 [PATCH 0/6] iio: adc: ltc2497: add LTC2493 support and line-frequency rejection Andrei Stancovici via B4 Relay
  2026-10-09  8:43 ` [PATCH 1/6] dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support Andrei Stancovici via B4 Relay
  2026-10-09  8:43 ` [PATCH 2/6] iio: adc: ltc2497: " Andrei Stancovici via B4 Relay
@ 2026-10-09  8:43 ` Andrei Stancovici via B4 Relay
  2026-10-09  8:43 ` [PATCH 4/6] iio: adc: ltc2497: add 2x speed mode support for the LTC2493 Andrei Stancovici via B4 Relay
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 10+ messages in thread
From: Andrei Stancovici via B4 Relay @ 2026-10-09  8:43 UTC (permalink / raw)
  To: Nuno Sá, Michael Hennerich, Jonathan Cameron, David Lechner,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Liam Beguin
  Cc: linux, linux-iio, devicetree, linux-kernel, Andrei Stancovici

From: Andrei Stancovici <andrei.stancovici@analog.com>

The LTC2493 includes the same internal PTAT temperature sensor as the
LTC2499, selected via the IM bit in the second config byte.

Tested on live LTC2493 hardware connected through an IIO network backend:
in_temp_raw, in_temp_scale, and in_temp_offset are readable; the reported
temperature is plausible; and voltage/temperature interleaving produces no
sticky-PTAT.

Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2493fe.pdf
Signed-off-by: Andrei Stancovici <andrei.stancovici@analog.com>
---
 drivers/iio/adc/ltc2497-core.c | 2 +-
 drivers/iio/adc/ltc2497.c      | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c
index 96b365efd1e9..87eade46beb5 100644
--- a/drivers/iio/adc/ltc2497-core.c
+++ b/drivers/iio/adc/ltc2497-core.c
@@ -396,7 +396,7 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
 			indio_dev->channels = ltc2497core_channel;
 		indio_dev->num_channels = ARRAY_SIZE(ltc2497core_channel);
 	}
-	/* Only the ltc2499 has a temperature channel; it is the last entry. */
+	/* Temperature is the last channel entry; trim it for parts without the sensor. */
 	if (!ddata->chip_info->has_temp)
 		indio_dev->num_channels--;
 
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index ea9dff3c0d73..12c8a2fecc07 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -174,6 +174,7 @@ static const struct ltc2497_chip_info ltc2497_info[] = {
 	[TYPE_LTC2493] = {
 		.resolution = 24,
 		.name = "ltc2493",
+		.has_temp = true,
 		.four_channel = true,
 	},
 	[TYPE_LTC2497] = {

-- 
2.43.0



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

* [PATCH 4/6] iio: adc: ltc2497: add 2x speed mode support for the LTC2493
  2026-10-09  8:43 [PATCH 0/6] iio: adc: ltc2497: add LTC2493 support and line-frequency rejection Andrei Stancovici via B4 Relay
                   ` (2 preceding siblings ...)
  2026-10-09  8:43 ` [PATCH 3/6] iio: adc: ltc2497: add LTC2493 internal temperature channel Andrei Stancovici via B4 Relay
@ 2026-10-09  8:43 ` Andrei Stancovici via B4 Relay
  2026-10-09  8:43 ` [PATCH 5/6] iio: adc: ltc2497: add FA/FB line-frequency rejection selection Andrei Stancovici via B4 Relay
  2026-10-09  8:43 ` [PATCH 6/6] iio: adc: ltc2497: enable line-frequency rejection on LTC2493 Andrei Stancovici via B4 Relay
  5 siblings, 0 replies; 10+ messages in thread
From: Andrei Stancovici via B4 Relay @ 2026-10-09  8:43 UTC (permalink / raw)
  To: Nuno Sá, Michael Hennerich, Jonathan Cameron, David Lechner,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Liam Beguin
  Cc: linux, linux-iio, devicetree, linux-kernel, Andrei Stancovici

From: Andrei Stancovici <andrei.stancovici@analog.com>

The LTC2493 supports the same SPD 2x conversion-speed mode as the
LTC2499, using the same config word and conversion times.  Expose it
through sampling_frequency and sampling_frequency_available on the
voltage channels.  The temperature channel ignores the mode and carries
no sampling_frequency.

Tested on live LTC2493 hardware connected through an IIO network
backend: 1x/2x switching works, voltage reads succeed at both rates, and
the temperature channel carries no sampling_frequency attribute.

Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2493fe.pdf
Signed-off-by: Andrei Stancovici <andrei.stancovici@analog.com>
---
 drivers/iio/adc/ltc2497-core.c | 6 +++++-
 drivers/iio/adc/ltc2497.c      | 1 +
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c
index 87eade46beb5..816312bf0e90 100644
--- a/drivers/iio/adc/ltc2497-core.c
+++ b/drivers/iio/adc/ltc2497-core.c
@@ -362,6 +362,7 @@ static const struct iio_chan_spec _name[] = {                           \
 }
 
 LTC2493_DEFINE_CHANNELS(ltc2493_channel, 0);
+LTC2493_DEFINE_CHANNELS(ltc2493_channel_samp_freq, BIT(IIO_CHAN_INFO_SAMP_FREQ));
 
 static const struct iio_info ltc2497core_info = {
 	.read_raw = ltc2497core_read_raw,
@@ -387,7 +388,10 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
 	indio_dev->info = &ltc2497core_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	if (ddata->chip_info->four_channel) {
-		indio_dev->channels = ltc2493_channel;
+		if (ddata->chip_info->has_speed_mode)
+			indio_dev->channels = ltc2493_channel_samp_freq;
+		else
+			indio_dev->channels = ltc2493_channel;
 		indio_dev->num_channels = ARRAY_SIZE(ltc2493_channel);
 	} else {
 		if (ddata->chip_info->has_speed_mode)
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index 12c8a2fecc07..a655b04e2454 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -175,6 +175,7 @@ static const struct ltc2497_chip_info ltc2497_info[] = {
 		.resolution = 24,
 		.name = "ltc2493",
 		.has_temp = true,
+		.has_speed_mode = true,
 		.four_channel = true,
 	},
 	[TYPE_LTC2497] = {

-- 
2.43.0



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

* [PATCH 5/6] iio: adc: ltc2497: add FA/FB line-frequency rejection selection
  2026-10-09  8:43 [PATCH 0/6] iio: adc: ltc2497: add LTC2493 support and line-frequency rejection Andrei Stancovici via B4 Relay
                   ` (3 preceding siblings ...)
  2026-10-09  8:43 ` [PATCH 4/6] iio: adc: ltc2497: add 2x speed mode support for the LTC2493 Andrei Stancovici via B4 Relay
@ 2026-10-09  8:43 ` Andrei Stancovici via B4 Relay
  2026-10-09  8:54   ` sashiko-bot
  2026-10-09  8:43 ` [PATCH 6/6] iio: adc: ltc2497: enable line-frequency rejection on LTC2493 Andrei Stancovici via B4 Relay
  5 siblings, 1 reply; 10+ messages in thread
From: Andrei Stancovici via B4 Relay @ 2026-10-09  8:43 UTC (permalink / raw)
  To: Nuno Sá, Michael Hennerich, Jonathan Cameron, David Lechner,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Liam Beguin
  Cc: linux, linux-iio, devicetree, linux-kernel, Andrei Stancovici

From: Andrei Stancovici <andrei.stancovici@analog.com>

The LTC2499 can suppress mains interference at 50Hz, 60Hz, or
simultaneously at both (the power-up default). Expose it through
filter_mode and filter_mode_available on the voltage channels.

The conversion time also depends on the rejection mode: 50Hz-only is the
longest at 163.5 ms (1x). The previous 150 ms budget was 13.5 ms short,
risking a mid-conversion reprogram in 50Hz-only 1x mode.

Tested on live LTC2499 hardware connected through an IIO network backend:
all three modes are selectable and readable; voltage reads succeed in each
mode; conversion times are respected; temperature reads honour the
rejection selection.

Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2499fa.pdf
Signed-off-by: Andrei Stancovici <andrei.stancovici@analog.com>
---
 drivers/iio/adc/ltc2497-core.c | 159 +++++++++++++++++++++++++++++++++--------
 drivers/iio/adc/ltc2497.c      |  50 +++++++++----
 drivers/iio/adc/ltc2497.h      |  44 +++++++++---
 3 files changed, 200 insertions(+), 53 deletions(-)

diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c
index 816312bf0e90..e5a8ab568128 100644
--- a/drivers/iio/adc/ltc2497-core.c
+++ b/drivers/iio/adc/ltc2497-core.c
@@ -7,6 +7,8 @@
  */
 
 #include <linux/delay.h>
+#include <linux/device/devres.h>
+#include <linux/gfp.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/driver.h>
 #include <linux/math64.h>
@@ -22,33 +24,37 @@
 #define LTC2497_SIGN			BIT(3)
 
 /*
- * Output-rate modes, indexed by ltc2497core_driverdata.speed_2x
- * (0 = 1x, the power-on default; 1 = 2x, LTC2499 only).  The advertised
- * sampling_frequency and the conversion-time budget are two views of the same
- * mode, so they are kept in lock-step here.
+ * Output rates indexed as [rejection][speed]; each row matches the
+ * corresponding conv_time_ms_tbl row so rates and wait times stay in step.
  */
-static const int ltc2497core_samp_freq_avail[] = {
-	6, 800000,	/* 1x: ~6.8 Hz  (1 / t_CONV_1 typ 146.9ms) */
-	13, 600000,	/* 2x: ~13.6 Hz (1 / t_CONV_2 typ  73.6ms) */
+static const int ltc2497core_samp_freq_avail[][4] = {
+	[LTC2499_REJECT_50_60]	= { 6, 800000, 13, 600000 },	/* ~6.8 / 13.6 Hz */
+	[LTC2499_REJECT_50]	= { 6, 240000, 12, 450000 },	/* ~6.24 / 12.45 Hz */
+	[LTC2499_REJECT_60]	= { 7, 490000, 14, 950000 },	/* ~7.49 / 14.95 Hz */
 };
 
-static const unsigned int ltc2497core_conv_time_ms_tbl[] = {
-	LTC2497_CONV_TIME_1X_MS,		/* 1x */
-	LTC2499_CONV_TIME_2X_MS,		/* 2x */
+static const unsigned int ltc2497core_conv_time_ms_tbl[][2] = {
+	[LTC2499_REJECT_50_60]	= { LTC2497_CONV_TIME_50_60_1X_MS,
+				    LTC2499_CONV_TIME_50_60_2X_MS },
+	[LTC2499_REJECT_50]	= { LTC2499_CONV_TIME_50_1X_MS,
+				    LTC2499_CONV_TIME_50_2X_MS },
+	[LTC2499_REJECT_60]	= { LTC2499_CONV_TIME_60_1X_MS,
+				    LTC2499_CONV_TIME_60_2X_MS },
 };
 
 static unsigned int ltc2497core_conv_time_ms(struct ltc2497core_driverdata *ddata,
 					     u8 address)
 {
 	/*
-	 * SPD is ignored by the part during a temperature measurement: it
-	 * always converts at 1x, so budget the 1x time regardless of the
-	 * selected voltage-channel mode.
+	 * A temperature measurement always converts at 1x (the part ignores
+	 * SPD while measuring temperature) but still honours the FA/FB
+	 * rejection selection, so budget the 1x cell of the current rejection
+	 * row regardless of the selected voltage-channel speed.
 	 */
 	if (address == LTC2497_TEMP_ADDR)
-		return ltc2497core_conv_time_ms_tbl[0];
+		return ltc2497core_conv_time_ms_tbl[ddata->rejection][0];
 
-	return ltc2497core_conv_time_ms_tbl[ddata->speed_2x];
+	return ltc2497core_conv_time_ms_tbl[ddata->rejection][ddata->speed_2x];
 }
 
 static int ltc2497core_wait_conv(struct ltc2497core_driverdata *ddata,
@@ -192,11 +198,12 @@ static int ltc2497core_read_raw(struct iio_dev *indio_dev,
 		/*
 		 * Only advertised on the voltage channels of parts with a speed
 		 * mode; the sampling frequency is a property of the selected 1x/2x
-		 * mode, not of an individual conversion.
+		 * speed and of the FA/FB rejection mode, not of an individual
+		 * conversion.
 		 */
 		mutex_lock(&ddata->lock);
-		*val = ltc2497core_samp_freq_avail[ddata->speed_2x * 2];
-		*val2 = ltc2497core_samp_freq_avail[ddata->speed_2x * 2 + 1];
+		*val = ltc2497core_samp_freq_avail[ddata->rejection][ddata->speed_2x * 2];
+		*val2 = ltc2497core_samp_freq_avail[ddata->rejection][ddata->speed_2x * 2 + 1];
 		mutex_unlock(&ddata->lock);
 
 		return IIO_VAL_INT_PLUS_MICRO;
@@ -211,11 +218,13 @@ static int ltc2497core_read_avail(struct iio_dev *indio_dev,
 				  const int **vals, int *type, int *length,
 				  long mask)
 {
+	struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
+
 	switch (mask) {
 	case IIO_CHAN_INFO_SAMP_FREQ:
-		*vals = ltc2497core_samp_freq_avail;
+		*vals = ltc2497core_samp_freq_avail[ddata->rejection];
 		*type = IIO_VAL_INT_PLUS_MICRO;
-		*length = ARRAY_SIZE(ltc2497core_samp_freq_avail);
+		*length = ARRAY_SIZE(ltc2497core_samp_freq_avail[ddata->rejection]);
 		return IIO_AVAIL_LIST;
 
 	default:
@@ -228,23 +237,28 @@ static int ltc2497core_write_raw(struct iio_dev *indio_dev,
 				 int val, int val2, long mask)
 {
 	struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
+	const int *avail;
 	unsigned int i;
 	bool speed_2x;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_SAMP_FREQ:
-		/* Match the (val, val2) pair against the advertised rates. */
-		for (i = 0; i < ARRAY_SIZE(ltc2497core_samp_freq_avail); i += 2) {
-			if (val == ltc2497core_samp_freq_avail[i] &&
-			    val2 == ltc2497core_samp_freq_avail[i + 1])
+		/*
+		 * The rates differ per rejection mode, so match against the
+		 * current mode's row under lock.
+		 */
+		mutex_lock(&ddata->lock);
+		avail = ltc2497core_samp_freq_avail[ddata->rejection];
+		for (i = 0; i < ARRAY_SIZE(ltc2497core_samp_freq_avail[0]); i += 2) {
+			if (val == avail[i] && val2 == avail[i + 1])
 				break;
 		}
-		if (i == ARRAY_SIZE(ltc2497core_samp_freq_avail))
+		if (i == ARRAY_SIZE(ltc2497core_samp_freq_avail[0])) {
+			mutex_unlock(&ddata->lock);
 			return -EINVAL;
+		}
 
 		speed_2x = i / 2;
-
-		mutex_lock(&ddata->lock);
 		ddata->speed_2x = speed_2x;
 		/*
 		 * The new speed only takes effect once the second command byte
@@ -268,6 +282,72 @@ static int ltc2497core_write_raw(struct iio_dev *indio_dev,
 	}
 }
 
+/*
+ * The three legal FA/FB combinations map one-to-one to the enumerators,
+ * so the reserved FA = FB = 1 state is unreachable through this driver.
+ */
+static const char * const ltc2497core_filter_modes_str[] = {
+	[LTC2499_REJECT_50_60]	= "50_60",
+	[LTC2499_REJECT_50]	= "50",
+	[LTC2499_REJECT_60]	= "60",
+};
+
+static int ltc2497core_set_filter_mode(struct iio_dev *indio_dev,
+				       const struct iio_chan_spec *chan,
+				       unsigned int val)
+{
+	struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
+
+	mutex_lock(&ddata->lock);
+	ddata->rejection = val;
+	/*
+	 * The new rejection mode only takes effect once the second command byte
+	 * is reprogrammed, so force the next read to reprogram rather than reuse
+	 * the value already latched for this address.  LTC2497_CONFIG_DEFAULT is
+	 * not a valid channel/temperature address, so it is a safe re-arm
+	 * sentinel (as used at probe).
+	 *
+	 * A conversion started under the old rejection mode may still be in
+	 * flight; its own duration (conv_time_prev), not the new mode's, still
+	 * gates the next reprogram, so the timing state is left untouched here.
+	 */
+	ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
+	mutex_unlock(&ddata->lock);
+
+	return 0;
+}
+
+static int ltc2497core_get_filter_mode(struct iio_dev *indio_dev,
+				       const struct iio_chan_spec *chan)
+{
+	struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
+	enum ltc2497_rejection rejection;
+
+	mutex_lock(&ddata->lock);
+	rejection = ddata->rejection;
+	mutex_unlock(&ddata->lock);
+
+	return rejection;
+}
+
+static const struct iio_enum ltc2497core_filter_mode_enum = {
+	.items = ltc2497core_filter_modes_str,
+	.num_items = ARRAY_SIZE(ltc2497core_filter_modes_str),
+	.set = ltc2497core_set_filter_mode,
+	.get = ltc2497core_get_filter_mode,
+};
+
+/*
+ * Rejection applies to voltage and temperature alike, so the attribute is
+ * device-wide.
+ */
+static const struct iio_chan_spec_ext_info ltc2497core_ext_info[] = {
+	IIO_ENUM("filter_mode", IIO_SHARED_BY_ALL, &ltc2497core_filter_mode_enum),
+	IIO_ENUM_AVAILABLE("filter_mode", IIO_SHARED_BY_ALL,
+			   &ltc2497core_filter_mode_enum),
+	{ }
+};
+
 #define LTC2497_CHAN(_chan, _addr, _ds_name, _extra_mask) { \
 	.type = IIO_VOLTAGE, \
 	.indexed = 1, \
@@ -404,6 +484,27 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
 	if (!ddata->chip_info->has_temp)
 		indio_dev->num_channels--;
 
+	if (ddata->chip_info->has_rejection_mode) {
+		struct iio_chan_spec *channels;
+		unsigned int i;
+
+		/*
+		 * Rejection applies to every channel; ext_info is attached at
+		 * probe because a const table would expose filter_mode on all
+		 * parts unconditionally.
+		 */
+		channels = devm_kmemdup(dev, indio_dev->channels,
+					indio_dev->num_channels * sizeof(*channels),
+					GFP_KERNEL);
+		if (!channels)
+			return -ENOMEM;
+
+		for (i = 0; i < indio_dev->num_channels; i++)
+			channels[i].ext_info = ltc2497core_ext_info;
+
+		indio_dev->channels = channels;
+	}
+
 	ret = ddata->result_and_measure(ddata, LTC2497_CONFIG_DEFAULT, NULL);
 	if (ret < 0)
 		return ret;
@@ -428,8 +529,8 @@ int ltc2497core_probe(struct device *dev, struct iio_dev *indio_dev)
 
 	ddata->addr_prev = LTC2497_CONFIG_DEFAULT;
 	ddata->time_prev = ktime_get();
-	/* Power-on default mode is 1x; a conversion is already in flight. */
-	ddata->conv_time_prev = LTC2497_CONV_TIME_1X_MS;
+	/* Power-on default is 50/60Hz rejection at 1x; a conversion is already in flight. */
+	ddata->conv_time_prev = LTC2497_CONV_TIME_50_60_1X_MS;
 
 	mutex_init(&ddata->lock);
 
diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index a655b04e2454..0df2ad9b3243 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -38,6 +38,23 @@ struct ltc2497_driverdata {
 	} data __aligned(IIO_DMA_MINALIGN);
 };
 
+/*
+ * The reserved FA = FB = 1 combination is not reachable: the enum has no
+ * enumerator for it.
+ */
+static u8 ltc2497_rejection_bits(enum ltc2497_rejection rejection)
+{
+	switch (rejection) {
+	case LTC2499_REJECT_50:
+		return LTC2499_FB;
+	case LTC2499_REJECT_60:
+		return LTC2499_FA;
+	case LTC2499_REJECT_50_60:
+	default:
+		return 0;
+	}
+}
+
 static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
 				      u8 address, int *val)
 {
@@ -86,32 +103,34 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
 	}
 
 	/*
-	 * Parts with a second config byte (LTC2499: internal PTAT sensor and/or
-	 * the 2x speed mode) latch their converter configuration from that byte
-	 * and only re-evaluate it when EN2 is set; a single byte, or a second
-	 * byte with EN2 = 0, means "keep previous".  A one-byte channel select
-	 * therefore cannot pull the device back out of temperature mode, so a
-	 * voltage read after a temperature read would keep returning the PTAT
-	 * result.  Always drive the second byte with EN2 set on these parts:
+	 * Parts with a second config byte (LTC2499: internal PTAT sensor, the 2x
+	 * speed mode, and/or FA/FB line-rejection selection) latch their
+	 * converter configuration from that byte and only re-evaluate it when
+	 * EN2 is set; a single byte, or a second byte with EN2 = 0, means "keep
+	 * previous".  A one-byte channel select therefore cannot pull the device
+	 * back out of temperature mode, so a voltage read after a temperature
+	 * read would keep returning the PTAT result.  Always drive the second
+	 * byte with EN2 set on these parts:
 	 *   - temperature read: IM = 1 (SPD is ignored by the part in
-	 *     temperature mode and is left 0 here);
-	 *   - voltage read: IM = 0 (external input), plus SPD when 2x is
-	 *     selected.
-	 * FA = FB = 0 keeps the power-on simultaneous 50/60Hz rejection, whose
-	 * worst-case conversion time the driver's wait already covers.
+	 *     temperature mode and is left 0 here), plus FA/FB (rejection is
+	 *     honoured during temperature conversion);
+	 *   - voltage read: IM = 0 (external input), plus FA/FB, plus SPD when
+	 *     2x is selected.
 	 *
 	 * The byte could be skipped while the latched configuration is already
 	 * the one wanted; it is sent on every conversion for simplicity.
 	 */
-	if (ddata->chip_info->has_temp || ddata->chip_info->has_speed_mode) {
+	if (ddata->chip_info->has_temp || ddata->chip_info->has_speed_mode ||
+	    ddata->chip_info->has_rejection_mode) {
+		u8 rejection_bits = ltc2497_rejection_bits(ddata->rejection);
 		u8 cmd[2];
 
 		if (address == LTC2497_TEMP_ADDR) {
 			cmd[0] = LTC2497_ENABLE | LTC2497_CONFIG_DEFAULT;
-			cmd[1] = LTC2499_EN2 | LTC2499_IM;
+			cmd[1] = LTC2499_EN2 | LTC2499_IM | rejection_bits;
 		} else {
 			cmd[0] = LTC2497_ENABLE | address;
-			cmd[1] = LTC2499_EN2;
+			cmd[1] = LTC2499_EN2 | rejection_bits;
 			if (ddata->speed_2x)
 				cmd[1] |= LTC2499_SPD;
 		}
@@ -187,6 +206,7 @@ static const struct ltc2497_chip_info ltc2497_info[] = {
 		.name = "ltc2499",
 		.has_temp = true,
 		.has_speed_mode = true,
+		.has_rejection_mode = true,
 	},
 };
 
diff --git a/drivers/iio/adc/ltc2497.h b/drivers/iio/adc/ltc2497.h
index 219f7d49854b..34ea62c2a4bc 100644
--- a/drivers/iio/adc/ltc2497.h
+++ b/drivers/iio/adc/ltc2497.h
@@ -4,15 +4,19 @@
 #define LTC2497_CONFIG_DEFAULT		LTC2497_ENABLE
 
 /*
- * Conversion-time bounds used to gate reads.  Each value is the datasheet
- * t_CONV maximum, rounded UP to the next whole millisecond.
+ * Worst-case conversion times (datasheet t_CONV max), one per rejection/speed
+ * combination.  Both FA/FB rejection and SPD speed shift the conversion time,
+ * so both must be correct to avoid reprogramming a conversion mid-flight (-EIO).
  *
- * The 2x mode (LTC2499_SPD, LTC2499 only) disables the offset auto-calibration
- * to roughly double the output rate; adding the 2x wait time is what makes the
- * SPD control actually faster.
+ * The simultaneous 50/60Hz 1x value is also used by LTC2496/LTC2497 (no speed
+ * or rejection control) and is the power-up default.
  */
-#define LTC2497_CONV_TIME_1X_MS		150ULL	/* ceil(t_CONV_1 simult. max 149.9) */
-#define LTC2499_CONV_TIME_2X_MS		76ULL	/* ceil(t_CONV_2 simult. max  75.1) */
+#define LTC2497_CONV_TIME_50_60_1X_MS	150ULL	/* t_CONV_1 simult. max 149.9 */
+#define LTC2499_CONV_TIME_50_60_2X_MS	76ULL	/* t_CONV_2 simult. max  75.1 */
+#define LTC2499_CONV_TIME_50_1X_MS	164ULL	/* t_CONV_1 50Hz    max 163.5 */
+#define LTC2499_CONV_TIME_50_2X_MS	82ULL	/* t_CONV_2 50Hz    max  81.9 */
+#define LTC2499_CONV_TIME_60_1X_MS	137ULL	/* t_CONV_1 60Hz    max 136.3 */
+#define LTC2499_CONV_TIME_60_2X_MS	69ULL	/* t_CONV_2 60Hz    max  68.2 */
 
 /*
  * Sentinel passed as `address` to result_and_measure() to request a
@@ -24,13 +28,29 @@
 /* Second config-byte bits (LTC2499 / LTC2493 only) */
 #define LTC2499_EN2			BIT(7)	/* enable second config byte */
 #define LTC2499_IM			BIT(6)	/* 1 = measure internal temp sensor */
+#define LTC2499_FA			BIT(5)	/* line-rejection select bit A */
+#define LTC2499_FB			BIT(4)	/* line-rejection select bit B */
 #define LTC2499_SPD			BIT(3)	/* 1 = 2x output rate (offset cal off) */
 
+/*
+ * Line-frequency rejection modes selected by FA/FB in the second config byte.
+ * The datasheet's fourth combination (FA = FB = 1) is reserved, so it is not
+ * given an enumerator and is unreachable through this driver.  Applies to both
+ * voltage and temperature conversions (unlike SPD, which the part ignores while
+ * measuring temperature).
+ */
+enum ltc2497_rejection {
+	LTC2499_REJECT_50_60,	/* FA=0 FB=0: simultaneous 50/60Hz (default) */
+	LTC2499_REJECT_50,	/* FA=0 FB=1: 50Hz only */
+	LTC2499_REJECT_60,	/* FA=1 FB=0: 60Hz only */
+};
+
 struct ltc2497_chip_info {
 	const char *name;
 	u32 resolution;
 	bool has_temp;
 	bool has_speed_mode;	/* SPD bit in the 2nd config byte (LTC2499/LTC2493) */
+	bool has_rejection_mode;	/* FA/FB bits in the 2nd config byte (LTC2499) */
 	bool four_channel;	/* 4 inputs (LTC2493) instead of 16 */
 };
 
@@ -41,8 +61,14 @@ struct ltc2497core_driverdata {
 	struct mutex lock;
 	const struct ltc2497_chip_info	*chip_info;
 	u8 addr_prev;
-	bool speed_2x;	/* SPD: false = 1x (default), true = 2x */
-	/* Conversion time (ms) of the conversion currently in flight. */
+	bool speed_2x;		/* SPD: false = 1x (default), true = 2x */
+	enum ltc2497_rejection rejection;	/* FA/FB line-rejection select */
+	/*
+	 * Conversion time (ms) of the conversion currently in flight.  It is
+	 * fixed by the mode active when that conversion was started, which
+	 * differs from the newly selected mode for the first read after a
+	 * sampling_frequency or filter_mode change.
+	 */
 	unsigned int conv_time_prev;
 	int (*result_and_measure)(struct ltc2497core_driverdata *ddata,
 				  u8 address, int *val);

-- 
2.43.0



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

* [PATCH 6/6] iio: adc: ltc2497: enable line-frequency rejection on LTC2493
  2026-10-09  8:43 [PATCH 0/6] iio: adc: ltc2497: add LTC2493 support and line-frequency rejection Andrei Stancovici via B4 Relay
                   ` (4 preceding siblings ...)
  2026-10-09  8:43 ` [PATCH 5/6] iio: adc: ltc2497: add FA/FB line-frequency rejection selection Andrei Stancovici via B4 Relay
@ 2026-10-09  8:43 ` Andrei Stancovici via B4 Relay
  5 siblings, 0 replies; 10+ messages in thread
From: Andrei Stancovici via B4 Relay @ 2026-10-09  8:43 UTC (permalink / raw)
  To: Nuno Sá, Michael Hennerich, Jonathan Cameron, David Lechner,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Liam Beguin
  Cc: linux, linux-iio, devicetree, linux-kernel, Andrei Stancovici

From: Andrei Stancovici <andrei.stancovici@analog.com>

The LTC2493 carries the same second configuration byte as the LTC2499,
with identical FA/FB line-rejection semantics and the same per-rejection
conversion times (50Hz-only being the longest at 163.5ms). The generic
filter_mode infrastructure is already implemented in the core and enabled
for the LTC2499. Enable the same flag for the LTC2493.

Tested on live LTC2493 hardware connected through an IIO network backend:
all three modes are selectable; conversion times are respected; voltage
and temperature reads succeed in each mode with no -EIO.

Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2493fe.pdf
Signed-off-by: Andrei Stancovici <andrei.stancovici@analog.com>
---
 drivers/iio/adc/ltc2497.c | 1 +
 drivers/iio/adc/ltc2497.h | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
index 0df2ad9b3243..d668a81f1ff7 100644
--- a/drivers/iio/adc/ltc2497.c
+++ b/drivers/iio/adc/ltc2497.c
@@ -195,6 +195,7 @@ static const struct ltc2497_chip_info ltc2497_info[] = {
 		.name = "ltc2493",
 		.has_temp = true,
 		.has_speed_mode = true,
+		.has_rejection_mode = true,
 		.four_channel = true,
 	},
 	[TYPE_LTC2497] = {
diff --git a/drivers/iio/adc/ltc2497.h b/drivers/iio/adc/ltc2497.h
index 34ea62c2a4bc..af939e57e1f8 100644
--- a/drivers/iio/adc/ltc2497.h
+++ b/drivers/iio/adc/ltc2497.h
@@ -50,7 +50,7 @@ struct ltc2497_chip_info {
 	u32 resolution;
 	bool has_temp;
 	bool has_speed_mode;	/* SPD bit in the 2nd config byte (LTC2499/LTC2493) */
-	bool has_rejection_mode;	/* FA/FB bits in the 2nd config byte (LTC2499) */
+	bool has_rejection_mode;	/* FA/FB bits in the 2nd config byte (LTC2499/LTC2493) */
 	bool four_channel;	/* 4 inputs (LTC2493) instead of 16 */
 };
 

-- 
2.43.0



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

* Re: [PATCH 5/6] iio: adc: ltc2497: add FA/FB line-frequency rejection selection
  2026-10-09  8:43 ` [PATCH 5/6] iio: adc: ltc2497: add FA/FB line-frequency rejection selection Andrei Stancovici via B4 Relay
@ 2026-10-09  8:54   ` sashiko-bot
  0 siblings, 0 replies; 10+ messages in thread
From: sashiko-bot @ 2026-10-09  8:54 UTC (permalink / raw)
  To: Andrei Stancovici; +Cc: conor+dt, robh, devicetree

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] iio: adc: I2C DMA memory corruption via stack buffer in ltc2497_result_and_measure
- [Low] iio: data race on ddata->rejection in read_avail
--

commit 26aab6330d34e8191cc6202f7b5b3be69e9b0fb8
Author: Andrei Stancovici <andrei.stancovici@analog.com>
iio: adc: ltc2497: add FA/FB line-frequency rejection selection

This patch adds support for exposing the FA/FB line-frequency rejection
options of the LTC2499 through filter_mode on the voltage channels. It
allows selection of 50Hz, 60Hz, or both, and updates conversion times
accordingly.

Datasheet: https://www.analog.com/media/en/technical-documentation/data-sheets/2499fa.pdf

> diff --git a/drivers/iio/adc/ltc2497-core.c b/drivers/iio/adc/ltc2497-core.c
> index 816312bf0e90b..e5a8ab5681281 100644
> --- a/drivers/iio/adc/ltc2497-core.c
> +++ b/drivers/iio/adc/ltc2497-core.c
[ ... ]
> @@ -211,11 +218,13 @@ static int ltc2497core_read_avail(struct iio_dev *indio_dev,
>  				  const int **vals, int *type, int *length,
>  				  long mask)
>  {
> +	struct ltc2497core_driverdata *ddata = iio_priv(indio_dev);
> +
>  	switch (mask) {
>  	case IIO_CHAN_INFO_SAMP_FREQ:
> -		*vals = ltc2497core_samp_freq_avail;
> +		*vals = ltc2497core_samp_freq_avail[ddata->rejection];

[Severity: Low]
Does this unguarded read of ddata->rejection in ltc2497core_read_avail() race
with concurrent sysfs writes?

Concurrently, filter_mode sysfs writes can invoke
ltc2497core_set_filter_mode(), which modifies ddata->rejection while holding
the ddata->lock. While an out-of-bounds array access is structurally
prevented because the inner array size is fixed and resolved at compile time,
this unguarded read of shared mutable state violates kernel concurrency rules
and will trigger KCSAN data race warnings.

> +		*type = IIO_VAL_INT_PLUS_MICRO;
> -		*length = ARRAY_SIZE(ltc2497core_samp_freq_avail);
> +		*length = ARRAY_SIZE(ltc2497core_samp_freq_avail[ddata->rejection]);
>  		return IIO_AVAIL_LIST;
>  
>  	default:
[ ... ]
> diff --git a/drivers/iio/adc/ltc2497.c b/drivers/iio/adc/ltc2497.c
> index a655b04e2454b..0df2ad9b32437 100644
> --- a/drivers/iio/adc/ltc2497.c
> +++ b/drivers/iio/adc/ltc2497.c
[ ... ]
> @@ -86,32 +103,34 @@ static int ltc2497_result_and_measure(struct ltc2497core_driverdata *ddata,
[ ... ]
> -	if (ddata->chip_info->has_temp || ddata->chip_info->has_speed_mode) {
> +	if (ddata->chip_info->has_temp || ddata->chip_info->has_speed_mode ||
> +	    ddata->chip_info->has_rejection_mode) {
> +		u8 rejection_bits = ltc2497_rejection_bits(ddata->rejection);
>  		u8 cmd[2];
>  
>  		if (address == LTC2497_TEMP_ADDR) {
>  			cmd[0] = LTC2497_ENABLE | LTC2497_CONFIG_DEFAULT;
> -			cmd[1] = LTC2499_EN2 | LTC2499_IM;
> +			cmd[1] = LTC2499_EN2 | LTC2499_IM | rejection_bits;
>  		} else {
>  			cmd[0] = LTC2497_ENABLE | address;
> -			cmd[1] = LTC2499_EN2;
> +			cmd[1] = LTC2499_EN2 | rejection_bits;
>  			if (ddata->speed_2x)
>  				cmd[1] |= LTC2499_SPD;
>  		}
>  
>  		ret = i2c_master_send(st->client, cmd, sizeof(cmd));

[Severity: High]
This problem wasn't introduced by this patch, but since the patch modifies
this exact block and relies on it, does this code pass an unaligned stack
buffer for DMA I/O?

In ltc2497_result_and_measure(), the 2-byte array cmd is allocated on the
stack and populated with configuration bits. This array is passed directly to
i2c_master_send(). If the underlying I2C master driver uses DMA for the
transfer, mapping a stack address is illegal (especially with
CONFIG_VMAP_STACK) and can lead to memory corruption, panics, or silent
failures.

The driver properly aligns its receive buffer (st->data) with
__aligned(IIO_DMA_MINALIGN), demonstrating awareness of this requirement, but
overlooks the transmit buffer.

>  		if (ret < 0) {
>  			dev_err(&st->client->dev, "i2c transfer failed: %pe\n",
>  				ERR_PTR(ret));

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261009-submission-ltc2493-support-v1-v1-0-3dad1d4b152a@analog.com?part=5

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

* Re: [PATCH 1/6] dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support
  2026-10-09  8:43 ` [PATCH 1/6] dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support Andrei Stancovici via B4 Relay
@ 2026-10-09 12:06   ` Joshua Crofts
  2026-10-09 14:45   ` Conor Dooley
  1 sibling, 0 replies; 10+ messages in thread
From: Joshua Crofts @ 2026-10-09 12:06 UTC (permalink / raw)
  To: Andrei Stancovici via B4 Relay
  Cc: andrei.stancovici, Nuno Sá, Michael Hennerich,
	Jonathan Cameron, David Lechner, Andy Shevchenko, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Liam Beguin, linux, linux-iio,
	devicetree, linux-kernel

On Fri, 09 Oct 2026 11:43:34 +0300
Andrei Stancovici via B4 Relay <devnull+andrei.stancovici.analog.com@kernel.org> wrote:

> From: Andrei Stancovici <andrei.stancovici@analog.com>
> 
> The LTC2493 is a 24-bit delta-sigma ADC with 4 single-ended or 2
> differential inputs and an I2C interface. Its channel map matches no
> part already listed, so it gets its own compatible rather than a
> fallback; no new property is needed.
> 
> Signed-off-by: Andrei Stancovici <andrei.stancovici@analog.com>
> ---

Reviewed-by: Joshua Crofts <joshua.crofts1@gmail.com>

-- 
Kind regards,
Joshua Crofts

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

* Re: [PATCH 1/6] dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support
  2026-10-09  8:43 ` [PATCH 1/6] dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support Andrei Stancovici via B4 Relay
  2026-10-09 12:06   ` Joshua Crofts
@ 2026-10-09 14:45   ` Conor Dooley
  1 sibling, 0 replies; 10+ messages in thread
From: Conor Dooley @ 2026-10-09 14:45 UTC (permalink / raw)
  To: andrei.stancovici
  Cc: Nuno Sá, Michael Hennerich, Jonathan Cameron, David Lechner,
	Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
	Liam Beguin, linux, linux-iio, devicetree, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 75 bytes --]

Acked-by: Conor Dooley <conor.dooley@microchip.com>
pw-bot: not-applicable

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

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

end of thread, other threads:[~2026-10-09 14:45 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-09  8:43 [PATCH 0/6] iio: adc: ltc2497: add LTC2493 support and line-frequency rejection Andrei Stancovici via B4 Relay
2026-10-09  8:43 ` [PATCH 1/6] dt-bindings: iio: adc: lltc,ltc2497: add LTC2493 support Andrei Stancovici via B4 Relay
2026-10-09 12:06   ` Joshua Crofts
2026-10-09 14:45   ` Conor Dooley
2026-10-09  8:43 ` [PATCH 2/6] iio: adc: ltc2497: " Andrei Stancovici via B4 Relay
2026-10-09  8:43 ` [PATCH 3/6] iio: adc: ltc2497: add LTC2493 internal temperature channel Andrei Stancovici via B4 Relay
2026-10-09  8:43 ` [PATCH 4/6] iio: adc: ltc2497: add 2x speed mode support for the LTC2493 Andrei Stancovici via B4 Relay
2026-10-09  8:43 ` [PATCH 5/6] iio: adc: ltc2497: add FA/FB line-frequency rejection selection Andrei Stancovici via B4 Relay
2026-10-09  8:54   ` sashiko-bot
2026-10-09  8:43 ` [PATCH 6/6] iio: adc: ltc2497: enable line-frequency rejection on LTC2493 Andrei Stancovici via B4 Relay

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox