Skip to content

Commit 715fbd1

Browse files
dbalutakartben
authored andcommitted
drivers: dai: Add initial support for NXP MICFIL PDM IP
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]>
1 parent da2f5a8 commit 715fbd1

File tree

6 files changed

+251
-0
lines changed

6 files changed

+251
-0
lines changed

drivers/dai/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ add_subdirectory_ifdef(CONFIG_DAI_INTEL_DMIC intel/dmic)
66
add_subdirectory_ifdef(CONFIG_DAI_INTEL_HDA intel/hda)
77
add_subdirectory_ifdef(CONFIG_DAI_NXP_SAI nxp/sai)
88
add_subdirectory_ifdef(CONFIG_DAI_NXP_ESAI nxp/esai)
9+
add_subdirectory_ifdef(CONFIG_DAI_NXP_MICFIL nxp/micfil)

drivers/dai/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ source "drivers/dai/intel/dmic/Kconfig.dmic"
3131
source "drivers/dai/intel/hda/Kconfig.hda"
3232
source "drivers/dai/nxp/sai/Kconfig.sai"
3333
source "drivers/dai/nxp/esai/Kconfig.esai"
34+
source "drivers/dai/nxp/micfil/Kconfig.micfil"
3435

3536
endif # DAI

drivers/dai/nxp/micfil/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
zephyr_library()
5+
zephyr_library_sources(micfil.c)

drivers/dai/nxp/micfil/Kconfig.micfil

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config DAI_NXP_MICFIL
5+
bool "NXP Pulse Density Modulation Microphone Interface (MICFIL) driver"
6+
default y
7+
depends on DT_HAS_NXP_DAI_MICFIL_ENABLED
8+
select PINCTRL
9+
help
10+
Select this to enable NXP PDM MICFIL driver.

