xref: /openbmc/linux/sound/soc/sof/intel/hda-dai.c (revision 80afde34)
1e149ca29SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2fdd961e3SKeyon Jie //
3fdd961e3SKeyon Jie // This file is provided under a dual BSD/GPLv2 license.  When using or
4fdd961e3SKeyon Jie // redistributing this file, you may do so under either license.
5fdd961e3SKeyon Jie //
6fdd961e3SKeyon Jie // Copyright(c) 2018 Intel Corporation. All rights reserved.
7fdd961e3SKeyon Jie //
8fdd961e3SKeyon Jie // Authors: Keyon Jie <yang.jie@linux.intel.com>
9fdd961e3SKeyon Jie //
10fdd961e3SKeyon Jie 
11fdd961e3SKeyon Jie #include <sound/pcm_params.h>
12fdd961e3SKeyon Jie #include <sound/hdaudio_ext.h>
131da51943SRanjani Sridharan #include <sound/intel-nhlt.h>
144c30004aSRanjani Sridharan #include <sound/sof/ipc4/header.h>
154c30004aSRanjani Sridharan #include <uapi/sound/sof/header.h>
164c30004aSRanjani Sridharan #include "../ipc4-priv.h"
174c30004aSRanjani Sridharan #include "../ipc4-topology.h"
18fdd961e3SKeyon Jie #include "../sof-priv.h"
19ee1e79b7SRanjani Sridharan #include "../sof-audio.h"
20fdd961e3SKeyon Jie #include "hda.h"
21fdd961e3SKeyon Jie 
221da51943SRanjani Sridharan /*
231da51943SRanjani Sridharan  * The default method is to fetch NHLT from BIOS. With this parameter set
241da51943SRanjani Sridharan  * it is possible to override that with NHLT in the SOF topology manifest.
251da51943SRanjani Sridharan  */
261da51943SRanjani Sridharan static bool hda_use_tplg_nhlt;
271da51943SRanjani Sridharan module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
281da51943SRanjani Sridharan MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
291da51943SRanjani Sridharan 
30a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
31fdd961e3SKeyon Jie 
32*80afde34SRanjani Sridharan static const struct hda_dai_widget_dma_ops *
33*80afde34SRanjani Sridharan hda_dai_get_ops(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
34fdd961e3SKeyon Jie {
35*80afde34SRanjani Sridharan 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
36*80afde34SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
37*80afde34SRanjani Sridharan 	struct snd_sof_widget *swidget = w->dobj.private;
38*80afde34SRanjani Sridharan 	struct snd_sof_dai *sdai = swidget->private;
39fdd961e3SKeyon Jie 
40*80afde34SRanjani Sridharan 	/* select and set the DAI widget ops if not set already */
41*80afde34SRanjani Sridharan 	if (!sdai->platform_private) {
42*80afde34SRanjani Sridharan 		const struct hda_dai_widget_dma_ops *ops =
43*80afde34SRanjani Sridharan 			hda_select_dai_widget_ops(sdev, swidget);
44fdd961e3SKeyon Jie 
45*80afde34SRanjani Sridharan 		if (!ops)
46bdf4ad3fSRanjani Sridharan 			return NULL;
47*80afde34SRanjani Sridharan 
48*80afde34SRanjani Sridharan 		/* check if mandatory ops are set */
49*80afde34SRanjani Sridharan 		if (!ops || !ops->get_hext_stream)
50*80afde34SRanjani Sridharan 			return NULL;
51*80afde34SRanjani Sridharan 
52*80afde34SRanjani Sridharan 		sdai->platform_private = ops;
53fdd961e3SKeyon Jie 	}
54fdd961e3SKeyon Jie 
55*80afde34SRanjani Sridharan 	return sdai->platform_private;
56fdd961e3SKeyon Jie }
57fdd961e3SKeyon Jie 
58880924caSPierre-Louis Bossart static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
590351a9b8SPierre-Louis Bossart 				struct hdac_ext_stream *hext_stream,
60880924caSPierre-Louis Bossart 				struct snd_soc_dai *cpu_dai,
612be2caf4SRanjani Sridharan 				struct snd_soc_dai *codec_dai)
62880924caSPierre-Louis Bossart {
63*80afde34SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
64*80afde34SRanjani Sridharan 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
650351a9b8SPierre-Louis Bossart 	struct hdac_stream *hstream = &hext_stream->hstream;
66880924caSPierre-Louis Bossart 	struct hdac_bus *bus = hstream->bus;
67880924caSPierre-Louis Bossart 	struct sof_intel_hda_stream *hda_stream;
687f1e16aeSPierre-Louis Bossart 	struct hdac_ext_link *hlink;
69880924caSPierre-Louis Bossart 	int stream_tag;
70880924caSPierre-Louis Bossart 
71b0cd60f3SPierre-Louis Bossart 	hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
727f1e16aeSPierre-Louis Bossart 	if (!hlink)
73880924caSPierre-Louis Bossart 		return -EINVAL;
74880924caSPierre-Louis Bossart 
75880924caSPierre-Louis Bossart 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
76880924caSPierre-Louis Bossart 		stream_tag = hdac_stream(hext_stream)->stream_tag;
777fa403f2SPierre-Louis Bossart 		snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
78880924caSPierre-Louis Bossart 	}
79*80afde34SRanjani Sridharan 
80*80afde34SRanjani Sridharan 	if (ops->release_hext_stream)
81*80afde34SRanjani Sridharan 		ops->release_hext_stream(sdev, cpu_dai, substream);
82*80afde34SRanjani Sridharan 
83880924caSPierre-Louis Bossart 	hext_stream->link_prepared = 0;
84880924caSPierre-Louis Bossart 
85880924caSPierre-Louis Bossart 	/* free the host DMA channel reserved by hostless streams */
86880924caSPierre-Louis Bossart 	hda_stream = hstream_to_sof_hda_stream(hext_stream);
87880924caSPierre-Louis Bossart 	hda_stream->host_reserved = 0;
88880924caSPierre-Louis Bossart 
89880924caSPierre-Louis Bossart 	return 0;
90880924caSPierre-Louis Bossart }
91880924caSPierre-Louis Bossart 
92f321ffc8SPierre-Louis Bossart static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
93b436ed8dSRanjani Sridharan 				  struct snd_pcm_hw_params *params, struct snd_soc_dai *cpu_dai)
94fdd961e3SKeyon Jie {
95*80afde34SRanjani Sridharan 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
961205300aSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
97be3e8de7SKuninori Morimoto 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
984842f79fSPierre-Louis Bossart 	struct hdac_ext_stream *hext_stream;
99a8310c00SRanjani Sridharan 	struct hdac_stream *hstream;
1007f1e16aeSPierre-Louis Bossart 	struct hdac_ext_link *hlink;
1014842f79fSPierre-Louis Bossart 	struct snd_sof_dev *sdev;
1024842f79fSPierre-Louis Bossart 	struct hdac_bus *bus;
103a8310c00SRanjani Sridharan 	unsigned int format_val;
1042a6afac2SRanjani Sridharan 	unsigned int link_bps;
105*80afde34SRanjani Sridharan 	int stream_tag;
1064842f79fSPierre-Louis Bossart 
1074842f79fSPierre-Louis Bossart 	sdev = snd_soc_component_get_drvdata(cpu_dai->component);
1084842f79fSPierre-Louis Bossart 	bus = sof_to_bus(sdev);
109fdd961e3SKeyon Jie 
1101f810d2bSPierre-Louis Bossart 	hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
1111f810d2bSPierre-Louis Bossart 	if (!hlink)
1121f810d2bSPierre-Louis Bossart 		return -EINVAL;
1131f810d2bSPierre-Louis Bossart 
114*80afde34SRanjani Sridharan 	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
115*80afde34SRanjani Sridharan 
1167d88b960SPierre-Louis Bossart 	if (!hext_stream) {
117*80afde34SRanjani Sridharan 		if (ops->assign_hext_stream)
118*80afde34SRanjani Sridharan 			hext_stream = ops->assign_hext_stream(sdev, cpu_dai, substream);
119*80afde34SRanjani Sridharan 	}
120*80afde34SRanjani Sridharan 
1217d88b960SPierre-Louis Bossart 	if (!hext_stream)
122bdf4ad3fSRanjani Sridharan 		return -EBUSY;
123921162c8SPierre-Louis Bossart 
124a8310c00SRanjani Sridharan 	hstream = &hext_stream->hstream;
125a8310c00SRanjani Sridharan 	stream_tag = hstream->stream_tag;
126a8310c00SRanjani Sridharan 
1272a6afac2SRanjani Sridharan 	if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK)
1282a6afac2SRanjani Sridharan 		snd_hdac_ext_bus_link_set_stream_id(hlink, stream_tag);
1292a6afac2SRanjani Sridharan 
13063611041SPierre-Louis Bossart 	/* set the hdac_stream in the codec dai */
1317d88b960SPierre-Louis Bossart 	snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream);
132fdd961e3SKeyon Jie 
133fdd961e3SKeyon Jie 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
1342a6afac2SRanjani Sridharan 		link_bps = codec_dai->driver->playback.sig_bits;
135fdd961e3SKeyon Jie 	else
1362a6afac2SRanjani Sridharan 		link_bps = codec_dai->driver->capture.sig_bits;
137fdd961e3SKeyon Jie 
138a8310c00SRanjani Sridharan 	snd_hdac_ext_stream_reset(hext_stream);
139a8310c00SRanjani Sridharan 
1402a6afac2SRanjani Sridharan 	format_val = snd_hdac_calc_stream_format(params_rate(params), params_channels(params),
1412a6afac2SRanjani Sridharan 						 params_format(params), link_bps, 0);
142a8310c00SRanjani Sridharan 
143a8310c00SRanjani Sridharan 	dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
1442a6afac2SRanjani Sridharan 		format_val, params_rate(params), params_channels(params), params_format(params));
145a8310c00SRanjani Sridharan 
146a8310c00SRanjani Sridharan 	snd_hdac_ext_stream_setup(hext_stream, format_val);
147a8310c00SRanjani Sridharan 
148a8310c00SRanjani Sridharan 	hext_stream->link_prepared = 1;
149a8310c00SRanjani Sridharan 
150a8310c00SRanjani Sridharan 	return 0;
151fdd961e3SKeyon Jie }
152fdd961e3SKeyon Jie 
153b436ed8dSRanjani Sridharan static int hda_link_dma_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
154f321ffc8SPierre-Louis Bossart {
1551205300aSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
156fdd961e3SKeyon Jie 	int stream = substream->stream;
157fdd961e3SKeyon Jie 
158b436ed8dSRanjani Sridharan 	return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params, cpu_dai);
159fdd961e3SKeyon Jie }
160fdd961e3SKeyon Jie 
161b436ed8dSRanjani Sridharan static int hda_link_dma_trigger(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai,
162b436ed8dSRanjani Sridharan 				int cmd)
163f321ffc8SPierre-Louis Bossart {
164*80afde34SRanjani Sridharan 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
165f321ffc8SPierre-Louis Bossart 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
166*80afde34SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
167f321ffc8SPierre-Louis Bossart 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
168*80afde34SRanjani Sridharan 	struct hdac_ext_stream *hext_stream;
169880924caSPierre-Louis Bossart 	int ret;
170bdf4ad3fSRanjani Sridharan 
171*80afde34SRanjani Sridharan 	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
172*80afde34SRanjani Sridharan 
173722cbbfaSPierre-Louis Bossart 	if (!hext_stream)
174722cbbfaSPierre-Louis Bossart 		return 0;
175722cbbfaSPierre-Louis Bossart 
176fdd961e3SKeyon Jie 	switch (cmd) {
177fdd961e3SKeyon Jie 	case SNDRV_PCM_TRIGGER_START:
178fdd961e3SKeyon Jie 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
17900b6cd95SPierre-Louis Bossart 		snd_hdac_ext_stream_start(hext_stream);
180fdd961e3SKeyon Jie 		break;
181fdd961e3SKeyon Jie 	case SNDRV_PCM_TRIGGER_SUSPEND:
182a3ebccb5SKai Vehmanen 	case SNDRV_PCM_TRIGGER_STOP:
1832be2caf4SRanjani Sridharan 		snd_hdac_ext_stream_clear(hext_stream);
1842be2caf4SRanjani Sridharan 		ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai);
185880924caSPierre-Louis Bossart 		if (ret < 0)
186880924caSPierre-Louis Bossart 			return ret;
187722cbbfaSPierre-Louis Bossart 
188e14cddc5SRanjani Sridharan 		break;
189bdf4ad3fSRanjani Sridharan 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
19000b6cd95SPierre-Louis Bossart 		snd_hdac_ext_stream_clear(hext_stream);
19169acac56SRanjani Sridharan 
192fdd961e3SKeyon Jie 		break;
193fdd961e3SKeyon Jie 	default:
194fdd961e3SKeyon Jie 		return -EINVAL;
195fdd961e3SKeyon Jie 	}
196fdd961e3SKeyon Jie 	return 0;
197fdd961e3SKeyon Jie }
198fdd961e3SKeyon Jie 
199b436ed8dSRanjani Sridharan static int hda_link_dma_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai)
2009272d6c2SPierre-Louis Bossart {
201*80afde34SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(cpu_dai->component);
202*80afde34SRanjani Sridharan 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, cpu_dai);
2039272d6c2SPierre-Louis Bossart 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
2049272d6c2SPierre-Louis Bossart 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
2059272d6c2SPierre-Louis Bossart 	struct hdac_ext_stream *hext_stream;
2069272d6c2SPierre-Louis Bossart 
207*80afde34SRanjani Sridharan 	if (!ops) {
208*80afde34SRanjani Sridharan 		dev_err(sdev->dev, "DAI widget ops not set\n");
209*80afde34SRanjani Sridharan 		return -EINVAL;
210*80afde34SRanjani Sridharan 	}
211*80afde34SRanjani Sridharan 
212*80afde34SRanjani Sridharan 	hext_stream = ops->get_hext_stream(sdev, cpu_dai, substream);
213880924caSPierre-Louis Bossart 	if (!hext_stream)
2149272d6c2SPierre-Louis Bossart 		return 0;
215880924caSPierre-Louis Bossart 
2162be2caf4SRanjani Sridharan 	return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai);
2179272d6c2SPierre-Louis Bossart }
2189272d6c2SPierre-Louis Bossart 
2199272d6c2SPierre-Louis Bossart static int hda_dai_widget_update(struct snd_soc_dapm_widget *w,
2209272d6c2SPierre-Louis Bossart 				 int channel, bool widget_setup)
2219272d6c2SPierre-Louis Bossart {
2229272d6c2SPierre-Louis Bossart 	struct snd_sof_dai_config_data data;
2239272d6c2SPierre-Louis Bossart 
2249272d6c2SPierre-Louis Bossart 	data.dai_data = channel;
2259272d6c2SPierre-Louis Bossart 
2269272d6c2SPierre-Louis Bossart 	/* set up/free DAI widget and send DAI_CONFIG IPC */
2279272d6c2SPierre-Louis Bossart 	if (widget_setup)
2289272d6c2SPierre-Louis Bossart 		return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data);
2299272d6c2SPierre-Louis Bossart 
2309272d6c2SPierre-Louis Bossart 	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
2319272d6c2SPierre-Louis Bossart }
2329272d6c2SPierre-Louis Bossart 
2339272d6c2SPierre-Louis Bossart static int hda_dai_hw_params_update(struct snd_pcm_substream *substream,
2349272d6c2SPierre-Louis Bossart 				    struct snd_pcm_hw_params *params,
2359272d6c2SPierre-Louis Bossart 				    struct snd_soc_dai *dai)
2369272d6c2SPierre-Louis Bossart {
237*80afde34SRanjani Sridharan 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
238*80afde34SRanjani Sridharan 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
239*80afde34SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
2409272d6c2SPierre-Louis Bossart 	struct hdac_ext_stream *hext_stream;
2419272d6c2SPierre-Louis Bossart 	int stream_tag;
2429272d6c2SPierre-Louis Bossart 
243*80afde34SRanjani Sridharan 	hext_stream = ops->get_hext_stream(sdev, dai, substream);
2449272d6c2SPierre-Louis Bossart 	if (!hext_stream)
2459272d6c2SPierre-Louis Bossart 		return -EINVAL;
2469272d6c2SPierre-Louis Bossart 
2479272d6c2SPierre-Louis Bossart 	stream_tag = hdac_stream(hext_stream)->stream_tag;
2489272d6c2SPierre-Louis Bossart 
2499272d6c2SPierre-Louis Bossart 	/* set up the DAI widget and send the DAI_CONFIG with the new tag */
2509272d6c2SPierre-Louis Bossart 	return hda_dai_widget_update(w, stream_tag - 1, true);
2519272d6c2SPierre-Louis Bossart }
2529272d6c2SPierre-Louis Bossart 
2539272d6c2SPierre-Louis Bossart static int hda_dai_hw_params(struct snd_pcm_substream *substream,
2549272d6c2SPierre-Louis Bossart 			     struct snd_pcm_hw_params *params,
2559272d6c2SPierre-Louis Bossart 			     struct snd_soc_dai *dai)
2569272d6c2SPierre-Louis Bossart {
257*80afde34SRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
258*80afde34SRanjani Sridharan 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
259*80afde34SRanjani Sridharan 	struct hdac_ext_stream *hext_stream;
2609272d6c2SPierre-Louis Bossart 	int ret;
2619272d6c2SPierre-Louis Bossart 
262*80afde34SRanjani Sridharan 	if (!ops) {
263*80afde34SRanjani Sridharan 		dev_err(sdev->dev, "DAI widget ops not set\n");
264*80afde34SRanjani Sridharan 		return -EINVAL;
265*80afde34SRanjani Sridharan 	}
266*80afde34SRanjani Sridharan 
267*80afde34SRanjani Sridharan 	hext_stream = ops->get_hext_stream(sdev, dai, substream);
268c4eb48f7SPierre-Louis Bossart 	if (hext_stream && hext_stream->link_prepared)
269c4eb48f7SPierre-Louis Bossart 		return 0;
270c4eb48f7SPierre-Louis Bossart 
271b436ed8dSRanjani Sridharan 	ret = hda_link_dma_hw_params(substream, params, dai);
2729272d6c2SPierre-Louis Bossart 	if (ret < 0)
2739272d6c2SPierre-Louis Bossart 		return ret;
2749272d6c2SPierre-Louis Bossart 
2759272d6c2SPierre-Louis Bossart 	return hda_dai_hw_params_update(substream, params, dai);
2769272d6c2SPierre-Louis Bossart }
2779272d6c2SPierre-Louis Bossart 
2789272d6c2SPierre-Louis Bossart 
2799272d6c2SPierre-Louis Bossart static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
2809272d6c2SPierre-Louis Bossart {
2819272d6c2SPierre-Louis Bossart 	struct snd_sof_widget *swidget = w->dobj.private;
2829272d6c2SPierre-Louis Bossart 	struct snd_soc_component *component = swidget->scomp;
2839272d6c2SPierre-Louis Bossart 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
2849272d6c2SPierre-Louis Bossart 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
2859272d6c2SPierre-Louis Bossart 	int ret = 0;
2869272d6c2SPierre-Louis Bossart 
2879272d6c2SPierre-Louis Bossart 	if (tplg_ops->dai_config) {
2889272d6c2SPierre-Louis Bossart 		ret = tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
2899272d6c2SPierre-Louis Bossart 		if (ret < 0)
2909272d6c2SPierre-Louis Bossart 			dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__,
2919272d6c2SPierre-Louis Bossart 				w->name);
2929272d6c2SPierre-Louis Bossart 	}
2939272d6c2SPierre-Louis Bossart 
2949272d6c2SPierre-Louis Bossart 	return ret;
2959272d6c2SPierre-Louis Bossart }
2969272d6c2SPierre-Louis Bossart 
2974c30004aSRanjani Sridharan static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
2989272d6c2SPierre-Louis Bossart {
2999272d6c2SPierre-Louis Bossart 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
300*80afde34SRanjani Sridharan 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
3019272d6c2SPierre-Louis Bossart 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
302*80afde34SRanjani Sridharan 	struct hdac_ext_stream *hext_stream;
3039272d6c2SPierre-Louis Bossart 	int stream = substream->stream;
3049272d6c2SPierre-Louis Bossart 	int ret;
3059272d6c2SPierre-Louis Bossart 
306*80afde34SRanjani Sridharan 	hext_stream = ops->get_hext_stream(sdev, dai, substream);
307722cbbfaSPierre-Louis Bossart 	if (hext_stream && hext_stream->link_prepared)
3089272d6c2SPierre-Louis Bossart 		return 0;
3099272d6c2SPierre-Louis Bossart 
31018701bb1SPierre-Louis Bossart 	dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream);
3119272d6c2SPierre-Louis Bossart 
312b436ed8dSRanjani Sridharan 	ret = hda_link_dma_prepare(substream, dai);
3139272d6c2SPierre-Louis Bossart 	if (ret < 0)
3149272d6c2SPierre-Louis Bossart 		return ret;
3159272d6c2SPierre-Louis Bossart 
3169272d6c2SPierre-Louis Bossart 	return hda_dai_hw_params_update(substream, &rtd->dpcm[stream].hw_params, dai);
3179272d6c2SPierre-Louis Bossart }
3189272d6c2SPierre-Louis Bossart 
31981622503SPierre-Louis Bossart static int hda_dai_hw_free_ipc(int stream, /* direction */
32081622503SPierre-Louis Bossart 			       struct snd_soc_dai *dai)
32181622503SPierre-Louis Bossart {
32281622503SPierre-Louis Bossart 	struct snd_soc_dapm_widget *w;
32381622503SPierre-Louis Bossart 
32481622503SPierre-Louis Bossart 	w = snd_soc_dai_get_widget(dai, stream);
32581622503SPierre-Louis Bossart 
32681622503SPierre-Louis Bossart 	/* free the link DMA channel in the FW and the DAI widget */
32781622503SPierre-Louis Bossart 	return hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
32881622503SPierre-Louis Bossart }
3299272d6c2SPierre-Louis Bossart 
330f321ffc8SPierre-Louis Bossart static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
331f321ffc8SPierre-Louis Bossart 				int cmd, struct snd_soc_dai *dai)
332fdd961e3SKeyon Jie {
3330acb48ddSRanjani Sridharan 	struct snd_soc_dapm_widget *w;
334bdf4ad3fSRanjani Sridharan 	int ret;
335fdd961e3SKeyon Jie 
33618701bb1SPierre-Louis Bossart 	dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
337519d1130SPierre-Louis Bossart 		dai->name, substream->stream);
338519d1130SPierre-Louis Bossart 
339b436ed8dSRanjani Sridharan 	ret = hda_link_dma_trigger(substream, dai, cmd);
340f321ffc8SPierre-Louis Bossart 	if (ret < 0)
341f321ffc8SPierre-Louis Bossart 		return ret;
342bdf4ad3fSRanjani Sridharan 
3435ef85c9eSPierre-Louis Bossart 	w = snd_soc_dai_get_widget(dai, substream->stream);
3440acb48ddSRanjani Sridharan 
345f321ffc8SPierre-Louis Bossart 	switch (cmd) {
346f321ffc8SPierre-Louis Bossart 	case SNDRV_PCM_TRIGGER_SUSPEND:
347f321ffc8SPierre-Louis Bossart 	case SNDRV_PCM_TRIGGER_STOP:
348f321ffc8SPierre-Louis Bossart 		/*
349f321ffc8SPierre-Louis Bossart 		 * free DAI widget during stop/suspend to keep widget use_count's balanced.
350f321ffc8SPierre-Louis Bossart 		 */
35181622503SPierre-Louis Bossart 		ret = hda_dai_hw_free_ipc(substream->stream, dai);
352bdf4ad3fSRanjani Sridharan 		if (ret < 0)
353bdf4ad3fSRanjani Sridharan 			return ret;
354bdf4ad3fSRanjani Sridharan 
355f321ffc8SPierre-Louis Bossart 		break;
356f321ffc8SPierre-Louis Bossart 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
357f321ffc8SPierre-Louis Bossart 		ret = hda_dai_config_pause_push_ipc(w);
358f321ffc8SPierre-Louis Bossart 		if (ret < 0)
359f321ffc8SPierre-Louis Bossart 			return ret;
360f321ffc8SPierre-Louis Bossart 		break;
361f321ffc8SPierre-Louis Bossart 
362f321ffc8SPierre-Louis Bossart 	default:
363f321ffc8SPierre-Louis Bossart 		break;
364f321ffc8SPierre-Louis Bossart 	}
365f321ffc8SPierre-Louis Bossart 	return 0;
366f321ffc8SPierre-Louis Bossart }
367f321ffc8SPierre-Louis Bossart 
3684c30004aSRanjani Sridharan /*
3694c30004aSRanjani Sridharan  * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
3704c30004aSRanjani Sridharan  * (over IPC channel) and DMA state change (direct host register changes).
3714c30004aSRanjani Sridharan  */
3724c30004aSRanjani Sridharan static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
3734c30004aSRanjani Sridharan 				int cmd, struct snd_soc_dai *dai)
3744c30004aSRanjani Sridharan {
375*80afde34SRanjani Sridharan 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, substream->stream);
3764c30004aSRanjani Sridharan 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
377*80afde34SRanjani Sridharan 	const struct hda_dai_widget_dma_ops *ops = hda_dai_get_ops(substream, dai);
378*80afde34SRanjani Sridharan 	struct snd_sof_widget *swidget = w->dobj.private;
379*80afde34SRanjani Sridharan 	struct hdac_ext_stream *hext_stream;
380*80afde34SRanjani Sridharan 	struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget;
381*80afde34SRanjani Sridharan 	struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
3824c30004aSRanjani Sridharan 	struct snd_soc_pcm_runtime *rtd;
3834c30004aSRanjani Sridharan 	struct snd_soc_dai *codec_dai;
3844c30004aSRanjani Sridharan 	int ret;
3854c30004aSRanjani Sridharan 
38618701bb1SPierre-Louis Bossart 	dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
3874c30004aSRanjani Sridharan 		dai->name, substream->stream);
3884c30004aSRanjani Sridharan 
389*80afde34SRanjani Sridharan 	hext_stream = ops->get_hext_stream(sdev, dai, substream);
390*80afde34SRanjani Sridharan 	if (!hext_stream)
391*80afde34SRanjani Sridharan 		return -EINVAL;
392*80afde34SRanjani Sridharan 
3934c30004aSRanjani Sridharan 	rtd = asoc_substream_to_rtd(substream);
3944c30004aSRanjani Sridharan 	codec_dai = asoc_rtd_to_codec(rtd, 0);
3954c30004aSRanjani Sridharan 
3964c30004aSRanjani Sridharan 	switch (cmd) {
3974c30004aSRanjani Sridharan 	case SNDRV_PCM_TRIGGER_START:
3984c30004aSRanjani Sridharan 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
39900b6cd95SPierre-Louis Bossart 		snd_hdac_ext_stream_start(hext_stream);
40037a26eecSRanjani Sridharan 		if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
40137a26eecSRanjani Sridharan 			ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
40237a26eecSRanjani Sridharan 							  SOF_IPC4_PIPE_PAUSED);
40337a26eecSRanjani Sridharan 			if (ret < 0)
40437a26eecSRanjani Sridharan 				return ret;
40537a26eecSRanjani Sridharan 			pipeline->state = SOF_IPC4_PIPE_PAUSED;
40637a26eecSRanjani Sridharan 		}
40737a26eecSRanjani Sridharan 
40837a26eecSRanjani Sridharan 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
40937a26eecSRanjani Sridharan 						  SOF_IPC4_PIPE_RUNNING);
41037a26eecSRanjani Sridharan 		if (ret < 0)
41137a26eecSRanjani Sridharan 			return ret;
41237a26eecSRanjani Sridharan 		pipeline->state = SOF_IPC4_PIPE_RUNNING;
4134c30004aSRanjani Sridharan 		break;
4144c30004aSRanjani Sridharan 	case SNDRV_PCM_TRIGGER_SUSPEND:
4154c30004aSRanjani Sridharan 	case SNDRV_PCM_TRIGGER_STOP:
4164c30004aSRanjani Sridharan 	{
417a2ba1f70SBard Liao 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
4184c30004aSRanjani Sridharan 						  SOF_IPC4_PIPE_PAUSED);
4194c30004aSRanjani Sridharan 		if (ret < 0)
4204c30004aSRanjani Sridharan 			return ret;
4214c30004aSRanjani Sridharan 
4224c30004aSRanjani Sridharan 		pipeline->state = SOF_IPC4_PIPE_PAUSED;
4234c30004aSRanjani Sridharan 
42400b6cd95SPierre-Louis Bossart 		snd_hdac_ext_stream_clear(hext_stream);
4254c30004aSRanjani Sridharan 
426a2ba1f70SBard Liao 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
4274c30004aSRanjani Sridharan 						  SOF_IPC4_PIPE_RESET);
4284c30004aSRanjani Sridharan 		if (ret < 0)
4294c30004aSRanjani Sridharan 			return ret;
4304c30004aSRanjani Sridharan 
4314c30004aSRanjani Sridharan 		pipeline->state = SOF_IPC4_PIPE_RESET;
4324c30004aSRanjani Sridharan 
433be7f4f8dSRanjani Sridharan 		ret = hda_link_dma_cleanup(substream, hext_stream, dai, codec_dai);
4344c30004aSRanjani Sridharan 		if (ret < 0) {
4354c30004aSRanjani Sridharan 			dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
4364c30004aSRanjani Sridharan 			return ret;
4374c30004aSRanjani Sridharan 		}
4384c30004aSRanjani Sridharan 		break;
4394c30004aSRanjani Sridharan 	}
4404c30004aSRanjani Sridharan 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
4414c30004aSRanjani Sridharan 	{
442a2ba1f70SBard Liao 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
4434c30004aSRanjani Sridharan 						  SOF_IPC4_PIPE_PAUSED);
4444c30004aSRanjani Sridharan 		if (ret < 0)
4454c30004aSRanjani Sridharan 			return ret;
4464c30004aSRanjani Sridharan 
4474c30004aSRanjani Sridharan 		pipeline->state = SOF_IPC4_PIPE_PAUSED;
4484c30004aSRanjani Sridharan 
44900b6cd95SPierre-Louis Bossart 		snd_hdac_ext_stream_clear(hext_stream);
4504c30004aSRanjani Sridharan 		break;
4514c30004aSRanjani Sridharan 	}
4524c30004aSRanjani Sridharan 	default:
4534c30004aSRanjani Sridharan 		dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd);
4544c30004aSRanjani Sridharan 		return -EINVAL;
4554c30004aSRanjani Sridharan 	}
4564c30004aSRanjani Sridharan 
4574c30004aSRanjani Sridharan 	return 0;
4584c30004aSRanjani Sridharan }
4594c30004aSRanjani Sridharan 
460f321ffc8SPierre-Louis Bossart static int hda_dai_hw_free(struct snd_pcm_substream *substream,
461f321ffc8SPierre-Louis Bossart 			   struct snd_soc_dai *dai)
462f321ffc8SPierre-Louis Bossart {
463f321ffc8SPierre-Louis Bossart 	int ret;
464f321ffc8SPierre-Louis Bossart 
465b436ed8dSRanjani Sridharan 	ret = hda_link_dma_hw_free(substream, dai);
466f321ffc8SPierre-Louis Bossart 	if (ret < 0)
467f321ffc8SPierre-Louis Bossart 		return ret;
468f321ffc8SPierre-Louis Bossart 
46981622503SPierre-Louis Bossart 	return hda_dai_hw_free_ipc(substream->stream, dai);
470f321ffc8SPierre-Louis Bossart }
471f321ffc8SPierre-Louis Bossart 
472309e6e55SPierre-Louis Bossart static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
473309e6e55SPierre-Louis Bossart 	.hw_params = hda_dai_hw_params,
474309e6e55SPierre-Louis Bossart 	.hw_free = hda_dai_hw_free,
475309e6e55SPierre-Louis Bossart 	.trigger = ipc3_hda_dai_trigger,
4764c30004aSRanjani Sridharan 	.prepare = hda_dai_prepare,
477fdd961e3SKeyon Jie };
47870368106SCezary Rojewski 
479f09e9284SPierre-Louis Bossart static int hda_dai_suspend(struct hdac_bus *bus)
480f09e9284SPierre-Louis Bossart {
481f09e9284SPierre-Louis Bossart 	struct snd_soc_pcm_runtime *rtd;
482f09e9284SPierre-Louis Bossart 	struct hdac_ext_stream *hext_stream;
483f09e9284SPierre-Louis Bossart 	struct hdac_stream *s;
48423b1944eSPierre-Louis Bossart 	int ret;
485f09e9284SPierre-Louis Bossart 
486f09e9284SPierre-Louis Bossart 	/* set internal flag for BE */
487f09e9284SPierre-Louis Bossart 	list_for_each_entry(s, &bus->stream_list, list) {
488722cbbfaSPierre-Louis Bossart 
489f09e9284SPierre-Louis Bossart 		hext_stream = stream_to_hdac_ext_stream(s);
490f09e9284SPierre-Louis Bossart 
491f09e9284SPierre-Louis Bossart 		/*
492f09e9284SPierre-Louis Bossart 		 * clear stream. This should already be taken care for running
493f09e9284SPierre-Louis Bossart 		 * streams when the SUSPEND trigger is called. But paused
494f09e9284SPierre-Louis Bossart 		 * streams do not get suspended, so this needs to be done
495f09e9284SPierre-Louis Bossart 		 * explicitly during suspend.
496f09e9284SPierre-Louis Bossart 		 */
497f09e9284SPierre-Louis Bossart 		if (hext_stream->link_substream) {
49823b1944eSPierre-Louis Bossart 			struct snd_soc_dai *cpu_dai;
49923b1944eSPierre-Louis Bossart 			struct snd_soc_dai *codec_dai;
50023b1944eSPierre-Louis Bossart 
501f09e9284SPierre-Louis Bossart 			rtd = asoc_substream_to_rtd(hext_stream->link_substream);
50223b1944eSPierre-Louis Bossart 			cpu_dai = asoc_rtd_to_cpu(rtd, 0);
50323b1944eSPierre-Louis Bossart 			codec_dai = asoc_rtd_to_codec(rtd, 0);
504f09e9284SPierre-Louis Bossart 
5050351a9b8SPierre-Louis Bossart 			ret = hda_link_dma_cleanup(hext_stream->link_substream,
5060351a9b8SPierre-Louis Bossart 						   hext_stream,
5072be2caf4SRanjani Sridharan 						   cpu_dai, codec_dai);
508880924caSPierre-Louis Bossart 			if (ret < 0)
509880924caSPierre-Louis Bossart 				return ret;
510722cbbfaSPierre-Louis Bossart 
51123b1944eSPierre-Louis Bossart 			/* for consistency with TRIGGER_SUSPEND we free DAI resources */
51223b1944eSPierre-Louis Bossart 			ret = hda_dai_hw_free_ipc(hdac_stream(hext_stream)->direction, cpu_dai);
51323b1944eSPierre-Louis Bossart 			if (ret < 0)
51423b1944eSPierre-Louis Bossart 				return ret;
51523b1944eSPierre-Louis Bossart 		}
516f09e9284SPierre-Louis Bossart 	}
517f09e9284SPierre-Louis Bossart 
518f09e9284SPierre-Louis Bossart 	return 0;
519f09e9284SPierre-Louis Bossart }
5204c30004aSRanjani Sridharan 
5214c30004aSRanjani Sridharan static const struct snd_soc_dai_ops ipc4_hda_dai_ops = {
5224c30004aSRanjani Sridharan 	.hw_params = hda_dai_hw_params,
5234c30004aSRanjani Sridharan 	.hw_free = hda_dai_hw_free,
5244c30004aSRanjani Sridharan 	.trigger = ipc4_hda_dai_trigger,
5254c30004aSRanjani Sridharan 	.prepare = hda_dai_prepare,
5264c30004aSRanjani Sridharan };
5274c30004aSRanjani Sridharan 
528fdd961e3SKeyon Jie #endif
529fdd961e3SKeyon Jie 
53051ec71dcSRanjani Sridharan void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
53151ec71dcSRanjani Sridharan {
53251ec71dcSRanjani Sridharan 	int i;
53351ec71dcSRanjani Sridharan 
53451ec71dcSRanjani Sridharan 	switch (sdev->pdata->ipc_type) {
53551ec71dcSRanjani Sridharan 	case SOF_IPC:
53651ec71dcSRanjani Sridharan 		for (i = 0; i < ops->num_drv; i++) {
537a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
53851ec71dcSRanjani Sridharan 			if (strstr(ops->drv[i].name, "iDisp") ||
53951ec71dcSRanjani Sridharan 			    strstr(ops->drv[i].name, "Analog") ||
54051ec71dcSRanjani Sridharan 			    strstr(ops->drv[i].name, "Digital"))
541309e6e55SPierre-Louis Bossart 				ops->drv[i].ops = &ipc3_hda_dai_ops;
54251ec71dcSRanjani Sridharan #endif
54351ec71dcSRanjani Sridharan 		}
54451ec71dcSRanjani Sridharan 		break;
5454c30004aSRanjani Sridharan 	case SOF_INTEL_IPC4:
5461da51943SRanjani Sridharan 	{
5471da51943SRanjani Sridharan 		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
5481da51943SRanjani Sridharan 
5494c30004aSRanjani Sridharan 		for (i = 0; i < ops->num_drv; i++) {
550a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
5514c30004aSRanjani Sridharan 			if (strstr(ops->drv[i].name, "iDisp") ||
5524c30004aSRanjani Sridharan 			    strstr(ops->drv[i].name, "Analog") ||
5534c30004aSRanjani Sridharan 			    strstr(ops->drv[i].name, "Digital"))
5544c30004aSRanjani Sridharan 				ops->drv[i].ops = &ipc4_hda_dai_ops;
5554c30004aSRanjani Sridharan #endif
5564c30004aSRanjani Sridharan 		}
5571da51943SRanjani Sridharan 
5581da51943SRanjani Sridharan 		if (!hda_use_tplg_nhlt)
5591da51943SRanjani Sridharan 			ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
5601da51943SRanjani Sridharan 
5614c30004aSRanjani Sridharan 		break;
5621da51943SRanjani Sridharan 	}
56351ec71dcSRanjani Sridharan 	default:
56451ec71dcSRanjani Sridharan 		break;
56551ec71dcSRanjani Sridharan 	}
56651ec71dcSRanjani Sridharan }
56751ec71dcSRanjani Sridharan 
5681da51943SRanjani Sridharan void hda_ops_free(struct snd_sof_dev *sdev)
5691da51943SRanjani Sridharan {
5701da51943SRanjani Sridharan 	if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
5711da51943SRanjani Sridharan 		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
5721da51943SRanjani Sridharan 
5731da51943SRanjani Sridharan 		if (!hda_use_tplg_nhlt)
5741da51943SRanjani Sridharan 			intel_nhlt_free(ipc4_data->nhlt);
5751da51943SRanjani Sridharan 	}
5761da51943SRanjani Sridharan }
5771da51943SRanjani Sridharan EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
5781da51943SRanjani Sridharan 
579fdd961e3SKeyon Jie /*
580fdd961e3SKeyon Jie  * common dai driver for skl+ platforms.
581fdd961e3SKeyon Jie  * some products who use this DAI array only physically have a subset of
582fdd961e3SKeyon Jie  * the DAIs, but no harm is done here by adding the whole set.
583fdd961e3SKeyon Jie  */
584fdd961e3SKeyon Jie struct snd_soc_dai_driver skl_dai[] = {
585fdd961e3SKeyon Jie {
586fdd961e3SKeyon Jie 	.name = "SSP0 Pin",
587e81d47e9SBard Liao 	.playback = {
588e81d47e9SBard Liao 		.channels_min = 1,
589e81d47e9SBard Liao 		.channels_max = 8,
590e81d47e9SBard Liao 	},
591e81d47e9SBard Liao 	.capture = {
592e81d47e9SBard Liao 		.channels_min = 1,
593e81d47e9SBard Liao 		.channels_max = 8,
594e81d47e9SBard Liao 	},
595fdd961e3SKeyon Jie },
596fdd961e3SKeyon Jie {
597fdd961e3SKeyon Jie 	.name = "SSP1 Pin",
598e81d47e9SBard Liao 	.playback = {
599e81d47e9SBard Liao 		.channels_min = 1,
600e81d47e9SBard Liao 		.channels_max = 8,
601e81d47e9SBard Liao 	},
602e81d47e9SBard Liao 	.capture = {
603e81d47e9SBard Liao 		.channels_min = 1,
604e81d47e9SBard Liao 		.channels_max = 8,
605e81d47e9SBard Liao 	},
606fdd961e3SKeyon Jie },
607fdd961e3SKeyon Jie {
608fdd961e3SKeyon Jie 	.name = "SSP2 Pin",
609e81d47e9SBard Liao 	.playback = {
610e81d47e9SBard Liao 		.channels_min = 1,
611e81d47e9SBard Liao 		.channels_max = 8,
612e81d47e9SBard Liao 	},
613e81d47e9SBard Liao 	.capture = {
614e81d47e9SBard Liao 		.channels_min = 1,
615e81d47e9SBard Liao 		.channels_max = 8,
616e81d47e9SBard Liao 	},
617fdd961e3SKeyon Jie },
618fdd961e3SKeyon Jie {
619fdd961e3SKeyon Jie 	.name = "SSP3 Pin",
620e81d47e9SBard Liao 	.playback = {
621e81d47e9SBard Liao 		.channels_min = 1,
622e81d47e9SBard Liao 		.channels_max = 8,
623e81d47e9SBard Liao 	},
624e81d47e9SBard Liao 	.capture = {
625e81d47e9SBard Liao 		.channels_min = 1,
626e81d47e9SBard Liao 		.channels_max = 8,
627e81d47e9SBard Liao 	},
628fdd961e3SKeyon Jie },
629fdd961e3SKeyon Jie {
630fdd961e3SKeyon Jie 	.name = "SSP4 Pin",
631e81d47e9SBard Liao 	.playback = {
632e81d47e9SBard Liao 		.channels_min = 1,
633e81d47e9SBard Liao 		.channels_max = 8,
634e81d47e9SBard Liao 	},
635e81d47e9SBard Liao 	.capture = {
636e81d47e9SBard Liao 		.channels_min = 1,
637e81d47e9SBard Liao 		.channels_max = 8,
638e81d47e9SBard Liao 	},
639fdd961e3SKeyon Jie },
640fdd961e3SKeyon Jie {
641fdd961e3SKeyon Jie 	.name = "SSP5 Pin",
642e81d47e9SBard Liao 	.playback = {
643e81d47e9SBard Liao 		.channels_min = 1,
644e81d47e9SBard Liao 		.channels_max = 8,
645e81d47e9SBard Liao 	},
646e81d47e9SBard Liao 	.capture = {
647e81d47e9SBard Liao 		.channels_min = 1,
648e81d47e9SBard Liao 		.channels_max = 8,
649e81d47e9SBard Liao 	},
650fdd961e3SKeyon Jie },
651fdd961e3SKeyon Jie {
652fdd961e3SKeyon Jie 	.name = "DMIC01 Pin",
653e81d47e9SBard Liao 	.capture = {
654e81d47e9SBard Liao 		.channels_min = 1,
655e81d47e9SBard Liao 		.channels_max = 4,
656e81d47e9SBard Liao 	},
657fdd961e3SKeyon Jie },
658fdd961e3SKeyon Jie {
659fdd961e3SKeyon Jie 	.name = "DMIC16k Pin",
660e81d47e9SBard Liao 	.capture = {
661e81d47e9SBard Liao 		.channels_min = 1,
662e81d47e9SBard Liao 		.channels_max = 4,
663e81d47e9SBard Liao 	},
664fdd961e3SKeyon Jie },
665a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
666fdd961e3SKeyon Jie {
667fdd961e3SKeyon Jie 	.name = "iDisp1 Pin",
668e81d47e9SBard Liao 	.playback = {
669e81d47e9SBard Liao 		.channels_min = 1,
670e81d47e9SBard Liao 		.channels_max = 8,
671e81d47e9SBard Liao 	},
672fdd961e3SKeyon Jie },
673fdd961e3SKeyon Jie {
674fdd961e3SKeyon Jie 	.name = "iDisp2 Pin",
675e81d47e9SBard Liao 	.playback = {
676e81d47e9SBard Liao 		.channels_min = 1,
677e81d47e9SBard Liao 		.channels_max = 8,
678e81d47e9SBard Liao 	},
679fdd961e3SKeyon Jie },
680fdd961e3SKeyon Jie {
681fdd961e3SKeyon Jie 	.name = "iDisp3 Pin",
682e81d47e9SBard Liao 	.playback = {
683e81d47e9SBard Liao 		.channels_min = 1,
684e81d47e9SBard Liao 		.channels_max = 8,
685e81d47e9SBard Liao 	},
686fdd961e3SKeyon Jie },
687fdd961e3SKeyon Jie {
688e68d6696SSathyanarayana Nujella 	.name = "iDisp4 Pin",
689e81d47e9SBard Liao 	.playback = {
690e81d47e9SBard Liao 		.channels_min = 1,
691e81d47e9SBard Liao 		.channels_max = 8,
692e81d47e9SBard Liao 	},
693e68d6696SSathyanarayana Nujella },
694e68d6696SSathyanarayana Nujella {
695fdd961e3SKeyon Jie 	.name = "Analog CPU DAI",
696e81d47e9SBard Liao 	.playback = {
697e81d47e9SBard Liao 		.channels_min = 1,
698e81d47e9SBard Liao 		.channels_max = 16,
699e81d47e9SBard Liao 	},
700e81d47e9SBard Liao 	.capture = {
701e81d47e9SBard Liao 		.channels_min = 1,
702e81d47e9SBard Liao 		.channels_max = 16,
703e81d47e9SBard Liao 	},
704fdd961e3SKeyon Jie },
705fdd961e3SKeyon Jie {
706fdd961e3SKeyon Jie 	.name = "Digital CPU DAI",
707e81d47e9SBard Liao 	.playback = {
708e81d47e9SBard Liao 		.channels_min = 1,
709e81d47e9SBard Liao 		.channels_max = 16,
710e81d47e9SBard Liao 	},
711e81d47e9SBard Liao 	.capture = {
712e81d47e9SBard Liao 		.channels_min = 1,
713e81d47e9SBard Liao 		.channels_max = 16,
714e81d47e9SBard Liao 	},
715fdd961e3SKeyon Jie },
716fdd961e3SKeyon Jie {
717fdd961e3SKeyon Jie 	.name = "Alt Analog CPU DAI",
718e81d47e9SBard Liao 	.playback = {
719e81d47e9SBard Liao 		.channels_min = 1,
720e81d47e9SBard Liao 		.channels_max = 16,
721e81d47e9SBard Liao 	},
722e81d47e9SBard Liao 	.capture = {
723e81d47e9SBard Liao 		.channels_min = 1,
724e81d47e9SBard Liao 		.channels_max = 16,
725e81d47e9SBard Liao 	},
726fdd961e3SKeyon Jie },
727fdd961e3SKeyon Jie #endif
728fdd961e3SKeyon Jie };
729f09e9284SPierre-Louis Bossart 
730f09e9284SPierre-Louis Bossart int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
731f09e9284SPierre-Louis Bossart {
732f09e9284SPierre-Louis Bossart 	/*
733f09e9284SPierre-Louis Bossart 	 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
734f09e9284SPierre-Louis Bossart 	 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
735f09e9284SPierre-Louis Bossart 	 * Since the component suspend is called last, we can trap this corner case
736f09e9284SPierre-Louis Bossart 	 * and force the DAIs to release their resources.
737f09e9284SPierre-Louis Bossart 	 */
738a4203256SPierre-Louis Bossart #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
739f09e9284SPierre-Louis Bossart 	int ret;
740f09e9284SPierre-Louis Bossart 
741f09e9284SPierre-Louis Bossart 	ret = hda_dai_suspend(sof_to_bus(sdev));
742f09e9284SPierre-Louis Bossart 	if (ret < 0)
743f09e9284SPierre-Louis Bossart 		return ret;
744f09e9284SPierre-Louis Bossart #endif
745f09e9284SPierre-Louis Bossart 
746f09e9284SPierre-Louis Bossart 	return 0;
747f09e9284SPierre-Louis Bossart }
748