Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Hans de Goede <hansg@kernel.org>
Link: https://patch.msgid.link/20250831104825.15097-4-hansg@kernel.org
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Hans de Goede and committed by
Jonathan Cameron
cec1aec9 33f5c69c

+60 -30
+42 -30
drivers/iio/inkern.c
··· 599 599 } 600 600 EXPORT_SYMBOL_GPL(iio_read_channel_average_raw); 601 601 602 + int iio_multiply_value(int *result, s64 multiplier, 603 + unsigned int type, int val, int val2) 604 + { 605 + s64 denominator; 606 + 607 + switch (type) { 608 + case IIO_VAL_INT: 609 + *result = multiplier * val; 610 + return IIO_VAL_INT; 611 + case IIO_VAL_INT_PLUS_MICRO: 612 + case IIO_VAL_INT_PLUS_NANO: 613 + switch (type) { 614 + case IIO_VAL_INT_PLUS_MICRO: 615 + denominator = MICRO; 616 + break; 617 + case IIO_VAL_INT_PLUS_NANO: 618 + denominator = NANO; 619 + break; 620 + } 621 + *result = multiplier * abs(val); 622 + *result += div_s64(multiplier * abs(val2), denominator); 623 + if (val < 0 || val2 < 0) 624 + *result *= -1; 625 + return IIO_VAL_INT; 626 + case IIO_VAL_FRACTIONAL: 627 + *result = div_s64(multiplier * val, val2); 628 + return IIO_VAL_INT; 629 + case IIO_VAL_FRACTIONAL_LOG2: 630 + *result = (multiplier * val) >> val2; 631 + return IIO_VAL_INT; 632 + default: 633 + return -EINVAL; 634 + } 635 + } 636 + EXPORT_SYMBOL_NS_GPL(iio_multiply_value, "IIO_UNIT_TEST"); 637 + 602 638 static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, 603 639 int raw, int *processed, 604 640 unsigned int scale) 605 641 { 606 642 int scale_type, scale_val, scale_val2; 607 643 int offset_type, offset_val, offset_val2; 608 - s64 denominator, raw64 = raw; 644 + s64 raw64 = raw; 645 + int ret; 609 646 610 647 offset_type = iio_channel_read(chan, &offset_val, &offset_val2, 611 648 IIO_CHAN_INFO_OFFSET); ··· 681 644 return 0; 682 645 } 683 646 684 - switch (scale_type) { 685 - case IIO_VAL_INT: 686 - *processed = raw64 * scale_val * scale; 687 - break; 688 - case IIO_VAL_INT_PLUS_MICRO: 689 - case IIO_VAL_INT_PLUS_NANO: 690 - switch (scale_type) { 691 - case IIO_VAL_INT_PLUS_MICRO: 692 - denominator = MICRO; 693 - break; 694 - case IIO_VAL_INT_PLUS_NANO: 695 - denominator = NANO; 696 - break; 697 - } 698 - *processed = raw64 * scale * abs(scale_val); 699 - *processed += div_s64(raw64 * scale * abs(scale_val2), denominator); 700 - if (scale_val < 0 || scale_val2 < 0) 701 - *processed *= -1; 702 - break; 703 - case IIO_VAL_FRACTIONAL: 704 - *processed = div_s64(raw64 * (s64)scale_val * scale, 705 - scale_val2); 706 - break; 707 - case IIO_VAL_FRACTIONAL_LOG2: 708 - *processed = (raw64 * (s64)scale_val * scale) >> scale_val2; 709 - break; 710 - default: 711 - return -EINVAL; 712 - } 647 + ret = iio_multiply_value(processed, raw64 * scale, 648 + scale_type, scale_val, scale_val2); 649 + if (ret < 0) 650 + return ret; 713 651 714 652 return 0; 715 653 }
+18
include/linux/iio/consumer.h
··· 382 382 int *val2); 383 383 384 384 /** 385 + * iio_multiply_value() - Multiply an IIO value 386 + * @result: Destination pointer for the multiplication result 387 + * @multiplier: Multiplier. 388 + * @type: One of the IIO_VAL_* constants. This decides how the @val and 389 + * @val2 parameters are interpreted. 390 + * @val: Value being multiplied. 391 + * @val2: Value being multiplied. @val2 use depends on type. 392 + * 393 + * Multiply an IIO value with a s64 multiplier storing the result as 394 + * IIO_VAL_INT. This is typically used for scaling. 395 + * 396 + * Returns: 397 + * IIO_VAL_INT on success or a negative error-number on failure. 398 + */ 399 + int iio_multiply_value(int *result, s64 multiplier, 400 + unsigned int type, int val, int val2); 401 + 402 + /** 385 403 * iio_convert_raw_to_processed() - Converts a raw value to a processed value 386 404 * @chan: The channel being queried 387 405 * @raw: The raw IIO to convert