From: Hans de Goede <hansg@kernel.org>
To: Jonathan Cameron <jic23@kernel.org>,
David Lechner <dlechner@baylibre.com>,
Andy Shevchenko <andy@kernel.org>
Cc: Hans de Goede <hansg@kernel.org>,
Matteo Martelli <matteomartelli3@gmail.com>,
Liam Beguin <liambeguin@gmail.com>,
linux-iio@vger.kernel.org
Subject: [PATCH v5 1/6] iio: consumers: Fix handling of negative channel scale in iio_convert_raw_to_processed()
Date: Sun, 31 Aug 2025 12:48:20 +0200 [thread overview]
Message-ID: <20250831104825.15097-2-hansg@kernel.org> (raw)
In-Reply-To: <20250831104825.15097-1-hansg@kernel.org>
There is an issue with the handling of negative channel scales
in iio_convert_raw_to_processed_unlocked() when the channel-scale
is of the IIO_VAL_INT_PLUS_[MICRO|NANO] type:
Things work for channel-scale values > -1.0 and < 0.0 because of
the use of signed values in:
*processed += div_s64(raw64 * (s64)scale_val2 * scale, 1000000LL);
Things will break however for scale values < -1.0. Lets for example say
that raw = 2, (caller-provided)scale = 10 and (channel)scale_val = -1.5.
The result should then be 2 * 10 * -1.5 = -30.
channel-scale = -1.5 means scale_val = -1 and scale_val2 = 500000,
now lets see what gets stored in processed:
1. *processed = raw64 * scale_val * scale;
2. *processed += raw64 * scale_val2 * scale / 1000000LL;
1. Sets processed to 2 * -1 * 10 = -20
2. Adds 2 * 500000 * 10 / 1000000 = 10 to processed
And the end result is processed = -20 + 10 = -10, which is not correct.
Fix this by always using the abs value of both scale_val and scale_val2
and if either is negative multiply the end-result by -1.
Note there seems to be an unwritten rule about negative
IIO_VAL_INT_PLUS_[MICRO|NANO] values that:
i. values > -1.0 and < 0.0 are written as val=0 val2=-xxx
ii. values <= -1.0 are written as val=-xxx val2=xxx
But iio_format_value() will also correctly display a third option:
iii. values <= -1.0 written as val=-xxx val2=-xxx
Since iio_format_value() uses abs(val) when val2 < 0.
This fix also makes iio_convert_raw_to_processed() properly handle
channel-scales using this third option.
Fixes: 48e44ce0f881 ("iio:inkern: Add function to read the processed value")
Cc: Matteo Martelli <matteomartelli3@gmail.com>
Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Hans de Goede <hansg@kernel.org>
---
Changes in v5:
- Do not put case foo: val = x; break; statements on a single line
Changes in v4:
- New patch in v4 of this patch-set
---
drivers/iio/inkern.c | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index c174ebb7d5e6..d36a80a7b8a9 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -11,6 +11,7 @@
#include <linux/mutex.h>
#include <linux/property.h>
#include <linux/slab.h>
+#include <linux/units.h>
#include <linux/iio/iio.h>
#include <linux/iio/iio-opaque.h>
@@ -604,7 +605,7 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
{
int scale_type, scale_val, scale_val2;
int offset_type, offset_val, offset_val2;
- s64 raw64 = raw;
+ s64 denominator, raw64 = raw;
offset_type = iio_channel_read(chan, &offset_val, &offset_val2,
IIO_CHAN_INFO_OFFSET);
@@ -648,20 +649,19 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
*processed = raw64 * scale_val * scale;
break;
case IIO_VAL_INT_PLUS_MICRO:
- if (scale_val2 < 0)
- *processed = -raw64 * scale_val * scale;
- else
- *processed = raw64 * scale_val * scale;
- *processed += div_s64(raw64 * (s64)scale_val2 * scale,
- 1000000LL);
- break;
case IIO_VAL_INT_PLUS_NANO:
- if (scale_val2 < 0)
- *processed = -raw64 * scale_val * scale;
- else
- *processed = raw64 * scale_val * scale;
- *processed += div_s64(raw64 * (s64)scale_val2 * scale,
- 1000000000LL);
+ switch (scale_type) {
+ case IIO_VAL_INT_PLUS_MICRO:
+ denominator = MICRO;
+ break;
+ case IIO_VAL_INT_PLUS_NANO:
+ denominator = NANO;
+ break;
+ }
+ *processed = raw64 * scale * abs(scale_val);
+ *processed += div_s64(raw64 * scale * abs(scale_val2), denominator);
+ if (scale_val < 0 || scale_val2 < 0)
+ *processed *= -1;
break;
case IIO_VAL_FRACTIONAL:
*processed = div_s64(raw64 * (s64)scale_val * scale,
--
2.51.0
next prev parent reply other threads:[~2025-08-31 10:48 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-31 10:48 [PATCH v5 0/6] iio: processed channel handling fixes + Intel Dollar Cove TI PMIC ADC driver Hans de Goede
2025-08-31 10:48 ` Hans de Goede [this message]
2025-08-31 10:48 ` [PATCH v5 2/6] iio: consumers: Fix offset handling in iio_convert_raw_to_processed() Hans de Goede
2025-08-31 10:48 ` [PATCH v5 3/6] iio: consumers: Add an iio_multiply_value() helper function Hans de Goede
2025-08-31 10:48 ` [PATCH v5 4/6] iio: Improve iio_read_channel_processed_scale() precision Hans de Goede
2025-08-31 10:48 ` [PATCH v5 5/6] iio: test: Add KUnit tests for iio_multiply_value() Hans de Goede
2025-08-31 10:48 ` [PATCH v5 6/6] iio: adc: Add Intel Dollar Cove TI PMIC ADC driver Hans de Goede
2025-09-01 19:50 ` [PATCH v5 0/6] iio: processed channel handling fixes + " Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250831104825.15097-2-hansg@kernel.org \
--to=hansg@kernel.org \
--cc=andy@kernel.org \
--cc=dlechner@baylibre.com \
--cc=jic23@kernel.org \
--cc=liambeguin@gmail.com \
--cc=linux-iio@vger.kernel.org \
--cc=matteomartelli3@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox