[PATCH v2 0/4] Add support for CLSA0101
Add Support for the CLSA0101 laptop, an Intel version of CLSA0100. This patch has been tested using the CLSA0100, ensuring it doesn't break the sound for it. We appreciate it if someone with CLSA0101 could verify that this the patch works for them.
Changes from V1: - Add CLSA0101 id into scan.c, serial-multi-instantiate.c and cs35l41_hda_i2c.c
Lucas Tanure (4): ALSA: hda: cs35l41: Use the CS35L41 HDA internal define ALSA: hda: cs35l41: Support CLSA0101 ACPI: scan: Add CLSA0101 Laptop Support platform/x86: serial-multi-instantiate: Add CLSA0101 Laptop
drivers/acpi/scan.c | 1 + .../platform/x86/serial-multi-instantiate.c | 1 + sound/pci/hda/cs35l41_hda.c | 67 ++++++++++++------- sound/pci/hda/cs35l41_hda_i2c.c | 3 + sound/pci/hda/patch_realtek.c | 12 ++++ 5 files changed, 58 insertions(+), 26 deletions(-)
Follow GPIO1 pattern, use cs35l41 HDA internal define for IRQ and then translate to ASoC cs35l41 define.
Signed-off-by: Lucas Tanure tanureal@opensource.cirrus.com --- sound/pci/hda/cs35l41_hda.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 28798d5c1cf1..48d94c683b75 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1014,6 +1014,7 @@ static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41) break; case CS35L41_INTERRUPT: using_irq = true; + hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN; break; default: dev_err(cs35l41->dev, "Invalid GPIO2 function %d\n", hw_cfg->gpio2.func); @@ -1273,7 +1274,7 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH); cs35l41->hw_cfg.bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH; cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2); - hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN; + hw_cfg->gpio2.func = CS35L41_INTERRUPT; hw_cfg->gpio2.valid = true; cs35l41->hw_cfg.valid = true; put_device(physdev);
Add support for Intel version of Legion 7 laptop.
Signed-off-by: Lucas Tanure tanureal@opensource.cirrus.com --- sound/pci/hda/cs35l41_hda.c | 66 ++++++++++++++++++++------------- sound/pci/hda/cs35l41_hda_i2c.c | 3 ++ sound/pci/hda/patch_realtek.c | 12 ++++++ 3 files changed, 55 insertions(+), 26 deletions(-)
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c index 48d94c683b75..6edf95553745 100644 --- a/sound/pci/hda/cs35l41_hda.c +++ b/sound/pci/hda/cs35l41_hda.c @@ -1133,6 +1133,45 @@ static int cs35l41_get_speaker_id(struct device *dev, int amp_index, return speaker_id; }
+/* + * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work. + * And devices created by serial-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. + */ +static int cs35l41_no_acpi_dsd(struct cs35l41_hda *cs35l41, struct device *physdev, int id, + const char *hid) +{ + struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; + + /* check I2C address to assign the index */ + cs35l41->index = id == 0x40 ? 0 : 1; + cs35l41->channel_index = 0; + cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH); + cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2); + hw_cfg->spk_pos = cs35l41->index; + hw_cfg->gpio2.func = CS35L41_INTERRUPT; + hw_cfg->gpio2.valid = true; + hw_cfg->valid = true; + put_device(physdev); + + if (strncmp(hid, "CLSA0100", 8) == 0) { + hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH; + } else if (strncmp(hid, "CLSA0101", 8) == 0) { + hw_cfg->bst_type = CS35L41_EXT_BOOST; + hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH; + hw_cfg->gpio1.valid = true; + } else { + hw_cfg->valid = false; + hw_cfg->gpio1.valid = false; + hw_cfg->gpio2.valid = false; + return -EINVAL; + } + + return 0; +} + static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id) { struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg; @@ -1161,7 +1200,7 @@ 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) - goto no_acpi_dsd; + return cs35l41_no_acpi_dsd(cs35l41, physdev, id, hid);
if (ret > ARRAY_SIZE(values)) { ret = -EINVAL; @@ -1255,31 +1294,6 @@ static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, i dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
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 serial-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. - */ - 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; - cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2); - hw_cfg->gpio2.func = CS35L41_INTERRUPT; - hw_cfg->gpio2.valid = true; - cs35l41->hw_cfg.valid = true; - put_device(physdev); - - return 0; }
int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq, diff --git a/sound/pci/hda/cs35l41_hda_i2c.c b/sound/pci/hda/cs35l41_hda_i2c.c index 9c08fa08c421..5baacfde4f16 100644 --- a/sound/pci/hda/cs35l41_hda_i2c.c +++ b/sound/pci/hda/cs35l41_hda_i2c.c @@ -22,6 +22,8 @@ static int cs35l41_hda_i2c_probe(struct i2c_client *clt, const struct i2c_device */ if (strstr(dev_name(&clt->dev), "CLSA0100")) device_name = "CLSA0100"; + else if (strstr(dev_name(&clt->dev), "CLSA0101")) + device_name = "CLSA0101"; else if (strstr(dev_name(&clt->dev), "CSC3551")) device_name = "CSC3551"; else @@ -45,6 +47,7 @@ static const struct i2c_device_id cs35l41_hda_i2c_id[] = {
static const struct acpi_device_id cs35l41_acpi_hda_match[] = { {"CLSA0100", 0 }, + {"CLSA0101", 0 }, {"CSC3551", 0 }, {} }; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0e340c0934db..65fd3e599a83 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6710,6 +6710,12 @@ static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const st cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0100", 2); }
+static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix, + int action) +{ + cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0101", 2); +} + /* for alc295_fixup_hp_top_speakers */ #include "hp_x360_helper.c"
@@ -7047,6 +7053,7 @@ enum { ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED, ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED, ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE, + ALC287_FIXUP_LEGION_16ITHG6, };
/* A special fixup for Lenovo C940 and Yoga Duet 7; @@ -8889,6 +8896,10 @@ static const struct hda_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC }, + [ALC287_FIXUP_LEGION_16ITHG6] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc287_fixup_legion_16ithg6_speakers, + }, };
static const struct snd_pci_quirk alc269_fixup_tbl[] = { @@ -9353,6 +9364,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x384a, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS), 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, 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),
Add CLSA0101 id to the ignore_serial_bus_ids so serial-multi-instantiate can correctly instantiate the driver.
Signed-off-by: Lucas Tanure tanureal@opensource.cirrus.com --- drivers/acpi/scan.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b100e6ca9bb4..42cec8120f18 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1722,6 +1722,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device) {"INT3515", }, /* Non-conforming _HID for Cirrus Logic already released */ {"CLSA0100", }, + {"CLSA0101", }, /* * Some ACPI devs contain SerialBus resources even though they are not * attached to a serial bus at all.
The device CLSA0101 has two instances of CS35L41 connected by I2C.
Signed-off-by: Lucas Tanure tanureal@opensource.cirrus.com --- drivers/platform/x86/serial-multi-instantiate.c | 1 + 1 file changed, 1 insertion(+)
diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c index 67feed25c9db..5362f1a7b77c 100644 --- a/drivers/platform/x86/serial-multi-instantiate.c +++ b/drivers/platform/x86/serial-multi-instantiate.c @@ -328,6 +328,7 @@ static const struct acpi_device_id smi_acpi_ids[] = { { "INT3515", (unsigned long)&int3515_data }, /* Non-conforming _HID for Cirrus Logic already released */ { "CLSA0100", (unsigned long)&cs35l41_hda }, + { "CLSA0101", (unsigned long)&cs35l41_hda }, { } }; MODULE_DEVICE_TABLE(acpi, smi_acpi_ids);
Sound works as expected with this patch.
Sound fails after resume from sleep & hibernate, but as mentioned by Lucas in another email, this is currently expected, and will be fixed in a patch for a separate issue.
This is arguably better than the old behavior where we only saw right channel sound from the left speaker. I say merge it.
Thanks, Lucas!
-Cameron
On 7/27/22 02:59, Lucas Tanure wrote:
Add Support for the CLSA0101 laptop, an Intel version of CLSA0100. This patch has been tested using the CLSA0100, ensuring it doesn't break the sound for it. We appreciate it if someone with CLSA0101 could verify that this the patch works for them.
Changes from V1:
- Add CLSA0101 id into scan.c, serial-multi-instantiate.c
and cs35l41_hda_i2c.c
Lucas Tanure (4): ALSA: hda: cs35l41: Use the CS35L41 HDA internal define ALSA: hda: cs35l41: Support CLSA0101 ACPI: scan: Add CLSA0101 Laptop Support platform/x86: serial-multi-instantiate: Add CLSA0101 Laptop
drivers/acpi/scan.c | 1 + .../platform/x86/serial-multi-instantiate.c | 1 + sound/pci/hda/cs35l41_hda.c | 67 ++++++++++++------- sound/pci/hda/cs35l41_hda_i2c.c | 3 + sound/pci/hda/patch_realtek.c | 12 ++++ 5 files changed, 58 insertions(+), 26 deletions(-)
On Wed, 27 Jul 2022 11:59:20 +0200, Lucas Tanure wrote:
Add Support for the CLSA0101 laptop, an Intel version of CLSA0100. This patch has been tested using the CLSA0100, ensuring it doesn't break the sound for it. We appreciate it if someone with CLSA0101 could verify that this the patch works for them.
Changes from V1:
- Add CLSA0101 id into scan.c, serial-multi-instantiate.c
and cs35l41_hda_i2c.c
Lucas Tanure (4): ALSA: hda: cs35l41: Use the CS35L41 HDA internal define ALSA: hda: cs35l41: Support CLSA0101 ACPI: scan: Add CLSA0101 Laptop Support platform/x86: serial-multi-instantiate: Add CLSA0101 Laptop
Applied all four patches now. Thanks.
Takashi
participants (3)
-
Cameron Berkenpas
-
Lucas Tanure
-
Takashi Iwai