162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license.  When using or
462306a36Sopenharmony_ci// redistributing this file, you may do so under either license.
562306a36Sopenharmony_ci//
662306a36Sopenharmony_ci// Copyright(c) 2018 Intel Corporation. All rights reserved.
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
962306a36Sopenharmony_ci//
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "ops.h"
1262306a36Sopenharmony_ci#include "sof-priv.h"
1362306a36Sopenharmony_ci#include "sof-audio.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * Helper function to determine the target DSP state during
1762306a36Sopenharmony_ci * system suspend. This function only cares about the device
1862306a36Sopenharmony_ci * D-states. Platform-specific substates, if any, should be
1962306a36Sopenharmony_ci * handled by the platform-specific parts.
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_cistatic u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	u32 target_dsp_state;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	switch (sdev->system_suspend_target) {
2662306a36Sopenharmony_ci	case SOF_SUSPEND_S5:
2762306a36Sopenharmony_ci	case SOF_SUSPEND_S4:
2862306a36Sopenharmony_ci		/* DSP should be in D3 if the system is suspending to S3+ */
2962306a36Sopenharmony_ci	case SOF_SUSPEND_S3:
3062306a36Sopenharmony_ci		/* DSP should be in D3 if the system is suspending to S3 */
3162306a36Sopenharmony_ci		target_dsp_state = SOF_DSP_PM_D3;
3262306a36Sopenharmony_ci		break;
3362306a36Sopenharmony_ci	case SOF_SUSPEND_S0IX:
3462306a36Sopenharmony_ci		/*
3562306a36Sopenharmony_ci		 * Currently, the only criterion for retaining the DSP in D0
3662306a36Sopenharmony_ci		 * is that there are streams that ignored the suspend trigger.
3762306a36Sopenharmony_ci		 * Additional criteria such Soundwire clock-stop mode and
3862306a36Sopenharmony_ci		 * device suspend latency considerations will be added later.
3962306a36Sopenharmony_ci		 */
4062306a36Sopenharmony_ci		if (snd_sof_stream_suspend_ignored(sdev))
4162306a36Sopenharmony_ci			target_dsp_state = SOF_DSP_PM_D0;
4262306a36Sopenharmony_ci		else
4362306a36Sopenharmony_ci			target_dsp_state = SOF_DSP_PM_D3;
4462306a36Sopenharmony_ci		break;
4562306a36Sopenharmony_ci	default:
4662306a36Sopenharmony_ci		/* This case would be during runtime suspend */
4762306a36Sopenharmony_ci		target_dsp_state = SOF_DSP_PM_D3;
4862306a36Sopenharmony_ci		break;
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return target_dsp_state;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
5562306a36Sopenharmony_cistatic void sof_cache_debugfs(struct snd_sof_dev *sdev)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct snd_sof_dfsentry *dfse;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	list_for_each_entry(dfse, &sdev->dfsentry_list, list) {
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		/* nothing to do if debugfs buffer is not IO mem */
6262306a36Sopenharmony_ci		if (dfse->type == SOF_DFSENTRY_TYPE_BUF)
6362306a36Sopenharmony_ci			continue;
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci		/* cache memory that is only accessible in D0 */
6662306a36Sopenharmony_ci		if (dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY)
6762306a36Sopenharmony_ci			memcpy_fromio(dfse->cache_buf, dfse->io_mem,
6862306a36Sopenharmony_ci				      dfse->size);
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci#endif
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic int sof_resume(struct device *dev, bool runtime_resume)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
7662306a36Sopenharmony_ci	const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
7762306a36Sopenharmony_ci	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
7862306a36Sopenharmony_ci	u32 old_state = sdev->dsp_power_state.state;
7962306a36Sopenharmony_ci	int ret;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	/* do nothing if dsp resume callbacks are not set */
8262306a36Sopenharmony_ci	if (!runtime_resume && !sof_ops(sdev)->resume)
8362306a36Sopenharmony_ci		return 0;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	if (runtime_resume && !sof_ops(sdev)->runtime_resume)
8662306a36Sopenharmony_ci		return 0;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	/* DSP was never successfully started, nothing to resume */
8962306a36Sopenharmony_ci	if (sdev->first_boot)
9062306a36Sopenharmony_ci		return 0;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/*
9362306a36Sopenharmony_ci	 * if the runtime_resume flag is set, call the runtime_resume routine
9462306a36Sopenharmony_ci	 * or else call the system resume routine
9562306a36Sopenharmony_ci	 */
9662306a36Sopenharmony_ci	if (runtime_resume)
9762306a36Sopenharmony_ci		ret = snd_sof_dsp_runtime_resume(sdev);
9862306a36Sopenharmony_ci	else
9962306a36Sopenharmony_ci		ret = snd_sof_dsp_resume(sdev);
10062306a36Sopenharmony_ci	if (ret < 0) {
10162306a36Sopenharmony_ci		dev_err(sdev->dev,
10262306a36Sopenharmony_ci			"error: failed to power up DSP after resume\n");
10362306a36Sopenharmony_ci		return ret;
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (sdev->dspless_mode_selected) {
10762306a36Sopenharmony_ci		sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
10862306a36Sopenharmony_ci		return 0;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/*
11262306a36Sopenharmony_ci	 * Nothing further to be done for platforms that support the low power
11362306a36Sopenharmony_ci	 * D0 substate. Resume trace and return when resuming from
11462306a36Sopenharmony_ci	 * low-power D0 substate
11562306a36Sopenharmony_ci	 */
11662306a36Sopenharmony_ci	if (!runtime_resume && sof_ops(sdev)->set_power_state &&
11762306a36Sopenharmony_ci	    old_state == SOF_DSP_PM_D0) {
11862306a36Sopenharmony_ci		ret = sof_fw_trace_resume(sdev);
11962306a36Sopenharmony_ci		if (ret < 0)
12062306a36Sopenharmony_ci			/* non fatal */
12162306a36Sopenharmony_ci			dev_warn(sdev->dev,
12262306a36Sopenharmony_ci				 "failed to enable trace after resume %d\n", ret);
12362306a36Sopenharmony_ci		return 0;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	/* load the firmware */
12962306a36Sopenharmony_ci	ret = snd_sof_load_firmware(sdev);
13062306a36Sopenharmony_ci	if (ret < 0) {
13162306a36Sopenharmony_ci		dev_err(sdev->dev,
13262306a36Sopenharmony_ci			"error: failed to load DSP firmware after resume %d\n",
13362306a36Sopenharmony_ci			ret);
13462306a36Sopenharmony_ci		sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
13562306a36Sopenharmony_ci		return ret;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	sof_set_fw_state(sdev, SOF_FW_BOOT_IN_PROGRESS);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/*
14162306a36Sopenharmony_ci	 * Boot the firmware. The FW boot status will be modified
14262306a36Sopenharmony_ci	 * in snd_sof_run_firmware() depending on the outcome.
14362306a36Sopenharmony_ci	 */
14462306a36Sopenharmony_ci	ret = snd_sof_run_firmware(sdev);
14562306a36Sopenharmony_ci	if (ret < 0) {
14662306a36Sopenharmony_ci		dev_err(sdev->dev,
14762306a36Sopenharmony_ci			"error: failed to boot DSP firmware after resume %d\n",
14862306a36Sopenharmony_ci			ret);
14962306a36Sopenharmony_ci		sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
15062306a36Sopenharmony_ci		return ret;
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* resume DMA trace */
15462306a36Sopenharmony_ci	ret = sof_fw_trace_resume(sdev);
15562306a36Sopenharmony_ci	if (ret < 0) {
15662306a36Sopenharmony_ci		/* non fatal */
15762306a36Sopenharmony_ci		dev_warn(sdev->dev,
15862306a36Sopenharmony_ci			 "warning: failed to init trace after resume %d\n",
15962306a36Sopenharmony_ci			 ret);
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	/* restore pipelines */
16362306a36Sopenharmony_ci	if (tplg_ops && tplg_ops->set_up_all_pipelines) {
16462306a36Sopenharmony_ci		ret = tplg_ops->set_up_all_pipelines(sdev, false);
16562306a36Sopenharmony_ci		if (ret < 0) {
16662306a36Sopenharmony_ci			dev_err(sdev->dev, "Failed to restore pipeline after resume %d\n", ret);
16762306a36Sopenharmony_ci			goto setup_fail;
16862306a36Sopenharmony_ci		}
16962306a36Sopenharmony_ci	}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* Notify clients not managed by pm framework about core resume */
17262306a36Sopenharmony_ci	sof_resume_clients(sdev);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	/* notify DSP of system resume */
17562306a36Sopenharmony_ci	if (pm_ops && pm_ops->ctx_restore) {
17662306a36Sopenharmony_ci		ret = pm_ops->ctx_restore(sdev);
17762306a36Sopenharmony_ci		if (ret < 0)
17862306a36Sopenharmony_ci			dev_err(sdev->dev, "ctx_restore IPC error during resume: %d\n", ret);
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cisetup_fail:
18262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
18362306a36Sopenharmony_ci	if (ret < 0) {
18462306a36Sopenharmony_ci		/*
18562306a36Sopenharmony_ci		 * Debugfs cannot be read in runtime suspend, so cache
18662306a36Sopenharmony_ci		 * the contents upon failure. This allows to capture
18762306a36Sopenharmony_ci		 * possible DSP coredump information.
18862306a36Sopenharmony_ci		 */
18962306a36Sopenharmony_ci		sof_cache_debugfs(sdev);
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci#endif
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	return ret;
19462306a36Sopenharmony_ci}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_cistatic int sof_suspend(struct device *dev, bool runtime_suspend)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
19962306a36Sopenharmony_ci	const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
20062306a36Sopenharmony_ci	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
20162306a36Sopenharmony_ci	pm_message_t pm_state;
20262306a36Sopenharmony_ci	u32 target_state = snd_sof_dsp_power_target(sdev);
20362306a36Sopenharmony_ci	u32 old_state = sdev->dsp_power_state.state;
20462306a36Sopenharmony_ci	int ret;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* do nothing if dsp suspend callback is not set */
20762306a36Sopenharmony_ci	if (!runtime_suspend && !sof_ops(sdev)->suspend)
20862306a36Sopenharmony_ci		return 0;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (runtime_suspend && !sof_ops(sdev)->runtime_suspend)
21162306a36Sopenharmony_ci		return 0;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	/* we need to tear down pipelines only if the DSP hardware is
21462306a36Sopenharmony_ci	 * active, which happens for PCI devices. if the device is
21562306a36Sopenharmony_ci	 * suspended, it is brought back to full power and then
21662306a36Sopenharmony_ci	 * suspended again
21762306a36Sopenharmony_ci	 */
21862306a36Sopenharmony_ci	if (tplg_ops && tplg_ops->tear_down_all_pipelines && (old_state == SOF_DSP_PM_D0))
21962306a36Sopenharmony_ci		tplg_ops->tear_down_all_pipelines(sdev, false);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
22262306a36Sopenharmony_ci		goto suspend;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* prepare for streams to be resumed properly upon resume */
22562306a36Sopenharmony_ci	if (!runtime_suspend) {
22662306a36Sopenharmony_ci		ret = snd_sof_dsp_hw_params_upon_resume(sdev);
22762306a36Sopenharmony_ci		if (ret < 0) {
22862306a36Sopenharmony_ci			dev_err(sdev->dev,
22962306a36Sopenharmony_ci				"error: setting hw_params flag during suspend %d\n",
23062306a36Sopenharmony_ci				ret);
23162306a36Sopenharmony_ci			return ret;
23262306a36Sopenharmony_ci		}
23362306a36Sopenharmony_ci	}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	pm_state.event = target_state;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* suspend DMA trace */
23862306a36Sopenharmony_ci	sof_fw_trace_suspend(sdev, pm_state);
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	/* Notify clients not managed by pm framework about core suspend */
24162306a36Sopenharmony_ci	sof_suspend_clients(sdev, pm_state);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	/* Skip to platform-specific suspend if DSP is entering D0 */
24462306a36Sopenharmony_ci	if (target_state == SOF_DSP_PM_D0)
24562306a36Sopenharmony_ci		goto suspend;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
24862306a36Sopenharmony_ci	/* cache debugfs contents during runtime suspend */
24962306a36Sopenharmony_ci	if (runtime_suspend)
25062306a36Sopenharmony_ci		sof_cache_debugfs(sdev);
25162306a36Sopenharmony_ci#endif
25262306a36Sopenharmony_ci	/* notify DSP of upcoming power down */
25362306a36Sopenharmony_ci	if (pm_ops && pm_ops->ctx_save) {
25462306a36Sopenharmony_ci		ret = pm_ops->ctx_save(sdev);
25562306a36Sopenharmony_ci		if (ret == -EBUSY || ret == -EAGAIN) {
25662306a36Sopenharmony_ci			/*
25762306a36Sopenharmony_ci			 * runtime PM has logic to handle -EBUSY/-EAGAIN so
25862306a36Sopenharmony_ci			 * pass these errors up
25962306a36Sopenharmony_ci			 */
26062306a36Sopenharmony_ci			dev_err(sdev->dev, "ctx_save IPC error during suspend: %d\n", ret);
26162306a36Sopenharmony_ci			return ret;
26262306a36Sopenharmony_ci		} else if (ret < 0) {
26362306a36Sopenharmony_ci			/* FW in unexpected state, continue to power down */
26462306a36Sopenharmony_ci			dev_warn(sdev->dev, "ctx_save IPC error: %d, proceeding with suspend\n",
26562306a36Sopenharmony_ci				 ret);
26662306a36Sopenharmony_ci		}
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cisuspend:
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* return if the DSP was not probed successfully */
27262306a36Sopenharmony_ci	if (sdev->fw_state == SOF_FW_BOOT_NOT_STARTED)
27362306a36Sopenharmony_ci		return 0;
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	/* platform-specific suspend */
27662306a36Sopenharmony_ci	if (runtime_suspend)
27762306a36Sopenharmony_ci		ret = snd_sof_dsp_runtime_suspend(sdev);
27862306a36Sopenharmony_ci	else
27962306a36Sopenharmony_ci		ret = snd_sof_dsp_suspend(sdev, target_state);
28062306a36Sopenharmony_ci	if (ret < 0)
28162306a36Sopenharmony_ci		dev_err(sdev->dev,
28262306a36Sopenharmony_ci			"error: failed to power down DSP during suspend %d\n",
28362306a36Sopenharmony_ci			ret);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/* Do not reset FW state if DSP is in D0 */
28662306a36Sopenharmony_ci	if (target_state == SOF_DSP_PM_D0)
28762306a36Sopenharmony_ci		return ret;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	/* reset FW state */
29062306a36Sopenharmony_ci	sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
29162306a36Sopenharmony_ci	sdev->enabled_cores_mask = 0;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return ret;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ciint snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	/* Notify DSP of upcoming power down */
30162306a36Sopenharmony_ci	if (sof_ops(sdev)->remove && pm_ops && pm_ops->ctx_save)
30262306a36Sopenharmony_ci		return pm_ops->ctx_save(sdev);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	return 0;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ciint snd_sof_runtime_suspend(struct device *dev)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	return sof_suspend(dev, true);
31062306a36Sopenharmony_ci}
31162306a36Sopenharmony_ciEXPORT_SYMBOL(snd_sof_runtime_suspend);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ciint snd_sof_runtime_idle(struct device *dev)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return snd_sof_dsp_runtime_idle(sdev);
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ciEXPORT_SYMBOL(snd_sof_runtime_idle);
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciint snd_sof_runtime_resume(struct device *dev)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	return sof_resume(dev, true);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ciEXPORT_SYMBOL(snd_sof_runtime_resume);
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ciint snd_sof_resume(struct device *dev)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	return sof_resume(dev, false);
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ciEXPORT_SYMBOL(snd_sof_resume);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ciint snd_sof_suspend(struct device *dev)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	return sof_suspend(dev, false);
33662306a36Sopenharmony_ci}
33762306a36Sopenharmony_ciEXPORT_SYMBOL(snd_sof_suspend);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ciint snd_sof_prepare(struct device *dev)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
34262306a36Sopenharmony_ci	const struct sof_dev_desc *desc = sdev->pdata->desc;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	/* will suspend to S3 by default */
34562306a36Sopenharmony_ci	sdev->system_suspend_target = SOF_SUSPEND_S3;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	/*
34862306a36Sopenharmony_ci	 * if the firmware is crashed or boot failed then we try to aim for S3
34962306a36Sopenharmony_ci	 * to reboot the firmware
35062306a36Sopenharmony_ci	 */
35162306a36Sopenharmony_ci	if (sdev->fw_state == SOF_FW_CRASHED ||
35262306a36Sopenharmony_ci	    sdev->fw_state == SOF_FW_BOOT_FAILED)
35362306a36Sopenharmony_ci		return 0;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (!desc->use_acpi_target_states)
35662306a36Sopenharmony_ci		return 0;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci#if defined(CONFIG_ACPI)
35962306a36Sopenharmony_ci	switch (acpi_target_system_state()) {
36062306a36Sopenharmony_ci	case ACPI_STATE_S0:
36162306a36Sopenharmony_ci		sdev->system_suspend_target = SOF_SUSPEND_S0IX;
36262306a36Sopenharmony_ci		break;
36362306a36Sopenharmony_ci	case ACPI_STATE_S1:
36462306a36Sopenharmony_ci	case ACPI_STATE_S2:
36562306a36Sopenharmony_ci	case ACPI_STATE_S3:
36662306a36Sopenharmony_ci		sdev->system_suspend_target = SOF_SUSPEND_S3;
36762306a36Sopenharmony_ci		break;
36862306a36Sopenharmony_ci	case ACPI_STATE_S4:
36962306a36Sopenharmony_ci		sdev->system_suspend_target = SOF_SUSPEND_S4;
37062306a36Sopenharmony_ci		break;
37162306a36Sopenharmony_ci	case ACPI_STATE_S5:
37262306a36Sopenharmony_ci		sdev->system_suspend_target = SOF_SUSPEND_S5;
37362306a36Sopenharmony_ci		break;
37462306a36Sopenharmony_ci	default:
37562306a36Sopenharmony_ci		break;
37662306a36Sopenharmony_ci	}
37762306a36Sopenharmony_ci#endif
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	return 0;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ciEXPORT_SYMBOL(snd_sof_prepare);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_civoid snd_sof_complete(struct device *dev)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	sdev->system_suspend_target = SOF_SUSPEND_NONE;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ciEXPORT_SYMBOL(snd_sof_complete);
390