ALSA: hda/tas2781: Add speaker id check for ASUS projects

Add speaker id check by gpio in ACPI for ASUS projects.
In other vendors, speaker id was checked by BIOS, and was applied in
last bit of subsys id, so we can load corresponding firmware binary file
for its speaker by subsys id.
But in ASUS project, the firmware binary name will be appended an extra
number to tell the speakers from different vendors. And this single digit
come from gpio level of speaker id in BIOS.

Signed-off-by: Baojun Xu <baojun.xu@ti.com>
Link: https://patch.msgid.link/20241123073718.475-1-baojun.xu@ti.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Baojun Xu 2024-11-23 15:37:18 +08:00 committed by Takashi Iwai
parent 1fd50509fe
commit 4e7035a75d
2 changed files with 60 additions and 4 deletions

View File

@ -156,6 +156,7 @@ struct tasdevice_priv {
struct tasdevice_rca rcabin; struct tasdevice_rca rcabin;
struct calidata cali_data; struct calidata cali_data;
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;

View File

@ -16,6 +16,7 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mod_devicetable.h> #include <linux/mod_devicetable.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/pci_ids.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <sound/hda_codec.h> #include <sound/hda_codec.h>
@ -110,10 +111,20 @@ static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
return 1; return 1;
} }
static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false };
static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {
{ "speakerid-gpios", &speakerid_gpios, 1 },
{ }
};
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 acpi_device *adev; struct acpi_device *adev;
struct device *physdev;
LIST_HEAD(resources); LIST_HEAD(resources);
const char *sub;
uint32_t subid;
int ret; int ret;
adev = acpi_dev_get_first_match_dev(hid, NULL, -1); adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
@ -123,18 +134,45 @@ static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
return -ENODEV; return -ENODEV;
} }
physdev = get_device(acpi_get_first_physical_node(adev));
ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p); ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);
if (ret < 0) if (ret < 0) {
dev_err(p->dev, "Failed to get ACPI resource.\n");
goto err; goto err;
}
sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
if (IS_ERR(sub)) {
dev_err(p->dev, "Failed to get SUBSYS ID.\n");
goto err;
}
/* 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)
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;
}
} else {
p->speaker_id = NULL;
}
acpi_dev_free_resource_list(&resources); acpi_dev_free_resource_list(&resources);
strscpy(p->dev_name, hid, sizeof(p->dev_name)); strscpy(p->dev_name, hid, sizeof(p->dev_name));
put_device(physdev);
acpi_dev_put(adev); acpi_dev_put(adev);
return 0; return 0;
err: err:
dev_err(p->dev, "read acpi error, ret: %d\n", ret); dev_err(p->dev, "read acpi error, ret: %d\n", ret);
put_device(physdev);
acpi_dev_put(adev); acpi_dev_put(adev);
return ret; return ret;
@ -615,7 +653,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
struct tasdevice_priv *tas_priv = context; struct tasdevice_priv *tas_priv = context;
struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
struct hda_codec *codec = tas_priv->codec; struct hda_codec *codec = tas_priv->codec;
int i, ret; int i, ret, spk_id;
pm_runtime_get_sync(tas_priv->dev); pm_runtime_get_sync(tas_priv->dev);
mutex_lock(&tas_priv->codec_lock); mutex_lock(&tas_priv->codec_lock);
@ -648,8 +686,25 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
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;
scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X.bin", if (tas_priv->speaker_id != NULL) {
codec->core.subsystem_id & 0xffff); // 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,
sizeof(tas_priv->coef_binaryname),
"TAS2XXX%04X%d.bin",
lower_16_bits(codec->core.subsystem_id),
spk_id);
} else {
snprintf(tas_priv->coef_binaryname,
sizeof(tas_priv->coef_binaryname),
"TAS2XXX%04X.bin",
lower_16_bits(codec->core.subsystem_id));
}
ret = tasdevice_dsp_parser(tas_priv); ret = tasdevice_dsp_parser(tas_priv);
if (ret) { if (ret) {
dev_err(tas_priv->dev, "dspfw load %s error\n", dev_err(tas_priv->dev, "dspfw load %s error\n",