Skip to content

Commit 16b9f60

Browse files
mstasiaknordickartben
authored andcommitted
drivers: audio: dmic_nrfx: add support for audio clocks on nRF54
Added support for audio clock for nRF54L20 and AudioPLL for nRF54H20 in DMIC PDM driver. Signed-off-by: Michał Stasiak <michal.stasiak@nordicsemi.no>
1 parent 894cbed commit 16b9f60

File tree

1 file changed

+77
-37
lines changed

1 file changed

+77
-37
lines changed

drivers/audio/dmic_nrfx_pdm.c

Lines changed: 77 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,21 @@ LOG_MODULE_REGISTER(dmic_nrfx_pdm, CONFIG_AUDIO_DMIC_LOG_LEVEL);
1818
#if CONFIG_SOC_SERIES_NRF54HX
1919
#define DMIC_NRFX_CLOCK_FREQ MHZ(16)
2020
#define DMIC_NRFX_CLOCK_FACTOR 8192
21+
#define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP_OR(DT_NODELABEL(audiopll), frequency, 0)
2122
#else
2223
#define DMIC_NRFX_CLOCK_FREQ MHZ(32)
2324
#define DMIC_NRFX_CLOCK_FACTOR 4096
25+
#define DMIC_NRFX_AUDIO_CLOCK_FREQ DT_PROP_OR(DT_NODELABEL(aclk), clock_frequency, \
26+
DT_PROP_OR(DT_NODELABEL(clock), hfclkaudio_frequency, 0))
2427
#endif
2528

2629
struct dmic_nrfx_pdm_drv_data {
2730
const nrfx_pdm_t *pdm;
31+
#if CONFIG_CLOCK_CONTROL_NRF
2832
struct onoff_manager *clk_mgr;
33+
#elif CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL
34+
const struct device *audiopll_dev;
35+
#endif
2936
struct onoff_client clk_cli;
3037
struct k_mem_slab *mem_slab;
3138
uint32_t block_size;
@@ -61,6 +68,35 @@ static void stop_pdm(struct dmic_nrfx_pdm_drv_data *drv_data)
6168
nrfx_pdm_stop(drv_data->pdm);
6269
}
6370

71+
static int request_clock(struct dmic_nrfx_pdm_drv_data *drv_data)
72+
{
73+
if (!drv_data->request_clock) {
74+
return 0;
75+
}
76+
#if CONFIG_CLOCK_CONTROL_NRF
77+
return onoff_request(drv_data->clk_mgr, &drv_data->clk_cli);
78+
#elif CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL
79+
return nrf_clock_control_request(drv_data->audiopll_dev, NULL, &drv_data->clk_cli);
80+
#else
81+
return -ENOTSUP;
82+
#endif
83+
}
84+
85+
static int release_clock(struct dmic_nrfx_pdm_drv_data *drv_data)
86+
{
87+
if (!drv_data->request_clock) {
88+
return 0;
89+
}
90+
91+
#if CONFIG_CLOCK_CONTROL_NRF
92+
return onoff_release(drv_data->clk_mgr);
93+
#elif CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL
94+
return nrf_clock_control_release(drv_data->audiopll_dev, NULL);
95+
#else
96+
return -ENOTSUP;
97+
#endif
98+
}
99+
64100
static void event_handler(const struct device *dev, const nrfx_pdm_evt_t *evt)
65101
{
66102
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)
119155

120156
if (drv_data->active) {
121157
drv_data->active = false;
122-
if (drv_data->request_clock) {
123-
(void)onoff_release(drv_data->clk_mgr);
158+
ret = release_clock(drv_data);
159+
if (ret < 0) {
160+
LOG_ERR("Failed to release clock: %d", ret);
161+
return;
124162
}
125163
}
126164
} else if (evt->buffer_released) {
@@ -191,9 +229,11 @@ static bool check_pdm_frequencies(const struct dmic_nrfx_pdm_drv_cfg *drv_cfg,
191229
{
192230
uint32_t req_rate = pdm_cfg->streams[0].pcm_rate;
193231
bool better_found = false;
194-
232+
const uint32_t src_freq =
233+
(NRF_PDM_HAS_SELECTABLE_CLOCK && drv_cfg->clk_src == ACLK)
234+
? DMIC_NRFX_AUDIO_CLOCK_FREQ
235+
: DMIC_NRFX_CLOCK_FREQ;
195236
#if NRF_PDM_HAS_PRESCALER
196-
uint32_t src_freq = 32 * 1000 * 1000UL;
197237
uint32_t req_freq = req_rate * ratio;
198238
uint32_t prescaler = src_freq / req_freq;
199239
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,
224264
}
225265
#else
226266
if (IS_ENABLED(CONFIG_SOC_SERIES_NRF53X) || IS_ENABLED(CONFIG_SOC_SERIES_NRF54HX)) {
227-
const uint32_t src_freq =
228-
(NRF_PDM_HAS_MCLKCONFIG && drv_cfg->clk_src == ACLK)
229-
/* The DMIC_NRFX_PDM_DEVICE() macro contains build
230-
* assertions that make sure that the ACLK clock
231-
* source is only used when it is available and only
232-
* with the "hfclkaudio-frequency" property defined,
233-
* but the default value of 0 here needs to be used
234-
* to prevent compilation errors when the property is
235-
* not defined (this expression will be eventually
236-
* optimized away then).
237-
*/
238-
/* TODO : PS does not provide correct formula for nRF54H20 PDM_CLK.
239-
* Assume that master clock source frequency is 8 MHz. Remove once
240-
* correct formula is found.
241-
*/
242-
? DT_PROP_OR(DT_NODELABEL(clock), hfclkaudio_frequency,
243-
0)
244-
: DMIC_NRFX_CLOCK_FREQ;
245267
uint32_t req_freq = req_rate * ratio;
246268
/* As specified in the nRF5340 PS:
247269
*
@@ -461,7 +483,7 @@ static int dmic_nrfx_pdm_configure(const struct device *dev,
461483
nrfx_cfg.edge = NRF_PDM_EDGE_LEFTRISING;
462484
channel->act_chan_map_lo = alt_map;
463485
}
464-
#if NRF_PDM_HAS_MCLKCONFIG
486+
#if NRF_PDM_HAS_SELECTABLE_CLOCK
465487
nrfx_cfg.mclksrc = drv_cfg->clk_src == ACLK
466488
? NRF_PDM_MCLKSRC_ACLK
467489
: NRF_PDM_MCLKSRC_PCLK32M;
@@ -489,8 +511,10 @@ static int dmic_nrfx_pdm_configure(const struct device *dev,
489511
* (which is always available without any additional actions),
490512
* it is required to request the proper clock to be running
491513
* before starting the transfer itself.
514+
* Targets using CLKSELECT register to select clock source
515+
* do not need to request audio clock.
492516
*/
493-
drv_data->request_clock = (drv_cfg->clk_src != PCLK32M);
517+
drv_data->request_clock = (drv_cfg->clk_src != PCLK32M && !NRF_PDM_HAS_CLKSELECT);
494518
drv_data->configured = true;
495519
return 0;
496520
}
@@ -508,8 +532,10 @@ static int start_transfer(struct dmic_nrfx_pdm_drv_data *drv_data)
508532
LOG_ERR("Failed to start PDM: 0x%08x", err);
509533
ret = -EIO;
510534

511-
if (drv_data->request_clock) {
512-
(void)onoff_release(drv_data->clk_mgr);
535+
ret = release_clock(drv_data);
536+
if (ret < 0) {
537+
LOG_ERR("Failed to release clock: %d", ret);
538+
return ret;
513539
}
514540

515541
drv_data->active = false;
@@ -529,7 +555,12 @@ static void clock_started_callback(struct onoff_manager *mgr,
529555
* the actual transfer in such case.
530556
*/
531557
if (!drv_data->active) {
532-
(void)onoff_release(drv_data->clk_mgr);
558+
int ret = release_clock(drv_data);
559+
560+
if (ret < 0) {
561+
LOG_ERR("Failed to release clock: %d", ret);
562+
return;
563+
}
533564
} else {
534565
(void)start_transfer(drv_data);
535566
}
@@ -548,7 +579,7 @@ static int trigger_start(const struct device *dev)
548579
if (drv_data->request_clock) {
549580
sys_notify_init_callback(&drv_data->clk_cli.notify,
550581
clock_started_callback);
551-
ret = onoff_request(drv_data->clk_mgr, &drv_data->clk_cli);
582+
ret = request_clock(drv_data);
552583
if (ret < 0) {
553584
drv_data->active = false;
554585

@@ -624,12 +655,11 @@ static int dmic_nrfx_pdm_read(const struct device *dev,
624655
return ret;
625656
}
626657

627-
#if CONFIG_CLOCK_CONTROL_NRF
628658
static void init_clock_manager(const struct device *dev)
629659
{
630-
struct dmic_nrfx_pdm_drv_data *drv_data = dev->data;
660+
#if CONFIG_CLOCK_CONTROL_NRF
631661
clock_control_subsys_t subsys;
632-
662+
struct dmic_nrfx_pdm_drv_data *drv_data = dev->data;
633663
#if NRF_CLOCK_HAS_HFCLKAUDIO
634664
const struct dmic_nrfx_pdm_drv_cfg *drv_cfg = dev->config;
635665

@@ -643,8 +673,12 @@ static void init_clock_manager(const struct device *dev)
643673

644674
drv_data->clk_mgr = z_nrf_clock_control_get_onoff(subsys);
645675
__ASSERT_NO_MSG(drv_data->clk_mgr != NULL);
646-
}
676+
#elif CONFIG_CLOCK_CONTROL_NRF2_AUDIOPLL
677+
struct dmic_nrfx_pdm_drv_data *drv_data = dev->data;
678+
679+
drv_data->audiopll_dev = DEVICE_DT_GET(DT_NODELABEL(audiopll));
647680
#endif
681+
}
648682

649683
static const struct _dmic_ops dmic_ops = {
650684
.configure = dmic_nrfx_pdm_configure,
@@ -677,8 +711,7 @@ static const struct _dmic_ops dmic_ops = {
677711
k_msgq_init(&dmic_nrfx_pdm_data##idx.mem_slab_queue, \
678712
(char *)mem_slab_msgs##idx, sizeof(void *), \
679713
ARRAY_SIZE(mem_slab_msgs##idx)); \
680-
IF_ENABLED(CONFIG_CLOCK_CONTROL_NRF, \
681-
(init_clock_manager(dev);)) \
714+
init_clock_manager(dev); \
682715
return 0; \
683716
} \
684717
static void event_handler##idx(const nrfx_pdm_evt_t *evt) \
@@ -695,13 +728,20 @@ static const struct _dmic_ops dmic_ops = {
695728
.clk_src = PDM_CLK_SRC(idx), \
696729
.mem_reg = DMM_DEV_TO_REG(PDM(idx)), \
697730
}; \
698-
BUILD_ASSERT(PDM_CLK_SRC(idx) != ACLK || NRF_PDM_HAS_MCLKCONFIG, \
731+
BUILD_ASSERT(PDM_CLK_SRC(idx) != ACLK || \
732+
NRF_PDM_HAS_SELECTABLE_CLOCK, \
699733
"Clock source ACLK is not available."); \
700734
BUILD_ASSERT(PDM_CLK_SRC(idx) != ACLK || \
701735
DT_NODE_HAS_PROP(DT_NODELABEL(clock), \
702-
hfclkaudio_frequency), \
736+
hfclkaudio_frequency) || \
737+
DT_NODE_HAS_PROP(DT_NODELABEL(aclk), \
738+
clock_frequency) || \
739+
DT_NODE_HAS_PROP(DT_NODELABEL(audiopll), \
740+
frequency), \
703741
"Clock source ACLK requires the hfclkaudio-frequency " \
704-
"property to be defined in the nordic,nrf-clock node."); \
742+
"property to be defined in the nordic,nrf-clock node " \
743+
"or clock-frequency property to be defined in aclk node" \
744+
"or frequency property to be defined in audiopll node"); \
705745
DEVICE_DT_DEFINE(PDM(idx), pdm_nrfx_init##idx, NULL, \
706746
&dmic_nrfx_pdm_data##idx, &dmic_nrfx_pdm_cfg##idx, \
707747
POST_KERNEL, CONFIG_AUDIO_DMIC_INIT_PRIORITY, \

0 commit comments

Comments
 (0)