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

Add initial support for MICFIL PDM DAI #84881

Merged
merged 3 commits into from
Feb 7, 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
14 changes: 14 additions & 0 deletions boards/nxp/imx8mp_evk/imx8mp_evk-pinctrl.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@
};
};

pdm_default: pdm_default {
group0 {
pinmux = <&iomuxc_sai5_rxc_pdm_clk_pdm_clk>,
<&iomuxc_sai5_rxd0_pdm_bit_stream_pdm_bit_stream0>,
<&iomuxc_sai5_rxd1_pdm_bit_stream_pdm_bit_stream1>,
<&iomuxc_sai5_rxd2_pdm_bit_stream_pdm_bit_stream2>,
<&iomuxc_sai5_rxd3_pdm_bit_stream_pdm_bit_stream3>;
bias-pull-up;
slew-rate = "fast";
drive-strength = "x6";
input-schmitt-enable;
};
};

uart2_default: uart2_default {
group0 {
pinmux = <&iomuxc_uart2_rxd_uart_rx_uart2_rx>,
Expand Down
5 changes: 5 additions & 0 deletions boards/nxp/imx8mp_evk/imx8mp_evk_mimx8ml8_adsp.dts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@
};
};

&micfil {
pinctrl-0 = <&pdm_default>;
pinctrl-names = "default";
};

&sai3 {
pinctrl-0 = <&sai3_default>;
pinctrl-names = "default";
Expand Down
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);
}
dbaluta marked this conversation as resolved.
Show resolved Hide resolved

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), \
}; \
dbaluta marked this conversation as resolved.
Show resolved Hide resolved
\
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:
dbaluta marked this conversation as resolved.
Show resolved Hide resolved
type: int
required: true
description: |
Depth (in words) for each channel's FIFO.
9 changes: 9 additions & 0 deletions dts/xtensa/nxp/nxp_imx8m.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,15 @@
status = "disabled";
};

micfil: micfil@30ca0000 {
compatible = "nxp,dai-micfil";
reg = <0x30ca0000 DT_SIZE_K(64)>;
dai-index = <2>;
dmas = <&sdma3 24 6>;
fifo-depth = <32>;
status = "disabled";
};

iomuxc: iomuxc@30330000 {
compatible = "nxp,imx-iomuxc";
reg = <0x30330000 DT_SIZE_K(64)>;
Expand Down
1 change: 1 addition & 0 deletions include/zephyr/drivers/dai.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ enum dai_type {
DAI_INTEL_DMIC_NHLT, /**< nhlt ssp */
DAI_INTEL_HDA_NHLT, /**< nhlt Intel HD/A */
DAI_INTEL_ALH_NHLT, /**< nhlt Intel ALH */
DAI_IMX_MICFIL, /**< i.MX PDM MICFIL */
};

/**
Expand Down
Loading