Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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 */
 13static 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
 23int 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}
 38EXPORT_SYMBOL_NS(sof_intel_board_card_late_probe, "SND_SOC_INTEL_SOF_BOARD_HELPERS");
 39
 40/*
 41 * DMIC DAI Link
 42 */
 43static const struct snd_soc_dapm_widget dmic_widgets[] = {
 44	SND_SOC_DAPM_MIC("SoC DMIC", NULL),
 45};
 46
 47static const struct snd_soc_dapm_route dmic_routes[] = {
 48	{"DMic", NULL, "SoC DMIC"},
 49};
 50
 51static 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 */
 76static 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
 86static 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
111static 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
135enum sof_dmic_be_type {
136	SOF_DMIC_01,
137	SOF_DMIC_16K,
138};
139
140enum 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
154static struct snd_soc_dai_link_component dmic_component[] = {
155	{
156		.name = "dmic-codec",
157		.dai_name = "dmic-hifi",
158	}
159};
160
161SND_SOC_DAILINK_DEF(hda_analog_cpus,
162		    DAILINK_COMP_ARRAY(COMP_CPU("Analog CPU DAI")));
163SND_SOC_DAILINK_DEF(hda_analog_codecs,
164		    DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Analog Codec DAI")));
165
166SND_SOC_DAILINK_DEF(hda_digital_cpus,
167		    DAILINK_COMP_ARRAY(COMP_CPU("Digital CPU DAI")));
168SND_SOC_DAILINK_DEF(hda_digital_codecs,
169		    DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D0", "Digital Codec DAI")));
170
171static 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
178static 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
221	return 0;
222}
223
224static int set_dmic_link(struct device *dev, struct snd_soc_dai_link *link,
225			 int be_id, enum sof_dmic_be_type be_type)
226{
227	struct snd_soc_dai_link_component *cpus;
228
229	/* cpus */
230	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
231			    GFP_KERNEL);
232	if (!cpus)
233		return -ENOMEM;
234
235	switch (be_type) {
236	case SOF_DMIC_01:
237		dev_dbg(dev, "link %d: dmic01\n", be_id);
238
239		link->name = "dmic01";
240		cpus->dai_name = "DMIC01 Pin";
241		break;
242	case SOF_DMIC_16K:
243		dev_dbg(dev, "link %d: dmic16k\n", be_id);
244
245		link->name = "dmic16k";
246		cpus->dai_name = "DMIC16k Pin";
247		break;
248	default:
249		dev_err(dev, "invalid be type %d\n", be_type);
250		return -EINVAL;
251	}
252
253	link->cpus = cpus;
254	link->num_cpus = 1;
255
256	/* codecs */
257	link->codecs = dmic_component;
258	link->num_codecs = ARRAY_SIZE(dmic_component);
259
260	/* platforms */
261	link->platforms = platform_component;
262	link->num_platforms = ARRAY_SIZE(platform_component);
263
264	link->id = be_id;
265	if (be_type == SOF_DMIC_01)
266		link->init = dmic_init;
267	link->ignore_suspend = 1;
268	link->no_pcm = 1;
269	link->capture_only = 1;
270
271	return 0;
272}
273
274static int set_idisp_hdmi_link(struct device *dev, struct snd_soc_dai_link *link,
275			       int be_id, int hdmi_id, bool idisp_codec)
276{
277	struct snd_soc_dai_link_component *cpus, *codecs;
278
279	dev_dbg(dev, "link %d: idisp hdmi %d, idisp codec %d\n", be_id, hdmi_id,
280		idisp_codec);
281
282	/* link name */
283	link->name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d", hdmi_id);
284	if (!link->name)
285		return -ENOMEM;
286
287	/* cpus */
288	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
289			    GFP_KERNEL);
290	if (!cpus)
291		return -ENOMEM;
292
293	cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "iDisp%d Pin", hdmi_id);
294	if (!cpus->dai_name)
295		return -ENOMEM;
296
297	link->cpus = cpus;
298	link->num_cpus = 1;
299
300	/* codecs */
301	if (idisp_codec) {
302		codecs = devm_kzalloc(dev,
303				      sizeof(struct snd_soc_dai_link_component),
304				      GFP_KERNEL);
305		if (!codecs)
306			return -ENOMEM;
307
308		codecs->name = "ehdaudio0D2";
309		codecs->dai_name = devm_kasprintf(dev, GFP_KERNEL,
310						  "intel-hdmi-hifi%d", hdmi_id);
311		if (!codecs->dai_name)
312			return -ENOMEM;
313
314		link->codecs = codecs;
315	} else {
316		link->codecs = &snd_soc_dummy_dlc;
317	}
318	link->num_codecs = 1;
319
320	/* platforms */
321	link->platforms = platform_component;
322	link->num_platforms = ARRAY_SIZE(platform_component);
323
324	link->id = be_id;
325	link->init = (hdmi_id == 1) ? hdmi_init : NULL;
326	link->no_pcm = 1;
327	link->playback_only = 1;
328
329	return 0;
330}
331
332static int set_ssp_amp_link(struct device *dev, struct snd_soc_dai_link *link,
333			    int be_id, enum snd_soc_acpi_intel_codec amp_type,
334			    int ssp_amp)
335{
336	struct snd_soc_dai_link_component *cpus;
337
338	dev_dbg(dev, "link %d: ssp amp %s, ssp %d\n", be_id,
339		snd_soc_acpi_intel_get_codec_name(amp_type), ssp_amp);
340
341	/* link name */
342	link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-Codec", ssp_amp);
343	if (!link->name)
344		return -ENOMEM;
345
346	/* cpus */
347	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
348			    GFP_KERNEL);
349	if (!cpus)
350		return -ENOMEM;
351
352	cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_amp);
353	if (!cpus->dai_name)
354		return -ENOMEM;
355
356	link->cpus = cpus;
357	link->num_cpus = 1;
358
359	/* codecs - caller to handle */
360
361	/* platforms */
362	/* feedback stream or firmware-generated echo reference */
363	link->platforms = platform_component;
364	link->num_platforms = ARRAY_SIZE(platform_component);
365
366	link->id = be_id;
367	link->no_pcm = 1;
368
369	return 0;
370}
371
372static int set_bt_offload_link(struct device *dev, struct snd_soc_dai_link *link,
373			       int be_id, int ssp_bt)
374{
375	struct snd_soc_dai_link_component *cpus;
376
377	dev_dbg(dev, "link %d: bt offload, ssp %d\n", be_id, ssp_bt);
378
379	/* link name */
380	link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-BT", ssp_bt);
381	if (!link->name)
382		return -ENOMEM;
383
384	/* cpus */
385	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
386			    GFP_KERNEL);
387	if (!cpus)
388		return -ENOMEM;
389
390	cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_bt);
391	if (!cpus->dai_name)
392		return -ENOMEM;
393
394	link->cpus = cpus;
395	link->num_cpus = 1;
396
397	/* codecs */
398	link->codecs = &snd_soc_dummy_dlc;
399	link->num_codecs = 1;
400
401	/* platforms */
402	link->platforms = platform_component;
403	link->num_platforms = ARRAY_SIZE(platform_component);
404
405	link->id = be_id;
406	link->no_pcm = 1;
407
408	return 0;
409}
410
411static int set_hdmi_in_link(struct device *dev, struct snd_soc_dai_link *link,
412			    int be_id, int ssp_hdmi)
413{
414	struct snd_soc_dai_link_component *cpus;
415
416	dev_dbg(dev, "link %d: hdmi-in, ssp %d\n", be_id, ssp_hdmi);
417
418	/* link name */
419	link->name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d-HDMI", ssp_hdmi);
420	if (!link->name)
421		return -ENOMEM;
422
423	/* cpus */
424	cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component),
425			    GFP_KERNEL);
426	if (!cpus)
427		return -ENOMEM;
428
429	cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "SSP%d Pin", ssp_hdmi);
430	if (!cpus->dai_name)
431		return -ENOMEM;
432
433	link->cpus = cpus;
434	link->num_cpus = 1;
435
436	/* codecs */
437	link->codecs = &snd_soc_dummy_dlc;
438	link->num_codecs = 1;
439
440	/* platforms */
441	link->platforms = platform_component;
442	link->num_platforms = ARRAY_SIZE(platform_component);
443
444	link->id = be_id;
445	link->no_pcm = 1;
446	link->capture_only = 1;
447
448	return 0;
449}
450
451static int set_hda_codec_link(struct device *dev, struct snd_soc_dai_link *link,
452			      int be_id, enum sof_hda_be_type be_type)
453{
454	switch (be_type) {
455	case SOF_HDA_ANALOG:
456		dev_dbg(dev, "link %d: hda analog\n", be_id);
457
458		link->name = "Analog Playback and Capture";
459
460		/* cpus */
461		link->cpus = hda_analog_cpus;
462		link->num_cpus = ARRAY_SIZE(hda_analog_cpus);
463
464		/* codecs */
465		link->codecs = hda_analog_codecs;
466		link->num_codecs = ARRAY_SIZE(hda_analog_codecs);
467		break;
468	case SOF_HDA_DIGITAL:
469		dev_dbg(dev, "link %d: hda digital\n", be_id);
470
471		link->name = "Digital Playback and Capture";
472
473		/* cpus */
474		link->cpus = hda_digital_cpus;
475		link->num_cpus = ARRAY_SIZE(hda_digital_cpus);
476
477		/* codecs */
478		link->codecs = hda_digital_codecs;
479		link->num_codecs = ARRAY_SIZE(hda_digital_codecs);
480		break;
481	default:
482		dev_err(dev, "invalid be type %d\n", be_type);
483		return -EINVAL;
484	}
485
486	/* platforms */
487	link->platforms = platform_component;
488	link->num_platforms = ARRAY_SIZE(platform_component);
489
490	link->id = be_id;
491	if (be_type == SOF_HDA_ANALOG)
492		link->init = hda_init;
493	link->no_pcm = 1;
494
495	return 0;
496}
497
498static int calculate_num_links(struct sof_card_private *ctx)
499{
500	int num_links = 0;
501
502	/* headphone codec */
503	if (ctx->codec_type != CODEC_NONE)
504		num_links++;
505
506	/* dmic01 and dmic16k */
507	if (ctx->dmic_be_num > 0)
508		num_links++;
509
510	if (ctx->dmic_be_num > 1)
511		num_links++;
512
513	/* idisp HDMI */
514	num_links += ctx->hdmi_num;
515
516	/* speaker amp */
517	if (ctx->amp_type != CODEC_NONE)
518		num_links++;
519
520	/* BT audio offload */
521	if (ctx->bt_offload_present)
522		num_links++;
523
524	/* HDMI-In */
525	num_links += hweight32(ctx->ssp_mask_hdmi_in);
526
527	/* HDA external codec */
528	if (ctx->hda_codec_present)
529		num_links += 2;
530
531	return num_links;
532}
533
534int sof_intel_board_set_dai_link(struct device *dev, struct snd_soc_card *card,
535				 struct sof_card_private *ctx)
536{
537	struct snd_soc_dai_link *links;
538	int num_links;
539	int i;
540	int idx = 0;
541	int ret;
542	int ssp_hdmi_in = 0;
543	unsigned long link_order, link;
544	unsigned long link_ids, be_id;
545
546	num_links = calculate_num_links(ctx);
547
548	links = devm_kcalloc(dev, num_links, sizeof(struct snd_soc_dai_link),
549			     GFP_KERNEL);
550	if (!links)
551		return -ENOMEM;
552
553	if (ctx->link_order_overwrite)
554		link_order = ctx->link_order_overwrite;
555	else
556		link_order = DEFAULT_LINK_ORDER;
557
558	if (ctx->link_id_overwrite)
559		link_ids = ctx->link_id_overwrite;
560	else
561		link_ids = 0;
562
563	dev_dbg(dev, "create dai links, link_order 0x%lx, id_overwrite 0x%lx\n",
564		link_order, link_ids);
565
566	while (link_order) {
567		link = link_order & SOF_LINK_ORDER_MASK;
568		link_order >>= SOF_LINK_ORDER_SHIFT;
569
570		if (ctx->link_id_overwrite) {
571			be_id = link_ids & SOF_LINK_IDS_MASK;
572			link_ids >>= SOF_LINK_IDS_SHIFT;
573		} else {
574			/* use array index as link id */
575			be_id = idx;
576		}
577
578		switch (link) {
579		case SOF_LINK_CODEC:
580			/* headphone codec */
581			if (ctx->codec_type == CODEC_NONE)
582				continue;
583
584			ret = set_ssp_codec_link(dev, &links[idx], be_id,
585						 ctx->codec_type, ctx->ssp_codec);
586			if (ret) {
587				dev_err(dev, "fail to set codec link, ret %d\n",
588					ret);
589				return ret;
590			}
591
592			ctx->codec_link = &links[idx];
593			idx++;
594			break;
595		case SOF_LINK_DMIC01:
596			/* dmic01 */
597			if (ctx->dmic_be_num == 0)
598				continue;
599
600			/* at least we have dmic01 */
601			ret = set_dmic_link(dev, &links[idx], be_id, SOF_DMIC_01);
602			if (ret) {
603				dev_err(dev, "fail to set dmic01 link, ret %d\n",
604					ret);
605				return ret;
606			}
607
608			idx++;
609			break;
610		case SOF_LINK_DMIC16K:
611			/* dmic16k */
612			if (ctx->dmic_be_num <= 1)
613				continue;
614
615			/* set up 2 BE links at most */
616			ret = set_dmic_link(dev, &links[idx], be_id,
617					    SOF_DMIC_16K);
618			if (ret) {
619				dev_err(dev, "fail to set dmic16k link, ret %d\n",
620					ret);
621				return ret;
622			}
623
624			idx++;
625			break;
626		case SOF_LINK_IDISP_HDMI:
627			/* idisp HDMI */
628			for (i = 1; i <= ctx->hdmi_num; i++) {
629				ret = set_idisp_hdmi_link(dev, &links[idx],
630							  be_id, i,
631							  ctx->hdmi.idisp_codec);
632				if (ret) {
633					dev_err(dev, "fail to set hdmi link, ret %d\n",
634						ret);
635					return ret;
636				}
637
638				idx++;
639				be_id++;
640			}
641			break;
642		case SOF_LINK_AMP:
643			/* speaker amp */
644			if (ctx->amp_type == CODEC_NONE)
645				continue;
646
647			ret = set_ssp_amp_link(dev, &links[idx], be_id,
648					       ctx->amp_type, ctx->ssp_amp);
649			if (ret) {
650				dev_err(dev, "fail to set amp link, ret %d\n",
651					ret);
652				return ret;
653			}
654
655			ctx->amp_link = &links[idx];
656			idx++;
657			break;
658		case SOF_LINK_BT_OFFLOAD:
659			/* BT audio offload */
660			if (!ctx->bt_offload_present)
661				continue;
662
663			ret = set_bt_offload_link(dev, &links[idx], be_id,
664						  ctx->ssp_bt);
665			if (ret) {
666				dev_err(dev, "fail to set bt link, ret %d\n",
667					ret);
668				return ret;
669			}
670
671			idx++;
672			break;
673		case SOF_LINK_HDMI_IN:
674			/* HDMI-In */
675			for_each_set_bit(ssp_hdmi_in, &ctx->ssp_mask_hdmi_in, 32) {
676				ret = set_hdmi_in_link(dev, &links[idx], be_id,
677						       ssp_hdmi_in);
678				if (ret) {
679					dev_err(dev, "fail to set hdmi-in link, ret %d\n",
680						ret);
681					return ret;
682				}
683
684				idx++;
685				be_id++;
686			}
687			break;
688		case SOF_LINK_HDA:
689			/* HDA external codec */
690			if (!ctx->hda_codec_present)
691				continue;
692
693			ret = set_hda_codec_link(dev, &links[idx], be_id,
694						 SOF_HDA_ANALOG);
695			if (ret) {
696				dev_err(dev, "fail to set hda analog link, ret %d\n",
697					ret);
698				return ret;
699			}
700
701			idx++;
702			be_id++;
703
704			ret = set_hda_codec_link(dev, &links[idx], be_id,
705						 SOF_HDA_DIGITAL);
706			if (ret) {
707				dev_err(dev, "fail to set hda digital link, ret %d\n",
708					ret);
709				return ret;
710			}
711
712			idx++;
713			break;
714		case SOF_LINK_NONE:
715			/* caught here if it's not used as terminator in macro */
716			fallthrough;
717		default:
718			dev_err(dev, "invalid link type %ld\n", link);
719			return -EINVAL;
720		}
721	}
722
723	if (idx != num_links) {
724		dev_err(dev, "link number mismatch, idx %d, num_links %d\n", idx,
725			num_links);
726		return -EINVAL;
727	}
728
729	card->dai_link = links;
730	card->num_links = num_links;
731
732	return 0;
733}
734EXPORT_SYMBOL_NS(sof_intel_board_set_dai_link, "SND_SOC_INTEL_SOF_BOARD_HELPERS");
735
736struct sof_card_private *
737sof_intel_board_get_ctx(struct device *dev, unsigned long board_quirk)
738{
739	struct sof_card_private *ctx;
740
741	dev_dbg(dev, "create ctx, board_quirk 0x%lx\n", board_quirk);
742
743	ctx = devm_kzalloc(dev, sizeof(struct sof_card_private), GFP_KERNEL);
744	if (!ctx)
745		return NULL;
746
747	ctx->codec_type = snd_soc_acpi_intel_detect_codec_type(dev);
748	ctx->amp_type = snd_soc_acpi_intel_detect_amp_type(dev);
749
750	ctx->dmic_be_num = 2;
751	ctx->hdmi_num = (board_quirk & SOF_NUM_IDISP_HDMI_MASK) >>
752			SOF_NUM_IDISP_HDMI_SHIFT;
753	/* default number of HDMI DAI's */
754	if (!ctx->hdmi_num)
755		ctx->hdmi_num = 3;
756
757	/* port number/mask of peripherals attached to ssp interface */
758	if (ctx->codec_type != CODEC_NONE)
759		ctx->ssp_codec = (board_quirk & SOF_SSP_PORT_CODEC_MASK) >>
760				SOF_SSP_PORT_CODEC_SHIFT;
761
762	if (ctx->amp_type != CODEC_NONE)
763		ctx->ssp_amp = (board_quirk & SOF_SSP_PORT_AMP_MASK) >>
764				SOF_SSP_PORT_AMP_SHIFT;
765
766	if (board_quirk & SOF_BT_OFFLOAD_PRESENT) {
767		ctx->bt_offload_present = true;
768		ctx->ssp_bt = (board_quirk & SOF_SSP_PORT_BT_OFFLOAD_MASK) >>
769				SOF_SSP_PORT_BT_OFFLOAD_SHIFT;
770	}
771
772	ctx->ssp_mask_hdmi_in = (board_quirk & SOF_SSP_MASK_HDMI_CAPTURE_MASK) >>
773				SOF_SSP_MASK_HDMI_CAPTURE_SHIFT;
774
775	return ctx;
776}
777EXPORT_SYMBOL_NS(sof_intel_board_get_ctx, "SND_SOC_INTEL_SOF_BOARD_HELPERS");
778
779MODULE_DESCRIPTION("ASoC Intel SOF Machine Driver Board Helpers");
780MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>");
781MODULE_LICENSE("GPL");
782MODULE_IMPORT_NS("SND_SOC_INTEL_HDA_DSP_COMMON");
783MODULE_IMPORT_NS("SND_SOC_ACPI_INTEL_MATCH");