[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251026191635.2447593-1-lkml@antheas.dev>
Date: Sun, 26 Oct 2025 20:16:34 +0100
From: Antheas Kapenekakis <lkml@...heas.dev>
To: Shenghao Ding <shenghao-ding@...com>,
Baojun Xu <baojun.xu@...com>
Cc: Takashi Iwai <tiwai@...e.com>,
linux-sound@...r.kernel.org,
linux-kernel@...r.kernel.org,
Antheas Kapenekakis <lkml@...heas.dev>,
stable@...r.kernel.org
Subject: [PATCH v1 1/2] ALSA: hda/tas2781: fix speaker id retrieval for
multiple probes
Currently, on ASUS projects, the TAS2781 codec attaches the speaker GPIO
to the first tasdevice_priv instance using devm. This causes
tas2781_read_acpi to fail on subsequent probes since the GPIO is already
managed by the first device. This causes a failure on Xbox Ally X,
because it has two amplifiers, and prevents us from quirking both the
Xbox Ally and Xbox Ally X in the realtek codec driver.
It is unnecessary to attach the GPIO to a device as it is static.
Therefore, instead of attaching it and then reading it when loading the
firmware, read its value directly in tas2781_read_acpi and store it in
the private data structure. Then, make reading the value non-fatal so
that ASUS projects that miss a speaker pin can still work, perhaps using
fallback firmware.
Fixes: 4e7035a75da9 ("ALSA: hda/tas2781: Add speaker id check for ASUS projects")
Cc: stable@...r.kernel.org # 6.17
Signed-off-by: Antheas Kapenekakis <lkml@...heas.dev>
---
include/sound/tas2781.h | 2 +-
.../hda/codecs/side-codecs/tas2781_hda_i2c.c | 44 +++++++++++--------
2 files changed, 26 insertions(+), 20 deletions(-)
diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h
index 0fbcdb15c74b..29d15ba65f04 100644
--- a/include/sound/tas2781.h
+++ b/include/sound/tas2781.h
@@ -197,7 +197,6 @@ struct tasdevice_priv {
struct acoustic_data acou_data;
#endif
struct tasdevice_fw *fmw;
- struct gpio_desc *speaker_id;
struct gpio_desc *reset;
struct mutex codec_lock;
struct regmap *regmap;
@@ -215,6 +214,7 @@ struct tasdevice_priv {
unsigned int magic_num;
unsigned int chip_id;
unsigned int sysclk;
+ int speaker_id;
int irq;
int cur_prog;
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
index 0357401a6023..c8619995b1d7 100644
--- a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
+++ b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
@@ -87,6 +87,7 @@ static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {
static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
{
+ struct gpio_desc *speaker_id;
struct acpi_device *adev;
struct device *physdev;
LIST_HEAD(resources);
@@ -119,19 +120,31 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
/* Speaker id was needed for ASUS projects. */
ret = kstrtou32(sub, 16, &subid);
if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
- ret = devm_acpi_dev_add_driver_gpios(p->dev,
- tas2781_speaker_id_gpios);
- if (ret < 0)
+ ret = acpi_dev_add_driver_gpios(adev, tas2781_speaker_id_gpios);
+ if (ret < 0) {
dev_err(p->dev, "Failed to add driver gpio %d.\n",
ret);
- p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN);
- if (IS_ERR(p->speaker_id)) {
- dev_err(p->dev, "Failed to get Speaker id.\n");
- ret = PTR_ERR(p->speaker_id);
- goto err;
+ p->speaker_id = -1;
+ goto end_2563;
+ }
+
+ speaker_id = fwnode_gpiod_get_index(acpi_fwnode_handle(adev),
+ "speakerid", 0, GPIOD_IN, NULL);
+ if (!IS_ERR(speaker_id)) {
+ p->speaker_id = gpiod_get_value_cansleep(speaker_id);
+ dev_dbg(p->dev, "Got speaker id gpio from ACPI: %d.\n",
+ p->speaker_id);
+ gpiod_put(speaker_id);
+ } else {
+ p->speaker_id = -1;
+ ret = PTR_ERR(speaker_id);
+ dev_err(p->dev, "Get speaker id gpio failed %d.\n",
+ ret);
}
+
+ acpi_dev_remove_driver_gpios(adev);
} else {
- p->speaker_id = NULL;
+ p->speaker_id = -1;
}
end_2563:
@@ -432,23 +445,16 @@ static void tasdevice_dspfw_init(void *context)
struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
struct hda_codec *codec = tas_priv->codec;
- int ret, spk_id;
+ int ret;
tasdevice_dsp_remove(tas_priv);
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
- if (tas_priv->speaker_id != NULL) {
- // Speaker id need to be checked for ASUS only.
- spk_id = gpiod_get_value(tas_priv->speaker_id);
- if (spk_id < 0) {
- // Speaker id is not valid, use default.
- dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id);
- spk_id = 0;
- }
+ if (tas_priv->speaker_id >= 0) {
snprintf(tas_priv->coef_binaryname,
sizeof(tas_priv->coef_binaryname),
"TAS2XXX%04X%d.bin",
lower_16_bits(codec->core.subsystem_id),
- spk_id);
+ tas_priv->speaker_id);
} else {
snprintf(tas_priv->coef_binaryname,
sizeof(tas_priv->coef_binaryname),
base-commit: 211ddde0823f1442e4ad052a2f30f050145ccada
--
2.51.1
Powered by blists - more mailing lists