@@ -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);
}
@@ -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 */
@@ -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)