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
21static bool i2s_test;
22module_param(i2s_test, bool, 0444);
23MODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards");
24
25static 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
41static 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
51static 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(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 */
73static 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
109static 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
190static 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
227static 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
239static 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
259static 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
279static 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
315static 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
361struct 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 */
370static 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
387static 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 */
399static void board_pdev_unregister(void *data)
400{
401	platform_device_unregister(data);
402}
403
404static 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, "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, "avs_probe_mb", PLATFORM_DEVID_NONE,
417					      (const void *)&mach, sizeof(mach));
418	if (IS_ERR(board)) {
419		dev_err(adev->dev, "probe board register failed\n");
420		return PTR_ERR(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
431static 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 (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, -1, -1)) {
438		dev_dbg(adev->dev, "no DMIC endpoints present\n");
439		return 0;
440	}
441
442	codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
443	if (IS_ERR(codec)) {
444		dev_err(adev->dev, "dmic codec register failed\n");
445		return PTR_ERR(codec);
446	}
447
448	ret = devm_add_action(adev->dev, board_pdev_unregister, codec);
449	if (ret < 0) {
450		platform_device_unregister(codec);
451		return ret;
452	}
453
454	ret = avs_dmic_platform_register(adev, "dmic-platform");
455	if (ret < 0)
456		return ret;
457
458	mach.tplg_filename = "dmic-tplg.bin";
459	mach.mach_params.platform = "dmic-platform";
460
461	board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE,
462					(const void *)&mach, sizeof(mach));
463	if (IS_ERR(board)) {
464		dev_err(adev->dev, "dmic board register failed\n");
465		return PTR_ERR(board);
466	}
467
468	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
469	if (ret < 0) {
470		platform_device_unregister(board);
471		return ret;
472	}
473
474	return 0;
475}
476
477static int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
478{
479	struct platform_device *board;
480	int num_ssps;
481	char *name;
482	int ret;
483
484	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
485	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
486		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
487			num_ssps, mach->drv_name,
488			(unsigned long)__fls(mach->mach_params.i2s_link_mask));
489		return -ENODEV;
490	}
491
492	name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name,
493			      mach->mach_params.i2s_link_mask);
494	if (!name)
495		return -ENOMEM;
496
497	ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata);
498	if (ret < 0)
499		return ret;
500
501	mach->mach_params.platform = name;
502
503	board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask,
504					      (const void *)mach, sizeof(*mach));
505	if (IS_ERR(board)) {
506		dev_err(adev->dev, "ssp board register failed\n");
507		return PTR_ERR(board);
508	}
509
510	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
511	if (ret < 0) {
512		platform_device_unregister(board);
513		return ret;
514	}
515
516	return 0;
517}
518
519static int avs_register_i2s_boards(struct avs_dev *adev)
520{
521	const struct avs_acpi_boards *boards;
522	struct snd_soc_acpi_mach *mach;
523	int ret;
524
525	if (!acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, -1, -1, -1)) {
526		dev_dbg(adev->dev, "no I2S endpoints present\n");
527		return 0;
528	}
529
530	if (i2s_test) {
531		int i, num_ssps;
532
533		num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
534		/* constrain just in case FW says there can be more SSPs than possible */
535		num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps);
536
537		mach = avs_test_i2s_machines;
538
539		for (i = 0; i < num_ssps; i++) {
540			ret = avs_register_i2s_board(adev, &mach[i]);
541			if (ret < 0)
542				dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name,
543					 ret);
544		}
545		return 0;
546	}
547
548	boards = avs_get_i2s_boards(adev);
549	if (!boards) {
550		dev_dbg(adev->dev, "no I2S endpoints supported\n");
551		return 0;
552	}
553
554	for (mach = boards->machs; mach->id[0]; mach++) {
555		if (!acpi_dev_present(mach->id, mach->uid, -1))
556			continue;
557
558		if (mach->machine_quirk)
559			if (!mach->machine_quirk(mach))
560				continue;
561
562		ret = avs_register_i2s_board(adev, mach);
563		if (ret < 0)
564			dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);
565	}
566
567	return 0;
568}
569
570static int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
571{
572	struct snd_soc_acpi_mach mach = {{0}};
573	struct platform_device *board;
574	struct hdac_device *hdev = &codec->core;
575	char *pname;
576	int ret, id;
577
578	pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));
579	if (!pname)
580		return -ENOMEM;
581
582	ret = avs_hda_platform_register(adev, pname);
583	if (ret < 0)
584		return ret;
585
586	mach.pdata = codec;
587	mach.mach_params.platform = pname;
588	mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
589					    hdev->vendor_id);
590	if (!mach.tplg_filename)
591		return -ENOMEM;
592
593	id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;
594	board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,
595					      sizeof(mach));
596	if (IS_ERR(board)) {
597		dev_err(adev->dev, "hda board register failed\n");
598		return PTR_ERR(board);
599	}
600
601	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
602	if (ret < 0) {
603		platform_device_unregister(board);
604		return ret;
605	}
606
607	return 0;
608}
609
610static int avs_register_hda_boards(struct avs_dev *adev)
611{
612	struct hdac_bus *bus = &adev->base.core;
613	struct hdac_device *hdev;
614	int ret;
615
616	if (!bus->num_codecs) {
617		dev_dbg(adev->dev, "no HDA endpoints present\n");
618		return 0;
619	}
620
621	list_for_each_entry(hdev, &bus->codec_list, list) {
622		struct hda_codec *codec;
623
624		codec = dev_to_hda_codec(&hdev->dev);
625
626		ret = avs_register_hda_board(adev, codec);
627		if (ret < 0)
628			dev_warn(adev->dev, "register hda-%08x failed: %d\n",
629				 codec->core.vendor_id, ret);
630	}
631
632	return 0;
633}
634
635int avs_register_all_boards(struct avs_dev *adev)
636{
637	int ret;
638
639#ifdef CONFIG_DEBUG_FS
640	ret = avs_register_probe_board(adev);
641	if (ret < 0)
642		dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret);
643#endif
644
645	ret = avs_register_dmic_board(adev);
646	if (ret < 0)
647		dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
648			 ret);
649
650	ret = avs_register_i2s_boards(adev);
651	if (ret < 0)
652		dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
653			 ret);
654
655	ret = avs_register_hda_boards(adev);
656	if (ret < 0)
657		dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",
658			 ret);
659
660	return 0;
661}
662
663void avs_unregister_all_boards(struct avs_dev *adev)
664{
665	snd_soc_unregister_component(adev->dev);
666}
667