Linux Sound subsystem development
 help / color / mirror / Atom feed
From: Richard Fitzgerald <rf@opensource.cirrus.com>
To: broonie@kernel.org
Cc: linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org,
	patches@opensource.cirrus.com
Subject: [PATCH 2/6] ASoC: cs-amp-lib: Add handling for Lenovo and HP UEFI speaker ID
Date: Mon,  8 Sep 2025 16:58:38 +0100	[thread overview]
Message-ID: <20250908155842.599459-3-rf@opensource.cirrus.com> (raw)
In-Reply-To: <20250908155842.599459-1-rf@opensource.cirrus.com>

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>
---
 include/sound/cs-amp-lib.h    |   1 +
 sound/soc/codecs/cs-amp-lib.c | 101 ++++++++++++++++++++++++++++++++++
 2 files changed, 102 insertions(+)

diff --git a/include/sound/cs-amp-lib.h b/include/sound/cs-amp-lib.h
index 5459c221badf..43a87a39110c 100644
--- a/include/sound/cs-amp-lib.h
+++ b/include/sound/cs-amp-lib.h
@@ -49,6 +49,7 @@ int cs_amp_write_cal_coeffs(struct cs_dsp *dsp,
 			    const struct cirrus_amp_cal_data *data);
 int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_index,
 				    struct cirrus_amp_cal_data *out_data);
+int cs_amp_get_vendor_spkid(struct device *dev);
 
 struct cs_amp_test_hooks {
 	efi_status_t (*get_efi_variable)(efi_char16_t *name,
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index b1530e7c75e8..9b51d056d863 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -20,6 +20,14 @@
 #define CIRRUS_LOGIC_CALIBRATION_EFI_GUID \
 	EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3)
 
+#define LENOVO_SPEAKER_ID_EFI_NAME L"SdwSpeaker"
+#define LENOVO_SPEAKER_ID_EFI_GUID \
+	EFI_GUID(0x48df970e, 0xe27f, 0x460a, 0xb5, 0x86, 0x77, 0x19, 0x80, 0x1d, 0x92, 0x82)
+
+#define HP_SPEAKER_ID_EFI_NAME L"HPSpeakerID"
+#define HP_SPEAKER_ID_EFI_GUID \
+	EFI_GUID(0xc49593a4, 0xd099, 0x419b, 0xa2, 0xc3, 0x67, 0xe9, 0x80, 0xe6, 0x1d, 0x1e)
+
 static int cs_amp_write_cal_coeff(struct cs_dsp *dsp,
 				  const struct cirrus_amp_cal_controls *controls,
 				  const char *ctl_name, u32 val)
@@ -114,6 +122,24 @@ static efi_status_t cs_amp_get_efi_variable(efi_char16_t *name,
 	return EFI_NOT_FOUND;
 }
 
+static int cs_amp_convert_efi_status(efi_status_t status)
+{
+	switch (status) {
+	case EFI_SUCCESS:
+		return 0;
+	case EFI_NOT_FOUND:
+		return -ENOENT;
+	case EFI_BUFFER_TOO_SMALL:
+		return -EFBIG;
+	case EFI_UNSUPPORTED:
+	case EFI_ACCESS_DENIED:
+	case EFI_SECURITY_VIOLATION:
+		return -EACCES;
+	default:
+		return -EIO;
+	}
+}
+
 static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev)
 {
 	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_
 }
 EXPORT_SYMBOL_NS_GPL(cs_amp_get_efi_calibration_data, "SND_SOC_CS_AMP_LIB");
 
