aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiam Beguin <liambeguin@gmail.com>2022-02-12 21:57:33 -0500
committerJonathan Cameron <Jonathan.Cameron@huawei.com>2022-02-27 13:38:16 +0000
commitf5fc003d48033559314f1c9de8198f58f14ed557 (patch)
tree40f62414836f50503b083c7113ebe3777631b47a
parenta29c3283653b80b916c5ca5292c5d36415e38e92 (diff)
downloadiio-f5fc003d48033559314f1c9de8198f58f14ed557.tar.gz
iio: afe: rescale: fix accuracy for small fractional scales
The approximation caused by integer divisions can be costly on smaller scale values since the decimal part is significant compared to the integer part. Switch to an IIO_VAL_INT_PLUS_NANO scale type in such cases to maintain accuracy. Signed-off-by: Liam Beguin <liambeguin@gmail.com> Reviewed-by: Peter Rosin <peda@axentia.se> Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com> Link: https://lore.kernel.org/r/20220213025739.2561834-5-liambeguin@gmail.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
-rw-r--r--drivers/iio/afe/iio-rescale.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
index 8eaf766e28cc12..5d78f0cf47d281 100644
--- a/drivers/iio/afe/iio-rescale.c
+++ b/drivers/iio/afe/iio-rescale.c
@@ -24,7 +24,7 @@ int rescale_process_scale(struct rescale *rescale, int scale_type,
int *val, int *val2)
{
s64 tmp;
- s32 rem;
+ s32 rem, rem2;
u32 mult;
u32 neg;
@@ -43,9 +43,23 @@ int rescale_process_scale(struct rescale *rescale, int scale_type,
tmp = (s64)*val * 1000000000LL;
tmp = div_s64(tmp, rescale->denominator);
tmp *= rescale->numerator;
- tmp = div_s64(tmp, 1000000000LL);
+
+ tmp = div_s64_rem(tmp, 1000000000LL, &rem);
*val = tmp;
- return scale_type;
+
+ if (!rem)
+ return scale_type;
+
+ tmp = 1 << *val2;
+
+ rem2 = *val % (int)tmp;
+ *val = *val / (int)tmp;
+
+ *val2 = rem / (int)tmp;
+ if (rem2)
+ *val2 += div_s64((s64)rem2 * 1000000000LL, tmp);
+
+ return IIO_VAL_INT_PLUS_NANO;
case IIO_VAL_INT_PLUS_NANO:
case IIO_VAL_INT_PLUS_MICRO:
mult = scale_type == IIO_VAL_INT_PLUS_NANO ? 1000000000L : 1000000L;