diff --git a/drivers/audio/dmic_nrfx_pdm.c b/drivers/audio/dmic_nrfx_pdm.c index 4ffd00f49099e5..b7ea336b9f9d67 100644 --- a/drivers/audio/dmic_nrfx_pdm.c +++ b/drivers/audio/dmic_nrfx_pdm.c @@ -8,17 +8,25 @@ #include #include #include +#include #include #include #include LOG_MODULE_REGISTER(dmic_nrfx_pdm, CONFIG_AUDIO_DMIC_LOG_LEVEL); +#if CONFIG_SOC_SERIES_NRF54HX +#define DMIC_NRFX_CLOCK_FREQ 8*1000*1000UL +#else +#define DMIC_NRFX_CLOCK_FREQ 32*1000*1000UL +#endif + 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; + void *mem_slab_buffer; uint32_t block_size; struct k_msgq rx_queue; bool request_clock : 1; @@ -36,17 +44,25 @@ struct dmic_nrfx_pdm_drv_cfg { PCLK32M_HFXO, ACLK } clk_src; + void *mem_reg; }; -static void free_buffer(struct dmic_nrfx_pdm_drv_data *drv_data, void *buffer) +static void free_buffer(struct dmic_nrfx_pdm_drv_data *drv_data) +{ + k_mem_slab_free(drv_data->mem_slab, drv_data->mem_slab_buffer); + LOG_DBG("Freed buffer %p", drv_data->mem_slab_buffer); +} + +static void stop_pdm(struct dmic_nrfx_pdm_drv_data *drv_data) { - k_mem_slab_free(drv_data->mem_slab, buffer); - LOG_DBG("Freed buffer %p", buffer); + drv_data->stopping = true; + nrfx_pdm_stop(drv_data->pdm); } static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt) { struct dmic_nrfx_pdm_drv_data *drv_data = dev->data; + const struct dmic_nrfx_pdm_drv_cfg *drv_cfg = dev->config; int ret; bool stop = false; @@ -54,11 +70,18 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt) void *buffer; nrfx_err_t err; - ret = k_mem_slab_alloc(drv_data->mem_slab, &buffer, K_NO_WAIT); + ret = k_mem_slab_alloc(drv_data->mem_slab, &drv_data->mem_slab_buffer, K_NO_WAIT); if (ret < 0) { LOG_ERR("Failed to allocate buffer: %d", ret); stop = true; } else { + ret = dmm_buffer_in_prepare(drv_cfg->mem_reg, drv_data->mem_slab_buffer, + drv_data->block_size, &buffer); + if (ret < 0) { + LOG_ERR("Failed to prepare buffer: %d", ret); + stop_pdm(drv_data); + return; + } 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); @@ -69,7 +92,14 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt) if (drv_data->stopping) { if (evt->buffer_released) { - free_buffer(drv_data, evt->buffer_released); + ret = dmm_buffer_in_release(drv_cfg->mem_reg, drv_data->mem_slab_buffer, + drv_data->block_size, evt->buffer_released); + if (ret < 0) { + LOG_ERR("Failed to release buffer: %d", ret); + stop_pdm(drv_data); + return; + } + free_buffer(drv_data); } if (drv_data->active) { @@ -79,22 +109,26 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt) } } } else if (evt->buffer_released) { + ret = dmm_buffer_in_release(drv_cfg->mem_reg, drv_data->mem_slab_buffer, + drv_data->block_size, evt->buffer_released); + if (ret < 0) { + LOG_ERR("Failed to release buffer: %d", ret); + stop_pdm(drv_data); + return; + } ret = k_msgq_put(&drv_data->rx_queue, - &evt->buffer_released, + &drv_data->mem_slab_buffer, K_NO_WAIT); if (ret < 0) { LOG_ERR("No room in RX queue"); stop = true; - - free_buffer(drv_data, evt->buffer_released); + free_buffer(drv_data); } else { LOG_DBG("Queued buffer %p", evt->buffer_released); } } - if (stop) { - drv_data->stopping = true; - nrfx_pdm_stop(drv_data->pdm); + stop_pdm(drv_data); } } @@ -168,7 +202,7 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg, better_found = true; } #else - if (IS_ENABLED(CONFIG_SOC_SERIES_NRF53X)) { + if (IS_ENABLED(CONFIG_SOC_SERIES_NRF53X) || IS_ENABLED(CONFIG_SOC_SERIES_NRF54HX)) { const uint32_t src_freq = (NRF_PDM_HAS_MCLKCONFIG && drv_cfg->clk_src == ACLK) /* The DMIC_NRFX_PDM_DEVICE() macro contains build @@ -180,9 +214,13 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg, * not defined (this expression will be eventually * optimized away then). */ + /* TODO : PS does not provide correct formula for nRF54H20 PDM_CLK. + * Assume that master clock source frequency is 8 MHz. Remove once + * correct formula is found. + */ ? DT_PROP_OR(DT_NODELABEL(clock), hfclkaudio_frequency, 0) - : 32*1000*1000UL; + : DMIC_NRFX_CLOCK_FREQ; uint32_t req_freq = req_rate * ratio; /* As specified in the nRF5340 PS: * @@ -562,6 +600,7 @@ static int dmic_nrfx_pdm_read(const struct device *dev, return ret; } +#if CONFIG_CLOCK_CONTROL_NRF static void init_clock_manager(const struct device *dev) { struct dmic_nrfx_pdm_drv_data *drv_data = dev->data; @@ -581,6 +620,7 @@ static void init_clock_manager(const struct device *dev) drv_data->clk_mgr = z_nrf_clock_control_get_onoff(subsys); __ASSERT_NO_MSG(drv_data->clk_mgr != NULL); } +#endif static const struct _dmic_ops dmic_ops = { .configure = dmic_nrfx_pdm_configure, @@ -609,7 +649,8 @@ static const struct _dmic_ops dmic_ops = { k_msgq_init(&dmic_nrfx_pdm_data##idx.rx_queue, \ (char *)rx_msgs##idx, sizeof(void *), \ ARRAY_SIZE(rx_msgs##idx)); \ - init_clock_manager(dev); \ + IF_ENABLED(CONFIG_CLOCK_CONTROL_NRF, \ + (init_clock_manager(dev);)) \ return 0; \ } \ static void event_handler##idx(const nrfx_pdm_evt_t *evt) \ @@ -624,6 +665,7 @@ static const struct _dmic_ops dmic_ops = { .nrfx_def_cfg.skip_psel_cfg = true, \ .pcfg = PINCTRL_DT_DEV_CONFIG_GET(PDM(idx)), \ .clk_src = PDM_CLK_SRC(idx), \ + .mem_reg = DMM_DEV_TO_REG(PDM(idx)), \ }; \ BUILD_ASSERT(PDM_CLK_SRC(idx) != ACLK || NRF_PDM_HAS_MCLKCONFIG, \ "Clock source ACLK is not available."); \