xref: /openbmc/linux/sound/soc/sof/intel/hda-dai.c (revision c4a11bf4)
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 "../sof-priv.h"
14 #include "../sof-audio.h"
15 #include "hda.h"
16 
17 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
18 
19 #if IS_ENABLED(CONFIG_SND_SOC_SOF_DEBUG_PROBES)
20 #include "../sof-probes.h"
21 #endif
22 
23 struct hda_pipe_params {
24 	u8 host_dma_id;
25 	u8 link_dma_id;
26 	u32 ch;
27 	u32 s_freq;
28 	u32 s_fmt;
29 	u8 linktype;
30 	snd_pcm_format_t format;
31 	int link_index;
32 	int stream;
33 	unsigned int host_bps;
34 	unsigned int link_bps;
35 };
36 
37 /*
38  * This function checks if the host dma channel corresponding
39  * to the link DMA stream_tag argument is assigned to one
40  * of the FEs connected to the BE DAI.
41  */
42 static bool hda_check_fes(struct snd_soc_pcm_runtime *rtd,
43 			  int dir, int stream_tag)
44 {
45 	struct snd_pcm_substream *fe_substream;
46 	struct hdac_stream *fe_hstream;
47 	struct snd_soc_dpcm *dpcm;
48 
49 	for_each_dpcm_fe(rtd, dir, dpcm) {
50 		fe_substream = snd_soc_dpcm_get_substream(dpcm->fe, dir);
51 		fe_hstream = fe_substream->runtime->private_data;
52 		if (fe_hstream->stream_tag == stream_tag)
53 			return true;
54 	}
55 
56 	return false;
57 }
58 
59 static struct hdac_ext_stream *
60 	hda_link_stream_assign(struct hdac_bus *bus,
61 			       struct snd_pcm_substream *substream)
62 {
63 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
64 	struct sof_intel_hda_stream *hda_stream;
65 	struct hdac_ext_stream *res = NULL;
66 	struct hdac_stream *stream = NULL;
67 
68 	int stream_dir = substream->stream;
69 
70 	if (!bus->ppcap) {
71 		dev_err(bus->dev, "stream type not supported\n");
72 		return NULL;
73 	}
74 
75 	spin_lock_irq(&bus->reg_lock);
76 	list_for_each_entry(stream, &bus->stream_list, list) {
77 		struct hdac_ext_stream *hstream =
78 			stream_to_hdac_ext_stream(stream);
79 		if (stream->direction != substream->stream)
80 			continue;
81 
82 		hda_stream = hstream_to_sof_hda_stream(hstream);
83 
84 		/* check if link is available */
85 		if (!hstream->link_locked) {
86 			if (stream->opened) {
87 				/*
88 				 * check if the stream tag matches the stream
89 				 * tag of one of the connected FEs
90 				 */
91 				if (hda_check_fes(rtd, stream_dir,
92 						  stream->stream_tag)) {
93 					res = hstream;
94 					break;
95 				}
96 			} else {
97 				res = hstream;
98 
99 				/*
100 				 * This must be a hostless stream.
101 				 * So reserve the host DMA channel.
102 				 */
103 				hda_stream->host_reserved = 1;
104 				break;
105 			}
106 		}
107 	}
108 
109 	if (res) {
110 		/*
111 		 * Decouple host and link DMA. The decoupled flag
112 		 * is updated in snd_hdac_ext_stream_decouple().
113 		 */
114 		if (!res->decoupled)
115 			snd_hdac_ext_stream_decouple_locked(bus, res, true);
116 
117 		res->link_locked = 1;
118 		res->link_substream = substream;
119 	}
120 	spin_unlock_irq(&bus->reg_lock);
121 
122 	return res;
123 }
124 
125 static int hda_link_dma_params(struct hdac_ext_stream *stream,
126 			       struct hda_pipe_params *params)
127 {
128 	struct hdac_stream *hstream = &stream->hstream;
129 	unsigned char stream_tag = hstream->stream_tag;
130 	struct hdac_bus *bus = hstream->bus;
131 	struct hdac_ext_link *link;
132 	unsigned int format_val;
133 
134 	snd_hdac_ext_stream_decouple(bus, stream, true);
135 	snd_hdac_ext_link_stream_reset(stream);
136 
137 	format_val = snd_hdac_calc_stream_format(params->s_freq, params->ch,
138 						 params->format,
139 						 params->link_bps, 0);
140 
141 	dev_dbg(bus->dev, "format_val=%d, rate=%d, ch=%d, format=%d\n",
142 		format_val, params->s_freq, params->ch, params->format);
143 
144 	snd_hdac_ext_link_stream_setup(stream, format_val);
145 
146 	if (stream->hstream.direction == SNDRV_PCM_STREAM_PLAYBACK) {
147 		list_for_each_entry(link, &bus->hlink_list, list) {
148 			if (link->index == params->link_index)
149 				snd_hdac_ext_link_set_stream_id(link,
150 								stream_tag);
151 		}
152 	}
153 
154 	stream->link_prepared = 1;
155 
156 	return 0;
157 }
158 
159 /* Update config for the DAI widget */
160 static struct sof_ipc_dai_config *hda_dai_update_config(struct snd_soc_dapm_widget *w,
161 							int channel)
162 {
163 	struct snd_sof_widget *swidget = w->dobj.private;
164 	struct sof_ipc_dai_config *config;
165 	struct snd_sof_dai *sof_dai;
166 
167 	if (!swidget)
168 		return NULL;
169 
170 	sof_dai = swidget->private;
171 
172 	if (!sof_dai || !sof_dai->dai_config) {
173 		dev_err(swidget->scomp->dev, "error: No config for DAI %s\n", w->name);
174 		return NULL;
175 	}
176 
177 	config = &sof_dai->dai_config[sof_dai->current_config];
178 
179 	/* update config with stream tag */
180 	config->hda.link_dma_ch = channel;
181 
182 	return config;
183 }
184 
185 static int hda_link_config_ipc(struct sof_intel_hda_stream *hda_stream,
186 			       struct snd_soc_dapm_widget *w, int channel)
187 {
188 	struct snd_sof_dev *sdev = hda_stream->sdev;
189 	struct sof_ipc_dai_config *config;
190 	struct sof_ipc_reply reply;
191 
192 	config = hda_dai_update_config(w, channel);
193 	if (!config) {
194 		dev_err(sdev->dev, "error: no config for DAI %s\n", w->name);
195 		return -ENOENT;
196 	}
197 
198 	/* send DAI_CONFIG IPC */
199 	return sof_ipc_tx_message(sdev->ipc, config->hdr.cmd, config, config->hdr.size,
200 				  &reply, sizeof(reply));
201 }
202 
203 static int hda_link_dai_widget_update(struct sof_intel_hda_stream *hda_stream,
204 				      struct snd_soc_dapm_widget *w,
205 				      int channel, bool widget_setup)
206 {
207 	struct snd_sof_dev *sdev = hda_stream->sdev;
208 	struct sof_ipc_dai_config *config;
209 
210 	config = hda_dai_update_config(w, channel);
211 	if (!config) {
212 		dev_err(sdev->dev, "error: no config for DAI %s\n", w->name);
213 		return -ENOENT;
214 	}
215 
216 	/* set up/free DAI widget and send DAI_CONFIG IPC */
217 	if (widget_setup)
218 		return hda_ctrl_dai_widget_setup(w);
219 
220 	return hda_ctrl_dai_widget_free(w);
221 }
222 
223 static int hda_link_hw_params(struct snd_pcm_substream *substream,
224 			      struct snd_pcm_hw_params *params,
225 			      struct snd_soc_dai *dai)
226 {
227 	struct hdac_stream *hstream = substream->runtime->private_data;
228 	struct hdac_bus *bus = hstream->bus;
229 	struct hdac_ext_stream *link_dev;
230 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
231 	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
232 	struct sof_intel_hda_stream *hda_stream;
233 	struct hda_pipe_params p_params = {0};
234 	struct snd_soc_dapm_widget *w;
235 	struct hdac_ext_link *link;
236 	int stream_tag;
237 	int ret;
238 
239 	/* get stored dma data if resuming from system suspend */
240 	link_dev = snd_soc_dai_get_dma_data(dai, substream);
241 	if (!link_dev) {
242 		link_dev = hda_link_stream_assign(bus, substream);
243 		if (!link_dev)
244 			return -EBUSY;
245 
246 		snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev);
247 	}
248 
249 	stream_tag = hdac_stream(link_dev)->stream_tag;
250 
251 	hda_stream = hstream_to_sof_hda_stream(link_dev);
252 
253 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
254 		w = dai->playback_widget;
255 	else
256 		w = dai->capture_widget;
257 
258 	/* set up the DAI widget and send the DAI_CONFIG with the new tag */
259 	ret = hda_link_dai_widget_update(hda_stream, w, stream_tag - 1, true);
260 	if (ret < 0)
261 		return ret;
262 
263 	link = snd_hdac_ext_bus_get_link(bus, codec_dai->component->name);
264 	if (!link)
265 		return -EINVAL;
266 
267 	/* set the stream tag in the codec dai dma params */
268 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
269 		snd_soc_dai_set_tdm_slot(codec_dai, stream_tag, 0, 0, 0);
270 	else
271 		snd_soc_dai_set_tdm_slot(codec_dai, 0, stream_tag, 0, 0);
272 
273 	p_params.s_fmt = snd_pcm_format_width(params_format(params));
274 	p_params.ch = params_channels(params);
275 	p_params.s_freq = params_rate(params);
276 	p_params.stream = substream->stream;
277 	p_params.link_dma_id = stream_tag - 1;
278 	p_params.link_index = link->index;
279 	p_params.format = params_format(params);
280 
281 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
282 		p_params.link_bps = codec_dai->driver->playback.sig_bits;
283 	else
284 		p_params.link_bps = codec_dai->driver->capture.sig_bits;
285 
286 	return hda_link_dma_params(link_dev, &p_params);
287 }
288 
289 static int hda_link_pcm_prepare(struct snd_pcm_substream *substream,
290 				struct snd_soc_dai *dai)
291 {
292 	struct hdac_ext_stream *link_dev =
293 				snd_soc_dai_get_dma_data(dai, substream);
294 	struct snd_sof_dev *sdev =
295 				snd_soc_component_get_drvdata(dai->component);
296 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
297 	int stream = substream->stream;
298 
299 	if (link_dev->link_prepared)
300 		return 0;
301 
302 	dev_dbg(sdev->dev, "hda: prepare stream dir %d\n", substream->stream);
303 
304 	return hda_link_hw_params(substream, &rtd->dpcm[stream].hw_params,
305 				  dai);
306 }
307 
308 static int hda_link_pcm_trigger(struct snd_pcm_substream *substream,
309 				int cmd, struct snd_soc_dai *dai)
310 {
311 	struct hdac_ext_stream *link_dev =
312 				snd_soc_dai_get_dma_data(dai, substream);
313 	struct sof_intel_hda_stream *hda_stream;
314 	struct snd_soc_pcm_runtime *rtd;
315 	struct snd_soc_dapm_widget *w;
316 	struct hdac_ext_link *link;
317 	struct hdac_stream *hstream;
318 	struct hdac_bus *bus;
319 	int stream_tag;
320 	int ret;
321 
322 	hstream = substream->runtime->private_data;
323 	bus = hstream->bus;
324 	rtd = asoc_substream_to_rtd(substream);
325 
326 	link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
327 	if (!link)
328 		return -EINVAL;
329 
330 	hda_stream = hstream_to_sof_hda_stream(link_dev);
331 
332 	dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd);
333 	switch (cmd) {
334 	case SNDRV_PCM_TRIGGER_RESUME:
335 		/* set up hw_params */
336 		ret = hda_link_pcm_prepare(substream, dai);
337 		if (ret < 0) {
338 			dev_err(dai->dev,
339 				"error: setting up hw_params during resume\n");
340 			return ret;
341 		}
342 
343 		fallthrough;
344 	case SNDRV_PCM_TRIGGER_START:
345 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
346 		snd_hdac_ext_link_stream_start(link_dev);
347 		break;
348 	case SNDRV_PCM_TRIGGER_SUSPEND:
349 	case SNDRV_PCM_TRIGGER_STOP:
350 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
351 			w = dai->playback_widget;
352 		else
353 			w = dai->capture_widget;
354 
355 		/*
356 		 * clear link DMA channel. It will be assigned when
357 		 * hw_params is set up again after resume.
358 		 */
359 		ret = hda_link_config_ipc(hda_stream, w, DMA_CHAN_INVALID);
360 		if (ret < 0)
361 			return ret;
362 
363 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
364 			stream_tag = hdac_stream(link_dev)->stream_tag;
365 			snd_hdac_ext_link_clear_stream_id(link, stream_tag);
366 		}
367 
368 		link_dev->link_prepared = 0;
369 
370 		fallthrough;
371 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
372 		snd_hdac_ext_link_stream_clear(link_dev);
373 		break;
374 	default:
375 		return -EINVAL;
376 	}
377 	return 0;
378 }
379 
380 static int hda_link_hw_free(struct snd_pcm_substream *substream,
381 			    struct snd_soc_dai *dai)
382 {
383 	unsigned int stream_tag;
384 	struct sof_intel_hda_stream *hda_stream;
385 	struct hdac_bus *bus;
386 	struct hdac_ext_link *link;
387 	struct hdac_stream *hstream;
388 	struct snd_soc_pcm_runtime *rtd;
389 	struct hdac_ext_stream *link_dev;
390 	struct snd_soc_dapm_widget *w;
391 	int ret;
392 
393 	hstream = substream->runtime->private_data;
394 	bus = hstream->bus;
395 	rtd = asoc_substream_to_rtd(substream);
396 	link_dev = snd_soc_dai_get_dma_data(dai, substream);
397 
398 	if (!link_dev) {
399 		dev_dbg(dai->dev,
400 			"%s: link_dev is not assigned\n", __func__);
401 		return -EINVAL;
402 	}
403 
404 	hda_stream = hstream_to_sof_hda_stream(link_dev);
405 
406 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
407 		w = dai->playback_widget;
408 	else
409 		w = dai->capture_widget;
410 
411 	/* free the link DMA channel in the FW and the DAI widget */
412 	ret = hda_link_dai_widget_update(hda_stream, w, DMA_CHAN_INVALID, false);
413 	if (ret < 0)
414 		return ret;
415 
416 	link = snd_hdac_ext_bus_get_link(bus, asoc_rtd_to_codec(rtd, 0)->component->name);
417 	if (!link)
418 		return -EINVAL;
419 
420 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
421 		stream_tag = hdac_stream(link_dev)->stream_tag;
422 		snd_hdac_ext_link_clear_stream_id(link, stream_tag);
423 	}
424 
425 	snd_soc_dai_set_dma_data(dai, substream, NULL);
426 	snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK);
427 	link_dev->link_prepared = 0;
428 
429 	/* free the host DMA channel reserved by hostless streams */
430 	hda_stream->host_reserved = 0;
431 
432 	return 0;
433 }
434 
435 static const struct snd_soc_dai_ops hda_link_dai_ops = {
436 	.hw_params = hda_link_hw_params,
437 	.hw_free = hda_link_hw_free,
438 	.trigger = hda_link_pcm_trigger,
439 	.prepare = hda_link_pcm_prepare,
440 };
441 
442 #endif
443 
444 /* only one flag used so far to harden hw_params/hw_free/trigger/prepare */
445 struct ssp_dai_dma_data {
446 	bool setup;
447 };
448 
449 static int ssp_dai_setup_or_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai,
450 				 bool setup)
451 {
452 	struct snd_soc_component *component;
453 	struct snd_sof_widget *swidget;
454 	struct snd_soc_dapm_widget *w;
455 	struct sof_ipc_fw_version *v;
456 	struct snd_sof_dev *sdev;
457 
458 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
459 		w = dai->playback_widget;
460 	else
461 		w = dai->capture_widget;
462 
463 	swidget = w->dobj.private;
464 	component = swidget->scomp;
465 	sdev = snd_soc_component_get_drvdata(component);
466 	v = &sdev->fw_ready.version;
467 
468 	/* DAI_CONFIG IPC during hw_params is not supported in older firmware */
469 	if (v->abi_version < SOF_ABI_VER(3, 18, 0))
470 		return 0;
471 
472 	if (setup)
473 		return hda_ctrl_dai_widget_setup(w);
474 
475 	return hda_ctrl_dai_widget_free(w);
476 }
477 
478 static int ssp_dai_startup(struct snd_pcm_substream *substream,
479 			   struct snd_soc_dai *dai)
480 {
481 	struct ssp_dai_dma_data *dma_data;
482 
483 	dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
484 	if (!dma_data)
485 		return -ENOMEM;
486 
487 	snd_soc_dai_set_dma_data(dai, substream, dma_data);
488 
489 	return 0;
490 }
491 
492 static int ssp_dai_setup(struct snd_pcm_substream *substream,
493 			 struct snd_soc_dai *dai,
494 			 bool setup)
495 {
496 	struct ssp_dai_dma_data *dma_data;
497 	int ret = 0;
498 
499 	dma_data = snd_soc_dai_get_dma_data(dai, substream);
500 	if (!dma_data) {
501 		dev_err(dai->dev, "%s: failed to get dma_data\n", __func__);
502 		return -EIO;
503 	}
504 
505 	if (dma_data->setup != setup) {
506 		ret = ssp_dai_setup_or_free(substream, dai, setup);
507 		if (!ret)
508 			dma_data->setup = setup;
509 	}
510 	return ret;
511 }
512 
513 static int ssp_dai_hw_params(struct snd_pcm_substream *substream,
514 			     struct snd_pcm_hw_params *params,
515 			     struct snd_soc_dai *dai)
516 {
517 	/* params are ignored for now */
518 	return ssp_dai_setup(substream, dai, true);
519 }
520 
521 static int ssp_dai_prepare(struct snd_pcm_substream *substream,
522 			   struct snd_soc_dai *dai)
523 {
524 	/*
525 	 * the SSP will only be reconfigured during resume operations and
526 	 * not in case of xruns
527 	 */
528 	return ssp_dai_setup(substream, dai, true);
529 }
530 
531 static int ssp_dai_trigger(struct snd_pcm_substream *substream,
532 			   int cmd, struct snd_soc_dai *dai)
533 {
534 	if (cmd != SNDRV_PCM_TRIGGER_SUSPEND)
535 		return 0;
536 
537 	return ssp_dai_setup(substream, dai, false);
538 }
539 
540 static int ssp_dai_hw_free(struct snd_pcm_substream *substream,
541 			   struct snd_soc_dai *dai)
542 {
543 	return ssp_dai_setup(substream, dai, false);
544 }
545 
546 static void ssp_dai_shutdown(struct snd_pcm_substream *substream,
547 			     struct snd_soc_dai *dai)
548 {
549 	struct ssp_dai_dma_data *dma_data;
550 
551 	dma_data = snd_soc_dai_get_dma_data(dai, substream);
552 	if (!dma_data) {
553 		dev_err(dai->dev, "%s: failed to get dma_data\n", __func__);
554 		return;
555 	}
556 	snd_soc_dai_set_dma_data(dai, substream, NULL);
557 	kfree(dma_data);
558 }
559 
560 static const struct snd_soc_dai_ops ssp_dai_ops = {
561 	.startup = ssp_dai_startup,
562 	.hw_params = ssp_dai_hw_params,
563 	.prepare = ssp_dai_prepare,
564 	.trigger = ssp_dai_trigger,
565 	.hw_free = ssp_dai_hw_free,
566 	.shutdown = ssp_dai_shutdown,
567 };
568 
569 /*
570  * common dai driver for skl+ platforms.
571  * some products who use this DAI array only physically have a subset of
572  * the DAIs, but no harm is done here by adding the whole set.
573  */
574 struct snd_soc_dai_driver skl_dai[] = {
575 {
576 	.name = "SSP0 Pin",
577 	.ops = &ssp_dai_ops,
578 	.playback = {
579 		.channels_min = 1,
580 		.channels_max = 8,
581 	},
582 	.capture = {
583 		.channels_min = 1,
584 		.channels_max = 8,
585 	},
586 },
587 {
588 	.name = "SSP1 Pin",
589 	.ops = &ssp_dai_ops,
590 	.playback = {
591 		.channels_min = 1,
592 		.channels_max = 8,
593 	},
594 	.capture = {
595 		.channels_min = 1,
596 		.channels_max = 8,
597 	},
598 },
599 {
600 	.name = "SSP2 Pin",
601 	.ops = &ssp_dai_ops,
602 	.playback = {
603 		.channels_min = 1,
604 		.channels_max = 8,
605 	},
606 	.capture = {
607 		.channels_min = 1,
608 		.channels_max = 8,
609 	},
610 },
611 {
612 	.name = "SSP3 Pin",
613 	.ops = &ssp_dai_ops,
614 	.playback = {
615 		.channels_min = 1,
616 		.channels_max = 8,
617 	},
618 	.capture = {
619 		.channels_min = 1,
620 		.channels_max = 8,
621 	},
622 },
623 {
624 	.name = "SSP4 Pin",
625 	.ops = &ssp_dai_ops,
626 	.playback = {
627 		.channels_min = 1,
628 		.channels_max = 8,
629 	},
630 	.capture = {
631 		.channels_min = 1,
632 		.channels_max = 8,
633 	},
634 },
635 {
636 	.name = "SSP5 Pin",
637 	.ops = &ssp_dai_ops,
638 	.playback = {
639 		.channels_min = 1,
640 		.channels_max = 8,
641 	},
642 	.capture = {
643 		.channels_min = 1,
644 		.channels_max = 8,
645 	},
646 },
647 {
648 	.name = "DMIC01 Pin",
649 	.capture = {
650 		.channels_min = 1,
651 		.channels_max = 4,
652 	},
653 },
654 {
655 	.name = "DMIC16k Pin",
656 	.capture = {
657 		.channels_min = 1,
658 		.channels_max = 4,
659 	},
660 },
661 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA)
662 {
663 	.name = "iDisp1 Pin",
664 	.ops = &hda_link_dai_ops,
665 	.playback = {
666 		.channels_min = 1,
667 		.channels_max = 8,
668 	},
669 },
670 {
671 	.name = "iDisp2 Pin",
672 	.ops = &hda_link_dai_ops,
673 	.playback = {
674 		.channels_min = 1,
675 		.channels_max = 8,
676 	},
677 },
678 {
679 	.name = "iDisp3 Pin",
680 	.ops = &hda_link_dai_ops,
681 	.playback = {
682 		.channels_min = 1,
683 		.channels_max = 8,
684 	},
685 },
686 {
687 	.name = "iDisp4 Pin",
688 	.ops = &hda_link_dai_ops,
689 	.playback = {
690 		.channels_min = 1,
691 		.channels_max = 8,
692 	},
693 },
694 {
695 	.name = "Analog CPU DAI",
696 	.ops = &hda_link_dai_ops,
697 	.playback = {
698 		.channels_min = 1,
699 		.channels_max = 16,
700 	},
701 	.capture = {
702 		.channels_min = 1,
703 		.channels_max = 16,
704 	},
705 },
706 {
707 	.name = "Digital CPU DAI",
708 	.ops = &hda_link_dai_ops,
709 	.playback = {
710 		.channels_min = 1,
711 		.channels_max = 16,
712 	},
713 	.capture = {
714 		.channels_min = 1,
715 		.channels_max = 16,
716 	},
717 },
718 {
719 	.name = "Alt Analog CPU DAI",
720 	.ops = &hda_link_dai_ops,
721 	.playback = {
722 		.channels_min = 1,
723 		.channels_max = 16,
724 	},
725 	.capture = {
726 		.channels_min = 1,
727 		.channels_max = 16,
728 	},
729 },
730 #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_PROBES)
731 {
732 	.name = "Probe Extraction CPU DAI",
733 	.compress_new = snd_soc_new_compress,
734 	.cops = &sof_probe_compr_ops,
735 	.capture = {
736 		.stream_name = "Probe Extraction",
737 		.channels_min = 1,
738 		.channels_max = 8,
739 		.rates = SNDRV_PCM_RATE_48000,
740 		.rate_min = 48000,
741 		.rate_max = 48000,
742 	},
743 },
744 #endif
745 #endif
746 };
747