xref: /openbmc/linux/sound/soc/sof/intel/hda-dai.c (revision 71de0a05)
1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
2 //
3 // This file is provided under a dual BSD/GPLv2 license.  When using or
4 // redistributing this file, you may do so under either license.
5 //
6 // Copyright(c) 2018 Intel Corporation. All rights reserved.
7 //
8 // Authors: Keyon Jie <yang.jie@linux.intel.com>
9 //
10 
11 #include <sound/pcm_params.h>
12 #include <sound/hdaudio_ext.h>
13 #include <sound/intel-nhlt.h>
14 #include <sound/sof/ipc4/header.h>
15 #include <uapi/sound/sof/header.h>
16 #include "../ipc4-priv.h"
17 #include "../ipc4-topology.h"
18 #include "../sof-priv.h"
19 #include "../sof-audio.h"
20 #include "hda.h"
21 
22 /*
23  * The default method is to fetch NHLT from BIOS. With this parameter set
24  * it is possible to override that with NHLT in the SOF topology manifest.
25  */
26 static bool hda_use_tplg_nhlt;
27 module_param_named(sof_use_tplg_nhlt, hda_use_tplg_nhlt, bool, 0444);
28 MODULE_PARM_DESC(sof_use_tplg_nhlt, "SOF topology nhlt override");
29 
30 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
31 
32 struct hda_pipe_params {
33 	u32 ch;
34 	u32 s_freq;
35 	snd_pcm_format_t format;
36 	int link_index;
37 	unsigned int link_bps;
38 };
39 
40 /*
41  * This function checks if the host dma channel corresponding
42  * to the link DMA stream_tag argument is assigned to one
43  * of the FEs connected to the BE DAI.
44  */
45 static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
46 			  int dir, int stream_tag)
47 {
48 	struct snd_pcm_substream *fe_substream;
49 	struct hdac_stream *fe_hstream;
50 	struct snd_soc_dpcm *dpcm;
51 
52 	for_each_dpcm_fe(rtd, dir, dpcm) {
53 		fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);
54 		fe_hstream = fe_substream->runtime->private_data;
55 		if (fe_hstream->stream_tag == stream_tag)
56 			return true;
57 	}
58 
59 	return false;
60 }
61 
62 static struct hdac_ext_stream *
63 hda_link_stream_assign(struct hdac_bus *bus,
64 		       struct snd_pcm_substream *substream)
65 {
66 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
67 	struct sof_intel_hda_stream *hda_stream;
68 	const struct sof_intel_dsp_desc *chip;
69 	struct snd_sof_dev *sdev;
70 	struct hdac_ext_stream *res = NULL;
71 	struct hdac_stream *hstream = NULL;
72 
73 	int stream_dir = substream->stream;
74 
75 	if (!bus->ppcap) {
76 		dev_err(bus->dev, "stream type not supported\n");
77 		return NULL;
78 	}
79 
80 	spin_lock_irq(&bus->reg_lock);
81 	list_for_each_entry(hstream, &bus->stream_list, list) {
82 		struct hdac_ext_stream *hext_stream =
83 			stream_to_hdac_ext_stream(hstream);
84 		if (hstream->direction != substream->stream)
85 			continue;
86 
87 		hda_stream = hstream_to_sof_hda_stream(hext_stream);
88 		sdev = hda_stream->sdev;
89 		chip = get_chip_info(sdev->pdata);
90 
91 		/* check if link is available */
92 		if (!hext_stream->link_locked) {
93 			/*
94 			 * choose the first available link for platforms that do not have the
95 			 * PROCEN_FMT_QUIRK set.
96 			 */
97 			if (!(chip->quirks & SOF_INTEL_PROCEN_FMT_QUIRK)) {
98 				res = hext_stream;
99 				break;
100 			}
101 
102 			if (hstream->opened) {
103 				/*
104 				 * check if the stream tag matches the stream
105 				 * tag of one of the connected FEs
106 				 */
107 				if (hda_check_fes(rtd, stream_dir,
108 						  hstream->stream_tag)) {
109 					res = hext_stream;
110 					break;
111 				}
112 			} else {
113 				res = hext_stream;
114 
115 				/*
116 				 * This must be a hostless stream.
117 				 * So reserve the host DMA channel.
118 				 */
119 				hda_stream->host_reserved = 1;
120 				break;
121 			}
122 		}
123 	}
124 
125 	if (res) {
126 		/* Make sure that host and link DMA is decoupled. */
127 		snd_hdac_ext_stream_decouple_locked(bus, res, true);
128 
129 		res->link_locked = 1;
130 		res->link_substream = substream;
131 	}
132 	spin_unlock_irq(&bus->reg_lock);
133 
134 	return res;
135 }
136 
137 static int hda_link_dma_cleanup(struct snd_pcm_substream *substream,
138 				struct hdac_ext_stream *hext_stream,
139 				struct snd_soc_dai *cpu_dai,
140 				struct snd_soc_dai *codec_dai,
141 				bool trigger_suspend_stop)
142 {
143 	struct hdac_stream *hstream = &hext_stream->hstream;
144 	struct hdac_bus *bus = hstream->bus;
145 	struct sof_intel_hda_stream *hda_stream;
146 	struct hdac_ext_link *hlink;
147 	int stream_tag;
148 
149 	hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
150 	if (!hlink)
151 		return -EINVAL;
152 
153 	if (trigger_suspend_stop)
154 		snd_hdac_ext_stream_clear(hext_stream);
155 
156 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
157 		stream_tag = hdac_stream(hext_stream)->stream_tag;
158 		snd_hdac_ext_bus_link_clear_stream_id(hlink, stream_tag);
159 	}
160 	snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
161 	snd_hdac_ext_stream_release(hext_stream, HDAC_EXT_STREAM_TYPE_LINK);
162 	hext_stream->link_prepared = 0;
163 
164 	/* free the host DMA channel reserved by hostless streams */
165 	hda_stream = hstream_to_sof_hda_stream(hext_stream);
166 	hda_stream->host_reserved = 0;
167 
168 	return 0;
169 }
170 
171 static int hda_link_dma_params(struct hdac_ext_stream *hext_stream,
172 			       struct hda_pipe_params *params)
173 {
174 	struct hdac_stream *hstream = &hext_stream->hstream;
175 	unsigned char stream_tag = hstream->stream_tag;
176 	struct hdac_bus *bus = hstream->bus;
177 	struct hdac_ext_link *hlink;
178 	unsigned int format_val;
179 
180 	snd_hdac_ext_stream_reset(hext_stream);
181 
182 	format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
183 						 params->format,
184 						 params->link_bps, 0);
185 
186 	dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
187 		format_val, params->s_freq, params->ch, params->format);
188 
189 	snd_hdac_ext_stream_setup(hext_stream, format_val);
190 
191 	if (hext_stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
192 		list_for_each_entry(hlink, &bus->hlink_list, list) {
193 			if (hlink->index == params->link_index)
194 				snd_hdac_ext_bus_link_set_stream_id(hlink,
195 								    stream_tag);
196 		}
197 	}
198 
199 	hext_stream->link_prepared = 1;
200 
201 	return 0;
202 }
203 
204 static int hda_link_dma_hw_params(struct snd_pcm_substream *substream,
205 				  struct snd_pcm_hw_params *params)
206 {
207 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
208 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
209 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
210 	struct hda_pipe_params p_params = {0};
211 	struct hdac_ext_stream *hext_stream;
212 	struct hdac_ext_link *hlink;
213 	struct snd_sof_dev *sdev;
214 	struct hdac_bus *bus;
215 
216 	sdev = snd_soc_component_get_drvdata(cpu_dai->component);
217 	bus = sof_to_bus(sdev);
218 
219 	hlink = snd_hdac_ext_bus_get_hlink_by_name(bus, codec_dai->component->name);
220 	if (!hlink)
221 		return -EINVAL;
222 
223 	hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
224 	if (!hext_stream) {
225 		hext_stream = hda_link_stream_assign(bus, substream);
226 		if (!hext_stream)
227 			return -EBUSY;
228 
229 		snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)hext_stream);
230 	}
231 
232 	/* set the hdac_stream in the codec dai */
233 	snd_soc_dai_set_stream(codec_dai, hdac_stream(hext_stream), substream->stream);
234 
235 	p_params.ch = params_channels(params);
236 	p_params.s_freq = params_rate(params);
237 	p_params.link_index = hlink->index;
238 	p_params.format = params_format(params);
239 
240 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
241 		p_params.link_bps = codec_dai->driver->playback.sig_bits;
242 	else
243 		p_params.link_bps = codec_dai->driver->capture.sig_bits;
244 
245 	return hda_link_dma_params(hext_stream, &p_params);
246 }
247 
248 static int hda_link_dma_prepare(struct snd_pcm_substream *substream)
249 {
250 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
251 	int stream = substream->stream;
252 
253 	return hda_link_dma_hw_params(substream, &rtd->dpcm[stream].hw_params);
254 }
255 
256 static int hda_link_dma_trigger(struct snd_pcm_substream *substream, int cmd)
257 {
258 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
259 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
260 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
261 	struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
262 	int ret;
263 
264 	if (!hext_stream)
265 		return 0;
266 
267 	switch (cmd) {
268 	case SNDRV_PCM_TRIGGER_START:
269 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
270 		snd_hdac_ext_stream_start(hext_stream);
271 		break;
272 	case SNDRV_PCM_TRIGGER_SUSPEND:
273 	case SNDRV_PCM_TRIGGER_STOP:
274 		ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, true);
275 		if (ret < 0)
276 			return ret;
277 
278 		break;
279 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
280 		snd_hdac_ext_stream_clear(hext_stream);
281 
282 		break;
283 	default:
284 		return -EINVAL;
285 	}
286 	return 0;
287 }
288 
289 static int hda_link_dma_hw_free(struct snd_pcm_substream *substream)
290 {
291 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
292 	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
293 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
294 	struct hdac_ext_stream *hext_stream;
295 
296 	hext_stream = snd_soc_dai_get_dma_data(cpu_dai, substream);
297 	if (!hext_stream)
298 		return 0;
299 
300 	return hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, false);
301 }
302 
303 static int hda_dai_widget_update(struct snd_soc_dapm_widget *w,
304 				 int channel, bool widget_setup)
305 {
306 	struct snd_sof_dai_config_data data;
307 
308 	data.dai_data = channel;
309 
310 	/* set up/free DAI widget and send DAI_CONFIG IPC */
311 	if (widget_setup)
312 		return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_2_STEP_STOP, &data);
313 
314 	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, &data);
315 }
316 
317 static int hda_dai_hw_params_update(struct snd_pcm_substream *substream,
318 				    struct snd_pcm_hw_params *params,
319 				    struct snd_soc_dai *dai)
320 {
321 	struct hdac_ext_stream *hext_stream;
322 	struct snd_soc_dapm_widget *w;
323 	int stream_tag;
324 
325 	hext_stream = snd_soc_dai_get_dma_data(dai, substream);
326 	if (!hext_stream)
327 		return -EINVAL;
328 
329 	stream_tag = hdac_stream(hext_stream)->stream_tag;
330 
331 	w = snd_soc_dai_get_widget(dai, substream->stream);
332 
333 	/* set up the DAI widget and send the DAI_CONFIG with the new tag */
334 	return hda_dai_widget_update(w, stream_tag - 1, true);
335 }
336 
337 static int hda_dai_hw_params(struct snd_pcm_substream *substream,
338 			     struct snd_pcm_hw_params *params,
339 			     struct snd_soc_dai *dai)
340 {
341 	struct hdac_ext_stream *hext_stream =
342 				snd_soc_dai_get_dma_data(dai, substream);
343 	int ret;
344 
345 	if (hext_stream && hext_stream->link_prepared)
346 		return 0;
347 
348 	ret = hda_link_dma_hw_params(substream, params);
349 	if (ret < 0)
350 		return ret;
351 
352 	return hda_dai_hw_params_update(substream, params, dai);
353 }
354 
355 
356 static int hda_dai_config_pause_push_ipc(struct snd_soc_dapm_widget *w)
357 {
358 	struct snd_sof_widget *swidget = w->dobj.private;
359 	struct snd_soc_component *component = swidget->scomp;
360 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
361 	const struct sof_ipc_tplg_ops *tplg_ops = sdev->ipc->ops->tplg;
362 	int ret = 0;
363 
364 	if (tplg_ops->dai_config) {
365 		ret = tplg_ops->dai_config(sdev, swidget, SOF_DAI_CONFIG_FLAGS_PAUSE, NULL);
366 		if (ret < 0)
367 			dev_err(sdev->dev, "%s: DAI config failed for widget %s\n", __func__,
368 				w->name);
369 	}
370 
371 	return ret;
372 }
373 
374 static int hda_dai_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
375 {
376 	struct hdac_ext_stream *hext_stream =
377 				snd_soc_dai_get_dma_data(dai, substream);
378 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
379 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
380 	int stream = substream->stream;
381 	int ret;
382 
383 	if (hext_stream && hext_stream->link_prepared)
384 		return 0;
385 
386 	dev_dbg(sdev->dev, "prepare stream dir %d\n", substream->stream);
387 
388 	ret = hda_link_dma_prepare(substream);
389 	if (ret < 0)
390 		return ret;
391 
392 	return hda_dai_hw_params_update(substream, &rtd->dpcm[stream].hw_params, dai);
393 }
394 
395 static int hda_dai_hw_free_ipc(int stream, /* direction */
396 			       struct snd_soc_dai *dai)
397 {
398 	struct snd_soc_dapm_widget *w;
399 
400 	w = snd_soc_dai_get_widget(dai, stream);
401 
402 	/* free the link DMA channel in the FW and the DAI widget */
403 	return hda_dai_widget_update(w, DMA_CHAN_INVALID, false);
404 }
405 
406 static int ipc3_hda_dai_trigger(struct snd_pcm_substream *substream,
407 				int cmd, struct snd_soc_dai *dai)
408 {
409 	struct snd_soc_dapm_widget *w;
410 	int ret;
411 
412 	dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
413 		dai->name, substream->stream);
414 
415 	ret = hda_link_dma_trigger(substream, cmd);
416 	if (ret < 0)
417 		return ret;
418 
419 	w = snd_soc_dai_get_widget(dai, substream->stream);
420 
421 	switch (cmd) {
422 	case SNDRV_PCM_TRIGGER_SUSPEND:
423 	case SNDRV_PCM_TRIGGER_STOP:
424 		/*
425 		 * free DAI widget during stop/suspend to keep widget use_count's balanced.
426 		 */
427 		ret = hda_dai_hw_free_ipc(substream->stream, dai);
428 		if (ret < 0)
429 			return ret;
430 
431 		break;
432 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
433 		ret = hda_dai_config_pause_push_ipc(w);
434 		if (ret < 0)
435 			return ret;
436 		break;
437 
438 	default:
439 		break;
440 	}
441 	return 0;
442 }
443 
444 /*
445  * In contrast to IPC3, the dai trigger in IPC4 mixes pipeline state changes
446  * (over IPC channel) and DMA state change (direct host register changes).
447  */
448 static int ipc4_hda_dai_trigger(struct snd_pcm_substream *substream,
449 				int cmd, struct snd_soc_dai *dai)
450 {
451 	struct hdac_ext_stream *hext_stream = snd_soc_dai_get_dma_data(dai, substream);
452 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(dai->component);
453 	struct snd_sof_widget *pipe_widget;
454 	struct sof_ipc4_pipeline *pipeline;
455 	struct snd_soc_pcm_runtime *rtd;
456 	struct snd_sof_widget *swidget;
457 	struct snd_soc_dapm_widget *w;
458 	struct snd_soc_dai *codec_dai;
459 	struct snd_soc_dai *cpu_dai;
460 	int ret;
461 
462 	dev_dbg(dai->dev, "cmd=%d dai %s direction %d\n", cmd,
463 		dai->name, substream->stream);
464 
465 	rtd = asoc_substream_to_rtd(substream);
466 	cpu_dai = asoc_rtd_to_cpu(rtd, 0);
467 	codec_dai = asoc_rtd_to_codec(rtd, 0);
468 
469 	w = snd_soc_dai_get_widget(dai, substream->stream);
470 	swidget = w->dobj.private;
471 	pipe_widget = swidget->spipe->pipe_widget;
472 	pipeline = pipe_widget->private;
473 
474 	switch (cmd) {
475 	case SNDRV_PCM_TRIGGER_START:
476 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
477 		snd_hdac_ext_stream_start(hext_stream);
478 		if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
479 			ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
480 							  SOF_IPC4_PIPE_PAUSED);
481 			if (ret < 0)
482 				return ret;
483 			pipeline->state = SOF_IPC4_PIPE_PAUSED;
484 		}
485 
486 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
487 						  SOF_IPC4_PIPE_RUNNING);
488 		if (ret < 0)
489 			return ret;
490 		pipeline->state = SOF_IPC4_PIPE_RUNNING;
491 		break;
492 	case SNDRV_PCM_TRIGGER_SUSPEND:
493 	case SNDRV_PCM_TRIGGER_STOP:
494 	{
495 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
496 						  SOF_IPC4_PIPE_PAUSED);
497 		if (ret < 0)
498 			return ret;
499 
500 		pipeline->state = SOF_IPC4_PIPE_PAUSED;
501 
502 		snd_hdac_ext_stream_clear(hext_stream);
503 
504 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
505 						  SOF_IPC4_PIPE_RESET);
506 		if (ret < 0)
507 			return ret;
508 
509 		pipeline->state = SOF_IPC4_PIPE_RESET;
510 
511 		ret = hda_link_dma_cleanup(substream, hext_stream, cpu_dai, codec_dai, false);
512 		if (ret < 0) {
513 			dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__);
514 			return ret;
515 		}
516 		break;
517 	}
518 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
519 	{
520 		ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
521 						  SOF_IPC4_PIPE_PAUSED);
522 		if (ret < 0)
523 			return ret;
524 
525 		pipeline->state = SOF_IPC4_PIPE_PAUSED;
526 
527 		snd_hdac_ext_stream_clear(hext_stream);
528 		break;
529 	}
530 	default:
531 		dev_err(sdev->dev, "%s: unknown trigger command %d\n", __func__, cmd);
532 		return -EINVAL;
533 	}
534 
535 	return 0;
536 }
537 
538 static int hda_dai_hw_free(struct snd_pcm_substream *substream,
539 			   struct snd_soc_dai *dai)
540 {
541 	int ret;
542 
543 	ret = hda_link_dma_hw_free(substream);
544 	if (ret < 0)
545 		return ret;
546 
547 	return hda_dai_hw_free_ipc(substream->stream, dai);
548 }
549 
550 static const struct snd_soc_dai_ops ipc3_hda_dai_ops = {
551 	.hw_params = hda_dai_hw_params,
552 	.hw_free = hda_dai_hw_free,
553 	.trigger = ipc3_hda_dai_trigger,
554 	.prepare = hda_dai_prepare,
555 };
556 
557 static int hda_dai_suspend(struct hdac_bus *bus)
558 {
559 	struct snd_soc_pcm_runtime *rtd;
560 	struct hdac_ext_stream *hext_stream;
561 	struct hdac_stream *s;
562 	int ret;
563 
564 	/* set internal flag for BE */
565 	list_for_each_entry(s, &bus->stream_list, list) {
566 
567 		hext_stream = stream_to_hdac_ext_stream(s);
568 
569 		/*
570 		 * clear stream. This should already be taken care for running
571 		 * streams when the SUSPEND trigger is called. But paused
572 		 * streams do not get suspended, so this needs to be done
573 		 * explicitly during suspend.
574 		 */
575 		if (hext_stream->link_substream) {
576 			struct snd_soc_dai *cpu_dai;
577 			struct snd_soc_dai *codec_dai;
578 
579 			rtd = asoc_substream_to_rtd(hext_stream->link_substream);
580 			cpu_dai = asoc_rtd_to_cpu(rtd, 0);
581 			codec_dai = asoc_rtd_to_codec(rtd, 0);
582 
583 			ret = hda_link_dma_cleanup(hext_stream->link_substream,
584 						   hext_stream,
585 						   cpu_dai, codec_dai, false);
586 			if (ret < 0)
587 				return ret;
588 
589 			/* for consistency with TRIGGER_SUSPEND we free DAI resources */
590 			ret = hda_dai_hw_free_ipc(hdac_stream(hext_stream)->direction, cpu_dai);
591 			if (ret < 0)
592 				return ret;
593 		}
594 	}
595 
596 	return 0;
597 }
598 
599 static const struct snd_soc_dai_ops ipc4_hda_dai_ops = {
600 	.hw_params = hda_dai_hw_params,
601 	.hw_free = hda_dai_hw_free,
602 	.trigger = ipc4_hda_dai_trigger,
603 	.prepare = hda_dai_prepare,
604 };
605 
606 #endif
607 
608 /* only one flag used so far to harden hw_params/hw_free/trigger/prepare */
609 struct ssp_dai_dma_data {
610 	bool setup;
611 };
612 
613 static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
614 				 bool setup)
615 {
616 	struct snd_soc_dapm_widget *w;
617 
618 	w = snd_soc_dai_get_widget(dai, substream->stream);
619 
620 	if (setup)
621 		return hda_ctrl_dai_widget_setup(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL);
622 
623 	return hda_ctrl_dai_widget_free(w, SOF_DAI_CONFIG_FLAGS_NONE, NULL);
624 }
625 
626 static int ssp_dai_startup(struct snd_pcm_substream *substream,
627 			   struct snd_soc_dai *dai)
628 {
629 	struct ssp_dai_dma_data *dma_data;
630 
631 	dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
632 	if (!dma_data)
633 		return -ENOMEM;
634 
635 	snd_soc_dai_set_dma_data(dai, substream, dma_data);
636 
637 	return 0;
638 }
639 
640 static int ssp_dai_setup(struct snd_pcm_substream *substream,
641 			 struct snd_soc_dai *dai,
642 			 bool setup)
643 {
644 	struct ssp_dai_dma_data *dma_data;
645 	int ret = 0;
646 
647 	dma_data = snd_soc_dai_get_dma_data(dai, substream);
648 	if (!dma_data) {
649 		dev_err(dai->dev, "%s: failed to get dma_data\n", __func__);
650 		return -EIO;
651 	}
652 
653 	if (dma_data->setup != setup) {
654 		ret = ssp_dai_setup_or_free(substream, dai, setup);
655 		if (!ret)
656 			dma_data->setup = setup;
657 	}
658 	return ret;
659 }
660 
661 static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
662 			     struct snd_pcm_hw_params *params,
663 			     struct snd_soc_dai *dai)
664 {
665 	/* params are ignored for now */
666 	return ssp_dai_setup(substream, dai, true);
667 }
668 
669 static int ssp_dai_prepare(struct snd_pcm_substream *substream,
670 			   struct snd_soc_dai *dai)
671 {
672 	/*
673 	 * the SSP will only be reconfigured during resume operations and
674 	 * not in case of xruns
675 	 */
676 	return ssp_dai_setup(substream, dai, true);
677 }
678 
679 static int ipc3_ssp_dai_trigger(struct snd_pcm_substream *substream,
680 				int cmd, struct snd_soc_dai *dai)
681 {
682 	if (cmd != SNDRV_PCM_TRIGGER_SUSPEND)
683 		return 0;
684 
685 	return ssp_dai_setup(substream, dai, false);
686 }
687 
688 static int ssp_dai_hw_free(struct snd_pcm_substream *substream,
689 			   struct snd_soc_dai *dai)
690 {
691 	return ssp_dai_setup(substream, dai, false);
692 }
693 
694 static void ssp_dai_shutdown(struct snd_pcm_substream *substream,
695 			     struct snd_soc_dai *dai)
696 {
697 	struct ssp_dai_dma_data *dma_data;
698 
699 	dma_data = snd_soc_dai_get_dma_data(dai, substream);
700 	if (!dma_data) {
701 		dev_err(dai->dev, "%s: failed to get dma_data\n", __func__);
702 		return;
703 	}
704 	snd_soc_dai_set_dma_data(dai, substream, NULL);
705 	kfree(dma_data);
706 }
707 
708 static const struct snd_soc_dai_ops ipc3_ssp_dai_ops = {
709 	.startup = ssp_dai_startup,
710 	.hw_params = ssp_dai_hw_params,
711 	.prepare = ssp_dai_prepare,
712 	.trigger = ipc3_ssp_dai_trigger,
713 	.hw_free = ssp_dai_hw_free,
714 	.shutdown = ssp_dai_shutdown,
715 };
716 
717 void hda_set_dai_drv_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *ops)
718 {
719 	int i;
720 
721 	switch (sdev->pdata->ipc_type) {
722 	case SOF_IPC:
723 		for (i = 0; i < ops->num_drv; i++) {
724 			if (strstr(ops->drv[i].name, "SSP")) {
725 				ops->drv[i].ops = &ipc3_ssp_dai_ops;
726 				continue;
727 			}
728 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
729 			if (strstr(ops->drv[i].name, "iDisp") ||
730 			    strstr(ops->drv[i].name, "Analog") ||
731 			    strstr(ops->drv[i].name, "Digital"))
732 				ops->drv[i].ops = &ipc3_hda_dai_ops;
733 #endif
734 		}
735 		break;
736 	case SOF_INTEL_IPC4:
737 	{
738 		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
739 
740 		for (i = 0; i < ops->num_drv; i++) {
741 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
742 			if (strstr(ops->drv[i].name, "iDisp") ||
743 			    strstr(ops->drv[i].name, "Analog") ||
744 			    strstr(ops->drv[i].name, "Digital"))
745 				ops->drv[i].ops = &ipc4_hda_dai_ops;
746 #endif
747 		}
748 
749 		if (!hda_use_tplg_nhlt)
750 			ipc4_data->nhlt = intel_nhlt_init(sdev->dev);
751 
752 		break;
753 	}
754 	default:
755 		break;
756 	}
757 }
758 
759 void hda_ops_free(struct snd_sof_dev *sdev)
760 {
761 	if (sdev->pdata->ipc_type == SOF_INTEL_IPC4) {
762 		struct sof_ipc4_fw_data *ipc4_data = sdev->private;
763 
764 		if (!hda_use_tplg_nhlt)
765 			intel_nhlt_free(ipc4_data->nhlt);
766 	}
767 }
768 EXPORT_SYMBOL_NS(hda_ops_free, SND_SOC_SOF_INTEL_HDA_COMMON);
769 
770 /*
771  * common dai driver for skl+ platforms.
772  * some products who use this DAI array only physically have a subset of
773  * the DAIs, but no harm is done here by adding the whole set.
774  */
775 struct snd_soc_dai_driver skl_dai[] = {
776 {
777 	.name = "SSP0 Pin",
778 	.playback = {
779 		.channels_min = 1,
780 		.channels_max = 8,
781 	},
782 	.capture = {
783 		.channels_min = 1,
784 		.channels_max = 8,
785 	},
786 },
787 {
788 	.name = "SSP1 Pin",
789 	.playback = {
790 		.channels_min = 1,
791 		.channels_max = 8,
792 	},
793 	.capture = {
794 		.channels_min = 1,
795 		.channels_max = 8,
796 	},
797 },
798 {
799 	.name = "SSP2 Pin",
800 	.playback = {
801 		.channels_min = 1,
802 		.channels_max = 8,
803 	},
804 	.capture = {
805 		.channels_min = 1,
806 		.channels_max = 8,
807 	},
808 },
809 {
810 	.name = "SSP3 Pin",
811 	.playback = {
812 		.channels_min = 1,
813 		.channels_max = 8,
814 	},
815 	.capture = {
816 		.channels_min = 1,
817 		.channels_max = 8,
818 	},
819 },
820 {
821 	.name = "SSP4 Pin",
822 	.playback = {
823 		.channels_min = 1,
824 		.channels_max = 8,
825 	},
826 	.capture = {
827 		.channels_min = 1,
828 		.channels_max = 8,
829 	},
830 },
831 {
832 	.name = "SSP5 Pin",
833 	.playback = {
834 		.channels_min = 1,
835 		.channels_max = 8,
836 	},
837 	.capture = {
838 		.channels_min = 1,
839 		.channels_max = 8,
840 	},
841 },
842 {
843 	.name = "DMIC01 Pin",
844 	.capture = {
845 		.channels_min = 1,
846 		.channels_max = 4,
847 	},
848 },
849 {
850 	.name = "DMIC16k Pin",
851 	.capture = {
852 		.channels_min = 1,
853 		.channels_max = 4,
854 	},
855 },
856 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
857 {
858 	.name = "iDisp1 Pin",
859 	.playback = {
860 		.channels_min = 1,
861 		.channels_max = 8,
862 	},
863 },
864 {
865 	.name = "iDisp2 Pin",
866 	.playback = {
867 		.channels_min = 1,
868 		.channels_max = 8,
869 	},
870 },
871 {
872 	.name = "iDisp3 Pin",
873 	.playback = {
874 		.channels_min = 1,
875 		.channels_max = 8,
876 	},
877 },
878 {
879 	.name = "iDisp4 Pin",
880 	.playback = {
881 		.channels_min = 1,
882 		.channels_max = 8,
883 	},
884 },
885 {
886 	.name = "Analog CPU DAI",
887 	.playback = {
888 		.channels_min = 1,
889 		.channels_max = 16,
890 	},
891 	.capture = {
892 		.channels_min = 1,
893 		.channels_max = 16,
894 	},
895 },
896 {
897 	.name = "Digital CPU DAI",
898 	.playback = {
899 		.channels_min = 1,
900 		.channels_max = 16,
901 	},
902 	.capture = {
903 		.channels_min = 1,
904 		.channels_max = 16,
905 	},
906 },
907 {
908 	.name = "Alt Analog CPU DAI",
909 	.playback = {
910 		.channels_min = 1,
911 		.channels_max = 16,
912 	},
913 	.capture = {
914 		.channels_min = 1,
915 		.channels_max = 16,
916 	},
917 },
918 #endif
919 };
920 
921 int hda_dsp_dais_suspend(struct snd_sof_dev *sdev)
922 {
923 	/*
924 	 * In the corner case where a SUSPEND happens during a PAUSE, the ALSA core
925 	 * does not throw the TRIGGER_SUSPEND. This leaves the DAIs in an unbalanced state.
926 	 * Since the component suspend is called last, we can trap this corner case
927 	 * and force the DAIs to release their resources.
928 	 */
929 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
930 	int ret;
931 
932 	ret = hda_dai_suspend(sof_to_bus(sdev));
933 	if (ret < 0)
934 		return ret;
935 #endif
936 
937 	return 0;
938 }
939