xref: /linux/sound/soc/intel/avs/board_selection.c (revision 177bf8620cf4ed290ee170a6c5966adc0924b336)
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