Skip to content

Commit 429383d

Browse files
ukleineknunojsa
authored andcommitted
iio: adc: ad400x: Make requested sampling frequency a hard upper limit
Usually freq is the maximal allowed frequency documented in the data sheet. So it makes sense to interpret a request to set a given frequency `freq` as: Sample as fast as possible, but not faster than `freq`. The math to achieve this is a bit harder than what is currently implemented in the driver. The status quo however doesn't ensure that the sample frequency isn't faster than the maximal allowed freq. (E.g. for st->ref_clk_rate = 166666665 and freq = 2000000, .period = 500 was passed to pwm_apply_state() which resulted in configuring a period of approx. 498 ns which results in a higher sample rate than 2000000 Hz.) Signed-off-by: Uwe Kleine-König <u.kleine-koenig@baylibre.com>
1 parent 26fc3de commit 429383d

File tree

1 file changed

+28
-1
lines changed

1 file changed

+28
-1
lines changed

drivers/iio/adc/ad400x.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,11 +205,38 @@ static int ad400x_get_sampling_freq(struct ad400x_state *st)
205205
static int __ad400x_set_sampling_freq(struct ad400x_state *st, int freq)
206206
{
207207
struct pwm_state cnv_state;
208+
u32 rem;
208209

209210
/* Sync up PWM state and prepare for pwm_apply_state(). */
210211
pwm_init_state(st->cnv_trigger, &cnv_state);
211212

212-
cnv_state.period = DIV_ROUND_CLOSEST_ULL(NSEC_PER_SEC, freq);
213+
/*
214+
* The goal here is that the PWM is configured with a minimal period not
215+
* less than 1 / freq (with freq measured in Hz). It should not be less
216+
* because freq is usually st->chip->max_rate which is a hard limit.
217+
*
218+
* When a period P (measured in ns) is passed to pwm_apply_state(), the
219+
* actually implemented period is:
220+
*
221+
* round_down(P * R / NSEC_PER_SEC) / R
222+
*
223+
* (measured in s) with R = st->ref_clk_rate. So we have:
224+
*
225+
* round_down(P * R / NSEC_PER_SEC) / R ≥ 1 / freq
226+
* ⟺ round_down(P * R / NSEC_PER_SEC) ≥ R / freq
227+
*
228+
* With the LHS being integer this is equivalent to:
229+
*
230+
* round_down(P * R / NSEC_PER_SEC) ≥ round_up(R / freq)
231+
* ⟺ P * R / NSEC_PER_SEC ≥ round_up(R / freq)
232+
* ⟺ P ≥ round_up(R / freq) * NSEC_PER_SEC / R
233+
*/
234+
235+
cnv_state.period = div_u64_rem((u64)DIV_ROUND_UP(st->ref_clk_rate, freq) * NSEC_PER_SEC,
236+
st->ref_clk_rate, &rem);
237+
if (rem)
238+
cnv_state.period += 1;
239+
213240
cnv_state.duty_cycle = DIV_ROUND_UP(NSEC_PER_SEC, st->ref_clk_rate);
214241

215242
return pwm_apply_state(st->cnv_trigger, &cnv_state);

0 commit comments

Comments
 (0)