iio: afe: rescale: add INT_PLUS_{MICRO,NANO} support
authorLiam Beguin <liambeguin@gmail.com>
Sun, 13 Feb 2022 02:57:31 +0000 (21:57 -0500)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Sun, 27 Feb 2022 13:38:05 +0000 (13:38 +0000)
Some ADCs use IIO_VAL_INT_PLUS_{NANO,MICRO} scale types.
Add support for these to allow using the iio-rescaler with them.

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-3-liambeguin@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/afe/iio-rescale.c

index 65832dd09249dbfaf13377255fe23058d29db67b..e67d9a9e6135c0b556bcb51ed5a5cb9bca6948fe 100644 (file)
@@ -23,6 +23,9 @@ int rescale_process_scale(struct rescale *rescale, int scale_type,
                          int *val, int *val2)
 {
        s64 tmp;
+       s32 rem;
+       u32 mult;
+       u32 neg;
 
        switch (scale_type) {
        case IIO_VAL_FRACTIONAL:
@@ -41,6 +44,37 @@ int rescale_process_scale(struct rescale *rescale, int scale_type,
                tmp *= rescale->numerator;
                tmp = div_s64(tmp, 1000000000LL);
                *val = tmp;
+               return scale_type;
+       case IIO_VAL_INT_PLUS_NANO:
+       case IIO_VAL_INT_PLUS_MICRO:
+               mult = scale_type == IIO_VAL_INT_PLUS_NANO ? 1000000000L : 1000000L;
+
+               /*
+                * For IIO_VAL_INT_PLUS_{MICRO,NANO} scale types if either *val
+                * OR *val2 is negative the schan scale is negative, i.e.
+                * *val = 1 and *val2 = -0.5 yields -1.5 not -0.5.
+                */
+               neg = *val < 0 || *val2 < 0;
+
+               tmp = (s64)abs(*val) * abs(rescale->numerator);
+               *val = div_s64_rem(tmp, abs(rescale->denominator), &rem);
+
+               tmp = (s64)rem * mult + (s64)abs(*val2) * abs(rescale->numerator);
+               tmp = div_s64(tmp, abs(rescale->denominator));
+
+               *val += div_s64_rem(tmp, mult, val2);
+
+               /*
+                * If only one of the rescaler elements or the schan scale is
+                * negative, the combined scale is negative.
+                */
+               if (neg ^ ((rescale->numerator < 0) ^ (rescale->denominator < 0))) {
+                       if (*val)
+                               *val = -*val;
+                       else
+                               *val2 = -*val2;
+               }
+
                return scale_type;
        default:
                return -EOPNOTSUPP;