diff options
| author | Antheas Kapenekakis <lkml@antheas.dev> | 2025-10-26 20:16:34 +0100 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2025-12-18 14:03:42 +0100 |
| commit | 3646c928bb77c28bd79f8e1893d32db49230b657 (patch) | |
| tree | 38d6a2abc6fa8c8f9abd24cabc78d43b4b77d76e /sound | |
| parent | acacb5b7109acb83b6154b4654acdbec6aa5f54f (diff) | |
| download | linux-3646c928bb77c28bd79f8e1893d32db49230b657.tar.gz linux-3646c928bb77c28bd79f8e1893d32db49230b657.tar.bz2 linux-3646c928bb77c28bd79f8e1893d32db49230b657.zip | |
ALSA: hda/tas2781: fix speaker id retrieval for multiple probes
commit 945865a0ddf3e3950aea32e23e10d815ee9b21bc upstream.
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@vger.kernel.org # 6.17
Signed-off-by: Antheas Kapenekakis <lkml@antheas.dev>
Reviewed-by: Baojun Xu <baojun.xu@ti.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20251026191635.2447593-1-lkml@antheas.dev
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'sound')
| -rw-r--r-- | sound/hda/codecs/side-codecs/tas2781_hda_i2c.c | 44 |
1 files changed, 25 insertions, 19 deletions
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), |
