diff mbox series

ALSA: hda/realtek: Add support for new HP G12 laptops

Message ID 20240801151605.76347-1-simont@opensource.cirrus.com (mailing list archive)
State New, archived
Headers show
Series ALSA: hda/realtek: Add support for new HP G12 laptops | expand

Commit Message

Simon Trimmer Aug. 1, 2024, 3:16 p.m. UTC
Some of these laptop models have quirk IDs that are identical but have
different amplifier parts fitted, this difference is described in the
ACPI information.

The solution introduced for this product family can derive the required
component binding information from ACPI instead of hardcoding it,
supports the new variants of the CS35L56 being used and has generalized
naming that makes it applicable to other ALC+amp combinations.

Signed-off-by: Simon Trimmer <simont@opensource.cirrus.com>
---
 sound/pci/hda/patch_realtek.c | 99 +++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

Comments

Simon Trimmer Aug. 2, 2024, 10:54 a.m. UTC | #1
Hi Takashi,
We were thinking about the random kernel config builds overnight and
checking the bus header files the count functions don't properly define the
empty versions of the functions to avoid the need to #ifdef the code around
config options.

We'll fix that up and spin a v2
-Simon

> -----Original Message-----
> From: Simon Trimmer <simont@opensource.cirrus.com>
> Sent: Thursday, August 1, 2024 4:16 PM
> To: tiwai@suse.com
> Cc: linux-sound@vger.kernel.org; alsa-devel@alsa-project.org; linux-
> kernel@vger.kernel.org; patches@opensource.cirrus.com; Simon Trimmer
> <simont@opensource.cirrus.com>
> Subject: [PATCH] ALSA: hda/realtek: Add support for new HP G12 laptops
> 
> Some of these laptop models have quirk IDs that are identical but have
> different amplifier parts fitted, this difference is described in the
> ACPI information.
> 
> The solution introduced for this product family can derive the required
> component binding information from ACPI instead of hardcoding it,
> supports the new variants of the CS35L56 being used and has generalized
> naming that makes it applicable to other ALC+amp combinations.
> 
> Signed-off-by: Simon Trimmer <simont@opensource.cirrus.com>
> ---
>  sound/pci/hda/patch_realtek.c | 99
> +++++++++++++++++++++++++++++++++++
>  1 file changed, 99 insertions(+)
> 
> diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
> index 1645d21d422f..1a05c647f08c 100644
> --- a/sound/pci/hda/patch_realtek.c
> +++ b/sound/pci/hda/patch_realtek.c
> @@ -11,15 +11,18 @@
>   */
> 
>  #include <linux/acpi.h>
> +#include <linux/cleanup.h>
>  #include <linux/init.h>
>  #include <linux/delay.h>
>  #include <linux/slab.h>
>  #include <linux/pci.h>
>  #include <linux/dmi.h>
>  #include <linux/module.h>
> +#include <linux/i2c.h>
>  #include <linux/input.h>
>  #include <linux/leds.h>
>  #include <linux/ctype.h>
> +#include <linux/spi/spi.h>
>  #include <sound/core.h>
>  #include <sound/jack.h>
>  #include <sound/hda_codec.h>
> @@ -6856,6 +6859,86 @@ static void comp_generic_fixup(struct hda_codec
> *cdc, int action, const char *bu
>  	}
>  }
> 
> +static void cs35lxx_autodet_fixup(struct hda_codec *cdc,
> +				  const struct hda_fixup *fix,
> +				  int action)
> +{
> +	struct device *dev = hda_codec_dev(cdc);
> +	struct acpi_device *adev;
> +	struct fwnode_handle *fwnode __free(fwnode_handle) = NULL;
> +	const char *bus = NULL;
> +	static const struct {
> +		const char *hid;
> +		const char *name;
> +	} acpi_ids[] = {{ "CSC3554", "cs35l54-hda" },
> +			{ "CSC3556", "cs35l56-hda" },
> +			{ "CSC3557", "cs35l57-hda" }};
> +	char *match;
> +	int i, count = 0, count_devindex = 0;
> +
> +	switch (action) {
> +	case HDA_FIXUP_ACT_PRE_PROBE:
> +		for (i = 0; i < ARRAY_SIZE(acpi_ids); ++i) {
> +			adev = acpi_dev_get_first_match_dev(acpi_ids[i].hid,
> NULL, -1);
> +			if (adev)
> +				break;
> +		}
> +		if (!adev) {
> +			dev_err(dev, "Failed to find ACPI entry for a Cirrus
> Amp\n");
> +			return;
> +		}
> +
> +		count = i2c_acpi_client_count(adev);
> +		if (count > 0) {
> +			bus = "i2c";
> +		} else {
> +			count = acpi_spi_count_resources(adev);
> +			if (count > 0)
> +				bus = "spi";
> +		}
> +
> +		fwnode = fwnode_handle_get(acpi_fwnode_handle(adev));
> +		acpi_dev_put(adev);
> +
> +		if (!bus) {
> +			dev_err(dev, "Did not find any buses for %s\n",
> acpi_ids[i].hid);
> +			return;
> +		}
> +
> +		if (!fwnode) {
> +			dev_err(dev, "Could not get fwnode for %s\n",
> acpi_ids[i].hid);
> +			return;
> +		}
> +
> +		/*
> +		 * When available the cirrus,dev-index property is an
accurate
> +		 * count of the amps in a system and is used in preference
to
> +		 * the count of bus devices that can contain additional
address
> +		 * alias entries.
> +		 */
> +		count_devindex = fwnode_property_count_u32(fwnode,
> "cirrus,dev-index");
> +		if (count_devindex > 0)
> +			count = count_devindex;
> +
> +		match = devm_kasprintf(dev, GFP_KERNEL, "-%%s:00-
> %s.%%d", acpi_ids[i].name);
> +		if (!match)
> +			return;
> +		dev_info(dev, "Found %d %s on %s (%s)\n", count,
> acpi_ids[i].hid, bus, match);
> +		comp_generic_fixup(cdc, action, bus, acpi_ids[i].hid, match,
> count);
> +
> +		break;
> +	case HDA_FIXUP_ACT_FREE:
> +		/*
> +		 * Pass the action on to comp_generic_fixup() so that
> +		 * hda_component_manager functions can be called in just
> once
> +		 * place. In this context the bus, hid, match_str or count
> +		 * values do not need to be calculated.
> +		 */
> +		comp_generic_fixup(cdc, action, NULL, NULL, NULL, 0);
> +		break;
> +	}
> +}
> +
>  static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct
> hda_fixup *fix, int action)
>  {
>  	comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-
> hda.%d", 2);
> @@ -7528,6 +7611,7 @@ enum {
>  	ALC256_FIXUP_CHROME_BOOK,
>  	ALC287_FIXUP_LENOVO_14ARP8_LEGION_IAH7,
>  	ALC287_FIXUP_LENOVO_SSID_17AA3820,
> +	ALCXXX_FIXUP_CS35LXX,
>  };
> 
>  /* A special fixup for Lenovo C940 and Yoga Duet 7;
> @@ -9857,6 +9941,10 @@ static const struct hda_fixup alc269_fixups[] = {
>  		.type = HDA_FIXUP_FUNC,
>  		.v.func = alc287_fixup_lenovo_ssid_17aa3820,
>  	},
> +	[ALCXXX_FIXUP_CS35LXX] = {
> +		.type = HDA_FIXUP_FUNC,
> +		.v.func = cs35lxx_autodet_fixup,
> +	},
>  };
> 
>  static const struct snd_pci_quirk alc269_fixup_tbl[] = {
> @@ -10271,6 +10359,17 @@ static const struct snd_pci_quirk
> alc269_fixup_tbl[] = {
>  	SND_PCI_QUIRK(0x103c, 0x8cdf, "HP SnowWhite",
> ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
>  	SND_PCI_QUIRK(0x103c, 0x8ce0, "HP SnowWhite",
> ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
>  	SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16",
> ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
> +	SND_PCI_QUIRK(0x103c, 0x8d01, "HP ZBook Power 14 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d08, "HP EliteBook 1045 14 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d85, "HP EliteBook 1040 14 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d86, "HP Elite x360 1040 14 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d8c, "HP EliteBook 830 13 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d8d, "HP Elite x360 830 13 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d8e, "HP EliteBook 840 14 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d8f, "HP EliteBook 840 14 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 860 16 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12",
> ALCXXX_FIXUP_CS35LXX),
> +	SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12",
> ALCXXX_FIXUP_CS35LXX),
>  	SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA",
> ALC256_FIXUP_ASUS_MIC),
>  	SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300",
> ALC282_FIXUP_ASUS_TX300),
>  	SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE",
> ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
> --
> 2.43.0
>
diff mbox series

Patch

diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 1645d21d422f..1a05c647f08c 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -11,15 +11,18 @@ 
  */
 
 #include <linux/acpi.h>
+#include <linux/cleanup.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/dmi.h>
 #include <linux/module.h>
+#include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/leds.h>
 #include <linux/ctype.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/jack.h>
 #include <sound/hda_codec.h>
@@ -6856,6 +6859,86 @@  static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bu
 	}
 }
 
