162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci//
362306a36Sopenharmony_ci// Copyright(c) 2021-2022 Intel Corporation. All rights reserved.
462306a36Sopenharmony_ci//
562306a36Sopenharmony_ci// Authors: Cezary Rojewski <cezary.rojewski@intel.com>
662306a36Sopenharmony_ci//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>
762306a36Sopenharmony_ci//
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/acpi.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/dmi.h>
1262306a36Sopenharmony_ci#include <linux/pci.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <sound/hda_codec.h>
1562306a36Sopenharmony_ci#include <sound/hda_register.h>
1662306a36Sopenharmony_ci#include <sound/intel-nhlt.h>
1762306a36Sopenharmony_ci#include <sound/soc-acpi.h>
1862306a36Sopenharmony_ci#include <sound/soc-component.h>
1962306a36Sopenharmony_ci#include "avs.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic bool i2s_test;
2262306a36Sopenharmony_cimodule_param(i2s_test, bool, 0444);
2362306a36Sopenharmony_ciMODULE_PARM_DESC(i2s_test, "Probe I2S test-board and skip all other I2S boards");
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic const struct dmi_system_id kbl_dmi_table[] = {
2662306a36Sopenharmony_ci	{
2762306a36Sopenharmony_ci		.matches = {
2862306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
2962306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "Skylake Y LPDDR3 RVP3"),
3062306a36Sopenharmony_ci		},
3162306a36Sopenharmony_ci	},
3262306a36Sopenharmony_ci	{
3362306a36Sopenharmony_ci		.matches = {
3462306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
3562306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "AmberLake Y"),
3662306a36Sopenharmony_ci		},
3762306a36Sopenharmony_ci	},
3862306a36Sopenharmony_ci	{}
3962306a36Sopenharmony_ci};
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic const struct dmi_system_id kblr_dmi_table[] = {
4262306a36Sopenharmony_ci	{
4362306a36Sopenharmony_ci		.matches = {
4462306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
4562306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "Kabylake R DDR4 RVP"),
4662306a36Sopenharmony_ci		},
4762306a36Sopenharmony_ci	},
4862306a36Sopenharmony_ci	{}
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic struct snd_soc_acpi_mach *dmi_match_quirk(void *arg)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	struct snd_soc_acpi_mach *mach = arg;
5462306a36Sopenharmony_ci	const struct dmi_system_id *dmi_id;
5562306a36Sopenharmony_ci	struct dmi_system_id *dmi_table;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (mach->quirk_data == NULL)
5862306a36Sopenharmony_ci		return mach;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	dmi_table = (struct dmi_system_id *)mach->quirk_data;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	dmi_id = dmi_first_match(dmi_table);
6362306a36Sopenharmony_ci	if (!dmi_id)
6462306a36Sopenharmony_ci		return NULL;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return mach;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define AVS_SSP(x)		(BIT(x))
7062306a36Sopenharmony_ci#define AVS_SSP_RANGE(a, b)	(GENMASK(b, a))
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci/* supported I2S board codec configurations */
7362306a36Sopenharmony_cistatic struct snd_soc_acpi_mach avs_skl_i2s_machines[] = {
7462306a36Sopenharmony_ci	{
7562306a36Sopenharmony_ci		.id = "INT343A",
7662306a36Sopenharmony_ci		.drv_name = "avs_rt286",
7762306a36Sopenharmony_ci		.mach_params = {
7862306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
7962306a36Sopenharmony_ci		},
8062306a36Sopenharmony_ci		.tplg_filename = "rt286-tplg.bin",
8162306a36Sopenharmony_ci	},
8262306a36Sopenharmony_ci	{
8362306a36Sopenharmony_ci		.id = "10508825",
8462306a36Sopenharmony_ci		.drv_name = "avs_nau8825",
8562306a36Sopenharmony_ci		.mach_params = {
8662306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(1),
8762306a36Sopenharmony_ci		},
8862306a36Sopenharmony_ci		.tplg_filename = "nau8825-tplg.bin",
8962306a36Sopenharmony_ci	},
9062306a36Sopenharmony_ci	{
9162306a36Sopenharmony_ci		.id = "INT343B",
9262306a36Sopenharmony_ci		.drv_name = "avs_ssm4567",
9362306a36Sopenharmony_ci		.mach_params = {
9462306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
9562306a36Sopenharmony_ci		},
9662306a36Sopenharmony_ci		.tplg_filename = "ssm4567-tplg.bin",
9762306a36Sopenharmony_ci	},
9862306a36Sopenharmony_ci	{
9962306a36Sopenharmony_ci		.id = "MX98357A",
10062306a36Sopenharmony_ci		.drv_name = "avs_max98357a",
10162306a36Sopenharmony_ci		.mach_params = {
10262306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
10362306a36Sopenharmony_ci		},
10462306a36Sopenharmony_ci		.tplg_filename = "max98357a-tplg.bin",
10562306a36Sopenharmony_ci	},
10662306a36Sopenharmony_ci	{},
10762306a36Sopenharmony_ci};
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic struct snd_soc_acpi_mach avs_kbl_i2s_machines[] = {
11062306a36Sopenharmony_ci	{
11162306a36Sopenharmony_ci		.id = "INT343A",
11262306a36Sopenharmony_ci		.drv_name = "avs_rt286",
11362306a36Sopenharmony_ci		.mach_params = {
11462306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
11562306a36Sopenharmony_ci		},
11662306a36Sopenharmony_ci		.quirk_data = &kbl_dmi_table,
11762306a36Sopenharmony_ci		.machine_quirk = dmi_match_quirk,
11862306a36Sopenharmony_ci		.tplg_filename = "rt286-tplg.bin",
11962306a36Sopenharmony_ci	},
12062306a36Sopenharmony_ci	{
12162306a36Sopenharmony_ci		.id = "INT343A",
12262306a36Sopenharmony_ci		.drv_name = "avs_rt298",
12362306a36Sopenharmony_ci		.mach_params = {
12462306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
12562306a36Sopenharmony_ci		},
12662306a36Sopenharmony_ci		.quirk_data = &kblr_dmi_table,
12762306a36Sopenharmony_ci		.machine_quirk = dmi_match_quirk,
12862306a36Sopenharmony_ci		.tplg_filename = "rt298-tplg.bin",
12962306a36Sopenharmony_ci	},
13062306a36Sopenharmony_ci	{
13162306a36Sopenharmony_ci		.id = "MX98927",
13262306a36Sopenharmony_ci		.drv_name = "avs_max98927",
13362306a36Sopenharmony_ci		.mach_params = {
13462306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
13562306a36Sopenharmony_ci		},
13662306a36Sopenharmony_ci		.tplg_filename = "max98927-tplg.bin",
13762306a36Sopenharmony_ci	},
13862306a36Sopenharmony_ci	{
13962306a36Sopenharmony_ci		.id = "10EC5663",
14062306a36Sopenharmony_ci		.drv_name = "avs_rt5663",
14162306a36Sopenharmony_ci		.mach_params = {
14262306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(1),
14362306a36Sopenharmony_ci		},
14462306a36Sopenharmony_ci		.tplg_filename = "rt5663-tplg.bin",
14562306a36Sopenharmony_ci	},
14662306a36Sopenharmony_ci	{
14762306a36Sopenharmony_ci		.id = "MX98373",
14862306a36Sopenharmony_ci		.drv_name = "avs_max98373",
14962306a36Sopenharmony_ci		.mach_params = {
15062306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
15162306a36Sopenharmony_ci		},
15262306a36Sopenharmony_ci		.tplg_filename = "max98373-tplg.bin",
15362306a36Sopenharmony_ci	},
15462306a36Sopenharmony_ci	{
15562306a36Sopenharmony_ci		.id = "MX98357A",
15662306a36Sopenharmony_ci		.drv_name = "avs_max98357a",
15762306a36Sopenharmony_ci		.mach_params = {
15862306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
15962306a36Sopenharmony_ci		},
16062306a36Sopenharmony_ci		.tplg_filename = "max98357a-tplg.bin",
16162306a36Sopenharmony_ci	},
16262306a36Sopenharmony_ci	{
16362306a36Sopenharmony_ci		.id = "DLGS7219",
16462306a36Sopenharmony_ci		.drv_name = "avs_da7219",
16562306a36Sopenharmony_ci		.mach_params = {
16662306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(1),
16762306a36Sopenharmony_ci		},
16862306a36Sopenharmony_ci		.tplg_filename = "da7219-tplg.bin",
16962306a36Sopenharmony_ci	},
17062306a36Sopenharmony_ci	{
17162306a36Sopenharmony_ci		.id = "ESSX8336",
17262306a36Sopenharmony_ci		.drv_name = "avs_es8336",
17362306a36Sopenharmony_ci		.mach_params = {
17462306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
17562306a36Sopenharmony_ci		},
17662306a36Sopenharmony_ci		.tplg_filename = "es8336-tplg.bin",
17762306a36Sopenharmony_ci	},
17862306a36Sopenharmony_ci	{},
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic struct snd_soc_acpi_mach avs_apl_i2s_machines[] = {
18262306a36Sopenharmony_ci	{
18362306a36Sopenharmony_ci		.id = "INT343A",
18462306a36Sopenharmony_ci		.drv_name = "avs_rt298",
18562306a36Sopenharmony_ci		.mach_params = {
18662306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(5),
18762306a36Sopenharmony_ci		},
18862306a36Sopenharmony_ci		.tplg_filename = "rt298-tplg.bin",
18962306a36Sopenharmony_ci	},
19062306a36Sopenharmony_ci	{
19162306a36Sopenharmony_ci		.id = "INT34C3",
19262306a36Sopenharmony_ci		.drv_name = "avs_tdf8532",
19362306a36Sopenharmony_ci		.mach_params = {
19462306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP_RANGE(0, 5),
19562306a36Sopenharmony_ci		},
19662306a36Sopenharmony_ci		.pdata = (unsigned long[]){ 0, 0, 0x14, 0, 0, 0 }, /* SSP2 TDMs */
19762306a36Sopenharmony_ci		.tplg_filename = "tdf8532-tplg.bin",
19862306a36Sopenharmony_ci	},
19962306a36Sopenharmony_ci	{
20062306a36Sopenharmony_ci		.id = "MX98357A",
20162306a36Sopenharmony_ci		.drv_name = "avs_max98357a",
20262306a36Sopenharmony_ci		.mach_params = {
20362306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(5),
20462306a36Sopenharmony_ci		},
20562306a36Sopenharmony_ci		.tplg_filename = "max98357a-tplg.bin",
20662306a36Sopenharmony_ci	},
20762306a36Sopenharmony_ci	{
20862306a36Sopenharmony_ci		.id = "DLGS7219",
20962306a36Sopenharmony_ci		.drv_name = "avs_da7219",
21062306a36Sopenharmony_ci		.mach_params = {
21162306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(1),
21262306a36Sopenharmony_ci		},
21362306a36Sopenharmony_ci		.tplg_filename = "da7219-tplg.bin",
21462306a36Sopenharmony_ci	},
21562306a36Sopenharmony_ci	{},
21662306a36Sopenharmony_ci};
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic struct snd_soc_acpi_mach avs_gml_i2s_machines[] = {
21962306a36Sopenharmony_ci	{
22062306a36Sopenharmony_ci		.id = "INT343A",
22162306a36Sopenharmony_ci		.drv_name = "avs_rt298",
22262306a36Sopenharmony_ci		.mach_params = {
22362306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(2),
22462306a36Sopenharmony_ci		},
22562306a36Sopenharmony_ci		.tplg_filename = "rt298-tplg.bin",
22662306a36Sopenharmony_ci	},
22762306a36Sopenharmony_ci	{},
22862306a36Sopenharmony_ci};
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic struct snd_soc_acpi_mach avs_test_i2s_machines[] = {
23162306a36Sopenharmony_ci	{
23262306a36Sopenharmony_ci		.drv_name = "avs_i2s_test",
23362306a36Sopenharmony_ci		.mach_params = {
23462306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(0),
23562306a36Sopenharmony_ci		},
23662306a36Sopenharmony_ci		.tplg_filename = "i2s-test-tplg.bin",
23762306a36Sopenharmony_ci	},
23862306a36Sopenharmony_ci	{
23962306a36Sopenharmony_ci		.drv_name = "avs_i2s_test",
24062306a36Sopenharmony_ci		.mach_params = {
24162306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(1),
24262306a36Sopenharmony_ci		},
24362306a36Sopenharmony_ci		.tplg_filename = "i2s-test-tplg.bin",
24462306a36Sopenharmony_ci	},
24562306a36Sopenharmony_ci	{
24662306a36Sopenharmony_ci		.drv_name = "avs_i2s_test",
24762306a36Sopenharmony_ci		.mach_params = {
24862306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(2),
24962306a36Sopenharmony_ci		},
25062306a36Sopenharmony_ci		.tplg_filename = "i2s-test-tplg.bin",
25162306a36Sopenharmony_ci	},
25262306a36Sopenharmony_ci	{
25362306a36Sopenharmony_ci		.drv_name = "avs_i2s_test",
25462306a36Sopenharmony_ci		.mach_params = {
25562306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(3),
25662306a36Sopenharmony_ci		},
25762306a36Sopenharmony_ci		.tplg_filename = "i2s-test-tplg.bin",
25862306a36Sopenharmony_ci	},
25962306a36Sopenharmony_ci	{
26062306a36Sopenharmony_ci		.drv_name = "avs_i2s_test",
26162306a36Sopenharmony_ci		.mach_params = {
26262306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(4),
26362306a36Sopenharmony_ci		},
26462306a36Sopenharmony_ci		.tplg_filename = "i2s-test-tplg.bin",
26562306a36Sopenharmony_ci	},
26662306a36Sopenharmony_ci	{
26762306a36Sopenharmony_ci		.drv_name = "avs_i2s_test",
26862306a36Sopenharmony_ci		.mach_params = {
26962306a36Sopenharmony_ci			.i2s_link_mask = AVS_SSP(5),
27062306a36Sopenharmony_ci		},
27162306a36Sopenharmony_ci		.tplg_filename = "i2s-test-tplg.bin",
27262306a36Sopenharmony_ci	},
27362306a36Sopenharmony_ci	/* no NULL terminator, as we depend on ARRAY SIZE due to .id == NULL */
27462306a36Sopenharmony_ci};
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistruct avs_acpi_boards {
27762306a36Sopenharmony_ci	int id;
27862306a36Sopenharmony_ci	struct snd_soc_acpi_mach *machs;
27962306a36Sopenharmony_ci};
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci#define AVS_MACH_ENTRY(_id, _mach) \
28262306a36Sopenharmony_ci	{ .id = PCI_DEVICE_ID_INTEL_##_id, .machs = (_mach), }
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci/* supported I2S boards per platform */
28562306a36Sopenharmony_cistatic const struct avs_acpi_boards i2s_boards[] = {
28662306a36Sopenharmony_ci	AVS_MACH_ENTRY(HDA_SKL_LP, avs_skl_i2s_machines),
28762306a36Sopenharmony_ci	AVS_MACH_ENTRY(HDA_KBL_LP, avs_kbl_i2s_machines),
28862306a36Sopenharmony_ci	AVS_MACH_ENTRY(HDA_APL, avs_apl_i2s_machines),
28962306a36Sopenharmony_ci	AVS_MACH_ENTRY(HDA_GML, avs_gml_i2s_machines),
29062306a36Sopenharmony_ci	{},
29162306a36Sopenharmony_ci};
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_cistatic const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	int id, i;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	id = adev->base.pci->device;
29862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(i2s_boards); i++)
29962306a36Sopenharmony_ci		if (i2s_boards[i].id == id)
30062306a36Sopenharmony_ci			return &i2s_boards[i];
30162306a36Sopenharmony_ci	return NULL;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/* platform devices owned by AVS audio are removed with this hook */
30562306a36Sopenharmony_cistatic void board_pdev_unregister(void *data)
30662306a36Sopenharmony_ci{
30762306a36Sopenharmony_ci	platform_device_unregister(data);
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic int __maybe_unused avs_register_probe_board(struct avs_dev *adev)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	struct platform_device *board;
31362306a36Sopenharmony_ci	struct snd_soc_acpi_mach mach = {{0}};
31462306a36Sopenharmony_ci	int ret;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	ret = avs_probe_platform_register(adev, "probe-platform");
31762306a36Sopenharmony_ci	if (ret < 0)
31862306a36Sopenharmony_ci		return ret;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	mach.mach_params.platform = "probe-platform";
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	board = platform_device_register_data(NULL, "avs_probe_mb", PLATFORM_DEVID_NONE,
32362306a36Sopenharmony_ci					      (const void *)&mach, sizeof(mach));
32462306a36Sopenharmony_ci	if (IS_ERR(board)) {
32562306a36Sopenharmony_ci		dev_err(adev->dev, "probe board register failed\n");
32662306a36Sopenharmony_ci		return PTR_ERR(board);
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
33062306a36Sopenharmony_ci	if (ret < 0) {
33162306a36Sopenharmony_ci		platform_device_unregister(board);
33262306a36Sopenharmony_ci		return ret;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci	return 0;
33562306a36Sopenharmony_ci}
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic int avs_register_dmic_board(struct avs_dev *adev)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	struct platform_device *codec, *board;
34062306a36Sopenharmony_ci	struct snd_soc_acpi_mach mach = {{0}};
34162306a36Sopenharmony_ci	int ret;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (!adev->nhlt ||
34462306a36Sopenharmony_ci	    !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_DMIC)) {
34562306a36Sopenharmony_ci		dev_dbg(adev->dev, "no DMIC endpoints present\n");
34662306a36Sopenharmony_ci		return 0;
34762306a36Sopenharmony_ci	}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	codec = platform_device_register_simple("dmic-codec", PLATFORM_DEVID_NONE, NULL, 0);
35062306a36Sopenharmony_ci	if (IS_ERR(codec)) {
35162306a36Sopenharmony_ci		dev_err(adev->dev, "dmic codec register failed\n");
35262306a36Sopenharmony_ci		return PTR_ERR(codec);
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	ret = devm_add_action(adev->dev, board_pdev_unregister, codec);
35662306a36Sopenharmony_ci	if (ret < 0) {
35762306a36Sopenharmony_ci		platform_device_unregister(codec);
35862306a36Sopenharmony_ci		return ret;
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	ret = avs_dmic_platform_register(adev, "dmic-platform");
36262306a36Sopenharmony_ci	if (ret < 0)
36362306a36Sopenharmony_ci		return ret;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	mach.tplg_filename = "dmic-tplg.bin";
36662306a36Sopenharmony_ci	mach.mach_params.platform = "dmic-platform";
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	board = platform_device_register_data(NULL, "avs_dmic", PLATFORM_DEVID_NONE,
36962306a36Sopenharmony_ci					(const void *)&mach, sizeof(mach));
37062306a36Sopenharmony_ci	if (IS_ERR(board)) {
37162306a36Sopenharmony_ci		dev_err(adev->dev, "dmic board register failed\n");
37262306a36Sopenharmony_ci		return PTR_ERR(board);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
37662306a36Sopenharmony_ci	if (ret < 0) {
37762306a36Sopenharmony_ci		platform_device_unregister(board);
37862306a36Sopenharmony_ci		return ret;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	return 0;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic int avs_register_i2s_board(struct avs_dev *adev, struct snd_soc_acpi_mach *mach)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct platform_device *board;
38762306a36Sopenharmony_ci	int num_ssps;
38862306a36Sopenharmony_ci	char *name;
38962306a36Sopenharmony_ci	int ret;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
39262306a36Sopenharmony_ci	if (fls(mach->mach_params.i2s_link_mask) > num_ssps) {
39362306a36Sopenharmony_ci		dev_err(adev->dev, "Platform supports %d SSPs but board %s requires SSP%ld\n",
39462306a36Sopenharmony_ci			num_ssps, mach->drv_name,
39562306a36Sopenharmony_ci			(unsigned long)__fls(mach->mach_params.i2s_link_mask));
39662306a36Sopenharmony_ci		return -ENODEV;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	name = devm_kasprintf(adev->dev, GFP_KERNEL, "%s.%d-platform", mach->drv_name,
40062306a36Sopenharmony_ci			      mach->mach_params.i2s_link_mask);
40162306a36Sopenharmony_ci	if (!name)
40262306a36Sopenharmony_ci		return -ENOMEM;
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_ci	ret = avs_i2s_platform_register(adev, name, mach->mach_params.i2s_link_mask, mach->pdata);
40562306a36Sopenharmony_ci	if (ret < 0)
40662306a36Sopenharmony_ci		return ret;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	mach->mach_params.platform = name;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	board = platform_device_register_data(NULL, mach->drv_name, mach->mach_params.i2s_link_mask,
41162306a36Sopenharmony_ci					      (const void *)mach, sizeof(*mach));
41262306a36Sopenharmony_ci	if (IS_ERR(board)) {
41362306a36Sopenharmony_ci		dev_err(adev->dev, "ssp board register failed\n");
41462306a36Sopenharmony_ci		return PTR_ERR(board);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
41862306a36Sopenharmony_ci	if (ret < 0) {
41962306a36Sopenharmony_ci		platform_device_unregister(board);
42062306a36Sopenharmony_ci		return ret;
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	return 0;
42462306a36Sopenharmony_ci}
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic int avs_register_i2s_boards(struct avs_dev *adev)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	const struct avs_acpi_boards *boards;
42962306a36Sopenharmony_ci	struct snd_soc_acpi_mach *mach;
43062306a36Sopenharmony_ci	int ret;
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (!adev->nhlt || !intel_nhlt_has_endpoint_type(adev->nhlt, NHLT_LINK_SSP)) {
43362306a36Sopenharmony_ci		dev_dbg(adev->dev, "no I2S endpoints present\n");
43462306a36Sopenharmony_ci		return 0;
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	if (i2s_test) {
43862306a36Sopenharmony_ci		int i, num_ssps;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci		num_ssps = adev->hw_cfg.i2s_caps.ctrl_count;
44162306a36Sopenharmony_ci		/* constrain just in case FW says there can be more SSPs than possible */
44262306a36Sopenharmony_ci		num_ssps = min_t(int, ARRAY_SIZE(avs_test_i2s_machines), num_ssps);
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci		mach = avs_test_i2s_machines;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci		for (i = 0; i < num_ssps; i++) {
44762306a36Sopenharmony_ci			ret = avs_register_i2s_board(adev, &mach[i]);
44862306a36Sopenharmony_ci			if (ret < 0)
44962306a36Sopenharmony_ci				dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name,
45062306a36Sopenharmony_ci					 ret);
45162306a36Sopenharmony_ci		}
45262306a36Sopenharmony_ci		return 0;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	boards = avs_get_i2s_boards(adev);
45662306a36Sopenharmony_ci	if (!boards) {
45762306a36Sopenharmony_ci		dev_dbg(adev->dev, "no I2S endpoints supported\n");
45862306a36Sopenharmony_ci		return 0;
45962306a36Sopenharmony_ci	}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	for (mach = boards->machs; mach->id[0]; mach++) {
46262306a36Sopenharmony_ci		if (!acpi_dev_present(mach->id, mach->uid, -1))
46362306a36Sopenharmony_ci			continue;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci		if (mach->machine_quirk)
46662306a36Sopenharmony_ci			if (!mach->machine_quirk(mach))
46762306a36Sopenharmony_ci				continue;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		ret = avs_register_i2s_board(adev, mach);
47062306a36Sopenharmony_ci		if (ret < 0)
47162306a36Sopenharmony_ci			dev_warn(adev->dev, "register i2s %s failed: %d\n", mach->drv_name, ret);
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	return 0;
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_cistatic int avs_register_hda_board(struct avs_dev *adev, struct hda_codec *codec)
47862306a36Sopenharmony_ci{
47962306a36Sopenharmony_ci	struct snd_soc_acpi_mach mach = {{0}};
48062306a36Sopenharmony_ci	struct platform_device *board;
48162306a36Sopenharmony_ci	struct hdac_device *hdev = &codec->core;
48262306a36Sopenharmony_ci	char *pname;
48362306a36Sopenharmony_ci	int ret, id;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	pname = devm_kasprintf(adev->dev, GFP_KERNEL, "%s-platform", dev_name(&hdev->dev));
48662306a36Sopenharmony_ci	if (!pname)
48762306a36Sopenharmony_ci		return -ENOMEM;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	ret = avs_hda_platform_register(adev, pname);
49062306a36Sopenharmony_ci	if (ret < 0)
49162306a36Sopenharmony_ci		return ret;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	mach.pdata = codec;
49462306a36Sopenharmony_ci	mach.mach_params.platform = pname;
49562306a36Sopenharmony_ci	mach.tplg_filename = devm_kasprintf(adev->dev, GFP_KERNEL, "hda-%08x-tplg.bin",
49662306a36Sopenharmony_ci					    hdev->vendor_id);
49762306a36Sopenharmony_ci	if (!mach.tplg_filename)
49862306a36Sopenharmony_ci		return -ENOMEM;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	id = adev->base.core.idx * HDA_MAX_CODECS + hdev->addr;
50162306a36Sopenharmony_ci	board = platform_device_register_data(NULL, "avs_hdaudio", id, (const void *)&mach,
50262306a36Sopenharmony_ci					      sizeof(mach));
50362306a36Sopenharmony_ci	if (IS_ERR(board)) {
50462306a36Sopenharmony_ci		dev_err(adev->dev, "hda board register failed\n");
50562306a36Sopenharmony_ci		return PTR_ERR(board);
50662306a36Sopenharmony_ci	}
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	ret = devm_add_action(adev->dev, board_pdev_unregister, board);
50962306a36Sopenharmony_ci	if (ret < 0) {
51062306a36Sopenharmony_ci		platform_device_unregister(board);
51162306a36Sopenharmony_ci		return ret;
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return 0;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic int avs_register_hda_boards(struct avs_dev *adev)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	struct hdac_bus *bus = &adev->base.core;
52062306a36Sopenharmony_ci	struct hdac_device *hdev;
52162306a36Sopenharmony_ci	int ret;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	if (!bus->num_codecs) {
52462306a36Sopenharmony_ci		dev_dbg(adev->dev, "no HDA endpoints present\n");
52562306a36Sopenharmony_ci		return 0;
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	list_for_each_entry(hdev, &bus->codec_list, list) {
52962306a36Sopenharmony_ci		struct hda_codec *codec;
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci		codec = dev_to_hda_codec(&hdev->dev);
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci		ret = avs_register_hda_board(adev, codec);
53462306a36Sopenharmony_ci		if (ret < 0)
53562306a36Sopenharmony_ci			dev_warn(adev->dev, "register hda-%08x failed: %d\n",
53662306a36Sopenharmony_ci				 codec->core.vendor_id, ret);
53762306a36Sopenharmony_ci	}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ciint avs_register_all_boards(struct avs_dev *adev)
54362306a36Sopenharmony_ci{
54462306a36Sopenharmony_ci	int ret;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
54762306a36Sopenharmony_ci	ret = avs_register_probe_board(adev);
54862306a36Sopenharmony_ci	if (ret < 0)
54962306a36Sopenharmony_ci		dev_warn(adev->dev, "enumerate PROBE endpoints failed: %d\n", ret);
55062306a36Sopenharmony_ci#endif
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	ret = avs_register_dmic_board(adev);
55362306a36Sopenharmony_ci	if (ret < 0)
55462306a36Sopenharmony_ci		dev_warn(adev->dev, "enumerate DMIC endpoints failed: %d\n",
55562306a36Sopenharmony_ci			 ret);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	ret = avs_register_i2s_boards(adev);
55862306a36Sopenharmony_ci	if (ret < 0)
55962306a36Sopenharmony_ci		dev_warn(adev->dev, "enumerate I2S endpoints failed: %d\n",
56062306a36Sopenharmony_ci			 ret);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	ret = avs_register_hda_boards(adev);
56362306a36Sopenharmony_ci	if (ret < 0)
56462306a36Sopenharmony_ci		dev_warn(adev->dev, "enumerate HDA endpoints failed: %d\n",
56562306a36Sopenharmony_ci			 ret);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	return 0;
56862306a36Sopenharmony_ci}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_civoid avs_unregister_all_boards(struct avs_dev *adev)
57162306a36Sopenharmony_ci{
57262306a36Sopenharmony_ci	snd_soc_unregister_component(adev->dev);
57362306a36Sopenharmony_ci}
574