Skip to content

Commit 93085f8

Browse files
ujfalusiranj063
authored andcommitted
ASoC: SOF: Intel: hda-mlink: Add support for mic privacy in VS SHIM registers
New register has been introduced with PTL in the vendor specific SHIM registers, outside of the IPs itself for microphone privacy status handling. Via the PVCCS register the current microphone privacy status can be checked and the interrupt generation on status change can be enabled/disabled. The status change interrupt is routed to the owner of the interface (DSP/host). The PVCCS is provided for each sublink under the IP to make it possible to control the interrupt generation per sublink. On status change the MDSTSCHG bit needs to be cleared for all sublink of the interface to be able to detect future changes in privacy. The status bit (MDSTS) is volatile in all PVCCS register, it reflects the current state of the GPIO signal. Microphone privacy is a hardware feature (if enabled and configured that way), the host has only passive, monitoring role. The added functions are generic to be future proof if the mic privacy support is extended beyond Soundwire and DMIC links. Signed-off-by: Peter Ujfalusi <[email protected]>
1 parent 9f9d3a8 commit 93085f8

File tree

2 files changed

+140
-0
lines changed

2 files changed

+140
-0
lines changed

include/sound/hda-mlink.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ struct mutex *hdac_bus_eml_get_mutex(struct hdac_bus *bus, bool alt, int elid);
6262

6363
int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enable);
6464

65+
/* microphone privacy specific function supported by ACE3+ architecture */
66+
void hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid,
67+
unsigned long mask);
68+
bool hdac_bus_eml_is_mic_privacy_changed(struct hdac_bus *bus, bool alt, int elid);
69+
bool hdac_bus_eml_get_mic_privacy_state(struct hdac_bus *bus, bool alt, int elid);
70+
6571
#else
6672

6773
static inline int
@@ -185,4 +191,23 @@ hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool enabl
185191
{
186192
return 0;
187193
}
194+
195+
static inline void
196+
hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid,
197+
unsigned long mask)
198+
{
199+
}
200+
201+
static inline bool
202+
hdac_bus_eml_is_mic_privacy_changed(struct hdac_bus *bus, bool alt, int elid)
203+
{
204+
return false;
205+
}
206+
207+
static inline bool
208+
hdac_bus_eml_get_mic_privacy_state(struct hdac_bus *bus, bool alt, int elid)
209+
{
210+
return false;
211+
}
212+
188213
#endif /* CONFIG_SND_SOC_SOF_HDA_MLINK */

