Commit a29c3283 authored by Liam Beguin's avatar Liam Beguin Committed by Jonathan Cameron
Browse files

iio: afe: rescale: add offset support



This is a preparatory change required for the addition of temperature
sensing front ends.

Signed-off-by: default avatarLiam Beguin <liambeguin@gmail.com>
Reviewed-by: default avatarPeter Rosin <peda@axentia.se>
Reviewed-by: default avatarAndy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20220213025739.2561834-4-liambeguin@gmail.com


Signed-off-by: default avatarJonathan Cameron <Jonathan.Cameron@huawei.com>
parent 701ee14d
Loading
Loading
Loading
Loading
+81 −0
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
 * IIO rescale driver
 *
 * Copyright (C) 2018 Axentia Technologies AB
 * Copyright (C) 2022 Liam Beguin <liambeguin@gmail.com>
 *
 * Author: Peter Rosin <peda@axentia.se>
 */
@@ -81,11 +82,46 @@ int rescale_process_scale(struct rescale *rescale, int scale_type,
	}
}

int rescale_process_offset(struct rescale *rescale, int scale_type,
			   int scale, int scale2, int schan_off,
			   int *val, int *val2)
{
	s64 tmp, tmp2;

	switch (scale_type) {
	case IIO_VAL_FRACTIONAL:
		tmp = (s64)rescale->offset * scale2;
		*val = div_s64(tmp, scale) + schan_off;
		return IIO_VAL_INT;
	case IIO_VAL_INT:
		*val = div_s64(rescale->offset, scale) + schan_off;
		return IIO_VAL_INT;
	case IIO_VAL_FRACTIONAL_LOG2:
		tmp = (s64)rescale->offset * (1 << scale2);
		*val = div_s64(tmp, scale) + schan_off;
		return IIO_VAL_INT;
	case IIO_VAL_INT_PLUS_NANO:
		tmp = (s64)rescale->offset * 1000000000LL;
		tmp2 = ((s64)scale * 1000000000LL) + scale2;
		*val = div64_s64(tmp, tmp2) + schan_off;
		return IIO_VAL_INT;
	case IIO_VAL_INT_PLUS_MICRO:
		tmp = (s64)rescale->offset * 1000000LL;
		tmp2 = ((s64)scale * 1000000LL) + scale2;
		*val = div64_s64(tmp, tmp2) + schan_off;
		return IIO_VAL_INT;
	default:
		return -EOPNOTSUPP;
	}
}

static int rescale_read_raw(struct iio_dev *indio_dev,
			    struct iio_chan_spec const *chan,
			    int *val, int *val2, long mask)
{
	struct rescale *rescale = iio_priv(indio_dev);
	int scale, scale2;
	int schan_off = 0;
	int ret;

	switch (mask) {
@@ -112,6 +148,47 @@ static int rescale_read_raw(struct iio_dev *indio_dev,
			ret = iio_read_channel_scale(rescale->source, val, val2);
		}
		return rescale_process_scale(rescale, ret, val, val2);
	case IIO_CHAN_INFO_OFFSET:
		/*
		 * Processed channels are scaled 1-to-1 and source offset is
		 * already taken into account.
		 *
		 * In other cases, real world measurement are expressed as:
		 *
		 *	schan_scale * (raw + schan_offset)
		 *
		 * Given that the rescaler parameters are applied recursively:
		 *
		 *	rescaler_scale * (schan_scale * (raw + schan_offset) +
		 *		rescaler_offset)
		 *
		 * Or,
		 *
		 *	(rescaler_scale * schan_scale) * (raw +
		 *		(schan_offset +	rescaler_offset / schan_scale)
		 *
		 * Thus, reusing the original expression the parameters exposed
		 * to userspace are:
		 *
		 *	scale = schan_scale * rescaler_scale
		 *	offset = schan_offset + rescaler_offset / schan_scale
		 */
		if (rescale->chan_processed) {
			*val = rescale->offset;
			return IIO_VAL_INT;
		}

		if (iio_channel_has_info(rescale->source->channel,
					 IIO_CHAN_INFO_OFFSET)) {
			ret = iio_read_channel_offset(rescale->source,
						      &schan_off, NULL);
			if (ret != IIO_VAL_INT)
				return ret < 0 ? ret : -EOPNOTSUPP;
		}

		ret = iio_read_channel_scale(rescale->source, &scale, &scale2);
		return rescale_process_offset(rescale, ret, scale, scale2,
					      schan_off, val, val2);
	default:
		return -EINVAL;
	}
@@ -188,6 +265,9 @@ static int rescale_configure_channel(struct device *dev,
	chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
		BIT(IIO_CHAN_INFO_SCALE);

	if (rescale->offset)
		chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OFFSET);

	/*
	 * Using .read_avail() is fringe to begin with and makes no sense
	 * whatsoever for processed channels, so we make sure that this cannot
@@ -352,6 +432,7 @@ static int rescale_probe(struct platform_device *pdev)
	rescale->cfg = of_device_get_match_data(dev);
	rescale->numerator = 1;
	rescale->denominator = 1;
	rescale->offset = 0;

	ret = rescale->cfg->props(dev, rescale);
	if (ret)
+4 −0
Original line number Diff line number Diff line
@@ -25,8 +25,12 @@ struct rescale {
	bool chan_processed;
	s32 numerator;
	s32 denominator;
	s32 offset;
};

int rescale_process_scale(struct rescale *rescale, int scale_type,
			  int *val, int *val2);
int rescale_process_offset(struct rescale *rescale, int scale_type,
			   int scale, int scale2, int schan_off,
			   int *val, int *val2);
#endif /* __IIO_RESCALE_H__ */