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