Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save levihuayuzhang/6137ae4ae46301a355fd37c63e0d876a to your computer and use it in GitHub Desktop.
Save levihuayuzhang/6137ae4ae46301a355fd37c63e0d876a to your computer and use it in GitHub Desktop.
Workaround for Lenovo Thinkbook 16p Gen4 IRH sound issue (Should be fixed in Linux v6.8 or later)
From 86d1cc3e8e024c6776424f09108030fabe67cf5f Mon Sep 17 00:00:00 2001
From: Huayu Zhang <[email protected]>
Date: Thu, 11 Jan 2024 16:18:29 +0800
Subject: [PATCH] add _DSD for SSID 0x17aa38a9 and 38ab (ThinkBook 16p G4 IRH)
the dmseg has following output after patching:
[ 4.401426] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: Cirrus Logic CS35L41 (35a40), Revision: B2
[ 4.455038] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: Cirrus Logic CS35L41 (35a40), Revision: B2
[ 6.362589] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.0: CS35L41 Bound - SSID: 17AA38A9, BST: 1, VSPK: 1, CH: L, FW EN: 1, SPKID: 0
[ 6.862707] cs35l41-hda i2c-CSC3551:00-cs35l41-hda.1: CS35L41 Bound - SSID: 17AA38A9, BST: 1, VSPK: 1, CH: R, FW EN: 1, SPKID: 0
And the system volumn control only affect the upfacing speakers nor the
downfacing bass speakers.
Signed-off-by: Huayu Zhang <[email protected]>
---
sound/pci/hda/cs35l41_hda_property.c | 4 ++++
sound/pci/hda/patch_realtek.c | 2 ++
2 files changed, 6 insertions(+)
diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
index 35277ce890a4..30fb638f5240 100644
--- a/sound/pci/hda/cs35l41_hda_property.c
+++ b/sound/pci/hda/cs35l41_hda_property.c
@@ -93,6 +93,8 @@ static const struct cs35l41_config cs35l41_config_table[] = {
{ "10431F12", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
{ "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+ { "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+ { "17AA38AB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
{ "17AA38B4", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
{ "17AA38B5", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
{ "17AA38B6", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
@@ -427,6 +429,8 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
{ "CSC3551", "10431F12", generic_dsd_config },
{ "CSC3551", "10431F1F", generic_dsd_config },
{ "CSC3551", "10431F62", generic_dsd_config },
+ { "CSC3551", "17AA38A9", generic_dsd_config },
+ { "CSC3551", "17AA38AB", generic_dsd_config },
{ "CSC3551", "17AA38B4", generic_dsd_config },
{ "CSC3551", "17AA38B5", generic_dsd_config },
{ "CSC3551", "17AA38B6", generic_dsd_config },
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 1dcfba27e075..97388c170837 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -10256,6 +10256,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38a9, "ThinkBook 16p G4 IRH", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x17aa, 0x38ab, "ThinkBook 16p G4 IRH", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x38b4, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x38b5, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x38b6, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
--
2.34.1
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
index f7815ee24f83..93d86c5a9d53 100644
--- a/sound/pci/hda/cs35l41_hda.c
+++ b/sound/pci/hda/cs35l41_hda.c
@@ -1270,6 +1270,8 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
size_t nval;
int i, ret;
+ printk("CSC3551: probing %s\n", hid);
+
adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
if (!adev) {
dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid);
@@ -1287,8 +1289,9 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
property = "cirrus,dev-index";
ret = device_property_count_u32(physdev, property);
if (ret <= 0) {
- ret = cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid);
- goto err_put_physdev;
+ //ret = cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid);
+ //goto err_put_physdev;
+ goto no_acpi_dsd;
}
if (ret > ARRAY_SIZE(values)) {
ret = -EINVAL;
@@ -1383,6 +1386,92 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i
put_device(physdev);
return ret;
+
+no_acpi_dsd:
+ /*
+ * Device CLSA0100 doesn't have _DSD so a gpiod_get by the label reset won't work.
+ * And devices created by i2c-multi-instantiate don't have their device struct pointing to
+ * the correct fwnode, so acpi_dev must be used here.
+ * And devm functions expect that the device requesting the resource has the correct
+ * fwnode.
+ */
+
+ printk("CSC3551: no_acpi_dsd: %s\n", hid);
+
+ /* TODO: This is a hack. */
+ if (strncmp(hid, "CSC3551", 7) == 0) {
+ goto csc3551;
+ }
+
+ if (strncmp(hid, "CLSA0100", 8) != 0)
+ return -EINVAL;
+
+ /* check I2C address to assign the index */
+ cs35l41->index = id == 0x40 ? 0 : 1;
+ cs35l41->hw_cfg.spk_pos = cs35l41->index;
+ cs35l41->channel_index = 0;
+ cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+ cs35l41->hw_cfg.bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
+ hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN;
+ hw_cfg->gpio2.valid = true;
+ cs35l41->hw_cfg.valid = true;
+ put_device(physdev);
+
+ return 0;
+
+ csc3551:
+
+ printk("CSC3551: id == 0x%x\n", id);
+
+ // cirrus,dev-index
+ if(id == 0x40)
+ cs35l41->index = 0;
+ else
+ cs35l41->index = 1;
+
+ cs35l41->channel_index = 0;
+
+ cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, cs35l41->index, GPIOD_OUT_LOW);
+
+ printk("CS3551: reset_gpio == 0x%x\n", cs35l41->reset_gpio);
+
+ // cirrus,speaker-position
+ if(cs35l41->index == 0)
+ hw_cfg->spk_pos = 0;
+ else
+ hw_cfg->spk_pos = 1;
+
+ // cirrus,gpio1-func
+ hw_cfg->gpio1.func = 1;
+ hw_cfg->gpio1.valid = true;
+
+ // cirrus,gpio2-func
+ hw_cfg->gpio2.func = 0x02;
+ hw_cfg->gpio2.valid = true;
+
+ // cirrus,boost-peak-milliamp
+ hw_cfg->bst_ipk = -1;
+
+ // cirrus,boost-ind-nanohenry
+ hw_cfg->bst_ind = -1;
+
+ // cirrus,boost-cap-microfarad
+ hw_cfg->bst_cap = -1;
+
+ cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, nval, -1);
+
+ if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0)
+ hw_cfg->bst_type = CS35L41_INT_BOOST;
+ else
+ hw_cfg->bst_type = CS35L41_EXT_BOOST;
+
+ hw_cfg->valid = true;
+
+ put_device(physdev);
+
+ printk("CSC3551: Done.\n");
+
+ return 0;
}
int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index e103bb3693c0..8ec2b0f99d8c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -9734,6 +9734,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+ SND_PCI_QUIRK(0x17aa, 0x38a9, "Lenovo ThinkBook 16p Gen4 IRH", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
From 124161547483109cbb491a8e39d1b5ef0973cd80 Mon Sep 17 00:00:00 2001
From: Huayu Zhang <[email protected]>
Date: Mon, 9 Oct 2023 00:59:56 +0800
Subject: [PATCH] thinkbook 16p gen4 sound fix
---
sound/pci/hda/cs35l41_hda_property.c | 41 ++++++++++++++++++++++++++++
sound/pci/hda/patch_realtek.c | 1 +
2 files changed, 42 insertions(+)
diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
index b62a4e6968e2..af359fbeb671 100644
--- a/sound/pci/hda/cs35l41_hda_property.c
+++ b/sound/pci/hda/cs35l41_hda_property.c
@@ -74,6 +74,46 @@ static int hp_vision_acpi_fix(struct cs35l41_hda *cs35l41, struct device *physde
return 0;
}
+static int lenovo_thinkbook16pgen4_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+ const char *hid)
+{
+ struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+
+ dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);
+
+ printk("CSC3551: id == 0x%x\n", id);
+
+ // cirrus,dev-index
+ cs35l41->index = id == 0x40 ? 0 : 1;
+ cs35l41->channel_index = 0;
+
+ // cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, cs35l41->index, GPIOD_OUT_LOW);
+ cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+ printk("CS3551: reset_gpio == 0x%x\n", cs35l41->reset_gpio);
+
+ // cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, nval, -1);
+ cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
+
+ // cirrus,speaker-position
+ hw_cfg->spk_pos = cs35l41->index;
+
+ // cirrus,gpio1-func
+ hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
+ hw_cfg->gpio1.valid = true;
+
+ // cirrus,gpio2-func
+ hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+ hw_cfg->gpio2.valid = true;
+
+ hw_cfg->bst_type = CS35L41_EXT_BOOST;
+ hw_cfg->valid = true;
+
+ put_device(physdev);
+ printk("CSC3551: Done.\n");
+
+ return 0;
+}
+
struct cs35l41_prop_model {
const char *hid;
const char *ssid;
@@ -85,6 +125,7 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
{ "CLSA0100", NULL, lenovo_legion_no_acpi },
{ "CLSA0101", NULL, lenovo_legion_no_acpi },
{ "CSC3551", "103C89C6", hp_vision_acpi_fix },
+ { "CSC3551", "17AA38A9", lenovo_thinkbook16pgen4_no_acpi },
{}
};
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 751783f3a15c..fc884fdcec5f 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -10031,6 +10031,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C),
+ SND_PCI_QUIRK(0x17aa, 0x38a9, "Lenovo ThinkBook 16p Gen 4", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual", ALC287_FIXUP_TAS2781_I2C),
--
2.42.0
From b7cb3f0b49270d631362da5bab871e2e8910a073 Mon Sep 17 00:00:00 2001
From: Huayu Zhang <[email protected]>
Date: Sat, 13 Apr 2024 19:26:24 +0800
Subject: [PATCH] Fix volumn control of ThinkBook 16P Gen4
change HDA & AMP configuration from ALC287_FIXUP_CS35L41_I2C_2 to
ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD for ThinkBook 16P Gen4 models to fix volumn
control issue (cannot fully mute).
Signed-off-by: Huayu Zhang <[email protected]>
---
sound/pci/hda/patch_realtek.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index d6940bc4ec39..1aef223307bb 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -10396,8 +10396,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C),
SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C),
- SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_CS35L41_I2C_2),
- SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+ SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
SND_PCI_QUIRK(0x17aa, 0x38b4, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x38b5, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x17aa, 0x38b6, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
--
2.34.1
@levihuayuzhang
Copy link
Author

levihuayuzhang commented May 27, 2024

Hi Huayu, I have the same issue on my Thinkbook 16P 2024. After attempting the patch, my laptop no longer has kernel errors, but it seems that only the upper low-frequency speaker is working, while the lower high-frequency speaker is not working. Do you have any information or help regarding this?

看到兄弟的提交了。估计会排期解决的。加油。(有用Gen5型号的朋友可以去跟帖汇报哈)(可以关注linux sound邮件组,Cirrus的几位佬)
然后估计CS35L41的驱动已经写好了。兄弟可以考虑把没打patch的kernel报错给发一下,alsa-info好像看不到amp型号,还有acpidump的输出可以重定向为文本,发给Bugzilla。(有可能是其他型号的amp,新型号或其他厂家的(比如德州仪器之类的))。

我刚刚跟新了bug的描述。希望能被大佬看到。在我电脑上6.8的内核,低频的Speaker是有声音的不过超级小,高频的Speaker不work

那应该就是cs35l41了。估计是配置问题。我当时就是上边音量还可以,并且可以调整大小。下面也有声音,但小,且无法和上方一起协同调整音量。这种情况就是解码器可以解码,amp也在工作,但估计之间的连接配置没写对。

我当时是试了几个不同的配置,其中一个刚好可以用。有几个配置在sound/pci/hda/patch_realtek.c里是写好的(可以ctrl+f搜搜看)。不过也可以在邮件组问问Stefan,之前都是这位大佬在对接这个芯片的相关事项。(如果确实是配置的问题,之前 Stefan说要去找Realtek的人问,或者自己尝试用已有的配置or自己写😂)。祝顺利。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment