Skip to content

Commit 7425bf2

Browse files
[nrf fromlist] 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. Signed-off-by: Michał Stasiak <[email protected]>
1 parent 6609cdd commit 7425bf2

File tree

2 files changed

+99
-33
lines changed

2 files changed

+99
-33
lines changed

drivers/audio/Kconfig.dmic_pdm_nrfx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ config AUDIO_DMIC_NRFX_PDM
55
bool "nRF PDM nrfx driver"
66
default y
77
depends on DT_HAS_NORDIC_NRF_PDM_ENABLED
8-
select NRFX_PDM
8+
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: 96 additions & 32 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;
@@ -28,6 +29,7 @@ struct dmic_nrfx_pdm_drv_data {
2829

2930
struct dmic_nrfx_pdm_drv_cfg {
3031
nrfx_pdm_event_handler_t event_handler;
32+
nrfx_pdm_t pdm;
3133
nrfx_pdm_config_t nrfx_def_cfg;
3234
const struct pinctrl_dev_config *pcfg;
3335
enum clock_source {
@@ -58,8 +60,7 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt)
5860
LOG_ERR("Failed to allocate buffer: %d", ret);
5961
stop = true;
6062
} else {
61-
err = nrfx_pdm_buffer_set(buffer,
62-
drv_data->block_size / 2);
63+
err = nrfx_pdm_buffer_set(drv_data->pdm, buffer, drv_data->block_size / 2);
6364
if (err != NRFX_SUCCESS) {
6465
LOG_ERR("Failed to set buffer: 0x%08x", err);
6566
stop = true;
@@ -94,7 +95,7 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt)
9495

9596
if (stop) {
9697
drv_data->stopping = true;
97-
nrfx_pdm_stop();
98+
nrfx_pdm_stop(drv_data->pdm);
9899
}
99100
}
100101

@@ -132,6 +133,37 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
132133
uint32_t req_rate = pdm_cfg->streams[0].pcm_rate;
133134
bool better_found = false;
134135

136+
#if NRF_PDM_HAS_PRESCALER
137+
uint32_t src_freq = 32 * 1000 * 1000UL;
138+
uint32_t req_freq = req_rate * ratio;
139+
uint32_t prescaler = src_freq / req_freq;
140+
uint32_t act_freq = src_freq / prescaler;
141+
142+
if (act_freq >= pdm_cfg->io.min_pdm_clk_freq && act_freq <= pdm_cfg->io.max_pdm_clk_freq &&
143+
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
144+
config->prescaler = prescaler;
145+
146+
better_found = true;
147+
}
148+
149+
/* Stop if an exact rate match is found. */
150+
if (*best_diff == 0) {
151+
return true;
152+
}
153+
154+
/* Prescaler value is rounded down by default,
155+
* thus value rounded up should be checked as well.
156+
*/
157+
prescaler += 1;
158+
act_freq = src_freq / prescaler;
159+
160+
if (act_freq >= pdm_cfg->io.min_pdm_clk_freq && act_freq <= pdm_cfg->io.max_pdm_clk_freq &&
161+
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
162+
config->prescaler = prescaler;
163+
164+
better_found = true;
165+
}
166+
#else
135167
if (IS_ENABLED(CONFIG_SOC_SERIES_NRF53X)) {
136168
const uint32_t src_freq =
137169
(NRF_PDM_HAS_MCLKCONFIG && drv_cfg->clk_src == ACLK)
@@ -171,17 +203,17 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
171203
uint32_t freq_val;
172204
nrf_pdm_freq_t freq_enum;
173205
} freqs[] = {
174-
{ 1000000, NRF_PDM_FREQ_1000K },
175-
{ 1032000, NRF_PDM_FREQ_1032K },
176-
{ 1067000, NRF_PDM_FREQ_1067K },
206+
{1000000, NRF_PDM_FREQ_1000K},
207+
{1032000, NRF_PDM_FREQ_1032K},
208+
{1067000, NRF_PDM_FREQ_1067K},
177209
#if defined(PDM_PDMCLKCTRL_FREQ_1231K)
178-
{ 1231000, NRF_PDM_FREQ_1231K },
210+
{1231000, NRF_PDM_FREQ_1231K},
179211
#endif
180212
#if defined(PDM_PDMCLKCTRL_FREQ_1280K)
181-
{ 1280000, NRF_PDM_FREQ_1280K },
213+
{1280000, NRF_PDM_FREQ_1280K},
182214
#endif
183215
#if defined(PDM_PDMCLKCTRL_FREQ_1333K)
184-
{ 1333000, NRF_PDM_FREQ_1333K }
216+
{1333000, NRF_PDM_FREQ_1333K}
185217
#endif
186218
};
187219

@@ -216,6 +248,7 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
216248
}
217249
}
218250
}
251+
#endif
219252

