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: Keyon Jie <yang.jie@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191025224122.7718-23-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Keyon Jie 2019-10-25 17:41:18 -05:00 committed by Mark Brown
parent 0b50b3b1c3
commit ac8c046f19
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 47 additions and 1 deletions

View File

@ -346,6 +346,16 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_RELEASE;
break;
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 */
ret = sof_pcm_prepare(component, substream);
if (ret < 0) {
@ -356,9 +366,30 @@ static int sof_pcm_trigger(struct snd_soc_component *component,
/* fallthrough */
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;
break;
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:
stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP;
ipc_first = true;

View File

@ -135,7 +135,9 @@ static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *k, int event)
{
struct snd_sof_widget *swidget = w->dobj.private;
int stream = SNDRV_PCM_STREAM_CAPTURE;
struct snd_sof_dev *sdev;
struct snd_sof_pcm *spcm;
int ret = 0;
if (!swidget)
@ -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",
event, w->name);
/* get runtime PCM params using widget's stream name */
spcm = snd_sof_find_spcm_name(sdev, swidget->widget->sname);
/* process events */
switch (event) {
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 */
ret = ipc_pcm_params(swidget, SOF_IPC_STREAM_CAPTURE);
ret = ipc_pcm_params(swidget, stream);
if (ret < 0) {
dev_err(sdev->dev,
"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,
swidget->widget->name);
break;
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 */
ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
if (ret < 0)