Skip to content

Commit

Permalink
drivers: dai: Add initial support for NXP MICFIL PDM IP
Browse files Browse the repository at this point in the history
Introduce new DAI driver used for NXP's PDM MICFIL IP.
This block implements required digital interface to provide
a 24-bits audio signal from a PDM microphone bitstream in a configurable
output sampling rate.

Signed-off-by: Daniel Baluta <[email protected]>
  • Loading branch information
dbaluta authored and kartben committed Feb 7, 2025
1 parent da2f5a8 commit 715fbd1
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/dai/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ add_subdirectory_ifdef(CONFIG_DAI_INTEL_DMIC intel/dmic)
add_subdirectory_ifdef(CONFIG_DAI_INTEL_HDA intel/hda)
add_subdirectory_ifdef(CONFIG_DAI_NXP_SAI nxp/sai)
add_subdirectory_ifdef(CONFIG_DAI_NXP_ESAI nxp/esai)
add_subdirectory_ifdef(CONFIG_DAI_NXP_MICFIL nxp/micfil)
1 change: 1 addition & 0 deletions drivers/dai/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ source "drivers/dai/intel/dmic/Kconfig.dmic"
source "drivers/dai/intel/hda/Kconfig.hda"
source "drivers/dai/nxp/sai/Kconfig.sai"
source "drivers/dai/nxp/esai/Kconfig.esai"
source "drivers/dai/nxp/micfil/Kconfig.micfil"

endif # DAI
5 changes: 5 additions & 0 deletions drivers/dai/nxp/micfil/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Copyright 2025 NXP
# SPDX-License-Identifier: Apache-2.0

zephyr_library()
zephyr_library_sources(micfil.c)
10 changes: 10 additions & 0 deletions drivers/dai/nxp/micfil/Kconfig.micfil
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2025 NXP
# SPDX-License-Identifier: Apache-2.0

config DAI_NXP_MICFIL
bool "NXP Pulse Density Modulation Microphone Interface (MICFIL) driver"
default y
depends on DT_HAS_NXP_DAI_MICFIL_ENABLED
select PINCTRL
help
Select this to enable NXP PDM MICFIL driver.
209 changes: 209 additions & 0 deletions drivers/dai/nxp/micfil/micfil.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* Copyright 2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/dai.h>
#include <zephyr/device.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/logging/log.h>

#include "fsl_pdm.h"

#define DT_DRV_COMPAT nxp_dai_micfil
LOG_MODULE_REGISTER(nxp_dai_micfil);

#define MICFIL_CLK_ROOT 24576000
#define MICFIL_OSR_DEFAULT 16

#define UINT_TO_MICFIL(x) ((PDM_Type *)(uintptr_t)(x))

#define MICFIL_FIFO_BASE(inst) \
POINTER_TO_UINT(&(UINT_TO_MICFIL(DT_INST_REG_ADDR(inst))->DATACH[0]))

#define MICFIL_DMA_HANDSHAKE(inst) \
((DT_INST_DMAS_CELL_BY_IDX(inst, 0, channel) & GENMASK(7, 0)) | \
((DT_INST_DMAS_CELL_BY_IDX(inst, 0, mux) << 8) & GENMASK(15, 8)))

struct dai_nxp_micfil_data {
struct dai_config cfg;
};

struct dai_nxp_micfil_config {
PDM_Type *base;
const struct dai_properties *rx_props;
const struct pinctrl_dev_config *pincfg;
};

/* this needs to match SOF struct sof_ipc_dai_micfil_params */
struct micfil_bespoke_config {
uint32_t pdm_rate;
uint32_t pdm_ch;
};

static void dai_nxp_micfil_trigger_start(const struct device *dev)
{
const struct dai_nxp_micfil_config *cfg = dev->config;

/* enable DMA requests */
PDM_EnableDMA(cfg->base, true);
/* enable the module */
PDM_Enable(cfg->base, true);
}

static void dai_nxp_micfil_trigger_stop(const struct device *dev)
{
const struct dai_nxp_micfil_config *cfg = dev->config;

/* disable DMA requests */
PDM_EnableDMA(cfg->base, false);
/* disable module */
PDM_Enable(cfg->base, false);
}

static const struct dai_properties
*dai_nxp_micfil_get_properties(const struct device *dev, enum dai_dir dir, int stream_id)
{
const struct dai_nxp_micfil_config *cfg = dev->config;

if (dir == DAI_DIR_RX) {
return cfg->rx_props;
}

LOG_ERR("invalid direction %d", dir);
return NULL;
}

static int dai_nxp_micfil_trigger(const struct device *dev, enum dai_dir dir,
enum dai_trigger_cmd cmd)
{
if (dir != DAI_DIR_RX) {
LOG_ERR("invalid direction %d", dir);
return -EINVAL;
}

switch (cmd) {
case DAI_TRIGGER_START:
dai_nxp_micfil_trigger_start(dev);
break;
case DAI_TRIGGER_STOP:
case DAI_TRIGGER_PAUSE:
dai_nxp_micfil_trigger_stop(dev);
break;
case DAI_TRIGGER_PRE_START:
case DAI_TRIGGER_COPY:
return 0;
default:
LOG_ERR("invalid trigger cmd %d", cmd);
return -EINVAL;
}

return 0;
}

