xref: /linux/sound/soc/intel/boards/sof_board_helpers.c (revision c532de5a67a70f8533d495f8f2aaa9a0491c3ad0)
1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // Copyright(c) 2023 Intel Corporation
4 
5 #include <sound/soc.h>
6 #include "../common/soc-intel-quirks.h"
7 #include "hda_dsp_common.h"
8 #include "sof_board_helpers.h"
9 
10 /*
11  * Intel HDMI DAI Link
12  */
13 static int hdmi_init(struct snd_soc_pcm_runtime *rtd)
14 {
15 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card);
16 	struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0);
17 
18 	ctx->hdmi.hdmi_comp = dai->component;
19 
20 	return 0;
21 }
22 
23 int sof_intel_board_card_late_probe(struct snd_soc_card *card)
24 {
25 	struct sof_card_private *ctx = snd_soc_card_get_drvdata(card);
26 
27 	if (!ctx->hdmi_num)
28 		return 0;
29 
30 	if (!ctx->hdmi.idisp_codec)
31 		return 0;
32 
33 	if (!ctx->hdmi.hdmi_comp)
34 		return -EINVAL;
35 
36 	return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp);
37 }
38 EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, SND_SOC_INTEL_SOF_BOARD_HELPERS);
39 
40 /*
41  * DMIC DAI Link
42  */
43 static const struct snd_soc_dapm_widget dmic_widgets[] = {
44 	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
45 };
46 
47 static const struct snd_soc_dapm_route dmic_routes[] = {
48 	{"DMic", NULL, "SoC DMIC"},
49 };
50 
51 static int dmic_init(struct snd_soc_pcm_runtime *rtd)
52 {
53 	struct snd_soc_card *card = rtd->card;
54 	int ret;
55 
56 	ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets,
57 					ARRAY_SIZE(dmic_widgets));
58 	if (ret) {
59 		dev_err(rtd->dev, "fail to add dmic widgets, ret %d\n", ret);
60 		return ret;
61 	}
62 
63 	ret = snd_soc_dapm_add_routes(&card->dapm, dmic_routes,
64 				      ARRAY_SIZE(dmic_routes));
65 	if (ret) {
66 		dev_err(rtd->dev, "fail to add dmic routes, ret %d\n", ret);
67 		return ret;
68 	}
69 
70 	return 0;
71 }
72 
73 /*
74  * HDA External Codec DAI Link
75  */
76 static const struct snd_soc_dapm_widget hda_widgets[] = {
77 	SND_SOC_DAPM_MIC("Analog In", NULL),
78 	SND_SOC_DAPM_MIC("Digital In", NULL),
79 	SND_SOC_DAPM_MIC("Alt Analog In", NULL),
80 
81 	SND_SOC_DAPM_HP("Analog Out", NULL),
82 	SND_SOC_DAPM_SPK("Digital Out", NULL),
83 	SND_SOC_DAPM_HP("Alt Analog Out", NULL),
84 };
85 
86 static const struct snd_soc_dapm_route hda_routes[] = {
87 	{ "Codec Input Pin1", NULL, "Analog In" },
88 	{ "Codec Input Pin2", NULL, "Digital In" },
89 	{ "Codec Input Pin3", NULL, "Alt Analog In" },
90 
91 	{ "Analog Out", NULL, "Codec Output Pin1" },
92 	{ "Digital Out", NULL, "Codec Output Pin2" },
93 	{ "Alt Analog Out", NULL, "Codec Output Pin3" },
94 
95 	/* CODEC BE connections */
96 	{ "codec0_in", NULL, "Analog CPU Capture" },
97 	{ "Analog CPU Capture", NULL, "Analog Codec Capture" },
98 	{ "codec1_in", NULL, "Digital CPU Capture" },
99 	{ "Digital CPU Capture", NULL, "Digital Codec Capture" },
100 	{ "codec2_in", NULL, "Alt Analog CPU Capture" },
101 	{ "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" },
102 
103 	{ "Analog Codec Playback", NULL, "Analog CPU Playback" },
104 	{ "Analog CPU Playback", NULL, "codec0_out" },
105 	{ "Digital Codec Playback", NULL, "Digital CPU Playback" },
106 	{ "Digital CPU Playback", NULL, "codec1_out" },
107 	{ "Alt Analog Codec Playback", NULL, "Alt Analog CPU Playback" },
108 	{ "Alt Analog CPU Playback", NULL, "codec2_out" },
109 };
110 
111 static int hda_init(struct snd_soc_pcm_runtime *rtd)
112 {
113 	struct snd_soc_card *card = rtd->card;
114 	int ret;
115 
116 	ret = snd_soc_dapm_new_controls(&card->dapm, hda_widgets,
117 					ARRAY_SIZE(hda_widgets));
118 	if (ret) {
119 		dev_err(rtd->dev, "fail to add hda widgets, ret %d\n", ret);
120 		return ret;
121 	}
122 
123 	ret = snd_soc_dapm_add_routes(&card->dapm, hda_routes,
124 				      ARRAY_SIZE(hda_routes));
125 	if (ret)
126 		dev_err(rtd->dev, "fail to add hda routes, ret %d\n", ret);
127 
128 	return ret;
129 }
130 
131 /*
132  * DAI Link Helpers
133  */
134 
135 enum sof_dmic_be_type {
136 	SOF_DMIC_01,
137 	SOF_DMIC_16K,
138 };
139 
140 enum sof_hda_be_type {
141 	SOF_HDA_ANALOG,
142 	SOF_HDA_DIGITAL,
143 };
144 
145 /* DEFAULT_LINK_ORDER: the order used in sof_rt5682 */
146 #define DEFAULT_LINK_ORDER	SOF_LINK_ORDER(SOF_LINK_CODEC, \
147 					SOF_LINK_DMIC01,       \
148 					SOF_LINK_DMIC16K,      \
149 					SOF_LINK_IDISP_HDMI,   \
150 					SOF_LINK_AMP,          \
151 					SOF_LINK_BT_OFFLOAD,   \
152 					SOF_LINK_HDMI_IN)
153 
154 static struct snd_soc_dai_link_component dmic_component[] = {
155 	{
156 		.name = "dmic-codec",
157 		.dai_name = "dmic-hifi",
158 	}
159 };
160 
161 SND_SOC_DAILINK_DEF(hda_analog_cpus,
162 		    DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI")));
163 SND_SOC_DAILINK_DEF(hda_analog_codecs,
164 		    DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI")));
165 
166 SND_SOC_DAILINK_DEF(hda_digital_cpus,
167 		    DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI")));
168 SND_SOC_DAILINK_DEF(hda_digital_codecs,
169 		    DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI")));
170 
171 static struct snd_soc_dai_link_component platform_component[] = {
172 	{
173 		/* name might be overridden during probe */
174 		.name = "0000:00:1f.3"
175 	}
176 };
177 
178 static int set_ssp_codec_link(struct device *dev, struct snd_soc_dai_link *link,
179 			      int be_id, enum snd_soc_acpi_intel_codec codec_type,
180 			      int ssp_codec)
181 {
182 	struct snd_soc_dai_link_component *cpus;
183 
184 	dev_dbg(dev, "link %d: ssp codec %s, ssp %d\n", be_id,
185 		snd_soc_acpi_intel_get_codec_name(codec_type), ssp_codec);
186 
187 	/* link name */
188 	link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_codec);
189 	if (!link->name)
190 		return -ENOMEM;
191 
192 	/* cpus */
193 	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
194 			    GFP_KERNEL);
195 	if (!cpus)
196 		return -ENOMEM;
197 
198 	if (soc_intel_is_byt() || soc_intel_is_cht()) {
199 		/* backward-compatibility for BYT/CHT boards */
200 		cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "ssp%d-port",
201 						ssp_codec);
202 	} else {
203 		cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin",
204 						ssp_codec);
205 	}
206 	if (!cpus->dai_name)
207 		return -ENOMEM;
208 
209 	link->cpus = cpus;
210 	link->num_cpus = 1;
211 
212 	/* codecs - caller to handle */
213 
214 	/* platforms */
215 	link->platforms = platform_component;
216 	link->num_platforms = ARRAY_SIZE(platform_component);
217 
218 	link->id = be_id;
219 	link->no_pcm = 1;
220 	link->dpcm_capture = 1;
221 	link->dpcm_playback = 1;
222 
223 	return 0;
224 }
225 
226 static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link,
227 			 int be_id, enum sof_dmic_be_type be_type)
228 {
229 	struct snd_soc_dai_link_component *cpus;
230 
231 	/* cpus */
232 	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
233 			    GFP_KERNEL);
234 	if (!cpus)
235 		return -ENOMEM;
236 
237 	switch (be_type) {
238 	case SOF_DMIC_01:
239 		dev_dbg(dev, "link %d: dmic01\n", be_id);
240 
241 		link->name = "dmic01";
242 		cpus->dai_name = "DMIC01 Pin";
243 		break;
244 	case SOF_DMIC_16K:
245 		dev_dbg(dev, "link %d: dmic16k\n", be_id);
246 
247 		link->name = "dmic16k";
248 		cpus->dai_name = "DMIC16k Pin";
249 		break;
250 	default:
251 		dev_err(dev, "invalid be type %d\n", be_type);
252 		return -EINVAL;
253 	}
254 
255 	link->cpus = cpus;
256 	link->num_cpus = 1;
257 
258 	/* codecs */
259 	link->codecs = dmic_component;
260 	link->num_codecs = ARRAY_SIZE(dmic_component);
261 
262 	/* platforms */
263 	link->platforms = platform_component;
264 	link->num_platforms = ARRAY_SIZE(platform_component);
265 
266 	link->id = be_id;
267 	if (be_type == SOF_DMIC_01)
268 		link->init = dmic_init;
269 	link->ignore_suspend = 1;
270 	link->no_pcm = 1;
271 	link->dpcm_capture = 1;
272 
273 	return 0;
274 }
275 
276 static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link,
277 			       int be_id, int hdmi_id, bool idisp_codec)
278 {
279 	struct snd_soc_dai_link_component *cpus, *codecs;
280 
281 	dev_dbg(dev, "link %d: idisp hdmi %d, idisp codec %d\n", be_id, hdmi_id,
282 		idisp_codec);
283 
284 	/* link name */
285 	link->name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", hdmi_id);
286 	if (!link->name)
287 		return -ENOMEM;
288 
289 	/* cpus */
290 	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
291 			    GFP_KERNEL);
292 	if (!cpus)
293 		return -ENOMEM;
294 
295 	cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", hdmi_id);
296 	if (!cpus->dai_name)
297 		return -ENOMEM;
298 
299 	link->cpus = cpus;
300 	link->num_cpus = 1;
301 
302 	/* codecs */
303 	if (idisp_codec) {
304 		codecs = devm_kzalloc(dev,
305 				      sizeof(struct snd_soc_dai_link_component),
306 				      GFP_KERNEL);
307 		if (!codecs)
308 			return -ENOMEM;
309 
310 		codecs->name = "ehdaudio0D2";
311 		codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL,
312 						  "intel-hdmi-hifi%d", hdmi_id);
313 		if (!codecs->dai_name)
314 			return -ENOMEM;
315 
316 		link->codecs = codecs;
317 	} else {
318 		link->codecs = &snd_soc_dummy_dlc;
319 	}
320 	link->num_codecs = 1;
321 
322 	/* platforms */
323 	link->platforms = platform_component;
324 	link->num_platforms = ARRAY_SIZE(platform_component);
325 
326 	link->id = be_id;
327 	link->init = (hdmi_id == 1) ? hdmi_init : NULL;
328 	link->no_pcm = 1;
329 	link->dpcm_playback = 1;
330 
331 	return 0;
332 }
333 
334 static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link,
335 			    int be_id, enum snd_soc_acpi_intel_codec amp_type,
336 			    int ssp_amp)
337 {
338 	struct snd_soc_dai_link_component *cpus;
339 
340 	dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id,
341 		snd_soc_acpi_intel_get_codec_name(amp_type), ssp_amp);
342 
343 	/* link name */
344 	link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp);
345 	if (!link->name)
346 		return -ENOMEM;
347 
348 	/* cpus */
349 	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
350 			    GFP_KERNEL);
351 	if (!cpus)
352 		return -ENOMEM;
353 
354 	cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_amp);
355 	if (!cpus->dai_name)
356 		return -ENOMEM;
357 
358 	link->cpus = cpus;
359 	link->num_cpus = 1;
360 
361 	/* codecs - caller to handle */
362 
363 	/* platforms */
364 	link->platforms = platform_component;
365 	link->num_platforms = ARRAY_SIZE(platform_component);
366 
367 	link->id = be_id;
368 	link->no_pcm = 1;
369 	link->dpcm_capture = 1; /* feedback stream or firmware-generated echo reference */
370 	link->dpcm_playback = 1;
371 
372 	return 0;
373 }
374 
375 static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link,
376 			       int be_id, int ssp_bt)
377 {
378 	struct snd_soc_dai_link_component *cpus;
379 
380 	dev_dbg(dev, "link %d: bt offload, ssp %d\n", be_id, ssp_bt);
381 
382 	/* link name */
383 	link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", ssp_bt);
384 	if (!link->name)
385 		return -ENOMEM;
386 
387 	/* cpus */
388 	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
389 			    GFP_KERNEL);
390 	if (!cpus)
391 		return -ENOMEM;
392 
393 	cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_bt);
394 	if (!cpus->dai_name)
395 		return -ENOMEM;
396 
397 	link->cpus = cpus;
398 	link->num_cpus = 1;
399 
400 	/* codecs */
401 	link->codecs = &snd_soc_dummy_dlc;
402 	link->num_codecs = 1;
403 
404 	/* platforms */
405 	link->platforms = platform_component;
406 	link->num_platforms = ARRAY_SIZE(platform_component);
407 
408 	link->id = be_id;
409 	link->no_pcm = 1;
410 	link->dpcm_capture = 1;
411 	link->dpcm_playback = 1;
412 
413 	return 0;
414 }
415 
416 static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link,
417 			    int be_id, int ssp_hdmi)
418 {
419 	struct snd_soc_dai_link_component *cpus;
420 
421 	dev_dbg(dev, "link %d: hdmi-in, ssp %d\n", be_id, ssp_hdmi);
422 
423 	/* link name */
424 	link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", ssp_hdmi);
425 	if (!link->name)
426 		return -ENOMEM;
427 
428 	/* cpus */
429 	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
430 			    GFP_KERNEL);
431 	if (!cpus)
432 		return -ENOMEM;
433 
434 	cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_hdmi);
435 	if (!cpus->dai_name)
436 		return -ENOMEM;
437 
438 	link->cpus = cpus;
439 	link->num_cpus = 1;
440 
441 	/* codecs */
442 	link->codecs = &snd_soc_dummy_dlc;
443 	link->num_codecs = 1;
444 
445 	/* platforms */
446 	link->platforms = platform_component;
447 	link->num_platforms = ARRAY_SIZE(platform_component);
448 
449 	link->id = be_id;
450 	link->no_pcm = 1;
451 	link->dpcm_capture = 1;
452 
453 	return 0;
454 }
455 
456 static int set_hda_codec_link(struct device *dev, struct snd_soc_dai_link *link,
457 			      int be_id, enum sof_hda_be_type be_type)
458 {
459 	switch (be_type) {
460 	case SOF_HDA_ANALOG:
461 		dev_dbg(dev, "link %d: hda analog\n", be_id);
462 
463 		link->name = "Analog Playback and Capture";
464 
465 		/* cpus */
466 		link->cpus = hda_analog_cpus;
467 		link->num_cpus = ARRAY_SIZE(hda_analog_cpus);
468 
469 		/* codecs */
470 		link->codecs = hda_analog_codecs;
471 		link->num_codecs = ARRAY_SIZE(hda_analog_codecs);
472 		break;
473 	case SOF_HDA_DIGITAL:
474 		dev_dbg(dev, "link %d: hda digital\n", be_id);
475 
476 		link->name = "Digital Playback and Capture";
477 
478 		/* cpus */
479 		link->cpus = hda_digital_cpus;
480 		link->num_cpus = ARRAY_SIZE(hda_digital_cpus);
481 
482 		/* codecs */
483 		link->codecs = hda_digital_codecs;
484 		link->num_codecs = ARRAY_SIZE(hda_digital_codecs);
485 		break;
486 	default:
487 		dev_err(dev, "invalid be type %d\n", be_type);
488 		return -EINVAL;
489 	}
490 
491 	/* platforms */
492 	link->platforms = platform_component;
493 	link->num_platforms = ARRAY_SIZE(platform_component);
494 
495 	link->id = be_id;
496 	if (be_type == SOF_HDA_ANALOG)
497 		link->init = hda_init;
498 	link->no_pcm = 1;
499 	link->dpcm_capture = 1;
500 	link->dpcm_playback = 1;
501 
502 	return 0;
503 }
504 
505 static int calculate_num_links(struct sof_card_private *ctx)
506 {
507 	int num_links = 0;
508 
509 	/* headphone codec */
510 	if (ctx->codec_type != CODEC_NONE)
511 		num_links++;
512 
513 	/* dmic01 and dmic16k */
514 	if (ctx->dmic_be_num > 0)
515 		num_links++;
516 
517 	if (ctx->dmic_be_num > 1)
518 		num_links++;
519 
520 	/* idisp HDMI */
521 	num_links += ctx->hdmi_num;
522 
523 	/* speaker amp */
524 	if (ctx->amp_type != CODEC_NONE)
525 		num_links++;
526 
527 	/* BT audio offload */
528 	if (ctx->bt_offload_present)
529 		num_links++;
530 
531 	/* HDMI-In */
532 	num_links += hweight32(ctx->ssp_mask_hdmi_in);
533 
534 	/* HDA external codec */
535 	if (ctx->hda_codec_present)
536 		num_links += 2;
537 
538 	return num_links;
539 }
540 
541 int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
542 				 struct sof_card_private *ctx)
543 {
544 	struct snd_soc_dai_link *links;
545 	int num_links;
546 	int i;
547 	int idx = 0;
548 	int ret;
549 	int ssp_hdmi_in = 0;
550 	unsigned long link_order, link;
551 	unsigned long link_ids, be_id;
552 
553 	num_links = calculate_num_links(ctx);
554 
555 	links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link),
556 			     GFP_KERNEL);
557 	if (!links)
558 		return -ENOMEM;
559 
560 	if (ctx->link_order_overwrite)
561 		link_order = ctx->link_order_overwrite;
562 	else
563 		link_order = DEFAULT_LINK_ORDER;
564 
565 	if (ctx->link_id_overwrite)
566 		link_ids = ctx->link_id_overwrite;
567 	else
568 		link_ids = 0;
569 
570 	dev_dbg(dev, "create dai links, link_order 0x%lx, id_overwrite 0x%lx\n",
571 		link_order, link_ids);
572 
573 	while (link_order) {
574 		link = link_order & SOF_LINK_ORDER_MASK;
575 		link_order >>= SOF_LINK_ORDER_SHIFT;
576 
577 		if (ctx->link_id_overwrite) {
578 			be_id = link_ids & SOF_LINK_IDS_MASK;
579 			link_ids >>= SOF_LINK_IDS_SHIFT;
580 		} else {
581 			/* use array index as link id */
582 			be_id = idx;
583 		}
584 
585 		switch (link) {
586 		case SOF_LINK_CODEC:
587 			/* headphone codec */
588 			if (ctx->codec_type == CODEC_NONE)
589 				continue;
590 
591 			ret = set_ssp_codec_link(dev, &links[idx], be_id,
592 						 ctx->codec_type, ctx->ssp_codec);
593 			if (ret) {
594 				dev_err(dev, "fail to set codec link, ret %d\n",
595 					ret);
596 				return ret;
597 			}
598 
599 			ctx->codec_link = &links[idx];
600 			idx++;
601 			break;
602 		case SOF_LINK_DMIC01:
603 			/* dmic01 */
604 			if (ctx->dmic_be_num == 0)
605 				continue;
606 
607 			/* at least we have dmic01 */
608 			ret = set_dmic_link(dev, &links[idx], be_id, SOF_DMIC_01);
609 			if (ret) {
610 				dev_err(dev, "fail to set dmic01 link, ret %d\n",
611 					ret);
612 				return ret;
613 			}
614 
615 			idx++;
616 			break;
617 		case SOF_LINK_DMIC16K:
618 			/* dmic16k */
619 			if (ctx->dmic_be_num <= 1)
620 				continue;
621 
622 			/* set up 2 BE links at most */
623 			ret = set_dmic_link(dev, &links[idx], be_id,
624 					    SOF_DMIC_16K);
625 			if (ret) {
626 				dev_err(dev, "fail to set dmic16k link, ret %d\n",
627 					ret);
628 				return ret;
629 			}
630 
631 			idx++;
632 			break;
633 		case SOF_LINK_IDISP_HDMI:
634 			/* idisp HDMI */
635 			for (i = 1; i <= ctx->hdmi_num; i++) {
636 				ret = set_idisp_hdmi_link(dev, &links[idx],
637 							  be_id, i,
638 							  ctx->hdmi.idisp_codec);
639 				if (ret) {
640 					dev_err(dev, "fail to set hdmi link, ret %d\n",
641 						ret);
642 					return ret;
643 				}
644 
645 				idx++;
646 				be_id++;
647 			}
648 			break;
649 		case SOF_LINK_AMP:
650 			/* speaker amp */
651 			if (ctx->amp_type == CODEC_NONE)
652 				continue;
653 
654 			ret = set_ssp_amp_link(dev, &links[idx], be_id,
655 					       ctx->amp_type, ctx->ssp_amp);
656 			if (ret) {
657 				dev_err(dev, "fail to set amp link, ret %d\n",
658 					ret);
659 				return ret;
660 			}
661 
662 			ctx->amp_link = &links[idx];
663 			idx++;
664 			break;
665 		case SOF_LINK_BT_OFFLOAD:
666 			/* BT audio offload */
667 			if (!ctx->bt_offload_present)
668 				continue;
669 
670 			ret = set_bt_offload_link(dev, &links[idx], be_id,
671 						  ctx->ssp_bt);
672 			if (ret) {
673 				dev_err(dev, "fail to set bt link, ret %d\n",
674 					ret);
675 				return ret;
676 			}
677 
678 			idx++;
679 			break;
680 		case SOF_LINK_HDMI_IN:
681 			/* HDMI-In */
682 			for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) {
683 				ret = set_hdmi_in_link(dev, &links[idx], be_id,
684 						       ssp_hdmi_in);
685 				if (ret) {
686 					dev_err(dev, "fail to set hdmi-in link, ret %d\n",
687 						ret);
688 					return ret;
689 				}
690 
691 				idx++;
692 				be_id++;
693 			}
694 			break;
695 		case SOF_LINK_HDA:
696 			/* HDA external codec */
697 			if (!ctx->hda_codec_present)
698 				continue;
699 
700 			ret = set_hda_codec_link(dev, &links[idx], be_id,
701 						 SOF_HDA_ANALOG);
702 			if (ret) {
703 				dev_err(dev, "fail to set hda analog link, ret %d\n",
704 					ret);
705 				return ret;
706 			}
707 
708 			idx++;
709 			be_id++;
710 
711 			ret = set_hda_codec_link(dev, &links[idx], be_id,
712 						 SOF_HDA_DIGITAL);
713 			if (ret) {
714 				dev_err(dev, "fail to set hda digital link, ret %d\n",
715 					ret);
716 				return ret;
717 			}
718 
719 			idx++;
720 			break;
721 		case SOF_LINK_NONE:
722 			/* caught here if it's not used as terminator in macro */
723 			fallthrough;
724 		default:
725 			dev_err(dev, "invalid link type %ld\n", link);
726 			return -EINVAL;
727 		}
728 	}
729 
730 	if (idx != num_links) {
731 		dev_err(dev, "link number mismatch, idx %d, num_links %d\n", idx,
732 			num_links);
733 		return -EINVAL;
734 	}
735 
736 	card->dai_link = links;
737 	card->num_links = num_links;
738 
739 	return 0;
740 }
741 EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, SND_SOC_INTEL_SOF_BOARD_HELPERS);
742 
743 struct sof_card_private *
744 sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk)
745 {
746 	struct sof_card_private *ctx;
747 
748 	dev_dbg(dev, "create ctx, board_quirk 0x%lx\n", board_quirk);
749 
750 	ctx = devm_kzalloc(dev, sizeof(struct sof_card_private), GFP_KERNEL);
751 	if (!ctx)
752 		return NULL;
753 
754 	ctx->codec_type = snd_soc_acpi_intel_detect_codec_type(dev);
755 	ctx->amp_type = snd_soc_acpi_intel_detect_amp_type(dev);
756 
757 	ctx->dmic_be_num = 2;
758 	ctx->hdmi_num = (board_quirk & SOF_NUM_IDISP_HDMI_MASK) >>
759 			SOF_NUM_IDISP_HDMI_SHIFT;
760 	/* default number of HDMI DAI's */
761 	if (!ctx->hdmi_num)
762 		ctx->hdmi_num = 3;
763 
764 	/* port number/mask of peripherals attached to ssp interface */
765 	if (ctx->codec_type != CODEC_NONE)
766 		ctx->ssp_codec = (board_quirk & SOF_SSP_PORT_CODEC_MASK) >>
767 				SOF_SSP_PORT_CODEC_SHIFT;
768 
769 	if (ctx->amp_type != CODEC_NONE)
770 		ctx->ssp_amp = (board_quirk & SOF_SSP_PORT_AMP_MASK) >>
771 				SOF_SSP_PORT_AMP_SHIFT;
772 
773 	if (board_quirk & SOF_BT_OFFLOAD_PRESENT) {
774 		ctx->bt_offload_present = true;
775 		ctx->ssp_bt = (board_quirk & SOF_SSP_PORT_BT_OFFLOAD_MASK) >>
776 				SOF_SSP_PORT_BT_OFFLOAD_SHIFT;
777 	}
778 
779 	ctx->ssp_mask_hdmi_in = (board_quirk & SOF_SSP_MASK_HDMI_CAPTURE_MASK) >>
780 				SOF_SSP_MASK_HDMI_CAPTURE_SHIFT;
781 
782 	return ctx;
783 }
784 EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, SND_SOC_INTEL_SOF_BOARD_HELPERS);
785 
786 MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers");
787 MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
788 MODULE_LICENSE("GPL");
789 MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
790 MODULE_IMPORT_NS(SND_SOC_ACPI_INTEL_MATCH);
791