RE: [PATCH v7 5/6] iio: adc: ad4691: add oversampling support

Sabau, Radu bogdan
2026-04-15T13:27:16Z

> -----Original Message-----
> From: Sabau, Radu bogdan
> Sent: Wednesday, April 15, 2026 4:03 PM

...

> > > >
> > > > More than this, if the OSR is 32 the maximum effective rate would be
> > 31250, so 25kHz
> > > > would make it the closes available one. If the user would select 1MHz
> from
> > the available
> > > > list it would be weird I would say. So perhaps a solution for this is to
> display
> > the avail list
> > > > depending on the set OSR value.
> > >
> > > Yes, the available list should reflect the current state of any other attributes
> > > that affect it.
> >
> > IMO, the above makes total sense to me.
> >
> > - Nuno Sá
> >
>
> Hi everyone and thank you so much for your feedback!
>
> After thinking this through carefully and testing on hardware (ad4692), here is
> the design I have in mind:
>
> in_voltageN_sampling_frequency = effective rate = `osc_freq / osr[N]`:
>
> The chip has a single internal oscillator shred by all channels; each channel
> independently accumulating osc[N] oscillator cycles before producing a result.
>
> Writing in_voltageN_sampling_frequency = freq:
>
> The driver computes the needed_osc = freq * osr[N] and snaps down to the
> largest
> available oscillator table entry satisfying both `osc <= needed_osc` and an exact
> division to osr. The divisibility constraint ensures the read-back is always an
> exact
> integer.
> The result is stored in a single shared `target_osc_freq_Hz` - writing the
> attribute
> for any channel changes the shared oscillator and therefore the read-back of
> all
> other channels.
>
> in_voltageN_sampling_frequency_available:
>
> Computed dynamically from the channel's current OSR. The list naturally
> becomes
> sparser as OSR increases, capping at `max_rate / osr[N]` which is exactly the
> chip's
> behaviour, and therefore more intuitive for the user.
>
> OSC_FREQ_REG write timing:
>
> `target_osc_freq_Hz` is written to hardware at two points:
> - Single-shot read: immediately before starting accumulation.
> - CNV busrt buffer enable: inside enter_conversion_mode, after the manual
> mode
> early return (manual mode uses SPI CS toggling, not the internal oscillator, so
> the
> write is skipped there).
>
> This keeps the deffered-write benefit - both sampling_frequency and osr can
> be
> set in any order before enabling the buffer/single-shot reading.
>
> Buffer Mode:
>
> After desired rates/osr are set by the user for each channel, reading back the
> sampling
> frequency of each channel gives him the true effective rate for each. Therefore
> he can use that information in order to set the buffer sampling frequency
> accordingly
> and helping him use the chip with correct synchronization more intuitively.
>
> I have also performed the next test using the hardware and got correct results:
> - test case (ad4692, 1MHz maximum internal oscillator rate):
>
> 1. Set channel 0 OSR=32. Available list: {31250, 15625, 12500, 6250, 3125}.
> Write sampling_frequency=10000 (not in the list) -> snaps to 6250
> (osc=200000Hz).
> Correct readback = 6250.
> 2. Set channel 1 OSR=4. Read channel 1 sampling frequency -> 50000
> (=200000/4).
> Shared oscillator correctly reflected across channels.
> 3. Change channel 0 OSR from 32 to 8. Driver recomputes as follows : effective
> stays
> 6250 as before and needed_osc becomes 50000, exact table hit. Readback
> channel 0:
> 6250 (rate preserved). Readback channel 1 (OSR=4): 12500. (oscillator
> change visible).
> The sampling for channel 0 can be of course set to another available value as
> well and
> Make match with the initial requested 50k of channel 1. (in this case, set
> channel 0 to
> 25k).
> 4. -EINVAL rejection is atomic: with OSR=1 and SF=1250 at start for lets say
> channel 0, writing
> OSR=32 is rejected since the needed_osc=40000, which is not a table entry
> and also has no
> table entry <= 40000 that is divisible by 32). Both OSR and SF remain
> unchanged. Raising SF
> to 500000 first then writing OSR=32 succeeds - osc snaps to 1000000,
> readback SF=31250.
>
> In (4) case we could still let the user have its sampling frequency as is
> (1250/32=39.0625),
> though it won't result in a precise true integer value, but a rounded (39)
> one, and when
> other channel would have OSR/rate changed it would imply a messy change
> in the previous
> channel's SF and requiring a non-existent/matching internal osc value (most
> of the times
> a float one), and true SF would be lost.
>
> Do you guys think this approach suits the best?
>
> Thanks,
> Radu

Hmm, perhaps changing the internal osc value when changing OSR is not correct.
If OSR is changed, only the effective SF of the respective channel should be changed
not the whole internal osc value. The effective rate readback value then becomes
target_osc_freq / new_osr automatically - no oscillator recalculation upon osr write,
no -EINVAL.

Then, if after an OSR change the effective rate is not on the available list (as the edge
case before of 39 rounded), writing `sampling_frequency` (choosing a new available value)
fixes it. The 39 rounded would still work correctly, only that the value at hand wouldn't
be precise to the last decimal though I guess the user should be aware that 1250/32 is
not an actual round 39, right?