Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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@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

authored by

Antheas Kapenekakis and committed by
Takashi Iwai
945865a0 9c3af1b2

+26 -20
+1 -1
include/sound/tas2781.h
··· 197 197 struct acoustic_data acou_data; 198 198 #endif 199 199 struct tasdevice_fw *fmw; 200 - struct gpio_desc *speaker_id; 201 200 struct gpio_desc *reset; 202 201 struct mutex codec_lock; 203 202 struct regmap *regmap; ··· 214 215 unsigned int magic_num; 215 216 unsigned int chip_id; 216 217 unsigned int sysclk; 218 + int speaker_id; 217 219 218 220 int irq; 219 221 int cur_prog;
+25 -19
sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
··· 87 87 88 88 static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) 89 89 { 90 + struct gpio_desc *speaker_id; 90 91 struct acpi_device *adev; 91 92 struct device *physdev; 92 93 LIST_HEAD(resources); ··· 120 119 /* Speaker id was needed for ASUS projects. */ 121 120 ret = kstrtou32(sub, 16, &subid); 122 121 if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) { 123 - ret = devm_acpi_dev_add_driver_gpios(p->dev, 124 - tas2781_speaker_id_gpios); 125 - if (ret < 0) 122 + ret = acpi_dev_add_driver_gpios(adev, tas2781_speaker_id_gpios); 123 + if (ret < 0) { 126 124 dev_err(p->dev, "Failed to add driver gpio %d.\n", 127 125 ret); 128 - p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN); 129 - if (IS_ERR(p->speaker_id)) { 130 - dev_err(p->dev, "Failed to get Speaker id.\n"); 131 - ret = PTR_ERR(p->speaker_id); 132 - goto err; 126 + p->speaker_id = -1; 127 + goto end_2563; 133 128 } 129 + 130 + speaker_id = fwnode_gpiod_get_index(acpi_fwnode_handle(adev), 131 + "speakerid", 0, GPIOD_IN, NULL); 132 + if (!IS_ERR(speaker_id)) { 133 + p->speaker_id = gpiod_get_value_cansleep(speaker_id); 134 + dev_dbg(p->dev, "Got speaker id gpio from ACPI: %d.\n", 135 + p->speaker_id); 136 + gpiod_put(speaker_id); 137 + } else { 138 + p->speaker_id = -1; 139 + ret = PTR_ERR(speaker_id); 140 + dev_err(p->dev, "Get speaker id gpio failed %d.\n", 141 + ret); 142 + } 143 + 144 + acpi_dev_remove_driver_gpios(adev); 134 145 } else { 135 - p->speaker_id = NULL; 146 + p->speaker_id = -1; 136 147 } 137 148 138 149 end_2563: ··· 445 432 struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); 446 433 struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv; 447 434 struct hda_codec *codec = tas_priv->codec; 448 - int ret, spk_id; 435 + int ret; 449 436 450 437 tasdevice_dsp_remove(tas_priv); 451 438 tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; 452 - if (tas_priv->speaker_id != NULL) { 453 - // Speaker id need to be checked for ASUS only. 454 - spk_id = gpiod_get_value(tas_priv->speaker_id); 455 - if (spk_id < 0) { 456 - // Speaker id is not valid, use default. 457 - dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id); 458 - spk_id = 0; 459 - } 439 + if (tas_priv->speaker_id >= 0) { 460 440 snprintf(tas_priv->coef_binaryname, 461 441 sizeof(tas_priv->coef_binaryname), 462 442 "TAS2XXX%04X%d.bin", 463 443 lower_16_bits(codec->core.subsystem_id), 464 - spk_id); 444 + tas_priv->speaker_id); 465 445 } else { 466 446 snprintf(tas_priv->coef_binaryname, 467 447 sizeof(tas_priv->coef_binaryname),