mirror of
https://github.com/torvalds/linux.git
synced 2026-06-01 02:53:36 +02:00
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: 4e7035a75d ("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
This commit is contained in:
parent
9c3af1b2f7
commit
945865a0dd
|
|
@ -197,7 +197,6 @@ struct tasdevice_priv {
|
||||||
struct acoustic_data acou_data;
|
struct acoustic_data acou_data;
|
||||||
#endif
|
#endif
|
||||||
struct tasdevice_fw *fmw;
|
struct tasdevice_fw *fmw;
|
||||||
struct gpio_desc *speaker_id;
|
|
||||||
struct gpio_desc *reset;
|
struct gpio_desc *reset;
|
||||||
struct mutex codec_lock;
|
struct mutex codec_lock;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
|
|
@ -215,6 +214,7 @@ struct tasdevice_priv {
|
||||||
unsigned int magic_num;
|
unsigned int magic_num;
|
||||||
unsigned int chip_id;
|
unsigned int chip_id;
|
||||||
unsigned int sysclk;
|
unsigned int sysclk;
|
||||||
|
int speaker_id;
|
||||||
|
|
||||||
int irq;
|
int irq;
|
||||||
int cur_prog;
|
int cur_prog;
|
||||||
|
|
|
||||||
|
|
@ -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)
|
static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
|
||||||
{
|
{
|
||||||
|
struct gpio_desc *speaker_id;
|
||||||
struct acpi_device *adev;
|
struct acpi_device *adev;
|
||||||
struct device *physdev;
|
struct device *physdev;
|
||||||
LIST_HEAD(resources);
|
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. */
|
/* Speaker id was needed for ASUS projects. */
|
||||||
ret = kstrtou32(sub, 16, &subid);
|
ret = kstrtou32(sub, 16, &subid);
|
||||||
if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
|
if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
|
||||||
ret = devm_acpi_dev_add_driver_gpios(p->dev,
|
ret = acpi_dev_add_driver_gpios(adev, tas2781_speaker_id_gpios);
|
||||||
tas2781_speaker_id_gpios);
|
if (ret < 0) {
|
||||||
if (ret < 0)
|
|
||||||
dev_err(p->dev, "Failed to add driver gpio %d.\n",
|
dev_err(p->dev, "Failed to add driver gpio %d.\n",
|
||||||
ret);
|
ret);
|
||||||
p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN);
|
p->speaker_id = -1;
|
||||||
if (IS_ERR(p->speaker_id)) {
|
goto end_2563;
|
||||||
dev_err(p->dev, "Failed to get Speaker id.\n");
|
|
||||||
ret = PTR_ERR(p->speaker_id);
|
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
p->speaker_id = NULL;
|
p->speaker_id = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
end_2563:
|
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 *tas_hda = dev_get_drvdata(tas_priv->dev);
|
||||||
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
|
struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
|
||||||
struct hda_codec *codec = tas_priv->codec;
|
struct hda_codec *codec = tas_priv->codec;
|
||||||
int ret, spk_id;
|
int ret;
|
||||||
|
|
||||||
tasdevice_dsp_remove(tas_priv);
|
tasdevice_dsp_remove(tas_priv);
|
||||||
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
|
tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
|
||||||
if (tas_priv->speaker_id != NULL) {
|
if (tas_priv->speaker_id >= 0) {
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
snprintf(tas_priv->coef_binaryname,
|
snprintf(tas_priv->coef_binaryname,
|
||||||
sizeof(tas_priv->coef_binaryname),
|
sizeof(tas_priv->coef_binaryname),
|
||||||
"TAS2XXX%04X%d.bin",
|
"TAS2XXX%04X%d.bin",
|
||||||
lower_16_bits(codec->core.subsystem_id),
|
lower_16_bits(codec->core.subsystem_id),
|
||||||
spk_id);
|
tas_priv->speaker_id);
|
||||||
} else {
|
} else {
|
||||||
snprintf(tas_priv->coef_binaryname,
|
snprintf(tas_priv->coef_binaryname,
|
||||||
sizeof(tas_priv->coef_binaryname),
|
sizeof(tas_priv->coef_binaryname),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user