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