Skip to content
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
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

Check notice on line 22 in drivers/audio/dmic_nrfx_pdm.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/audio/dmic_nrfx_pdm.c:22 -#define DMIC_NRFX_CLOCK_FREQ 8*1000*1000UL +#define DMIC_NRFX_CLOCK_FREQ 8 * 1000 * 1000UL #else -#define DMIC_NRFX_CLOCK_FREQ 32*1000*1000UL +#define DMIC_NRFX_CLOCK_FREQ 32 * 1000 * 1000UL

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 @@
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 @@

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 @@
}
}
} 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) {

Check notice on line 122 in drivers/audio/dmic_nrfx_pdm.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/audio/dmic_nrfx_pdm.c:122 - ret = k_msgq_put(&drv_data->rx_queue, - &drv_data->mem_slab_buffer, - K_NO_WAIT); + ret = k_msgq_put(&drv_data->rx_queue, &drv_data->mem_slab_buffer, K_NO_WAIT);
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 @@
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,10 +214,14 @@
* 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;

Check notice on line 224 in drivers/audio/dmic_nrfx_pdm.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/audio/dmic_nrfx_pdm.c:224 - /* 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; + /* 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;
/* As specified in the nRF5340 PS:
*
* PDMCLKCTRL = 4096 * floor(f_pdm * 1048576 /
Expand Down Expand Up @@ -562,6 +600,7 @@
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 @@
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 @@
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 @@
.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 All @@ -635,7 +677,7 @@
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, \
&dmic_ops);

Check notice on line 680 in drivers/audio/dmic_nrfx_pdm.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

drivers/audio/dmic_nrfx_pdm.c:680 -#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_##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)); \ - IF_ENABLED(CONFIG_CLOCK_CONTROL_NRF, \ - (init_clock_manager(dev);)) \ - return 0; \ - } \ - static void event_handler##idx(const nrfx_pdm_evt_t *evt) \ - { \ - event_handler(DEVICE_DT_GET(PDM(idx)), evt); \ - } \ - PINCTRL_DT_DEFINE(PDM(idx)); \ - static const struct dmic_nrfx_pdm_drv_cfg dmic_nrfx_pdm_cfg##idx = { \ - .event_handler = event_handler##idx, \ - .nrfx_def_cfg = NRFX_PDM_DEFAULT_CONFIG(0, 0), \ - .nrfx_def_cfg.skip_gpio_cfg = true, \ - .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."); \ - BUILD_ASSERT(PDM_CLK_SRC(idx) != ACLK || \ - DT_NODE_HAS_PROP(DT_NODELABEL(clock), \ - hfclkaudio_frequency), \ - "Clock source ACLK requires the hfclkaudio-frequency " \ - "property to be defined in the nordic,nrf-clock 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, \ +#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_##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)); \ + IF_ENABLED(CONFIG_CLOCK_CONTROL_NRF, (init_clock_manager(dev);)) \ + return 0; \ + } \ + static void event_handler##idx(const nrfx_pdm_evt_t *evt)

#ifdef CONFIG_HAS_HW_NRF_PDM0
PDM_NRFX_DEVICE(0);
Expand Down
2 changes: 1 addition & 1 deletion dts/bindings/audio/nordic,nrf-pdm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Nordic PDM (Pulse Density Modulation interface)

compatible: "nordic,nrf-pdm"

include: [base.yaml, pinctrl-device.yaml]
include: ["base.yaml", "pinctrl-device.yaml", "memory-region.yaml", "nordic-clockpin.yaml"]

properties:
reg:
Expand Down
9 changes: 9 additions & 0 deletions dts/common/nordic/nrf54h20.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,15 @@
power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>;
};

pdm0: pdm@993000 {
compatible = "nordic,nrf-pdm";
reg = <0x993000 0x1000>;
status = "disabled";
interrupts = <403 NRF_DEFAULT_IRQ_PRIORITY>;
nordic,clockpin-enable = <NRF_FUN_PDM_CLK>;
power-domains = <&gpd NRF_GPD_SLOW_ACTIVE>;
};

qdec130: qdec@994000 {
compatible = "nordic,nrf-qdec";
reg = <0x994000 0x1000>;
Expand Down
Loading