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_peripherals
*peripherals
)
136 unsigned int part_id
, link_id
, unique_id
, mfg_id
, version
;
139 for (i
= 0; i
< link
->num_adr
; i
++) {
140 u64 adr
= link
->adr_d
[i
].adr
;
141 int reported_part_count
= 0;
143 mfg_id
= SDW_MFG_ID(adr
);
144 part_id
= SDW_PART_ID(adr
);
145 link_id
= SDW_DISCO_LINK_ID(adr
);
146 version
= SDW_VERSION(adr
);
148 for (j
= 0; j
< peripherals
->num_peripherals
; j
++) {
149 struct sdw_slave
*peripheral
= peripherals
->array
[j
];
151 /* find out how many identical parts were reported on that link */
152 if (peripheral
->bus
->link_id
== link_id
&&
153 peripheral
->id
.part_id
== part_id
&&
154 peripheral
->id
.mfg_id
== mfg_id
&&
155 peripheral
->id
.sdw_version
== version
)
156 reported_part_count
++;
159 for (j
= 0; j
< peripherals
->num_peripherals
; j
++) {
160 struct sdw_slave
*peripheral
= peripherals
->array
[j
];
161 int expected_part_count
= 0;
163 if (peripheral
->bus
->link_id
!= link_id
||
164 peripheral
->id
.part_id
!= part_id
||
165 peripheral
->id
.mfg_id
!= mfg_id
||
166 peripheral
->id
.sdw_version
!= version
)
169 /* find out how many identical parts are expected */
170 for (k
= 0; k
< link
->num_adr
; k
++) {
171 u64 adr2
= link
->adr_d
[k
].adr
;
173 if (SDW_CODEC_ADR_MASK(adr2
) == SDW_CODEC_ADR_MASK(adr
))
174 expected_part_count
++;
177 if (reported_part_count
== expected_part_count
) {
179 * we have to check unique id
180 * if there is more than one
183 unique_id
= SDW_UNIQUE_ID(adr
);
184 if (reported_part_count
== 1 ||
185 peripheral
->id
.unique_id
== unique_id
) {
186 dev_dbg(dev
, "found part_id %#x at link %d\n", part_id
, link_id
);
190 dev_dbg(dev
, "part_id %#x reported %d expected %d on link %d, skipping\n",
191 part_id
, reported_part_count
, expected_part_count
, link_id
);
194 if (j
== peripherals
->num_peripherals
) {
195 dev_dbg(dev
, "Slave part_id %#x not found\n", part_id
);
201 EXPORT_SYMBOL_GPL(snd_soc_acpi_sdw_link_slaves_found
);
203 MODULE_LICENSE("GPL v2");
204 MODULE_DESCRIPTION("ALSA SoC ACPI module");