ASoC: Intel: Skylake: Add support for active suspend
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>
This commit is contained in:
@@ -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;
|
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,
|
static int skl_pcm_open(struct snd_pcm_substream *substream,
|
||||||
struct snd_soc_dai *dai)
|
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",
|
dev_dbg(dai->dev, "stream tag set in dma params=%d\n",
|
||||||
dma_params->stream_tag);
|
dma_params->stream_tag);
|
||||||
|
skl_set_suspend_active(substream, dai, true);
|
||||||
snd_pcm_set_sync(substream);
|
snd_pcm_set_sync(substream);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -257,6 +283,7 @@ static void skl_pcm_close(struct snd_pcm_substream *substream,
|
|||||||
* dma_params
|
* dma_params
|
||||||
*/
|
*/
|
||||||
snd_soc_dai_set_dma_data(dai, substream, NULL);
|
snd_soc_dai_set_dma_data(dai, substream, NULL);
|
||||||
|
skl_set_suspend_active(substream, dai, false);
|
||||||
|
|
||||||
kfree(dma_params);
|
kfree(dma_params);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,16 +169,40 @@ static int skl_suspend(struct device *dev)
|
|||||||
{
|
{
|
||||||
struct pci_dev *pci = to_pci_dev(dev);
|
struct pci_dev *pci = to_pci_dev(dev);
|
||||||
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
|
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
|
||||||
|
struct skl *skl = ebus_to_skl(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);
|
return _skl_suspend(ebus);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int skl_resume(struct device *dev)
|
static int skl_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct pci_dev *pci = to_pci_dev(dev);
|
struct pci_dev *pci = to_pci_dev(dev);
|
||||||
struct hdac_ext_bus *ebus = pci_get_drvdata(pci);
|
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 */
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ struct skl {
|
|||||||
struct list_head ppl_list;
|
struct list_head ppl_list;
|
||||||
|
|
||||||
const char *fw_name;
|
const char *fw_name;
|
||||||
|
|
||||||
|
int supend_active;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define skl_to_ebus(s) (&(s)->ebus)
|
#define skl_to_ebus(s) (&(s)->ebus)
|
||||||
|
|||||||
Reference in New Issue
Block a user