+static void cs35lxx_autodet_fixup(struct hda_codec *cdc,
+				  const struct hda_fixup *fix,
+				  int action)
+{
+	struct device *dev = hda_codec_dev(cdc);
+	struct acpi_device *adev;
+	struct fwnode_handle *fwnode __free(fwnode_handle) = NULL;
+	const char *bus = NULL;
+	static const struct {
+		const char *hid;
+		const char *name;
+	} acpi_ids[] = {{ "CSC3554", "cs35l54-hda" },
+			{ "CSC3556", "cs35l56-hda" },
+			{ "CSC3557", "cs35l57-hda" }};
+	char *match;
+	int i, count = 0, count_devindex = 0;
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		for (i = 0; i < ARRAY_SIZE(acpi_ids); ++i) {
+			adev = acpi_dev_get_first_match_dev(acpi_ids[i].hid, NULL, -1);
+			if (adev)
+				break;
+		}
+		if (!adev) {
+			dev_err(dev, "Failed to find ACPI entry for a Cirrus Amp\n");
+			return;
+		}
+
+		count = i2c_acpi_client_count(adev);
+		if (count > 0) {
+			bus = "i2c";
+		} else {
+			count = acpi_spi_count_resources(adev);
+			if (count > 0)
+				bus = "spi";
+		}
+
+		fwnode = fwnode_handle_get(acpi_fwnode_handle(adev));
+		acpi_dev_put(adev);
+
+		if (!bus) {
+			dev_err(dev, "Did not find any buses for %s\n", acpi_ids[i].hid);
+			return;
+		}
+
+		if (!fwnode) {
+			dev_err(dev, "Could not get fwnode for %s\n", acpi_ids[i].hid);
+			return;
+		}
+
+		/*
+		 * When available the cirrus,dev-index property is an accurate
+		 * count of the amps in a system and is used in preference to
+		 * the count of bus devices that can contain additional address
+		 * alias entries.
+		 */
+		count_devindex = fwnode_property_count_u32(fwnode, "cirrus,dev-index");
+		if (count_devindex > 0)
+			count = count_devindex;
+
+		match = devm_kasprintf(dev, GFP_KERNEL, "-%%s:00-%s.%%d", acpi_ids[i].name);
+		if (!match)
+			return;
+		dev_info(dev, "Found %d %s on %s (%s)\n", count, acpi_ids[i].hid, bus, match);
+		comp_generic_fixup(cdc, action, bus, acpi_ids[i].hid, match, count);
+
+		break;
+	case HDA_FIXUP_ACT_FREE:
+		/*
+		 * Pass the action on to comp_generic_fixup() so that
+		 * hda_component_manager functions can be called in just once
+		 * place. In this context the bus, hid, match_str or count
+		 * values do not need to be calculated.
+		 */
+		comp_generic_fixup(cdc, action, NULL, NULL, NULL, 0);
+		break;
+	}
+}
+
 static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
 {
 	comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
@@ -7528,6 +7611,7 @@  enum {
 	ALC256_FIXUP_CHROME_BOOK,
 	ALC287_FIXUP_LENOVO_14ARP8_LEGION_IAH7,
 	ALC287_FIXUP_LENOVO_SSID_17AA3820,
+	ALCXXX_FIXUP_CS35LXX,
 };
 
 /* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -9857,6 +9941,10 @@  static const struct hda_fixup alc269_fixups[] = {
 		.type = HDA_FIXUP_FUNC,
 		.v.func = alc287_fixup_lenovo_ssid_17aa3820,
 	},
+	[ALCXXX_FIXUP_CS35LXX] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = cs35lxx_autodet_fixup,
+	},
 };
 
 static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -10271,6 +10359,17 @@  static const struct snd_pci_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x103c, 0x8cdf, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
 	SND_PCI_QUIRK(0x103c, 0x8ce0, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
 	SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
+	SND_PCI_QUIRK(0x103c, 0x8d01, "HP ZBook Power 14 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d08, "HP EliteBook 1045 14 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d85, "HP EliteBook 1040 14 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d86, "HP Elite x360 1040 14 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d8c, "HP EliteBook 830 13 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d8d, "HP Elite x360 830 13 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d8e, "HP EliteBook 840 14 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d8f, "HP EliteBook 840 14 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 860 16 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALCXXX_FIXUP_CS35LXX),
+	SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALCXXX_FIXUP_CS35LXX),
 	SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
 	SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
 	SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),