[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <6d12b6fe-85fb-4345-bf32-02c0fbb1a27a@foss.st.com>
Date: Mon, 7 Apr 2025 18:07:17 +0200
From: Olivier MOYSAN <olivier.moysan@...s.st.com>
To: David Lechner <dlechner@...libre.com>,
Jonathan Cameron
<jic23@...nel.org>,
Lars-Peter Clausen <lars@...afoo.de>,
Maxime Coquelin
<mcoquelin.stm32@...il.com>,
Alexandre Torgue <alexandre.torgue@...s.st.com>
CC: Fabrice Gasnier <fabrice.gasnier@...s.st.com>, <linux-iio@...r.kernel.org>,
<linux-stm32@...md-mailman.stormreply.com>,
<linux-arm-kernel@...ts.infradead.org>, <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH v2] iio: adc: stm32: add oversampling support
Hi David,
Thanks for reviewing,
On 4/4/25 18:15, David Lechner wrote:
> On 4/3/25 11:23 AM, Olivier Moysan wrote:
>> Add oversampling support for STM32H7, STM32MP15 & STM32MP13.
>> STM32F4 ADC has no oversampling feature.
>>
>> The current support of the oversampling feature aims at increasing
>> the data SNR, without changing the data resolution.
>> As the oversampling by itself increases data resolution,
>> a right shift is applied to keep initial resolution.
>
> Why do we not want the extra bits too? I guess if we wanted the extra bits
> in the future we could make the in_voltage_scale attribute writable to
> select the resolution.
>
Yes, I agree that the oversampling feature could could be further
exploited. It could also be used to increase the data resolution.
This additional feature can be managed as a separate patch later.
The main logic here was to keep the resolution aligned with the one
requested in the DT, through the "assigned-resolution-bits" property.
>> Only the oversampling ratio corresponding to a power of two are
>> supported here, to get a direct link between right shift and
>> oversampling ratio. (2exp(n) ratio <=> n right shift)
>>
>> The oversampling ratio is shared by all channels, whatever channel type.
>> (e.g. single ended or differential).
>>
>> Oversampling can be configured using IIO ABI:
>> - in_voltage_oversampling_ratio_available
>> - in_voltage_oversampling_ratio
>
> This would require info_mask_shared_by_type but the patch uses
> info_mask_shared_by_all, so the attributes will be:
>
> - oversampling_ratio
> - oversampling_ratio_available
>
> I guess currently it doesn't matter which one gets used if there are only
> voltage channels, but it could make a difference, e.g. if a temperature
> channel was ever added.
>
> In any case, the description should match what is actually implemented.
>
The oversampling configuration is shared by all the channels of a given
ADC instance. So, it makes sense to use info_mask_shared_by_all here.
What is the most relevant is to change the commit message to
"- oversampling_ratio
- oversampling_ratio_available"
which are the attributes actually exposed.
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@...s.st.com>
>> Signed-off-by: Olivier Moysan <olivier.moysan@...s.st.com>
>>
>> ---
>> Changes in v2:
>> - Remove useless header files
>> - Use FIELD_PREP macro
>> - Reorder stm32_adc_write_raw() function
>
> Link to v1? (for the lazy reviewer :-p)
>
>> ---
>> drivers/iio/adc/stm32-adc-core.h | 14 ++++
>> drivers/iio/adc/stm32-adc.c | 137 +++++++++++++++++++++++++++++++
>> 2 files changed, 151 insertions(+)
>>
>> diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h
>> index 73b2c2e91c08..bfd42c5456bf 100644
>> --- a/drivers/iio/adc/stm32-adc-core.h
>> +++ b/drivers/iio/adc/stm32-adc-core.h
>> @@ -91,6 +91,7 @@
>> #define STM32H7_ADC_IER 0x04
>> #define STM32H7_ADC_CR 0x08
>> #define STM32H7_ADC_CFGR 0x0C
>> +#define STM32H7_ADC_CFGR2 0x10
>> #define STM32H7_ADC_SMPR1 0x14
>> #define STM32H7_ADC_SMPR2 0x18
>> #define STM32H7_ADC_PCSEL 0x1C
>> @@ -160,6 +161,13 @@
>> #define STM32H7_DMNGT_SHIFT 0
>> #define STM32H7_DMNGT_MASK GENMASK(1, 0)
>>
>> +/* STM32H7_ADC_CFGR2 bit fields */
>> +#define STM32H7_OVSR_MASK GENMASK(25, 16) /* Correspond to OSVR field in datasheet */
>
> nit: Comment seems obvious and can be left out.
>
Oversampling bit name is "OSVR" in datasheet H7, while oversampling
shift is "OVSS". For naming consistency, I used OVSR instead of OSVR,
and highlighted it with a comment. As an alternative, STM32H7_OVSR could
be renamed, but I would rather keep it unchanged.
>> +#define STM32H7_OVSR(v) FIELD_PREP(STM32H7_OVSR_MASK, v)
>> +#define STM32H7_OVSS_MASK GENMASK(8, 5)
>> +#define STM32H7_OVSS(v) FIELD_PREP(STM32H7_OVSS_MASK, v)
>> +#define STM32H7_ROVSE BIT(0)
>> +
>
> ...
>
>> +static const unsigned int stm32h7_adc_oversampling_avail[] = {
>> +1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024
>
> Normal style is to have 1 tab indent here.
>
ok
>> +};
>> +
>> +static const unsigned int stm32mp13_adc_oversampling_avail[] = {
>> +1, 2, 4, 8, 16, 32, 64, 128, 256
>
> And here.
>
ok
>> };
>>
>
> ...
>
>> @@ -889,6 +912,41 @@ static void stm32mp13_adc_start_conv(struct iio_dev *indio_dev, bool dma)
>> stm32_adc_set_bits(adc, STM32H7_ADC_CR, STM32H7_ADSTART);
>> }
>>
>> +static void stm32h7_adc_set_ovs(struct iio_dev *indio_dev, u32 ovs_idx)
>> +{
>> + struct stm32_adc *adc = iio_priv(indio_dev);
>> + u32 ovsr_bits, bits, msk;
>> +
>> + msk = STM32H7_ROVSE | STM32H7_OVSR_MASK | STM32H7_OVSS_MASK;
>> + stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR2, msk);
>> +
>> + if (!ovs_idx)
>> + return;
>> +
>> + ovsr_bits = (1 << ovs_idx) - 1;
>> + bits = STM32H7_ROVSE | STM32H7_OVSS(ovs_idx) | STM32H7_OVSR(ovsr_bits);
>> +
>> + stm32_adc_set_bits(adc, STM32H7_ADC_CFGR2, bits & msk);
>> +}
>> +
>> +static void stm32mp13_adc_set_ovs(struct iio_dev *indio_dev, u32 ovs_idx)
>> +{
>> + struct stm32_adc *adc = iio_priv(indio_dev);
>> + u32 bits, msk;
>> +
>> + msk = STM32H7_ROVSE | STM32MP13_OVSR_MASK | STM32MP13_OVSS_MASK;
>> + stm32_adc_clr_bits(adc, STM32H7_ADC_CFGR2, msk);
>> +
>> + if (!ovs_idx)
>> + return;
>> +
>> + bits = STM32H7_ROVSE | STM32MP13_OVSS(ovs_idx);
>> + if (ovs_idx - 1)
>> + bits |= STM32MP13_OVSR(ovs_idx - 1);
>> +
>> + stm32_adc_set_bits(adc, STM32H7_ADC_CFGR2, bits & msk);
>> +}
>
>
> Some comments in these functions could be useful to avoid needing the
> datasheet to understand all the different things that are happening here
> and more importantly, why it was decided to do it this way when there are
> many other possibilities (i.e. repeat the bit from commit message about
> always using 12-bit output).
>
ok, I will add some comments here.
>> @@ -1461,6 +1519,69 @@ static int stm32_adc_single_conv(struct iio_dev *indio_dev,
>> return ret;
>> }
>>
>> +static int stm32_adc_write_raw(struct iio_dev *indio_dev,
>> + struct iio_chan_spec const *chan,
>> + int val, int val2, long mask)
>> +{
>> + struct stm32_adc *adc = iio_priv(indio_dev);
>> + struct device *dev = indio_dev->dev.parent;
>> + int nb = adc->cfg->adc_info->num_ovs;
>> + u32 idx;
>> + int ret;
>> +
>> + switch (mask) {
>> + case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
>> + if (val2)
>> + return -EINVAL;
>> +
>> + for (idx = 0; idx < nb; idx++)
>> + if (adc->cfg->adc_info->oversampling[idx] == val)
>> + break;
>> +
>> + if (idx >= nb)
>> + return -EINVAL;
>> +
>> + ret = iio_device_claim_direct_mode(indio_dev);
>> + if (ret)
>> + return ret;
>
> We've been replacing this everywhere with:
>
> if (!iio_device_claim_direct(indio_dev))
> return -EBUSY;
>
> See: https://lore.kernel.org/linux-iio/20250331121317.1694135-1-jic23@kernel.org/
>
ok
>> +
>> + ret = pm_runtime_resume_and_get(dev);
>> + if (ret < 0)
>> + goto err;
>> +
>> + adc->cfg->set_ovs(indio_dev, idx);
>> +
>> + pm_runtime_mark_last_busy(dev);
>> + pm_runtime_put_autosuspend(dev);
>> +
>> + adc->ovs_idx = idx;
>> +
>> +err:
>> + iio_device_release_direct_mode(indio_dev);
>
> iio_device_release_direct(indio_dev);
>
>> +
>> + return ret;
>> + default:
>> + return -EINVAL;
>> + }
>> +}
BRs
Olivier
Powered by blists - more mailing lists