lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251207185216.7498ab0f@jic23-huawei>
Date: Sun, 7 Dec 2025 18:52:16 +0000
From: Jonathan Cameron <jic23@...nel.org>
To: Romain Gantois <romain.gantois@...tlin.com>
Cc: Liam Girdwood <lgirdwood@...il.com>, Mark Brown <broonie@...nel.org>,
 Rob Herring <robh@...nel.org>, Krzysztof Kozlowski <krzk+dt@...nel.org>,
 Conor Dooley <conor+dt@...nel.org>, David Lechner <dlechner@...libre.com>,
 Nuno Sá <nuno.sa@...log.com>, Andy Shevchenko
 <andy@...nel.org>, Thomas Petazzoni <thomas.petazzoni@...tlin.com>,
 linux-kernel@...r.kernel.org, devicetree@...r.kernel.org,
 linux-iio@...r.kernel.org
Subject: Re: [PATCH v4 3/6] iio: add processed write API

On Mon, 24 Nov 2025 15:48:07 +0100
Romain Gantois <romain.gantois@...tlin.com> wrote:

> Add a function to allow IIO consumers to write a processed value to a
> channel.
> 
> Signed-off-by: Romain Gantois <romain.gantois@...tlin.com>
I'm lazy so I'll just ask the question rather than try to find an answer.
Is there any existing consumer of DAC channels that can use this?
It might be easier to land as a refactor than with the new driver and
reduce what is in the more controversial patch for the regulator.

Jonathan

