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

authored by

Baojun Xu and committed by
Takashi Iwai
4e7035a7 1fd50509

+60 -4
+1
include/sound/tas2781.h
··· 156 156 struct tasdevice_rca rcabin; 157 157 struct calidata cali_data; 158 158 struct tasdevice_fw *fmw; 159 + struct gpio_desc *speaker_id; 159 160 struct gpio_desc *reset; 160 161 struct mutex codec_lock; 161 162 struct regmap *regmap;
+59 -4
sound/pci/hda/tas2781_hda_i2c.c
··· 16 16 #include <linux/i2c.h> 17 17 #include <linux/mod_devicetable.h> 18 18 #include <linux/module.h> 19 + #include <linux/pci_ids.h> 19 20 #include <linux/pm_runtime.h> 20 21 #include <linux/regmap.h> 21 22 #include <sound/hda_codec.h> ··· 111 110 return 1; 112 111 } 113 112 113 + static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false }; 114 + 115 + static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = { 116 + { "speakerid-gpios", &speakerid_gpios, 1 }, 117 + { } 118 + }; 119 + 114 120 static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid) 115 121 { 116 122 struct acpi_device *adev; 123 + struct device *physdev; 117 124 LIST_HEAD(resources); 125 + const char *sub; 126 + uint32_t subid; 118 127 int ret; 119 128 120 129 adev = acpi_dev_get_first_match_dev(hid, NULL, -1); ··· 134 123 return -ENODEV; 135 124 } 136 125 126 + physdev = get_device(acpi_get_first_physical_node(adev)); 137 127 ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p); 138 - if (ret < 0) 128 + if (ret < 0) { 129 + dev_err(p->dev, "Failed to get ACPI resource.\n"); 139 130 goto err; 131 + } 132 + sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev)); 133 + if (IS_ERR(sub)) { 134 + dev_err(p->dev, "Failed to get SUBSYS ID.\n"); 135 + goto err; 136 + } 137 + /* Speaker id was needed for ASUS projects. */ 138 + ret = kstrtou32(sub, 16, &subid); 139 + if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) { 140 + ret = devm_acpi_dev_add_driver_gpios(p->dev, 141 + tas2781_speaker_id_gpios); 142 + if (ret < 0) 143 + dev_err(p->dev, "Failed to add driver gpio %d.\n", 144 + ret); 145 + p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN); 146 + if (IS_ERR(p->speaker_id)) { 147 + dev_err(p->dev, "Failed to get Speaker id.\n"); 148 + ret = PTR_ERR(p->speaker_id); 149 + goto err; 150 + } 151 + } else { 152 + p->speaker_id = NULL; 153 + } 140 154 141 155 acpi_dev_free_resource_list(&resources); 142 156 strscpy(p->dev_name, hid, sizeof(p->dev_name)); 157 + put_device(physdev); 143 158 acpi_dev_put(adev); 144 159 145 160 return 0; 146 161 147 162 err: 148 163 dev_err(p->dev, "read acpi error, ret: %d\n", ret); 164 + put_device(physdev); 149 165 acpi_dev_put(adev); 150 166 151 167 return ret; ··· 653 615 struct tasdevice_priv *tas_priv = context; 654 616 struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev); 655 617 struct hda_codec *codec = tas_priv->codec; 656 - int i, ret; 618 + int i, ret, spk_id; 657 619 658 620 pm_runtime_get_sync(tas_priv->dev); 659 621 mutex_lock(&tas_priv->codec_lock); ··· 686 648 tasdevice_dsp_remove(tas_priv); 687 649 688 650 tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; 689 - scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X.bin", 690 - codec->core.subsystem_id & 0xffff); 651 + if (tas_priv->speaker_id != NULL) { 652 + // Speaker id need to be checked for ASUS only. 653 + spk_id = gpiod_get_value(tas_priv->speaker_id); 654 + if (spk_id < 0) { 655 + // Speaker id is not valid, use default. 656 + dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id); 657 + spk_id = 0; 658 + } 659 + snprintf(tas_priv->coef_binaryname, 660 + sizeof(tas_priv->coef_binaryname), 661 + "TAS2XXX%04X%d.bin", 662 + lower_16_bits(codec->core.subsystem_id), 663 + spk_id); 664 + } else { 665 + snprintf(tas_priv->coef_binaryname, 666 + sizeof(tas_priv->coef_binaryname), 667 + "TAS2XXX%04X.bin", 668 + lower_16_bits(codec->core.subsystem_id)); 669 + } 691 670 ret = tasdevice_dsp_parser(tas_priv); 692 671 if (ret) { 693 672 dev_err(tas_priv->dev, "dspfw load %s error\n",