Message ID | 20210509225907.351562-1-linus.walleij@linaro.org (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [v2] iio: afe: iio-rescale: Support processed channels | expand |
Hi! Thanks for the update! On 2021-05-10 00:59, Linus Walleij wrote: > It happens that an ADC will only provide raw or processed > voltage conversion channels. (adc/ab8500-gpadc.c). > On the Samsung GT-I9070 this is used for a light sensor > and current sense amplifier so we need to think of something. > > The idea is to allow processed channels and scale them > with 1/1 and then the rescaler can modify the result > on top. > > Link: https://lore.kernel.org/linux-iio/20201101232211.1194304-1-linus.walleij@linaro.org/ > Cc: Peter Rosin <peda@axentia.se> > Signed-off-by: Linus Walleij <linus.walleij@linaro.org> > --- > ChangeLog v1->v2: > - Deny calls to .read_avail() for processed channels, and > insert a comment. > - Move an assignment of IIO_VAL_FRACTIONAL down to the end > of the block for better readability. > --- > drivers/iio/afe/iio-rescale.c | 39 +++++++++++++++++++++++++++++++---- > 1 file changed, 35 insertions(+), 4 deletions(-) > > diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c > index e42ea2b1707d..ddbb760ae8df 100644 > --- a/drivers/iio/afe/iio-rescale.c > +++ b/drivers/iio/afe/iio-rescale.c > @@ -29,6 +29,7 @@ struct rescale { > struct iio_channel *source; > struct iio_chan_spec chan; > struct iio_chan_spec_ext_info *ext_info; > + bool chan_processed; > s32 numerator; > s32 denominator; > }; > @@ -43,10 +44,27 @@ static int rescale_read_raw(struct iio_dev *indio_dev, > > switch (mask) { > case IIO_CHAN_INFO_RAW: > - return iio_read_channel_raw(rescale->source, val); > + if (rescale->chan_processed) > + /* > + * When only processed channels are supported, we > + * read the processed data and scale it by 1/1 > + * augmented with whatever the rescaler has calculated. > + */ > + return iio_read_channel_processed(rescale->source, val); > + else > + return iio_read_channel_raw(rescale->source, val); > > case IIO_CHAN_INFO_SCALE: > - ret = iio_read_channel_scale(rescale->source, val, val2); > + if (rescale->chan_processed) { > + /* > + * Processed channels are scaled 1-to-1 > + */ > + *val = 1; > + *val2 = 1; > + ret = IIO_VAL_FRACTIONAL; > + } else { > + ret = iio_read_channel_scale(rescale->source, val, val2); > + } > switch (ret) { > case IIO_VAL_FRACTIONAL: > *val *= rescale->numerator; > @@ -82,6 +100,14 @@ static int rescale_read_avail(struct iio_dev *indio_dev, > > switch (mask) { > case IIO_CHAN_INFO_RAW: > + /* > + * Using .read_avail() is fringe to begin with and makes > + * no sense whatsoever for processed channels, so if called > + * on a processed channel, we just error out here. > + */ > + if (rescale->chan_processed) > + return -EINVAL; > + I believe this is not the correct place to block requests for .read_avail. It's too late; the driver should not first promise that it is possible to call .read_avail just to later return -EINVAL. It's better to just avoid adding the IIO_CHAN_INFO_RAW bit to chan->info_mask_separate_available in the rescale_configure_channel function. See some suggested -++ below at the end... > *type = IIO_VAL_INT; > return iio_read_avail_channel_raw(rescale->source, > vals, length); > @@ -132,8 +158,13 @@ static int rescale_configure_channel(struct device *dev, > > if (!iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) || > !iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) { > - dev_err(dev, "source channel does not support raw/scale\n"); > - return -EINVAL; > + if (iio_channel_has_info(schan, IIO_CHAN_INFO_PROCESSED)) { > + dev_info(dev, "using processed channel\n"); > + rescale->chan_processed = true; > + } else { > + dev_err(dev, "source channel does not support raw+scale or processed data\n"); > + return -EINVAL; > + } > } I'd also rather have this logic reversed/flattened: if (iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) && iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) { dev_info(dev, "using raw+scale source channel\n"); } else if (iio_channel_has_info(schan, IIO_CHAN_INFO_PROCESSED)) { dev_info(dev, "using processed source channel\n"); rescale->chan_processed = true; } else { dev_err(dev, "source channel is not supported\n"); return -EINVAL; } > > chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE); - if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW)) + if (iio_channel_has_available(schan, IIO_CHAN_INFO_RAW) && + !rescale->chan_processed) chan->info_mask_separate_available |= BIT(IIO_CHAN_INFO_RAW); (disclaimer, all new code untested and written directly in the mail client) CHeers, Peter
diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c index e42ea2b1707d..ddbb760ae8df 100644 --- a/drivers/iio/afe/iio-rescale.c +++ b/drivers/iio/afe/iio-rescale.c @@ -29,6 +29,7 @@ struct rescale { struct iio_channel *source; struct iio_chan_spec chan; struct iio_chan_spec_ext_info *ext_info; + bool chan_processed; s32 numerator; s32 denominator; }; @@ -43,10 +44,27 @@ static int rescale_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: - return iio_read_channel_raw(rescale->source, val); + if (rescale->chan_processed) + /* + * When only processed channels are supported, we + * read the processed data and scale it by 1/1 + * augmented with whatever the rescaler has calculated. + */ + return iio_read_channel_processed(rescale->source, val); + else + return iio_read_channel_raw(rescale->source, val); case IIO_CHAN_INFO_SCALE: - ret = iio_read_channel_scale(rescale->source, val, val2); + if (rescale->chan_processed) { + /* + * Processed channels are scaled 1-to-1 + */ + *val = 1; + *val2 = 1; + ret = IIO_VAL_FRACTIONAL; + } else { + ret = iio_read_channel_scale(rescale->source, val, val2); + } switch (ret) { case IIO_VAL_FRACTIONAL: *val *= rescale->numerator; @@ -82,6 +100,14 @@ static int rescale_read_avail(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: + /* + * Using .read_avail() is fringe to begin with and makes + * no sense whatsoever for processed channels, so if called + * on a processed channel, we just error out here. + */ + if (rescale->chan_processed) + return -EINVAL; + *type = IIO_VAL_INT; return iio_read_avail_channel_raw(rescale->source, vals, length); @@ -132,8 +158,13 @@ static int rescale_configure_channel(struct device *dev, if (!iio_channel_has_info(schan, IIO_CHAN_INFO_RAW) || !iio_channel_has_info(schan, IIO_CHAN_INFO_SCALE)) { - dev_err(dev, "source channel does not support raw/scale\n"); - return -EINVAL; + if (iio_channel_has_info(schan, IIO_CHAN_INFO_PROCESSED)) { + dev_info(dev, "using processed channel\n"); + rescale->chan_processed = true; + } else { + dev_err(dev, "source channel does not support raw+scale or processed data\n"); + return -EINVAL; + } } chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
It happens that an ADC will only provide raw or processed voltage conversion channels. (adc/ab8500-gpadc.c). On the Samsung GT-I9070 this is used for a light sensor and current sense amplifier so we need to think of something. The idea is to allow processed channels and scale them with 1/1 and then the rescaler can modify the result on top. Link: https://lore.kernel.org/linux-iio/20201101232211.1194304-1-linus.walleij@linaro.org/ Cc: Peter Rosin <peda@axentia.se> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> --- ChangeLog v1->v2: - Deny calls to .read_avail() for processed channels, and insert a comment. - Move an assignment of IIO_VAL_FRACTIONAL down to the end of the block for better readability. --- drivers/iio/afe/iio-rescale.c | 39 +++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-)