Commit ac8c046f authored by Keyon Jie's avatar Keyon Jie Committed by Mark Brown

ASoC: SOF: ignore suspend/resume for D0ix compatible streams

During system suspend, the PM framework will freeze all applications and
the ALSA/ASoC core will suspend all RUNNING PCM streams.

However, D0ix-compatible PCM streams should keep the related pipelines
active in the DSP when the system is entering S0ix. The TRIGGER_SUSPEND
event is trapped in such cases to prevent the pipelines from being
stopped. Likewise, the TRIGGER_RESUME/START events should not affect the
pipeline state.

The SOF driver also triggers some DSP Firmware pipelines based on the
DAPM widgets power events. In such cases, we also ignore PRE_PMU and
POST_PMD events to keep the pipelines active.
Signed-off-by: default avatarKeyon Jie <yang.jie@linux.intel.com>
Signed-off-by: default avatarPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191025224122.7718-23-pierre-louis.bossart@linux.intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 0b50b3b1
...@@ -346,6 +346,16 @@ static int sof_pcm_trigger(struct snd_soc_component *component, ...@@ -346,6 +346,16 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE; stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE;
break; break;
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
if (spcm->stream[substream->stream].suspend_ignored) {
/*
* this case will be triggered when INFO_RESUME is
* supported, no need to resume streams that remained
* enabled in D0ix.
*/
spcm->stream[substream->stream].suspend_ignored = false;
return 0;
}
/* set up hw_params */ /* set up hw_params */
ret = sof_pcm_prepare(component, substream); ret = sof_pcm_prepare(component, substream);
if (ret < 0) { if (ret < 0) {
...@@ -356,9 +366,30 @@ static int sof_pcm_trigger(struct snd_soc_component *component, ...@@ -356,9 +366,30 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
/* fallthrough */ /* fallthrough */
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
if (spcm->stream[substream->stream].suspend_ignored) {
/*
* This case will be triggered when INFO_RESUME is
* not supported, no need to re-start streams that
* remained enabled in D0ix.
*/
spcm->stream[substream->stream].suspend_ignored = false;
return 0;
}
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START; stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_START;
break; break;
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
if (sdev->s0_suspend &&
spcm->stream[substream->stream].d0i3_compatible) {
/*
* trap the event, not sending trigger stop to
* prevent the FW pipelines from being stopped,
* and mark the flag to ignore the upcoming DAPM
* PM events.
*/
spcm->stream[substream->stream].suspend_ignored = true;
return 0;
}
/* fallthrough */
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
ipc_first = true; ipc_first = true;
......
...@@ -135,7 +135,9 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, ...@@ -135,7 +135,9 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event) struct snd_kcontrol *k, int event)
{ {
struct snd_sof_widget *swidget = w->dobj.private; struct snd_sof_widget *swidget = w->dobj.private;
int stream = SNDRV_PCM_STREAM_CAPTURE;
struct snd_sof_dev *sdev; struct snd_sof_dev *sdev;
struct snd_sof_pcm *spcm;
int ret = 0; int ret = 0;
if (!swidget) if (!swidget)
...@@ -146,11 +148,19 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, ...@@ -146,11 +148,19 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
dev_dbg(sdev->dev, "received event %d for widget %s\n", dev_dbg(sdev->dev, "received event %d for widget %s\n",
event, w->name); event, w->name);
/* get runtime PCM params using widget's stream name */
spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname);
/* process events */ /* process events */
switch (event) { switch (event) {
case SND_SOC_DAPM_PRE_PMU: case SND_SOC_DAPM_PRE_PMU:
if (spcm->stream[stream].suspend_ignored) {
dev_dbg(sdev->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
return 0;
}
/* set pcm params */ /* set pcm params */
ret = ipc_pcm_params(swidget, SOF_IPC_STREAM_CAPTURE); ret = ipc_pcm_params(swidget, stream);
if (ret < 0) { if (ret < 0) {
dev_err(sdev->dev, dev_err(sdev->dev,
"error: failed to set pcm params for widget %s\n", "error: failed to set pcm params for widget %s\n",
...@@ -166,6 +176,11 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w, ...@@ -166,6 +176,11 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
swidget->widget->name); swidget->widget->name);
break; break;
case SND_SOC_DAPM_POST_PMD: case SND_SOC_DAPM_POST_PMD:
if (spcm->stream[stream].suspend_ignored) {
dev_dbg(sdev->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n");
return 0;
}
/* stop trigger */ /* stop trigger */
ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP); ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
if (ret < 0) if (ret < 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment