Skip to content

Commit 3646c92

Browse files
antheasgregkh
authored andcommitted
ALSA: hda/tas2781: fix speaker id retrieval for multiple probes
commit 945865a 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: 4e7035a ("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>
1 parent acacb5b commit 3646c92

2 files changed

Lines changed: 26 additions & 20 deletions

File tree

include/sound/tas2781.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,6 @@ struct tasdevice_priv {
197197
struct acoustic_data acou_data;
198198
#endif
199199
struct tasdevice_fw *fmw;
200-
struct gpio_desc *speaker_id;
201200
struct gpio_desc *reset;
202201
struct mutex codec_lock;
203202
struct regmap *regmap;
@@ -215,6 +214,7 @@ struct tasdevice_priv {
215214
unsigned int magic_num;
216215
unsigned int chip_id;
217216
unsigned int sysclk;
217+
int speaker_id;
218218

219219
int irq;
220220
int cur_prog;

sound/hda/codecs/side-codecs/tas2781_hda_i2c.c

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {
8787

8888
static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
8989
{
90+
struct gpio_desc *speaker_id;
9091
struct acpi_device *adev;
9192
struct device *physdev;
9293
LIST_HEAD(resources);
@@ -119,19 +120,31 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
119120
/* Speaker id was needed for ASUS projects. */
120121
ret = kstrtou32(sub, 16, &subid);
121122
if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
122-
ret = devm_acpi_dev_add_driver_gpios(p->dev,
123-
tas2781_speaker_id_gpios);
124-
if (ret < 0)
123+
ret = acpi_dev_add_driver_gpios(adev, tas2781_speaker_id_gpios);
124+
if (ret < 0) {
125125
dev_err(p->dev, "Failed to add driver gpio %d.\n",
126126
ret);
127-
p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN);
128-
if (IS_ERR(p->speaker_id)) {
129-
dev_err(p->dev, "Failed to get Speaker id.\n");
130-
ret = PTR_ERR(p->speaker_id);
131-
goto err;
127+
p->speaker_id = -1;
128+
goto end_2563;
129+
}
130+
131+
speaker_id = fwnode_gpiod_get_index(acpi_fwnode_handle(adev),
132+
"speakerid", 0, GPIOD_IN, NULL);
133+
if (!IS_ERR(speaker_id)) {
134+
p->speaker_id = gpiod_get_value_cansleep(speaker_id);
135+
dev_dbg(p->dev, "Got speaker id gpio from ACPI: %d.\n",
136+
p->speaker_id);
137+
gpiod_put(speaker_id);
138+
} else {
139+
p->speaker_id = -1;
140+
ret = PTR_ERR(speaker_id);
141+
dev_err(p->dev, "Get speaker id gpio failed %d.\n",
142+
ret);
132143
}
144+
145+
acpi_dev_remove_driver_gpios(adev);
133146
} else {
134-
p->speaker_id = NULL;
147+
p->speaker_id = -1;
135148
}
136149

137150
end_2563:
@@ -432,23 +445,16 @@ static void tasdevice_dspfw_init(void *context)
432445
struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
433446
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
434447
struct hda_codec *codec = tas_priv->codec;
435-
int ret, spk_id;
448+
int ret;
436449

437450
tasdevice_dsp_remove(tas_priv);
438451
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
439-
if (tas_priv->speaker_id != NULL) {
440-
// Speaker id need to be checked for ASUS only.
441-
spk_id = gpiod_get_value(tas_priv->speaker_id);
442-
if (spk_id < 0) {
443-
// Speaker id is not valid, use default.
444-
dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id);
445-
spk_id = 0;
446-
}
452+
if (tas_priv->speaker_id >= 0) {
447453
snprintf(tas_priv->coef_binaryname,
448454
sizeof(tas_priv->coef_binaryname),
449455
"TAS2XXX%04X%d.bin",
450456
lower_16_bits(codec->core.subsystem_id),
451-
spk_id);
457+
tas_priv->speaker_id);
452458
} else {
453459
snprintf(tas_priv->coef_binaryname,
454460
sizeof(tas_priv->coef_binaryname),

0 commit comments

Comments
 (0)