Commit d56829e9 authored by Piotr Maziarz's avatar Piotr Maziarz Committed by Mark Brown

ASoC: Intel: avs: Standby power-state support

Introduce avs_suspend_standby() and avs_resume_standby() to support S0IX
streaming. The AudioDSP is not shutdown during such scenario and the PCI
device is armed for possible wake operation through an audio event.

As capability for a stream to be active during low power S0 is based off
of ->ignore_suspend, adjust the field's value according to platform
capabilities if needed.
Signed-off-by: default avatarPiotr Maziarz <piotrx.maziarz@linux.intel.com>
Signed-off-by: default avatarCezary Rojewski <cezary.rojewski@intel.com>
Link: https://lore.kernel.org/r/20221027124702.1761002-8-cezary.rojewski@intel.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 730cb320
...@@ -24,6 +24,13 @@ struct avs_tplg_library; ...@@ -24,6 +24,13 @@ struct avs_tplg_library;
struct avs_soc_component; struct avs_soc_component;
struct avs_ipc_msg; struct avs_ipc_msg;
#ifdef CONFIG_ACPI
#define AVS_S0IX_SUPPORTED \
(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0)
#else
#define AVS_S0IX_SUPPORTED false
#endif
/* /*
* struct avs_dsp_ops - Platform-specific DSP operations * struct avs_dsp_ops - Platform-specific DSP operations
* *
......
...@@ -534,12 +534,30 @@ static void avs_pci_remove(struct pci_dev *pci) ...@@ -534,12 +534,30 @@ static void avs_pci_remove(struct pci_dev *pci)
pm_runtime_get_noresume(&pci->dev); pm_runtime_get_noresume(&pci->dev);
} }
static int __maybe_unused avs_suspend_common(struct avs_dev *adev) static int avs_suspend_standby(struct avs_dev *adev)
{
struct hdac_bus *bus = &adev->base.core;
struct pci_dev *pci = adev->base.pci;
if (bus->cmd_dma_state)
snd_hdac_bus_stop_cmd_io(bus);
snd_hdac_ext_bus_link_power_down_all(bus);
enable_irq_wake(pci->irq);
pci_save_state(pci);
return 0;
}
static int __maybe_unused avs_suspend_common(struct avs_dev *adev, bool low_power)
{ {
struct hdac_bus *bus = &adev->base.core; struct hdac_bus *bus = &adev->base.core;
int ret; int ret;
flush_work(&adev->probe_work); flush_work(&adev->probe_work);
if (low_power && adev->num_lp_paths)
return avs_suspend_standby(adev);
snd_hdac_ext_bus_link_power_down_all(bus); snd_hdac_ext_bus_link_power_down_all(bus);
...@@ -577,11 +595,30 @@ static int __maybe_unused avs_suspend_common(struct avs_dev *adev) ...@@ -577,11 +595,30 @@ static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
return 0; return 0;
} }
static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge) static int avs_resume_standby(struct avs_dev *adev)
{
struct hdac_bus *bus = &adev->base.core;
struct pci_dev *pci = adev->base.pci;
pci_restore_state(pci);
disable_irq_wake(pci->irq);
snd_hdac_ext_bus_link_power_up_all(bus);
if (bus->cmd_dma_state)
snd_hdac_bus_init_cmd_io(bus);
return 0;
}
static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power, bool purge)
{ {
struct hdac_bus *bus = &adev->base.core; struct hdac_bus *bus = &adev->base.core;
int ret; int ret;
if (low_power && adev->num_lp_paths)
return avs_resume_standby(adev);
snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true); snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, true);
avs_hdac_bus_init_chip(bus, true); avs_hdac_bus_init_chip(bus, true);
...@@ -599,26 +636,50 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge) ...@@ -599,26 +636,50 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool purge)
static int __maybe_unused avs_suspend(struct device *dev) static int __maybe_unused avs_suspend(struct device *dev)
{ {
return avs_suspend_common(to_avs_dev(dev)); return avs_suspend_common(to_avs_dev(dev), true);
} }
static int __maybe_unused avs_resume(struct device *dev) static int __maybe_unused avs_resume(struct device *dev)
{ {
return avs_resume_common(to_avs_dev(dev), true); return avs_resume_common(to_avs_dev(dev), true, true);
} }
static int __maybe_unused avs_runtime_suspend(struct device *dev) static int __maybe_unused avs_runtime_suspend(struct device *dev)
{ {
return avs_suspend_common(to_avs_dev(dev)); return avs_suspend_common(to_avs_dev(dev), true);
} }
static int __maybe_unused avs_runtime_resume(struct device *dev) static int __maybe_unused avs_runtime_resume(struct device *dev)
{ {
return avs_resume_common(to_avs_dev(dev), true); return avs_resume_common(to_avs_dev(dev), true, false);
}
static int __maybe_unused avs_freeze(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), false);
}
static int __maybe_unused avs_thaw(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), false, true);
}
static int __maybe_unused avs_poweroff(struct device *dev)
{
return avs_suspend_common(to_avs_dev(dev), false);
}
static int __maybe_unused avs_restore(struct device *dev)
{
return avs_resume_common(to_avs_dev(dev), false, true);
} }
static const struct dev_pm_ops avs_dev_pm = { static const struct dev_pm_ops avs_dev_pm = {
SET_SYSTEM_SLEEP_PM_OPS(avs_suspend, avs_resume) .suspend = avs_suspend,
.resume = avs_resume,
.freeze = avs_freeze,
.thaw = avs_thaw,
.poweroff = avs_poweroff,
.restore = avs_restore,
SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL) SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
}; };
......
...@@ -1405,6 +1405,11 @@ static int avs_widget_load(struct snd_soc_component *comp, int index, ...@@ -1405,6 +1405,11 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
if (!le32_to_cpu(dw->priv.size)) if (!le32_to_cpu(dw->priv.size))
return 0; return 0;
if (w->ignore_suspend && !AVS_S0IX_SUPPORTED) {
dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
w->ignore_suspend = false;
}
tplg = acomp->tplg; tplg = acomp->tplg;
mach = dev_get_platdata(comp->card->dev); mach = dev_get_platdata(comp->card->dev);
...@@ -1442,6 +1447,11 @@ static int avs_dai_load(struct snd_soc_component *comp, int index, ...@@ -1442,6 +1447,11 @@ static int avs_dai_load(struct snd_soc_component *comp, int index,
static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_link *link, static int avs_link_load(struct snd_soc_component *comp, int index, struct snd_soc_dai_link *link,
struct snd_soc_tplg_link_config *cfg) struct snd_soc_tplg_link_config *cfg)
{ {
if (link->ignore_suspend && !AVS_S0IX_SUPPORTED) {
dev_info_once(comp->dev, "Device does not support S0IX, check BIOS settings\n");
link->ignore_suspend = false;
}
if (!link->no_pcm) { if (!link->no_pcm) {
/* Stream control handled by IPCs. */ /* Stream control handled by IPCs. */
link->nonatomic = true; link->nonatomic = true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment