diff --git a/drivers/audio/Kconfig.dmic_pdm_nrfx b/drivers/audio/Kconfig.dmic_pdm_nrfx index dfbda8259f2..51a56bebb54 100644 --- a/drivers/audio/Kconfig.dmic_pdm_nrfx +++ b/drivers/audio/Kconfig.dmic_pdm_nrfx @@ -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. diff --git a/drivers/audio/dmic_nrfx_pdm.c b/drivers/audio/dmic_nrfx_pdm.c index c663aa177b2..971fd902665 100644 --- a/drivers/audio/dmic_nrfx_pdm.c +++ b/drivers/audio/dmic_nrfx_pdm.c @@ -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) 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) 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, 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, (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, } } } +#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, 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, /* 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, } 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) 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, 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 = { #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 = { 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 diff --git a/modules/hal_nordic/nrfx/Kconfig b/modules/hal_nordic/nrfx/Kconfig index e7df6d3b389..9718d25aee9 100644 --- a/modules/hal_nordic/nrfx/Kconfig +++ b/modules/hal_nordic/nrfx/Kconfig @@ -173,6 +173,16 @@ config NRFX_PDM0 depends on $(dt_nodelabel_has_compat,pdm0,$(DT_COMPAT_NORDIC_NRF_PDM)) select NRFX_PDM +config NRFX_PDM20 + bool "PDM20 driver instance" + depends on $(dt_nodelabel_has_compat,pdm20,$(DT_COMPAT_NORDIC_NRF_PDM)) + select NRFX_PDM + +config NRFX_PDM21 + bool "PDM21 driver instance" + depends on $(dt_nodelabel_has_compat,pdm21,$(DT_COMPAT_NORDIC_NRF_PDM)) + select NRFX_PDM + config NRFX_POWER bool "POWER driver" depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_POWER)) diff --git a/modules/hal_nordic/nrfx/nrfx_config.h b/modules/hal_nordic/nrfx/nrfx_config.h index a7632a8cc43..c7a7f169c01 100644 --- a/modules/hal_nordic/nrfx/nrfx_config.h +++ b/modules/hal_nordic/nrfx/nrfx_config.h @@ -209,11 +209,17 @@ #ifdef CONFIG_NRFX_PDM #define NRFX_PDM_ENABLED 1 #endif +#ifdef CONFIG_NRFX_PDM_LOG +#define NRFX_PDM_CONFIG_LOG_ENABLED 1 +#endif #ifdef CONFIG_NRFX_PDM0 #define NRFX_PDM0_ENABLED 1 #endif -#ifdef CONFIG_NRFX_PDM_LOG -#define NRFX_PDM_CONFIG_LOG_ENABLED 1 +#ifdef CONFIG_NRFX_PDM20 +#define NRFX_PDM20_ENABLED 1 +#endif +#ifdef CONFIG_NRFX_PDM21 +#define NRFX_PDM21_ENABLED 1 #endif #ifdef CONFIG_NRFX_POWER diff --git a/modules/hal_nordic/nrfx/nrfx_config_common.h b/modules/hal_nordic/nrfx/nrfx_config_common.h index f156c21777f..e04a11c6df8 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_common.h +++ b/modules/hal_nordic/nrfx/nrfx_config_common.h @@ -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. */ diff --git a/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h b/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h index a5dbcaa3db8..ab04db03f15 100644 --- a/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h +++ b/modules/hal_nordic/nrfx/nrfx_config_nrf5340_application.h @@ -596,6 +596,15 @@ #define NRFX_PDM_CONFIG_LOG_LEVEL 3 #endif +/** + * @brief NRFX_PDM0_ENABLED + * + * Boolean. Accepted values 0 and 1. + */ +#ifndef NRFX_PDM0_ENABLED +#define NRFX_PDM0_ENABLED 0 +#endif + /** * @brief NRFX_POWER_ENABLED * diff --git a/samples/drivers/audio/dmic/boards/nrf54l15dk_nrf54l15_cpuapp.overlay b/samples/drivers/audio/dmic/boards/nrf54l15dk_nrf54l15_cpuapp.overlay new file mode 100644 index 00000000000..6131d6d7193 --- /dev/null +++ b/samples/drivers/audio/dmic/boards/nrf54l15dk_nrf54l15_cpuapp.overlay @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&pinctrl { + pdm20_default_alt: pdm20_default_alt { + group1 { + psels = , + ; + }; + }; +}; + +dmic_dev: &pdm20 { + status = "okay"; + pinctrl-0 = <&pdm20_default_alt>; + pinctrl-names = "default"; + clock-source = "PCLK32M"; +}; diff --git a/samples/drivers/audio/dmic/sample.yaml b/samples/drivers/audio/dmic/sample.yaml index 8cc5464b781..3f8dc0b1610 100644 --- a/samples/drivers/audio/dmic/sample.yaml +++ b/samples/drivers/audio/dmic/sample.yaml @@ -7,6 +7,7 @@ tests: integration_platforms: - nrf52840dk/nrf52840 - nrf5340dk/nrf5340/cpuapp + - nrf54l15dk/nrf54l15/cpuapp harness: console harness_config: type: multi_line diff --git a/soc/nordic/common/Kconfig.peripherals b/soc/nordic/common/Kconfig.peripherals index 09e962283bc..9ea6ebc45c5 100644 --- a/soc/nordic/common/Kconfig.peripherals +++ b/soc/nordic/common/Kconfig.peripherals @@ -131,6 +131,12 @@ config HAS_HW_NRF_OSCILLATORS config HAS_HW_NRF_PDM0 def_bool $(dt_nodelabel_enabled_with_compat,pdm0,$(DT_COMPAT_NORDIC_NRF_PDM)) +config HAS_HW_NRF_PDM20 + def_bool $(dt_nodelabel_enabled_with_compat,pdm20,$(DT_COMPAT_NORDIC_NRF_PDM)) + +config HAS_HW_NRF_PDM21 + def_bool $(dt_nodelabel_enabled_with_compat,pdm21,$(DT_COMPAT_NORDIC_NRF_PDM)) + config HAS_HW_NRF_POWER def_bool $(dt_compat_enabled,$(DT_COMPAT_NORDIC_NRF_POWER)) diff --git a/soc/nordic/validate_base_addresses.c b/soc/nordic/validate_base_addresses.c index 84d773159bc..07ae94a233b 100644 --- a/soc/nordic/validate_base_addresses.c +++ b/soc/nordic/validate_base_addresses.c @@ -222,6 +222,8 @@ CHECK_DT_REG(nfct, NRF_NFCT); CHECK_DT_REG(nrf_mpu, NRF_MPU); CHECK_DT_REG(oscillators, NRF_OSCILLATORS); CHECK_DT_REG(pdm0, NRF_PDM0); +CHECK_DT_REG(pdm20, NRF_PDM20); +CHECK_DT_REG(pdm21, NRF_PDM21); CHECK_DT_REG(power, NRF_POWER); CHECK_DT_REG(ppi, NRF_PPI); CHECK_DT_REG(pwm0, NRF_PWM0);