Skip to content

Commit 079d803

Browse files
mstasiaknordicmasz-nordic
authored andcommitted
[nrf fromlist] drivers: audio: dmic_nrfx_pdm: introduce prescaler calculation
Added usage of new API responsible for calculating PDM prescaler values. Upstream PR #: 96703 Signed-off-by: Michał Stasiak <[email protected]>
1 parent 5c04023 commit 079d803

File tree

1 file changed

+10
-217
lines changed

1 file changed

+10
-217
lines changed

drivers/audio/dmic_nrfx_pdm.c

Lines changed: 10 additions & 217 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ LOG_MODULE_REGISTER(dmic_nrfx_pdm, CONFIG_AUDIO_DMIC_LOG_LEVEL);
2121

2222
#if CONFIG_SOC_SERIES_NRF54HX
2323
#define DMIC_NRFX_CLOCK_FREQ MHZ(16)
24-
#define DMIC_NRFX_CLOCK_FACTOR 8192
2524
#define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP_OR(NODE_AUDIOPLL, frequency, 0)
2625
#elif DT_NODE_HAS_STATUS_OKAY(NODE_AUDIO_AUXPLL)
2726
#define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP(NODE_AUDIO_AUXPLL, nordic_frequency)
@@ -31,7 +30,6 @@ BUILD_ASSERT((DMIC_NRFX_AUDIO_CLOCK_FREQ == NRF_AUXPLL_FREQ_DIV_AUDIO_48K) ||
3130
#define DMIC_NRFX_CLOCK_FREQ MHZ(32)
3231
#else
3332
#define DMIC_NRFX_CLOCK_FREQ MHZ(32)
34-
#define DMIC_NRFX_CLOCK_FACTOR 4096
3533
#define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP_OR(DT_NODELABEL(aclk), clock_frequency, \
3634
DT_PROP_OR(DT_NODELABEL(clock), hfclkaudio_frequency, 0))
3735
#endif
@@ -202,220 +200,6 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt)
202200
}
203201
}
204202