220253
return better_found;
221254
}
@@ -236,8 +269,26 @@ static bool find_suitable_clock(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
236269
uint8_t ratio_val;
237270
nrf_pdm_ratio_t ratio_enum;
238271
} ratios[] = {
239-
{ 64, NRF_PDM_RATIO_64X },
240-
{ 80, NRF_PDM_RATIO_80X }
272+
#if defined(PDM_RATIO_RATIO_Ratio32)
273+
{32, NRF_PDM_RATIO_32X},
274+
#endif
275+
#if defined(PDM_RATIO_RATIO_Ratio48)
276+
{48, NRF_PDM_RATIO_48X},
277+
#endif
278+
#if defined(PDM_RATIO_RATIO_Ratio50)
279+
{50, NRF_PDM_RATIO_50X},
280+
#endif
281+
{64, NRF_PDM_RATIO_64X},
282+
{80, NRF_PDM_RATIO_80X},
283+
#if defined(PDM_RATIO_RATIO_Ratio96)
284+
{96, NRF_PDM_RATIO_96X},
285+
#endif
286+
#if defined(PDM_RATIO_RATIO_Ratio100)
287+
{100, NRF_PDM_RATIO_100X},
288+
#endif
289+
#if defined(PDM_RATIO_RATIO_Ratio128)
290+
{128, NRF_PDM_RATIO_128X}
291+
#endif
241292
};
242293

