18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// soc-apci.c - support for ACPI enumeration. 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (c) 2013-15, Intel Corporation. 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/export.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <sound/soc-acpi.h> 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_cistruct snd_soc_acpi_mach * 128c2ecf20Sopenharmony_cisnd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci struct snd_soc_acpi_mach *mach; 158c2ecf20Sopenharmony_ci struct snd_soc_acpi_mach *mach_alt; 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci for (mach = machines; mach->id[0]; mach++) { 188c2ecf20Sopenharmony_ci if (acpi_dev_present(mach->id, NULL, -1)) { 198c2ecf20Sopenharmony_ci if (mach->machine_quirk) { 208c2ecf20Sopenharmony_ci mach_alt = mach->machine_quirk(mach); 218c2ecf20Sopenharmony_ci if (!mach_alt) 228c2ecf20Sopenharmony_ci continue; /* not full match, ignore */ 238c2ecf20Sopenharmony_ci mach = mach_alt; 248c2ecf20Sopenharmony_ci } 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci return mach; 278c2ecf20Sopenharmony_ci } 288c2ecf20Sopenharmony_ci } 298c2ecf20Sopenharmony_ci return NULL; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine); 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level, 348c2ecf20Sopenharmony_ci void *context, void **ret) 358c2ecf20Sopenharmony_ci{ 368c2ecf20Sopenharmony_ci struct acpi_device *adev; 378c2ecf20Sopenharmony_ci acpi_status status = AE_OK; 388c2ecf20Sopenharmony_ci struct snd_soc_acpi_package_context *pkg_ctx = context; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci pkg_ctx->data_valid = false; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci if (acpi_bus_get_device(handle, &adev)) 438c2ecf20Sopenharmony_ci return AE_OK; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci if (adev->status.present && adev->status.functional) { 468c2ecf20Sopenharmony_ci struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; 478c2ecf20Sopenharmony_ci union acpi_object *myobj = NULL; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci status = acpi_evaluate_object_typed(handle, pkg_ctx->name, 508c2ecf20Sopenharmony_ci NULL, &buffer, 518c2ecf20Sopenharmony_ci ACPI_TYPE_PACKAGE); 528c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 538c2ecf20Sopenharmony_ci return AE_OK; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci myobj = buffer.pointer; 568c2ecf20Sopenharmony_ci if (!myobj || myobj->package.count != pkg_ctx->length) { 578c2ecf20Sopenharmony_ci kfree(buffer.pointer); 588c2ecf20Sopenharmony_ci return AE_OK; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci status = acpi_extract_package(myobj, 628c2ecf20Sopenharmony_ci pkg_ctx->format, pkg_ctx->state); 638c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 648c2ecf20Sopenharmony_ci kfree(buffer.pointer); 658c2ecf20Sopenharmony_ci return AE_OK; 668c2ecf20Sopenharmony_ci } 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci kfree(buffer.pointer); 698c2ecf20Sopenharmony_ci pkg_ctx->data_valid = true; 708c2ecf20Sopenharmony_ci return AE_CTRL_TERMINATE; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return AE_OK; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cibool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN], 778c2ecf20Sopenharmony_ci struct snd_soc_acpi_package_context *ctx) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci acpi_status status; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci status = acpi_get_devices(hid, snd_soc_acpi_find_package, ctx, NULL); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status) || !ctx->data_valid) 848c2ecf20Sopenharmony_ci return false; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return true; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_acpi_find_package_from_hid); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci struct snd_soc_acpi_mach *mach = arg; 938c2ecf20Sopenharmony_ci struct snd_soc_acpi_codecs *codec_list = 948c2ecf20Sopenharmony_ci (struct snd_soc_acpi_codecs *) mach->quirk_data; 958c2ecf20Sopenharmony_ci int i; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (mach->quirk_data == NULL) 988c2ecf20Sopenharmony_ci return mach; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci for (i = 0; i < codec_list->num_codecs; i++) { 1018c2ecf20Sopenharmony_ci if (!acpi_dev_present(codec_list->codecs[i], NULL, -1)) 1028c2ecf20Sopenharmony_ci return NULL; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return mach; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1108c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALSA SoC ACPI module"); 111