2021-07-15 04:26:38

by Liam Beguin

[permalink] [raw]
Subject: [PATCH v5 00/10] iio: afe: add temperature rescaling support

From: Liam Beguin <[email protected]>

Add temperature rescaling support to the IIO Analog Front End driver.

This series includes minor bug fixes and adds support for RTD temperature
sensors as well as temperature transducers.

At first I tried to use iio_convert_raw_to_processed() to get more
precision out of processed values but ran into issues when one of my
ADCs didn't provide a scale. I tried to address this in the first two
patches.

When adding offset support to iio-rescale, I also noticed that
iio_read_channel_processed() assumes that the offset is always an
integer which I tried to address in the third patch without breaking
valid implicit truncations.

As was suggested by Jonathan [1], I started implementing Kunit tests for
some of these cases[2]. It's pretty far from being ready but it still
helped test things faster this time around!

I'll send another series with the tests once I've cleaned it up and
figured out how to avoid copying part of the driver...

[1] https://patchwork.kernel.org/project/linux-iio/patch/[email protected]/#24290449
[2] https://git.sr.ht/~liambeguin/Linux/commit/iio-rescale-test/v1

Changes since v4:
- only use gcd() when necessary in overflow mitigation
- fix INT_PLUS_{MICRO,NANO} support
- apply Reviewed-by
- fix temperature-transducer bindings

Changes since v3:
- drop unnecessary fallthrough statements
- drop redundant local variables in some calculations
- fix s64 divisions on 32bit platforms by using do_div
- add comment describing iio-rescaler offset calculation
- drop unnecessary MAINTAINERS entry

Changes since v2:
- don't break implicit offset truncations
- make a best effort to get a valid value for fractional types
- drop return value change in iio_convert_raw_to_processed_unlocked()
- don't rely on processed value for offset calculation
- add INT_PLUS_{MICRO,NANO} support in iio-rescale
- revert generic implementation in favor of temperature-sense-rtd and
temperature-transducer
- add separate section to MAINTAINERS file

Changes since v1:
- rebase on latest iio `testing` branch
- also apply consumer scale on integer channel scale types
- don't break implicit truncation in processed channel offset
calculation
- drop temperature AFE flavors in favor of a simpler generic
implementation

Thanks for your time

Liam Beguin (10):
iio: inkern: apply consumer scale on IIO_VAL_INT cases
iio: inkern: apply consumer scale when no channel scale is available
iio: inkern: make a best effort on offset calculation
iio: afe: rescale: reduce risk of integer overflow
iio: afe: rescale: add INT_PLUS_{MICRO,NANO} support
iio: afe: rescale: add offset support
iio: afe: rescale: add RTD temperature sensor support
iio: afe: rescale: add temperature transducers
dt-bindings: iio: afe: add bindings for temperature-sense-rtd
dt-bindings: iio: afe: add bindings for temperature transducers

.../iio/afe/temperature-sense-rtd.yaml | 101 ++++++++++
.../iio/afe/temperature-transducer.yaml | 114 +++++++++++
drivers/iio/afe/iio-rescale.c | 183 +++++++++++++++++-
drivers/iio/inkern.c | 40 +++-
4 files changed, 426 insertions(+), 12 deletions(-)
create mode 100644 Documentation/devicetree/bindings/iio/afe/temperature-sense-rtd.yaml
create mode 100644 Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml

Range-diff against v4:
-: ------------ > 1: 42a7a1047edc iio: inkern: apply consumer scale on IIO_VAL_INT cases
-: ------------ > 2: a1cd89fdad11 iio: inkern: apply consumer scale when no channel scale is available
-: ------------ > 3: ed0721fb6bd1 iio: inkern: make a best effort on offset calculation
1: e23e6cb26b92 ! 4: 7b3e374eb7ad iio: afe: rescale: reduce risk of integer overflow
@@ Commit message

Reduce the risk of integer overflow by doing the scale calculation with
64bit integers and looking for a Greatest Common Divider for both parts
- of the fractional value.
+ of the fractional value when required.

Signed-off-by: Liam Beguin <[email protected]>

