Re: [PATCH 2/4] iio: add processed write API

David Lechner
2025-09-16T19:23:07Z

On 9/16/25 5:24 AM, Romain Gantois wrote:
> Add a function to allow IIO consumers to write a processed value to a
> channel.
>
> Signed-off-by: Romain Gantois <romain.gantois@bootlin.com>
> ---
> drivers/iio/inkern.c | 99 ++++++++++++++++++++++++++++++++++++++++++++
> include/linux/iio/consumer.h | 17 ++++++++
> 2 files changed, 116 insertions(+)
>
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index c174ebb7d5e6d183674b7ffb15c4ce0f65fa3aed..6486fdb7c66a4c84312541f0f42cc24469972a9c 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -598,6 +598,85 @@ int iio_read_channel_average_raw(struct iio_channel *chan, int *val)
> }
> EXPORT_SYMBOL_GPL(iio_read_channel_average_raw);
>
> +static int iio_convert_processed_to_raw_unlocked(struct iio_channel *chan,
> + int processed, int *raw,
> + unsigned int scale)
> +{
> + int scale_type, scale_val, scale_val2;
> + int offset_type, offset_val, offset_val2;
> + s64 tmp_num, tmp_den;
> +
> + scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
> + IIO_CHAN_INFO_SCALE);
> + if (scale_type >= 0) {
> + switch (scale_type) {
> + case IIO_VAL_INT:
> + tmp_num = processed;
> + tmp_den = scale_val;
> + break;
> + case IIO_VAL_INT_PLUS_MICRO:
> + tmp_num = (s64)processed * 1000000LL;
> +
> + if (scale_val2 < 0) {
> + tmp_den = (s64)scale_val * 1000000LL - (s64)scale_val2;
> + tmp_den *= -1;
> + } else {
> + tmp_den = (s64)scale_val * 1000000LL + (s64)scale_val2;
> + }
> +
> + break;
> + case IIO_VAL_INT_PLUS_NANO:
> + tmp_num = (s64)processed * 1000000000LL;
> +
> + if (scale_val2 < 0) {
> + tmp_den = (s64)scale_val * 1000000000LL - (s64)scale_val2;
> + tmp_den *= -1;
> + } else {
> + tmp_den = (s64)scale_val * 1000000000LL + (s64)scale_val2;
> + }
> +
> + break;
> + case IIO_VAL_FRACTIONAL:
> + tmp_num = (s64)processed * (s64)scale_val2;
> + tmp_den = scale_val;
> + break;
> + case IIO_VAL_FRACTIONAL_LOG2:
> + tmp_num = (s64)processed << scale_val2;
> + tmp_den = scale_val;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + tmp_den *= scale;
> +
> + *raw = div64_s64(tmp_num, tmp_den);
> + }

It can be quite tricky to get all of these combinations right. I would
prefer if added some unit tests like we did in [1].

[1]: https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio.git/commit/?h=testing&id=c732e60ee10ed0611a59513cbf9c8d35fbe7cf65

> +
> + offset_type = iio_channel_read(chan, &offset_val, &offset_val2,
> + IIO_CHAN_INFO_OFFSET);
> + if (offset_type >= 0) {
> + switch (offset_type) {
> + case IIO_VAL_INT:
> + case IIO_VAL_INT_PLUS_MICRO:
> + case IIO_VAL_INT_PLUS_NANO:
> + break;
> + case IIO_VAL_FRACTIONAL:
> + offset_val /= offset_val2;
> + break;
> + case IIO_VAL_FRACTIONAL_LOG2:
> + offset_val >>= offset_val2;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + *raw -= offset_val;
> + }
> +
> + return 0;
> +}