diff --git a/drivers/audio/dmic_nrfx_pdm.c b/drivers/audio/dmic_nrfx_pdm.c index ea78330deb5..2e8d71b0a93 100644 --- a/drivers/audio/dmic_nrfx_pdm.c +++ b/drivers/audio/dmic_nrfx_pdm.c @@ -18,14 +18,21 @@ LOG_MODULE_REGISTER(dmic_nrfx_pdm, CONFIG_AUDIO_DMIC_LOG_LEVEL); #if CONFIG_SOC_SERIES_NRF54HX #define DMIC_NRFX_CLOCK_FREQ MHZ(16) #define DMIC_NRFX_CLOCK_FACTOR 8192 +#define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP_OR(DT_NODELABEL(audiopll), frequency, 0) #else #define DMIC_NRFX_CLOCK_FREQ MHZ(32) #define DMIC_NRFX_CLOCK_FACTOR 4096 +#define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP_OR(DT_NODELABEL(aclk), clock_frequency, \ + DT_PROP_OR(DT_NODELABEL(clock), hfclkaudio_frequency, 0)) #endif struct dmic_nrfx_pdm_drv_data { const nrfx_pdm_t *pdm; +#if CONFIG_CLOCK_CONTROL_NRF struct onoff_manager *clk_mgr; +#elif CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL + const struct device *audiopll_dev; +#endif struct onoff_client clk_cli; struct k_mem_slab *mem_slab; uint32_t block_size; @@ -61,6 +68,35 @@ static void stop_pdm(struct dmic_nrfx_pdm_drv_data *drv_data) nrfx_pdm_stop(drv_data->pdm); } +static int request_clock(struct dmic_nrfx_pdm_drv_data *drv_data) +{ + if (!drv_data->request_clock) { + return 0; + } +#if CONFIG_CLOCK_CONTROL_NRF + return onoff_request(drv_data->clk_mgr, &drv_data->clk_cli); +#elif CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL + return nrf_clock_control_request(drv_data->audiopll_dev, NULL, &drv_data->clk_cli); +#else + return -ENOTSUP; +#endif +} + +static int release_clock(struct dmic_nrfx_pdm_drv_data *drv_data) +{ + if (!drv_data->request_clock) { + return 0; + } + +#if CONFIG_CLOCK_CONTROL_NRF + return onoff_release(drv_data->clk_mgr); +#elif CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL + return nrf_clock_control_release(drv_data->audiopll_dev, NULL); +#else + return -ENOTSUP; +#endif +} + static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt) { struct dmic_nrfx_pdm_drv_data *drv_data = dev->data; @@ -119,8 +155,10 @@ static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt) if (drv_data->active) { drv_data->active = false; - if (drv_data->request_clock) { - (void)onoff_release(drv_data->clk_mgr); + ret = release_clock(drv_data); + if (ret < 0) { + LOG_ERR("Failed to release clock: %d", ret); + return; } } } else if (evt->buffer_released) { @@ -191,9 +229,11 @@ 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; - + const uint32_t src_freq = + (NRF_PDM_HAS_SELECTABLE_CLOCK && drv_cfg->clk_src == ACLK) + ? DMIC_NRFX_AUDIO_CLOCK_FREQ + : DMIC_NRFX_CLOCK_FREQ; #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; @@ -224,24 +264,6 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg, } #else 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 - * assertions that make sure that the ACLK clock - * source is only used when it is available and only - * with the "hfclkaudio-frequency" property defined, - * but the default value of 0 here needs to be used - * to prevent compilation errors when the property is - * 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) - : DMIC_NRFX_CLOCK_FREQ; uint32_t req_freq = req_rate * ratio; /* As specified in the nRF5340 PS: * @@ -461,7 +483,7 @@ static int dmic_nrfx_pdm_configure(const struct device *dev, nrfx_cfg.edge = NRF_PDM_EDGE_LEFTRISING; channel->act_chan_map_lo = alt_map; } -#if NRF_PDM_HAS_MCLKCONFIG +#if NRF_PDM_HAS_SELECTABLE_CLOCK nrfx_cfg.mclksrc = drv_cfg->clk_src == ACLK ? NRF_PDM_MCLKSRC_ACLK : NRF_PDM_MCLKSRC_PCLK32M; @@ -489,8 +511,10 @@ static int dmic_nrfx_pdm_configure(const struct device *dev, * (which is always available without any additional actions), * it is required to request the proper clock to be running * before starting the transfer itself. + * Targets using CLKSELECT register to select clock source + * do not need to request audio clock. */ - drv_data->request_clock = (drv_cfg->clk_src != PCLK32M); + drv_data->request_clock = (drv_cfg->clk_src != PCLK32M && !NRF_PDM_HAS_CLKSELECT); drv_data->configured = true; return 0; } @@ -508,8 +532,10 @@ static int start_transfer(struct dmic_nrfx_pdm_drv_data *drv_data) LOG_ERR("Failed to start PDM: 0x%08x", err); ret = -EIO; - if (drv_data->request_clock) { - (void)onoff_release(drv_data->clk_mgr); + ret = release_clock(drv_data); + if (ret < 0) { + LOG_ERR("Failed to release clock: %d", ret); + return ret; } drv_data->active = false; @@ -529,7 +555,12 @@ static void clock_started_callback(struct onoff_manager *mgr, * the actual transfer in such case. */ if (!drv_data->active) { - (void)onoff_release(drv_data->clk_mgr); + int ret = release_clock(drv_data); + + if (ret < 0) { + LOG_ERR("Failed to release clock: %d", ret); + return; + } } else { (void)start_transfer(drv_data); } @@ -548,7 +579,7 @@ static int trigger_start(const struct device *dev) if (drv_data->request_clock) { sys_notify_init_callback(&drv_data->clk_cli.notify, clock_started_callback); - ret = onoff_request(drv_data->clk_mgr, &drv_data->clk_cli); + ret = request_clock(drv_data); if (ret < 0) { drv_data->active = false; @@ -624,12 +655,11 @@ 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; +#if CONFIG_CLOCK_CONTROL_NRF clock_control_subsys_t subsys; - + struct dmic_nrfx_pdm_drv_data *drv_data = dev->data; #if NRF_CLOCK_HAS_HFCLKAUDIO const struct dmic_nrfx_pdm_drv_cfg *drv_cfg = dev->config; @@ -643,8 +673,12 @@ 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); -} +#elif CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL + struct dmic_nrfx_pdm_drv_data *drv_data = dev->data; + + drv_data->audiopll_dev = DEVICE_DT_GET(DT_NODELABEL(audiopll)); #endif +} static const struct _dmic_ops dmic_ops = { .configure = dmic_nrfx_pdm_configure, @@ -677,8 +711,7 @@ static const struct _dmic_ops dmic_ops = { k_msgq_init(&dmic_nrfx_pdm_data##idx.mem_slab_queue, \ (char *)mem_slab_msgs##idx, sizeof(void *), \ ARRAY_SIZE(mem_slab_msgs##idx)); \ - IF_ENABLED(CONFIG_CLOCK_CONTROL_NRF, \ - (init_clock_manager(dev);)) \ + init_clock_manager(dev); \ return 0; \ } \ static void event_handler##idx(const nrfx_pdm_evt_t *evt) \ @@ -695,13 +728,20 @@ static const struct _dmic_ops dmic_ops = { .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, \ + BUILD_ASSERT(PDM_CLK_SRC(idx) != ACLK || \ + NRF_PDM_HAS_SELECTABLE_CLOCK, \ "Clock source ACLK is not available."); \ BUILD_ASSERT(PDM_CLK_SRC(idx) != ACLK || \ DT_NODE_HAS_PROP(DT_NODELABEL(clock), \ - hfclkaudio_frequency), \ + hfclkaudio_frequency) || \ + DT_NODE_HAS_PROP(DT_NODELABEL(aclk), \ + clock_frequency) || \ + DT_NODE_HAS_PROP(DT_NODELABEL(audiopll), \ + frequency), \ "Clock source ACLK requires the hfclkaudio-frequency " \ - "property to be defined in the nordic,nrf-clock node."); \ + "property to be defined in the nordic,nrf-clock node " \ + "or clock-frequency property to be defined in aclk node" \ + "or frequency property to be defined in audiopll node"); \ DEVICE_DT_DEFINE(PDM(idx), pdm_nrfx_init##idx, NULL, \ &dmic_nrfx_pdm_data##idx, &dmic_nrfx_pdm_cfg##idx, \ POST_KERNEL, CONFIG_AUDIO_DMIC_INIT_PRIORITY, \