Browse Source

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 <michal.stasiak@nordicsemi.no>
pull/80057/head
Michał Stasiak 10 months ago committed by Anas Nashif
parent
commit
f8466b4791
  1. 2
      drivers/audio/Kconfig.dmic_pdm_nrfx
  2. 96
      drivers/audio/dmic_nrfx_pdm.c
  3. 2
      modules/hal_nordic/nrfx/nrfx_config_common.h

2
drivers/audio/Kconfig.dmic_pdm_nrfx

@ -6,6 +6,8 @@ config AUDIO_DMIC_NRFX_PDM @@ -6,6 +6,8 @@ config AUDIO_DMIC_NRFX_PDM
default y
depends on DT_HAS_NORDIC_NRF_PDM_ENABLED
select NRFX_PDM0 if HAS_HW_NRF_PDM0
select NRFX_PDM20 if HAS_HW_NRF_PDM20
select NRFX_PDM21 if HAS_HW_NRF_PDM21
select PINCTRL
help
Enable support for nrfx PDM driver for nRF MCU series.

96
drivers/audio/dmic_nrfx_pdm.c

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
LOG_MODULE_REGISTER(dmic_nrfx_pdm, CONFIG_AUDIO_DMIC_LOG_LEVEL);
struct dmic_nrfx_pdm_drv_data {
const nrfx_pdm_t *pdm;
struct onoff_manager *clk_mgr;
struct onoff_client clk_cli;
struct k_mem_slab *mem_slab;
@ -58,8 +59,7 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt) @@ -58,8 +59,7 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt)
LOG_ERR("Failed to allocate buffer: %d", ret);
stop = true;
} else {
err = nrfx_pdm_buffer_set(buffer,
drv_data->block_size / 2);
err = nrfx_pdm_buffer_set(drv_data->pdm, buffer, drv_data->block_size / 2);
if (err != NRFX_SUCCESS) {
LOG_ERR("Failed to set buffer: 0x%08x", err);
stop = true;
@ -94,10 +94,15 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt) @@ -94,10 +94,15 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt)
if (stop) {
drv_data->stopping = true;
nrfx_pdm_stop();
nrfx_pdm_stop(drv_data->pdm);
}
}
static bool is_in_freq_range(uint32_t freq, const struct dmic_cfg *pdm_cfg)
{
return freq >= pdm_cfg->io.min_pdm_clk_freq && freq <= pdm_cfg->io.max_pdm_clk_freq;
}
static bool is_better(uint32_t freq,
uint8_t ratio,
uint32_t req_rate,
@ -132,6 +137,37 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg, @@ -132,6 +137,37 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
uint32_t req_rate = pdm_cfg->streams[0].pcm_rate;
bool better_found = false;
#if NRF_PDM_HAS_PRESCALER
uint32_t src_freq = 32 * 1000 * 1000UL;
uint32_t req_freq = req_rate * ratio;
uint32_t prescaler = src_freq / req_freq;
uint32_t act_freq = src_freq / prescaler;
if (is_in_freq_range(act_freq, pdm_cfg) &&
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
config->prescaler = prescaler;
better_found = true;
}
/* Stop if an exact rate match is found. */
if (*best_diff == 0) {
return true;
}
/* Prescaler value is rounded down by default,
* thus value rounded up should be checked as well.
*/
prescaler += 1;
act_freq = src_freq / prescaler;
if (is_in_freq_range(act_freq, pdm_cfg) &&
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
config->prescaler = prescaler;
better_found = true;
}
#else
if (IS_ENABLED(CONFIG_SOC_SERIES_NRF53X)) {
const uint32_t src_freq =
(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, @@ -158,10 +194,8 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
(src_freq + req_freq / 2));
uint32_t act_freq = src_freq / (1048576 / clk_factor);
if (act_freq >= pdm_cfg->io.min_pdm_clk_freq &&
act_freq <= pdm_cfg->io.max_pdm_clk_freq &&
is_better(act_freq, ratio, req_rate,
best_diff, best_rate, best_freq)) {
if (is_in_freq_range(act_freq, pdm_cfg) &&
is_better(act_freq, ratio, req_rate, best_diff, best_rate, best_freq)) {
config->clock_freq = clk_factor * 4096;
better_found = true;
@ -216,6 +250,7 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg, @@ -216,6 +250,7 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
}
}
}
#endif /* NRF_PDM_HAS_PRESCALER */
return better_found;
}
@ -236,8 +271,26 @@ static bool find_suitable_clock(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg, @@ -236,8 +271,26 @@ static bool find_suitable_clock(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
uint8_t ratio_val;
nrf_pdm_ratio_t ratio_enum;
} ratios[] = {
{ 64, NRF_PDM_RATIO_64X },
{ 80, NRF_PDM_RATIO_80X }
#if defined(PDM_RATIO_RATIO_Ratio32)
{ 32, NRF_PDM_RATIO_32X },
#endif
#if defined(PDM_RATIO_RATIO_Ratio48)
{ 48, NRF_PDM_RATIO_48X },
#endif
#if defined(PDM_RATIO_RATIO_Ratio50)
{ 50, NRF_PDM_RATIO_50X },
#endif
{ 64, NRF_PDM_RATIO_64X },
{ 80, NRF_PDM_RATIO_80X },
#if defined(PDM_RATIO_RATIO_Ratio96)
{ 96, NRF_PDM_RATIO_96X },
#endif
#if defined(PDM_RATIO_RATIO_Ratio100)
{ 100, NRF_PDM_RATIO_100X },
#endif
#if defined(PDM_RATIO_RATIO_Ratio128)
{ 128, NRF_PDM_RATIO_128X }
#endif
};
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, @@ -327,7 +380,7 @@ static int dmic_nrfx_pdm_configure(const struct device *dev,
/* If either rate or width is 0, the stream is to be disabled. */
if (stream->pcm_rate == 0 || stream->pcm_width == 0) {
if (drv_data->configured) {
nrfx_pdm_uninit();
nrfx_pdm_uninit(drv_data->pdm);
drv_data->configured = false;
}
@ -357,11 +410,11 @@ static int dmic_nrfx_pdm_configure(const struct device *dev, @@ -357,11 +410,11 @@ static int dmic_nrfx_pdm_configure(const struct device *dev,
}
if (drv_data->configured) {
nrfx_pdm_uninit();
nrfx_pdm_uninit(drv_data->pdm);
drv_data->configured = false;
}
err = nrfx_pdm_init(&nrfx_cfg, drv_cfg->event_handler);
err = nrfx_pdm_init(drv_data->pdm, &nrfx_cfg, drv_cfg->event_handler);
if (err != NRFX_SUCCESS) {
LOG_ERR("Failed to initialize PDM: 0x%08x", err);
return -EIO;
@ -385,7 +438,7 @@ static int start_transfer(struct dmic_nrfx_pdm_drv_data *drv_data) @@ -385,7 +438,7 @@ static int start_transfer(struct dmic_nrfx_pdm_drv_data *drv_data)
nrfx_err_t err;
int ret;
err = nrfx_pdm_start();
err = nrfx_pdm_start(drv_data->pdm);
if (err == NRFX_SUCCESS) {
return 0;
}
@ -460,7 +513,7 @@ static int dmic_nrfx_pdm_trigger(const struct device *dev, @@ -460,7 +513,7 @@ static int dmic_nrfx_pdm_trigger(const struct device *dev,
case DMIC_TRIGGER_STOP:
if (drv_data->active) {
drv_data->stopping = true;
nrfx_pdm_stop();
nrfx_pdm_stop(drv_data->pdm);
}
break;
@ -541,16 +594,18 @@ static const struct _dmic_ops dmic_ops = { @@ -541,16 +594,18 @@ static const struct _dmic_ops dmic_ops = {
#define PDM_NRFX_DEVICE(idx) \
static void *rx_msgs##idx[DT_PROP(PDM(idx), queue_size)]; \
static struct dmic_nrfx_pdm_drv_data dmic_nrfx_pdm_data##idx; \
static const nrfx_pdm_t dmic_nrfx_pdm##idx = NRFX_PDM_INSTANCE(idx); \
static int pdm_nrfx_init##idx(const struct device *dev) \
{ \
IRQ_CONNECT(DT_IRQN(PDM(idx)), DT_IRQ(PDM(idx), priority), \
nrfx_isr, nrfx_pdm_irq_handler, 0); \
nrfx_isr, nrfx_pdm_##idx##_irq_handler, 0); \
const struct dmic_nrfx_pdm_drv_cfg *drv_cfg = dev->config; \
int err = pinctrl_apply_state(drv_cfg->pcfg, \
PINCTRL_STATE_DEFAULT); \
if (err < 0) { \
return err; \
} \
dmic_nrfx_pdm_data##idx.pdm = &dmic_nrfx_pdm##idx; \
k_msgq_init(&dmic_nrfx_pdm_data##idx.rx_queue, \
(char *)rx_msgs##idx, sizeof(void *), \
ARRAY_SIZE(rx_msgs##idx)); \
@ -582,5 +637,14 @@ static const struct _dmic_ops dmic_ops = { @@ -582,5 +637,14 @@ static const struct _dmic_ops dmic_ops = {
POST_KERNEL, CONFIG_AUDIO_DMIC_INIT_PRIORITY, \
&dmic_ops);
/* Existing SoCs only have one PDM instance. */
#ifdef CONFIG_HAS_HW_NRF_PDM0
PDM_NRFX_DEVICE(0);
#endif
#ifdef CONFIG_HAS_HW_NRF_PDM20
PDM_NRFX_DEVICE(20);
#endif
#ifdef CONFIG_HAS_HW_NRF_PDM21
PDM_NRFX_DEVICE(21);
#endif

2
modules/hal_nordic/nrfx/nrfx_config_common.h

@ -18,7 +18,7 @@ @@ -18,7 +18,7 @@
/** @brief Symbol specifying minor version of the nrfx API to be used. */
#ifndef NRFX_CONFIG_API_VER_MINOR
#define NRFX_CONFIG_API_VER_MINOR 6
#define NRFX_CONFIG_API_VER_MINOR 7
#endif
/** @brief Symbol specifying micro version of the nrfx API to be used. */

Loading…
Cancel
Save