243294
for (int r = 0; best_diff != 0 && r < ARRAY_SIZE(ratios); ++r) {
@@ -327,7 +378,7 @@ static int dmic_nrfx_pdm_configure(const struct device *dev,
327378
/* If either rate or width is 0, the stream is to be disabled. */
328379
if (stream->pcm_rate == 0 || stream->pcm_width == 0) {
329380
if (drv_data->configured) {
330-
nrfx_pdm_uninit();
381+
nrfx_pdm_uninit(drv_data->pdm);
331382
drv_data->configured = false;
332383
}
333384

@@ -357,11 +408,11 @@ static int dmic_nrfx_pdm_configure(const struct device *dev,
357408
}
358409

359410
if (drv_data->configured) {
360-
nrfx_pdm_uninit();
411+
nrfx_pdm_uninit(drv_data->pdm);
361412
drv_data->configured = false;
362413
}
363414

364-
err = nrfx_pdm_init(&nrfx_cfg, drv_cfg->event_handler);
415+
err = nrfx_pdm_init(drv_data->pdm, &nrfx_cfg, drv_cfg->event_handler);
365416
if (err != NRFX_SUCCESS) {
366417
LOG_ERR("Failed to initialize PDM: 0x%08x", err);
367418
return -EIO;
@@ -385,7 +436,7 @@ static int start_transfer(struct dmic_nrfx_pdm_drv_data *drv_data)
385436
nrfx_err_t err;
386437
int ret;
387438

388-
err = nrfx_pdm_start();
439+
err = nrfx_pdm_start(drv_data->pdm);
389440
if (err == NRFX_SUCCESS) {
390441
return 0;
391442
}
@@ -460,7 +511,7 @@ static int dmic_nrfx_pdm_trigger(const struct device *dev,
460511
case DMIC_TRIGGER_STOP:
461512
if (drv_data->active) {
462513
drv_data->stopping = true;
463-
nrfx_pdm_stop();
514+
nrfx_pdm_stop(drv_data->pdm);
464515
}
465516
break;
466517

@@ -540,11 +591,28 @@ static const struct _dmic_ops dmic_ops = {
540591

541592
#define PDM_NRFX_DEVICE(idx) \
542593
static void *rx_msgs##idx[DT_PROP(PDM(idx), queue_size)]; \
543-
static struct dmic_nrfx_pdm_drv_data dmic_nrfx_pdm_data##idx; \
594+
static void event_handler##idx(const nrfx_pdm_evt_t *evt) \
595+
{ \
596+
event_handler(DEVICE_DT_GET(PDM(idx)), evt); \
597+
} \
598+
PINCTRL_DT_DEFINE(PDM(idx)); \
599+
static const struct dmic_nrfx_pdm_drv_cfg dmic_nrfx_pdm_cfg##idx = { \
600+
.event_handler = event_handler##idx, \
601+
.pdm = NRFX_PDM_INSTANCE(idx), \
602+
.nrfx_def_cfg = NRFX_PDM_DEFAULT_CONFIG(0, 0), \
603+
.nrfx_def_cfg.skip_gpio_cfg = true, \
604+
.nrfx_def_cfg.skip_psel_cfg = true, \
605+
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(PDM(idx)), \
606+
.clk_src = PDM_CLK_SRC(idx), \
607+
}; \
608+
static struct dmic_nrfx_pdm_drv_data dmic_nrfx_pdm_data##idx = \
609+
{ \
610+
.pdm = &dmic_nrfx_pdm_cfg##idx.pdm \
611+
}; \
544612
static int pdm_nrfx_init##idx(const struct device *dev) \
545613
{ \
546614
IRQ_CONNECT(DT_IRQN(PDM(idx)), DT_IRQ(PDM(idx), priority), \
547-
nrfx_isr, nrfx_pdm_irq_handler, 0); \
615+
nrfx_isr, nrfx_pdm_##idx##_irq_handler, 0); \
548616
const struct dmic_nrfx_pdm_drv_cfg *drv_cfg = dev->config; \
549617
int err = pinctrl_apply_state(drv_cfg->pcfg, \
550618
PINCTRL_STATE_DEFAULT); \
@@ -557,19 +625,6 @@ static const struct _dmic_ops dmic_ops = {
557625
init_clock_manager(dev); \
558626
return 0; \
559627
} \
560-
static void event_handler##idx(const nrfx_pdm_evt_t *evt) \
561-
{ \
562-
event_handler(DEVICE_DT_GET(PDM(idx)), evt); \
563-
} \
564-
PINCTRL_DT_DEFINE(PDM(idx)); \
565-
static const struct dmic_nrfx_pdm_drv_cfg dmic_nrfx_pdm_cfg##idx = { \
566-
.event_handler = event_handler##idx, \
567-
.nrfx_def_cfg = NRFX_PDM_DEFAULT_CONFIG(0, 0), \
568-
.nrfx_def_cfg.skip_gpio_cfg = true, \
569-
.nrfx_def_cfg.skip_psel_cfg = true, \
570-
.pcfg = PINCTRL_DT_DEV_CONFIG_GET(PDM(idx)), \
571-
.clk_src = PDM_CLK_SRC(idx), \
572-
}; \
573628
BUILD_ASSERT(PDM_CLK_SRC(idx) != ACLK || NRF_PDM_HAS_MCLKCONFIG, \
574629
"Clock source ACLK is not available."); \
575630
BUILD_ASSERT(PDM_CLK_SRC(idx) != ACLK || \
@@ -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

0 commit comments

Comments
 (0)