* [PATCH 0/3] iio: adc: stm32: add smart calibration @ 2022-11-15 10:31 ` Olivier Moysan 0 siblings, 0 replies; 12+ messages in thread From: Olivier Moysan @ 2022-11-15 10:31 UTC (permalink / raw) To: fabrice.gasnier, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: Olivier Moysan, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel Refine offset and linear calibration strategy for STM32MP15 and STM32MP13 SoCs: - offset calibration This calibration depends on factors such as temperature and voltage. As it is not time consuming, it's worth doing it on each ADC start, to get the best accuracy. There is no need to save these data. - linear calibration This calibration is basically SoC dependent, so it can be done only once. When this calibration has been performed at boot stage, the ADC kernel driver can retrieve the calibration data from the ADC registers. Otherwise, the linear calibration is performed once by the ADC driver. The backup of these data, allows to restore them on successive ADC starts. Olivier Moysan (3): iio: adc: stm32-adc: smart calibration support iio: adc: stm32-adc: improve calibration error log iio: adc: stm32-adc: add debugfs to read raw calibration result drivers/iio/adc/stm32-adc-core.h | 1 + drivers/iio/adc/stm32-adc.c | 135 ++++++++++++++++++------------- 2 files changed, 78 insertions(+), 58 deletions(-) -- 2.25.1 ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 0/3] iio: adc: stm32: add smart calibration @ 2022-11-15 10:31 ` Olivier Moysan 0 siblings, 0 replies; 12+ messages in thread From: Olivier Moysan @ 2022-11-15 10:31 UTC (permalink / raw) To: fabrice.gasnier, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: Olivier Moysan, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel Refine offset and linear calibration strategy for STM32MP15 and STM32MP13 SoCs: - offset calibration This calibration depends on factors such as temperature and voltage. As it is not time consuming, it's worth doing it on each ADC start, to get the best accuracy. There is no need to save these data. - linear calibration This calibration is basically SoC dependent, so it can be done only once. When this calibration has been performed at boot stage, the ADC kernel driver can retrieve the calibration data from the ADC registers. Otherwise, the linear calibration is performed once by the ADC driver. The backup of these data, allows to restore them on successive ADC starts. Olivier Moysan (3): iio: adc: stm32-adc: smart calibration support iio: adc: stm32-adc: improve calibration error log iio: adc: stm32-adc: add debugfs to read raw calibration result drivers/iio/adc/stm32-adc-core.h | 1 + drivers/iio/adc/stm32-adc.c | 135 ++++++++++++++++++------------- 2 files changed, 78 insertions(+), 58 deletions(-) -- 2.25.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH 1/3] iio: adc: stm32-adc: smart calibration support 2022-11-15 10:31 ` Olivier Moysan @ 2022-11-15 10:31 ` Olivier Moysan -1 siblings, 0 replies; 12+ messages in thread From: Olivier Moysan @ 2022-11-15 10:31 UTC (permalink / raw) To: fabrice.gasnier, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: Olivier Moysan, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel Add smart calibration support for STM32MP1. - STM32MP15x: both linear & offset calibration are supported - STM32MP13x: Only offset calibration is supported Linear calibration: Linear calibration is SoC dependent and does not change over time so it can be done only once. Linear calibration may have already been done in u-boot. Skip calibration execution if calibration data are already available. Save calibration factors in private data and restore them from private data on next ADC start. Offset calibration: This calibration may vary over time, depending on temperature or voltage. Run offset single-ended and differential calibration on each ADC start, as it is not time consuming. This calibration do not need to be saved. So, remove calfact_s and calfact_d value and bitfields that are no longer used. Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com> --- drivers/iio/adc/stm32-adc-core.h | 1 + drivers/iio/adc/stm32-adc.c | 108 +++++++++++++++---------------- 2 files changed, 53 insertions(+), 56 deletions(-) diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h index 9d6dfa1c03fa..73b2c2e91c08 100644 --- a/drivers/iio/adc/stm32-adc-core.h +++ b/drivers/iio/adc/stm32-adc-core.h @@ -142,6 +142,7 @@ #define STM32H7_LINCALRDYW3 BIT(24) #define STM32H7_LINCALRDYW2 BIT(23) #define STM32H7_LINCALRDYW1 BIT(22) +#define STM32H7_LINCALRDYW_MASK GENMASK(27, 22) #define STM32H7_ADCALLIN BIT(16) #define STM32H7_BOOST BIT(8) #define STM32H7_ADSTP BIT(4) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 8d03d21a33d6..2b2b55eb130e 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -119,16 +119,12 @@ struct stm32_adc_trig_info { /** * struct stm32_adc_calib - optional adc calibration data - * @calfact_s: Calibration offset for single ended channels - * @calfact_d: Calibration offset in differential * @lincalfact: Linearity calibration factor - * @calibrated: Indicates calibration status + * @lincal_saved: Indicates that linear calibration factors are saved */ struct stm32_adc_calib { - u32 calfact_s; - u32 calfact_d; u32 lincalfact[STM32H7_LINCALFACT_NUM]; - bool calibrated; + bool lincal_saved; }; /** @@ -165,8 +161,6 @@ struct stm32_adc_vrefint { * @extsel: trigger selection register & bitfield * @res: resolution selection register & bitfield * @difsel: differential mode selection register & bitfield - * @calfact_s: single-ended calibration factors register & bitfield - * @calfact_d: differential calibration factors register & bitfield * @smpr: smpr1 & smpr2 registers offset array * @smp_bits: smpr1 & smpr2 index and bitfields * @or_vddcore: option register & vddcore bitfield @@ -186,8 +180,6 @@ struct stm32_adc_regspec { const struct stm32_adc_regs extsel; const struct stm32_adc_regs res; const struct stm32_adc_regs difsel; - const struct stm32_adc_regs calfact_s; - const struct stm32_adc_regs calfact_d; const u32 smpr[2]; const struct stm32_adc_regs *smp_bits; const struct stm32_adc_regs or_vddcore; @@ -525,10 +517,6 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = { STM32H7_EXTSEL_SHIFT }, .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT }, .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK}, - .calfact_s = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_S_MASK, - STM32H7_CALFACT_S_SHIFT }, - .calfact_d = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_D_MASK, - STM32H7_CALFACT_D_SHIFT }, .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, .smp_bits = stm32h7_smp_bits, }; @@ -550,10 +538,6 @@ static const struct stm32_adc_regspec stm32mp13_adc_regspec = { STM32H7_EXTSEL_SHIFT }, .res = { STM32H7_ADC_CFGR, STM32MP13_RES_MASK, STM32MP13_RES_SHIFT }, .difsel = { STM32MP13_ADC_DIFSEL, STM32MP13_DIFSEL_MASK}, - .calfact_s = { STM32MP13_ADC_CALFACT, STM32MP13_CALFACT_S_MASK, - STM32MP13_CALFACT_S_SHIFT }, - .calfact_d = { STM32MP13_ADC_CALFACT, STM32MP13_CALFACT_D_MASK, - STM32MP13_CALFACT_D_SHIFT }, .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, .smp_bits = stm32h7_smp_bits, .or_vddcore = { STM32MP13_ADC2_OR, STM32MP13_OP0 }, @@ -575,10 +559,6 @@ static const struct stm32_adc_regspec stm32mp1_adc_regspec = { STM32H7_EXTSEL_SHIFT }, .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT }, .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK}, - .calfact_s = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_S_MASK, - STM32H7_CALFACT_S_SHIFT }, - .calfact_d = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_D_MASK, - STM32H7_CALFACT_D_SHIFT }, .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, .smp_bits = stm32h7_smp_bits, .or_vddcore = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN }, @@ -1000,9 +980,6 @@ static int stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev) int i, ret; u32 lincalrdyw_mask, val; - if (!adc->cfg->has_linearcal) - goto skip_linearcal; - /* Read linearity calibration */ lincalrdyw_mask = STM32H7_LINCALRDYW6; for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { @@ -1024,15 +1001,7 @@ static int stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev) lincalrdyw_mask >>= 1; } - -skip_linearcal: - /* Read offset calibration */ - val = stm32_adc_readl(adc, adc->cfg->regs->calfact_s.reg); - adc->cal.calfact_s = (val & adc->cfg->regs->calfact_s.mask); - adc->cal.calfact_s >>= adc->cfg->regs->calfact_s.shift; - adc->cal.calfact_d = (val & adc->cfg->regs->calfact_d.mask); - adc->cal.calfact_d >>= adc->cfg->regs->calfact_d.shift; - adc->cal.calibrated = true; + adc->cal.lincal_saved = true; return 0; } @@ -1048,13 +1017,6 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev) int i, ret; u32 lincalrdyw_mask, val; - val = (adc->cal.calfact_s << adc->cfg->regs->calfact_s.shift) | - (adc->cal.calfact_d << adc->cfg->regs->calfact_d.shift); - stm32_adc_writel(adc, adc->cfg->regs->calfact_s.reg, val); - - if (!adc->cfg->has_linearcal) - return 0; - lincalrdyw_mask = STM32H7_LINCALRDYW6; for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { /* @@ -1116,19 +1078,20 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev) /** * stm32h7_adc_selfcalib() - Procedure to calibrate ADC * @indio_dev: IIO device instance + * @do_lincal: linear calibration request flag * Note: Must be called once ADC is out of power down. + * + * Run offset calibration unconditionally. + * Run linear calibration if requested & supported. */ -static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev) +static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal) { struct stm32_adc *adc = iio_priv(indio_dev); int ret; u32 msk = STM32H7_ADCALDIF; u32 val; - if (adc->cal.calibrated) - return true; - - if (adc->cfg->has_linearcal) + if (adc->cfg->has_linearcal && do_lincal) msk |= STM32H7_ADCALLIN; /* ADC must be disabled for calibration */ stm32h7_adc_disable(indio_dev); @@ -1172,6 +1135,33 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev) return ret; } +/** + * stm32h7_adc_check_selfcalib() - Check linear calibration status + * @indio_dev: IIO device instance + * + * Used to check if linear calibration has been done. + * Return true if linear calibration factors are already saved in private data + * or if a linear calibration has been done at boot stage. + */ +static int stm32h7_adc_check_selfcalib(struct iio_dev *indio_dev) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + u32 val; + + if (adc->cal.lincal_saved) + return true; + + /* + * Check if linear calibration factors are available in ADC registers, + * by checking that all LINCALRDYWx bits are set. + */ + val = stm32_adc_readl(adc, STM32H7_ADC_CR) & STM32H7_LINCALRDYW_MASK; + if (val == STM32H7_LINCALRDYW_MASK) + return true; + + return false; +} + /** * stm32h7_adc_prepare() - Leave power down mode to enable ADC. * @indio_dev: IIO device instance @@ -1186,16 +1176,20 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev) static int stm32h7_adc_prepare(struct iio_dev *indio_dev) { struct stm32_adc *adc = iio_priv(indio_dev); - int calib, ret; + int lincal_done = false; + int ret; ret = stm32h7_adc_exit_pwr_down(indio_dev); if (ret) return ret; - ret = stm32h7_adc_selfcalib(indio_dev); + if (adc->cfg->has_linearcal) + lincal_done = stm32h7_adc_check_selfcalib(indio_dev); + + /* Always run offset calibration. Run linear calibration only once */ + ret = stm32h7_adc_selfcalib(indio_dev, !lincal_done); if (ret < 0) goto pwr_dwn; - calib = ret; stm32_adc_int_ch_enable(indio_dev); @@ -1205,13 +1199,15 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev) if (ret) goto ch_disable; - /* Either restore or read calibration result for future reference */ - if (calib) - ret = stm32h7_adc_restore_selfcalib(indio_dev); - else - ret = stm32h7_adc_read_selfcalib(indio_dev); - if (ret) - goto disable; + if (adc->cfg->has_linearcal) { + if (!adc->cal.lincal_saved) + ret = stm32h7_adc_read_selfcalib(indio_dev); + else + ret = stm32h7_adc_restore_selfcalib(indio_dev); + + if (ret) + goto disable; + } if (adc->cfg->has_presel) stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel); -- 2.25.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 1/3] iio: adc: stm32-adc: smart calibration support @ 2022-11-15 10:31 ` Olivier Moysan 0 siblings, 0 replies; 12+ messages in thread From: Olivier Moysan @ 2022-11-15 10:31 UTC (permalink / raw) To: fabrice.gasnier, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: Olivier Moysan, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel Add smart calibration support for STM32MP1. - STM32MP15x: both linear & offset calibration are supported - STM32MP13x: Only offset calibration is supported Linear calibration: Linear calibration is SoC dependent and does not change over time so it can be done only once. Linear calibration may have already been done in u-boot. Skip calibration execution if calibration data are already available. Save calibration factors in private data and restore them from private data on next ADC start. Offset calibration: This calibration may vary over time, depending on temperature or voltage. Run offset single-ended and differential calibration on each ADC start, as it is not time consuming. This calibration do not need to be saved. So, remove calfact_s and calfact_d value and bitfields that are no longer used. Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com> --- drivers/iio/adc/stm32-adc-core.h | 1 + drivers/iio/adc/stm32-adc.c | 108 +++++++++++++++---------------- 2 files changed, 53 insertions(+), 56 deletions(-) diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h index 9d6dfa1c03fa..73b2c2e91c08 100644 --- a/drivers/iio/adc/stm32-adc-core.h +++ b/drivers/iio/adc/stm32-adc-core.h @@ -142,6 +142,7 @@ #define STM32H7_LINCALRDYW3 BIT(24) #define STM32H7_LINCALRDYW2 BIT(23) #define STM32H7_LINCALRDYW1 BIT(22) +#define STM32H7_LINCALRDYW_MASK GENMASK(27, 22) #define STM32H7_ADCALLIN BIT(16) #define STM32H7_BOOST BIT(8) #define STM32H7_ADSTP BIT(4) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 8d03d21a33d6..2b2b55eb130e 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -119,16 +119,12 @@ struct stm32_adc_trig_info { /** * struct stm32_adc_calib - optional adc calibration data - * @calfact_s: Calibration offset for single ended channels - * @calfact_d: Calibration offset in differential * @lincalfact: Linearity calibration factor - * @calibrated: Indicates calibration status + * @lincal_saved: Indicates that linear calibration factors are saved */ struct stm32_adc_calib { - u32 calfact_s; - u32 calfact_d; u32 lincalfact[STM32H7_LINCALFACT_NUM]; - bool calibrated; + bool lincal_saved; }; /** @@ -165,8 +161,6 @@ struct stm32_adc_vrefint { * @extsel: trigger selection register & bitfield * @res: resolution selection register & bitfield * @difsel: differential mode selection register & bitfield - * @calfact_s: single-ended calibration factors register & bitfield - * @calfact_d: differential calibration factors register & bitfield * @smpr: smpr1 & smpr2 registers offset array * @smp_bits: smpr1 & smpr2 index and bitfields * @or_vddcore: option register & vddcore bitfield @@ -186,8 +180,6 @@ struct stm32_adc_regspec { const struct stm32_adc_regs extsel; const struct stm32_adc_regs res; const struct stm32_adc_regs difsel; - const struct stm32_adc_regs calfact_s; - const struct stm32_adc_regs calfact_d; const u32 smpr[2]; const struct stm32_adc_regs *smp_bits; const struct stm32_adc_regs or_vddcore; @@ -525,10 +517,6 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = { STM32H7_EXTSEL_SHIFT }, .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT }, .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK}, - .calfact_s = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_S_MASK, - STM32H7_CALFACT_S_SHIFT }, - .calfact_d = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_D_MASK, - STM32H7_CALFACT_D_SHIFT }, .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, .smp_bits = stm32h7_smp_bits, }; @@ -550,10 +538,6 @@ static const struct stm32_adc_regspec stm32mp13_adc_regspec = { STM32H7_EXTSEL_SHIFT }, .res = { STM32H7_ADC_CFGR, STM32MP13_RES_MASK, STM32MP13_RES_SHIFT }, .difsel = { STM32MP13_ADC_DIFSEL, STM32MP13_DIFSEL_MASK}, - .calfact_s = { STM32MP13_ADC_CALFACT, STM32MP13_CALFACT_S_MASK, - STM32MP13_CALFACT_S_SHIFT }, - .calfact_d = { STM32MP13_ADC_CALFACT, STM32MP13_CALFACT_D_MASK, - STM32MP13_CALFACT_D_SHIFT }, .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, .smp_bits = stm32h7_smp_bits, .or_vddcore = { STM32MP13_ADC2_OR, STM32MP13_OP0 }, @@ -575,10 +559,6 @@ static const struct stm32_adc_regspec stm32mp1_adc_regspec = { STM32H7_EXTSEL_SHIFT }, .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT }, .difsel = { STM32H7_ADC_DIFSEL, STM32H7_DIFSEL_MASK}, - .calfact_s = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_S_MASK, - STM32H7_CALFACT_S_SHIFT }, - .calfact_d = { STM32H7_ADC_CALFACT, STM32H7_CALFACT_D_MASK, - STM32H7_CALFACT_D_SHIFT }, .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, .smp_bits = stm32h7_smp_bits, .or_vddcore = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN }, @@ -1000,9 +980,6 @@ static int stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev) int i, ret; u32 lincalrdyw_mask, val; - if (!adc->cfg->has_linearcal) - goto skip_linearcal; - /* Read linearity calibration */ lincalrdyw_mask = STM32H7_LINCALRDYW6; for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { @@ -1024,15 +1001,7 @@ static int stm32h7_adc_read_selfcalib(struct iio_dev *indio_dev) lincalrdyw_mask >>= 1; } - -skip_linearcal: - /* Read offset calibration */ - val = stm32_adc_readl(adc, adc->cfg->regs->calfact_s.reg); - adc->cal.calfact_s = (val & adc->cfg->regs->calfact_s.mask); - adc->cal.calfact_s >>= adc->cfg->regs->calfact_s.shift; - adc->cal.calfact_d = (val & adc->cfg->regs->calfact_d.mask); - adc->cal.calfact_d >>= adc->cfg->regs->calfact_d.shift; - adc->cal.calibrated = true; + adc->cal.lincal_saved = true; return 0; } @@ -1048,13 +1017,6 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev) int i, ret; u32 lincalrdyw_mask, val; - val = (adc->cal.calfact_s << adc->cfg->regs->calfact_s.shift) | - (adc->cal.calfact_d << adc->cfg->regs->calfact_d.shift); - stm32_adc_writel(adc, adc->cfg->regs->calfact_s.reg, val); - - if (!adc->cfg->has_linearcal) - return 0; - lincalrdyw_mask = STM32H7_LINCALRDYW6; for (i = STM32H7_LINCALFACT_NUM - 1; i >= 0; i--) { /* @@ -1116,19 +1078,20 @@ static int stm32h7_adc_restore_selfcalib(struct iio_dev *indio_dev) /** * stm32h7_adc_selfcalib() - Procedure to calibrate ADC * @indio_dev: IIO device instance + * @do_lincal: linear calibration request flag * Note: Must be called once ADC is out of power down. + * + * Run offset calibration unconditionally. + * Run linear calibration if requested & supported. */ -static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev) +static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal) { struct stm32_adc *adc = iio_priv(indio_dev); int ret; u32 msk = STM32H7_ADCALDIF; u32 val; - if (adc->cal.calibrated) - return true; - - if (adc->cfg->has_linearcal) + if (adc->cfg->has_linearcal && do_lincal) msk |= STM32H7_ADCALLIN; /* ADC must be disabled for calibration */ stm32h7_adc_disable(indio_dev); @@ -1172,6 +1135,33 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev) return ret; } +/** + * stm32h7_adc_check_selfcalib() - Check linear calibration status + * @indio_dev: IIO device instance + * + * Used to check if linear calibration has been done. + * Return true if linear calibration factors are already saved in private data + * or if a linear calibration has been done at boot stage. + */ +static int stm32h7_adc_check_selfcalib(struct iio_dev *indio_dev) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + u32 val; + + if (adc->cal.lincal_saved) + return true; + + /* + * Check if linear calibration factors are available in ADC registers, + * by checking that all LINCALRDYWx bits are set. + */ + val = stm32_adc_readl(adc, STM32H7_ADC_CR) & STM32H7_LINCALRDYW_MASK; + if (val == STM32H7_LINCALRDYW_MASK) + return true; + + return false; +} + /** * stm32h7_adc_prepare() - Leave power down mode to enable ADC. * @indio_dev: IIO device instance @@ -1186,16 +1176,20 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev) static int stm32h7_adc_prepare(struct iio_dev *indio_dev) { struct stm32_adc *adc = iio_priv(indio_dev); - int calib, ret; + int lincal_done = false; + int ret; ret = stm32h7_adc_exit_pwr_down(indio_dev); if (ret) return ret; - ret = stm32h7_adc_selfcalib(indio_dev); + if (adc->cfg->has_linearcal) + lincal_done = stm32h7_adc_check_selfcalib(indio_dev); + + /* Always run offset calibration. Run linear calibration only once */ + ret = stm32h7_adc_selfcalib(indio_dev, !lincal_done); if (ret < 0) goto pwr_dwn; - calib = ret; stm32_adc_int_ch_enable(indio_dev); @@ -1205,13 +1199,15 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev) if (ret) goto ch_disable; - /* Either restore or read calibration result for future reference */ - if (calib) - ret = stm32h7_adc_restore_selfcalib(indio_dev); - else - ret = stm32h7_adc_read_selfcalib(indio_dev); - if (ret) - goto disable; + if (adc->cfg->has_linearcal) { + if (!adc->cal.lincal_saved) + ret = stm32h7_adc_read_selfcalib(indio_dev); + else + ret = stm32h7_adc_restore_selfcalib(indio_dev); + + if (ret) + goto disable; + } if (adc->cfg->has_presel) stm32_adc_writel(adc, STM32H7_ADC_PCSEL, adc->pcsel); -- 2.25.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/3] iio: adc: stm32-adc: improve calibration error log 2022-11-15 10:31 ` Olivier Moysan @ 2022-11-15 10:31 ` Olivier Moysan -1 siblings, 0 replies; 12+ messages in thread From: Olivier Moysan @ 2022-11-15 10:31 UTC (permalink / raw) To: fabrice.gasnier, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: Olivier Moysan, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel Add more information in calibration error log to differentiate single-ended and differential calibration. Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com> --- drivers/iio/adc/stm32-adc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 2b2b55eb130e..65dd45537505 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1109,7 +1109,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal) !(val & STM32H7_ADCAL), 100, STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) { - dev_err(&indio_dev->dev, "calibration failed\n"); + dev_err(&indio_dev->dev, "calibration (single-ended) error %d\n", ret); goto out; } @@ -1125,7 +1125,8 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal) !(val & STM32H7_ADCAL), 100, STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) { - dev_err(&indio_dev->dev, "calibration failed\n"); + dev_err(&indio_dev->dev, "calibration (diff%s) error %d\n", + (msk & STM32H7_ADCALLIN) ? "+linear" : "", ret); goto out; } -- 2.25.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 2/3] iio: adc: stm32-adc: improve calibration error log @ 2022-11-15 10:31 ` Olivier Moysan 0 siblings, 0 replies; 12+ messages in thread From: Olivier Moysan @ 2022-11-15 10:31 UTC (permalink / raw) To: fabrice.gasnier, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: Olivier Moysan, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel Add more information in calibration error log to differentiate single-ended and differential calibration. Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com> --- drivers/iio/adc/stm32-adc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 2b2b55eb130e..65dd45537505 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -1109,7 +1109,7 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal) !(val & STM32H7_ADCAL), 100, STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) { - dev_err(&indio_dev->dev, "calibration failed\n"); + dev_err(&indio_dev->dev, "calibration (single-ended) error %d\n", ret); goto out; } @@ -1125,7 +1125,8 @@ static int stm32h7_adc_selfcalib(struct iio_dev *indio_dev, int do_lincal) !(val & STM32H7_ADCAL), 100, STM32H7_ADC_CALIB_TIMEOUT_US); if (ret) { - dev_err(&indio_dev->dev, "calibration failed\n"); + dev_err(&indio_dev->dev, "calibration (diff%s) error %d\n", + (msk & STM32H7_ADCALLIN) ? "+linear" : "", ret); goto out; } -- 2.25.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/3] iio: adc: stm32-adc: add debugfs to read raw calibration result 2022-11-15 10:31 ` Olivier Moysan @ 2022-11-15 10:31 ` Olivier Moysan -1 siblings, 0 replies; 12+ messages in thread From: Olivier Moysan @ 2022-11-15 10:31 UTC (permalink / raw) To: fabrice.gasnier, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: Olivier Moysan, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel Add debugfs to read linear ADC STM32 self calibration results. Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com> Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com> --- drivers/iio/adc/stm32-adc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 65dd45537505..45d4e79f8e55 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -7,6 +7,7 @@ */ #include <linux/clk.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> @@ -1879,6 +1880,23 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = { {}, }; +static void stm32_adc_debugfs_init(struct iio_dev *indio_dev) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + struct dentry *d = iio_get_debugfs_dentry(indio_dev); + struct stm32_adc_calib *cal = &adc->cal; + char buf[16]; + unsigned int i; + + if (!adc->cfg->has_linearcal) + return; + + for (i = 0; i < STM32H7_LINCALFACT_NUM; i++) { + snprintf(buf, sizeof(buf), "lincalfact%d", i + 1); + debugfs_create_u32(buf, 0444, d, &cal->lincalfact[i]); + } +} + static int stm32_adc_fw_get_resolution(struct iio_dev *indio_dev) { struct device *dev = &indio_dev->dev; @@ -2465,6 +2483,9 @@ static int stm32_adc_probe(struct platform_device *pdev) pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); + if (IS_ENABLED(CONFIG_DEBUG_FS)) + stm32_adc_debugfs_init(indio_dev); + return 0; err_hw_stop: @@ -2493,6 +2514,7 @@ static int stm32_adc_remove(struct platform_device *pdev) struct stm32_adc *adc = iio_priv(indio_dev); pm_runtime_get_sync(&pdev->dev); + /* iio_device_unregister() also removes debugfs entries */ iio_device_unregister(indio_dev); stm32_adc_hw_stop(&pdev->dev); pm_runtime_disable(&pdev->dev); -- 2.25.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH 3/3] iio: adc: stm32-adc: add debugfs to read raw calibration result @ 2022-11-15 10:31 ` Olivier Moysan 0 siblings, 0 replies; 12+ messages in thread From: Olivier Moysan @ 2022-11-15 10:31 UTC (permalink / raw) To: fabrice.gasnier, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: Olivier Moysan, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel Add debugfs to read linear ADC STM32 self calibration results. Signed-off-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com> Signed-off-by: Olivier Moysan <olivier.moysan@foss.st.com> --- drivers/iio/adc/stm32-adc.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c index 65dd45537505..45d4e79f8e55 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c @@ -7,6 +7,7 @@ */ #include <linux/clk.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> @@ -1879,6 +1880,23 @@ static const struct iio_chan_spec_ext_info stm32_adc_ext_info[] = { {}, }; +static void stm32_adc_debugfs_init(struct iio_dev *indio_dev) +{ + struct stm32_adc *adc = iio_priv(indio_dev); + struct dentry *d = iio_get_debugfs_dentry(indio_dev); + struct stm32_adc_calib *cal = &adc->cal; + char buf[16]; + unsigned int i; + + if (!adc->cfg->has_linearcal) + return; + + for (i = 0; i < STM32H7_LINCALFACT_NUM; i++) { + snprintf(buf, sizeof(buf), "lincalfact%d", i + 1); + debugfs_create_u32(buf, 0444, d, &cal->lincalfact[i]); + } +} + static int stm32_adc_fw_get_resolution(struct iio_dev *indio_dev) { struct device *dev = &indio_dev->dev; @@ -2465,6 +2483,9 @@ static int stm32_adc_probe(struct platform_device *pdev) pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); + if (IS_ENABLED(CONFIG_DEBUG_FS)) + stm32_adc_debugfs_init(indio_dev); + return 0; err_hw_stop: @@ -2493,6 +2514,7 @@ static int stm32_adc_remove(struct platform_device *pdev) struct stm32_adc *adc = iio_priv(indio_dev); pm_runtime_get_sync(&pdev->dev); + /* iio_device_unregister() also removes debugfs entries */ iio_device_unregister(indio_dev); stm32_adc_hw_stop(&pdev->dev); pm_runtime_disable(&pdev->dev); -- 2.25.1 _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH 0/3] iio: adc: stm32: add smart calibration 2022-11-15 10:31 ` Olivier Moysan @ 2022-11-23 11:04 ` Fabrice Gasnier -1 siblings, 0 replies; 12+ messages in thread From: Fabrice Gasnier @ 2022-11-23 11:04 UTC (permalink / raw) To: Olivier Moysan, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: linux-iio, linux-stm32, linux-arm-kernel, linux-kernel On 11/15/22 11:31, Olivier Moysan wrote: > Refine offset and linear calibration strategy for STM32MP15 and > STM32MP13 SoCs: > > - offset calibration > This calibration depends on factors such as temperature and voltage. > As it is not time consuming, it's worth doing it on each ADC > start, to get the best accuracy. There is no need to save these data. > > - linear calibration > This calibration is basically SoC dependent, so it can be done only once. > When this calibration has been performed at boot stage, the ADC kernel > driver can retrieve the calibration data from the ADC registers. > Otherwise, the linear calibration is performed once by the ADC driver. > The backup of these data, allows to restore them on successive ADC starts. > > Olivier Moysan (3): > iio: adc: stm32-adc: smart calibration support > iio: adc: stm32-adc: improve calibration error log > iio: adc: stm32-adc: add debugfs to read raw calibration result Hi Olivier, For the series, you can add my: Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com> Thanks, Fabrice > > drivers/iio/adc/stm32-adc-core.h | 1 + > drivers/iio/adc/stm32-adc.c | 135 ++++++++++++++++++------------- > 2 files changed, 78 insertions(+), 58 deletions(-) > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/3] iio: adc: stm32: add smart calibration @ 2022-11-23 11:04 ` Fabrice Gasnier 0 siblings, 0 replies; 12+ messages in thread From: Fabrice Gasnier @ 2022-11-23 11:04 UTC (permalink / raw) To: Olivier Moysan, Jonathan Cameron, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue Cc: linux-iio, linux-stm32, linux-arm-kernel, linux-kernel On 11/15/22 11:31, Olivier Moysan wrote: > Refine offset and linear calibration strategy for STM32MP15 and > STM32MP13 SoCs: > > - offset calibration > This calibration depends on factors such as temperature and voltage. > As it is not time consuming, it's worth doing it on each ADC > start, to get the best accuracy. There is no need to save these data. > > - linear calibration > This calibration is basically SoC dependent, so it can be done only once. > When this calibration has been performed at boot stage, the ADC kernel > driver can retrieve the calibration data from the ADC registers. > Otherwise, the linear calibration is performed once by the ADC driver. > The backup of these data, allows to restore them on successive ADC starts. > > Olivier Moysan (3): > iio: adc: stm32-adc: smart calibration support > iio: adc: stm32-adc: improve calibration error log > iio: adc: stm32-adc: add debugfs to read raw calibration result Hi Olivier, For the series, you can add my: Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com> Thanks, Fabrice > > drivers/iio/adc/stm32-adc-core.h | 1 + > drivers/iio/adc/stm32-adc.c | 135 ++++++++++++++++++------------- > 2 files changed, 78 insertions(+), 58 deletions(-) > _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/3] iio: adc: stm32: add smart calibration 2022-11-23 11:04 ` Fabrice Gasnier @ 2022-11-23 20:56 ` Jonathan Cameron -1 siblings, 0 replies; 12+ messages in thread From: Jonathan Cameron @ 2022-11-23 20:56 UTC (permalink / raw) To: Fabrice Gasnier Cc: Olivier Moysan, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel On Wed, 23 Nov 2022 12:04:36 +0100 Fabrice Gasnier <fabrice.gasnier@foss.st.com> wrote: > On 11/15/22 11:31, Olivier Moysan wrote: > > Refine offset and linear calibration strategy for STM32MP15 and > > STM32MP13 SoCs: > > > > - offset calibration > > This calibration depends on factors such as temperature and voltage. > > As it is not time consuming, it's worth doing it on each ADC > > start, to get the best accuracy. There is no need to save these data. > > > > - linear calibration > > This calibration is basically SoC dependent, so it can be done only once. > > When this calibration has been performed at boot stage, the ADC kernel > > driver can retrieve the calibration data from the ADC registers. > > Otherwise, the linear calibration is performed once by the ADC driver. > > The backup of these data, allows to restore them on successive ADC starts. > > > > Olivier Moysan (3): > > iio: adc: stm32-adc: smart calibration support > > iio: adc: stm32-adc: improve calibration error log > > iio: adc: stm32-adc: add debugfs to read raw calibration result > > Hi Olivier, > > For the series, you can add my: > Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com> Applied to the togreg branch of iio.git and pushed out as testing to let 0-day have a first look at it. Thanks, Jonathan > > Thanks, > Fabrice > > > > > drivers/iio/adc/stm32-adc-core.h | 1 + > > drivers/iio/adc/stm32-adc.c | 135 ++++++++++++++++++------------- > > 2 files changed, 78 insertions(+), 58 deletions(-) > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH 0/3] iio: adc: stm32: add smart calibration @ 2022-11-23 20:56 ` Jonathan Cameron 0 siblings, 0 replies; 12+ messages in thread From: Jonathan Cameron @ 2022-11-23 20:56 UTC (permalink / raw) To: Fabrice Gasnier Cc: Olivier Moysan, Lars-Peter Clausen, Maxime Coquelin, Alexandre Torgue, linux-iio, linux-stm32, linux-arm-kernel, linux-kernel On Wed, 23 Nov 2022 12:04:36 +0100 Fabrice Gasnier <fabrice.gasnier@foss.st.com> wrote: > On 11/15/22 11:31, Olivier Moysan wrote: > > Refine offset and linear calibration strategy for STM32MP15 and > > STM32MP13 SoCs: > > > > - offset calibration > > This calibration depends on factors such as temperature and voltage. > > As it is not time consuming, it's worth doing it on each ADC > > start, to get the best accuracy. There is no need to save these data. > > > > - linear calibration > > This calibration is basically SoC dependent, so it can be done only once. > > When this calibration has been performed at boot stage, the ADC kernel > > driver can retrieve the calibration data from the ADC registers. > > Otherwise, the linear calibration is performed once by the ADC driver. > > The backup of these data, allows to restore them on successive ADC starts. > > > > Olivier Moysan (3): > > iio: adc: stm32-adc: smart calibration support > > iio: adc: stm32-adc: improve calibration error log > > iio: adc: stm32-adc: add debugfs to read raw calibration result > > Hi Olivier, > > For the series, you can add my: > Reviewed-by: Fabrice Gasnier <fabrice.gasnier@foss.st.com> Applied to the togreg branch of iio.git and pushed out as testing to let 0-day have a first look at it. Thanks, Jonathan > > Thanks, > Fabrice > > > > > drivers/iio/adc/stm32-adc-core.h | 1 + > > drivers/iio/adc/stm32-adc.c | 135 ++++++++++++++++++------------- > > 2 files changed, 78 insertions(+), 58 deletions(-) > > _______________________________________________ linux-arm-kernel mailing list linux-arm-kernel@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2022-11-23 20:45 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2022-11-15 10:31 [PATCH 0/3] iio: adc: stm32: add smart calibration Olivier Moysan 2022-11-15 10:31 ` Olivier Moysan 2022-11-15 10:31 ` [PATCH 1/3] iio: adc: stm32-adc: smart calibration support Olivier Moysan 2022-11-15 10:31 ` Olivier Moysan 2022-11-15 10:31 ` [PATCH 2/3] iio: adc: stm32-adc: improve calibration error log Olivier Moysan 2022-11-15 10:31 ` Olivier Moysan 2022-11-15 10:31 ` [PATCH 3/3] iio: adc: stm32-adc: add debugfs to read raw calibration result Olivier Moysan 2022-11-15 10:31 ` Olivier Moysan 2022-11-23 11:04 ` [PATCH 0/3] iio: adc: stm32: add smart calibration Fabrice Gasnier 2022-11-23 11:04 ` Fabrice Gasnier 2022-11-23 20:56 ` Jonathan Cameron 2022-11-23 20:56 ` Jonathan Cameron
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.