OSDN Git Service

ASoC: Intel: avs: Handle SUSPEND and RESUME triggers
authorAmadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Thu, 27 Oct 2022 12:46:57 +0000 (14:46 +0200)
committerMark Brown <broonie@kernel.org>
Fri, 28 Oct 2022 12:04:34 +0000 (13:04 +0100)
With power management operations added, service SUSPEND and RESUME
trigger commands for running streams.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20221027124702.1761002-5-cezary.rojewski@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/avs/pcm.c

index df965db..db29496 100644 (file)
@@ -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_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_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,36 @@ 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);
 
+               /* Timeout on DRSM poll shall not stop the resume so ignore the result. */
+               if (cmd == SNDRV_PCM_TRIGGER_RESUME)
+                       snd_hdac_stream_wait_drsm(hdac_stream(host_stream));
+
+               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 +665,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:
@@ -974,6 +1018,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 |