Skip to content

Commit 83c3606

Browse files
mbukowskkartben
authored andcommitted
drivers: audio: intel: add support for microphone privacy
Implements driver for Intel microphone privacy feature. Signed-off-by: Michal Bukowski <michal.bukowski@intel.com>
1 parent 8748a05 commit 83c3606

File tree

8 files changed

+592
-0
lines changed

8 files changed

+592
-0
lines changed

drivers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ add_subdirectory_ifdef(CONFIG_I2S i2s)
5353
add_subdirectory_ifdef(CONFIG_I3C i3c)
5454
add_subdirectory_ifdef(CONFIG_IEEE802154 ieee802154)
5555
add_subdirectory_ifdef(CONFIG_INPUT input)
56+
add_subdirectory_ifdef(CONFIG_INTEL_ADSP_MIC_PRIVACY audio/mic_privacy/intel)
5657
add_subdirectory_ifdef(CONFIG_IPM ipm)
5758
add_subdirectory_ifdef(CONFIG_KSCAN kscan)
5859
add_subdirectory_ifdef(CONFIG_LED led)

drivers/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ menu "Device Drivers"
88
# zephyr-keep-sorted-start
99
source "drivers/adc/Kconfig"
1010
source "drivers/audio/Kconfig"
11+
source "drivers/audio/mic_privacy/intel/Kconfig.mic_privacy"
1112
source "drivers/auxdisplay/Kconfig"
1213
source "drivers/bbram/Kconfig"
1314
source "drivers/bluetooth/Kconfig"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_library()
4+
zephyr_library_sources_ifdef(CONFIG_INTEL_ADSP_MIC_PRIVACY mic_privacy.c)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SOF Microphone Privacy configuration options
2+
3+
# Copyright (c) 2025 Intel Corporation
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config INTEL_ADSP_MIC_PRIVACY
7+
bool "MIC PRIVACY device driver support"
8+
default y
9+
depends on DT_HAS_INTEL_ADSP_MIC_PRIVACY_ENABLED
10+
help
11+
Enable MIC PRIVACY device driver
Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/*
2+
* Copyright (c) 2025 Intel Corporation
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <errno.h>
7+
#include <stdbool.h>
8+
#include <stdint.h>
9+
#include "mic_privacy_registers.h"
10+
#include <zephyr/drivers/mic_privacy/intel/mic_privacy.h>
11+
#include <zephyr/irq.h>
12+
#include <zephyr/device.h>
13+
#include <zephyr/logging/log.h>
14+
#include <zephyr/pm/device.h>
15+
16+
#define LOG_DOMAIN mic_priv_zephyr
17+
18+
LOG_MODULE_REGISTER(LOG_DOMAIN);
19+
20+
#define DT_DRV_COMPAT intel_adsp_mic_privacy
21+
22+
#define DMICPVC_ADDRESS (DT_INST_REG_ADDR(0))
23+
#define DFMICPVCP_ADDRESS (DMICPVC_ADDRESS)
24+
#define DFMICPVCS_ADDRESS (DMICPVC_ADDRESS + 0x0004)
25+
#define DFFWMICPVCCS_ADDRESS (DMICPVC_ADDRESS + 0x0006)
26+
27+
#define DMICVSSX_ADDRESS (0x16000)
28+
#define DMICXLVSCTL_ADDRESS (DMICVSSX_ADDRESS + 0x0004)
29+
#define DMICXPVCCS_ADDRESS (DMICVSSX_ADDRESS + 0x0010)
30+
31+
static inline void ace_mic_priv_intc_unmask(void)
32+
{
33+
ACE_DINT[0].ie[ACE_INTL_MIC_PRIV] = BIT(0);
34+
}
35+
36+
static inline void ace_dmic_intc_unmask(void)
37+
{
38+
ACE_DINT[0].ie[ACE_INTL_DMIC] = BIT(0);
39+
}
40+
41+
static void mic_privacy_enable_fw_managed_irq(bool enable_irq, const void *fn)
42+
{
43+
union DFFWMICPVCCS pv_ccs;
44+
45+
pv_ccs.full = sys_read16(DFFWMICPVCCS_ADDRESS);
46+
if (enable_irq) {
47+
pv_ccs.part.mdstschgie = 1;
48+
} else {
49+
pv_ccs.part.mdstschgie = 0;
50+
}
51+
sys_write16(pv_ccs.full, DFFWMICPVCCS_ADDRESS);
52+
53+
if (enable_irq && !irq_is_enabled(DT_INST_IRQN(0))) {
54+
55+
irq_connect_dynamic(DT_INST_IRQN(0), 0,
56+
fn,
57+
DEVICE_DT_INST_GET(0), 0);
58+
59+
irq_enable(DT_INST_IRQN(0));
60+
ace_mic_priv_intc_unmask();
61+
}
62+
}
63+
64+
static void mic_privacy_clear_fw_managed_irq(void)
65+
{
66+
union DFFWMICPVCCS pv_ccs;
67+
68+
pv_ccs.full = sys_read16(DFFWMICPVCCS_ADDRESS);
69+
pv_ccs.part.mdstschg = 1;
70+
sys_write16(pv_ccs.full, DFFWMICPVCCS_ADDRESS);
71+
}
72+
73+
static void mic_privacy_enable_dmic_irq(bool enable_irq, const void *fn)
74+
{
75+
union DFFWMICPVCCS pv_ccs;
76+
77+
pv_ccs.full = sys_read16(DMICXPVCCS_ADDRESS);
78+
if (enable_irq) {
79+
pv_ccs.part.mdstschgie = 1;
80+
} else {
81+
pv_ccs.part.mdstschgie = 0;
82+
}
83+
sys_write16(pv_ccs.full, DMICXPVCCS_ADDRESS);
84+
85+
if (enable_irq) {
86+
irq_connect_dynamic(ACE_INTL_DMIC, 0,
87+
fn,
88+
NULL, 0);
89+
irq_enable(ACE_INTL_DMIC);
90+
ace_dmic_intc_unmask();
91+
}
92+
}
93+
94+
static bool mic_privacy_get_dmic_irq_status(void)
95+
{
96+
union DFFWMICPVCCS pv_ccs;
97+
98+
pv_ccs.full = sys_read16(DMICXPVCCS_ADDRESS);
99+
return pv_ccs.part.mdstschg;
100+
}
101+
102+
static void mic_privacy_clear_dmic_irq_status(void)
103+
{
104+
union DFFWMICPVCCS pv_ccs;
105+
106+
pv_ccs.full = sys_read16(DMICXPVCCS_ADDRESS);
107+
pv_ccs.part.mdstschg = 1;
108+
sys_write16(pv_ccs.full, DMICXPVCCS_ADDRESS);
109+
}
110+
111+
static enum mic_privacy_policy mic_privacy_get_policy(void)
112+
{
113+
union DFMICPVCP micpvcp;
114+
115+
micpvcp.full = sys_read32(DFMICPVCP_ADDRESS);
116+
117+
if (micpvcp.part.ddze == 2 && micpvcp.part.ddzpl == 1) {
118+
return MIC_PRIVACY_HW_MANAGED;
119+
} else if (micpvcp.part.ddze == 2 && micpvcp.part.ddzpl == 0) {
120+
return MIC_PRIVACY_FW_MANAGED;
121+
} else if (micpvcp.part.ddze == 3) {
122+
return MIC_PRIVACY_FORCE_MIC_DISABLED;
123+
} else {
124+
return MIC_PRIVACY_DISABLED;
125+
}
126+
}
127+
128+
static uint32_t mic_privacy_get_privacy_policy_register_raw_value(void)
129+
{
130+
return sys_read32(DFMICPVCP_ADDRESS);
131+
}
132+
133+
static uint32_t mic_privacy_get_dma_data_zeroing_wait_time(void)
134+
{
135+
union DFMICPVCP micpvcp;
136+
137+
micpvcp.full = sys_read32(DFMICPVCP_ADDRESS);
138+
return micpvcp.part.ddzwt;
139+
}
140+
141+
static uint32_t mic_privacy_get_dma_data_zeroing_link_select(void)
142+
{
143+
union DFMICPVCP micpvcp;
144+
145+
micpvcp.full = sys_read32(DFMICPVCP_ADDRESS);
146+
return micpvcp.part.ddzls;
147+
}
148+
149+
static uint32_t mic_privacy_get_dmic_mic_disable_status(void)
150+
{
151+
union DMICXPVCCS pvccs;
152+
153+
pvccs.full = sys_read32(DMICXPVCCS_ADDRESS);
154+
return pvccs.part.mdsts;
155+
}
156+
157+
static uint32_t mic_privacy_get_fw_managed_mic_disable_status(void)
158+
{
159+
union DFFWMICPVCCS pv_ccs;
160+
161+
pv_ccs.full = sys_read16(DFFWMICPVCCS_ADDRESS);
162+
return pv_ccs.part.mdsts;
163+
}
164+
165+
static void mic_privacy_set_fw_managed_mode(bool is_fw_managed_enabled)
166+
{
167+
union DFFWMICPVCCS pv_ccs;
168+
169+
pv_ccs.full = sys_read16(DFFWMICPVCCS_ADDRESS);
170+
if (is_fw_managed_enabled) {
171+
pv_ccs.part.fmmd = 1;
172+
} else {
173+
pv_ccs.part.fmmd = 0;
174+
}
175+
sys_write16(pv_ccs.full, DFFWMICPVCCS_ADDRESS);
176+
}
177+
178+
static void mic_privacy_set_fw_mic_disable_status(bool fw_mic_disable_status)
179+
{
180+
union DFFWMICPVCCS pv_ccs;
181+
182+
pv_ccs.full = sys_read16(DFFWMICPVCCS_ADDRESS);
183+
if (fw_mic_disable_status) {
184+
pv_ccs.part.fmdsts = 1;
185+
} else {
186+
pv_ccs.part.fmdsts = 0;
187+
}
188+
sys_write16(pv_ccs.full, DFFWMICPVCCS_ADDRESS);
189+
}
190+
191+
static uint32_t mic_privacy_get_fw_mic_disable_status(void)
192+
{
193+
union DFFWMICPVCCS pv_ccs;
194+
195+
pv_ccs.full = sys_read16(DFFWMICPVCCS_ADDRESS);
196+
return pv_ccs.part.fmdsts;
197+
}
198+
199+
static int intel_adsp_mic_priv_init(const struct device *dev)
200+
{
201+
return 0;
202+
};
203+
204+
static const struct mic_privacy_api_funcs mic_privacy_ops = {
205+
.enable_fw_managed_irq = mic_privacy_enable_fw_managed_irq,
206+
.clear_fw_managed_irq = mic_privacy_clear_fw_managed_irq,
207+
.enable_dmic_irq = mic_privacy_enable_dmic_irq,
208+
.get_dmic_irq_status = mic_privacy_get_dmic_irq_status,
209+
.clear_dmic_irq_status = mic_privacy_clear_dmic_irq_status,
210+
.get_policy = mic_privacy_get_policy,
211+
.get_privacy_policy_register_raw_value = mic_privacy_get_privacy_policy_register_raw_value,
212+
.get_dma_data_zeroing_wait_time = mic_privacy_get_dma_data_zeroing_wait_time,
213+
.get_dma_data_zeroing_link_select = mic_privacy_get_dma_data_zeroing_link_select,
214+
.get_dmic_mic_disable_status = mic_privacy_get_dmic_mic_disable_status,
215+
.get_fw_managed_mic_disable_status = mic_privacy_get_fw_managed_mic_disable_status,
216+
.set_fw_managed_mode = mic_privacy_set_fw_managed_mode,
217+
.set_fw_mic_disable_status = mic_privacy_set_fw_mic_disable_status,
218+
.get_fw_mic_disable_status = mic_privacy_get_fw_mic_disable_status
219+
};
220+
221+
#define INTEL_ADSP_MIC_PRIVACY_INIT(inst) \
222+
\
223+
static const struct intel_adsp_mic_priv_cfg intel_adsp_mic_priv##inst##_config = { \
224+
.base = DT_INST_REG_ADDR(inst), \
225+
.regblock_size = DT_INST_REG_SIZE(inst), \
226+
}; \
227+
\
228+
static struct intel_adsp_mic_priv_data intel_adsp_mic_priv##inst##_data = {}; \
229+
\
230+
DEVICE_DT_INST_DEFINE(inst, &intel_adsp_mic_priv_init, \
231+
NULL, \
232+
&intel_adsp_mic_priv##inst##_data, \
233+
&intel_adsp_mic_priv##inst##_config, POST_KERNEL, \
234+
0, \
235+
&mic_privacy_ops); \
236+
\
237+
238+
DT_INST_FOREACH_STATUS_OKAY(INTEL_ADSP_MIC_PRIVACY_INIT)

0 commit comments

Comments
 (0)