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