* [PATCH v6 0/3 ] iio: adc: Add support for TI ADS1110 to ti-ads1100 driver
@ 2026-07-11 18:44 Jakub Szczudlo
2026-07-11 18:44 ` [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode Jakub Szczudlo
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Jakub Szczudlo @ 2026-07-11 18:44 UTC (permalink / raw)
To: linux-iio
Cc: andy, antoniu.miclaus, conor+dt, devicetree, dlechner, duje,
jic23, jishnu.prakash, jorge.marques, joshua.crofts1, krzk+dt,
linusw, jakubszczudlo40, marcelo.schmitt, mazziesaccount,
mike.looijmans, nuno.sa, robh, sakari.ailus, wens
Add support for the TI ADS1110 to the existing ADS1100 ADC IIO driver.
The ADS1110 is pin-to-pin compatible with the ADS1100 while providing
higher resolution and an internal voltage reference. This patch series
extends driver support for ADS1110, updates device tree bindings and
Kconfig text, and improves the overall hardware description for the
TI ADS1100 family.
Tested on: Raspberry pi 3b+ with 7.0 stable kernel
Signed-off-by: Jakub Szczudlo <jakubszczudlo40@gmail.com>
---
V5 -> V6:
- correct for loop so it will be more readible and return error when iterator matches array size
- fix SI unit letter size
- correct using available_data_rate_hz array when using ads1110
- bring cast to char* back
- Link to v5: https://lore.kernel.org/linux-iio/20260628194341.66752-1-jakubszczudlo40@gmail.com/
V4 -> V5:
- Correct pm macros to be more generic
- fix variables ordering in new functions
- delete unnecessary casts
- add unit to variable names
- change array name so it will sound as array not variable
- correct get_vref_milivolts so it will check if not negative value returned
- delete unnecessary short read check in i2c receive
- Link to v4: https://lore.kernel.org/linux-iio/20260622221550.374235-1-jakubszczudlo40@gmail.com/
V3 -> V4:
- make fixes patch the first change in the series
- correct error handling when short read
- use ACQUIRE macros from pm_runtime.h in new functions
- Link to v3: https://lore.kernel.org/linux-iio/20260613190957.654798-1-jakubszczudlo40@gmail.com/
V2 -> V3:
- clean patch from unreleated changes
- divide adding support for ads1110 into separate patch
- add missing changelog
- Link to v2: https://lore.kernel.org/linux-iio/20260607183542.368184-1-jakubszczudlo40@gmail.com/
V1 -> V2:
- go from creating new driver to extending ADS1100 driver to support ADS1110
- Link to v1: https://lore.kernel.org/linux-iio/20260527164312.355729-1-jakubszczudlo40@gmail.com/
Jakub Szczudlo (3):
iio: adc: Fix incorrect reading when datarate changed in single mode
dt-bindings: iio: adc: ti,ads1100: add support for ADS1110
iio: adc: Add ti-ads1110 support to ti-ads1100 driver
.../bindings/iio/adc/ti,ads1100.yaml | 10 +-
drivers/iio/adc/Kconfig | 9 +-
drivers/iio/adc/ti-ads1100.c | 147 +++++++++++++++---
3 files changed, 137 insertions(+), 29 deletions(-)
--
2.47.3
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode 2026-07-11 18:44 [PATCH v6 0/3 ] iio: adc: Add support for TI ADS1110 to ti-ads1100 driver Jakub Szczudlo @ 2026-07-11 18:44 ` Jakub Szczudlo 2026-07-11 18:54 ` sashiko-bot 2026-07-11 19:51 ` David Lechner 2026-07-11 18:44 ` [PATCH v6 2/3] dt-bindings: iio: adc: ti,ads1100: add support for ADS1110 Jakub Szczudlo 2026-07-11 18:44 ` [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver Jakub Szczudlo 2 siblings, 2 replies; 10+ messages in thread From: Jakub Szczudlo @ 2026-07-11 18:44 UTC (permalink / raw) To: linux-iio Cc: andy, antoniu.miclaus, conor+dt, devicetree, dlechner, duje, jic23, jishnu.prakash, jorge.marques, joshua.crofts1, krzk+dt, linusw, jakubszczudlo40, marcelo.schmitt, mazziesaccount, mike.looijmans, nuno.sa, robh, sakari.ailus, wens When device is suspended and it is in single mode then changing datarate doesn't make it actual wait for new measurement, so to be sure that read after change is correct functions that changes datarate and gain will wait for new data. Fixes: 541880542f2b ("iio: adc: Add TI ADS1100 and ADS1000") Signed-off-by: Jakub Szczudlo <jakubszczudlo40@gmail.com> --- drivers/iio/adc/ti-ads1100.c | 67 +++++++++++++++++++++++++++++++++--- 1 file changed, 63 insertions(+), 4 deletions(-) diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c index 9fe8d54cce83..6ad80d42d390 100644 --- a/drivers/iio/adc/ti-ads1100.c +++ b/drivers/iio/adc/ti-ads1100.c @@ -15,10 +15,12 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/iopoll.h> #include <linux/mutex.h> #include <linux/property.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/time.h> #include <linux/units.h> #include <linux/iio/iio.h> @@ -43,6 +45,9 @@ static const int ads1100_data_rate[] = { 128, 32, 16, 8 }; static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 }; +/* Timeout based on the minimum sample rate of 8 SPS (7500ms) */ +#define ADS1100_MAX_DRDY_TIMEOUT_US (7500 * USEC_PER_MSEC) + struct ads1100_data { struct i2c_client *client; struct regulator *reg_vdd; @@ -123,10 +128,46 @@ static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val) return 0; } +static bool ads1100_new_data_not_ready(struct ads1100_data *data) +{ + u8 buffer[3]; + int ret; + + ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); + if (ret < 0) { + dev_err(&data->client->dev, "I2C read fail: %d\n", ret); + return true; + } + + return FIELD_GET(ADS1100_CFG_ST_BSY, buffer[2]); +} + +static int ads1100_poll_data_ready(struct ads1100_data *data) +{ + int data_rate_Hz = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)]; + /* To be sure we wait 5 times more than data rate */ + unsigned long wait_time_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, 5 * data_rate_Hz); + bool data_ready; + u8 buffer[3]; + int ret; + + /* To be sure that polled value will have value after config change */ + ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); + if (ret < 0) { + dev_err(&data->client->dev, "I2C read fail: %d\n", ret); + return ret; + } + + return readx_poll_timeout(ads1100_new_data_not_ready, data, + data_ready, data_ready != 0, + wait_time_us, ADS1100_MAX_DRDY_TIMEOUT_US); +} + static int ads1100_set_scale(struct ads1100_data *data, int val, int val2) { int microvolts; int gain; + int ret; /* With Vdd between 2.7 and 5V, the scale is always below 1 */ if (val) @@ -135,6 +176,11 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2) if (!val2) return -EINVAL; + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&data->client->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + microvolts = regulator_get_voltage(data->reg_vdd); /* * val2 is in 'micro' units, n = val2 / 1000000 @@ -149,22 +195,35 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2) ads1100_set_config_bits(data, ADS1100_PGA_MASK, ffs(gain) - 1); - return 0; + return ads1100_poll_data_ready(data); } static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate) { unsigned int i; unsigned int size; + int ret; size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1; for (i = 0; i < size; i++) { if (ads1100_data_rate[i] == rate) - return ads1100_set_config_bits(data, ADS1100_DR_MASK, - FIELD_PREP(ADS1100_DR_MASK, i)); + break; } - return -EINVAL; + if (i == size) + return -EINVAL; + + PM_RUNTIME_ACQUIRE_IF_ENABLED_AUTOSUSPEND(&data->client->dev, pm); + ret = PM_RUNTIME_ACQUIRE_ERR(&pm); + if (ret) + return ret; + + ret = ads1100_set_config_bits(data, ADS1100_DR_MASK, + FIELD_PREP(ADS1100_DR_MASK, i)); + if (ret) + return ret; + + return ads1100_poll_data_ready(data); } static int ads1100_get_vdd_millivolts(struct ads1100_data *data) -- 2.47.3 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode 2026-07-11 18:44 ` [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode Jakub Szczudlo @ 2026-07-11 18:54 ` sashiko-bot 2026-07-11 19:51 ` David Lechner 1 sibling, 0 replies; 10+ messages in thread From: sashiko-bot @ 2026-07-11 18:54 UTC (permalink / raw) To: Jakub Szczudlo; +Cc: devicetree, robh, conor+dt Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [High] The newly introduced polling mechanism in `ads1100_poll_data_ready` uses an inverted wait condition that guarantees failure, silently swallows I2C errors, and incorrectly relies on a status bit that is always zero in continuous mode. -- --- Patch [1]: [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode --- commit 9efe89d3c5acb6ee87bd34da568f0f0c50cd6e20 Author: Jakub Szczudlo <jakubszczudlo40@gmail.com> iio: adc: Fix incorrect reading when datarate changed in single mode When device is suspended and it is in single mode then changing datarate doesn't make it actual wait for new measurement, so to be sure that read after change is correct functions that changes datarate and gain will wait for new data. > diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c > --- a/drivers/iio/adc/ti-ads1100.c > +++ b/drivers/iio/adc/ti-ads1100.c [ ... ] > +static bool ads1100_new_data_not_ready(struct ads1100_data *data) > +{ > + u8 buffer[3]; > + int ret; > + > + ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); > + if (ret < 0) { > + dev_err(&data->client->dev, "I2C read fail: %d\n", ret); > + return true; [Severity: High] If an I2C read error occurs, this returns true. Since the polling condition below checks for non-zero, won't this cause the poll to exit immediately and silently treat the hardware failure as a successful wait? > + } > + > + return FIELD_GET(ADS1100_CFG_ST_BSY, buffer[2]); > +} > + > +static int ads1100_poll_data_ready(struct ads1100_data *data) > +{ > + int data_rate_Hz = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)]; > + /* To be sure we wait 5 times more than data rate */ > + unsigned long wait_time_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, 5 * data_rate_Hz); > + bool data_ready; > + u8 buffer[3]; > + int ret; > + > + /* To be sure that polled value will have value after config change */ > + ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); > + if (ret < 0) { > + dev_err(&data->client->dev, "I2C read fail: %d\n", ret); > + return ret; > + } > + > + return readx_poll_timeout(ads1100_new_data_not_ready, data, > + data_ready, data_ready != 0, > + wait_time_us, ADS1100_MAX_DRDY_TIMEOUT_US); [Severity: High] Is this condition inverted? The readx_poll_timeout macro stops polling when the condition evaluates to true. With data_ready != 0, it stops immediately if the device is busy, and spins until timeout if the device is ready. Additionally, because acquiring PM runtime resumes the device into continuous mode, the ST/BSY bit is always 0. Does this mean every write to the scale or data rate attributes will hang for 7.5 seconds and return -ETIMEDOUT? > +} -- Sashiko AI review · https://sashiko.dev/#/patchset/20260711184414.1013686-1-jakubszczudlo40@gmail.com?part=1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode 2026-07-11 18:44 ` [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode Jakub Szczudlo 2026-07-11 18:54 ` sashiko-bot @ 2026-07-11 19:51 ` David Lechner 1 sibling, 0 replies; 10+ messages in thread From: David Lechner @ 2026-07-11 19:51 UTC (permalink / raw) To: Jakub Szczudlo, linux-iio Cc: andy, antoniu.miclaus, conor+dt, devicetree, duje, jic23, jishnu.prakash, jorge.marques, joshua.crofts1, krzk+dt, linusw, marcelo.schmitt, mazziesaccount, mike.looijmans, nuno.sa, robh, sakari.ailus, wens On 7/11/26 1:44 PM, Jakub Szczudlo wrote: > When device is suspended and it is in single mode then changing > datarate doesn't make it actual wait for new measurement, so to s/actual/actually/ s/for new/for a new/ > be sure that read after change is correct functions that changes > datarate and gain will wait for new data. > > Fixes: 541880542f2b ("iio: adc: Add TI ADS1100 and ADS1000") > Signed-off-by: Jakub Szczudlo <jakubszczudlo40@gmail.com> > --- > drivers/iio/adc/ti-ads1100.c | 67 +++++++++++++++++++++++++++++++++--- > 1 file changed, 63 insertions(+), 4 deletions(-) > > diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c > index 9fe8d54cce83..6ad80d42d390 100644 > --- a/drivers/iio/adc/ti-ads1100.c > +++ b/drivers/iio/adc/ti-ads1100.c > @@ -15,10 +15,12 @@ > #include <linux/module.h> > #include <linux/init.h> > #include <linux/i2c.h> > +#include <linux/iopoll.h> > #include <linux/mutex.h> > #include <linux/property.h> > #include <linux/pm_runtime.h> > #include <linux/regulator/consumer.h> > +#include <linux/time.h> > #include <linux/units.h> > > #include <linux/iio/iio.h> > @@ -43,6 +45,9 @@ > static const int ads1100_data_rate[] = { 128, 32, 16, 8 }; > static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 }; > > +/* Timeout based on the minimum sample rate of 8 SPS (7500ms) */ > +#define ADS1100_MAX_DRDY_TIMEOUT_US (7500 * USEC_PER_MSEC) > + > struct ads1100_data { > struct i2c_client *client; > struct regulator *reg_vdd; > @@ -123,10 +128,46 @@ static int ads1100_get_adc_result(struct ads1100_data *data, int chan, int *val) > return 0; > } > > +static bool ads1100_new_data_not_ready(struct ads1100_data *data) > +{ > + u8 buffer[3]; > + int ret; > + > + ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); > + if (ret < 0) { > + dev_err(&data->client->dev, "I2C read fail: %d\n", ret); > + return true; > + } > + > + return FIELD_GET(ADS1100_CFG_ST_BSY, buffer[2]); > +} > + > +static int ads1100_poll_data_ready(struct ads1100_data *data) > +{ > + int data_rate_Hz = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)]; > + /* To be sure we wait 5 times more than data rate */ > + unsigned long wait_time_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, 5 * data_rate_Hz); > + bool data_ready; > + u8 buffer[3]; > + int ret; > + > + /* To be sure that polled value will have value after config change */ > + ret = i2c_master_recv(data->client, (char *)&buffer, sizeof(buffer)); > + if (ret < 0) { > + dev_err(&data->client->dev, "I2C read fail: %d\n", ret); > + return ret; > + } > + > + return readx_poll_timeout(ads1100_new_data_not_ready, data, > + data_ready, data_ready != 0, This is a bit confusing. The function says data_not_ready, but the variable is data_ready, so when data_ready is true, is it ready or not? Also no need to compare a bool to 0. It would be easier to understand if the function was named ads1100_new_data_is_ready() and returned true when data is ready. > + wait_time_us, ADS1100_MAX_DRDY_TIMEOUT_US); > +} > + ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v6 2/3] dt-bindings: iio: adc: ti,ads1100: add support for ADS1110 2026-07-11 18:44 [PATCH v6 0/3 ] iio: adc: Add support for TI ADS1110 to ti-ads1100 driver Jakub Szczudlo 2026-07-11 18:44 ` [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode Jakub Szczudlo @ 2026-07-11 18:44 ` Jakub Szczudlo 2026-07-11 18:44 ` [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver Jakub Szczudlo 2 siblings, 0 replies; 10+ messages in thread From: Jakub Szczudlo @ 2026-07-11 18:44 UTC (permalink / raw) To: linux-iio Cc: andy, antoniu.miclaus, conor+dt, devicetree, dlechner, duje, jic23, jishnu.prakash, jorge.marques, joshua.crofts1, krzk+dt, linusw, jakubszczudlo40, marcelo.schmitt, mazziesaccount, mike.looijmans, nuno.sa, robh, sakari.ailus, wens, Krzysztof Kozlowski Register layouts are the same as for ADS1100 but ADS1110 have different data rates and have internal voltage reference that is always 2.048V. Also correct order of ads so they will be sorted alphabetically. Signed-off-by: Jakub Szczudlo <jakubszczudlo40@gmail.com> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com> --- .../devicetree/bindings/iio/adc/ti,ads1100.yaml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml b/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml index 970ccab15e1e..28c5e2dd0ad6 100644 --- a/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml +++ b/Documentation/devicetree/bindings/iio/adc/ti,ads1100.yaml @@ -4,19 +4,23 @@ $id: http://devicetree.org/schemas/iio/adc/ti,ads1100.yaml# $schema: http://devicetree.org/meta-schemas/core.yaml# -title: TI ADS1100/ADS1000 single channel I2C analog to digital converter +title: TI ADS1100 and similar single channel I2C Analog to Digital Converters maintainers: - Mike Looijmans <mike.looijmans@topic.nl> description: | - Datasheet at: https://www.ti.com/lit/gpn/ads1100 + Datasheets: + - https://www.ti.com/lit/gpn/ads1000 + - https://www.ti.com/lit/gpn/ads1100 + - https://www.ti.com/lit/gpn/ads1110 properties: compatible: enum: - - ti,ads1100 - ti,ads1000 + - ti,ads1100 + - ti,ads1110 reg: maxItems: 1 -- 2.47.3 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver 2026-07-11 18:44 [PATCH v6 0/3 ] iio: adc: Add support for TI ADS1110 to ti-ads1100 driver Jakub Szczudlo 2026-07-11 18:44 ` [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode Jakub Szczudlo 2026-07-11 18:44 ` [PATCH v6 2/3] dt-bindings: iio: adc: ti,ads1100: add support for ADS1110 Jakub Szczudlo @ 2026-07-11 18:44 ` Jakub Szczudlo 2026-07-11 18:57 ` sashiko-bot 2026-07-11 20:01 ` David Lechner 2 siblings, 2 replies; 10+ messages in thread From: Jakub Szczudlo @ 2026-07-11 18:44 UTC (permalink / raw) To: linux-iio Cc: andy, antoniu.miclaus, conor+dt, devicetree, dlechner, duje, jic23, jishnu.prakash, jorge.marques, joshua.crofts1, krzk+dt, linusw, jakubszczudlo40, marcelo.schmitt, mazziesaccount, mike.looijmans, nuno.sa, robh, sakari.ailus, wens Add ADS1110 support that have faster datarate than ADS1100, it also uses internal voltage reference of 2.048V for measurement. Signed-off-by: Jakub Szczudlo <jakubszczudlo40@gmail.com> --- drivers/iio/adc/Kconfig | 9 ++-- drivers/iio/adc/ti-ads1100.c | 84 +++++++++++++++++++++++++++--------- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 1c663c98c6c9..2459ff2af105 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -1765,11 +1765,14 @@ config TI_ADS1018 called ti-ads1018. config TI_ADS1100 - tristate "Texas Instruments ADS1100 and ADS1000 ADC" + tristate "Texas Instruments ADS1100 and similar single channel I2C ADC" depends on I2C help - If you say yes here you get support for Texas Instruments ADS1100 and - ADS1000 ADC chips. + If you say yes here you get support for TI single channel I2C Analog + Devices. + * ADS1000 12-Bit, 128 MSPS Analog-to-Digital Converter + * ADS1100 16-Bit, 128 MSPS Analog-to-Digital Converter + * ADS1110 16-Bit, 240 MSPS Analog-to-Digital Converter This driver can also be built as a module. If so, the module will be called ti-ads1100. diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c index 6ad80d42d390..06892ebc593d 100644 --- a/drivers/iio/adc/ti-ads1100.c +++ b/drivers/iio/adc/ti-ads1100.c @@ -5,7 +5,7 @@ * Copyright (c) 2023, Topic Embedded Products * * Datasheet: https://www.ti.com/lit/gpn/ads1100 - * IIO driver for ADS1100 and ADS1000 ADC 16-bit I2C + * IIO driver for ADS1100 and similar single channel ADC 16-bit I2C */ #include <linux/bitfield.h> @@ -41,20 +41,44 @@ #define ADS1100_SINGLESHOT ADS1100_CFG_SC #define ADS1100_SLEEP_DELAY_MS 2000 +#define ADS1110_INTERNAL_REF_mV 2048 static const int ads1100_data_rate[] = { 128, 32, 16, 8 }; +static const int ads1110_data_rate[] = { 240, 60, 30, 15 }; static const int ads1100_data_rate_bits[] = { 12, 14, 15, 16 }; /* Timeout based on the minimum sample rate of 8 SPS (7500ms) */ #define ADS1100_MAX_DRDY_TIMEOUT_US (7500 * USEC_PER_MSEC) +struct ads1100_config { + const char *name; + const int *available_data_rate_hz; + const int data_rate_count; + bool has_internal_vref_only; +}; + +static const struct ads1100_config ads1100_config = { + .name = "ads1100", + .available_data_rate_hz = ads1100_data_rate, + .data_rate_count = ARRAY_SIZE(ads1100_data_rate), + .has_internal_vref_only = false, +}; + +static const struct ads1100_config ads1110_config = { + .name = "ads1110", + .available_data_rate_hz = ads1110_data_rate, + .data_rate_count = ARRAY_SIZE(ads1110_data_rate), + .has_internal_vref_only = true, +}; + struct ads1100_data { struct i2c_client *client; struct regulator *reg_vdd; struct mutex lock; int scale_avail[2 * 4]; /* 4 gain settings */ + const struct ads1100_config *ads_config; u8 config; - bool supports_data_rate; /* Only the ADS1100 can select the rate */ + bool supports_data_rate; }; static const struct iio_chan_spec ads1100_channel = { @@ -90,6 +114,20 @@ static int ads1100_set_config_bits(struct ads1100_data *data, u8 mask, u8 value) return 0; }; +static int ads1100_get_vref_milivolts(struct ads1100_data *data) +{ + int voltage_uV; + + if (data->ads_config->has_internal_vref_only) + return ADS1110_INTERNAL_REF_mV; + + voltage_uV = regulator_get_voltage(data->reg_vdd); + if (voltage_uV < 0) + return voltage_uV; + + return voltage_uV / (MICRO / MILLI); +} + static int ads1100_data_bits(struct ads1100_data *data) { return ads1100_data_rate_bits[FIELD_GET(ADS1100_DR_MASK, data->config)]; @@ -144,7 +182,8 @@ static bool ads1100_new_data_not_ready(struct ads1100_data *data) static int ads1100_poll_data_ready(struct ads1100_data *data) { - int data_rate_Hz = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)]; + int data_rate_index = FIELD_GET(ADS1100_DR_MASK, data->config); + int data_rate_Hz = data->ads_config->available_data_rate_hz[data_rate_index]; /* To be sure we wait 5 times more than data rate */ unsigned long wait_time_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, 5 * data_rate_Hz); bool data_ready; @@ -181,7 +220,7 @@ static int ads1100_set_scale(struct ads1100_data *data, int val, int val2) if (ret) return ret; - microvolts = regulator_get_voltage(data->reg_vdd); + microvolts = ads1100_get_vref_milivolts(data) * (MICRO / MILLI); /* * val2 is in 'micro' units, n = val2 / 1000000 * result must be millivolts, d = microvolts / 1000 @@ -204,9 +243,9 @@ static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate) unsigned int size; int ret; - size = data->supports_data_rate ? ARRAY_SIZE(ads1100_data_rate) : 1; + size = data->supports_data_rate ? data->ads_config->data_rate_count : 1; for (i = 0; i < size; i++) { - if (ads1100_data_rate[i] == rate) + if (data->ads_config->available_data_rate_hz[i] == rate) break; } @@ -226,14 +265,9 @@ static int ads1100_set_data_rate(struct ads1100_data *data, int chan, int rate) return ads1100_poll_data_ready(data); } -static int ads1100_get_vdd_millivolts(struct ads1100_data *data) -{ - return regulator_get_voltage(data->reg_vdd) / (MICRO / MILLI); -} - static void ads1100_calc_scale_avail(struct ads1100_data *data) { - int millivolts = ads1100_get_vdd_millivolts(data); + int millivolts = ads1100_get_vref_milivolts(data); unsigned int i; for (i = 0; i < ARRAY_SIZE(data->scale_avail) / 2; i++) { @@ -255,9 +289,9 @@ static int ads1100_read_avail(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: *type = IIO_VAL_INT; - *vals = ads1100_data_rate; + *vals = data->ads_config->available_data_rate_hz; if (data->supports_data_rate) - *length = ARRAY_SIZE(ads1100_data_rate); + *length = data->ads_config->data_rate_count; else *length = 1; return IIO_AVAIL_LIST; @@ -276,6 +310,7 @@ static int ads1100_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { int ret; + int data_rate_index; struct ads1100_data *data = iio_priv(indio_dev); guard(mutex)(&data->lock); @@ -292,12 +327,12 @@ static int ads1100_read_raw(struct iio_dev *indio_dev, return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: /* full-scale is the supply voltage in millivolts */ - *val = ads1100_get_vdd_millivolts(data); + *val = ads1100_get_vref_milivolts(data); *val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config); return IIO_VAL_FRACTIONAL_LOG2; case IIO_CHAN_INFO_SAMP_FREQ: - *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, - data->config)]; + data_rate_index = FIELD_GET(ADS1100_DR_MASK, data->config); + *val = data->ads_config->available_data_rate_hz[data_rate_index]; return IIO_VAL_INT; default: return -EINVAL; @@ -397,6 +432,11 @@ static int ads1100_probe(struct i2c_client *client) if (ret) return ret; + data->ads_config = i2c_get_match_data(client); + if (!data->ads_config) + return dev_err_probe(dev, -EINVAL, + "Can't get device data from firmware\n"); + ret = ads1100_setup(data); if (ret) return dev_err_probe(dev, ret, @@ -459,16 +499,18 @@ static DEFINE_RUNTIME_DEV_PM_OPS(ads1100_pm_ops, NULL); static const struct i2c_device_id ads1100_id[] = { - { .name = "ads1100" }, - { .name = "ads1000" }, + { .name = "ads1000", .driver_data = (kernel_ulong_t)&ads1100_config }, + { .name = "ads1100", .driver_data = (kernel_ulong_t)&ads1100_config }, + { .name = "ads1110", .driver_data = (kernel_ulong_t)&ads1110_config }, { } }; MODULE_DEVICE_TABLE(i2c, ads1100_id); static const struct of_device_id ads1100_of_match[] = { - {.compatible = "ti,ads1100" }, - {.compatible = "ti,ads1000" }, + { .compatible = "ti,ads1000", .data = &ads1100_config }, + { .compatible = "ti,ads1100", .data = &ads1100_config }, + { .compatible = "ti,ads1110", .data = &ads1110_config }, { } }; -- 2.47.3 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver 2026-07-11 18:44 ` [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver Jakub Szczudlo @ 2026-07-11 18:57 ` sashiko-bot 2026-07-11 20:01 ` David Lechner 1 sibling, 0 replies; 10+ messages in thread From: sashiko-bot @ 2026-07-11 18:57 UTC (permalink / raw) To: Jakub Szczudlo; +Cc: conor+dt, robh, devicetree Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider: - [High] Incorrect polling condition in `readx_poll_timeout` causes premature loop termination and timeouts. - [Medium] Negative error codes from `regulator_get_voltage` are propagated without checks, leaking to userspace as valid scale values. - [Medium] The IIO device name is hardcoded to "ads1100", ignoring the newly introduced `name` field in `ads1100_config`. - [Low] The Kconfig help text erroneously claims the device speeds are in 'MSPS' rather than 'SPS'. - [Low] Typo in function name: `ads1100_get_vref_milivolts` instead of `millivolts`. -- --- Patch [3]: [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver --- commit 28295190b9a9db57f2e01d15ded56ba73c22d69b Author: Jakub Szczudlo <jakubszczudlo40@gmail.com> iio: adc: Add ti-ads1110 support to ti-ads1100 driver Add ADS1110 support that have faster datarate than ADS1100, it also uses internal voltage reference of 2.048V for measurement. > diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig > index 1c663c98c6c96..2459ff2af1050 100644 > --- a/drivers/iio/adc/Kconfig > +++ b/drivers/iio/adc/Kconfig > @@ -1765,11 +1765,14 @@ config TI_ADS1018 > called ti-ads1018. > > config TI_ADS1100 > - tristate "Texas Instruments ADS1100 and ADS1000 ADC" > + tristate "Texas Instruments ADS1100 and similar single channel I2C ADC" > depends on I2C > help > - If you say yes here you get support for Texas Instruments ADS1100 and > - ADS1000 ADC chips. > + If you say yes here you get support for TI single channel I2C Analog > + Devices. > + * ADS1000 12-Bit, 128 MSPS Analog-to-Digital Converter > + * ADS1100 16-Bit, 128 MSPS Analog-to-Digital Converter > + * ADS1110 16-Bit, 240 MSPS Analog-to-Digital Converter [Severity: Low] Does this code use the correct units for the datarate? The ADS1100 and similar hardware typically operate at 8 to 240 SPS (Samples Per Second). MSPS implies millions of samples per second, which seems too high. > diff --git a/drivers/iio/adc/ti-ads1100.c b/drivers/iio/adc/ti-ads1100.c > index 6ad80d42d390a..06892ebc593d0 100644 > --- a/drivers/iio/adc/ti-ads1100.c > +++ b/drivers/iio/adc/ti-ads1100.c > @@ -90,6 +114,20 @@ static int ads1100_set_config_bits(struct ads1100_data *data, u8 mask, u8 value) > return 0; > }; > > +static int ads1100_get_vref_milivolts(struct ads1100_data *data) [Severity: Low] This isn't a bug, but there is a typo in the function name ads1100_get_vref_milivolts (milivolts instead of millivolts). > +{ > + int voltage_uV; > + > + if (data->ads_config->has_internal_vref_only) > + return ADS1110_INTERNAL_REF_mV; > + > + voltage_uV = regulator_get_voltage(data->reg_vdd); > + if (voltage_uV < 0) > + return voltage_uV; [Severity: Medium] Does this leak negative error codes to callers? If regulator_get_voltage() fails, it returns a negative error code like -EINVAL. Callers like ads1100_read_raw() and ads1100_calc_scale_avail() appear to use the return value from ads1100_get_vref_milivolts() without checking for errors. This could expose negative scale values to userspace. > + > + return voltage_uV / (MICRO / MILLI); > +} > > @@ -144,7 +182,8 @@ static bool ads1100_new_data_not_ready(struct ads1100_data *data) > > static int ads1100_poll_data_ready(struct ads1100_data *data) > { > - int data_rate_Hz = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, data->config)]; > + int data_rate_index = FIELD_GET(ADS1100_DR_MASK, data->config); > + int data_rate_Hz = data->ads_config->available_data_rate_hz[data_rate_index]; > /* To be sure we wait 5 times more than data rate */ > unsigned long wait_time_us = DIV_ROUND_CLOSEST(USEC_PER_SEC, 5 * data_rate_Hz); > bool data_ready; [Severity: High] Does this function terminate polling prematurely? When readx_poll_timeout() is called later in ads1100_poll_data_ready() to wait for the conversion: return readx_poll_timeout(ads1100_new_data_not_ready, data, data_ready, data_ready != 0, wait_time_us, ADS1100_MAX_DRDY_TIMEOUT_US); The termination condition used is data_ready != 0. However, the polled function ads1100_new_data_not_ready() reads the busy bit and returns true (non-zero) when the device is still busy, and false (zero) when the data is ready. Does this cause readx_poll_timeout() to immediately return success when the device is busy, or loop until a timeout occurs if the device is ready? > > @@ -397,6 +432,11 @@ static int ads1100_probe(struct i2c_client *client) > if (ret) > return ret; > > + data->ads_config = i2c_get_match_data(client); > + if (!data->ads_config) > + return dev_err_probe(dev, -EINVAL, > + "Can't get device data from firmware\n"); > + [Severity: Medium] Is the IIO device name hardcoded to ads1100 instead of using the name from ads1100_config? Earlier in ads1100_probe(), the code sets: indio_dev->name = "ads1100"; Since the newly introduced ads1100_config struct adds a name field (e.g. ads1110), does hardcoding the name ignore the config and potentially break userspace device matching for the ADS1110? > ret = ads1100_setup(data); > if (ret) > return dev_err_probe(dev, ret, -- Sashiko AI review · https://sashiko.dev/#/patchset/20260711184414.1013686-1-jakubszczudlo40@gmail.com?part=3 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver 2026-07-11 18:44 ` [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver Jakub Szczudlo 2026-07-11 18:57 ` sashiko-bot @ 2026-07-11 20:01 ` David Lechner 2026-07-12 10:16 ` Jakub Szczudło 1 sibling, 1 reply; 10+ messages in thread From: David Lechner @ 2026-07-11 20:01 UTC (permalink / raw) To: Jakub Szczudlo, linux-iio Cc: andy, antoniu.miclaus, conor+dt, devicetree, duje, jic23, jishnu.prakash, jorge.marques, joshua.crofts1, krzk+dt, linusw, marcelo.schmitt, mazziesaccount, mike.looijmans, nuno.sa, robh, sakari.ailus, wens On 7/11/26 1:44 PM, Jakub Szczudlo wrote: > Add ADS1110 support that have faster datarate than ADS1100, it also uses > internal voltage reference of 2.048V for measurement. > ... > +static int ads1100_get_vref_milivolts(struct ads1100_data *data) > +{ > + int voltage_uV; > + > + if (data->ads_config->has_internal_vref_only) > + return ADS1110_INTERNAL_REF_mV; > + > + voltage_uV = regulator_get_voltage(data->reg_vdd); > + if (voltage_uV < 0) > + return voltage_uV; > + > + return voltage_uV / (MICRO / MILLI); > +} > + ... T; > @@ -276,6 +310,7 @@ static int ads1100_read_raw(struct iio_dev *indio_dev, > int *val2, long mask) > { > int ret; > + int data_rate_index; > struct ads1100_data *data = iio_priv(indio_dev); > > guard(mutex)(&data->lock); > @@ -292,12 +327,12 @@ static int ads1100_read_raw(struct iio_dev *indio_dev, > return IIO_VAL_INT; > case IIO_CHAN_INFO_SCALE: > /* full-scale is the supply voltage in millivolts */ > - *val = ads1100_get_vdd_millivolts(data); > + *val = ads1100_get_vref_milivolts(data); Obviously, the existing code was getting away without checking for error here. Since the ads1100_get_vref_milivolts() function handles the error case now, seems like we should be checking the return value here as well. > *val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config); > return IIO_VAL_FRACTIONAL_LOG2; > case IIO_CHAN_INFO_SAMP_FREQ: > - *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, > - data->config)]; > + data_rate_index = FIELD_GET(ADS1100_DR_MASK, data->config); > + *val = data->ads_config->available_data_rate_hz[data_rate_index]; > return IIO_VAL_INT; > default: > return -EINVAL; ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver 2026-07-11 20:01 ` David Lechner @ 2026-07-12 10:16 ` Jakub Szczudło 2026-07-12 16:32 ` David Lechner 0 siblings, 1 reply; 10+ messages in thread From: Jakub Szczudło @ 2026-07-12 10:16 UTC (permalink / raw) To: David Lechner Cc: linux-iio, andy, antoniu.miclaus, conor+dt, devicetree, duje, Jonathan Cameron, jishnu.prakash, jorge.marques, joshua.crofts1, krzk+dt, linusw, marcelo.schmitt, Matti Vaittinen, mike.looijmans, nuno.sa, robh, sakari.ailus, wens sob., 11 lip 2026, 22:01 użytkownik David Lechner <dlechner@baylibre.com> napisał: > > On 7/11/26 1:44 PM, Jakub Szczudlo wrote: > > Add ADS1110 support that have faster datarate than ADS1100, it also uses > > internal voltage reference of 2.048V for measurement. > > > > ... > > > +static int ads1100_get_vref_milivolts(struct ads1100_data *data) > > +{ > > + int voltage_uV; > > + > > + if (data->ads_config->has_internal_vref_only) > > + return ADS1110_INTERNAL_REF_mV; > > + > > + voltage_uV = regulator_get_voltage(data->reg_vdd); > > + if (voltage_uV < 0) > > + return voltage_uV; > > + > > + return voltage_uV / (MICRO / MILLI); > > +} > > + > > ... > > T; > > @@ -276,6 +310,7 @@ static int ads1100_read_raw(struct iio_dev *indio_dev, > > int *val2, long mask) > > { > > int ret; > > + int data_rate_index; > > struct ads1100_data *data = iio_priv(indio_dev); > > > > guard(mutex)(&data->lock); > > @@ -292,12 +327,12 @@ static int ads1100_read_raw(struct iio_dev *indio_dev, > > return IIO_VAL_INT; > > case IIO_CHAN_INFO_SCALE: > > /* full-scale is the supply voltage in millivolts */ > > - *val = ads1100_get_vdd_millivolts(data); > > + *val = ads1100_get_vref_milivolts(data); > > Obviously, the existing code was getting away without checking for > error here. Since the ads1100_get_vref_milivolts() function handles > the error case now, seems like we should be checking the return value > here as well. > > > *val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config); > > return IIO_VAL_FRACTIONAL_LOG2; > > case IIO_CHAN_INFO_SAMP_FREQ: > > - *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, > > - data->config)]; > > + data_rate_index = FIELD_GET(ADS1100_DR_MASK, data->config); > > + *val = data->ads_config->available_data_rate_hz[data_rate_index]; > > return IIO_VAL_INT; > > default: > > return -EINVAL; I'm thinking about next patchset where I will address voltage regulator stuff, adding it to struct and taking it voltage just once in probe. Can we leave it as it is for now? Best regards, Jakub Szczudlo ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver 2026-07-12 10:16 ` Jakub Szczudło @ 2026-07-12 16:32 ` David Lechner 0 siblings, 0 replies; 10+ messages in thread From: David Lechner @ 2026-07-12 16:32 UTC (permalink / raw) To: Jakub Szczudło Cc: linux-iio, andy, antoniu.miclaus, conor+dt, devicetree, duje, Jonathan Cameron, jishnu.prakash, jorge.marques, joshua.crofts1, krzk+dt, linusw, marcelo.schmitt, Matti Vaittinen, mike.looijmans, nuno.sa, robh, sakari.ailus, wens On 7/12/26 5:16 AM, Jakub Szczudło wrote: > sob., 11 lip 2026, 22:01 użytkownik David Lechner > <dlechner@baylibre.com> napisał: >> >> On 7/11/26 1:44 PM, Jakub Szczudlo wrote: >>> Add ADS1110 support that have faster datarate than ADS1100, it also uses >>> internal voltage reference of 2.048V for measurement. >>> >> >> ... >> >>> +static int ads1100_get_vref_milivolts(struct ads1100_data *data) >>> +{ >>> + int voltage_uV; >>> + >>> + if (data->ads_config->has_internal_vref_only) >>> + return ADS1110_INTERNAL_REF_mV; >>> + >>> + voltage_uV = regulator_get_voltage(data->reg_vdd); >>> + if (voltage_uV < 0) >>> + return voltage_uV; >>> + >>> + return voltage_uV / (MICRO / MILLI); >>> +} >>> + >> >> ... >> >> T; >>> @@ -276,6 +310,7 @@ static int ads1100_read_raw(struct iio_dev *indio_dev, >>> int *val2, long mask) >>> { >>> int ret; >>> + int data_rate_index; >>> struct ads1100_data *data = iio_priv(indio_dev); >>> >>> guard(mutex)(&data->lock); >>> @@ -292,12 +327,12 @@ static int ads1100_read_raw(struct iio_dev *indio_dev, >>> return IIO_VAL_INT; >>> case IIO_CHAN_INFO_SCALE: >>> /* full-scale is the supply voltage in millivolts */ >>> - *val = ads1100_get_vdd_millivolts(data); >>> + *val = ads1100_get_vref_milivolts(data); >> >> Obviously, the existing code was getting away without checking for >> error here. Since the ads1100_get_vref_milivolts() function handles >> the error case now, seems like we should be checking the return value >> here as well. >> >>> *val2 = 15 + FIELD_GET(ADS1100_PGA_MASK, data->config); >>> return IIO_VAL_FRACTIONAL_LOG2; >>> case IIO_CHAN_INFO_SAMP_FREQ: >>> - *val = ads1100_data_rate[FIELD_GET(ADS1100_DR_MASK, >>> - data->config)]; >>> + data_rate_index = FIELD_GET(ADS1100_DR_MASK, data->config); >>> + *val = data->ads_config->available_data_rate_hz[data_rate_index]; >>> return IIO_VAL_INT; >>> default: >>> return -EINVAL; > > > I'm thinking about next patchset where I will address voltage > regulator stuff, adding it to struct and taking it voltage just once > in probe. Can we leave it as it is for now? Sure. Just mention that again in the cover letter if you do a v7 to remind us. > > Best regards, > Jakub Szczudlo ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-07-12 16:32 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-11 18:44 [PATCH v6 0/3 ] iio: adc: Add support for TI ADS1110 to ti-ads1100 driver Jakub Szczudlo 2026-07-11 18:44 ` [PATCH v6 1/3] iio: adc: Fix incorrect reading when datarate changed in single mode Jakub Szczudlo 2026-07-11 18:54 ` sashiko-bot 2026-07-11 19:51 ` David Lechner 2026-07-11 18:44 ` [PATCH v6 2/3] dt-bindings: iio: adc: ti,ads1100: add support for ADS1110 Jakub Szczudlo 2026-07-11 18:44 ` [PATCH v6 3/3] iio: adc: Add ti-ads1110 support to ti-ads1100 driver Jakub Szczudlo 2026-07-11 18:57 ` sashiko-bot 2026-07-11 20:01 ` David Lechner 2026-07-12 10:16 ` Jakub Szczudło 2026-07-12 16:32 ` David Lechner
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox