Skip to content

Commit

Permalink
drivers: audio: dmic_nrfx: Add DMM support to driver
Browse files Browse the repository at this point in the history
Added support for DMM in PDM drivers in order to use it
with nRF54H20.

Signed-off-by: Michał Stasiak <[email protected]>
  • Loading branch information
mstasiaknordic committed Dec 2, 2024
1 parent 3d6dbcc commit 8214c09
Showing 1 changed file with 56 additions and 14 deletions.
70 changes: 56 additions & 14 deletions drivers/audio/dmic_nrfx_pdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,25 @@
#include <zephyr/drivers/clock_control/nrf_clock_control.h>
#include <zephyr/drivers/pinctrl.h>
#include <soc.h>
#include <dmm.h>
#include <nrfx_pdm.h>

#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
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;
Expand All @@ -36,29 +44,44 @@ 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;

if (evt->buffer_requested) {
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);
Expand All @@ -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) {
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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
Expand All @@ -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:
*
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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) \
Expand All @@ -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."); \
Expand Down

0 comments on commit 8214c09

Please sign in to comment.