@@ drivers/iio/afe/iio-rescale.c: static int rescale_read_raw(struct iio_dev *indio
- *val2 *= rescale->denominator;
+ tmp = (s64)*val * rescale->numerator;
+ tmp2 = (s64)*val2 * rescale->denominator;
-+ factor = gcd(tmp, tmp2);
-+ do_div(tmp, factor);
++ if (check_mul_overflow(*val, rescale->numerator, (s32 *)&tmp) ||
++ check_mul_overflow(*val2, rescale->denominator, (s32 *)&tmp2)) {
++ factor = gcd(tmp, tmp2);
++ do_div(tmp, factor);
++ do_div(tmp2, factor);
++ }
+ *val = tmp;
-+ do_div(tmp2, factor);
+ *val2 = tmp2;
return ret;
case IIO_VAL_INT:
2: 28203b672942 ! 5: 1d334090e974 iio: afe: rescale: add INT_PLUS_{MICRO,NANO} support
@@ Metadata
## Commit message ##
iio: afe: rescale: add INT_PLUS_{MICRO,NANO} support

- Add IIO_VAL_INT_PLUS_{NANO,MICRO} scaling support.
- Scale the integer part and the decimal parts individually and keep the
- original scaling type.
+ Some ADCs use IIO_VAL_INT_PLUS_{NANO,MICRO} scale types.
+ Add support for these to allow using the iio-rescaler with them.

Signed-off-by: Liam Beguin <[email protected]>

@@ drivers/iio/afe/iio-rescale.c: static int rescale_read_raw(struct iio_dev *indio
*val = tmp;
return ret;
+ case IIO_VAL_INT_PLUS_NANO:
++ tmp = ((s64)*val * 1000000000LL + *val2) * rescale->numerator;
++ do_div(tmp, rescale->denominator);
++
++ *val = div_s64(tmp, 1000000000LL);
++ *val2 = tmp - *val * 1000000000LL;
++ return ret;
+ case IIO_VAL_INT_PLUS_MICRO:
-+ tmp = (s64)*val * rescale->numerator;
-+ *val = div_s64(tmp, rescale->denominator);
-+ tmp = (s64)*val2 * rescale->numerator;
-+ *val2 = div_s64(tmp, rescale->denominator);
++ tmp = ((s64)*val * 1000000LL + *val2) * rescale->numerator;
++ do_div(tmp, rescale->denominator);
++
++ *val = div_s64(tmp, 1000000LL);
++ *val2 = tmp - *val * 1000000LL;
+ return ret;
default:
+ dev_err(&indio_dev->dev, "unsupported type %d\n", ret);
3: a6c944ae0f99 = 6: 61873203c140 iio: afe: rescale: add offset support
4: cc5eb96512d5 = 7: 4e6117b9c663 iio: afe: rescale: add RTD temperature sensor support
5: d8aa257aad35 = 8: bc647d45e293 iio: afe: rescale: add temperature transducers
6: f038d6a08ea2 ! 9: 570b418eed85 dt-bindings: iio: afe: add bindings for temperature-sense-rtd
@@ Commit message
voltage across an RTD resistor such as a PT1000.

Signed-off-by: Liam Beguin <[email protected]>
+ Reviewed-by: Rob Herring <[email protected]>

## Documentation/devicetree/bindings/iio/afe/temperature-sense-rtd.yaml (new) ##
@@
7: 1db42cb25254 ! 10: 3c44ea89754e dt-bindings: iio: afe: add bindings for temperature transducers
@@ Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml (new)
+
+ sense-offset-millicelsius:
+ description: |
-+ Temperature offset. The default is <0>.
++ Temperature offset.
+ This offset is commonly used to convert from Kelvins to degrees Celsius.
+ In that case, sense-offset-millicelsius would be set to <(-273150)>.
++ default: 0
+
+ sense-resistor-ohms:
+ description: |
-+ The sense resistor. Defaults to <1>.
-+ Set sense-resistor-ohms to <1> when using a temperature to voltage
-+ transducer.
++ The sense resistor.
++ By default sense-resistor-ohms cancels out the resistor making the
++ circuit behave like a temperature transducer.
++ default: 1
+
+ alpha-ppm-per-celsius:
+ description: |
@@ Documentation/devicetree/bindings/iio/afe/temperature-transducer.yaml (new)
+ datasheet.
+
+additionalProperties: false
++
+required:
+ - compatible
+ - io-channels

base-commit: 6cbb3aa0f9d5d23221df787cf36f74d3866fdb78
--
2.30.1.489.g328c10930387


2021-07-15 04:27:05

by Liam Beguin

[permalink] [raw]
Subject: [PATCH v5 02/10] iio: inkern: apply consumer scale when no channel scale is available

From: Liam Beguin <[email protected]>

When a consumer calls iio_read_channel_processed() and no channel scale
is available, it's assumed that the scale is one and the raw value is
returned as expected.

On the other hand, if the consumer calls iio_convert_raw_to_processed()
the scaling factor requested by the consumer is not applied.

This for example causes the consumer to process mV when expecting uV.
Make sure to always apply the scaling factor requested by the consumer.

Fixes: adc8ec5ff183 ("iio: inkern: pass through raw values if no scaling")
Signed-off-by: Liam Beguin <[email protected]>
---
drivers/iio/inkern.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index b752fe5818e7..b69027690ed5 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -590,10 +590,10 @@ static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan,
IIO_CHAN_INFO_SCALE);
if (scale_type < 0) {
/*
- * Just pass raw values as processed if no scaling is
- * available.
+ * If no channel scaling is available apply consumer scale to
+ * raw value and return.
*/
- *processed = raw;
+ *processed = raw * scale;
return 0;
}

--
2.30.1.489.g328c10930387

2021-07-15 04:27:20

by Liam Beguin

[permalink] [raw]
Subject: [PATCH v5 07/10] iio: afe: rescale: add RTD temperature sensor support

From: Liam Beguin <[email protected]>

An RTD (Resistance Temperature Detector) is a kind of temperature
sensor used to get a linear voltage to temperature reading within a
give range (usually 0 to 100 degrees Celsius). Common types of RTDs
include PT100, PT500, and PT1000.

Signed-off-by: Liam Beguin <[email protected]>
---
drivers/iio/afe/iio-rescale.c | 48 +++++++++++++++++++++++++++++++++++
1 file changed, 48 insertions(+)

diff --git a/drivers/iio/afe/iio-rescale.c b/drivers/iio/afe/iio-rescale.c
index 4d3b44884a89..055f6b7c9869 100644
--- a/drivers/iio/afe/iio-rescale.c
+++ b/drivers/iio/afe/iio-rescale.c
@@ -356,10 +356,52 @@ static int rescale_voltage_divider_props(struct device *dev,
return 0;
}

+static int rescale_temp_sense_rtd_props(struct device *dev,
+ struct rescale *rescale)
+{
+ u32 factor;
+ u32 alpha;
+ u32 iexc;
+ u32 tmp;
+ int ret;
+ u32 r0;
+
+ ret = device_property_read_u32(dev, "excitation-current-microamp",
+ &iexc);
+ if (ret) {
+ dev_err(dev, "failed to read excitation-current-microamp: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = device_property_read_u32(dev, "alpha-ppm-per-celsius", &alpha);
+ if (ret) {
+ dev_err(dev, "failed to read alpha-ppm-per-celsius: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = device_property_read_u32(dev, "r-naught-ohms", &r0);
+ if (ret) {
+ dev_err(dev, "failed to read r-naught-ohms: %d\n", ret);
+ return ret;
+ }
+
+ tmp = r0 * iexc * alpha / 1000000;
+ factor = gcd(tmp, 1000000);
+ rescale->numerator = 1000000 / factor;
+ rescale->denominator = tmp / factor;
+
+ rescale->offset = -1 * ((r0 * iexc) / 1000);
+
+ return 0;
+}
+
enum rescale_variant {
CURRENT_SENSE_AMPLIFIER,
CURRENT_SENSE_SHUNT,
VOLTAGE_DIVIDER,
+ TEMP_SENSE_RTD,
};

static const struct rescale_cfg rescale_cfg[] = {
@@ -375,6 +417,10 @@ static const struct rescale_cfg rescale_cfg[] = {
.type = IIO_VOLTAGE,
.props = rescale_voltage_divider_props,
},
+ [TEMP_SENSE_RTD] = {
+ .type = IIO_TEMP,
+ .props = rescale_temp_sense_rtd_props,
+ },
};

static const struct of_device_id rescale_match[] = {
@@ -384,6 +430,8 @@ static const struct of_device_id rescale_match[] = {
.data = &rescale_cfg[CURRENT_SENSE_SHUNT], },
{ .compatible = "voltage-divider",
.data = &rescale_cfg[VOLTAGE_DIVIDER], },
+ { .compatible = "temperature-sense-rtd",
+ .data = &rescale_cfg[TEMP_SENSE_RTD], },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, rescale_match);
--
2.30.1.489.g328c10930387