diff mbox series

[v12,07/16] iio: afe: rescale: add INT_PLUS_{MICRO,NANO} support

Message ID 20220108205319.2046348-8-liambeguin@gmail.com (mailing list archive)
State Changes Requested
Headers show
Series iio: afe: add temperature rescaling support | expand

Commit Message

Liam Beguin Jan. 8, 2022, 8:53 p.m. UTC
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>
---
 drivers/iio/afe/iio-rescale.c | 35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)

Comments

Andy Shevchenko Jan. 9, 2022, 12:48 p.m. UTC | #1
On Sat, Jan 8, 2022 at 10:53 PM Liam Beguin <liambeguin@gmail.com> wrote:
>
> Some ADCs use IIO_VAL_INT_PLUS_{NANO,MICRO} scale types.
> Add support for these to allow using the iio-rescaler with them.

...

> +               mult = scale_type == IIO_VAL_INT_PLUS_NANO ? GIGA : MEGA;
> +
> +               /*
> +                * 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));

Isn't it too many repetitive abs() calls?

What about

// Create a macro and use for u16 (struct rn5t618_channel_ratios), s16
(struct twl4030_prescale_divider_ratios), s32 (can be reused in struct
rescale)
struct u32_fract {
  u32 numerator;
  u32 denominator;
};
// (potential reuse in struct hclge_ptp_cycle) and so on...

  struct u32_fract fract = {
    .numerator = abs(rescale->numerator),
    .denominator = abs(rescale->denominator),
  };

// obviously we can add a macro/inliner to abs() the fract struct and
return original sign

and reuse fract.numerator, fract.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;
> +               }


--
With Best Regards,
Andy Shevchenko
Peter Rosin Jan. 9, 2022, 8:20 p.m. UTC | #2
Hi!

On 2022-01-09 13:48, Andy Shevchenko wrote:
> On Sat, Jan 8, 2022 at 10:53 PM Liam Beguin <liambeguin@gmail.com> wrote:
>>
>> Some ADCs use IIO_VAL_INT_PLUS_{NANO,MICRO} scale types.
>> Add support for these to allow using the iio-rescaler with them.
> 
> ...
> 
>> +               mult = scale_type == IIO_VAL_INT_PLUS_NANO ? GIGA : MEGA;
>> +
>> +               /*
>> +                * 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));
> 
> Isn't it too many repetitive abs() calls?
> 
> What about
> 
> // Create a macro and use for u16 (struct rn5t618_channel_ratios), s16
> (struct twl4030_prescale_divider_ratios), s32 (can be reused in struct
> rescale)
> struct u32_fract {
>   u32 numerator;
>   u32 denominator;
> };
> // (potential reuse in struct hclge_ptp_cycle) and so on...
> 
>   struct u32_fract fract = {
>     .numerator = abs(rescale->numerator),
>     .denominator = abs(rescale->denominator),
>   };
> 
> // obviously we can add a macro/inliner to abs() the fract struct and
> return original sign
> 
> and reuse fract.numerator, fract.denominator?

This feels a bit excessive when the "problem" is two extra abs calls.
I don't think the code will get any easier to read by changing
abs(rescale->denominator) into fract.denominator and with my maintainer
hat on, I vote for just letting the compiler exercise its CSE engine.

Cheers,
Peter
Liam Beguin Jan. 11, 2022, 2:33 p.m. UTC | #3
On Sun, Jan 09, 2022 at 09:20:09PM +0100, Peter Rosin wrote:
> Hi!
> 
> On 2022-01-09 13:48, Andy Shevchenko wrote:
> > On Sat, Jan 8, 2022 at 10:53 PM Liam Beguin <liambeguin@gmail.com> wrote:
> >>
> >> Some ADCs use IIO_VAL_INT_PLUS_{NANO,MICRO} scale types.
> >> Add support for these to allow using the iio-rescaler with them.
> > 
> > ...
> > 
> >> +               mult = scale_type == IIO_VAL_INT_PLUS_NANO ? GIGA : MEGA;
> >> +
> >> +               /*
> >> +                * 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));
> > 
> > Isn't it too many repetitive abs() calls?
> > 
> > What about
> > 
> > // Create a macro and use for u16 (struct rn5t618_channel_ratios), s16
> > (struct twl4030_prescale_divider_ratios), s32 (can be reused in struct
> > rescale)
> > struct u32_fract {
> >   u32 numerator;
> >   u32 denominator;
> > };
> > // (potential reuse in struct hclge_ptp_cycle) and so on...
> > 
> >   struct u32_fract fract = {
> >     .numerator = abs(rescale->numerator),
> >     .denominator = abs(rescale->denominator),
> >   };
> > 
> > // obviously we can add a macro/inliner to abs() the fract struct and
> > return original sign
> > 
> > and reuse fract.numerator, fract.denominator?
> 
> This feels a bit excessive when the "problem" is two extra abs calls.
> I don't think the code will get any easier to read by changing
> abs(rescale->denominator) into fract.denominator and with my maintainer
> hat on, I vote for just letting the compiler exercise its CSE engine.

I agree with Peter here, and would rather keep it as is.

Liam

> Cheers,
> Peter
diff mbox series

Patch

diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
index 65832dd09249..f833eb38f8bb 100644
--- a/drivers/iio/afe/iio-rescale.c
+++ b/drivers/iio/afe/iio-rescale.c
@@ -14,6 +14,7 @@ 
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/property.h>
+#include <linux/units.h>
 
 #include <linux/iio/afe/rescale.h>
 #include <linux/iio/consumer.h>
@@ -23,6 +24,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 +45,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 ? GIGA : MEGA;
+
+		/*
+		 * 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;