[PATCH 2/2] iio: adc: ti-ads112c14: fix settlingtime creep on write back

From: David Lechner (TI)

Date: Fri Sep 25 2026 - 17:29:09 EST


Fix the settlingtime attribute so that writing back the value that was
read does not change the setting.

Reading the attribute rounds the total settling time down to the nearest
microsecond. Writing it subtracted the fixed latency (also rounded down
to the nearest microsecond) and then rounded the remaining delay up to
the next tmod period. These don't agree, so writing back the value just
read could select the next higher DELAY value, causing the settling time
to creep up on each write.

Instead, convert the requested total settling time to tmod periods
(rounding up) and compare that against the fixed latency plus delay in
tmod periods. This picks the smallest DELAY value that reads back as
greater than or equal to the requested value.

Fixes: 839cbb1e2331 ("iio: adc: ti-ads112c14: add settlingtime attribute")
Reported-by: Sashiko <sashiko-bot@xxxxxxxxxx>
Closes: https://sashiko.dev/#/message/20260910-iio-adc-ti-ads112c14-filter-support-v3-9-e5a9b27ddb1a%40baylibre.com
Signed-off-by: David Lechner (TI) <dlechner@xxxxxxxxxxxx>
---
drivers/iio/adc/ti-ads112c14.c | 25 +++++++++----------------
1 file changed, 9 insertions(+), 16 deletions(-)

diff --git a/drivers/iio/adc/ti-ads112c14.c b/drivers/iio/adc/ti-ads112c14.c
index 483f159e2836..3f46ebb3d84d 100644
--- a/drivers/iio/adc/ti-ads112c14.c
+++ b/drivers/iio/adc/ti-ads112c14.c
@@ -655,29 +655,22 @@ static int ads112c14_find_delay_for_settling_time_us(struct ads112c14_data *data
struct ads112c14_channel_state *channel_state,
s64 settling_time_us, u8 *delay)
{
- u64 delay_us, delay_tmod_needed;
- u32 fixed_latency_us;
- int ret, fmod_Hz;
+ int latency_tmod, fmod_Hz;
+ u64 total_tmod_needed;
u8 i;

- ret = ads112c14_get_settling_time_us(data, channel_state, 0, &fixed_latency_us);
- if (ret)
- return ret;
-
- if (settling_time_us <= fixed_latency_us) {
- *delay = 0;
- return 0;
- }
-
fmod_Hz = ads112c14_get_fmod_Hz(data, channel_state);
if (fmod_Hz <= 0)
return -EINVAL;

- delay_us = settling_time_us - fixed_latency_us;
- delay_tmod_needed = DIV_ROUND_UP_ULL(delay_us * fmod_Hz, USEC_PER_SEC);
+ latency_tmod = ads112c14_get_latency_tmod(channel_state);
+ if (latency_tmod < 0)
+ return latency_tmod;
+
+ total_tmod_needed = DIV_ROUND_UP_ULL(settling_time_us * fmod_Hz, USEC_PER_SEC);

- for (i = 1; i < ADS112C14_DELAY_MAX; i++) {
- if (ads112c14_delay_to_tmod(i) >= delay_tmod_needed)
+ for (i = 0; i < ADS112C14_DELAY_MAX; i++) {
+ if (latency_tmod + ads112c14_delay_to_tmod(i) >= total_tmod_needed)
break;
}


--
2.43.0