+struct cs_amp_spkid_efi {
+	efi_char16_t *name;
+	efi_guid_t *guid;
+	u8 values[2];
+};
+
+static int cs_amp_get_efi_byte_spkid(struct device *dev, const struct cs_amp_spkid_efi *info)
+{
+	efi_status_t status;
+	unsigned long size;
+	u8 spkid;
+	int i, ret;
+
+	size = sizeof(spkid);
+	status = cs_amp_get_efi_variable(info->name, info->guid, &size, &spkid);
+	ret = cs_amp_convert_efi_status(status);
+	if (ret < 0)
+		return ret;
+
+	if (size == 0)
+		return -ENOENT;
+
+	for (i = 0; i < ARRAY_SIZE(info->values); i++) {
+		if (info->values[i] == spkid)
+			return i;
+	}
+
+	dev_err(dev, "EFI speaker ID bad value %#x\n", spkid);
+
+	return -EINVAL;
+}
+
+static const struct cs_amp_spkid_efi cs_amp_spkid_byte_types[] = {
+	{
+		.name = LENOVO_SPEAKER_ID_EFI_NAME,
+		.guid = &LENOVO_SPEAKER_ID_EFI_GUID,
+		.values = { 0xd0, 0xd1 },
+	},
+	{
+		.name = HP_SPEAKER_ID_EFI_NAME,
+		.guid = &HP_SPEAKER_ID_EFI_GUID,
+		.values = { 0x30, 0x31 },
+	},
+};
+
+/**
+ * cs_amp_get_vendor_spkid - get a speaker ID from vendor-specific storage
+ * @dev:	pointer to struct device
+ *
+ * Known vendor-specific methods of speaker ID are checked and if one is
+ * found its speaker ID value is returned.
+ *
+ * Return: >=0 is a valid speaker ID. -ENOENT if a vendor-specific method
+ *	   was not found. -EACCES if the vendor-specific storage could not
+ *	   be read. Other error values indicate that the data from the
+ *	   vendor-specific storage was found but could not be understood.
+ */
+int cs_amp_get_vendor_spkid(struct device *dev)
+{
+	int i, ret;
+
+	if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE) &&
+	    !IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST))
+		return -ENOENT;
+
+	for (i = 0; i < ARRAY_SIZE(cs_amp_spkid_byte_types); i++) {
+		ret = cs_amp_get_efi_byte_spkid(dev, &cs_amp_spkid_byte_types[i]);
+		if (ret != -ENOENT)
+			return ret;
+	}
+
+	return -ENOENT;
+}
+EXPORT_SYMBOL_NS_GPL(cs_amp_get_vendor_spkid, "SND_SOC_CS_AMP_LIB");
+
 static const struct cs_amp_test_hooks cs_amp_test_hook_ptrs = {
 	.get_efi_variable = cs_amp_get_efi_variable,
 	.write_cal_coeff = cs_amp_write_cal_coeff,
-- 
2.39.5


  parent reply	other threads:[~2025-09-08 15:58 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-09-08 15:58 [PATCH 0/6] ASoC: cs35l56: Handle vendor-specific UEFI variables Richard Fitzgerald
2025-09-08 15:58 ` [PATCH 1/6] ASoC: cs-amp-lib: Rename defines for Cirrus Logic EFI Richard Fitzgerald
2025-09-08 15:58 ` Richard Fitzgerald [this message]
2025-09-08 15:58 ` [PATCH 3/6] ASoC: cs35l56: Check for vendor-specific speaker ID value Richard Fitzgerald
2025-09-08 15:58 ` [PATCH 4/6] ASoC: cs-amp-lib-test: Add tests for cs_amp_get_vendor_spkid() Richard Fitzgerald
2025-09-08 15:58 ` [PATCH 5/6] ASoC: cs-amp-lib: Add HP-specific EFI variable for calibration data Richard Fitzgerald
2025-09-08 15:58 ` [PATCH 6/6] ASoC: cs-amp-lib-test: Add test for getting cal data from HP EFI Richard Fitzgerald

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250908155842.599459-3-rf@opensource.cirrus.com \
    --to=rf@opensource.cirrus.com \
    --cc=broonie@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-sound@vger.kernel.org \
    --cc=patches@opensource.cirrus.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox