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

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.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 730cb320
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -24,6 +24,13 @@ struct avs_tplg_library;
struct avs_soc_component;
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
 *
+68 −7
Original line number Diff line number Diff line
@@ -534,12 +534,30 @@ static void avs_pci_remove(struct pci_dev *pci)
	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;
	int ret;

	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);

@@ -577,11 +595,30 @@ static int __maybe_unused avs_suspend_common(struct avs_dev *adev)
	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;
	int ret;

	if (low_power && adev->num_lp_paths)
		return avs_resume_standby(adev);

	snd_hdac_display_power(bus, HDA_CODEC_IDX_CONTROLLER, 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)

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)
{
	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)
{
	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)
{
	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 = {
	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)
};

+10 −0
Original line number Diff line number Diff line
@@ -1405,6 +1405,11 @@ static int avs_widget_load(struct snd_soc_component *comp, int index,
	if (!le32_to_cpu(dw->priv.size))
		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;
	mach = dev_get_platdata(comp->card->dev);

@@ -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,
			 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) {
		/* Stream control handled by IPCs. */
		link->nonatomic = true;