Commit cec1aec9 authored by Hans de Goede's avatar Hans de Goede Committed by Jonathan Cameron
Browse files

iio: consumers: Add an iio_multiply_value() helper function



The channel-scale handling in iio_convert_raw_to_processed() in essence
does the following:

processed  = raw * caller-provided-scale * channel-scale

Which can also be written as:

multiplier = raw * caller-provided-scale
iio-value  = channel-scale
processed  = multiplier * iio-value

Where iio-value is a set of IIO_VAL_* type + val + val2 integers, being
able to handle multiplication of iio-values like this is something
which is useful to have in general and, as previous bugfixes to
iio_convert_raw_to_processed() have shown, also tricky to implement.

Split the iio-value multiplication code from iio_convert_raw_to_processed()
out into a new iio_multiply_value() helper. This serves multiple purposes:

1. Having this split out allows writing a KUnit test for this.
2. Having this split out allows re-use to get better precision
   when scaling values in iio_read_channel_processed_scale().

Reviewed-by: default avatarAndy Shevchenko <andy@kernel.org>
Signed-off-by: default avatarHans de Goede <hansg@kernel.org>
Link: https://patch.msgid.link/20250831104825.15097-4-hansg@kernel.org


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 33f5c69c
Loading
Loading
Loading
Loading
+42 −30
Original line number Diff line number Diff line
@@ -599,13 +599,50 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
}
EXPORT_SYMBOL_GPL(iio_read_channel_average_raw);

int iio_multiply_value(int *result, s64 multiplier,
		       unsigned int type, int val, int val2)
{
	s64 denominator;

	switch (type) {
	case IIO_VAL_INT:
		*result = multiplier * val;
		return IIO_VAL_INT;
	case IIO_VAL_INT_PLUS_MICRO:
	case IIO_VAL_INT_PLUS_NANO:
		switch (type) {
		case IIO_VAL_INT_PLUS_MICRO:
			denominator = MICRO;
			break;
		case IIO_VAL_INT_PLUS_NANO:
			denominator = NANO;
			break;
		}
		*result = multiplier * abs(val);
		*result += div_s64(multiplier * abs(val2), denominator);
		if (val < 0 || val2 < 0)
			*result *= -1;
		return IIO_VAL_INT;
	case IIO_VAL_FRACTIONAL:
		*result = div_s64(multiplier * val, val2);
		return IIO_VAL_INT;
	case IIO_VAL_FRACTIONAL_LOG2:
		*result = (multiplier * val) >> val2;
		return IIO_VAL_INT;
	default:
		return -EINVAL;
	}
}
EXPORT_SYMBOL_NS_GPL(iio_multiply_value, "IIO_UNIT_TEST");

static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
						 int raw, int *processed,
						 unsigned int scale)
{
	int scale_type, scale_val, scale_val2;
	int offset_type, offset_val, offset_val2;
	s64 denominator, raw64 = raw;
	s64 raw64 = raw;
	int ret;

	offset_type = iio_channel_read(chan, &offset_val, &offset_val2,
				       IIO_CHAN_INFO_OFFSET);
@@ -644,35 +681,10 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
		return 0;
	}

	switch (scale_type) {
	case IIO_VAL_INT:
		*processed = raw64 * scale_val * scale;
		break;
	case IIO_VAL_INT_PLUS_MICRO:
	case IIO_VAL_INT_PLUS_NANO:
		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,
				     scale_val2);
		break;
	case IIO_VAL_FRACTIONAL_LOG2:
		*processed = (raw64 * (s64)scale_val * scale) >> scale_val2;
		break;
	default:
		return -EINVAL;
	}
	ret = iio_multiply_value(processed, raw64 * scale,
				 scale_type, scale_val, scale_val2);
	if (ret < 0)
		return ret;

	return 0;
}
+18 −0
Original line number Diff line number Diff line
@@ -381,6 +381,24 @@ int iio_read_channel_offset(struct iio_channel *chan, int *val,
int iio_read_channel_scale(struct iio_channel *chan, int *val,
			   int *val2);

/**
 * iio_multiply_value() - Multiply an IIO value
 * @result:	Destination pointer for the multiplication result
 * @multiplier:	Multiplier.
 * @type:	One of the IIO_VAL_* constants. This decides how the @val and
 *		@val2 parameters are interpreted.
 * @val:	Value being multiplied.
 * @val2:	Value being multiplied. @val2 use depends on type.
 *
 * Multiply an IIO value with a s64 multiplier storing the result as
 * IIO_VAL_INT. This is typically used for scaling.
 *
 * Returns:
 * IIO_VAL_INT on success or a negative error-number on failure.
 */
int iio_multiply_value(int *result, s64 multiplier,
		       unsigned int type, int val, int val2);

/**
 * iio_convert_raw_to_processed() - Converts a raw value to a processed value
 * @chan:		The channel being queried