From: Amadeusz Sławiński <amadeuszx.slawinski@xxxxxxxxxxxxxxx> With power management operations added, service SUSPEND and RESUME trigger commands for running streams. Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@xxxxxxxxxxxxxxx> Signed-off-by: Cezary Rojewski <cezary.rojewski@xxxxxxxxx> --- sound/soc/intel/avs/pcm.c | 81 +++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 55f213d5bab9..5c9923cba126 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -208,30 +208,43 @@ static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct avs_dma_data *data; int ret = 0; data = snd_soc_dai_get_dma_data(dai, substream); switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + if (rtd->dai_link->ignore_suspend) + break; + fallthrough; case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = avs_path_pause(data->path); + if (ret < 0) { + dev_err(dai->dev, "pause BE path failed: %d\n", ret); + break; + } + ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); if (ret < 0) dev_err(dai->dev, "run BE path failed: %d\n", ret); break; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (rtd->dai_link->ignore_suspend) + break; + fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: ret = avs_path_pause(data->path); if (ret < 0) dev_err(dai->dev, "pause BE path failed: %d\n", ret); - if (cmd == SNDRV_PCM_TRIGGER_STOP) { - ret = avs_path_reset(data->path); - if (ret < 0) - dev_err(dai->dev, "reset BE path failed: %d\n", ret); - } + ret = avs_path_reset(data->path); + if (ret < 0) + dev_err(dai->dev, "reset BE path failed: %d\n", ret); break; default: @@ -351,6 +364,7 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct hdac_ext_stream *link_stream; struct avs_dma_data *data; int ret = 0; @@ -361,15 +375,29 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd, link_stream = substream->runtime->private_data; switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + if (rtd->dai_link->ignore_suspend) + break; + fallthrough; case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: snd_hdac_ext_link_stream_start(link_stream); + ret = avs_path_pause(data->path); + if (ret < 0) { + dev_err(dai->dev, "pause BE path failed: %d\n", ret); + break; + } + ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); if (ret < 0) dev_err(dai->dev, "run BE path failed: %d\n", ret); break; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (rtd->dai_link->ignore_suspend) + break; + fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: ret = avs_path_pause(data->path); @@ -378,11 +406,9 @@ static int avs_dai_hda_be_trigger(struct snd_pcm_substream *substream, int cmd, snd_hdac_ext_link_stream_clear(link_stream); - if (cmd == SNDRV_PCM_TRIGGER_STOP) { - ret = avs_path_reset(data->path); - if (ret < 0) - dev_err(dai->dev, "reset BE path failed: %d\n", ret); - } + ret = avs_path_reset(data->path); + if (ret < 0) + dev_err(dai->dev, "reset BE path failed: %d\n", ret); break; default: @@ -587,6 +613,7 @@ static int avs_dai_fe_prepare(struct snd_pcm_substream *substream, struct snd_so static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct avs_dma_data *data; struct hdac_ext_stream *host_stream; struct hdac_bus *bus; @@ -598,17 +625,42 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru bus = hdac_stream(host_stream)->bus; switch (cmd) { + case SNDRV_PCM_TRIGGER_RESUME: + if (rtd->dai_link->ignore_suspend) + break; + fallthrough; case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: spin_lock_irqsave(&bus->reg_lock, flags); snd_hdac_stream_start(hdac_stream(host_stream), true); spin_unlock_irqrestore(&bus->reg_lock, flags); + if (cmd == SNDRV_PCM_TRIGGER_RESUME) { + u32 mask = 1 << hdac_stream(host_stream)->index; + u32 reg; + + ret = readb_poll_timeout(bus->drsmcap + AZX_REG_DRSM_CTL, reg, + (reg & mask) == 0, 250, 2000); + if (ret) + dev_dbg(dai->dev, "polling RSM 0x%08x failed: %d\n", mask, ret); + } + + ret = avs_path_pause(data->path); + if (ret < 0) { + dev_err(dai->dev, "pause FE path failed: %d\n", ret); + break; + } + ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); if (ret < 0) dev_err(dai->dev, "run FE path failed: %d\n", ret); + break; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (rtd->dai_link->ignore_suspend) + break; + fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_STOP: ret = avs_path_pause(data->path); @@ -619,11 +671,9 @@ static int avs_dai_fe_trigger(struct snd_pcm_substream *substream, int cmd, stru snd_hdac_stream_stop(hdac_stream(host_stream)); spin_unlock_irqrestore(&bus->reg_lock, flags); - if (cmd == SNDRV_PCM_TRIGGER_STOP) { - ret = avs_path_reset(data->path); - if (ret < 0) - dev_err(dai->dev, "reset FE path failed: %d\n", ret); - } + ret = avs_path_reset(data->path); + if (ret < 0) + dev_err(dai->dev, "reset FE path failed: %d\n", ret); break; default: @@ -987,6 +1037,7 @@ static int avs_component_open(struct snd_soc_component *component, SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP; hwparams.formats = SNDRV_PCM_FMTBIT_S16_LE | -- 2.25.1