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: afe: rescale: add offset support

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

Signed-off-by: Liam Beguin <liambeguin@gmail.com>
Reviewed-by: Peter Rosin <peda@axentia.se>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Link: https://lore.kernel.org/r/20220213025739.2561834-4-liambeguin@gmail.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Liam Beguin and committed by
Jonathan Cameron
a29c3283 701ee14d

+85
+81
drivers/iio/afe/iio-rescale.c
··· 3 3 * IIO rescale driver 4 4 * 5 5 * Copyright (C) 2018 Axentia Technologies AB 6 + * Copyright (C) 2022 Liam Beguin <liambeguin@gmail.com> 6 7 * 7 8 * Author: Peter Rosin <peda@axentia.se> 8 9 */ ··· 82 81 } 83 82 } 84 83 84 + int rescale_process_offset(struct rescale *rescale, int scale_type, 85 + int scale, int scale2, int schan_off, 86 + int *val, int *val2) 87 + { 88 + s64 tmp, tmp2; 89 + 90 + switch (scale_type) { 91 + case IIO_VAL_FRACTIONAL: 92 + tmp = (s64)rescale->offset * scale2; 93 + *val = div_s64(tmp, scale) + schan_off; 94 + return IIO_VAL_INT; 95 + case IIO_VAL_INT: 96 + *val = div_s64(rescale->offset, scale) + schan_off; 97 + return IIO_VAL_INT; 98 + case IIO_VAL_FRACTIONAL_LOG2: 99 + tmp = (s64)rescale->offset * (1 << scale2); 100 + *val = div_s64(tmp, scale) + schan_off; 101 + return IIO_VAL_INT; 102 + case IIO_VAL_INT_PLUS_NANO: 103 + tmp = (s64)rescale->offset * 1000000000LL; 104 + tmp2 = ((s64)scale * 1000000000LL) + scale2; 105 + *val = div64_s64(tmp, tmp2) + schan_off; 106 + return IIO_VAL_INT; 107 + case IIO_VAL_INT_PLUS_MICRO: 108 + tmp = (s64)rescale->offset * 1000000LL; 109 + tmp2 = ((s64)scale * 1000000LL) + scale2; 110 + *val = div64_s64(tmp, tmp2) + schan_off; 111 + return IIO_VAL_INT; 112 + default: 113 + return -EOPNOTSUPP; 114 + } 115 + } 116 + 85 117 static int rescale_read_raw(struct iio_dev *indio_dev, 86 118 struct iio_chan_spec const *chan, 87 119 int *val, int *val2, long mask) 88 120 { 89 121 struct rescale *rescale = iio_priv(indio_dev); 122 + int scale, scale2; 123 + int schan_off = 0; 90 124 int ret; 91 125 92 126 switch (mask) { ··· 148 112 ret = iio_read_channel_scale(rescale->source, val, val2); 149 113 } 150 114 return rescale_process_scale(rescale, ret, val, val2); 115 + case IIO_CHAN_INFO_OFFSET: 116 + /* 117 + * Processed channels are scaled 1-to-1 and source offset is 118 + * already taken into account. 119 + * 120 + * In other cases, real world measurement are expressed as: 121 + * 122 + * schan_scale * (raw + schan_offset) 123 + * 124 + * Given that the rescaler parameters are applied recursively: 125 + * 126 + * rescaler_scale * (schan_scale * (raw + schan_offset) + 127 + * rescaler_offset) 128 + * 129 + * Or, 130 + * 131 + * (rescaler_scale * schan_scale) * (raw + 132 + * (schan_offset + rescaler_offset / schan_scale) 133 + * 134 + * Thus, reusing the original expression the parameters exposed 135 + * to userspace are: 136 + * 137 + * scale = schan_scale * rescaler_scale 138 + * offset = schan_offset + rescaler_offset / schan_scale 139 + */ 140 + if (rescale->chan_processed) { 141 + *val = rescale->offset; 142 + return IIO_VAL_INT; 143 + } 144 + 145 + if (iio_channel_has_info(rescale->source->channel, 146 + IIO_CHAN_INFO_OFFSET)) { 147 + ret = iio_read_channel_offset(rescale->source, 148 + &schan_off, NULL); 149 + if (ret != IIO_VAL_INT) 150 + return ret < 0 ? ret : -EOPNOTSUPP; 151 + } 152 + 153 + ret = iio_read_channel_scale(rescale->source, &scale, &scale2); 154 + return rescale_process_offset(rescale, ret, scale, scale2, 155 + schan_off, val, val2); 151 156 default: 152 157 return -EINVAL; 153 158 } ··· 264 187 265 188 chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | 266 189 BIT(IIO_CHAN_INFO_SCALE); 190 + 191 + if (rescale->offset) 192 + chan->info_mask_separate |= BIT(IIO_CHAN_INFO_OFFSET); 267 193 268 194 /* 269 195 * Using .read_avail() is fringe to begin with and makes no sense ··· 432 352 rescale->cfg = of_device_get_match_data(dev); 433 353 rescale->numerator = 1; 434 354 rescale->denominator = 1; 355 + rescale->offset = 0; 435 356 436 357 ret = rescale->cfg->props(dev, rescale); 437 358 if (ret)
+4
include/linux/iio/afe/rescale.h
··· 25 25 bool chan_processed; 26 26 s32 numerator; 27 27 s32 denominator; 28 + s32 offset; 28 29 }; 29 30 30 31 int rescale_process_scale(struct rescale *rescale, int scale_type, 31 32 int *val, int *val2); 33 + int rescale_process_offset(struct rescale *rescale, int scale_type, 34 + int scale, int scale2, int schan_off, 35 + int *val, int *val2); 32 36 #endif /* __IIO_RESCALE_H__ */