ASoC: Intel: Skylake: Add support for active suspend
authorJeeja KP <jeeja.kp@intel.com>
Thu, 3 Dec 2015 18:00:00 +0000 (23:30 +0530)
committerMark Brown <broonie@kernel.org>
Tue, 8 Dec 2015 17:58:07 +0000 (17:58 +0000)
Some of the usecases can be marked as 'ignore_suspend' by
machine. For these on suspend we should keep audio controller
ON by saving the state and not suspending the device

For this we need to maintain a counter for these streams and be
active on suspend when such a stream is opened.

Signed-off-by: Jeeja KP <jeeja.kp@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/intel/skylake/skl-pcm.c
sound/soc/intel/skylake/skl.c
sound/soc/intel/skylake/skl.h

index 6570e5753e494eb8e35bb0cd24733806771ae937..b89ae6f7c096125b92f1170f0e557b8df7f6ad35 100644 (file)
@@ -109,6 +109,31 @@ static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *e
                return HDAC_EXT_STREAM_TYPE_COUPLED;
 }
 
+/*
+ * check if the stream opened is marked as ignore_suspend by machine, if so
+ * then enable suspend_active refcount
+ *
+ * The count supend_active does not need lock as it is used in open/close
+ * and suspend context
+ */
+static void skl_set_suspend_active(struct snd_pcm_substream *substream,
+                                        struct snd_soc_dai *dai, bool enable)
+{
+       struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev);
+       struct snd_soc_dapm_widget *w;
+       struct skl *skl = ebus_to_skl(ebus);
+
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+               w = dai->playback_widget;
+       else
+               w = dai->capture_widget;
+
+       if (w->ignore_suspend && enable)
+               skl->supend_active++;
+       else if (w->ignore_suspend && !enable)
+               skl->supend_active--;
+}
+
 static int skl_pcm_open(struct snd_pcm_substream *substream,
                struct snd_soc_dai *dai)
 {
@@ -146,6 +171,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream,
 
        dev_dbg(dai->dev, "stream tag set in dma params=%d\n",
                                 dma_params->stream_tag);
+       skl_set_suspend_active(substream, dai, true);
        snd_pcm_set_sync(substream);
 
        return 0;
@@ -257,6 +283,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
         * dma_params
         */
        snd_soc_dai_set_dma_data(dai, substream, NULL);
+       skl_set_suspend_active(substream, dai, false);
 
        kfree(dma_params);
 }
index d3e87b6f93fe4c6cef9bd5be26d42a9980408861..2c16325d1ce110805e229bd89e1435ed6b519c0d 100644 (file)
@@ -169,16 +169,40 @@ static int skl_suspend(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+       struct skl *skl  = ebus_to_skl(ebus);
 
-       return _skl_suspend(ebus);
+       /*
+        * Do not suspend if streams which are marked ignore suspend are
+        * running, we need to save the state for these and continue
+        */
+       if (skl->supend_active) {
+               pci_save_state(pci);
+               pci_disable_device(pci);
+               return 0;
+       } else {
+               return _skl_suspend(ebus);
+       }
 }
 
 static int skl_resume(struct device *dev)
 {
        struct pci_dev *pci = to_pci_dev(dev);
        struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
+       struct skl *skl  = ebus_to_skl(ebus);
+       int ret;
 
-       return _skl_resume(ebus);
+       /*
+        * resume only when we are not in suspend active, otherwise need to
+        * restore the device
+        */
+       if (skl->supend_active) {
+               pci_restore_state(pci);
+               ret = pci_enable_device(pci);
+       } else {
+               ret = _skl_resume(ebus);
+       }
+
+       return ret;
 }
 #endif /* CONFIG_PM_SLEEP */
 
index 774c29cf84dc53890e42abc072863a076dfa4fee..3d167eed0f59480d1dc81bab6ddecdacee590a92 100644 (file)
@@ -70,6 +70,8 @@ struct skl {
        struct list_head ppl_list;
 
        const char *fw_name;
+
+       int supend_active;
 };
 
 #define skl_to_ebus(s) (&(s)->ebus)