xref: /openbmc/linux/sound/soc/sof/pm.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1e149ca29SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
28920153cSLiam Girdwood //
38920153cSLiam Girdwood // This file is provided under a dual BSD/GPLv2 license.  When using or
48920153cSLiam Girdwood // redistributing this file, you may do so under either license.
58920153cSLiam Girdwood //
68920153cSLiam Girdwood // Copyright(c) 2018 Intel Corporation. All rights reserved.
78920153cSLiam Girdwood //
88920153cSLiam Girdwood // Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
98920153cSLiam Girdwood //
108920153cSLiam Girdwood 
118920153cSLiam Girdwood #include "ops.h"
128920153cSLiam Girdwood #include "sof-priv.h"
13ee1e79b7SRanjani Sridharan #include "sof-audio.h"
148920153cSLiam Girdwood 
15700d1677SRanjani Sridharan /*
16700d1677SRanjani Sridharan  * Helper function to determine the target DSP state during
17700d1677SRanjani Sridharan  * system suspend. This function only cares about the device
18700d1677SRanjani Sridharan  * D-states. Platform-specific substates, if any, should be
19700d1677SRanjani Sridharan  * handled by the platform-specific parts.
20700d1677SRanjani Sridharan  */
snd_sof_dsp_power_target(struct snd_sof_dev * sdev)21700d1677SRanjani Sridharan static u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
22700d1677SRanjani Sridharan {
23700d1677SRanjani Sridharan 	u32 target_dsp_state;
24700d1677SRanjani Sridharan 
25700d1677SRanjani Sridharan 	switch (sdev->system_suspend_target) {
269d2d4627SPierre-Louis Bossart 	case SOF_SUSPEND_S5:
279d2d4627SPierre-Louis Bossart 	case SOF_SUSPEND_S4:
289d2d4627SPierre-Louis Bossart 		/* DSP should be in D3 if the system is suspending to S3+ */
29700d1677SRanjani Sridharan 	case SOF_SUSPEND_S3:
30700d1677SRanjani Sridharan 		/* DSP should be in D3 if the system is suspending to S3 */
31700d1677SRanjani Sridharan 		target_dsp_state = SOF_DSP_PM_D3;
32700d1677SRanjani Sridharan 		break;
33700d1677SRanjani Sridharan 	case SOF_SUSPEND_S0IX:
34700d1677SRanjani Sridharan 		/*
35700d1677SRanjani Sridharan 		 * Currently, the only criterion for retaining the DSP in D0
36700d1677SRanjani Sridharan 		 * is that there are streams that ignored the suspend trigger.
37700d1677SRanjani Sridharan 		 * Additional criteria such Soundwire clock-stop mode and
38700d1677SRanjani Sridharan 		 * device suspend latency considerations will be added later.
39700d1677SRanjani Sridharan 		 */
40700d1677SRanjani Sridharan 		if (snd_sof_stream_suspend_ignored(sdev))
41700d1677SRanjani Sridharan 			target_dsp_state = SOF_DSP_PM_D0;
42700d1677SRanjani Sridharan 		else
43700d1677SRanjani Sridharan 			target_dsp_state = SOF_DSP_PM_D3;
44700d1677SRanjani Sridharan 		break;
45700d1677SRanjani Sridharan 	default:
46700d1677SRanjani Sridharan 		/* This case would be during runtime suspend */
47700d1677SRanjani Sridharan 		target_dsp_state = SOF_DSP_PM_D3;
48700d1677SRanjani Sridharan 		break;
49700d1677SRanjani Sridharan 	}
50700d1677SRanjani Sridharan 
51700d1677SRanjani Sridharan 	return target_dsp_state;
52700d1677SRanjani Sridharan }
53700d1677SRanjani Sridharan 
548920153cSLiam Girdwood #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
sof_cache_debugfs(struct snd_sof_dev * sdev)558920153cSLiam Girdwood static void sof_cache_debugfs(struct snd_sof_dev *sdev)
568920153cSLiam Girdwood {
578920153cSLiam Girdwood 	struct snd_sof_dfsentry *dfse;
588920153cSLiam Girdwood 
598920153cSLiam Girdwood 	list_for_each_entry(dfse, &sdev->dfsentry_list, list) {
608920153cSLiam Girdwood 
618920153cSLiam Girdwood 		/* nothing to do if debugfs buffer is not IO mem */
628920153cSLiam Girdwood 		if (dfse->type == SOF_DFSENTRY_TYPE_BUF)
638920153cSLiam Girdwood 			continue;
648920153cSLiam Girdwood 
658920153cSLiam Girdwood 		/* cache memory that is only accessible in D0 */
668920153cSLiam Girdwood 		if (dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY)
678920153cSLiam Girdwood 			memcpy_fromio(dfse->cache_buf, dfse->io_mem,
688920153cSLiam Girdwood 				      dfse->size);
698920153cSLiam Girdwood 	}
708920153cSLiam Girdwood }
718920153cSLiam Girdwood #endif
728920153cSLiam Girdwood 
sof_resume(struct device * dev,bool runtime_resume)738920153cSLiam Girdwood static int sof_resume(struct device *dev, bool runtime_resume)
748920153cSLiam Girdwood {
758920153cSLiam Girdwood 	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
76510758eeSPeter Ujfalusi 	const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
77510758eeSPeter Ujfalusi 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
7861e285caSRanjani Sridharan 	u32 old_state = sdev->dsp_power_state.state;
798920153cSLiam Girdwood 	int ret;
808920153cSLiam Girdwood 
818920153cSLiam Girdwood 	/* do nothing if dsp resume callbacks are not set */
82c26fde3bSDaniel Baluta 	if (!runtime_resume && !sof_ops(sdev)->resume)
83c26fde3bSDaniel Baluta 		return 0;
84c26fde3bSDaniel Baluta 
85c26fde3bSDaniel Baluta 	if (runtime_resume && !sof_ops(sdev)->runtime_resume)
868920153cSLiam Girdwood 		return 0;
878920153cSLiam Girdwood 
88410e5e55SPierre-Louis Bossart 	/* DSP was never successfully started, nothing to resume */
89410e5e55SPierre-Louis Bossart 	if (sdev->first_boot)
90410e5e55SPierre-Louis Bossart 		return 0;
91410e5e55SPierre-Louis Bossart 
928920153cSLiam Girdwood 	/*
938920153cSLiam Girdwood 	 * if the runtime_resume flag is set, call the runtime_resume routine
948920153cSLiam Girdwood 	 * or else call the system resume routine
958920153cSLiam Girdwood 	 */
968920153cSLiam Girdwood 	if (runtime_resume)
978920153cSLiam Girdwood 		ret = snd_sof_dsp_runtime_resume(sdev);
988920153cSLiam Girdwood 	else
998920153cSLiam Girdwood 		ret = snd_sof_dsp_resume(sdev);
1008920153cSLiam Girdwood 	if (ret < 0) {
1018920153cSLiam Girdwood 		dev_err(sdev->dev,
1028920153cSLiam Girdwood 			"error: failed to power up DSP after resume\n");
1038920153cSLiam Girdwood 		return ret;
1048920153cSLiam Girdwood 	}
1058920153cSLiam Girdwood 
10628d40e7aSPeter Ujfalusi 	if (sdev->dspless_mode_selected) {
10728d40e7aSPeter Ujfalusi 		sof_set_fw_state(sdev, SOF_DSPLESS_MODE);
10828d40e7aSPeter Ujfalusi 		return 0;
10928d40e7aSPeter Ujfalusi 	}
11028d40e7aSPeter Ujfalusi 
111fc907cc5SRanjani Sridharan 	/*
112fc907cc5SRanjani Sridharan 	 * Nothing further to be done for platforms that support the low power
113249ee180SLibin Yang 	 * D0 substate. Resume trace and return when resuming from
114249ee180SLibin Yang 	 * low-power D0 substate
115fc907cc5SRanjani Sridharan 	 */
116fc907cc5SRanjani Sridharan 	if (!runtime_resume && sof_ops(sdev)->set_power_state &&
117249ee180SLibin Yang 	    old_state == SOF_DSP_PM_D0) {
1181dedbe4fSPeter Ujfalusi 		ret = sof_fw_trace_resume(sdev);
119249ee180SLibin Yang 		if (ret < 0)
120249ee180SLibin Yang 			/* non fatal */
121249ee180SLibin Yang 			dev_warn(sdev->dev,
122249ee180SLibin Yang 				 "failed to enable trace after resume %d\n", ret);
123fb9a8119SRanjani Sridharan 		return 0;
124249ee180SLibin Yang 	}
125fb9a8119SRanjani Sridharan 
12658a5c9a4SPeter Ujfalusi 	sof_set_fw_state(sdev, SOF_FW_BOOT_PREPARE);
1276ca5cecbSRanjani Sridharan 
1288920153cSLiam Girdwood 	/* load the firmware */
1298920153cSLiam Girdwood 	ret = snd_sof_load_firmware(sdev);
1308920153cSLiam Girdwood 	if (ret < 0) {
1318920153cSLiam Girdwood 		dev_err(sdev->dev,
1328920153cSLiam Girdwood 			"error: failed to load DSP firmware after resume %d\n",
1338920153cSLiam Girdwood 			ret);
134e2406275SPeter Ujfalusi 		sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
1358920153cSLiam Girdwood 		return ret;
1368920153cSLiam Girdwood 	}
1378920153cSLiam Girdwood 
13858a5c9a4SPeter Ujfalusi 	sof_set_fw_state(sdev, SOF_FW_BOOT_IN_PROGRESS);
1396ca5cecbSRanjani Sridharan 
1406ca5cecbSRanjani Sridharan 	/*
1416ca5cecbSRanjani Sridharan 	 * Boot the firmware. The FW boot status will be modified
1426ca5cecbSRanjani Sridharan 	 * in snd_sof_run_firmware() depending on the outcome.
1436ca5cecbSRanjani Sridharan 	 */
1448920153cSLiam Girdwood 	ret = snd_sof_run_firmware(sdev);
1458920153cSLiam Girdwood 	if (ret < 0) {
1468920153cSLiam Girdwood 		dev_err(sdev->dev,
1478920153cSLiam Girdwood 			"error: failed to boot DSP firmware after resume %d\n",
1488920153cSLiam Girdwood 			ret);
149e2406275SPeter Ujfalusi 		sof_set_fw_state(sdev, SOF_FW_BOOT_FAILED);
1508920153cSLiam Girdwood 		return ret;
1518920153cSLiam Girdwood 	}
1528920153cSLiam Girdwood 
153758f24d4SLibin Yang 	/* resume DMA trace */
1541dedbe4fSPeter Ujfalusi 	ret = sof_fw_trace_resume(sdev);
1558920153cSLiam Girdwood 	if (ret < 0) {
1568920153cSLiam Girdwood 		/* non fatal */
1578920153cSLiam Girdwood 		dev_warn(sdev->dev,
1588920153cSLiam Girdwood 			 "warning: failed to init trace after resume %d\n",
1598920153cSLiam Girdwood 			 ret);
1608920153cSLiam Girdwood 	}
1618920153cSLiam Girdwood 
1628920153cSLiam Girdwood 	/* restore pipelines */
163510758eeSPeter Ujfalusi 	if (tplg_ops && tplg_ops->set_up_all_pipelines) {
16431cd6e46SRanjani Sridharan 		ret = tplg_ops->set_up_all_pipelines(sdev, false);
1658920153cSLiam Girdwood 		if (ret < 0) {
16631cd6e46SRanjani Sridharan 			dev_err(sdev->dev, "Failed to restore pipeline after resume %d\n", ret);
167*171b53beSKai Vehmanen 			goto setup_fail;
1688920153cSLiam Girdwood 		}
16931cd6e46SRanjani Sridharan 	}
1708920153cSLiam Girdwood 
1711069967aSPeter Ujfalusi 	/* Notify clients not managed by pm framework about core resume */
1721069967aSPeter Ujfalusi 	sof_resume_clients(sdev);
1731069967aSPeter Ujfalusi 
1748920153cSLiam Girdwood 	/* notify DSP of system resume */
175657774acSRanjani Sridharan 	if (pm_ops && pm_ops->ctx_restore) {
176657774acSRanjani Sridharan 		ret = pm_ops->ctx_restore(sdev);
1778920153cSLiam Girdwood 		if (ret < 0)
178657774acSRanjani Sridharan 			dev_err(sdev->dev, "ctx_restore IPC error during resume: %d\n", ret);
179657774acSRanjani Sridharan 	}
1808920153cSLiam Girdwood 
181*171b53beSKai Vehmanen setup_fail:
182*171b53beSKai Vehmanen #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
183*171b53beSKai Vehmanen 	if (ret < 0) {
184*171b53beSKai Vehmanen 		/*
185*171b53beSKai Vehmanen 		 * Debugfs cannot be read in runtime suspend, so cache
186*171b53beSKai Vehmanen 		 * the contents upon failure. This allows to capture
187*171b53beSKai Vehmanen 		 * possible DSP coredump information.
188*171b53beSKai Vehmanen 		 */
189*171b53beSKai Vehmanen 		sof_cache_debugfs(sdev);
190*171b53beSKai Vehmanen 	}
191*171b53beSKai Vehmanen #endif
192*171b53beSKai Vehmanen 
1938920153cSLiam Girdwood 	return ret;
1948920153cSLiam Girdwood }
1958920153cSLiam Girdwood 
sof_suspend(struct device * dev,bool runtime_suspend)1968920153cSLiam Girdwood static int sof_suspend(struct device *dev, bool runtime_suspend)
1978920153cSLiam Girdwood {
1988920153cSLiam Girdwood 	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
199510758eeSPeter Ujfalusi 	const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
200510758eeSPeter Ujfalusi 	const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
2011069967aSPeter Ujfalusi 	pm_message_t pm_state;
2026f95eec6SRanjani Sridharan 	u32 target_state = snd_sof_dsp_power_target(sdev);
2030b186bb0SDaniel Baluta 	u32 old_state = sdev->dsp_power_state.state;
2048920153cSLiam Girdwood 	int ret;
2058920153cSLiam Girdwood 
2068920153cSLiam Girdwood 	/* do nothing if dsp suspend callback is not set */
207c26fde3bSDaniel Baluta 	if (!runtime_suspend && !sof_ops(sdev)->suspend)
208c26fde3bSDaniel Baluta 		return 0;
209c26fde3bSDaniel Baluta 
210c26fde3bSDaniel Baluta 	if (runtime_suspend && !sof_ops(sdev)->runtime_suspend)
2118920153cSLiam Girdwood 		return 0;
2128920153cSLiam Girdwood 
2130b186bb0SDaniel Baluta 	/* we need to tear down pipelines only if the DSP hardware is
2140b186bb0SDaniel Baluta 	 * active, which happens for PCI devices. if the device is
2150b186bb0SDaniel Baluta 	 * suspended, it is brought back to full power and then
2160b186bb0SDaniel Baluta 	 * suspended again
2170b186bb0SDaniel Baluta 	 */
2180b186bb0SDaniel Baluta 	if (tplg_ops && tplg_ops->tear_down_all_pipelines && (old_state == SOF_DSP_PM_D0))
219d185e068SRanjani Sridharan 		tplg_ops->tear_down_all_pipelines(sdev, false);
220d185e068SRanjani Sridharan 
2216ca5cecbSRanjani Sridharan 	if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
222fb9a8119SRanjani Sridharan 		goto suspend;
2238920153cSLiam Girdwood 
224a1ce6e43SRanjani Sridharan 	/* prepare for streams to be resumed properly upon resume */
2257077a07aSRanjani Sridharan 	if (!runtime_suspend) {
2268e84b6a4SRanjani Sridharan 		ret = snd_sof_dsp_hw_params_upon_resume(sdev);
2277077a07aSRanjani Sridharan 		if (ret < 0) {
2287077a07aSRanjani Sridharan 			dev_err(sdev->dev,
2297077a07aSRanjani Sridharan 				"error: setting hw_params flag during suspend %d\n",
2307077a07aSRanjani Sridharan 				ret);
2317077a07aSRanjani Sridharan 			return ret;
2327077a07aSRanjani Sridharan 		}
2337077a07aSRanjani Sridharan 	}
2348920153cSLiam Girdwood 
2351069967aSPeter Ujfalusi 	pm_state.event = target_state;
236fb9a8119SRanjani Sridharan 
23761e285caSRanjani Sridharan 	/* suspend DMA trace */
2381069967aSPeter Ujfalusi 	sof_fw_trace_suspend(sdev, pm_state);
2391dedbe4fSPeter Ujfalusi 
2401069967aSPeter Ujfalusi 	/* Notify clients not managed by pm framework about core suspend */
2411069967aSPeter Ujfalusi 	sof_suspend_clients(sdev, pm_state);
242fb9a8119SRanjani Sridharan 
2431069967aSPeter Ujfalusi 	/* Skip to platform-specific suspend if DSP is entering D0 */
244fb9a8119SRanjani Sridharan 	if (target_state == SOF_DSP_PM_D0)
245758f24d4SLibin Yang 		goto suspend;
2461dedbe4fSPeter Ujfalusi 
247fb9a8119SRanjani Sridharan #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
2481069967aSPeter Ujfalusi 	/* cache debugfs contents during runtime suspend */
2491069967aSPeter Ujfalusi 	if (runtime_suspend)
2501069967aSPeter Ujfalusi 		sof_cache_debugfs(sdev);
2518920153cSLiam Girdwood #endif
2528920153cSLiam Girdwood 	/* notify DSP of upcoming power down */
2538920153cSLiam Girdwood 	if (pm_ops && pm_ops->ctx_save) {
2548920153cSLiam Girdwood 		ret = pm_ops->ctx_save(sdev);
2558920153cSLiam Girdwood 		if (ret == -EBUSY || ret == -EAGAIN) {
2568920153cSLiam Girdwood 			/*
257657774acSRanjani Sridharan 			 * runtime PM has logic to handle -EBUSY/-EAGAIN so
258657774acSRanjani Sridharan 			 * pass these errors up
259e2eba551SKai Vehmanen 			 */
260e2eba551SKai Vehmanen 			dev_err(sdev->dev, "ctx_save IPC error during suspend: %d\n", ret);
261e2eba551SKai Vehmanen 			return ret;
262e2eba551SKai Vehmanen 		} else if (ret < 0) {
263e2eba551SKai Vehmanen 			/* FW in unexpected state, continue to power down */
264657774acSRanjani Sridharan 			dev_warn(sdev->dev, "ctx_save IPC error: %d, proceeding with suspend\n",
2658920153cSLiam Girdwood 				 ret);
266e2eba551SKai Vehmanen 		}
267e2eba551SKai Vehmanen 	}
268657774acSRanjani Sridharan 
269e2eba551SKai Vehmanen suspend:
2708920153cSLiam Girdwood 
271657774acSRanjani Sridharan 	/* return if the DSP was not probed successfully */
2728920153cSLiam Girdwood 	if (sdev->fw_state == SOF_FW_BOOT_NOT_STARTED)
273fb9a8119SRanjani Sridharan 		return 0;
2746ca5cecbSRanjani Sridharan 
2756ca5cecbSRanjani Sridharan 	/* platform-specific suspend */
2766ca5cecbSRanjani Sridharan 	if (runtime_suspend)
2776ca5cecbSRanjani Sridharan 		ret = snd_sof_dsp_runtime_suspend(sdev);
2786ca5cecbSRanjani Sridharan 	else
279fb9a8119SRanjani Sridharan 		ret = snd_sof_dsp_suspend(sdev, target_state);
2808920153cSLiam Girdwood 	if (ret < 0)
2811c38c922SFred Oh 		dev_err(sdev->dev,
2828920153cSLiam Girdwood 			"error: failed to power down DSP during suspend %d\n",
28361e285caSRanjani Sridharan 			ret);
2848920153cSLiam Girdwood 
2858920153cSLiam Girdwood 	/* Do not reset FW state if DSP is in D0 */
2868920153cSLiam Girdwood 	if (target_state == SOF_DSP_PM_D0)
2878920153cSLiam Girdwood 		return ret;
2888920153cSLiam Girdwood 
28961e285caSRanjani Sridharan 	/* reset FW state */
29061e285caSRanjani Sridharan 	sof_set_fw_state(sdev, SOF_FW_BOOT_NOT_STARTED);
291fb9a8119SRanjani Sridharan 	sdev->enabled_cores_mask = 0;
292fb9a8119SRanjani Sridharan 
2936ca5cecbSRanjani Sridharan 	return ret;
29458a5c9a4SPeter Ujfalusi }
295b640e8a4SKai Vehmanen 
snd_sof_dsp_power_down_notify(struct snd_sof_dev * sdev)2966ca5cecbSRanjani Sridharan int snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev)
2978920153cSLiam Girdwood {
2988920153cSLiam Girdwood 	const struct sof_ipc_pm_ops *pm_ops = sof_ipc_get_ops(sdev, pm);
2998920153cSLiam Girdwood 
3003541aef1SMarcin Rajwa 	/* Notify DSP of upcoming power down */
3013541aef1SMarcin Rajwa 	if (sof_ops(sdev)->remove && pm_ops && pm_ops->ctx_save)
302510758eeSPeter Ujfalusi 		return pm_ops->ctx_save(sdev);
303657774acSRanjani Sridharan 
3043541aef1SMarcin Rajwa 	return 0;
305657774acSRanjani Sridharan }
306657774acSRanjani Sridharan 
snd_sof_runtime_suspend(struct device * dev)3073541aef1SMarcin Rajwa int snd_sof_runtime_suspend(struct device *dev)
3083541aef1SMarcin Rajwa {
3093541aef1SMarcin Rajwa 	return sof_suspend(dev, true);
3103541aef1SMarcin Rajwa }
3118920153cSLiam Girdwood EXPORT_SYMBOL(snd_sof_runtime_suspend);
3128920153cSLiam Girdwood 
snd_sof_runtime_idle(struct device * dev)3138920153cSLiam Girdwood int snd_sof_runtime_idle(struct device *dev)
3148920153cSLiam Girdwood {
3158920153cSLiam Girdwood 	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
3168920153cSLiam Girdwood 
31762fde977SKai Vehmanen 	return snd_sof_dsp_runtime_idle(sdev);
31862fde977SKai Vehmanen }
31962fde977SKai Vehmanen EXPORT_SYMBOL(snd_sof_runtime_idle);
32062fde977SKai Vehmanen 
snd_sof_runtime_resume(struct device * dev)32162fde977SKai Vehmanen int snd_sof_runtime_resume(struct device *dev)
32262fde977SKai Vehmanen {
32362fde977SKai Vehmanen 	return sof_resume(dev, true);
32462fde977SKai Vehmanen }
3258920153cSLiam Girdwood EXPORT_SYMBOL(snd_sof_runtime_resume);
3268920153cSLiam Girdwood 
snd_sof_resume(struct device * dev)3278920153cSLiam Girdwood int snd_sof_resume(struct device *dev)
3288920153cSLiam Girdwood {
3298920153cSLiam Girdwood 	return sof_resume(dev, false);
3308920153cSLiam Girdwood }
3318920153cSLiam Girdwood EXPORT_SYMBOL(snd_sof_resume);
3328920153cSLiam Girdwood 
snd_sof_suspend(struct device * dev)3338920153cSLiam Girdwood int snd_sof_suspend(struct device *dev)
3348920153cSLiam Girdwood {
3358920153cSLiam Girdwood 	return sof_suspend(dev, false);
3368920153cSLiam Girdwood }
3378920153cSLiam Girdwood EXPORT_SYMBOL(snd_sof_suspend);
3388920153cSLiam Girdwood 
snd_sof_prepare(struct device * dev)3398920153cSLiam Girdwood int snd_sof_prepare(struct device *dev)
3408920153cSLiam Girdwood {
3418920153cSLiam Girdwood 	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
3420b50b3b1SKeyon Jie 	const struct sof_dev_desc *desc = sdev->pdata->desc;
3430b50b3b1SKeyon Jie 
3440b50b3b1SKeyon Jie 	/* will suspend to S3 by default */
3450b50b3b1SKeyon Jie 	sdev->system_suspend_target = SOF_SUSPEND_S3;
34643437d04SDaniel Baluta 
34743437d04SDaniel Baluta 	/*
34843437d04SDaniel Baluta 	 * if the firmware is crashed or boot failed then we try to aim for S3
34943437d04SDaniel Baluta 	 * to reboot the firmware
35043437d04SDaniel Baluta 	 */
3514e1f8648SPeter Ujfalusi 	if (sdev->fw_state == SOF_FW_CRASHED ||
352b54b3a4eSPeter Ujfalusi 	    sdev->fw_state == SOF_FW_BOOT_FAILED)
353b54b3a4eSPeter Ujfalusi 		return 0;
3544e1f8648SPeter Ujfalusi 
355b54b3a4eSPeter Ujfalusi 	if (!desc->use_acpi_target_states)
356b54b3a4eSPeter Ujfalusi 		return 0;
3574e1f8648SPeter Ujfalusi 
3584e1f8648SPeter Ujfalusi #if defined(CONFIG_ACPI)
35943437d04SDaniel Baluta 	switch (acpi_target_system_state()) {
36043437d04SDaniel Baluta 	case ACPI_STATE_S0:
3610b50b3b1SKeyon Jie 		sdev->system_suspend_target = SOF_SUSPEND_S0IX;
3620b50b3b1SKeyon Jie 		break;
363a9330845SPierre-Louis Bossart 	case ACPI_STATE_S1:
364a9330845SPierre-Louis Bossart 	case ACPI_STATE_S2:
365043ae13bSRanjani Sridharan 	case ACPI_STATE_S3:
366a9330845SPierre-Louis Bossart 		sdev->system_suspend_target = SOF_SUSPEND_S3;
367a9330845SPierre-Louis Bossart 		break;
368a9330845SPierre-Louis Bossart 	case ACPI_STATE_S4:
369a9330845SPierre-Louis Bossart 		sdev->system_suspend_target = SOF_SUSPEND_S4;
370a9330845SPierre-Louis Bossart 		break;
371a9330845SPierre-Louis Bossart 	case ACPI_STATE_S5:
3729d2d4627SPierre-Louis Bossart 		sdev->system_suspend_target = SOF_SUSPEND_S5;
3739d2d4627SPierre-Louis Bossart 		break;
3749d2d4627SPierre-Louis Bossart 	default:
3759d2d4627SPierre-Louis Bossart 		break;
3769d2d4627SPierre-Louis Bossart 	}
3779d2d4627SPierre-Louis Bossart #endif
378a9330845SPierre-Louis Bossart 
379a9330845SPierre-Louis Bossart 	return 0;
380a9330845SPierre-Louis Bossart }
3810b50b3b1SKeyon Jie EXPORT_SYMBOL(snd_sof_prepare);
3820b50b3b1SKeyon Jie 
snd_sof_complete(struct device * dev)3830b50b3b1SKeyon Jie void snd_sof_complete(struct device *dev)
3840b50b3b1SKeyon Jie {
3850b50b3b1SKeyon Jie 	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
3860b50b3b1SKeyon Jie 
3870b50b3b1SKeyon Jie 	sdev->system_suspend_target = SOF_SUSPEND_NONE;
3880b50b3b1SKeyon Jie }
3890b50b3b1SKeyon Jie EXPORT_SYMBOL(snd_sof_complete);
3900b50b3b1SKeyon Jie