Skip to content

Commit f8466b4

Browse files
mstasiaknordicnashif
authored andcommitted
drivers: audio: dmic: Add support for multiple nrf PDM instances
Driver now uses multi-instance PDM nrfx API and defines PDM device based on available instances. It also introduces calculating PDM frequency using prescaler, present on nRF54L15 FP1. Updated nrfx API version changed to 3.7 to use the new PDM API. Signed-off-by: Michał Stasiak <[email protected]>
1 parent c092964 commit f8466b4

File tree

3 files changed

+83
-17
lines changed

3 files changed

+83
-17
lines changed

drivers/audio/Kconfig.dmic_pdm_nrfx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ config AUDIO_DMIC_NRFX_PDM
66
default y
77
depends on DT_HAS_NORDIC_NRF_PDM_ENABLED
88
select NRFX_PDM0 if HAS_HW_NRF_PDM0
9+
select NRFX_PDM20 if HAS_HW_NRF_PDM20
10+
select NRFX_PDM21 if HAS_HW_NRF_PDM21
911
select PINCTRL
1012
help
1113
Enable support for nrfx PDM driver for nRF MCU series.

drivers/audio/dmic_nrfx_pdm.c

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
LOG_MODULE_REGISTER(dmic_nrfx_pdm, CONFIG_AUDIO_DMIC_LOG_LEVEL);
1616

1717
struct dmic_nrfx_pdm_drv_data {
18+
const nrfx_pdm_t *pdm;
1819
struct onoff_manager *clk_mgr;
1920
struct onoff_client clk_cli;
2021
struct k_mem_slab *mem_slab;
@@ -58,8 +59,7 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt)
5859
LOG_ERR("Failed to allocate buffer: %d", ret);
5960
stop = true;
6061
} else {
61-
err = nrfx_pdm_buffer_set(buffer,
62-
drv_data->block_size / 2);
62+
err = nrfx_pdm_buffer_set(drv_data->pdm, buffer, drv_data->block_size / 2);
6363
if (err != NRFX_SUCCESS) {
6464
LOG_ERR("Failed to set buffer: 0x%08x", err);
6565
stop = true;
@@ -94,10 +94,15 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt)
9494

9595
if (stop) {
9696
drv_data->stopping = true;
97-
nrfx_pdm_stop();
97+
nrfx_pdm_stop(drv_data->pdm);
9898
}
9999
}
100100

101+
static bool is_in_freq_range(uint32_t freq, const struct dmic_cfg *pdm_cfg)
102+
{
103+
return freq >= pdm_cfg->io.min_pdm_clk_freq && freq <= pdm_cfg->io.max_pdm_clk_freq;
104+
}
105+
101106
static bool is_better(uint32_t freq,
102107
uint8_t ratio,
103108
uint32_t req_rate,
@@ -132,6 +137,37 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
132137
uint32_t req_rate = pdm_cfg->streams[0].pcm_rate;
133138
bool better_found = false;
134139

140+
#if NRF_PDM_HAS_PRESCALER
141+
uint32_t src_freq = 32 * 1000 * 1000UL;
142+
uint32_t req_freq = req_rate * ratio;
143+
uint32_t prescaler = src_freq / req_freq;
144+
uint32_t act_freq = src_freq / prescaler;
145+
146+
if (is_in_freq_range(act_freq, pdm_cfg) &&
147+
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
148+
config->prescaler = prescaler;
149+
150+
better_found = true;
151+
}
152+
153+
/* Stop if an exact rate match is found. */
154+
if (*best_diff == 0) {
155+
return true;
156+
}
157+
158+
/* Prescaler value is rounded down by default,
159+
* thus value rounded up should be checked as well.
160+
*/
161+
prescaler += 1;
162+
act_freq = src_freq / prescaler;
163+
164+
if (is_in_freq_range(act_freq, pdm_cfg) &&
165+
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
166+
config->prescaler = prescaler;
167+
168+
better_found = true;
169+
}
170+
#else
135171
if (IS_ENABLED(CONFIG_SOC_SERIES_NRF53X)) {
136172
const uint32_t src_freq =
137173
(NRF_PDM_HAS_MCLKCONFIG && drv_cfg->clk_src == ACLK)
@@ -158,10 +194,8 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
158194
(src_freq + req_freq / 2));
159195
uint32_t act_freq = src_freq / (1048576 / clk_factor);
160196

161-
if (act_freq >= pdm_cfg->io.min_pdm_clk_freq &&
162-
act_freq <= pdm_cfg->io.max_pdm_clk_freq &&
163-
is_better(act_freq, ratio, req_rate,
164-
best_diff, best_rate, best_freq)) {
197+
if (is_in_freq_range(act_freq, pdm_cfg) &&
198+
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
165199
config->clock_freq = clk_factor * 4096;
166200

167201
better_found = true;
@@ -216,6 +250,7 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
216250
}
217251
}
218252
}
253+
#endif /* NRF_PDM_HAS_PRESCALER */
219254