205-
static bool is_in_freq_range(uint32_t freq, const struct dmic_cfg *pdm_cfg)
206-
{
207-
return freq >= pdm_cfg->io.min_pdm_clk_freq && freq <= pdm_cfg->io.max_pdm_clk_freq;
208-
}
209-
210-
static bool is_better(uint32_t freq,
211-
uint8_t ratio,
212-
uint32_t req_rate,
213-
uint32_t *best_diff,
214-
uint32_t *best_rate,
215-
uint32_t *best_freq)
216-
{
217-
uint32_t act_rate = freq / ratio;
218-
uint32_t diff = act_rate >= req_rate ? (act_rate - req_rate)
219-
: (req_rate - act_rate);
220-
221-
LOG_DBG("Freq %u, ratio %u, act_rate %u", freq, ratio, act_rate);
222-
223-
if (diff < *best_diff) {
224-
*best_diff = diff;
225-
*best_rate = act_rate;
226-
*best_freq = freq;
227-
return true;
228-
}
229-
230-
return false;
231-
}
232-
233-
static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
234-
nrfx_pdm_config_t *config,
235-
const struct dmic_cfg *pdm_cfg,
236-
uint8_t ratio,
237-
uint32_t *best_diff,
238-
uint32_t *best_rate,
239-
uint32_t *best_freq)
240-
{
241-
uint32_t req_rate = pdm_cfg->streams[0].pcm_rate;
242-
bool better_found = false;
243-
const uint32_t src_freq =
244-
(NRF_PDM_HAS_SELECTABLE_CLOCK && drv_cfg->clk_src == ACLK)
245-
? DMIC_NRFX_AUDIO_CLOCK_FREQ
246-
: DMIC_NRFX_CLOCK_FREQ;
247-
#if NRF_PDM_HAS_PRESCALER
248-
uint32_t req_freq = req_rate * ratio;
249-
uint32_t prescaler = src_freq / req_freq;
250-
uint32_t act_freq = src_freq / prescaler;
251-
252-
if (is_in_freq_range(act_freq, pdm_cfg) &&
253-
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
254-
config->prescaler = prescaler;
255-
256-
better_found = true;
257-
}
258-
259-
/* Stop if an exact rate match is found. */
260-
if (*best_diff == 0) {
261-
return true;
262-
}
263-
264-
/* Prescaler value is rounded down by default,
265-
* thus value rounded up should be checked as well.
266-
*/
267-
prescaler += 1;
268-
act_freq = src_freq / prescaler;
269-
270-
if (is_in_freq_range(act_freq, pdm_cfg) &&
271-
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
272-
config->prescaler = prescaler;
273-
274-
better_found = true;
275-
}
276-
#else
277-
if (IS_ENABLED(CONFIG_SOC_SERIES_NRF53X) || IS_ENABLED(CONFIG_SOC_SERIES_NRF54HX)) {
278-
uint32_t req_freq = req_rate * ratio;
279-
/* As specified in the nRF5340 PS:
280-
*
281-
* PDMCLKCTRL = 4096 * floor(f_pdm * 1048576 /
282-
* (f_source + f_pdm / 2))
283-
* f_actual = f_source / floor(1048576 * 4096 / PDMCLKCTRL)
284-
*/
285-
uint32_t clk_factor = (uint32_t)((req_freq * 1048576ULL) /
286-
(src_freq + req_freq / 2));
287-
uint32_t act_freq = src_freq / (1048576 / clk_factor);
288-
289-
if (is_in_freq_range(act_freq, pdm_cfg) &&
290-
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
291-
config->clock_freq = clk_factor * DMIC_NRFX_CLOCK_FACTOR;
292-
293-
better_found = true;
294-
}
295-
} else { /* -> !IS_ENABLED(CONFIG_SOC_SERIES_NRF53X)) */
296-
static const struct {
297-
uint32_t freq_val;
298-
nrf_pdm_freq_t freq_enum;
299-
} freqs[] = {
300-
{ 1000000, NRF_PDM_FREQ_1000K },
301-
{ 1032000, NRF_PDM_FREQ_1032K },
302-
{ 1067000, NRF_PDM_FREQ_1067K },
303-
#if defined(PDM_PDMCLKCTRL_FREQ_1231K)
304-
{ 1231000, NRF_PDM_FREQ_1231K },
305-
#endif
306-
#if defined(PDM_PDMCLKCTRL_FREQ_1280K)
307-
{ 1280000, NRF_PDM_FREQ_1280K },
308-
#endif
309-
#if defined(PDM_PDMCLKCTRL_FREQ_1333K)
310-
{ 1333000, NRF_PDM_FREQ_1333K }
311-
#endif
312-
};
313-
314-
for (int i = 0; i < ARRAY_SIZE(freqs); ++i) {
315-
uint32_t freq_val = freqs[i].freq_val;
316-
317-
if (freq_val < pdm_cfg->io.min_pdm_clk_freq) {
318-
continue;
319-
}
320-
if (freq_val > pdm_cfg->io.max_pdm_clk_freq) {
321-
break;
322-
}
323-
324-
if (is_better(freq_val, ratio, req_rate,
325-
best_diff, best_rate, best_freq)) {
326-
config->clock_freq = freqs[i].freq_enum;
327-
328-
/* Stop if an exact rate match is found. */
329-
if (*best_diff == 0) {
330-
return true;
331-
}
332-
333-
better_found = true;
334-
}
335-
336-
/* Since frequencies are in ascending order, stop
337-
* checking next ones for the current ratio after
338-
* resulting PCM rate goes above the one requested.
339-
*/
340-
if ((freq_val / ratio) > req_rate) {
341-
break;
342-
}
343-
}
344-
}
345-
#endif /* NRF_PDM_HAS_PRESCALER */
346-
347-
return better_found;
348-
}
349-
350-
/* Finds clock settings that give the PCM output rate closest to that requested,
351-
* taking into account the hardware limitations.
352-
*/
353-
static bool find_suitable_clock(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
354-
nrfx_pdm_config_t *config,
355-
const struct dmic_cfg *pdm_cfg)
356-
{
357-
uint32_t best_diff = UINT32_MAX;
358-
uint32_t best_rate;
359-
uint32_t best_freq;
360-
361-
#if NRF_PDM_HAS_RATIO_CONFIG
362-
static const struct {
363-
uint8_t ratio_val;
364-
nrf_pdm_ratio_t ratio_enum;
365-
} ratios[] = {
366-
#if defined(PDM_RATIO_RATIO_Ratio32)
367-
{ 32, NRF_PDM_RATIO_32X },
368-
#endif
369-
#if defined(PDM_RATIO_RATIO_Ratio48)
370-
{ 48, NRF_PDM_RATIO_48X },
371-
#endif
372-
#if defined(PDM_RATIO_RATIO_Ratio50)
373-
{ 50, NRF_PDM_RATIO_50X },
374-
#endif
375-
{ 64, NRF_PDM_RATIO_64X },
376-
{ 80, NRF_PDM_RATIO_80X },
377-
#if defined(PDM_RATIO_RATIO_Ratio96)
378-
{ 96, NRF_PDM_RATIO_96X },
379-
#endif
380-
#if defined(PDM_RATIO_RATIO_Ratio100)
381-
{ 100, NRF_PDM_RATIO_100X },
382-
#endif
383-
#if defined(PDM_RATIO_RATIO_Ratio128)
384-
{ 128, NRF_PDM_RATIO_128X }
385-
#endif
386-
};
387-
388-
for (int r = 0; best_diff != 0 && r < ARRAY_SIZE(ratios); ++r) {
389-
uint8_t ratio = ratios[r].ratio_val;
390-
391-
if (check_pdm_frequencies(drv_cfg, config, pdm_cfg, ratio,
392-
&best_diff, &best_rate, &best_freq)) {
393-
config->ratio = ratios[r].ratio_enum;
394-
395-
/* Look no further if a configuration giving the exact
396-
* PCM rate is found.
397-
*/
398-
if (best_diff == 0) {
399-
break;
400-
}
401-
}
402-
}
403-
#else
404-
uint8_t ratio = 64;
405-
406-
(void)check_pdm_frequencies(drv_cfg, config, pdm_cfg, ratio,
407-
&best_diff, &best_rate, &best_freq);
408-
#endif
409-
410-
if (best_diff == UINT32_MAX) {
411-
return false;
412-
}
413-
414-
LOG_INF("PDM clock frequency: %u, actual PCM rate: %u",
415-
best_freq, best_rate);
416-
return true;
417-
}
418-
419203
static int dmic_nrfx_pdm_configure(const struct device *dev,
420204
struct dmic_cfg *config)
421205
{
@@ -499,7 +283,16 @@ static int dmic_nrfx_pdm_configure(const struct device *dev,
499283
? NRF_PDM_MCLKSRC_ACLK
500284
: NRF_PDM_MCLKSRC_PCLK32M;
501285
#endif
502-
if (!find_suitable_clock(drv_cfg, &nrfx_cfg, config)) {
286+
nrfx_pdm_output_t output_config = {
287+
.base_clock_freq = (NRF_PDM_HAS_SELECTABLE_CLOCK && drv_cfg->clk_src == ACLK)
288+
? DMIC_NRFX_AUDIO_CLOCK_FREQ
289+
: DMIC_NRFX_CLOCK_FREQ,
290+
.sampling_rate = config->streams[0].pcm_rate,
291+
.output_freq_min = config->io.min_pdm_clk_freq,
292+
.output_freq_max = config->io.max_pdm_clk_freq
293+
};
294+
295+
if (nrfx_pdm_prescalers_calc(&output_config, &nrfx_cfg.prescalers) != NRFX_SUCCESS) {
503296
LOG_ERR("Cannot find suitable PDM clock configuration.");
504297
return -EINVAL;
505298
}

0 commit comments

Comments
 (0)