1 // SPDX-License-Identifier: GPL-2.0
3 // soc-apci.c - support for ACPI enumeration.
5 // Copyright (c) 2013-15, Intel Corporation.
7 #include <linux/export.h>
8 #include <linux/module.h>
9 #include <sound/soc-acpi.h>
11 static bool snd_soc_acpi_id_present(struct snd_soc_acpi_mach
*machine
)
13 const struct snd_soc_acpi_codecs
*comp_ids
= machine
->comp_ids
;
17 if (acpi_dev_present(machine
->id
, NULL
, -1))
22 for (i
= 0; i
< comp_ids
->num_codecs
; i
++) {
23 if (acpi_dev_present(comp_ids
->codecs
[i
], NULL
, -1)) {
24 strscpy(machine
->id
, comp_ids
->codecs
[i
], ACPI_ID_LEN
);
33 struct snd_soc_acpi_mach
*
34 snd_soc_acpi_find_machine(struct snd_soc_acpi_mach
*machines
)
36 struct snd_soc_acpi_mach
*mach
;
37 struct snd_soc_acpi_mach
*mach_alt
;
39 for (mach
= machines
; mach
->id
[0] || mach
->comp_ids
; mach
++) {
40 if (snd_soc_acpi_id_present(mach
)) {
41 if (mach
->machine_quirk
) {
42 mach_alt
= mach
->machine_quirk(mach
);
44 continue; /* not full match, ignore */
53 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_machine
);
55 static acpi_status
snd_soc_acpi_find_package(acpi_handle handle
, u32 level
,
56 void *context
, void **ret
)
58 struct acpi_device
*adev
= acpi_fetch_acpi_dev(handle
);
60 struct snd_soc_acpi_package_context
*pkg_ctx
= context
;
62 pkg_ctx
->data_valid
= false;
64 if (adev
&& adev
->status
.present
&& adev
->status
.functional
) {
65 struct acpi_buffer buffer
= {ACPI_ALLOCATE_BUFFER
, NULL
};
66 union acpi_object
*myobj
= NULL
;
68 status
= acpi_evaluate_object_typed(handle
, pkg_ctx
->name
,
71 if (ACPI_FAILURE(status
))
74 myobj
= buffer
.pointer
;
75 if (!myobj
|| myobj
->package
.count
!= pkg_ctx
->length
) {
76 kfree(buffer
.pointer
);
80 status
= acpi_extract_package(myobj
,
81 pkg_ctx
->format
, pkg_ctx
->state
);
82 if (ACPI_FAILURE(status
)) {
83 kfree(buffer
.pointer
);
87 kfree(buffer
.pointer
);
88 pkg_ctx
->data_valid
= true;
89 return AE_CTRL_TERMINATE
;
95 bool snd_soc_acpi_find_package_from_hid(const u8 hid
[ACPI_ID_LEN
],
96 struct snd_soc_acpi_package_context
*ctx
)
100 status
= acpi_get_devices(hid
, snd_soc_acpi_find_package
, ctx
, NULL
);
102 if (ACPI_FAILURE(status
) || !ctx
->data_valid
)
107 EXPORT_SYMBOL_GPL(snd_soc_acpi_find_package_from_hid
);
109 struct snd_soc_acpi_mach
*snd_soc_acpi_codec_list(void *arg
)
111 struct snd_soc_acpi_mach
*mach
= arg
;
112 struct snd_soc_acpi_codecs
*codec_list
=
113 (struct snd_soc_acpi_codecs
*) mach
->quirk_data
;
116 if (mach
->quirk_data
== NULL
)
119 for (i
= 0; i
< codec_list
->num_codecs
; i
++) {
120 if (!acpi_dev_present(codec_list
->codecs
[i
], NULL
, -1))
126 EXPORT_SYMBOL_GPL(snd_soc_acpi_codec_list
);
128 #define SDW_CODEC_ADR_MASK(_adr) ((_adr) & (SDW_DISCO_LINK_ID_MASK | SDW_VERSION_MASK | \
129 SDW_MFG_ID_MASK | SDW_PART_ID_MASK))
131 /* Check if all Slaves defined on the link can be found */
132 bool snd_soc_acpi_sdw_link_slaves_found(struct device
*dev
,
133 const struct snd_soc_acpi_link_adr
*link
,
134 struct sdw_extended_slave_id
*ids
,
137 unsigned int part_id
, link_id
, unique_id
, mfg_id
, version
;
140 for (i
= 0; i
< link
->num_adr
; i
++) {
141 u64 adr
= link
->adr_d
[i
].adr
;
142 int reported_part_count
= 0;
144 mfg_id
= SDW_MFG_ID(adr
);
145 part_id
= SDW_PART_ID(adr
);
146 link_id
= SDW_DISCO_LINK_ID(adr
);
147 version
= SDW_VERSION(adr
);
149 for (j
= 0; j
< num_slaves
; j
++) {
150 /* find out how many identical parts were reported on that link */
151 if (ids
[j
].link_id
== link_id
&&
152 ids
[j
].id
.part_id
== part_id
&&
153 ids
[j
].id
.mfg_id
== mfg_id
&&
154 ids
[j
].id
.sdw_version
== version
)
155 reported_part_count
++;
158 for (j
= 0; j
< num_slaves
; j
++) {
159 int expected_part_count
= 0;
161 if (ids
[j
].link_id
!= link_id
||
162 ids
[j
].id
.part_id
!= part_id
||
163 ids
[j
].id
.mfg_id
!= mfg_id
||
164 ids
[j
].id
.sdw_version
!= version
)
167 /* find out how many identical parts are expected */
168 for (k
= 0; k
< link
->num_adr
; k
++) {
169 u64 adr2
= link
->adr_d
[k
].adr
;
171 if (SDW_CODEC_ADR_MASK(adr2
) == SDW_CODEC_ADR_MASK(adr
))
172 expected_part_count
++;
175 if (reported_part_count
== expected_part_count
) {
177 * we have to check unique id
178 * if there is more than one
181 unique_id
= SDW_UNIQUE_ID(adr
);
182 if (reported_part_count
== 1 ||
183 ids
[j
].id
.unique_id
== unique_id
) {
184 dev_dbg(dev
, "found part_id %#x at link %d\n", part_id
, link_id
);
188 dev_dbg(dev
, "part_id %#x reported %d expected %d on link %d, skipping\n",
189 part_id
, reported_part_count
, expected_part_count
, link_id
);
192 if (j
== num_slaves
) {
193 dev_dbg(dev
, "Slave part_id %#x not found\n", part_id
);
199 EXPORT_SYMBOL_GPL(snd_soc_acpi_sdw_link_slaves_found
);
201 MODULE_LICENSE("GPL v2");
202 MODULE_DESCRIPTION("ALSA SoC ACPI module");