sound/soc/sof/intel/hda-mlink.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
* @shim_offset: offset to SHIM register base
4343
* @ip_offset: offset to IP register base
4444
* @shim_vs_offset: offset to vendor-specific (VS) SHIM base
45+
* @mic_privacy_mask: bitmask of sublinks where mic privacy is applied
4546
*/
4647
struct hdac_ext2_link {
4748
struct hdac_ext_link hext_link;
@@ -65,6 +66,8 @@ struct hdac_ext2_link {
6566
u32 shim_offset;
6667
u32 ip_offset;
6768
u32 shim_vs_offset;
69+
70+
unsigned long mic_privacy_mask;
6871
};
6972

7073
#define hdac_ext_link_to_ext2(h) container_of(h, struct hdac_ext2_link, hext_link)
@@ -90,6 +93,13 @@ struct hdac_ext2_link {
9093
#define AZX_REG_INTEL_UAOL_IP_OFFSET 0x100
9194
#define AZX_REG_INTEL_UAOL_VS_SHIM_OFFSET 0xC00
9295

96+
/* Microphone privacy */
97+
#define AZX_REG_INTEL_VS_SHIM_PVCCS 0x10
98+
#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE BIT(0)
99+
#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG BIT(8)
100+
#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS BIT(9)
101+
#define AZX_REG_INTEL_VS_SHIM_PVCCS_FMDIS BIT(10)
102+
93103
/* HDAML section - this part follows sequences in the hardware specification,
94104
* including naming conventions and the use of the hdaml_ prefix.
95105
* The code is intentionally minimal with limited dependencies on frameworks or
@@ -696,6 +706,14 @@ static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid,
696706
}
697707

698708
ret = hdaml_link_init(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
709+
if ((h2link->mic_privacy_mask & BIT(sublink)) && !ret) {
710+
u16 __iomem *pvccs = h2link->base_ptr +
711+
h2link->shim_vs_offset +
712+
sublink * h2link->instance_offset +
713+
AZX_REG_INTEL_VS_SHIM_PVCCS;
714+
715+
writew(readw(pvccs) | AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs);
716+
}
699717

700718
skip_init:
701719
if (eml_lock)
@@ -742,6 +760,16 @@ static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid
742760
if (--h2link->sublink_ref_count[sublink] > 0)
743761
goto skip_shutdown;
744762
}
763+
764+
if (h2link->mic_privacy_mask & BIT(sublink)) {
765+
u16 __iomem *pvccs = h2link->base_ptr +
766+
h2link->shim_vs_offset +
767+
sublink * h2link->instance_offset +
768+
AZX_REG_INTEL_VS_SHIM_PVCCS;
769+
770+
writew(readw(pvccs) & ~AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs);
771+
}
772+
745773
ret = hdaml_link_shutdown(hlink->ml_addr + AZX_REG_ML_LCTL, sublink);
746774

747775
skip_shutdown:
@@ -987,6 +1015,93 @@ int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool e
9871015
}
9881016
EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, "SND_SOC_SOF_HDA_MLINK");
9891017

1018+
void hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid,
1019+
unsigned long mask)
1020+
{
1021+
struct hdac_ext2_link *h2link;
1022+
1023+
if (!mask)
1024+
return;
1025+
1026+
h2link = find_ext2_link(bus, alt, elid);
1027+
if (!h2link)
1028+
return;
1029+
1030+
if (__fls(mask) > h2link->slcount) {
1031+
dev_warn(bus->dev,
1032+
"%s: invalid sublink mask for %d:%d, slcount %d: %#lx\n",
1033+
__func__, alt, elid, h2link->slcount, mask);
1034+
return;
1035+
}
1036+
1037+
dev_dbg(bus->dev, "sublink mask for %d:%d, slcount %d: %#lx\n", alt,
1038+
elid, h2link->slcount, mask);
1039+
1040+
h2link->mic_privacy_mask = mask;
1041+
}
1042+
EXPORT_SYMBOL_NS(hdac_bus_eml_set_mic_privacy_mask, "SND_SOC_SOF_HDA_MLINK");
1043+
1044+
bool hdac_bus_eml_is_mic_privacy_changed(struct hdac_bus *bus, bool alt, int elid)
1045+
{
1046+
struct hdac_ext2_link *h2link;
1047+
bool changed = false;
1048+
u16 __iomem *pvccs;
1049+
int i;
1050+
1051+
h2link = find_ext2_link(bus, alt, elid);
1052+
if (!h2link)
1053+
return false;
1054+
1055+
/* The change in privacy state needs to be acked for each link */
1056+
for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) {
1057+
u16 val;
1058+
1059+
if (h2link->sublink_ref_count[i] == 0)
1060+
continue;
1061+
1062+
pvccs = h2link->base_ptr +
1063+
h2link->shim_vs_offset +
1064+
i * h2link->instance_offset +
1065+
AZX_REG_INTEL_VS_SHIM_PVCCS;
1066+
1067+
val = readw(pvccs);
1068+
if (val & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG) {
1069+
writew(val, pvccs);
1070+
changed = true;
1071+
}
1072+
}
1073+
1074+
return changed;
1075+
}
1076+
EXPORT_SYMBOL_NS(hdac_bus_eml_is_mic_privacy_changed, "SND_SOC_SOF_HDA_MLINK");
1077+
1078+
bool hdac_bus_eml_get_mic_privacy_state(struct hdac_bus *bus, bool alt, int elid)
1079+
{
1080+
struct hdac_ext2_link *h2link;
1081+
u16 __iomem *pvccs;
1082+
int i;
1083+
1084+
h2link = find_ext2_link(bus, alt, elid);
1085+
if (!h2link)
1086+
return false;
1087+
1088+
for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) {
1089+
if (h2link->sublink_ref_count[i] == 0)
1090+
continue;
1091+
1092+
/* Return the privacy state from the first active link */
1093+
pvccs = h2link->base_ptr +
1094+
h2link->shim_vs_offset +
1095+
i * h2link->instance_offset +
1096+
AZX_REG_INTEL_VS_SHIM_PVCCS;
1097+
1098+
return readw(pvccs) & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS;
1099+
}
1100+
1101+
return false;
1102+
}
1103+
EXPORT_SYMBOL_NS(hdac_bus_eml_get_mic_privacy_state, "SND_SOC_SOF_HDA_MLINK");
1104+
9901105
#endif
9911106

9921107
MODULE_LICENSE("Dual BSD/GPL");

0 commit comments

Comments
 (0)