static int dai_nxp_micfil_get_config(const struct device *dev, struct dai_config *cfg,
enum dai_dir dir)
{
struct dai_nxp_micfil_data *micfil_data = dev->data;

memcpy(cfg, &micfil_data->cfg, sizeof(*cfg));
return 0;
}

static int dai_nxp_micfil_set_config(const struct device *dev,
const struct dai_config *cfg, const void *bespoke_cfg)

{
const struct micfil_bespoke_config *bespoke = bespoke_cfg;
const struct dai_nxp_micfil_config *micfil_cfg = dev->config;
pdm_channel_config_t chan_config = { 0 };
pdm_config_t global_config = { 0 };
int ret, i;

if (cfg->type != DAI_IMX_MICFIL) {
LOG_ERR("wrong DAI type: %d", cfg->type);
return -EINVAL;
}

global_config.fifoWatermark = micfil_cfg->rx_props->fifo_depth - 1;
global_config.qualityMode = kPDM_QualityModeVeryLow0;
global_config.cicOverSampleRate = MICFIL_OSR_DEFAULT;

PDM_Init(micfil_cfg->base, &global_config);

for (i = 0; i < bespoke->pdm_ch; i++) {
chan_config.gain = kPDM_DfOutputGain2;
chan_config.cutOffFreq = kPDM_DcRemoverBypass;
PDM_SetChannelConfig(micfil_cfg->base, i, &chan_config);
}

ret = PDM_SetSampleRateConfig(micfil_cfg->base, MICFIL_CLK_ROOT, bespoke->pdm_rate);
if (ret == kStatus_Fail) {
LOG_ERR("Failure to set samplerate config rate %d", bespoke->pdm_rate);
return -EINVAL;
}

return 0;
}

static int dai_nxp_micfil_probe(const struct device *dev)
{
/* nothing do to here, but mandatory to exist */
return 0;
}

static int dai_nxp_micfil_remove(const struct device *dev)
{
/* nothing do to here, but mandatory to exist */
return 0;
}

const struct dai_driver_api dai_nxp_micfil_ops = {
.probe = dai_nxp_micfil_probe,
.remove = dai_nxp_micfil_remove,
.config_set = dai_nxp_micfil_set_config,
.config_get = dai_nxp_micfil_get_config,
.get_properties = dai_nxp_micfil_get_properties,
.trigger = dai_nxp_micfil_trigger,
};

static int micfil_init(const struct device *dev)
{
const struct dai_nxp_micfil_config *cfg = dev->config;
int ret;

/* pinctrl is optional so do not return an error if not defined */
ret = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT);
if (ret < 0 && ret != -ENOENT) {
return ret;
}

return 0;
}

#define DAI_NXP_MICFIL_INIT(inst) \
PINCTRL_DT_INST_DEFINE(inst); \
static struct dai_nxp_micfil_data dai_nxp_micfil_data_##inst = { \
.cfg.type = DAI_IMX_MICFIL, \
.cfg.dai_index = DT_INST_PROP_OR(inst, dai_index, 0), \
}; \
\
static const struct dai_properties micfil_rx_props_##inst = { \
.fifo_address = MICFIL_FIFO_BASE(inst), \
.fifo_depth = DT_INST_PROP(inst, fifo_depth), \
.dma_hs_id = MICFIL_DMA_HANDSHAKE(inst), \
}; \
\
static const struct dai_nxp_micfil_config dai_nxp_micfil_config_##inst = { \
.base = UINT_TO_MICFIL(DT_INST_REG_ADDR(inst)), \
.rx_props = &micfil_rx_props_##inst, \
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
}; \
\
DEVICE_DT_INST_DEFINE(inst, &micfil_init, NULL, \
&dai_nxp_micfil_data_##inst, &dai_nxp_micfil_config_##inst, \
POST_KERNEL, CONFIG_DAI_INIT_PRIORITY, \
&dai_nxp_micfil_ops); \

DT_INST_FOREACH_STATUS_OKAY(DAI_NXP_MICFIL_INIT)
25 changes: 25 additions & 0 deletions dts/bindings/dai/nxp,dai-micfil.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright 2023 NXP
# SPDX-License-Identifier: Apache-2.0

description: NXP PDM MICFIL node

compatible: "nxp,dai-micfil"

include: [base.yaml, pinctrl-device.yaml]

properties:
reg:
required: true
dai-index:
type: int
description: |
Use this property to specify the index of the DAI. At the
moment, this is only used by SOF to fetch the "struct device"
associated with the DAI whose index Linux passes to SOF
through an IPC. If this property is not specified, the DAI
index will be considered 0.
fifo-depth:
type: int
required: true
description: |
Depth (in words) for each channel's FIFO.

0 comments on commit 715fbd1

Please sign in to comment.