lkml.org 
[lkml]   [2022]   [Feb]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v15 03/10] iio: afe: rescale: add offset support
    Date
    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>
    ---
    drivers/iio/afe/iio-rescale.c | 81 +++++++++++++++++++++++++++++++++
    include/linux/iio/afe/rescale.h | 4 ++
    2 files changed, 85 insertions(+)

    diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
    index e67d9a9e6135..8eaf766e28cc 100644
    --- a/drivers/iio/afe/iio-rescale.c
    +++ b/drivers/iio/afe/iio-rescale.c
    @@ -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)
    diff --git a/include/linux/iio/afe/rescale.h b/include/linux/iio/afe/rescale.h
    index 8a2eb34af327..6eecb435488f 100644
    --- a/include/linux/iio/afe/rescale.h
    +++ b/include/linux/iio/afe/rescale.h
    @@ -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__ */
    --
    2.35.1.4.g5d01301f2b86
    \
     
     \ /
      Last update: 2022-02-13 03:58    [W:3.482 / U:0.076 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site