Skip to content

[nrf fromlist] drivers: audio: dmic_nrfx: allow use of ACLK for nRF54L20 #2623

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 76 additions & 36 deletions drivers/audio/dmic_nrfx_pdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,23 @@ 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 \
COND_CODE_1(CONFIG_SOC_NRF54L20, \
(DT_PROP_OR(DT_NODELABEL(aclk), clock_frequency, 0)), \
(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;
Expand Down Expand Up @@ -61,6 +70,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 0;
#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 0;
#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;
Expand Down Expand Up @@ -119,8 +157,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) {
Expand Down Expand Up @@ -191,9 +231,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;
Expand Down Expand Up @@ -224,24 +266,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:
*
Expand Down Expand Up @@ -461,7 +485,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;
Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand All @@ -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,
Expand Down Expand Up @@ -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) \
Expand All @@ -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, \
Expand Down
14 changes: 14 additions & 0 deletions dts/bindings/clock/nordic,nrf-aclk.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright (c) 2025 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0

description: Nordic Audio clock node

compatible: "nordic,nrf-aclk"

include: fixed-clock.yaml

properties:
clock-frequency:
type: int
description: |
Frequency of the Audio clock in Hz.
6 changes: 6 additions & 0 deletions dts/common/nordic/nrf54l20.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@
#clock-cells = <0>;
clock-frequency = <DT_FREQ_M(128)>;
};

aclk: aclk {
compatible = "nordic,nrf-aclk";
#clock-cells = <0>;
clock-frequency = <DT_FREQ_M(24)>;
};
};

soc {
Expand Down