Skip to content
Open
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
2 changes: 1 addition & 1 deletion sound/soc/sof/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += ipc3-compress.o
endif
ifneq ($(CONFIG_SND_SOC_SOF_IPC4),)
snd-sof-y += ipc4.o ipc4-loader.o ipc4-topology.o ipc4-control.o ipc4-pcm.o\
ipc4-mtrace.o ipc4-telemetry.o
ipc4-mtrace.o ipc4-telemetry.o ipc4-wov.o
snd-sof-$(CONFIG_SND_SOC_SOF_COMPRESS) += ipc4-compress.o
endif

Expand Down
106 changes: 106 additions & 0 deletions sound/soc/sof/ipc4-wov.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// Copyright(c) 2026 Intel Corporation

#include <linux/bits.h>
#include <sound/pcm.h>
#include <sound/control.h>
#include <sound/soc.h>
#include "sof-audio.h"
#include "sof-priv.h"
#include "ipc4-wov.h"

/* IPC4 PHRASE_DETECTED primary/extension field layout */
#define SOF_IPC4_PHRASE_WORD_ID_MASK GENMASK(15, 0)
#define SOF_IPC4_PHRASE_WORD_ID_SHIFT 0
#define SOF_IPC4_PHRASE_SV_SCORE_MASK GENMASK(15, 0)

/* PCM ID for WoV keyword detection capture stream */
#define SOF_WOV_PCM_ID 11

Comment on lines +18 to +20
/* kcontrol names as defined in the dmic-wov feature topology */
#define SOF_WOV_KEYWORD_ID_CTL "wov_trigger_id"
#define SOF_WOV_EVENT_CTL "wov_event"

/* sof_ipc4_wov_notify_kcontrol_by_name - Locate mixer control by name and notify */
static void sof_ipc4_wov_notify_kcontrol_by_name(struct snd_card *card,
const char *name)
{
struct snd_ctl_elem_id id;
struct snd_kcontrol *kctl;

if (!card || !name)
return;

memset(&id, 0, sizeof(id));
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(id.name, name, sizeof(id.name));

kctl = snd_ctl_find_id(card, &id);
if (kctl)
snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, 0);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what kind of controls are these?
They are coming from topology and attached to the module?

Why are you sending notification to two controls? and what user space can read out from them?
Where is the information?

If they are standard controls then why not use the standard kcontrol change notification for byte/enum/switch that we already have and leave this global one out, not handle it?

}

/* sof_ipc4_wov_notify_kcontrols - Iterate SOF controls and notify userspace */
static void sof_ipc4_wov_notify_kcontrols(struct snd_sof_dev *sdev)
{
static const char * const wov_ctl_names[] = {
SOF_WOV_KEYWORD_ID_CTL,
SOF_WOV_EVENT_CTL,
};
struct snd_sof_control *scontrol;
int i;

list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
for (i = 0; i < ARRAY_SIZE(wov_ctl_names); i++) {
if (strcmp(scontrol->name, wov_ctl_names[i]))
continue;

/* Force firmware re-read on next .get */
scontrol->comp_data_dirty = true;

if (scontrol->scomp && scontrol->scomp->card) {
sof_ipc4_wov_notify_kcontrol_by_name(
scontrol->scomp->card->snd_card,
scontrol->name);
}
}
}
}

void sof_ipc4_wov_phrase_detected(struct snd_sof_dev *sdev,
struct sof_ipc4_msg *ipc4_msg)
{
struct snd_sof_pcm *spcm;
struct snd_pcm_substream *substream;
u32 word_id = (ipc4_msg->primary & SOF_IPC4_PHRASE_WORD_ID_MASK)
>> SOF_IPC4_PHRASE_WORD_ID_SHIFT;
u32 sv_score = ipc4_msg->extension & SOF_IPC4_PHRASE_SV_SCORE_MASK;

dev_dbg(sdev->dev, "WoV: PHRASE_DETECTED word_id=%u sv_score=%u\n",
word_id, sv_score);

pm_wakeup_event(sdev->dev, 2000);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why?


/* 1. Notify WoV kcontrols */
sof_ipc4_wov_notify_kcontrols(sdev);

/* 2. Unblock capture PCM stream */
list_for_each_entry(spcm, &sdev->pcm_list, list) {
if (le32_to_cpu(spcm->pcm.pcm_id) != SOF_WOV_PCM_ID)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is ABI and will be enforced in all cases? not possible to have more than one PCM for WoV?

continue;

substream = spcm->stream[SNDRV_PCM_STREAM_CAPTURE].substream;
if (!substream || !substream->runtime) {
dev_warn(sdev->dev, "WoV: PCM %d not open\n",
SOF_WOV_PCM_ID);
return;
}
Comment on lines +94 to +98

snd_sof_pcm_period_elapsed(substream);
return;
}

dev_warn(sdev->dev, "WoV: PHRASE_DETECTED but PCM %d not found\n",
SOF_WOV_PCM_ID);
}
13 changes: 13 additions & 0 deletions sound/soc/sof/ipc4-wov.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */
/* Copyright(c) 2026 Intel Corporation */

#ifndef __SOF_IPC4_WOV_H
#define __SOF_IPC4_WOV_H

#include "sof-priv.h"
#include "ipc4-priv.h"

void sof_ipc4_wov_phrase_detected(struct snd_sof_dev *sdev,
struct sof_ipc4_msg *ipc4_msg);

#endif /* __SOF_IPC4_WOV_H */
4 changes: 4 additions & 0 deletions sound/soc/sof/ipc4.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "sof-audio.h"
#include "ipc4-fw-reg.h"
#include "ipc4-priv.h"
#include "ipc4-wov.h"
#include "ipc4-topology.h"
#include "ipc4-telemetry.h"
#include "ops.h"
Expand Down Expand Up @@ -840,6 +841,9 @@ static void sof_ipc4_rx_msg(struct snd_sof_dev *sdev)
case SOF_IPC4_NOTIFY_EXCEPTION_CAUGHT:
snd_sof_dsp_panic(sdev, 0, true);
break;
case SOF_IPC4_NOTIFY_PHRASE_DETECTED:
sof_ipc4_wov_phrase_detected(sdev, ipc4_msg);
break;
case SOF_IPC4_NOTIFY_MODULE_NOTIFICATION:
data_size = sizeof(struct sof_ipc4_notify_module_data);
handler_func = sof_ipc4_module_notification_handler;
Expand Down
Loading