drivers/dai/nxp/micfil/micfil.c

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <zephyr/drivers/dai.h>
7+
#include <zephyr/device.h>
8+
#include <zephyr/kernel.h>
9+
#include <zephyr/drivers/pinctrl.h>
10+
#include <zephyr/logging/log.h>
11+
12+
#include "fsl_pdm.h"
13+
14+
#define DT_DRV_COMPAT nxp_dai_micfil
15+
LOG_MODULE_REGISTER(nxp_dai_micfil);
16+
17+
#define MICFIL_CLK_ROOT 24576000
18+
#define MICFIL_OSR_DEFAULT 16
19+
20+
#define UINT_TO_MICFIL(x) ((PDM_Type *)(uintptr_t)(x))
21+
22+
#define MICFIL_FIFO_BASE(inst) \
23+
POINTER_TO_UINT(&(UINT_TO_MICFIL(DT_INST_REG_ADDR(inst))->DATACH[0]))
24+
25+
#define MICFIL_DMA_HANDSHAKE(inst) \
26+
((DT_INST_DMAS_CELL_BY_IDX(inst, 0, channel) & GENMASK(7, 0)) | \
27+
((DT_INST_DMAS_CELL_BY_IDX(inst, 0, mux) << 8) & GENMASK(15, 8)))
28+
29+
struct dai_nxp_micfil_data {
30+
struct dai_config cfg;
31+
};
32+
33+
struct dai_nxp_micfil_config {
34+
PDM_Type *base;
35+
const struct dai_properties *rx_props;
36+
const struct pinctrl_dev_config *pincfg;
37+
};
38+
39+
/* this needs to match SOF struct sof_ipc_dai_micfil_params */
40+
struct micfil_bespoke_config {
41+
uint32_t pdm_rate;
42+
uint32_t pdm_ch;
43+
};
44+
45+
static void dai_nxp_micfil_trigger_start(const struct device *dev)
46+
{
47+
const struct dai_nxp_micfil_config *cfg = dev->config;
48+
49+
/* enable DMA requests */
50+
PDM_EnableDMA(cfg->base, true);
51+
/* enable the module */
52+
PDM_Enable(cfg->base, true);
53+
}
54+
55+
static void dai_nxp_micfil_trigger_stop(const struct device *dev)
56+
{
57+
const struct dai_nxp_micfil_config *cfg = dev->config;
58+
59+
/* disable DMA requests */
60+
PDM_EnableDMA(cfg->base, false);
61+
/* disable module */
62+
PDM_Enable(cfg->base, false);
63+
}
64+
65+
static const struct dai_properties
66+
*dai_nxp_micfil_get_properties(const struct device *dev, enum dai_dir dir, int stream_id)
67+
{
68+
const struct dai_nxp_micfil_config *cfg = dev->config;
69+
70+
if (dir == DAI_DIR_RX) {
71+
return cfg->rx_props;
72+
}
73+
74+
LOG_ERR("invalid direction %d", dir);
75+
return NULL;
76+
}
77+
78+
static int dai_nxp_micfil_trigger(const struct device *dev, enum dai_dir dir,
79+
enum dai_trigger_cmd cmd)
80+
{
81+
if (dir != DAI_DIR_RX) {
82+
LOG_ERR("invalid direction %d", dir);
83+
return -EINVAL;
84+
}
85+
86+
switch (cmd) {
87+
case DAI_TRIGGER_START:
88+
dai_nxp_micfil_trigger_start(dev);
89+
break;
90+
case DAI_TRIGGER_STOP:
91+
case DAI_TRIGGER_PAUSE:
92+
dai_nxp_micfil_trigger_stop(dev);
93+
break;
94+
case DAI_TRIGGER_PRE_START:
95+
case DAI_TRIGGER_COPY:
96+
return 0;
97+
default:
98+
LOG_ERR("invalid trigger cmd %d", cmd);
99+
return -EINVAL;
100+
}
101+
102+
return 0;
103+
}
104+
105+
static int dai_nxp_micfil_get_config(const struct device *dev, struct dai_config *cfg,
106+
enum dai_dir dir)
107+
{
108+
struct dai_nxp_micfil_data *micfil_data = dev->data;
109+
110+
memcpy(cfg, &micfil_data->cfg, sizeof(*cfg));
111+
return 0;
112+
}
113+
114+
static int dai_nxp_micfil_set_config(const struct device *dev,
115+
const struct dai_config *cfg, const void *bespoke_cfg)
116+
117+
{
118+
const struct micfil_bespoke_config *bespoke = bespoke_cfg;
119+
const struct dai_nxp_micfil_config *micfil_cfg = dev->config;
120+
pdm_channel_config_t chan_config = { 0 };
121+
pdm_config_t global_config = { 0 };
122+
int ret, i;
123+
124+
if (cfg->type != DAI_IMX_MICFIL) {
125+
LOG_ERR("wrong DAI type: %d", cfg->type);
126+
return -EINVAL;
127+
}
128+
129+
global_config.fifoWatermark = micfil_cfg->rx_props->fifo_depth - 1;
130+
global_config.qualityMode = kPDM_QualityModeVeryLow0;
131+
global_config.cicOverSampleRate = MICFIL_OSR_DEFAULT;
132+
133+
PDM_Init(micfil_cfg->base, &global_config);
134+
135+
for (i = 0; i < bespoke->pdm_ch; i++) {
136+
chan_config.gain = kPDM_DfOutputGain2;
137+
chan_config.cutOffFreq = kPDM_DcRemoverBypass;
138+
PDM_SetChannelConfig(micfil_cfg->base, i, &chan_config);
139+
}
140+
141+
ret = PDM_SetSampleRateConfig(micfil_cfg->base, MICFIL_CLK_ROOT, bespoke->pdm_rate);
142+
if (ret == kStatus_Fail) {
143+
LOG_ERR("Failure to set samplerate config rate %d", bespoke->pdm_rate);
144+
return -EINVAL;
145+
}
146+
147+
return 0;
148+
}
149+
150+
static int dai_nxp_micfil_probe(const struct device *dev)
151+
{
152+
/* nothing do to here, but mandatory to exist */
153+
return 0;
154+
}
155+
156+
static int dai_nxp_micfil_remove(const struct device *dev)
157+
{
158+
/* nothing do to here, but mandatory to exist */
159+
return 0;
160+
}
161+
162+
const struct dai_driver_api dai_nxp_micfil_ops = {
163+
.probe = dai_nxp_micfil_probe,
164+
.remove = dai_nxp_micfil_remove,
165+
.config_set = dai_nxp_micfil_set_config,
166+
.config_get = dai_nxp_micfil_get_config,
167+
.get_properties = dai_nxp_micfil_get_properties,
168+
.trigger = dai_nxp_micfil_trigger,
169+
};
170+
171+
static int micfil_init(const struct device *dev)
172+
{
173+
const struct dai_nxp_micfil_config *cfg = dev->config;
174+
int ret;
175+
176+
/* pinctrl is optional so do not return an error if not defined */
177+
ret = pinctrl_apply_state(cfg->pincfg, PINCTRL_STATE_DEFAULT);
178+
if (ret < 0 && ret != -ENOENT) {
179+
return ret;
180+
}
181+
182+
return 0;
183+
}
184+
185+
#define DAI_NXP_MICFIL_INIT(inst) \
186+
PINCTRL_DT_INST_DEFINE(inst); \
187+
static struct dai_nxp_micfil_data dai_nxp_micfil_data_##inst = { \
188+
.cfg.type = DAI_IMX_MICFIL, \
189+
.cfg.dai_index = DT_INST_PROP_OR(inst, dai_index, 0), \
190+
}; \
191+
\
192+
static const struct dai_properties micfil_rx_props_##inst = { \
193+
.fifo_address = MICFIL_FIFO_BASE(inst), \
194+
.fifo_depth = DT_INST_PROP(inst, fifo_depth), \
195+
.dma_hs_id = MICFIL_DMA_HANDSHAKE(inst), \
196+
}; \
197+
\
198+
static const struct dai_nxp_micfil_config dai_nxp_micfil_config_##inst = { \
199+
.base = UINT_TO_MICFIL(DT_INST_REG_ADDR(inst)), \
200+
.rx_props = &micfil_rx_props_##inst, \
201+
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(inst), \
202+
}; \
203+
\
204+
DEVICE_DT_INST_DEFINE(inst, &micfil_init, NULL, \
205+
&dai_nxp_micfil_data_##inst, &dai_nxp_micfil_config_##inst, \
206+
POST_KERNEL, CONFIG_DAI_INIT_PRIORITY, \
207+
&dai_nxp_micfil_ops); \
208+
209+
DT_INST_FOREACH_STATUS_OKAY(DAI_NXP_MICFIL_INIT)

dts/bindings/dai/nxp,dai-micfil.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Copyright 2023 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: NXP PDM MICFIL node
5+
6+
compatible: "nxp,dai-micfil"
7+
8+
include: [base.yaml, pinctrl-device.yaml]
9+
10+
properties:
11+
reg:
12+
required: true
13+
dai-index:
14+
type: int
15+
description: |
16+
Use this property to specify the index of the DAI. At the
17+
moment, this is only used by SOF to fetch the "struct device"
18+
associated with the DAI whose index Linux passes to SOF
19+
through an IPC. If this property is not specified, the DAI
20+
index will be considered 0.
21+
fifo-depth:
22+
type: int
23+
required: true
24+
description: |
25+
Depth (in words) for each channel's FIFO.

0 commit comments

Comments
 (0)