xref: /kernel/linux/linux-5.10/sound/soc/sof/pm.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// This file is provided under a dual BSD/GPLv2 license.  When using or
48c2ecf20Sopenharmony_ci// redistributing this file, you may do so under either license.
58c2ecf20Sopenharmony_ci//
68c2ecf20Sopenharmony_ci// Copyright(c) 2018 Intel Corporation. All rights reserved.
78c2ecf20Sopenharmony_ci//
88c2ecf20Sopenharmony_ci// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
98c2ecf20Sopenharmony_ci//
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "ops.h"
128c2ecf20Sopenharmony_ci#include "sof-priv.h"
138c2ecf20Sopenharmony_ci#include "sof-audio.h"
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/*
168c2ecf20Sopenharmony_ci * Helper function to determine the target DSP state during
178c2ecf20Sopenharmony_ci * system suspend. This function only cares about the device
188c2ecf20Sopenharmony_ci * D-states. Platform-specific substates, if any, should be
198c2ecf20Sopenharmony_ci * handled by the platform-specific parts.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_cistatic u32 snd_sof_dsp_power_target(struct snd_sof_dev *sdev)
228c2ecf20Sopenharmony_ci{
238c2ecf20Sopenharmony_ci	u32 target_dsp_state;
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci	switch (sdev->system_suspend_target) {
268c2ecf20Sopenharmony_ci	case SOF_SUSPEND_S3:
278c2ecf20Sopenharmony_ci		/* DSP should be in D3 if the system is suspending to S3 */
288c2ecf20Sopenharmony_ci		target_dsp_state = SOF_DSP_PM_D3;
298c2ecf20Sopenharmony_ci		break;
308c2ecf20Sopenharmony_ci	case SOF_SUSPEND_S0IX:
318c2ecf20Sopenharmony_ci		/*
328c2ecf20Sopenharmony_ci		 * Currently, the only criterion for retaining the DSP in D0
338c2ecf20Sopenharmony_ci		 * is that there are streams that ignored the suspend trigger.
348c2ecf20Sopenharmony_ci		 * Additional criteria such Soundwire clock-stop mode and
358c2ecf20Sopenharmony_ci		 * device suspend latency considerations will be added later.
368c2ecf20Sopenharmony_ci		 */
378c2ecf20Sopenharmony_ci		if (snd_sof_stream_suspend_ignored(sdev))
388c2ecf20Sopenharmony_ci			target_dsp_state = SOF_DSP_PM_D0;
398c2ecf20Sopenharmony_ci		else
408c2ecf20Sopenharmony_ci			target_dsp_state = SOF_DSP_PM_D3;
418c2ecf20Sopenharmony_ci		break;
428c2ecf20Sopenharmony_ci	default:
438c2ecf20Sopenharmony_ci		/* This case would be during runtime suspend */
448c2ecf20Sopenharmony_ci		target_dsp_state = SOF_DSP_PM_D3;
458c2ecf20Sopenharmony_ci		break;
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	return target_dsp_state;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic int sof_send_pm_ctx_ipc(struct snd_sof_dev *sdev, int cmd)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	struct sof_ipc_pm_ctx pm_ctx;
548c2ecf20Sopenharmony_ci	struct sof_ipc_reply reply;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	memset(&pm_ctx, 0, sizeof(pm_ctx));
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	/* configure ctx save ipc message */
598c2ecf20Sopenharmony_ci	pm_ctx.hdr.size = sizeof(pm_ctx);
608c2ecf20Sopenharmony_ci	pm_ctx.hdr.cmd = SOF_IPC_GLB_PM_MSG | cmd;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	/* send ctx save ipc to dsp */
638c2ecf20Sopenharmony_ci	return sof_ipc_tx_message(sdev->ipc, pm_ctx.hdr.cmd, &pm_ctx,
648c2ecf20Sopenharmony_ci				 sizeof(pm_ctx), &reply, sizeof(reply));
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
688c2ecf20Sopenharmony_cistatic void sof_cache_debugfs(struct snd_sof_dev *sdev)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	struct snd_sof_dfsentry *dfse;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	list_for_each_entry(dfse, &sdev->dfsentry_list, list) {
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		/* nothing to do if debugfs buffer is not IO mem */
758c2ecf20Sopenharmony_ci		if (dfse->type == SOF_DFSENTRY_TYPE_BUF)
768c2ecf20Sopenharmony_ci			continue;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		/* cache memory that is only accessible in D0 */
798c2ecf20Sopenharmony_ci		if (dfse->access_type == SOF_DEBUGFS_ACCESS_D0_ONLY)
808c2ecf20Sopenharmony_ci			memcpy_fromio(dfse->cache_buf, dfse->io_mem,
818c2ecf20Sopenharmony_ci				      dfse->size);
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci#endif
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cistatic int sof_resume(struct device *dev, bool runtime_resume)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
898c2ecf20Sopenharmony_ci	u32 old_state = sdev->dsp_power_state.state;
908c2ecf20Sopenharmony_ci	int ret;
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* do nothing if dsp resume callbacks are not set */
938c2ecf20Sopenharmony_ci	if (!runtime_resume && !sof_ops(sdev)->resume)
948c2ecf20Sopenharmony_ci		return 0;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (runtime_resume && !sof_ops(sdev)->runtime_resume)
978c2ecf20Sopenharmony_ci		return 0;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* DSP was never successfully started, nothing to resume */
1008c2ecf20Sopenharmony_ci	if (sdev->first_boot)
1018c2ecf20Sopenharmony_ci		return 0;
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	/*
1048c2ecf20Sopenharmony_ci	 * if the runtime_resume flag is set, call the runtime_resume routine
1058c2ecf20Sopenharmony_ci	 * or else call the system resume routine
1068c2ecf20Sopenharmony_ci	 */
1078c2ecf20Sopenharmony_ci	if (runtime_resume)
1088c2ecf20Sopenharmony_ci		ret = snd_sof_dsp_runtime_resume(sdev);
1098c2ecf20Sopenharmony_ci	else
1108c2ecf20Sopenharmony_ci		ret = snd_sof_dsp_resume(sdev);
1118c2ecf20Sopenharmony_ci	if (ret < 0) {
1128c2ecf20Sopenharmony_ci		dev_err(sdev->dev,
1138c2ecf20Sopenharmony_ci			"error: failed to power up DSP after resume\n");
1148c2ecf20Sopenharmony_ci		return ret;
1158c2ecf20Sopenharmony_ci	}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	/*
1188c2ecf20Sopenharmony_ci	 * Nothing further to be done for platforms that support the low power
1198c2ecf20Sopenharmony_ci	 * D0 substate.
1208c2ecf20Sopenharmony_ci	 */
1218c2ecf20Sopenharmony_ci	if (!runtime_resume && sof_ops(sdev)->set_power_state &&
1228c2ecf20Sopenharmony_ci	    old_state == SOF_DSP_PM_D0)
1238c2ecf20Sopenharmony_ci		return 0;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	sdev->fw_state = SOF_FW_BOOT_PREPARE;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	/* load the firmware */
1288c2ecf20Sopenharmony_ci	ret = snd_sof_load_firmware(sdev);
1298c2ecf20Sopenharmony_ci	if (ret < 0) {
1308c2ecf20Sopenharmony_ci		dev_err(sdev->dev,
1318c2ecf20Sopenharmony_ci			"error: failed to load DSP firmware after resume %d\n",
1328c2ecf20Sopenharmony_ci			ret);
1338c2ecf20Sopenharmony_ci		return ret;
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	sdev->fw_state = SOF_FW_BOOT_IN_PROGRESS;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	/*
1398c2ecf20Sopenharmony_ci	 * Boot the firmware. The FW boot status will be modified
1408c2ecf20Sopenharmony_ci	 * in snd_sof_run_firmware() depending on the outcome.
1418c2ecf20Sopenharmony_ci	 */
1428c2ecf20Sopenharmony_ci	ret = snd_sof_run_firmware(sdev);
1438c2ecf20Sopenharmony_ci	if (ret < 0) {
1448c2ecf20Sopenharmony_ci		dev_err(sdev->dev,
1458c2ecf20Sopenharmony_ci			"error: failed to boot DSP firmware after resume %d\n",
1468c2ecf20Sopenharmony_ci			ret);
1478c2ecf20Sopenharmony_ci		return ret;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	/* resume DMA trace, only need send ipc */
1518c2ecf20Sopenharmony_ci	ret = snd_sof_init_trace_ipc(sdev);
1528c2ecf20Sopenharmony_ci	if (ret < 0) {
1538c2ecf20Sopenharmony_ci		/* non fatal */
1548c2ecf20Sopenharmony_ci		dev_warn(sdev->dev,
1558c2ecf20Sopenharmony_ci			 "warning: failed to init trace after resume %d\n",
1568c2ecf20Sopenharmony_ci			 ret);
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	/* restore pipelines */
1608c2ecf20Sopenharmony_ci	ret = sof_restore_pipelines(sdev->dev);
1618c2ecf20Sopenharmony_ci	if (ret < 0) {
1628c2ecf20Sopenharmony_ci		dev_err(sdev->dev,
1638c2ecf20Sopenharmony_ci			"error: failed to restore pipeline after resume %d\n",
1648c2ecf20Sopenharmony_ci			ret);
1658c2ecf20Sopenharmony_ci		return ret;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	/* notify DSP of system resume */
1698c2ecf20Sopenharmony_ci	ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_RESTORE);
1708c2ecf20Sopenharmony_ci	if (ret < 0)
1718c2ecf20Sopenharmony_ci		dev_err(sdev->dev,
1728c2ecf20Sopenharmony_ci			"error: ctx_restore ipc error during resume %d\n",
1738c2ecf20Sopenharmony_ci			ret);
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	return ret;
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic int sof_suspend(struct device *dev, bool runtime_suspend)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
1818c2ecf20Sopenharmony_ci	u32 target_state = 0;
1828c2ecf20Sopenharmony_ci	int ret;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	/* do nothing if dsp suspend callback is not set */
1858c2ecf20Sopenharmony_ci	if (!runtime_suspend && !sof_ops(sdev)->suspend)
1868c2ecf20Sopenharmony_ci		return 0;
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	if (runtime_suspend && !sof_ops(sdev)->runtime_suspend)
1898c2ecf20Sopenharmony_ci		return 0;
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	if (sdev->fw_state != SOF_FW_BOOT_COMPLETE)
1928c2ecf20Sopenharmony_ci		goto suspend;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/* set restore_stream for all streams during system suspend */
1958c2ecf20Sopenharmony_ci	if (!runtime_suspend) {
1968c2ecf20Sopenharmony_ci		ret = sof_set_hw_params_upon_resume(sdev->dev);
1978c2ecf20Sopenharmony_ci		if (ret < 0) {
1988c2ecf20Sopenharmony_ci			dev_err(sdev->dev,
1998c2ecf20Sopenharmony_ci				"error: setting hw_params flag during suspend %d\n",
2008c2ecf20Sopenharmony_ci				ret);
2018c2ecf20Sopenharmony_ci			return ret;
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci	}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	target_state = snd_sof_dsp_power_target(sdev);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	/* Skip to platform-specific suspend if DSP is entering D0 */
2088c2ecf20Sopenharmony_ci	if (target_state == SOF_DSP_PM_D0)
2098c2ecf20Sopenharmony_ci		goto suspend;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/* release trace */
2128c2ecf20Sopenharmony_ci	snd_sof_release_trace(sdev);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_ENABLE_DEBUGFS_CACHE)
2158c2ecf20Sopenharmony_ci	/* cache debugfs contents during runtime suspend */
2168c2ecf20Sopenharmony_ci	if (runtime_suspend)
2178c2ecf20Sopenharmony_ci		sof_cache_debugfs(sdev);
2188c2ecf20Sopenharmony_ci#endif
2198c2ecf20Sopenharmony_ci	/* notify DSP of upcoming power down */
2208c2ecf20Sopenharmony_ci	ret = sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
2218c2ecf20Sopenharmony_ci	if (ret == -EBUSY || ret == -EAGAIN) {
2228c2ecf20Sopenharmony_ci		/*
2238c2ecf20Sopenharmony_ci		 * runtime PM has logic to handle -EBUSY/-EAGAIN so
2248c2ecf20Sopenharmony_ci		 * pass these errors up
2258c2ecf20Sopenharmony_ci		 */
2268c2ecf20Sopenharmony_ci		dev_err(sdev->dev,
2278c2ecf20Sopenharmony_ci			"error: ctx_save ipc error during suspend %d\n",
2288c2ecf20Sopenharmony_ci			ret);
2298c2ecf20Sopenharmony_ci		return ret;
2308c2ecf20Sopenharmony_ci	} else if (ret < 0) {
2318c2ecf20Sopenharmony_ci		/* FW in unexpected state, continue to power down */
2328c2ecf20Sopenharmony_ci		dev_warn(sdev->dev,
2338c2ecf20Sopenharmony_ci			 "ctx_save ipc error %d, proceeding with suspend\n",
2348c2ecf20Sopenharmony_ci			 ret);
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cisuspend:
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	/* return if the DSP was not probed successfully */
2408c2ecf20Sopenharmony_ci	if (sdev->fw_state == SOF_FW_BOOT_NOT_STARTED)
2418c2ecf20Sopenharmony_ci		return 0;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/* platform-specific suspend */
2448c2ecf20Sopenharmony_ci	if (runtime_suspend)
2458c2ecf20Sopenharmony_ci		ret = snd_sof_dsp_runtime_suspend(sdev);
2468c2ecf20Sopenharmony_ci	else
2478c2ecf20Sopenharmony_ci		ret = snd_sof_dsp_suspend(sdev, target_state);
2488c2ecf20Sopenharmony_ci	if (ret < 0)
2498c2ecf20Sopenharmony_ci		dev_err(sdev->dev,
2508c2ecf20Sopenharmony_ci			"error: failed to power down DSP during suspend %d\n",
2518c2ecf20Sopenharmony_ci			ret);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	/* Do not reset FW state if DSP is in D0 */
2548c2ecf20Sopenharmony_ci	if (target_state == SOF_DSP_PM_D0)
2558c2ecf20Sopenharmony_ci		return ret;
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	/* reset FW state */
2588c2ecf20Sopenharmony_ci	sdev->fw_state = SOF_FW_BOOT_NOT_STARTED;
2598c2ecf20Sopenharmony_ci	sdev->enabled_cores_mask = 0;
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	return ret;
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ciint snd_sof_dsp_power_down_notify(struct snd_sof_dev *sdev)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	/* Notify DSP of upcoming power down */
2678c2ecf20Sopenharmony_ci	if (sof_ops(sdev)->remove)
2688c2ecf20Sopenharmony_ci		return sof_send_pm_ctx_ipc(sdev, SOF_IPC_PM_CTX_SAVE);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	return 0;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ciint snd_sof_runtime_suspend(struct device *dev)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	return sof_suspend(dev, true);
2768c2ecf20Sopenharmony_ci}
2778c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_runtime_suspend);
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ciint snd_sof_runtime_idle(struct device *dev)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	return snd_sof_dsp_runtime_idle(sdev);
2848c2ecf20Sopenharmony_ci}
2858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_runtime_idle);
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ciint snd_sof_runtime_resume(struct device *dev)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	return sof_resume(dev, true);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_runtime_resume);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ciint snd_sof_resume(struct device *dev)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	return sof_resume(dev, false);
2968c2ecf20Sopenharmony_ci}
2978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_resume);
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ciint snd_sof_suspend(struct device *dev)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	return sof_suspend(dev, false);
3028c2ecf20Sopenharmony_ci}
3038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_suspend);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ciint snd_sof_prepare(struct device *dev)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
3088c2ecf20Sopenharmony_ci	const struct sof_dev_desc *desc = sdev->pdata->desc;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/* will suspend to S3 by default */
3118c2ecf20Sopenharmony_ci	sdev->system_suspend_target = SOF_SUSPEND_S3;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	if (!desc->use_acpi_target_states)
3148c2ecf20Sopenharmony_ci		return 0;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci#if defined(CONFIG_ACPI)
3178c2ecf20Sopenharmony_ci	if (acpi_target_system_state() == ACPI_STATE_S0)
3188c2ecf20Sopenharmony_ci		sdev->system_suspend_target = SOF_SUSPEND_S0IX;
3198c2ecf20Sopenharmony_ci#endif
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return 0;
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_prepare);
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_civoid snd_sof_complete(struct device *dev)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	struct snd_sof_dev *sdev = dev_get_drvdata(dev);
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	sdev->system_suspend_target = SOF_SUSPEND_NONE;
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ciEXPORT_SYMBOL(snd_sof_complete);
332