diff --git a/include/sound/tas2781.h b/include/sound/tas2781.h index 8cd6da0480b7..72d2060904f6 100644 --- a/include/sound/tas2781.h +++ b/include/sound/tas2781.h @@ -156,6 +156,7 @@ struct tasdevice_priv { struct tasdevice_rca rcabin; struct calidata cali_data; struct tasdevice_fw *fmw; + struct gpio_desc *speaker_id; struct gpio_desc *reset; struct mutex codec_lock; struct regmap *regmap; diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 370d847517f9..45cfb5a6f309 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -110,10 +111,20 @@ static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) 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) { struct acpi_device *adev; + struct device *physdev; LIST_HEAD(resources); + const char *sub; + uint32_t subid; int ret; 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; } + physdev = get_device(acpi_get_first_physical_node(adev)); 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; + } + 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); strscpy(p->dev_name, hid, sizeof(p->dev_name)); + put_device(physdev); acpi_dev_put(adev); return 0; err: dev_err(p->dev, "read acpi error, ret: %d\n", ret); + put_device(physdev); acpi_dev_put(adev); return ret; @@ -615,7 +653,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) struct tasdevice_priv *tas_priv = context; struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); struct hda_codec *codec = tas_priv->codec; - int i, ret; + int i, ret, spk_id; pm_runtime_get_sync(tas_priv->dev); 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); tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; - scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X.bin", - codec->core.subsystem_id & 0xffff); + 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; + } + 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); if (ret) { dev_err(tas_priv->dev, "dspfw load %s error\n",