1 // SPDX-License-Identifier: GPL-2.0-only
2 //
3 // Copyright(c) 2021-2022 Intel Corporation
4 //
5 // Authors: Cezary Rojewski <cezary.rojewski@intel.com>
6 // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
7 //
8
9 #include <linux/acpi.h>
10 #include <linux/module.h>
11 #include <linux/dmi.h>
12 #include <linux/pci.h>
13 #include <acpi/nhlt.h>
14 #include <linux/platform_device.h>
15 #include <sound/hda_codec.h>
16 #include <sound/hda_register.h>
17 #include <sound/soc-acpi.h>
18 #include <sound/soc-component.h>
19 #include "avs.h"
20 #include "debug.h"
21 #include "pcm.h"
22 #include "utils.h"
23
24 static char *i2s_test;
25 module_param(i2s_test, charp, 0444);
26 MODULE_PARM_DESC(i2s_test, "Use I2S test-board instead of ACPI, i2s_test=ssp0tdm,ssp1tdm,... 0 to ignore port");
27
28 bool obsolete_card_names = IS_ENABLED(CONFIG_SND_SOC_INTEL_AVS_CARDNAME_OBSOLETE);
29 module_param_named(obsolete_card_names, obsolete_card_names, bool, 0444);
30 MODULE_PARM_DESC(obsolete_card_names, "Use obsolete card names 0=no, 1=yes");
31
32 static const struct dmi_system_id kbl_dmi_table[] = {
33 {
34 .matches = {
35 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
36 DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
37 },
38 },
39 {
40 .matches = {
41 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
42 DMI_MATCH(DMI_BOARD_NAME, "AmberLake Y"),
43 },
44 },
45 {}
46 };
47
48 static const struct dmi_system_id kblr_dmi_table[] = {
49 {
50 .matches = {
51 DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
52 DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
53 },
54 },
55 {}
56 };
57
dmi_match_quirk(void * arg)58 static struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)
59 {
60 struct snd_soc_acpi_mach *mach = arg;
61 struct dmi_system_id *dmi_table;
62
63 dmi_table = (struct dmi_system_id *)mach->quirk_data;
64
65 if (!dmi_table || dmi_first_match(dmi_table))
66 return mach;
67 return NULL;
68 }
69
70 #define AVS_SSP(x) (BIT(x))
71 #define AVS_SSP_RANGE(a, b) (GENMASK(b, a))
72
73 /* supported I2S board codec configurations */
74 static struct snd_soc_acpi_mach avs_skl_i2s_machines[] = {
75 {
76 .id = "INT343A",
77 .drv_name = "avs_rt286",
78 .mach_params = {
79 .i2s_link_mask = AVS_SSP(0),
80 },
81 .tplg_filename = "rt286-tplg.bin",
82 },
83 {
84 .id = "10508825",
85 .drv_name = "avs_nau8825",
86 .mach_params = {
87 .i2s_link_mask = AVS_SSP(1),
88 },
89 .tplg_filename = "nau8825-tplg.bin",
90 },
91 {
92 .id = "INT343B",
93 .drv_name = "avs_ssm4567",
94 .mach_params = {
95 .i2s_link_mask = AVS_SSP(0),
96 },
97 .tplg_filename = "ssm4567-tplg.bin",
98 },
99 {
100 .id = "MX98357A",
101 .drv_name = "avs_max98357a",
102 .mach_params = {
103 .i2s_link_mask = AVS_SSP(0),
104 },
105 .tplg_filename = "max98357a-tplg.bin",
106 },
107 {},
108 };
109
110 static struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
111 {
112 .id = "INT343A",
113 .drv_name = "avs_rt286",
114 .mach_params = {
115 .i2s_link_mask = AVS_SSP(0),
116 },
117 .quirk_data = &kbl_dmi_table,
118 .machine_quirk = dmi_match_quirk,
119 .tplg_filename = "rt286-tplg.bin",
120 },
121 {
122 .id = "INT343A",
123 .drv_name = "avs_rt298",
124 .mach_params = {
125 .i2s_link_mask = AVS_SSP(0),
126 },
127 .quirk_data = &kblr_dmi_table,
128 .machine_quirk = dmi_match_quirk,
129 .tplg_filename = "rt298-tplg.bin",
130 },
131 {
132 .id = "MX98927",
133 .drv_name = "avs_max98927",
134 .mach_params = {
135 .i2s_link_mask = AVS_SSP(0),
136 },
137 .tplg_filename = "max98927-tplg.bin",
138 },
139 {
140 .id = "10EC5514",
141 .drv_name = "avs_rt5514",
142 .mach_params = {
143 .i2s_link_mask = AVS_SSP(0),
144 },
145 .pdata = (struct avs_mach_pdata[]){ { .tdms = (unsigned long[]){ 0x2 } } },
146 .tplg_filename = "rt5514-tplg.bin",
147 },
148 {
149 .id = "10EC5663",
150 .drv_name = "avs_rt5663",
151 .mach_params = {
152 .i2s_link_mask = AVS_SSP(1),
153 },
154 .tplg_filename = "rt5663-tplg.bin",
155 },
156 {
157 .id = "MX98373",
158 .drv_name = "avs_max98373",
159 .mach_params = {
160 .i2s_link_mask = AVS_SSP(0),
161 },
162 .tplg_filename = "max98373-tplg.bin",
163 },
164 {
165 .id = "MX98357A",
166 .drv_name = "avs_max98357a",
167 .mach_params = {
168 .i2s_link_mask = AVS_SSP(0),
169 },
170 .tplg_filename = "max98357a-tplg.bin",
171 },
172 {
173 .id = "DLGS7219",
174 .drv_name = "avs_da7219",
175 .mach_params = {
176 .i2s_link_mask = AVS_SSP(1),
177 },
178 .tplg_filename = "da7219-tplg.bin",
179 },
180 {
181 .id = "ESSX8336",
182 .drv_name = "avs_es8336",
183 .mach_params = {
184 .i2s_link_mask = AVS_SSP(0),
185 },
186 .tplg_filename = "es8336-tplg.bin",
187 },
188 {},
189 };
190
191 static struct snd_soc_acpi_mach avs_apl_i2s_machines[] = {
192 {
193 .id = "INT343A",
194 .drv_name = "avs_rt298",
195 .mach_params = {
196 .i2s_link_mask = AVS_SSP(5),
197 },
198 .tplg_filename = "rt298-tplg.bin",
199 },
200 {
201 .id = "INT34C3",
202 .drv_name = "avs_tdf8532",
203 .mach_params = {
204 .i2s_link_mask = AVS_SSP_RANGE(0, 5),
205 },
206 .pdata = (struct avs_mach_pdata[]){ {
207 .tdms = (unsigned long[]){ 0x1, 0x1, 0x14, 0x1, 0x1, 0x1 }
208 } },
209 .tplg_filename = "tdf8532-tplg.bin",
210 },
211 {
212 .id = "MX98357A",
213 .drv_name = "avs_max98357a",
214 .mach_params = {
215 .i2s_link_mask = AVS_SSP(5),
216 },
217 .tplg_filename = "max98357a-tplg.bin",
218 },
219 {
220 .id = "DLGS7219",
221 .drv_name = "avs_da7219",
222 .mach_params = {
223 .i2s_link_mask = AVS_SSP(1),
224 },
225 .tplg_filename = "da7219-tplg.bin",
226 },
227 {},
228 };
229
230 static struct snd_soc_acpi_mach avs_gml_i2s_machines[] = {
231 {
232 .id = "INT343A",
233 .drv_name = "avs_rt298",
234 .mach_params = {
235 .i2s_link_mask = AVS_SSP(2),
236 },
237 .tplg_filename = "rt298-tplg.bin",
238 },
239 {},
240 };
241
242 static struct snd_soc_acpi_mach avs_cnl_i2s_machines[] = {
243 {
244 .id = "INT34C2",
245 .drv_name = "avs_rt274",
246 .mach_params = {
247 .i2s_link_mask = AVS_SSP(0),
248 },
249 .tplg_filename = "rt274-tplg.bin",
250 },
251 {
252 .id = "10EC5682",
253 .drv_name = "avs_rt5682",
254 .mach_params = {
255 .i2s_link_mask = AVS_SSP(1),
256 },
257 .tplg_filename = "rt5682-tplg.bin",
258 },
259 {},
260 };
261
262 static struct snd_soc_acpi_mach avs_icl_i2s_machines[] = {
263 {
264 .id = "INT343A",
265 .drv_name = "avs_rt298",
266 .mach_params = {
267 .i2s_link_mask = AVS_SSP(0),
268 },
269 .tplg_filename = "rt298-tplg.bin",
270 },
271 {
272 .id = "INT34C2",
273 .drv_name = "avs_rt274",
274 .mach_params = {
275 .i2s_link_mask = AVS_SSP(0),
276 },
277 .tplg_filename = "rt274-tplg.bin",
278 },
279 {},
280 };
281
282 static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = {
283 {
284 .id = "INT34C2",
285 .drv_name = "avs_rt274",
286 .mach_params = {
287 .i2s_link_mask = AVS_SSP(0),
288 },
289 .tplg_filename = "rt274-tplg.bin",
290 },
291 {
292 .id = "10EC0298",
293 .drv_name = "avs_rt298",
294 .mach_params = {
295 .i2s_link_mask = AVS_SSP(0),
296 },
297 .tplg_filename = "rt298-tplg.bin",
298 },
299 {
300 .id = "10EC1308",
301 .drv_name = "avs_rt1308",
302 .mach_params = {
303 .i2s_link_mask = AVS_SSP(1),
304 },
305 .tplg_filename = "rt1308-tplg.bin",
306 },
307 {
308 .id = "10EC5640",
309 .uid = "1",
310 .drv_name = "avs_rt5640",
311 .mach_params = {
312 .i2s_link_mask = AVS_SSP(0),
313 },
314 .tplg_filename = "rt5640-tplg.bin",
315 },
316 {
317 .id = "10EC5640",
318 .uid = "3",
319 .drv_name = "avs_rt5640",
320 .mach_params = {
321 .i2s_link_mask = AVS_SSP(1),
322 },
323 .tplg_filename = "rt5640-tplg.bin",
324 },
325 {
326 .id = "10EC5640",
327 .uid = "2",
328 .drv_name = "avs_rt5640",
329 .mach_params = {
330 .i2s_link_mask = AVS_SSP(2),
331 },
332 .tplg_filename = "rt5640-tplg.bin",
333 },
334 {
335 .id = "ESSX8336",
336 .drv_name = "avs_es8336",
337 .mach_params = {
338 .i2s_link_mask = AVS_SSP(0),
339 },
340 .tplg_filename = "es8336-tplg.bin",
341 },
342 {},
343 };
344
345 static struct snd_soc_acpi_mach avs_mbl_i2s_machines[] = {
346 {
347 .id = "PCM3168A",
348 .drv_name = "avs_pcm3168a",
349 .mach_params = {
350 .i2s_link_mask = AVS_SSP(0) | AVS_SSP(2),
351 },
352 .tplg_filename = "pcm3168a-tplg.bin",
353 },
354 {}
355 };
356
357 struct avs_acpi_boards {
358 int id;
359 struct snd_soc_acpi_mach *machs;
360 };
361
362 #define AVS_MACH_ENTRY(_id, _mach) \
363 { .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), }
364
365 /* supported I2S boards per platform */
366 static const struct avs_acpi_boards i2s_boards[] = {
367 AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines),
368 AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines),
369 AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines),
370 AVS_MACH_ENTRY(HDA_GLK, avs_gml_i2s_machines),
371 AVS_MACH_ENTRY(HDA_CNL_LP, avs_cnl_i2s_machines),
372 AVS_MACH_ENTRY(HDA_CNL_H, avs_cnl_i2s_machines),
373 AVS_MACH_ENTRY(HDA_CML_LP, avs_cnl_i2s_machines),
374 AVS_MACH_ENTRY(HDA_ICL_LP, avs_icl_i2s_machines),
375 AVS_MACH_ENTRY(HDA_TGL_LP, avs_tgl_i2s_machines),
376 AVS_MACH_ENTRY(HDA_EHL_0, avs_tgl_i2s_machines),
377 AVS_MACH_ENTRY(HDA_ADL_N, avs_mbl_i2s_machines),
378 AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines),
379 AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines),
380 AVS_MACH_ENTRY(HDA_RPL_M, avs_mbl_i2s_machines),
381 AVS_MACH_ENTRY(HDA_FCL, avs_tgl_i2s_machines),
382 { },
383 };
384
avs_get_i2s_machines(struct avs_dev * adev)385 static struct snd_soc_acpi_mach *avs_get_i2s_machines(struct avs_dev *adev)
386 {
387 int id, i;
388
389 id = adev->base.pci->device;
390 for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)
391 if (i2s_boards[i].id == id)
392 return i2s_boards[i].machs;
393 return NULL;
394 }
395
396 /* Platform devices spawned by AVS driver are removed with this hook. */
avs_unregister_board(void * pdev)397 static void avs_unregister_board(void *pdev)
398 {
399 platform_device_unregister(pdev);
400 }
401
avs_register_board(struct avs_dev * adev,const char * name,const void * data,size_t size)402 static struct platform_device *avs_register_board(struct avs_dev *adev, const char *name,
403 const void *data, size_t size)
404 {
405 struct platform_device *pdev;
406 int ret;
407
408 pdev = platform_device_register_data(NULL, name, PLATFORM_DEVID_AUTO, data, size);
409 if (IS_ERR(pdev))
410 return pdev;
411
412 ret = devm_add_action_or_reset(adev->dev, avs_unregister_board, pdev);
413 if (ret)
414 return ERR_PTR(ret);
415
416 return pdev;
417 }
418
avs_register_board_pdata(struct avs_dev * adev,const char * name,struct snd_soc_acpi_mach * mach,struct hda_codec * codec,unsigned long * tdms,char * codec_name)419 static struct platform_device *avs_register_board_pdata(struct avs_dev *adev, const char *name,
420 struct snd_soc_acpi_mach *mach,
421 struct hda_codec *codec,
422 unsigned long *tdms, char *codec_name)
423 {
424 struct avs_mach_pdata *pdata;
425
426 pdata = devm_kzalloc(adev->dev, sizeof(*pdata), GFP_KERNEL);
427 if (!pdata)
428 return ERR_PTR(-ENOMEM);
429
430 pdata->codec = codec;
431 pdata->tdms = tdms;
432 pdata->codec_name = codec_name;
433 pdata->obsolete_card_names = obsolete_card_names;
434 mach->pdata = pdata;
435
436 return avs_register_board(adev, name, mach, sizeof(*mach));
437 }
438
avs_register_probe_board(struct avs_dev * adev)439 static int __maybe_unused avs_register_probe_board(struct avs_dev *adev)
440 {
441 struct platform_device *pdev;
442
443 pdev = avs_register_board(adev, "avs_probe_mb", NULL, 0);
444 if (IS_ERR(pdev))
445 return PTR_ERR(pdev);
446
447 return avs_register_probe_component(adev, dev_name(&pdev->dev));
448 }
449
avs_register_dmic_board(struct avs_dev * adev)450 static int avs_register_dmic_board(struct avs_dev *adev)
451 {
452 static struct snd_soc_acpi_mach mach = {
453 .tplg_filename = "dmic-tplg.bin",
454 };
455 struct platform_device *pdev;
456 char *codec_name;
457
458 if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) {
459 dev_dbg(adev->dev, "no DMIC endpoints present\n");
460 return 0;
461 }
462
463 /* DMIC present in Intel PCH is enumerated statically. */
464 pdev = avs_register_board(adev, "dmic-codec", NULL, 0);
465 if (IS_ERR(pdev))
466 return PTR_ERR(pdev);
467
468 codec_name = devm_kstrdup(adev->dev, dev_name(&pdev->dev), GFP_KERNEL);
469 if (!codec_name)
470 return -ENOMEM;
471
472 pdev = avs_register_board_pdata(adev, "avs_dmic", &mach, NULL, NULL, codec_name);
473 if (IS_ERR(pdev))
474 return PTR_ERR(pdev);
475
476 return avs_register_dmic_component(adev, dev_name(&pdev->dev));
477 }
478
avs_register_i2s_test_board(struct avs_dev * adev,int ssp_port,int tdm_slot)479 static int avs_register_i2s_test_board(struct avs_dev *adev, int ssp_port, int tdm_slot)
480 {
481 struct snd_soc_acpi_mach mach = {{0}};
482 struct platform_device *pdev;
483 unsigned long *tdms;
484
485 tdms = devm_kcalloc(adev->dev, ssp_port + 1, sizeof(*tdms), GFP_KERNEL);
486 mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL,
487 AVS_STRING_FMT("i2s", "-test-tplg.bin",
488 ssp_port, tdm_slot));
489 if (!tdms || !mach.tplg_filename)
490 return -ENOMEM;
491
492 tdms[ssp_port] = BIT(tdm_slot);
493 mach.drv_name = "avs_i2s_test";
494 mach.mach_params.i2s_link_mask = AVS_SSP(ssp_port);
495
496 pdev = avs_register_board_pdata(adev, mach.drv_name, &mach, NULL, tdms, NULL);
497 if (IS_ERR(pdev))
498 return PTR_ERR(pdev);
499
500 return avs_register_i2s_component(adev, dev_name(&pdev->dev), AVS_SSP(ssp_port), tdms);
501 }
502
avs_register_i2s_test_boards(struct avs_dev * adev)503 static int avs_register_i2s_test_boards(struct avs_dev *adev)
504 {
505 int max_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
506 int ssp_port, tdm_slot, ret;
507 unsigned long tdm_slots;
508 u32 *array, num_elems;
509
510 if (!i2s_test)
511 return 0;
512
513 ret = parse_int_array(i2s_test, strlen(i2s_test), (int **)&array);
514 if (ret) {
515 dev_err(adev->dev, "failed to parse i2s_test parameter\n");
516 return ret;
517 }
518
519 num_elems = *array;
520 if (num_elems > max_ssps) {
521 dev_err(adev->dev, "board supports only %d SSP, %d specified\n",
522 max_ssps, num_elems);
523 ret = -EINVAL;
524 goto exit;
525 }
526
527 for (ssp_port = 0; ssp_port < num_elems; ssp_port++) {
528 tdm_slots = array[1 + ssp_port];
529 for_each_set_bit(tdm_slot, &tdm_slots, 16) {
530 ret = avs_register_i2s_test_board(adev, ssp_port, tdm_slot);
531 if (ret)
532 goto exit;
533 }
534 }
535
536 exit:
537 kfree(array);
538 return ret;
539 }
540
avs_register_i2s_board(struct avs_dev * adev,struct snd_soc_acpi_mach * mach)541 static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
542 {
543 u32 i2s_mask = mach->mach_params.i2s_link_mask;
544 struct platform_device *pdev;
545 unsigned long *tdms = NULL;
546
547 if (mach->pdata)
548 tdms = ((struct avs_mach_pdata *)mach->pdata)->tdms;
549
550 pdev = avs_register_board_pdata(adev, mach->drv_name, mach, NULL, tdms, NULL);
551 if (IS_ERR(pdev))
552 return PTR_ERR(pdev);
553
554 return avs_register_i2s_component(adev, dev_name(&pdev->dev), i2s_mask, tdms);
555 }
556
avs_register_i2s_boards(struct avs_dev * adev)557 static int avs_register_i2s_boards(struct avs_dev *adev)
558 {
559 int num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
560 struct snd_soc_acpi_mach *machs;
561 struct snd_soc_acpi_mach *mach;
562 int ret;
563
564 if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, -1, -1, -1)) {
565 dev_dbg(adev->dev, "no I2S endpoints present\n");
566 return 0;
567 }
568
569 machs = avs_get_i2s_machines(adev);
570 if (!machs) {
571 dev_dbg(adev->dev, "no I2S endpoints supported\n");
572 return 0;
573 }
574
575 for (mach = machs; mach->id[0]; mach++) {
576 if (!acpi_dev_present(mach->id, mach->uid, -1))
577 continue;
578
579 if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
580 dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
581 num_ssps, mach->drv_name,
582 (unsigned long)__fls(mach->mach_params.i2s_link_mask));
583 continue;
584 }
585 if (mach->machine_quirk)
586 if (!mach->machine_quirk(mach))
587 continue;
588
589 ret = avs_register_i2s_board(adev, mach);
590 if (ret < 0)
591 dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);
592 }
593
594 return 0;
595 }
596
avs_register_hda_board(struct avs_dev * adev,struct hda_codec * codec)597 static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
598 {
599 struct hdac_device *hdev = &codec->core;
600 struct snd_soc_acpi_mach mach = {{0}};
601 struct platform_device *pdev;
602
603 mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
604 hdev->vendor_id);
605 if (!mach.tplg_filename)
606 return -ENOMEM;
607
608 pdev = avs_register_board_pdata(adev, "avs_hdaudio", &mach, codec, NULL, NULL);
609 if (IS_ERR(pdev))
610 return PTR_ERR(pdev);
611
612 return avs_register_hda_component(adev, dev_name(&pdev->dev));
613 }
614
avs_register_hda_boards(struct avs_dev * adev)615 static int avs_register_hda_boards(struct avs_dev *adev)
616 {
617 struct hdac_bus *bus = &adev->base.core;
618 struct hdac_device *hdev;
619 int ret;
620
621 if (!bus->num_codecs) {
622 dev_dbg(adev->dev, "no HDA endpoints present\n");
623 return 0;
624 }
625
626 list_for_each_entry(hdev, &bus->codec_list, list) {
627 struct hda_codec *codec;
628
629 codec = dev_to_hda_codec(&hdev->dev);
630
631 ret = avs_register_hda_board(adev, codec);
632 if (ret < 0)
633 dev_warn(adev->dev, "register hda-%08x failed: %d\n",
634 codec->core.vendor_id, ret);
635 }
636
637 return 0;
638 }
639
avs_register_all_boards(struct avs_dev * adev)640 int avs_register_all_boards(struct avs_dev *adev)
641 {
642 int ret;
643
644 #ifdef CONFIG_DEBUG_FS
645 ret = avs_register_probe_board(adev);
646 if (ret < 0)
647 dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret);
648 #endif
649
650 ret = avs_register_dmic_board(adev);
651 if (ret < 0)
652 dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
653 ret);
654
655 ret = avs_register_i2s_test_boards(adev);
656 if (ret)
657 dev_dbg(adev->dev, "enumerate I2S TEST endpoints failed: %d\n", ret);
658
659 ret = avs_register_i2s_boards(adev);
660 if (ret < 0)
661 dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
662 ret);
663
664 ret = avs_register_hda_boards(adev);
665 if (ret < 0)
666 dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",
667 ret);
668
669 return 0;
670 }
671
avs_unregister_all_boards(struct avs_dev * adev)672 void avs_unregister_all_boards(struct avs_dev *adev)
673 {
674 snd_soc_unregister_component(adev->dev);
675 }
676