* [PATCH] spi: cs42l43: Workaround for wrong speaker ID on Dell XPS 13 DX13260
@ 2026-09-19 13:47 Richard Fitzgerald
0 siblings, 0 replies; only message in thread
From: Richard Fitzgerald @ 2026-09-19 13:47 UTC (permalink / raw)
To: broonie; +Cc: linux-spi, linux-sound, linux-kernel, patches
Create an acpi_gpio_mapping so that speaker ID GPIOs can be read directly
from the ACPI GpioIo() instead of relying on the spk-id-gpios property to
have the correct number of pins. Change the reading loop to read each pin
one at a time until it reaches a pin index that doesn't exist.
This fixes problems on Dell XPS 13 DX13260:
- No speaker audio
- The wrong firmware was loaded so the speaker protection did not match
the speaker characteristics.
The Dell XPS 13 DX13260 has two speaker ID GPIOs, to form a 2-bit ID. The
ACPI GpioIo() has both pins but the Linux-specific spk-id-gpios property
only has a mapping to the first pin. This meant that the speaker ID was
wrong in most cases, and that would lead to the codec driver loading the
wrong amp firmware, or not finding a firmware (as 0 is not valid on this
laptop).
Instead of quirking this specific system, the code can be rewritten so
that it will always use the direct GpioIo() mapping. This works on all
ACPI systems, so avoids having to keep adding quirks for other systems
that have the same ACPI error.
Assisted-by: Codex:gpt-5.6-sol
Reported-by: Wiza Jalakasi <wjalakasi@gmail.com>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221956
Tested-by: Wiza Jalakasi <wjalakasi@gmail.com>
Fixes: f3c605147741e ("spi: cs42l43: Add GPIO speaker id support to the bridge configuration")
Signed-off-by: Richard Fitzgerald <rf@opensource.cirrus.com>
---
drivers/spi/spi-cs42l43.c | 131 ++++++++++++++++++++++++++++++++------
1 file changed, 113 insertions(+), 18 deletions(-)
diff --git a/drivers/spi/spi-cs42l43.c b/drivers/spi/spi-cs42l43.c
index 7106a8a4f2805..ee227205010f7 100644
--- a/drivers/spi/spi-cs42l43.c
+++ b/drivers/spi/spi-cs42l43.c
@@ -19,6 +19,7 @@
#include <linux/mfd/cs42l43-regs.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/overflow.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
@@ -29,6 +30,7 @@
#define CS42L43_FIFO_SIZE 16
#define CS42L43_SPI_ROOT_HZ 49152000
#define CS42L43_SPI_MAX_LENGTH 65532
+#define CS42L43_MAX_SPK_ID_GPIOS 8
enum cs42l43_spi_cmd {
CS42L43_WRITE,
@@ -41,6 +43,12 @@ struct cs42l43_spi {
struct spi_controller *ctlr;
};
+struct cs42l43_spk_id_gpio_mapping {
+ struct fwnode_handle *fwnode;
+ struct acpi_gpio_params params[CS42L43_MAX_SPK_ID_GPIOS];
+ struct acpi_gpio_mapping mappings[2];
+};
+
static const unsigned int cs42l43_clock_divs[] = {
2, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30
};
@@ -215,31 +223,118 @@ static size_t cs42l43_spi_max_length(struct spi_device *spi)
return CS42L43_SPI_MAX_LENGTH;
}
-static int cs42l43_get_speaker_id_gpios(struct cs42l43_spi *priv, int *result)
+static struct cs42l43_spk_id_gpio_mapping *
+cs42l43_add_speaker_id_gpio_mapping(struct cs42l43_spi *priv)
{
- struct gpio_descs *descs;
- u32 spkid;
+ struct fwnode_reference_args args;
+ struct acpi_device *adev;
int i, ret;
- descs = gpiod_get_array_optional(priv->dev, "spk-id", GPIOD_IN);
- if (!descs)
- return 0;
- else if (IS_ERR(descs))
- return PTR_ERR(descs);
-
- spkid = 0;
- for (i = 0; i < descs->ndescs; i++) {
- ret = gpiod_get_value_cansleep(descs->desc[i]);
+ struct cs42l43_spk_id_gpio_mapping *mapping __free(kfree) = kzalloc_obj(*mapping,
+ GFP_KERNEL);
+
+ if (!mapping)
+ return ERR_PTR(-ENOMEM);
+
+ ret = fwnode_property_get_reference_args(dev_fwnode(priv->dev), "spk-id-gpios",
+ NULL, 3, 0, &args);
+ if (ret)
+ return ERR_PTR(ret);
+
+ struct fwnode_handle *fwnode __free(fwnode_handle) = args.fwnode;
+
+ if (args.nargs < 3)
+ return ERR_PTR(-EINVAL);
+
+ if (overflows_type(args.args[0], mapping->params[0].crs_entry_index))
+ return ERR_PTR(-EOVERFLOW);
+
+ adev = to_acpi_device_node(fwnode);
+ if (!adev)
+ return ERR_PTR(-EINVAL);
+
+ for (i = 0; i < ARRAY_SIZE(mapping->params); i++) {
+ mapping->params[i].crs_entry_index = args.args[0];
+ mapping->params[i].line_index = i;
+ mapping->params[i].active_low = !!args.args[2];
+ }
+
+ mapping->mappings[0] = (struct acpi_gpio_mapping) {
+ .name = "spk-id-gpios",
+ .data = mapping->params,
+ .size = ARRAY_SIZE(mapping->params),
+ };
+
+ ret = acpi_dev_add_driver_gpios(adev, mapping->mappings);
+ if (ret)
+ return ERR_PTR(ret);
+
+ mapping->fwnode = no_free_ptr(fwnode);
+
+ return no_free_ptr(mapping);
+}
+
+static void cs42l43_remove_speaker_id_gpio_mapping(struct cs42l43_spk_id_gpio_mapping *mapping)
+{
+ if (!mapping)
+ return;
+
+ if (mapping->fwnode) {
+ acpi_dev_remove_driver_gpios(to_acpi_device_node(mapping->fwnode));
+ fwnode_handle_put(mapping->fwnode);
+ }
+
+ kfree(mapping);
+}
+
+static int cs42l43_get_speaker_id_gpios(struct cs42l43_spi *priv, int *result)
+{
+ struct fwnode_handle *gpio_fwnode = dev_fwnode(priv->dev);
+ struct cs42l43_spk_id_gpio_mapping *mapping = NULL;
+ struct gpio_desc *desc;
+ u32 spkid = 0;
+ int i, ret = 0;
+
+ if (is_acpi_node(gpio_fwnode)) {
+ mapping = cs42l43_add_speaker_id_gpio_mapping(priv);
+ if (IS_ERR(mapping)) {
+ ret = PTR_ERR(mapping);
+ if (ret == -ENOENT)
+ return 0;
+
+ return ret;
+ }
+
+ gpio_fwnode = mapping->fwnode;
+ }
+
+ for (i = 0; i < CS42L43_MAX_SPK_ID_GPIOS; i++) {
+ desc = fwnode_gpiod_get_index(gpio_fwnode, "spk-id", i, GPIOD_IN,
+ dev_name(priv->dev));
+ if (IS_ERR(desc)) {
+ ret = PTR_ERR(desc);
+ if (ret == -ENOENT)
+ break;
+
+ goto out;
+ }
+
+ ret = gpiod_get_value_cansleep(desc);
+ gpiod_put(desc);
if (ret < 0)
- goto err;
+ goto out;
- spkid |= (ret << i);
+ spkid |= (u32)ret << i;
}
- dev_dbg(priv->dev, "spk-id-gpios = %d\n", spkid);
- *result = spkid;
-err:
- gpiod_put_array(descs);
+ if (i) {
+ dev_dbg(priv->dev, "spk-id-gpios = %u from %d GPIOs\n", spkid, i);
+ *result = spkid;
+ }
+
+ ret = 0;
+out:
+ cs42l43_remove_speaker_id_gpio_mapping(mapping);
return ret;
}
--
2.47.3
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-19 13:47 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-19 13:47 [PATCH] spi: cs42l43: Workaround for wrong speaker ID on Dell XPS 13 DX13260 Richard Fitzgerald
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®