xref: /openbmc/linux/sound/soc/soc-acpi.c (revision fe7498ef)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // soc-apci.c - support for ACPI enumeration.
4 //
5 // Copyright (c) 2013-15, Intel Corporation.
6 
7 #include <linux/export.h>
8 #include <linux/module.h>
9 #include <sound/soc-acpi.h>
10 
11 static bool snd_soc_acpi_id_present(struct snd_soc_acpi_mach *machine)
12 {
13 	const struct snd_soc_acpi_codecs *comp_ids = machine->comp_ids;
14 	int i;
15 
16 	if (machine->id[0]) {
17 		if (acpi_dev_present(machine->id, NULL, -1))
18 			return true;
19 	}
20 
21 	if (comp_ids) {
22 		for (i = 0; i < comp_ids->num_codecs; i++) {
23 			if (acpi_dev_present(comp_ids->codecs[i], NULL, -1))
24 				return true;
25 		}
26 	}
27 
28 	return false;
29 }
30 
31 struct snd_soc_acpi_mach *
32 snd_soc_acpi_find_machine(struct snd_soc_acpi_mach *machines)
33 {
34 	struct snd_soc_acpi_mach *mach;
35 	struct snd_soc_acpi_mach *mach_alt;
36 
37 	for (mach = machines; mach->id[0] || mach->comp_ids; mach++) {
38 		if (snd_soc_acpi_id_present(mach)) {
39 			if (mach->machine_quirk) {
40 				mach_alt = mach->machine_quirk(mach);
41 				if (!mach_alt)
42 					continue; /* not full match, ignore */
43 				mach = mach_alt;
44 			}
45 
46 			return mach;
47 		}
48 	}
49 	return NULL;
50 }
51 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine);
52 
53 static acpi_status snd_soc_acpi_find_package(acpi_handle handle, u32 level,
54 					     void *context, void **ret)
55 {
56 	struct acpi_device *adev;
57 	acpi_status status;
58 	struct snd_soc_acpi_package_context *pkg_ctx = context;
59 
60 	pkg_ctx->data_valid = false;
61 
62 	if (acpi_bus_get_device(handle, &adev))
63 		return AE_OK;
64 
65 	if (adev->status.present && adev->status.functional) {
66 		struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
67 		union acpi_object  *myobj = NULL;
68 
69 		status = acpi_evaluate_object_typed(handle, pkg_ctx->name,
70 						NULL, &buffer,
71 						ACPI_TYPE_PACKAGE);
72 		if (ACPI_FAILURE(status))
73 			return AE_OK;
74 
75 		myobj = buffer.pointer;
76 		if (!myobj || myobj->package.count != pkg_ctx->length) {
77 			kfree(buffer.pointer);
78 			return AE_OK;
79 		}
80 
81 		status = acpi_extract_package(myobj,
82 					pkg_ctx->format, pkg_ctx->state);
83 		if (ACPI_FAILURE(status)) {
84 			kfree(buffer.pointer);
85 			return AE_OK;
86 		}
87 
88 		kfree(buffer.pointer);
89 		pkg_ctx->data_valid = true;
90 		return AE_CTRL_TERMINATE;
91 	}
92 
93 	return AE_OK;
94 }
95 
96 bool snd_soc_acpi_find_package_from_hid(const u8 hid[ACPI_ID_LEN],
97 				struct snd_soc_acpi_package_context *ctx)
98 {
99 	acpi_status status;
100 
101 	status = acpi_get_devices(hid, snd_soc_acpi_find_package, ctx, NULL);
102 
103 	if (ACPI_FAILURE(status) || !ctx->data_valid)
104 		return false;
105 
106 	return true;
107 }
108 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_package_from_hid);
109 
110 struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
111 {
112 	struct snd_soc_acpi_mach *mach = arg;
113 	struct snd_soc_acpi_codecs *codec_list =
114 		(struct snd_soc_acpi_codecs *) mach->quirk_data;
115 	int i;
116 
117 	if (mach->quirk_data == NULL)
118 		return mach;
119 
120 	for (i = 0; i < codec_list->num_codecs; i++) {
121 		if (!acpi_dev_present(codec_list->codecs[i], NULL, -1))
122 			return NULL;
123 	}
124 
125 	return mach;
126 }
127 EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list);
128 
129 MODULE_LICENSE("GPL v2");
130 MODULE_DESCRIPTION("ALSA SoC ACPI module");
131