220255
return better_found;
221256
}
@@ -236,8 +271,26 @@ static bool find_suitable_clock(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
236271
uint8_t ratio_val;
237272
nrf_pdm_ratio_t ratio_enum;
238273
} ratios[] = {
239-
{ 64, NRF_PDM_RATIO_64X },
240-
{ 80, NRF_PDM_RATIO_80X }
274+
#if defined(PDM_RATIO_RATIO_Ratio32)
275+
{ 32, NRF_PDM_RATIO_32X },
276+
#endif
277+
#if defined(PDM_RATIO_RATIO_Ratio48)
278+
{ 48, NRF_PDM_RATIO_48X },
279+
#endif
280+
#if defined(PDM_RATIO_RATIO_Ratio50)
281+
{ 50, NRF_PDM_RATIO_50X },
282+
#endif
283+
{ 64, NRF_PDM_RATIO_64X },
284+
{ 80, NRF_PDM_RATIO_80X },
285+
#if defined(PDM_RATIO_RATIO_Ratio96)
286+
{ 96, NRF_PDM_RATIO_96X },
287+
#endif
288+
#if defined(PDM_RATIO_RATIO_Ratio100)
289+
{ 100, NRF_PDM_RATIO_100X },
290+
#endif
291+
#if defined(PDM_RATIO_RATIO_Ratio128)
292+
{ 128, NRF_PDM_RATIO_128X }
293+
#endif
241294
};
242295

243296
for (int r = 0; best_diff != 0 && r < ARRAY_SIZE(ratios); ++r) {
@@ -327,7 +380,7 @@ static int dmic_nrfx_pdm_configure(const struct device *dev,
327380
/* If either rate or width is 0, the stream is to be disabled. */
328381
if (stream->pcm_rate == 0 || stream->pcm_width == 0) {
329382
if (drv_data->configured) {
330-
nrfx_pdm_uninit();
383+
nrfx_pdm_uninit(drv_data->pdm);
331384
drv_data->configured = false;
332385
}
333386

@@ -357,11 +410,11 @@ static int dmic_nrfx_pdm_configure(const struct device *dev,
357410
}
358411

359412
if (drv_data->configured) {
360-
nrfx_pdm_uninit();
413+
nrfx_pdm_uninit(drv_data->pdm);
361414
drv_data->configured = false;
362415
}
363416

364-
err = nrfx_pdm_init(&nrfx_cfg, drv_cfg->event_handler);
417+
err = nrfx_pdm_init(drv_data->pdm, &nrfx_cfg, drv_cfg->event_handler);
365418
if (err != NRFX_SUCCESS) {
366419
LOG_ERR("Failed to initialize PDM: 0x%08x", err);
367420
return -EIO;
@@ -385,7 +438,7 @@ static int start_transfer(struct dmic_nrfx_pdm_drv_data *drv_data)
385438
nrfx_err_t err;
386439
int ret;
387440

388-
err = nrfx_pdm_start();
441+
err = nrfx_pdm_start(drv_data->pdm);
389442
if (err == NRFX_SUCCESS) {
390443
return 0;
391444
}
@@ -460,7 +513,7 @@ static int dmic_nrfx_pdm_trigger(const struct device *dev,
460513
case DMIC_TRIGGER_STOP:
461514
if (drv_data->active) {
462515
drv_data->stopping = true;
463-
nrfx_pdm_stop();
516+
nrfx_pdm_stop(drv_data->pdm);
464517
}
465518
break;
466519

@@ -541,16 +594,18 @@ static const struct _dmic_ops dmic_ops = {
541594
#define PDM_NRFX_DEVICE(idx) \
542595
static void *rx_msgs##idx[DT_PROP(PDM(idx), queue_size)]; \
543596
static struct dmic_nrfx_pdm_drv_data dmic_nrfx_pdm_data##idx; \
597+
static const nrfx_pdm_t dmic_nrfx_pdm##idx = NRFX_PDM_INSTANCE(idx); \
544598
static int pdm_nrfx_init##idx(const struct device *dev) \
545599
{ \
546600
IRQ_CONNECT(DT_IRQN(PDM(idx)), DT_IRQ(PDM(idx), priority), \
547-
nrfx_isr, nrfx_pdm_irq_handler, 0); \
601+
nrfx_isr, nrfx_pdm_##idx##_irq_handler, 0); \
548602
const struct dmic_nrfx_pdm_drv_cfg *drv_cfg = dev->config; \
549603
int err = pinctrl_apply_state(drv_cfg->pcfg, \
550604
PINCTRL_STATE_DEFAULT); \
551605
if (err < 0) { \
552606
return err; \
553607
} \
608+
dmic_nrfx_pdm_data##idx.pdm = &dmic_nrfx_pdm##idx; \
554609
k_msgq_init(&dmic_nrfx_pdm_data##idx.rx_queue, \
555610
(char *)rx_msgs##idx, sizeof(void *), \
556611
ARRAY_SIZE(rx_msgs##idx)); \
@@ -582,5 +637,14 @@ static const struct _dmic_ops dmic_ops = {
582637
POST_KERNEL, CONFIG_AUDIO_DMIC_INIT_PRIORITY, \
583638
&dmic_ops);
584639

585-
/* Existing SoCs only have one PDM instance. */
640+
#ifdef CONFIG_HAS_HW_NRF_PDM0
586641
PDM_NRFX_DEVICE(0);
642+
#endif
643+
644+
#ifdef CONFIG_HAS_HW_NRF_PDM20
645+
PDM_NRFX_DEVICE(20);
646+
#endif
647+
648+
#ifdef CONFIG_HAS_HW_NRF_PDM21
649+
PDM_NRFX_DEVICE(21);
650+
#endif

modules/hal_nordic/nrfx/nrfx_config_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
/** @brief Symbol specifying minor version of the nrfx API to be used. */
2020
#ifndef NRFX_CONFIG_API_VER_MINOR
21-
#define NRFX_CONFIG_API_VER_MINOR 6
21+
#define NRFX_CONFIG_API_VER_MINOR 7
2222
#endif
2323

2424
/** @brief Symbol specifying micro version of the nrfx API to be used. */

0 commit comments

Comments
 (0)