> ---
>  drivers/iio/inkern.c         | 127 +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/iio/consumer.h |  36 ++++++++++++
>  2 files changed, 163 insertions(+)
> 
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index 70b6f589f37a..6667e8e7648b 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -635,6 +635,54 @@ int iio_multiply_value(int *result, s64 multiplier,
>  }
>  EXPORT_SYMBOL_NS_GPL(iio_multiply_value, "IIO_UNIT_TEST");
>  
> +int iio_divide_by_value(int *result, s64 numerator,
> +			unsigned int type, int val, int val2)
> +{
> +	s64 tmp_num, tmp_den;
> +
> +	switch (type) {
> +	case IIO_VAL_INT:
> +		tmp_num = numerator;
> +		tmp_den = val;
> +		break;
> +	case IIO_VAL_INT_PLUS_MICRO:
> +		tmp_num = numerator * MICRO;
> +		/* Cast inside abs() to avoid undefined behavior if val* == -INT_MIN. */
> +		tmp_den = abs((s64)val) * MICRO + abs((s64)val2);
> +
> +		if (val < 0 || val2 < 0)
> +			tmp_num *= -1;
> +
> +		break;
> +	case IIO_VAL_INT_PLUS_NANO:
> +		tmp_num = numerator * NANO;
> +		tmp_den = abs((s64)val) * NANO + abs((s64)val2);
> +
> +		if (val < 0 || val2 < 0)
> +			tmp_num *= -1;
> +
> +		break;
> +	case IIO_VAL_FRACTIONAL:
> +		tmp_num = (s64)numerator * (s64)val2;
> +		tmp_den = val;
> +		break;
> +	case IIO_VAL_FRACTIONAL_LOG2:
> +		tmp_num = (s64)numerator << val2;
> +		tmp_den = val;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (!tmp_den)
> +		return -EDOM;
> +
> +	*result = div64_s64(tmp_num, tmp_den);
> +
> +	return IIO_VAL_INT;
> +}
> +EXPORT_SYMBOL_NS_GPL(iio_divide_by_value, "IIO_UNIT_TEST");
> +
>  static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
>  						 int raw, int *processed,
>  						 unsigned int scale)
> @@ -703,6 +751,66 @@ int iio_convert_raw_to_processed(struct iio_channel *chan, int raw,
>  }
>  EXPORT_SYMBOL_NS_GPL(iio_convert_raw_to_processed, "IIO_CONSUMER");
>  
> +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;
> +	int ret, half_step = 0;
> +
> +	scale_type = iio_channel_read(chan, &scale_val, &scale_val2,
> +				      IIO_CHAN_INFO_SCALE);
> +	if (scale_type >= 0) {
> +		ret = iio_divide_by_value(raw, processed, scale_type, scale_val, scale_val2);
> +		if (ret < 0)
> +			return ret;
> +	} else {
> +		*raw = processed;
> +	}
> +
> +	if (!scale)
> +		return -EDOM;
> +
> +	*raw = div_s64(*raw, scale);
> +
> +	offset_type = iio_channel_read(chan, &offset_val, &offset_val2,
> +				       IIO_CHAN_INFO_OFFSET);
> +
> +	switch (offset_type) {
> +	case IIO_VAL_INT:
> +	case IIO_VAL_INT_PLUS_MICRO:
> +		half_step = MICRO / 2;
> +		break;
> +	case IIO_VAL_INT_PLUS_NANO:
> +		half_step = NANO / 2;
> +		break;
> +	case IIO_VAL_FRACTIONAL:
> +		offset_val = DIV_ROUND_CLOSEST(offset_val, offset_val2);
> +		break;
> +	case IIO_VAL_FRACTIONAL_LOG2:
> +		offset_val >>= offset_val2;
> +		break;
> +	default:
> +		if (offset_type >= 0)
> +			return -EINVAL;
> +
> +		offset_val = 0;
> +	}
> +
> +	/* Round fractional part to closest to reduce rounding bias. */
> +	if (half_step) {
> +		if (offset_val2 >= half_step)
> +			*raw -= 1;
> +		else if (offset_val2 <= -half_step)
> +			*raw += 1;
> +	}
> +
> +	*raw -= offset_val;
> +
> +	return 0;
> +}
> +
>  int iio_read_channel_attribute(struct iio_channel *chan, int *val, int *val2,
>  			       enum iio_chan_info_enum attribute)
>  {
> @@ -1039,3 +1147,22 @@ ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf)
>  	return do_iio_read_channel_label(chan->indio_dev, chan->channel, buf);
>  }
>  EXPORT_SYMBOL_NS_GPL(iio_read_channel_label, "IIO_CONSUMER");
> +
> +int iio_write_channel_processed_scale(struct iio_channel *chan, int val,
> +				      unsigned int scale)
> +{
> +	struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(chan->indio_dev);
> +	int ret, processed;
> +
> +	guard(mutex)(&iio_dev_opaque->info_exist_lock);
> +
> +	if (!chan->indio_dev->info)
> +		return -ENODEV;
> +
> +	ret = iio_convert_processed_to_raw_unlocked(chan, val, &processed, scale);
> +	if (ret)
> +		return ret;
> +
> +	return iio_channel_write(chan, processed, 0, IIO_CHAN_INFO_RAW);
> +}
> +EXPORT_SYMBOL_NS_GPL(iio_write_channel_processed_scale, "IIO_CONSUMER");
> diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
> index a38b277c2c02..f80ab1b80234 100644
> --- a/include/linux/iio/consumer.h
> +++ b/include/linux/iio/consumer.h
> @@ -399,6 +399,24 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val,
>  int iio_multiply_value(int *result, s64 multiplier,
>  		       unsigned int type, int val, int val2);
>  
> +/**
> + * iio_divide_by_value() - Divide by an IIO value
> + * @result:	Destination pointer for the division result
> + * @numerator:	Numerator.
> + * @type:	One of the %IIO_VAL_* constants. This decides how the @val
> + *		and @val2 parameters are interpreted.
> + * @val:	Denominator.
> + * @val2:	Denominator. @val2 use depends on type.
> + *
> + * Divide @numerator by an IIO value, 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_divide_by_value(int *result, s64 numerator,
> +			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
> @@ -469,4 +487,22 @@ ssize_t iio_write_channel_ext_info(struct iio_channel *chan, const char *attr,
>   */
>  ssize_t iio_read_channel_label(struct iio_channel *chan, char *buf);
>  
> +/**
> + * iio_write_channel_processed_scale() - scale and write processed value to a given channel
> + * @chan:		The channel being queried.
> + * @val:		Value to write.
> + * @scale:		Processed value is divided by this scale factor during the conversion.
> + *
> + * This function writes a processed value to a channel. A processed value means
> + * that this value will have the correct unit and not some device internal
> + * representation. If the device does not support writing a processed value, the
> + * function will query the channel's scale and offset and write an appropriately
> + * transformed raw value.
> + *
> + * Returns:
> + * 0 or a negative error-number on failure.
> + */
> +int iio_write_channel_processed_scale(struct iio_channel *chan, int val,
> +				      unsigned int scale);
> +
>  #endif
> 


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