Skip to content

Commit 267b9cd

Browse files
rfvirgilbroonie
authored andcommitted
ASoC: cs-amp-lib: Add handling for Lenovo and HP UEFI speaker ID
Add handling of the Lenovo-specific and HP-specific EFI variables for speaker ID. Future Lenovo and HP models will not give the codec driver access to the speaker detect GPIO. Instead, the BIOS will read the GPIO and create an EFI variable with a value indicating the state of the GPIO. The Lenovo and HP EFI variables are both defined to have only two valid values. But the variable name, GUID and values are different. This adds a new exported function cs_amp_get_vendor_spkid(). Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com> Message-ID: <20250909113039.922065-3-rf@opensource.cirrus.com> Signed-off-by: Mark Brown <broonie@kernel.org>
1 parent 89ace3a commit 267b9cd

2 files changed

Lines changed: 102 additions & 0 deletions

File tree

include/sound/cs-amp-lib.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ int cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
4949
const struct cirrus_amp_cal_data *data);
5050
int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index,
5151
struct cirrus_amp_cal_data *out_data);
52+
int cs_amp_get_vendor_spkid(struct device *dev);
5253

5354
struct cs_amp_test_hooks {
5455
efi_status_t (*get_efi_variable)(efi_char16_t *name,

sound/soc/codecs/cs-amp-lib.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,14 @@
2020
#define CIRRUS_LOGIC_CALIBRATION_EFI_GUID \
2121
EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3)
2222

23+
#define LENOVO_SPEAKER_ID_EFI_NAME L"SdwSpeaker"
24+
#define LENOVO_SPEAKER_ID_EFI_GUID \
25+
EFI_GUID(0x48df970e, 0xe27f, 0x460a, 0xb5, 0x86, 0x77, 0x19, 0x80, 0x1d, 0x92, 0x82)
26+
27+
#define HP_SPEAKER_ID_EFI_NAME L"HPSpeakerID"
28+
#define HP_SPEAKER_ID_EFI_GUID \
29+
EFI_GUID(0xc49593a4, 0xd099, 0x419b, 0xa2, 0xc3, 0x67, 0xe9, 0x80, 0xe6, 0x1d, 0x1e)
30+
2331
static int cs_amp_write_cal_coeff(struct cs_dsp *dsp,
2432
const struct cirrus_amp_cal_controls *controls,
2533
const char *ctl_name, u32 val)
@@ -114,6 +122,24 @@ static efi_status_t cs_amp_get_efi_variable(efi_char16_t *name,
114122
return EFI_NOT_FOUND;
115123
}
116124

125+
static int cs_amp_convert_efi_status(efi_status_t status)
126+
{
127+
switch (status) {
128+
case EFI_SUCCESS:
129+
return 0;
130+
case EFI_NOT_FOUND:
131+
return -ENOENT;
132+
case EFI_BUFFER_TOO_SMALL:
133+
return -EFBIG;
134+
case EFI_UNSUPPORTED:
135+
case EFI_ACCESS_DENIED:
136+
case EFI_SECURITY_VIOLATION:
137+
return -EACCES;
138+
default:
139+
return -EIO;
140+
}
141+
}
142+
117143
static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev)
118144
{
119145
struct cirrus_amp_efi_data *efi_data;
@@ -276,6 +302,81 @@ int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_
276302
}
277303
EXPORT_SYMBOL_NS_GPL(cs_amp_get_efi_calibration_data, "SND_SOC_CS_AMP_LIB");
278304

305+
struct cs_amp_spkid_efi {
306+
efi_char16_t *name;
307+
efi_guid_t *guid;
308+
u8 values[2];
309+
};
310+
311+
static int cs_amp_get_efi_byte_spkid(struct device *dev, const struct cs_amp_spkid_efi *info)
312+
{
313+
efi_status_t status;
314+
unsigned long size;
315+
u8 spkid;
316+
int i, ret;
317+
318+
size = sizeof(spkid);
319+
status = cs_amp_get_efi_variable(info->name, info->guid, &size, &spkid);
320+
ret = cs_amp_convert_efi_status(status);
321+
if (ret < 0)
322+
return ret;
323+
324+
if (size == 0)
325+
return -ENOENT;
326+
327+
for (i = 0; i < ARRAY_SIZE(info->values); i++) {
328+
if (info->values[i] == spkid)
329+
return i;
330+
}
331+
332+
dev_err(dev, "EFI speaker ID bad value %#x\n", spkid);
333+
334+
return -EINVAL;
335+
}
336+
337+
static const struct cs_amp_spkid_efi cs_amp_spkid_byte_types[] = {
338+
{
339+
.name = LENOVO_SPEAKER_ID_EFI_NAME,
340+
.guid = &LENOVO_SPEAKER_ID_EFI_GUID,
341+
.values = { 0xd0, 0xd1 },
342+
},
343+
{
344+
.name = HP_SPEAKER_ID_EFI_NAME,
345+
.guid = &HP_SPEAKER_ID_EFI_GUID,
346+
.values = { 0x30, 0x31 },
347+
},
348+
};
349+
350+
/**
351+
* cs_amp_get_vendor_spkid - get a speaker ID from vendor-specific storage
352+
* @dev: pointer to struct device
353+
*
354+
* Known vendor-specific methods of speaker ID are checked and if one is
355+
* found its speaker ID value is returned.
356+
*
357+
* Return: >=0 is a valid speaker ID. -ENOENT if a vendor-specific method
358+
* was not found. -EACCES if the vendor-specific storage could not
359+
* be read. Other error values indicate that the data from the
360+
* vendor-specific storage was found but could not be understood.
361+
*/
362+
int cs_amp_get_vendor_spkid(struct device *dev)
363+
{
364+
int i, ret;
365+
366+
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE) &&
367+
!IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST))
368+
return -ENOENT;
369+
370+
for (i = 0; i < ARRAY_SIZE(cs_amp_spkid_byte_types); i++) {
371+
ret = cs_amp_get_efi_byte_spkid(dev, &cs_amp_spkid_byte_types[i]);
372+
if (ret != -ENOENT)
373+
return ret;
374+
}
375+
376+
return -ENOENT;
377+
}
378+
EXPORT_SYMBOL_NS_GPL(cs_amp_get_vendor_spkid, "SND_SOC_CS_AMP_LIB");
379+
279380
static const struct cs_amp_test_hooks cs_amp_test_hook_ptrs = {
280381
.get_efi_variable = cs_amp_get_efi_variable,
281382
.write_cal_coeff = cs_amp_write_cal_coeff,

0 commit comments

Comments
 (0)