* [PATCH v9 0/7] iio: adc: add ad7606 calibration support
@ 2025-06-06 14:19 Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 1/7] Documentation: ABI: IIO: add new convdelay documentation Angelo Dureghello
` (7 more replies)
0 siblings, 8 replies; 11+ messages in thread
From: Angelo Dureghello @ 2025-06-06 14:19 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, Michael Hennerich, devicetree,
Angelo Dureghello, Conor Dooley
Add gain, offset and phase (as a delay) calibration support, for
ad7606b, ad7606c16 and ad7606c18.
Calibration is available for devices with software mode capability.
Offset and phase calibration is configurable by sysfs attributes, while
gain calibration value in ohms must match the external RFilter value,
when an external RFilter is available, so implemented through a specific
devicetree "adi,rfilter-ohms" property.
This patchset depends on:
https://lore.kernel.org/linux-iio/20250505131544.0a7477a2@jic23-huawei/
Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
Changes in v9:
- add patch 6/7 changing chan_scale to a more generic chan_info,
- parse gain fdt property in existing function, to reduce code.
- Link to v8: https://lore.kernel.org/r/20250603-wip-bl-ad7606-calibration-v8-0-2371e7108f32@baylibre.com
Changes in v8:
- fix bug related to wrong calib gain setup,
- fix return value on wrong "reg" read from fdt on calib setup,
- fix commit messages/titles,
- add new function to write calib gain on ADC registers after reset.
- Link to v7: https://lore.kernel.org/r/20250526-wip-bl-ad7606-calibration-v7-0-b487022ce199@baylibre.com
Changes in v7:
- Fix each wrong commit desc. occurence related to convdelay.
- Fix ABI documentation with better words.
- Fix wrong comments in driver source code.
- Add r_gain default before reading the fdt value.
- Link to v6: https://lore.kernel.org/r/20250522-wip-bl-ad7606-calibration-v6-0-487b90433da0@baylibre.com
Changes in v6:
- exit for error in case of fdt that breaks the dt_schema,
- add (5/6) patch to fix the above on older code too,
- Link to v5: https://lore.kernel.org/r/20250519-wip-bl-ad7606-calibration-v5-0-4054fc7c9f3d@baylibre.com
Changes in v5:
- fix tab/spaces wrong formatting on ABI doc (1/5),
- fix description in ABI doc (1/5),
- fix code multiline alignments (3/5),
- fix calibration offset calculation as oneliner expression (3/5),
- Link to v4: https://lore.kernel.org/r/20250508-wip-bl-ad7606-calibration-v4-0-91a3f2837e6b@baylibre.com
Changes in v4:
- fix ad7606_chan_calib_gain_setup appropriately to be called once.
- Link to v3: https://lore.kernel.org/r/20250506-wip-bl-ad7606-calibration-v3-0-6eb7b6e72307@baylibre.com
Changes in v3:
- fix dt_bindings,
- change sysfs calib_delay to convdelay,
- fix sysfs documentation accordingly,
- used u32 for reg and r_gain,
- used DIV_ROUND_CLOSEST for setting r_gain,
- minor syntax fixes,
- Link to v2: https://lore.kernel.org/r/20250502-wip-bl-ad7606-calibration-v2-0-174bd0af081b@baylibre.com
Changes in v2:
- change phase_delay to calib_delay,
- fix dt_bindings,
- fix gain calibarion fdt parsing,
- fix ad7606c-18 calib offset range,
- fix calib offset calculation,
- fix calib gain range,
- Link to v1: https://lore.kernel.org/r/20250429-wip-bl-ad7606-calibration-v1-0-eb4d4821b172@baylibre.com
---
Angelo Dureghello (7):
Documentation: ABI: IIO: add new convdelay documentation
iio: core: add ADC delay calibration definition
iio: adc: ad7606: add offset and phase calibration support
dt-bindings: iio: adc: adi,ad7606: add gain calibration support
iio: adc: ad7606: exit for invalid fdt dt_schema properties
iio: adc: ad7606: rename chan_scale to a more generic chan_info
iio: adc: ad7606: add gain calibration support
Documentation/ABI/testing/sysfs-bus-iio | 24 ++
.../devicetree/bindings/iio/adc/adi,ad7606.yaml | 29 ++
drivers/iio/adc/ad7606.c | 351 ++++++++++++++++-----
drivers/iio/adc/ad7606.h | 22 +-
drivers/iio/industrialio-core.c | 1 +
include/linux/iio/types.h | 1 +
6 files changed, 347 insertions(+), 81 deletions(-)
---
base-commit: 351e9e8549a49300e674fc562b4b2a7e4bd74a66
change-id: 20250429-wip-bl-ad7606-calibration-20a396a60352
Best regards,
--
Angelo Dureghello <adureghello@baylibre.com>
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v9 1/7] Documentation: ABI: IIO: add new convdelay documentation
2025-06-06 14:19 [PATCH v9 0/7] iio: adc: add ad7606 calibration support Angelo Dureghello
@ 2025-06-06 14:19 ` Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 2/7] iio: core: add ADC delay calibration definition Angelo Dureghello
` (6 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Angelo Dureghello @ 2025-06-06 14:19 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, Michael Hennerich, devicetree,
Angelo Dureghello
From: Angelo Dureghello <adureghello@baylibre.com>
Add new IIO "convdelay" documentation.
The ad7606 implements a phase calibation feature, in nanoseconds.
Being this a time delay, using the convdelay suffix.
Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
Documentation/ABI/testing/sysfs-bus-iio | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/Documentation/ABI/testing/sysfs-bus-iio b/Documentation/ABI/testing/sysfs-bus-iio
index ef52c427a015cf47bb9847782e13afbee01e9f31..3bc386995fb6ddf5fd0718587a84d703cb973d70 100644
--- a/Documentation/ABI/testing/sysfs-bus-iio
+++ b/Documentation/ABI/testing/sysfs-bus-iio
@@ -559,6 +559,30 @@ Description:
- a small discrete set of values like "0 2 4 6 8"
- a range specified as "[min step max]"
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_convdelay
+KernelVersion: 6.17
+Contact: linux-iio@vger.kernel.org
+Description:
+ Delay of start of conversion from common reference point shared
+ by all channels. Can be writable when used to compensate for
+ delay variation introduced by external filters feeding a
+ simultaneous sampling ADC.
+
+ E.g., for the ad7606 ADC series, this value is intended as a
+ configurable time delay in seconds, to correct delay introduced
+ by an optional external filtering circuit.
+
+What: /sys/bus/iio/devices/iio:deviceX/in_voltageY_convdelay_available
+KernelVersion: 6.16
+Contact: linux-iio@vger.kernel.org
+Description:
+ Available values of convdelay. Maybe expressed as:
+
+ - a range specified as "[min step max]"
+
+ If shared across all channels, <type>_convdelay_available
+ is used.
+
What: /sys/bus/iio/devices/iio:deviceX/in_accel_x_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_y_calibscale
What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v9 2/7] iio: core: add ADC delay calibration definition
2025-06-06 14:19 [PATCH v9 0/7] iio: adc: add ad7606 calibration support Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 1/7] Documentation: ABI: IIO: add new convdelay documentation Angelo Dureghello
@ 2025-06-06 14:19 ` Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 3/7] iio: adc: ad7606: add offset and phase calibration support Angelo Dureghello
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Angelo Dureghello @ 2025-06-06 14:19 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, Michael Hennerich, devicetree,
Angelo Dureghello
From: Angelo Dureghello <adureghello@baylibre.com>
ADCs as ad7606 implement a phase calibration as a delay. Add such
definition, needed for ad7606.
Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
drivers/iio/industrialio-core.c | 1 +
include/linux/iio/types.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 178e99b111debc59a247fcc3a6037e429db3bebf..f13c3aa470d774bfe655d6a9fb00c263789db637 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -188,6 +188,7 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_CALIBAMBIENT] = "calibambient",
[IIO_CHAN_INFO_ZEROPOINT] = "zeropoint",
[IIO_CHAN_INFO_TROUGH] = "trough_raw",
+ [IIO_CHAN_INFO_CONVDELAY] = "convdelay",
};
/**
* iio_device_id() - query the unique ID for the device
diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
index d89982c98368cf72c0fc30fa66ab001e48af4e8b..ad2761efcc8315e1f9907d2a7159447fb463333e 100644
--- a/include/linux/iio/types.h
+++ b/include/linux/iio/types.h
@@ -69,6 +69,7 @@ enum iio_chan_info_enum {
IIO_CHAN_INFO_CALIBAMBIENT,
IIO_CHAN_INFO_ZEROPOINT,
IIO_CHAN_INFO_TROUGH,
+ IIO_CHAN_INFO_CONVDELAY,
};
#endif /* _IIO_TYPES_H_ */
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v9 3/7] iio: adc: ad7606: add offset and phase calibration support
2025-06-06 14:19 [PATCH v9 0/7] iio: adc: add ad7606 calibration support Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 1/7] Documentation: ABI: IIO: add new convdelay documentation Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 2/7] iio: core: add ADC delay calibration definition Angelo Dureghello
@ 2025-06-06 14:19 ` Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 4/7] dt-bindings: iio: adc: adi,ad7606: add gain " Angelo Dureghello
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Angelo Dureghello @ 2025-06-06 14:19 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, Michael Hennerich, devicetree,
Angelo Dureghello
From: Angelo Dureghello <adureghello@baylibre.com>
Add support for offset and phase calibration, only for
devices that support software mode, that are:
ad7606b
ad7606c-16
ad7606c-18
Tested-by: David Lechner <dlechner@baylibre.com>
Reviewed-by: Nuno Sá <nuno.sa@analog.com>
Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
drivers/iio/adc/ad7606.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++
drivers/iio/adc/ad7606.h | 9 +++
2 files changed, 169 insertions(+)
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index 9e489c05dea6f0a9fd144640fb0e23775eb4f3d8..f0c22365f23fa2bf00edddcdd7d608bd1393bf28 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -95,6 +95,22 @@ static const unsigned int ad7616_oversampling_avail[8] = {
1, 2, 4, 8, 16, 32, 64, 128,
};
+static const int ad7606_calib_offset_avail[3] = {
+ -128, 1, 127,
+};
+
+static const int ad7606c_18bit_calib_offset_avail[3] = {
+ -512, 4, 508,
+};
+
+static const int ad7606b_calib_phase_avail[][2] = {
+ { 0, 0 }, { 0, 1250 }, { 0, 318750 },
+};
+
+static const int ad7606c_calib_phase_avail[][2] = {
+ { 0, 0 }, { 0, 1000 }, { 0, 255000 },
+};
+
static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan);
static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
@@ -164,6 +180,8 @@ const struct ad7606_chip_info ad7606b_info = {
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_offset_avail = ad7606_calib_offset_avail,
+ .calib_phase_avail = ad7606b_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606b_info, "IIO_AD7606");
@@ -177,6 +195,8 @@ const struct ad7606_chip_info ad7606c_16_info = {
.scale_setup_cb = ad7606c_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_offset_avail = ad7606_calib_offset_avail,
+ .calib_phase_avail = ad7606c_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_16_info, "IIO_AD7606");
@@ -226,6 +246,8 @@ const struct ad7606_chip_info ad7606c_18_info = {
.scale_setup_cb = ad7606c_18bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_offset_avail = ad7606c_18bit_calib_offset_avail,
+ .calib_phase_avail = ad7606c_calib_phase_avail,
};
EXPORT_SYMBOL_NS_GPL(ad7606c_18_info, "IIO_AD7606");
@@ -681,6 +703,40 @@ static int ad7606_scan_direct(struct iio_dev *indio_dev, unsigned int ch,
return ret;
}
+static int ad7606_get_calib_offset(struct ad7606_state *st, int ch, int *val)
+{
+ int ret;
+
+ ret = st->bops->reg_read(st, AD7606_CALIB_OFFSET(ch));
+ if (ret < 0)
+ return ret;
+
+ *val = st->chip_info->calib_offset_avail[0] +
+ ret * st->chip_info->calib_offset_avail[1];
+
+ return 0;
+}
+
+static int ad7606_get_calib_phase(struct ad7606_state *st, int ch, int *val,
+ int *val2)
+{
+ int ret;
+
+ ret = st->bops->reg_read(st, AD7606_CALIB_PHASE(ch));
+ if (ret < 0)
+ return ret;
+
+ *val = 0;
+
+ /*
+ * ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs.
+ * ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs.
+ */
+ *val2 = ret * st->chip_info->calib_phase_avail[1][1];
+
+ return 0;
+}
+
static int ad7606_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
@@ -715,6 +771,22 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
pwm_get_state(st->cnvst_pwm, &cnvst_pwm_state);
*val = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, cnvst_pwm_state.period);
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ad7606_get_calib_offset(st, chan->scan_index, val);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CONVDELAY:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ad7606_get_calib_phase(st, chan->scan_index, val, val2);
+ iio_device_release_direct(indio_dev);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT_PLUS_NANO;
}
return -EINVAL;
}
@@ -765,6 +837,64 @@ static int ad7606_write_os_hw(struct iio_dev *indio_dev, int val)
return 0;
}
+static int ad7606_set_calib_offset(struct ad7606_state *st, int ch, int val)
+{
+ int start_val, step_val, stop_val;
+ int offset;
+
+ start_val = st->chip_info->calib_offset_avail[0];
+ step_val = st->chip_info->calib_offset_avail[1];
+ stop_val = st->chip_info->calib_offset_avail[2];
+
+ if (val < start_val || val > stop_val)
+ return -EINVAL;
+
+ offset = (val - start_val) / step_val;
+
+ return st->bops->reg_write(st, AD7606_CALIB_OFFSET(ch), offset);
+}
+
+static int ad7606_set_calib_phase(struct ad7606_state *st, int ch, int val,
+ int val2)
+{
+ int wreg, start_ns, step_ns, stop_ns;
+
+ if (val != 0)
+ return -EINVAL;
+
+ start_ns = st->chip_info->calib_phase_avail[0][1];
+ step_ns = st->chip_info->calib_phase_avail[1][1];
+ stop_ns = st->chip_info->calib_phase_avail[2][1];
+
+ /*
+ * ad7606b: phase delay from 0 to 318.75 μs in steps of 1.25 μs.
+ * ad7606c-16/18: phase delay from 0 µs to 255 µs in steps of 1 µs.
+ */
+ if (val2 < start_ns || val2 > stop_ns)
+ return -EINVAL;
+
+ wreg = val2 / step_ns;
+
+ return st->bops->reg_write(st, AD7606_CALIB_PHASE(ch), wreg);
+}
+
+static int ad7606_write_raw_get_fmt(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, long info)
+{
+ switch (info) {
+ case IIO_CHAN_INFO_SCALE:
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
+ case IIO_CHAN_INFO_CALIBBIAS:
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CONVDELAY:
+ return IIO_VAL_INT_PLUS_NANO;
+ default:
+ return -EINVAL;
+ }
+}
+
static int ad7606_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val,
@@ -818,6 +948,18 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
if (val < 0 && val2 != 0)
return -EINVAL;
return ad7606_set_sampling_freq(st, val);
+ case IIO_CHAN_INFO_CALIBBIAS:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ad7606_set_calib_offset(st, chan->scan_index, val);
+ iio_device_release_direct(indio_dev);
+ return ret;
+ case IIO_CHAN_INFO_CONVDELAY:
+ if (!iio_device_claim_direct(indio_dev))
+ return -EBUSY;
+ ret = ad7606_set_calib_phase(st, chan->scan_index, val, val2);
+ iio_device_release_direct(indio_dev);
+ return ret;
default:
return -EINVAL;
}
@@ -996,6 +1138,14 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
*type = IIO_VAL_INT_PLUS_MICRO;
return IIO_AVAIL_LIST;
+ case IIO_CHAN_INFO_CALIBBIAS:
+ *vals = st->chip_info->calib_offset_avail;
+ *type = IIO_VAL_INT;
+ return IIO_AVAIL_RANGE;
+ case IIO_CHAN_INFO_CONVDELAY:
+ *vals = (const int *)st->chip_info->calib_phase_avail;
+ *type = IIO_VAL_INT_PLUS_NANO;
+ return IIO_AVAIL_RANGE;
}
return -EINVAL;
}
@@ -1058,6 +1208,7 @@ static const struct iio_info ad7606_info_sw_mode = {
.read_raw = &ad7606_read_raw,
.write_raw = &ad7606_write_raw,
.read_avail = &ad7606_read_avail,
+ .write_raw_get_fmt = ad7606_write_raw_get_fmt,
.debugfs_reg_access = &ad7606_reg_access,
.validate_trigger = &ad7606_validate_trigger,
.update_scan_mode = &ad7606_update_scan_mode,
@@ -1250,6 +1401,15 @@ static int ad7606_probe_channels(struct iio_dev *indio_dev)
chan->info_mask_separate_available |=
BIT(IIO_CHAN_INFO_SCALE);
+ if (st->chip_info->calib_offset_avail) {
+ chan->info_mask_separate |=
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_CONVDELAY);
+ chan->info_mask_separate_available |=
+ BIT(IIO_CHAN_INFO_CALIBBIAS) |
+ BIT(IIO_CHAN_INFO_CONVDELAY);
+ }
+
/*
* All chips with software mode support oversampling,
* so we skip the oversampling_available check. And the
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index 441e62c521bcbea69b4f70bb2d55f65334d22276..f613583a7fa4095115b0b28e3f8e51cd32b93524 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -40,6 +40,11 @@
#define AD7606_RANGE_CH_ADDR(ch) (0x03 + ((ch) >> 1))
#define AD7606_OS_MODE 0x08
+#define AD7606_CALIB_GAIN(ch) (0x09 + (ch))
+#define AD7606_CALIB_GAIN_MASK GENMASK(5, 0)
+#define AD7606_CALIB_OFFSET(ch) (0x11 + (ch))
+#define AD7606_CALIB_PHASE(ch) (0x19 + (ch))
+
struct ad7606_state;
typedef int (*ad7606_scale_setup_cb_t)(struct iio_dev *indio_dev,
@@ -61,6 +66,8 @@ typedef int (*ad7606_sw_setup_cb_t)(struct iio_dev *indio_dev);
* @init_delay_ms: required delay in milliseconds for initialization
* after a restart
* @offload_storagebits: storage bits used by the offload hw implementation
+ * @calib_offset_avail: pointer to offset calibration range/limits array
+ * @calib_phase_avail: pointer to phase calibration range/limits array
*/
struct ad7606_chip_info {
unsigned int max_samplerate;
@@ -74,6 +81,8 @@ struct ad7606_chip_info {
bool os_req_reset;
unsigned long init_delay_ms;
u8 offload_storagebits;
+ const int *calib_offset_avail;
+ const int (*calib_phase_avail)[2];
};
/**
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v9 4/7] dt-bindings: iio: adc: adi,ad7606: add gain calibration support
2025-06-06 14:19 [PATCH v9 0/7] iio: adc: add ad7606 calibration support Angelo Dureghello
` (2 preceding siblings ...)
2025-06-06 14:19 ` [PATCH v9 3/7] iio: adc: ad7606: add offset and phase calibration support Angelo Dureghello
@ 2025-06-06 14:19 ` Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 5/7] iio: adc: ad7606: exit for invalid fdt dt_schema properties Angelo Dureghello
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Angelo Dureghello @ 2025-06-06 14:19 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, Michael Hennerich, devicetree,
Angelo Dureghello, Conor Dooley
From: Angelo Dureghello <adureghello@baylibre.com>
Add gain calibration support by a per-channel resistor value.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
.../devicetree/bindings/iio/adc/adi,ad7606.yaml | 29 ++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
index 29f12d650442b8ff2eb455306ce59a0e87867ddd..6926f5f090ad6bbbe7bfd9327dc5ae17dafcd1fd 100644
--- a/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
+++ b/Documentation/devicetree/bindings/iio/adc/adi,ad7606.yaml
@@ -204,6 +204,15 @@ patternProperties:
considered a bipolar differential channel. Otherwise it is bipolar
single-ended.
+ adi,rfilter-ohms:
+ description:
+ For ADCs that supports gain calibration, this property must be set to
+ the value of the external RFilter resistor. Proper gain error
+ correction is applied based on this value.
+ default: 0
+ minimum: 0
+ maximum: 64512
+
required:
- reg
- bipolar
@@ -256,6 +265,25 @@ allOf:
properties:
adi,oversampling-ratio-gpios: false
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - adi,ad7605-4
+ - adi,ad7606-4
+ - adi,ad7606-6
+ - adi,ad7606-8
+ - adi,ad7607
+ - adi,ad7608
+ - adi,ad7609
+ - adi,ad7616
+ then:
+ patternProperties:
+ "^channel@[0-9a-f]+$":
+ properties:
+ adi,rfilter-ohms: false
+
- if:
properties:
compatible:
@@ -398,6 +426,7 @@ examples:
reg = <8>;
diff-channels = <8 8>;
bipolar;
+ adi,rfilter-ohms = <2048>;
};
};
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v9 5/7] iio: adc: ad7606: exit for invalid fdt dt_schema properties
2025-06-06 14:19 [PATCH v9 0/7] iio: adc: add ad7606 calibration support Angelo Dureghello
` (3 preceding siblings ...)
2025-06-06 14:19 ` [PATCH v9 4/7] dt-bindings: iio: adc: adi,ad7606: add gain " Angelo Dureghello
@ 2025-06-06 14:19 ` Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 6/7] iio: adc: ad7606: rename chan_scale to a more generic chan_info Angelo Dureghello
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Angelo Dureghello @ 2025-06-06 14:19 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, Michael Hennerich, devicetree,
Angelo Dureghello
From: Angelo Dureghello <adureghello@baylibre.com>
Fix ad7606_get_chan_config() fdt parsing function to exit for error in
case of invalid dt_schema values.
Idea is to not proceed when there are values that are not allowed under
the dt_schema.
Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
drivers/iio/adc/ad7606.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index f0c22365f23fa2bf00edddcdd7d608bd1393bf28..e5878974a28293664dd8dbded5fffcea6db31ef3 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -319,15 +319,13 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
ret = fwnode_property_read_u32(child, "reg", ®);
if (ret)
- continue;
+ return ret;
/* channel number (here) is from 1 to num_channels */
- if (reg < 1 || reg > num_channels) {
- dev_warn(dev,
- "Invalid channel number (ignoring): %d\n", reg);
- continue;
- }
+ if (reg < 1 || reg > num_channels)
+ return -EINVAL;
+ /* Loop until we are in the right channel. */
if (reg != (ch + 1))
continue;
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v9 6/7] iio: adc: ad7606: rename chan_scale to a more generic chan_info
2025-06-06 14:19 [PATCH v9 0/7] iio: adc: add ad7606 calibration support Angelo Dureghello
` (4 preceding siblings ...)
2025-06-06 14:19 ` [PATCH v9 5/7] iio: adc: ad7606: exit for invalid fdt dt_schema properties Angelo Dureghello
@ 2025-06-06 14:19 ` Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 7/7] iio: adc: ad7606: add gain calibration support Angelo Dureghello
2025-06-06 19:14 ` [PATCH v9 0/7] iio: adc: add ad7606 " Andy Shevchenko
7 siblings, 0 replies; 11+ messages in thread
From: Angelo Dureghello @ 2025-06-06 14:19 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, Michael Hennerich, devicetree,
Angelo Dureghello
From: Angelo Dureghello <adureghello@baylibre.com>
Non functional, renaming chan-related chan_scale structure to a more
generic chan_info, to host other chan specific settings, not just
scale-related.
Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
drivers/iio/adc/ad7606.c | 142 +++++++++++++++++++++++------------------------
drivers/iio/adc/ad7606.h | 8 +--
2 files changed, 75 insertions(+), 75 deletions(-)
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index e5878974a28293664dd8dbded5fffcea6db31ef3..d19682186e7cd73a60541f62adf08d987ba24ec3 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -283,21 +283,21 @@ static int ad7606_16bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
if (!st->sw_mode_en) {
/* tied to logic low, analog input range is +/- 5V */
- cs->range = 0;
- cs->scale_avail = ad7606_16bit_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7606_16bit_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
return 0;
}
/* Scale of 0.076293 is only available in sw mode */
/* After reset, in software mode, ±10 V is set by default */
- cs->range = 2;
- cs->scale_avail = ad7606_16bit_sw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail);
+ ci->range = 2;
+ ci->scale_avail = ad7606_16bit_sw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_16bit_sw_scale_avail);
return 0;
}
@@ -359,14 +359,14 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
bool bipolar, differential;
int ret;
if (!st->sw_mode_en) {
- cs->range = 0;
- cs->scale_avail = ad7606_18bit_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7606_18bit_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
return 0;
}
@@ -376,12 +376,12 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
return ret;
if (differential) {
- cs->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_18bit_differential_bipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_18bit_differential_bipolar_scale_avail);
/* Bipolar differential ranges start at 8 (b1000) */
- cs->reg_offset = 8;
- cs->range = 1;
+ ci->reg_offset = 8;
+ ci->range = 1;
chan->differential = 1;
chan->channel2 = chan->channel;
@@ -391,23 +391,23 @@ static int ad7606c_18bit_chan_scale_setup(struct iio_dev *indio_dev,
chan->differential = 0;
if (bipolar) {
- cs->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_18bit_single_ended_bipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_18bit_single_ended_bipolar_scale_avail);
/* Bipolar single-ended ranges start at 0 (b0000) */
- cs->reg_offset = 0;
- cs->range = 3;
+ ci->reg_offset = 0;
+ ci->range = 3;
chan->scan_type.sign = 's';
return 0;
}
- cs->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_18bit_single_ended_unipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_18bit_single_ended_unipolar_scale_avail);
/* Unipolar single-ended ranges start at 5 (b0101) */
- cs->reg_offset = 5;
- cs->range = 1;
+ ci->reg_offset = 5;
+ ci->range = 1;
chan->scan_type.sign = 'u';
return 0;
@@ -417,14 +417,14 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
bool bipolar, differential;
int ret;
if (!st->sw_mode_en) {
- cs->range = 0;
- cs->scale_avail = ad7606_16bit_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7606_16bit_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_16bit_hw_scale_avail);
return 0;
}
@@ -434,12 +434,12 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
return ret;
if (differential) {
- cs->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_16bit_differential_bipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_16bit_differential_bipolar_scale_avail);
/* Bipolar differential ranges start at 8 (b1000) */
- cs->reg_offset = 8;
- cs->range = 1;
+ ci->reg_offset = 8;
+ ci->range = 1;
chan->differential = 1;
chan->channel2 = chan->channel;
chan->scan_type.sign = 's';
@@ -450,23 +450,23 @@ static int ad7606c_16bit_chan_scale_setup(struct iio_dev *indio_dev,
chan->differential = 0;
if (bipolar) {
- cs->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_16bit_single_ended_bipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_16bit_single_ended_bipolar_scale_avail);
/* Bipolar single-ended ranges start at 0 (b0000) */
- cs->reg_offset = 0;
- cs->range = 3;
+ ci->reg_offset = 0;
+ ci->range = 3;
chan->scan_type.sign = 's';
return 0;
}
- cs->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail;
- cs->num_scales =
+ ci->scale_avail = ad7606c_16bit_single_ended_unipolar_scale_avail;
+ ci->num_scales =
ARRAY_SIZE(ad7606c_16bit_single_ended_unipolar_scale_avail);
/* Unipolar single-ended ranges start at 5 (b0101) */
- cs->reg_offset = 5;
- cs->range = 1;
+ ci->reg_offset = 5;
+ ci->range = 1;
chan->scan_type.sign = 'u';
return 0;
@@ -476,11 +476,11 @@ static int ad7607_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
- cs->range = 0;
- cs->scale_avail = ad7607_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7607_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7607_hw_scale_avail);
return 0;
}
@@ -488,11 +488,11 @@ static int ad7608_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
- cs->range = 0;
- cs->scale_avail = ad7606_18bit_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7606_18bit_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7606_18bit_hw_scale_avail);
return 0;
}
@@ -500,11 +500,11 @@ static int ad7609_chan_scale_setup(struct iio_dev *indio_dev,
struct iio_chan_spec *chan)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[chan->scan_index];
+ struct ad7606_chan_info *ci = &st->chan_info[chan->scan_index];
- cs->range = 0;
- cs->scale_avail = ad7609_hw_scale_avail;
- cs->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail);
+ ci->range = 0;
+ ci->scale_avail = ad7609_hw_scale_avail;
+ ci->num_scales = ARRAY_SIZE(ad7609_hw_scale_avail);
return 0;
}
@@ -743,7 +743,7 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
{
int ret, ch = 0;
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs;
+ struct ad7606_chan_info *ci;
struct pwm_state cnvst_pwm_state;
switch (m) {
@@ -758,9 +758,9 @@ static int ad7606_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
ch = chan->scan_index;
- cs = &st->chan_scales[ch];
- *val = cs->scale_avail[cs->range][0];
- *val2 = cs->scale_avail[cs->range][1];
+ ci = &st->chan_info[ch];
+ *val = ci->scale_avail[ci->range][0];
+ *val2 = ci->scale_avail[ci->range][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
*val = st->oversampling;
@@ -795,12 +795,12 @@ static ssize_t in_voltage_scale_available_show(struct device *dev,
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs = &st->chan_scales[0];
- const unsigned int (*vals)[2] = cs->scale_avail;
+ struct ad7606_chan_info *ci = &st->chan_info[0];
+ const unsigned int (*vals)[2] = ci->scale_avail;
unsigned int i;
size_t len = 0;
- for (i = 0; i < cs->num_scales; i++)
+ for (i = 0; i < ci->num_scales; i++)
len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
vals[i][0], vals[i][1]);
buf[len - 1] = '\n';
@@ -901,7 +901,7 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
{
struct ad7606_state *st = iio_priv(indio_dev);
unsigned int scale_avail_uv[AD760X_MAX_SCALES];
- struct ad7606_chan_scale *cs;
+ struct ad7606_chan_info *ci;
int i, ret, ch = 0;
guard(mutex)(&st->lock);
@@ -910,21 +910,21 @@ static int ad7606_write_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SCALE:
if (st->sw_mode_en)
ch = chan->scan_index;
- cs = &st->chan_scales[ch];
- for (i = 0; i < cs->num_scales; i++) {
- scale_avail_uv[i] = cs->scale_avail[i][0] * MICRO +
- cs->scale_avail[i][1];
+ ci = &st->chan_info[ch];
+ for (i = 0; i < ci->num_scales; i++) {
+ scale_avail_uv[i] = ci->scale_avail[i][0] * MICRO +
+ ci->scale_avail[i][1];
}
val = (val * MICRO) + val2;
- i = find_closest(val, scale_avail_uv, cs->num_scales);
+ i = find_closest(val, scale_avail_uv, ci->num_scales);
if (!iio_device_claim_direct(indio_dev))
return -EBUSY;
- ret = st->write_scale(indio_dev, ch, i + cs->reg_offset);
+ ret = st->write_scale(indio_dev, ch, i + ci->reg_offset);
iio_device_release_direct(indio_dev);
if (ret < 0)
return ret;
- cs->range = i;
+ ci->range = i;
return 0;
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
@@ -1115,7 +1115,7 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
long info)
{
struct ad7606_state *st = iio_priv(indio_dev);
- struct ad7606_chan_scale *cs;
+ struct ad7606_chan_info *ci;
unsigned int ch = 0;
switch (info) {
@@ -1130,9 +1130,9 @@ static int ad7606_read_avail(struct iio_dev *indio_dev,
if (st->sw_mode_en)
ch = chan->scan_index;
- cs = &st->chan_scales[ch];
- *vals = (int *)cs->scale_avail;
- *length = cs->num_scales * 2;
+ ci = &st->chan_info[ch];
+ *vals = (int *)ci->scale_avail;
+ *length = ci->num_scales * 2;
*type = IIO_VAL_INT_PLUS_MICRO;
return IIO_AVAIL_LIST;
@@ -1655,7 +1655,7 @@ static int ad7606_resume(struct device *dev)
struct ad7606_state *st = iio_priv(indio_dev);
if (st->gpio_standby) {
- gpiod_set_value(st->gpio_range, st->chan_scales[0].range);
+ gpiod_set_value(st->gpio_range, st->chan_info[0].range);
gpiod_set_value(st->gpio_standby, 1);
ad7606_reset(st);
}
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index f613583a7fa4095115b0b28e3f8e51cd32b93524..26db8e3c724f47f68b7d5323f5d1db75b3334540 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -86,14 +86,14 @@ struct ad7606_chip_info {
};
/**
- * struct ad7606_chan_scale - channel scale configuration
+ * struct ad7606_chan_info - channel configuration
* @scale_avail: pointer to the array which stores the available scales
* @num_scales: number of elements stored in the scale_avail array
* @range: voltage range selection, selects which scale to apply
* @reg_offset: offset for the register value, to be applied when
* writing the value of 'range' to the register value
*/
-struct ad7606_chan_scale {
+struct ad7606_chan_info {
#define AD760X_MAX_SCALES 16
const unsigned int (*scale_avail)[2];
unsigned int num_scales;
@@ -106,7 +106,7 @@ struct ad7606_chan_scale {
* @dev: pointer to kernel device
* @chip_info: entry in the table of chips that describes this device
* @bops: bus operations (SPI or parallel)
- * @chan_scales: scale configuration for channels
+ * @chan_info: scale configuration for channels
* @oversampling: oversampling selection
* @cnvst_pwm: pointer to the PWM device connected to the cnvst pin
* @base_address: address from where to read data in parallel operation
@@ -137,7 +137,7 @@ struct ad7606_state {
struct device *dev;
const struct ad7606_chip_info *chip_info;
const struct ad7606_bus_ops *bops;
- struct ad7606_chan_scale chan_scales[AD760X_MAX_CHANNELS];
+ struct ad7606_chan_info chan_info[AD760X_MAX_CHANNELS];
unsigned int oversampling;
struct pwm_device *cnvst_pwm;
void __iomem *base_address;
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH v9 7/7] iio: adc: ad7606: add gain calibration support
2025-06-06 14:19 [PATCH v9 0/7] iio: adc: add ad7606 calibration support Angelo Dureghello
` (5 preceding siblings ...)
2025-06-06 14:19 ` [PATCH v9 6/7] iio: adc: ad7606: rename chan_scale to a more generic chan_info Angelo Dureghello
@ 2025-06-06 14:19 ` Angelo Dureghello
2025-06-06 19:14 ` [PATCH v9 0/7] iio: adc: add ad7606 " Andy Shevchenko
7 siblings, 0 replies; 11+ messages in thread
From: Angelo Dureghello @ 2025-06-06 14:19 UTC (permalink / raw)
To: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: linux-iio, linux-kernel, Michael Hennerich, devicetree,
Angelo Dureghello
From: Angelo Dureghello <adureghello@baylibre.com>
Add gain calibration support, using resistor values set on devicetree,
values to be set accordingly with ADC external RFilter, as explained in
the ad7606c-16 datasheet, rev0, page 37.
Usage example in the fdt yaml documentation.
Signed-off-by: Angelo Dureghello <adureghello@baylibre.com>
---
drivers/iio/adc/ad7606.c | 39 +++++++++++++++++++++++++++++++++++++++
drivers/iio/adc/ad7606.h | 5 +++++
2 files changed, 44 insertions(+)
diff --git a/drivers/iio/adc/ad7606.c b/drivers/iio/adc/ad7606.c
index d19682186e7cd73a60541f62adf08d987ba24ec3..d9271894f091a837d29197f7de892c022b7e4152 100644
--- a/drivers/iio/adc/ad7606.c
+++ b/drivers/iio/adc/ad7606.c
@@ -33,6 +33,10 @@
#include "ad7606.h"
+#define AD7606_CALIB_GAIN_MIN 0
+#define AD7606_CALIB_GAIN_STEP 1024
+#define AD7606_CALIB_GAIN_MAX (63 * AD7606_CALIB_GAIN_STEP)
+
/*
* Scales are computed as 5000/32768 and 10000/32768 respectively,
* so that when applied to the raw values they provide mV values.
@@ -180,6 +184,7 @@ const struct ad7606_chip_info ad7606b_info = {
.scale_setup_cb = ad7606_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_gain_avail = true,
.calib_offset_avail = ad7606_calib_offset_avail,
.calib_phase_avail = ad7606b_calib_phase_avail,
};
@@ -195,6 +200,7 @@ const struct ad7606_chip_info ad7606c_16_info = {
.scale_setup_cb = ad7606c_16bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_gain_avail = true,
.calib_offset_avail = ad7606_calib_offset_avail,
.calib_phase_avail = ad7606c_calib_phase_avail,
};
@@ -246,6 +252,7 @@ const struct ad7606_chip_info ad7606c_18_info = {
.scale_setup_cb = ad7606c_18bit_chan_scale_setup,
.sw_setup_cb = ad7606b_sw_mode_setup,
.offload_storagebits = 32,
+ .calib_gain_avail = true,
.calib_offset_avail = ad7606c_18bit_calib_offset_avail,
.calib_phase_avail = ad7606c_calib_phase_avail,
};
@@ -306,6 +313,7 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
bool *bipolar, bool *differential)
{
struct ad7606_state *st = iio_priv(indio_dev);
+ struct ad7606_chan_info *ci;
unsigned int num_channels = st->chip_info->num_adc_channels;
struct device *dev = st->dev;
int ret;
@@ -349,6 +357,14 @@ static int ad7606_get_chan_config(struct iio_dev *indio_dev, int ch,
return -EINVAL;
}
+ ci = &st->chan_info[reg - 1];
+
+ ci->r_gain = 0;
+ ret = fwnode_property_read_u32(child, "adi,rfilter-ohms",
+ &ci->r_gain);
+ if (ret == 0 && ci->r_gain > AD7606_CALIB_GAIN_MAX)
+ return -EINVAL;
+
return 0;
}
@@ -1352,6 +1368,23 @@ static int ad7606b_sw_mode_setup(struct iio_dev *indio_dev)
return st->bops->sw_mode_config(indio_dev);
}
+static int ad7606_set_gain_calib(struct ad7606_state *st)
+{
+ struct ad7606_chan_info *ci;
+ int i, ret;
+
+ for (i = 0; i < st->chip_info->num_adc_channels; i++) {
+ ci = &st->chan_info[i];
+ ret = st->bops->reg_write(st, AD7606_CALIB_GAIN(i),
+ DIV_ROUND_CLOSEST(ci->r_gain,
+ AD7606_CALIB_GAIN_STEP));
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int ad7606_probe_channels(struct iio_dev *indio_dev)
{
struct ad7606_state *st = iio_priv(indio_dev);
@@ -1630,6 +1663,12 @@ int ad7606_probe(struct device *dev, int irq, void __iomem *base_address,
st->chip_info->sw_setup_cb(indio_dev);
}
+ if (st->sw_mode_en && st->chip_info->calib_gain_avail) {
+ ret = ad7606_set_gain_calib(st);
+ if (ret)
+ return ret;
+ }
+
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_NS_GPL(ad7606_probe, "IIO_AD7606");
diff --git a/drivers/iio/adc/ad7606.h b/drivers/iio/adc/ad7606.h
index 26db8e3c724f47f68b7d5323f5d1db75b3334540..2951bb731354d64cbec6e8460b3d841a22bb17ec 100644
--- a/drivers/iio/adc/ad7606.h
+++ b/drivers/iio/adc/ad7606.h
@@ -66,6 +66,7 @@ typedef int (*ad7606_sw_setup_cb_t)(struct iio_dev *indio_dev);
* @init_delay_ms: required delay in milliseconds for initialization
* after a restart
* @offload_storagebits: storage bits used by the offload hw implementation
+ * @calib_gain_avail: chip supports gain calibration
* @calib_offset_avail: pointer to offset calibration range/limits array
* @calib_phase_avail: pointer to phase calibration range/limits array
*/
@@ -81,6 +82,7 @@ struct ad7606_chip_info {
bool os_req_reset;
unsigned long init_delay_ms;
u8 offload_storagebits;
+ bool calib_gain_avail;
const int *calib_offset_avail;
const int (*calib_phase_avail)[2];
};
@@ -92,6 +94,8 @@ struct ad7606_chip_info {
* @range: voltage range selection, selects which scale to apply
* @reg_offset: offset for the register value, to be applied when
* writing the value of 'range' to the register value
+ * @r_gain: gain resistor value in ohms, to be set to match the
+ * external r_filter value
*/
struct ad7606_chan_info {
#define AD760X_MAX_SCALES 16
@@ -99,6 +103,7 @@ struct ad7606_chan_info {
unsigned int num_scales;
unsigned int range;
unsigned int reg_offset;
+ unsigned int r_gain;
};
/**
--
2.49.0
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH v9 0/7] iio: adc: add ad7606 calibration support
2025-06-06 14:19 [PATCH v9 0/7] iio: adc: add ad7606 calibration support Angelo Dureghello
` (6 preceding siblings ...)
2025-06-06 14:19 ` [PATCH v9 7/7] iio: adc: ad7606: add gain calibration support Angelo Dureghello
@ 2025-06-06 19:14 ` Andy Shevchenko
2025-06-07 13:08 ` Jonathan Cameron
7 siblings, 1 reply; 11+ messages in thread
From: Andy Shevchenko @ 2025-06-06 19:14 UTC (permalink / raw)
To: Angelo Dureghello
Cc: Jonathan Cameron, David Lechner, Nuno Sá, Lars-Peter Clausen,
Michael Hennerich, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-iio, linux-kernel, devicetree, Conor Dooley
On Fri, Jun 06, 2025 at 04:19:15PM +0200, Angelo Dureghello wrote:
> Add gain, offset and phase (as a delay) calibration support, for
> ad7606b, ad7606c16 and ad7606c18.
>
> Calibration is available for devices with software mode capability.
>
> Offset and phase calibration is configurable by sysfs attributes, while
> gain calibration value in ohms must match the external RFilter value,
> when an external RFilter is available, so implemented through a specific
> devicetree "adi,rfilter-ohms" property.
FWIW,
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v9 0/7] iio: adc: add ad7606 calibration support
2025-06-06 19:14 ` [PATCH v9 0/7] iio: adc: add ad7606 " Andy Shevchenko
@ 2025-06-07 13:08 ` Jonathan Cameron
2025-06-07 13:11 ` Jonathan Cameron
0 siblings, 1 reply; 11+ messages in thread
From: Jonathan Cameron @ 2025-06-07 13:08 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Angelo Dureghello, David Lechner, Nuno Sá,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-iio, linux-kernel,
devicetree, Conor Dooley
On Fri, 6 Jun 2025 22:14:19 +0300
Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> On Fri, Jun 06, 2025 at 04:19:15PM +0200, Angelo Dureghello wrote:
> > Add gain, offset and phase (as a delay) calibration support, for
> > ad7606b, ad7606c16 and ad7606c18.
> >
> > Calibration is available for devices with software mode capability.
> >
> > Offset and phase calibration is configurable by sysfs attributes, while
> > gain calibration value in ohms must match the external RFilter value,
> > when an external RFilter is available, so implemented through a specific
> > devicetree "adi,rfilter-ohms" property.
>
> FWIW,
> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
>
Applied to the testing branch of iio.git. I'll rebase that on rc1
shortly and push out as togreg.
Thanks,
Jonathan
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v9 0/7] iio: adc: add ad7606 calibration support
2025-06-07 13:08 ` Jonathan Cameron
@ 2025-06-07 13:11 ` Jonathan Cameron
0 siblings, 0 replies; 11+ messages in thread
From: Jonathan Cameron @ 2025-06-07 13:11 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Angelo Dureghello, David Lechner, Nuno Sá,
Lars-Peter Clausen, Michael Hennerich, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, linux-iio, linux-kernel,
devicetree, Conor Dooley
On Sat, 7 Jun 2025 14:08:11 +0100
Jonathan Cameron <jic23@kernel.org> wrote:
> On Fri, 6 Jun 2025 22:14:19 +0300
> Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
>
> > On Fri, Jun 06, 2025 at 04:19:15PM +0200, Angelo Dureghello wrote:
> > > Add gain, offset and phase (as a delay) calibration support, for
> > > ad7606b, ad7606c16 and ad7606c18.
> > >
> > > Calibration is available for devices with software mode capability.
> > >
> > > Offset and phase calibration is configurable by sysfs attributes, while
> > > gain calibration value in ohms must match the external RFilter value,
> > > when an external RFilter is available, so implemented through a specific
> > > devicetree "adi,rfilter-ohms" property.
> >
> > FWIW,
> > Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> >
>
> Applied to the testing branch of iio.git. I'll rebase that on rc1
> shortly and push out as togreg.
>
I just saw that David gave non trivial feedback on v8.
I'll keep this queued up but I'm happy to rebase if we do need to make
any additional tweaks (or to add tags if appropriate!)
Jonathan
> Thanks,
>
> Jonathan
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2025-06-07 13:11 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-06-06 14:19 [PATCH v9 0/7] iio: adc: add ad7606 calibration support Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 1/7] Documentation: ABI: IIO: add new convdelay documentation Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 2/7] iio: core: add ADC delay calibration definition Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 3/7] iio: adc: ad7606: add offset and phase calibration support Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 4/7] dt-bindings: iio: adc: adi,ad7606: add gain " Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 5/7] iio: adc: ad7606: exit for invalid fdt dt_schema properties Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 6/7] iio: adc: ad7606: rename chan_scale to a more generic chan_info Angelo Dureghello
2025-06-06 14:19 ` [PATCH v9 7/7] iio: adc: ad7606: add gain calibration support Angelo Dureghello
2025-06-06 19:14 ` [PATCH v9 0/7] iio: adc: add ad7606 " Andy Shevchenko
2025-06-07 13:08 ` Jonathan Cameron
2025-06-07 13:11 ` Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).