aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/sound/pci/hda
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2024-03-11 09:12:58 +0100
committerTakashi Iwai <tiwai@suse.de>2024-03-11 09:12:58 +0100
commit14b9e4ab71b3f58828c107d7158e52da1e670d1c (patch)
treec47d143c8315a02985cce3e0d6d63b07b5f865a2 /sound/pci/hda
parentMerge tag 'asoc-fix-v6.8-rc7' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-linus (diff)
parentplatform/x86: serial-multi-instantiate: Add support for CS35L54 and CS35L57 (diff)
downloadwireguard-linux-14b9e4ab71b3f58828c107d7158e52da1e670d1c.tar.xz
wireguard-linux-14b9e4ab71b3f58828c107d7158e52da1e670d1c.zip
Merge branch 'for-next' into for-linus
Prep for 6.9 merge. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/hda')
-rw-r--r--sound/pci/hda/Kconfig4
-rw-r--r--sound/pci/hda/Makefile2
-rw-r--r--sound/pci/hda/cs35l41_hda_property.c90
-rw-r--r--sound/pci/hda/cs35l56_hda.c16
-rw-r--r--sound/pci/hda/cs35l56_hda.h2
-rw-r--r--sound/pci/hda/cs35l56_hda_i2c.c7
-rw-r--r--sound/pci/hda/cs35l56_hda_spi.c7
-rw-r--r--sound/pci/hda/hda_beep.c1
-rw-r--r--sound/pci/hda/hda_beep.h1
-rw-r--r--sound/pci/hda/hda_codec.c2
-rw-r--r--sound/pci/hda/hda_component.c169
-rw-r--r--sound/pci/hda/hda_component.h65
-rw-r--r--sound/pci/hda/hda_controller.c14
-rw-r--r--sound/pci/hda/patch_realtek.c270
14 files changed, 426 insertions, 224 deletions
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index 8e0ff70fb610..26da739eea82 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -116,6 +116,9 @@ config SND_HDA_CS_DSP_CONTROLS
tristate
select FW_CS_DSP
+config SND_HDA_SCODEC_COMPONENT
+ tristate
+
config SND_HDA_SCODEC_CS35L41_I2C
tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
depends on I2C
@@ -201,6 +204,7 @@ config SND_HDA_CODEC_REALTEK
tristate "Build Realtek HD-audio codec support"
select SND_HDA_GENERIC
select SND_HDA_GENERIC_LEDS
+ select SND_HDA_SCODEC_COMPONENT
help
Say Y or M here to include Realtek HD-audio codec support in
snd-hda-intel driver, such as ALC880.
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 793e296c3f64..13e04e1f65de 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -37,6 +37,7 @@ snd-hda-scodec-cs35l56-objs := cs35l56_hda.o
snd-hda-scodec-cs35l56-i2c-objs := cs35l56_hda_i2c.o
snd-hda-scodec-cs35l56-spi-objs := cs35l56_hda_spi.o
snd-hda-cs-dsp-ctls-objs := hda_cs_dsp_ctl.o
+snd-hda-scodec-component-objs := hda_component.o
snd-hda-scodec-tas2781-i2c-objs := tas2781_hda_i2c.o
# common driver
@@ -67,6 +68,7 @@ obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o
obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o
+obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
# this must be the last entry after codec drivers;
diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
index e436d4dab317..72ec872afb8d 100644
--- a/sound/pci/hda/cs35l41_hda_property.c
+++ b/sound/pci/hda/cs35l41_hda_property.c
@@ -51,19 +51,30 @@ static const struct cs35l41_config cs35l41_config_table[] = {
{ "103C8A2E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 },
{ "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8BDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8BE0", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8BE1", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8BE2", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
- { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
- { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
- { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8BE3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8BE5", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8BE6", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE7", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE8", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
{ "103C8B3A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8C15", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+ { "103C8C16", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+ { "103C8C17", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+ { "103C8C4F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8C50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8C51", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8CDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+ { "103C8CDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 3900, 24 },
{ "104312AF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
{ "10431433", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
{ "10431463", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
@@ -210,6 +221,7 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
struct spi_device *spi;
bool dsd_found;
int ret;
+ int i;
for (cfg = cs35l41_config_table; cfg->ssid; cfg++) {
if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id))
@@ -295,16 +307,6 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
cs35l41->index = id == 0x40 ? 0 : 1;
}
- if (cfg->num_amps == 3)
- /* 3 amps means a center channel, so no duplicate channels */
- cs35l41->channel_index = 0;
- else
- /*
- * if 4 amps, there are duplicate channels, so they need different indexes
- * if 2 amps, no duplicate channels, channel_index would be 0
- */
- cs35l41->channel_index = cs35l41->index / 2;
-
cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
cs35l41->index, GPIOD_OUT_LOW,
"cs35l41-reset");
@@ -312,6 +314,11 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
hw_cfg->spk_pos = cfg->channel[cs35l41->index];
+ cs35l41->channel_index = 0;
+ for (i = 0; i < cs35l41->index; i++)
+ if (cfg->channel[i] == hw_cfg->spk_pos)
+ cs35l41->channel_index++;
+
if (cfg->boost_type == INTERNAL) {
hw_cfg->bst_type = CS35L41_INT_BOOST;
hw_cfg->bst_ind = cfg->boost_ind_nanohenry;
@@ -336,6 +343,42 @@ static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physde
}
/*
+ * Systems 103C8C66, 103C8C67, 103C8C68, 103C8C6A use a dual speaker id system - each speaker has
+ * its own speaker id.
+ */
+static int hp_i2c_int_2amp_dual_spkid(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+ const char *hid)
+{
+ struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+
+ /* If _DSD exists for this laptop, we cannot support it through here */
+ if (acpi_dev_has_props(cs35l41->dacpi))
+ return -ENOENT;
+
+ /* 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);
+ if (cs35l41->index == 0)
+ cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 1);
+ else
+ 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;
+
+ hw_cfg->bst_type = CS35L41_INT_BOOST;
+ hw_cfg->bst_ind = 1000;
+ hw_cfg->bst_ipk = 4100;
+ hw_cfg->bst_cap = 24;
+ hw_cfg->gpio1.func = CS35L41_NOT_USED;
+ hw_cfg->gpio1.valid = true;
+
+ return 0;
+}
+
+/*
* 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.
@@ -392,19 +435,34 @@ static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
{ "CSC3551", "103C8A2E", generic_dsd_config },
{ "CSC3551", "103C8A30", generic_dsd_config },
{ "CSC3551", "103C8A31", generic_dsd_config },
+ { "CSC3551", "103C8A6E", generic_dsd_config },
{ "CSC3551", "103C8BB3", generic_dsd_config },
{ "CSC3551", "103C8BB4", generic_dsd_config },
+ { "CSC3551", "103C8BDD", generic_dsd_config },
+ { "CSC3551", "103C8BDE", generic_dsd_config },
{ "CSC3551", "103C8BDF", generic_dsd_config },
{ "CSC3551", "103C8BE0", generic_dsd_config },
{ "CSC3551", "103C8BE1", generic_dsd_config },
{ "CSC3551", "103C8BE2", generic_dsd_config },
- { "CSC3551", "103C8BE9", generic_dsd_config },
- { "CSC3551", "103C8BDD", generic_dsd_config },
- { "CSC3551", "103C8BDE", generic_dsd_config },
{ "CSC3551", "103C8BE3", generic_dsd_config },
{ "CSC3551", "103C8BE5", generic_dsd_config },
{ "CSC3551", "103C8BE6", generic_dsd_config },
+ { "CSC3551", "103C8BE7", generic_dsd_config },
+ { "CSC3551", "103C8BE8", generic_dsd_config },
+ { "CSC3551", "103C8BE9", generic_dsd_config },
{ "CSC3551", "103C8B3A", generic_dsd_config },
+ { "CSC3551", "103C8C15", generic_dsd_config },
+ { "CSC3551", "103C8C16", generic_dsd_config },
+ { "CSC3551", "103C8C17", generic_dsd_config },
+ { "CSC3551", "103C8C4F", generic_dsd_config },
+ { "CSC3551", "103C8C50", generic_dsd_config },
+ { "CSC3551", "103C8C51", generic_dsd_config },
+ { "CSC3551", "103C8C66", hp_i2c_int_2amp_dual_spkid },
+ { "CSC3551", "103C8C67", hp_i2c_int_2amp_dual_spkid },
+ { "CSC3551", "103C8C68", hp_i2c_int_2amp_dual_spkid },
+ { "CSC3551", "103C8C6A", hp_i2c_int_2amp_dual_spkid },
+ { "CSC3551", "103C8CDD", generic_dsd_config },
+ { "CSC3551", "103C8CDE", generic_dsd_config },
{ "CSC3551", "104312AF", generic_dsd_config },
{ "CSC3551", "10431433", generic_dsd_config },
{ "CSC3551", "10431463", generic_dsd_config },
diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c
index 75a14ba54fcd..1fae241642b1 100644
--- a/sound/pci/hda/cs35l56_hda.c
+++ b/sound/pci/hda/cs35l56_hda.c
@@ -458,13 +458,15 @@ static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
if (preloaded_fw_ver) {
snprintf(base_name, sizeof(base_name),
- "cirrus/cs35l56-%02x%s-%06x-dsp1-misc",
+ "cirrus/cs35l%02x-%02x%s-%06x-dsp1-misc",
+ cs35l56->base.type,
cs35l56->base.rev,
cs35l56->base.secured ? "-s" : "",
preloaded_fw_ver & 0xffffff);
} else {
snprintf(base_name, sizeof(base_name),
- "cirrus/cs35l56-%02x%s-dsp1-misc",
+ "cirrus/cs35l%02x-%02x%s-dsp1-misc",
+ cs35l56->base.type,
cs35l56->base.rev,
cs35l56->base.secured ? "-s" : "");
}
@@ -834,9 +836,10 @@ static int cs35l56_hda_system_resume(struct device *dev)
return 0;
}
-static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id)
+static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
{
u32 values[HDA_MAX_COMPONENTS];
+ char hid_string[8];
struct acpi_device *adev;
const char *property, *sub;
size_t nval;
@@ -847,7 +850,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int id)
* the serial-multi-instantiate driver, so lookup the node by HID
*/
if (!ACPI_COMPANION(cs35l56->base.dev)) {
- adev = acpi_dev_get_first_match_dev("CSC3556", NULL, -1);
+ snprintf(hid_string, sizeof(hid_string), "CSC%04X", hid);
+ adev = acpi_dev_get_first_match_dev(hid_string, NULL, -1);
if (!adev) {
dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n",
dev_name(cs35l56->base.dev));
@@ -935,14 +939,14 @@ err:
return ret;
}
-int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id)
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
{
int ret;
mutex_init(&cs35l56->base.irq_lock);
dev_set_drvdata(cs35l56->base.dev, cs35l56);
- ret = cs35l56_hda_read_acpi(cs35l56, id);
+ ret = cs35l56_hda_read_acpi(cs35l56, hid, id);
if (ret)
goto err;
diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h
index 6e5bc5397db5..464e4aa63cd1 100644
--- a/sound/pci/hda/cs35l56_hda.h
+++ b/sound/pci/hda/cs35l56_hda.h
@@ -42,7 +42,7 @@ struct cs35l56_hda {
extern const struct dev_pm_ops cs35l56_hda_pm_ops;
-int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int id);
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id);
void cs35l56_hda_remove(struct device *dev);
#endif /*__CS35L56_HDA_H__*/
diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c
index a9ef6d86de83..13beee807308 100644
--- a/sound/pci/hda/cs35l56_hda_i2c.c
+++ b/sound/pci/hda/cs35l56_hda_i2c.c
@@ -13,6 +13,7 @@
static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
{
+ const struct i2c_device_id *id = i2c_client_get_device_id(clt);
struct cs35l56_hda *cs35l56;
int ret;
@@ -33,7 +34,7 @@ static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
return ret;
}
- ret = cs35l56_hda_common_probe(cs35l56, clt->addr);
+ ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, clt->addr);
if (ret)
return ret;
ret = cs35l56_irq_request(&cs35l56->base, clt->irq);
@@ -49,7 +50,9 @@ static void cs35l56_hda_i2c_remove(struct i2c_client *clt)
}
static const struct i2c_device_id cs35l56_hda_i2c_id[] = {
- { "cs35l56-hda", 0 },
+ { "cs35l54-hda", 0x3554 },
+ { "cs35l56-hda", 0x3556 },
+ { "cs35l57-hda", 0x3557 },
{}
};
diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c
index 080426de9083..a3b2fa76663d 100644
--- a/sound/pci/hda/cs35l56_hda_spi.c
+++ b/sound/pci/hda/cs35l56_hda_spi.c
@@ -13,6 +13,7 @@
static int cs35l56_hda_spi_probe(struct spi_device *spi)
{
+ const struct spi_device_id *id = spi_get_device_id(spi);
struct cs35l56_hda *cs35l56;
int ret;
@@ -33,7 +34,7 @@ static int cs35l56_hda_spi_probe(struct spi_device *spi)
return ret;
}
- ret = cs35l56_hda_common_probe(cs35l56, spi_get_chipselect(spi, 0));
+ ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, spi_get_chipselect(spi, 0));
if (ret)
return ret;
ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
@@ -49,7 +50,9 @@ static void cs35l56_hda_spi_remove(struct spi_device *spi)
}
static const struct spi_device_id cs35l56_hda_spi_id[] = {
- { "cs35l56-hda", 0 },
+ { "cs35l54-hda", 0x3554 },
+ { "cs35l56-hda", 0x3556 },
+ { "cs35l57-hda", 0x3557 },
{}
};
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index e63621bcb214..e51d47572557 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -231,7 +231,6 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
codec->beep = beep;
INIT_WORK(&beep->beep_work, &snd_hda_generate_beep);
- mutex_init(&beep->mutex);
input_dev = input_allocate_device();
if (!input_dev) {
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h
index db76e3ddba65..923ea862446a 100644
--- a/sound/pci/hda/hda_beep.h
+++ b/sound/pci/hda/hda_beep.h
@@ -27,7 +27,6 @@ struct hda_beep {
unsigned int playing:1;
unsigned int keep_power_at_enable:1; /* set by driver */
struct work_struct beep_work; /* scheduled task for beep event */
- struct mutex mutex;
void (*power_hook)(struct hda_beep *beep, bool on);
};
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 12f02cdc9659..2cac337f5263 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -3313,7 +3313,7 @@ int snd_hda_codec_parse_pcms(struct hda_codec *codec)
list_for_each_entry(cpcm, &codec->pcm_list_head, list) {
int stream;
- for (stream = 0; stream < 2; stream++) {
+ for_each_pcm_streams(stream) {
struct hda_pcm_stream *info = &cpcm->stream[stream];
if (!info->substreams)
diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c
new file mode 100644
index 000000000000..cd299d7d84ba
--- /dev/null
+++ b/sound/pci/hda/hda_component.c
@@ -0,0 +1,169 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio Component Binding Interface
+ *
+ * Copyright (C) 2021, 2023 Cirrus Logic, Inc. and
+ * Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/acpi.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/hda_codec.h>
+#include "hda_component.h"
+#include "hda_local.h"
+
+#ifdef CONFIG_ACPI
+void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps,
+ acpi_handle handle, u32 event, void *data)
+{
+ int i;
+
+ for (i = 0; i < num_comps; i++) {
+ if (comps[i].dev && comps[i].acpi_notify)
+ comps[i].acpi_notify(acpi_device_handle(comps[i].adev), event,
+ comps[i].dev);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, SND_HDA_SCODEC_COMPONENT);
+
+int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component *comps, int num_comps,
+ acpi_notify_handler handler, void *data)
+{
+ bool support_notifications = false;
+ struct acpi_device *adev;
+ int ret;
+ int i;
+
+ adev = comps[0].adev;
+ if (!acpi_device_handle(adev))
+ return 0;
+
+ for (i = 0; i < num_comps; i++)
+ support_notifications = support_notifications ||
+ comps[i].acpi_notifications_supported;
+
+ if (support_notifications) {
+ ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
+ handler, data);
+ if (ret < 0) {
+ codec_warn(cdc, "Failed to install notify handler: %d\n", ret);
+ return 0;
+ }
+
+ codec_dbg(cdc, "Notify handler installed\n");
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, SND_HDA_SCODEC_COMPONENT);
+
+void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component *comps,
+ acpi_notify_handler handler)
+{
+ struct acpi_device *adev;
+ int ret;
+
+ adev = comps[0].adev;
+ if (!acpi_device_handle(adev))
+ return;
+
+ ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, handler);
+ if (ret < 0)
+ codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret);
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, SND_HDA_SCODEC_COMPONENT);
+#endif /* ifdef CONFIG_ACPI */
+
+void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps, int action)
+{
+ int i;
+
+ for (i = 0; i < num_comps; i++) {
+ if (comps[i].dev && comps[i].pre_playback_hook)
+ comps[i].pre_playback_hook(comps[i].dev, action);
+ }
+ for (i = 0; i < num_comps; i++) {
+ if (comps[i].dev && comps[i].playback_hook)
+ comps[i].playback_hook(comps[i].dev, action);
+ }
+ for (i = 0; i < num_comps; i++) {
+ if (comps[i].dev && comps[i].post_playback_hook)
+ comps[i].post_playback_hook(comps[i].dev, action);
+ }
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, SND_HDA_SCODEC_COMPONENT);
+
+struct hda_scodec_match {
+ const char *bus;
+ const char *hid;
+ const char *match_str;
+ int index;
+};
+
+/* match the device name in a slightly relaxed manner */
+static int hda_comp_match_dev_name(struct device *dev, void *data)
+{
+ struct hda_scodec_match *p = data;
+ const char *d = dev_name(dev);
+ int n = strlen(p->bus);
+ char tmp[32];
+
+ /* check the bus name */
+ if (strncmp(d, p->bus, n))
+ return 0;
+ /* skip the bus number */
+ if (isdigit(d[n]))
+ n++;
+ /* the rest must be exact matching */
+ snprintf(tmp, sizeof(tmp), p->match_str, p->hid, p->index);
+ return !strcmp(d + n, tmp);
+}
+
+int hda_component_manager_init(struct hda_codec *cdc,
+ struct hda_component *comps, int count,
+ const char *bus, const char *hid,
+ const char *match_str,
+ const struct component_master_ops *ops)
+{
+ struct device *dev = hda_codec_dev(cdc);
+ struct component_match *match = NULL;
+ struct hda_scodec_match *sm;
+ int ret, i;
+
+ for (i = 0; i < count; i++) {
+ sm = devm_kmalloc(dev, sizeof(*sm), GFP_KERNEL);
+ if (!sm)
+ return -ENOMEM;
+
+ sm->bus = bus;
+ sm->hid = hid;
+ sm->match_str = match_str;
+ sm->index = i;
+ comps[i].codec = cdc;
+ component_match_add(dev, &match, hda_comp_match_dev_name, sm);
+ }
+
+ ret = component_master_add_with_match(dev, ops, match);
+ if (ret)
+ codec_err(cdc, "Fail to register component aggregator %d\n", ret);
+
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, SND_HDA_SCODEC_COMPONENT);
+
+void hda_component_manager_free(struct hda_codec *cdc,
+ const struct component_master_ops *ops)
+{
+ struct device *dev = hda_codec_dev(cdc);
+
+ component_master_del(dev, ops);
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, SND_HDA_SCODEC_COMPONENT);
+
+MODULE_DESCRIPTION("HD Audio component binding library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h
index bbd6f0ed16c1..c80a66691b5d 100644
--- a/sound/pci/hda/hda_component.h
+++ b/sound/pci/hda/hda_component.h
@@ -6,8 +6,12 @@
* Cirrus Logic International Semiconductor Ltd.
*/
+#ifndef __HDA_COMPONENT_H__
+#define __HDA_COMPONENT_H__
+
#include <linux/acpi.h>
#include <linux/component.h>
+#include <sound/hda_codec.h>
#define HDA_MAX_COMPONENTS 4
#define HDA_MAX_NAME_SIZE 50
@@ -23,3 +27,64 @@ struct hda_component {
void (*playback_hook)(struct device *dev, int action);
void (*post_playback_hook)(struct device *dev, int action);
};
+
+#ifdef CONFIG_ACPI
+void hda_component_acpi_device_notify(struct hda_component *comps, int num_comps,
+ acpi_handle handle, u32 event, void *data);
+int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component *comps, int num_comps,
+ acpi_notify_handler handler, void *data);
+void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component *comps,
+ acpi_notify_handler handler);
+#else
+static inline void hda_component_acpi_device_notify(struct hda_component *comps,
+ int num_comps,
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+}
+
+static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component *comps,
+ int num_comps,
+ acpi_notify_handler handler,
+ void *data)
+
+{
+ return 0;
+}
+
+static inline void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+ struct hda_component *comps,
+ acpi_notify_handler handler)
+{
+}
+#endif /* ifdef CONFIG_ACPI */
+
+void hda_component_manager_playback_hook(struct hda_component *comps, int num_comps,
+ int action);
+
+int hda_component_manager_init(struct hda_codec *cdc,
+ struct hda_component *comps, int count,
+ const char *bus, const char *hid,
+ const char *match_str,
+ const struct component_master_ops *ops);
+
+void hda_component_manager_free(struct hda_codec *cdc,
+ const struct component_master_ops *ops);
+
+static inline int hda_component_manager_bind(struct hda_codec *cdc,
+ struct hda_component *comps)
+{
+ return component_bind_all(hda_codec_dev(cdc), comps);
+}
+
+static inline void hda_component_manager_unbind(struct hda_codec *cdc,
+ struct hda_component *comps)
+{
+ component_unbind_all(hda_codec_dev(cdc), comps);
+}
+
+#endif /* ifndef __HDA_COMPONENT_H__ */
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c
index efe98f6f19a3..206306a0eb82 100644
--- a/sound/pci/hda/hda_controller.c
+++ b/sound/pci/hda/hda_controller.c
@@ -24,6 +24,7 @@
#include <sound/core.h>
#include <sound/initval.h>
+#include <sound/pcm_params.h>
#include "hda_controller.h"
#include "hda_local.h"
@@ -108,6 +109,7 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
struct azx_pcm *apcm = snd_pcm_substream_chip(substream);
struct azx *chip = apcm->chip;
struct azx_dev *azx_dev = get_azx_dev(substream);
+ struct hdac_stream *hdas = azx_stream(azx_dev);
int ret = 0;
trace_azx_pcm_hw_params(chip, azx_dev);
@@ -117,9 +119,15 @@ static int azx_pcm_hw_params(struct snd_pcm_substream *substream,
goto unlock;
}
- azx_dev->core.bufsize = 0;
- azx_dev->core.period_bytes = 0;
- azx_dev->core.format_val = 0;
+ /* Set up BDLEs here, return -ENOMEM if too many BDLEs are required */
+ hdas->bufsize = params_buffer_bytes(hw_params);
+ hdas->period_bytes = params_period_bytes(hw_params);
+ hdas->format_val = 0;
+ hdas->no_period_wakeup =
+ (hw_params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
+ (hw_params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
+ if (snd_hdac_stream_setup_periods(hdas) < 0)
+ ret = -ENOMEM;
unlock:
dsp_unlock(azx_dev);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index a1facdb98d9a..71a935e690b5 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -133,7 +133,6 @@ struct alc_spec {
u8 alc_mute_keycode_map[1];
/* component binding */
- struct component_match *match;
struct hda_component comps[HDA_MAX_COMPONENTS];
};
@@ -6720,91 +6719,30 @@ static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec,
}
}
-#ifdef CONFIG_ACPI
static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data)
{
struct hda_codec *cdc = data;
struct alc_spec *spec = cdc->spec;
- int i;
codec_info(cdc, "ACPI Notification %d\n", event);
- for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
- if (spec->comps[i].dev && spec->comps[i].acpi_notify)
- spec->comps[i].acpi_notify(acpi_device_handle(spec->comps[i].adev), event,
- spec->comps[i].dev);
- }
-}
-
-static int comp_bind_acpi(struct device *dev)
-{
- struct hda_codec *cdc = dev_to_hda_codec(dev);
- struct alc_spec *spec = cdc->spec;
- bool support_notifications = false;
- struct acpi_device *adev;
- int ret;
- int i;
-
- adev = spec->comps[0].adev;
- if (!acpi_device_handle(adev))
- return 0;
-
- for (i = 0; i < HDA_MAX_COMPONENTS; i++)
- support_notifications = support_notifications ||
- spec->comps[i].acpi_notifications_supported;
-
- if (support_notifications) {
- ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
- comp_acpi_device_notify, cdc);
- if (ret < 0) {
- codec_warn(cdc, "Failed to install notify handler: %d\n", ret);
- return 0;
- }
-
- codec_dbg(cdc, "Notify handler installed\n");
- }
-
- return 0;
+ hda_component_acpi_device_notify(spec->comps, ARRAY_SIZE(spec->comps),
+ handle, event, data);
}
-static void comp_unbind_acpi(struct device *dev)
-{
- struct hda_codec *cdc = dev_to_hda_codec(dev);
- struct alc_spec *spec = cdc->spec;
- struct acpi_device *adev;
- int ret;
-
- adev = spec->comps[0].adev;
- if (!acpi_device_handle(adev))
- return;
-
- ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
- comp_acpi_device_notify);
- if (ret < 0)
- codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret);
-}
-#else
-static int comp_bind_acpi(struct device *dev)
-{
- return 0;
-}
-
-static void comp_unbind_acpi(struct device *dev)
-{
-}
-#endif
-
static int comp_bind(struct device *dev)
{
struct hda_codec *cdc = dev_to_hda_codec(dev);
struct alc_spec *spec = cdc->spec;
int ret;
- ret = component_bind_all(dev, spec->comps);
+ ret = hda_component_manager_bind(cdc, spec->comps);
if (ret)
return ret;
- return comp_bind_acpi(dev);
+ return hda_component_manager_bind_acpi_notifications(cdc,
+ spec->comps, ARRAY_SIZE(spec->comps),
+ comp_acpi_device_notify, cdc);
}
static void comp_unbind(struct device *dev)
@@ -6812,8 +6750,8 @@ static void comp_unbind(struct device *dev)
struct hda_codec *cdc = dev_to_hda_codec(dev);
struct alc_spec *spec = cdc->spec;
- comp_unbind_acpi(dev);
- component_unbind_all(dev, spec->comps);
+ hda_component_manager_unbind_acpi_notifications(cdc, spec->comps, comp_acpi_device_notify);
+ hda_component_manager_unbind(cdc, spec->comps);
}
static const struct component_master_ops comp_master_ops = {
@@ -6825,177 +6763,78 @@ static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_
struct snd_pcm_substream *sub, int action)
{
struct alc_spec *spec = cdc->spec;
- int i;
-
- for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
- if (spec->comps[i].dev && spec->comps[i].pre_playback_hook)
- spec->comps[i].pre_playback_hook(spec->comps[i].dev, action);
- }
- for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
- if (spec->comps[i].dev && spec->comps[i].playback_hook)
- spec->comps[i].playback_hook(spec->comps[i].dev, action);
- }
- for (i = 0; i < HDA_MAX_COMPONENTS; i++) {
- if (spec->comps[i].dev && spec->comps[i].post_playback_hook)
- spec->comps[i].post_playback_hook(spec->comps[i].dev, action);
- }
-}
-
-struct scodec_dev_name {
- const char *bus;
- const char *hid;
- int index;
-};
-
-/* match the device name in a slightly relaxed manner */
-static int comp_match_cs35l41_dev_name(struct device *dev, void *data)
-{
- struct scodec_dev_name *p = data;
- const char *d = dev_name(dev);
- int n = strlen(p->bus);
- char tmp[32];
-
- /* check the bus name */
- if (strncmp(d, p->bus, n))
- return 0;
- /* skip the bus number */
- if (isdigit(d[n]))
- n++;
- /* the rest must be exact matching */
- snprintf(tmp, sizeof(tmp), "-%s:00-cs35l41-hda.%d", p->hid, p->index);
- return !strcmp(d + n, tmp);
-}
-
-static int comp_match_tas2781_dev_name(struct device *dev,
- void *data)
-{
- struct scodec_dev_name *p = data;
- const char *d = dev_name(dev);
- int n = strlen(p->bus);
- char tmp[32];
-
- /* check the bus name */
- if (strncmp(d, p->bus, n))
- return 0;
- /* skip the bus number */
- if (isdigit(d[n]))
- n++;
- /* the rest must be exact matching */
- snprintf(tmp, sizeof(tmp), "-%s:00", p->hid);
-
- return !strcmp(d + n, tmp);
-}
-
-static void cs35l41_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
- const char *hid, int count)
-{
- struct device *dev = hda_codec_dev(cdc);
- struct alc_spec *spec = cdc->spec;
- struct scodec_dev_name *rec;
- int ret, i;
- switch (action) {
- case HDA_FIXUP_ACT_PRE_PROBE:
- for (i = 0; i < count; i++) {
- rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL);
- if (!rec)
- return;
- rec->bus = bus;
- rec->hid = hid;
- rec->index = i;
- spec->comps[i].codec = cdc;
- component_match_add(dev, &spec->match,
- comp_match_cs35l41_dev_name, rec);
- }
- ret = component_master_add_with_match(dev, &comp_master_ops, spec->match);
- if (ret)
- codec_err(cdc, "Fail to register component aggregator %d\n", ret);
- else
- spec->gen.pcm_playback_hook = comp_generic_playback_hook;
- break;
- case HDA_FIXUP_ACT_FREE:
- component_master_del(dev, &comp_master_ops);
- break;
- }
+ hda_component_manager_playback_hook(spec->comps, ARRAY_SIZE(spec->comps), action);
}
-static void tas2781_generic_fixup(struct hda_codec *cdc, int action,
- const char *bus, const char *hid)
+static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
+ const char *hid, const char *match_str, int count)
{
- struct device *dev = hda_codec_dev(cdc);
struct alc_spec *spec = cdc->spec;
- struct scodec_dev_name *rec;
int ret;
switch (action) {
case HDA_FIXUP_ACT_PRE_PROBE:
- rec = devm_kmalloc(dev, sizeof(*rec), GFP_KERNEL);
- if (!rec)
- return;
- rec->bus = bus;
- rec->hid = hid;
- rec->index = 0;
- spec->comps[0].codec = cdc;
- component_match_add(dev, &spec->match,
- comp_match_tas2781_dev_name, rec);
- ret = component_master_add_with_match(dev, &comp_master_ops,
- spec->match);
+ ret = hda_component_manager_init(cdc, spec->comps, count, bus, hid,
+ match_str, &comp_master_ops);
if (ret)
- codec_err(cdc,
- "Fail to register component aggregator %d\n",
- ret);
- else
- spec->gen.pcm_playback_hook =
- comp_generic_playback_hook;
+ return;
+
+ spec->gen.pcm_playback_hook = comp_generic_playback_hook;
break;
case HDA_FIXUP_ACT_FREE:
- component_master_del(dev, &comp_master_ops);
+ hda_component_manager_free(cdc, &comp_master_ops);
break;
}
}
static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
- cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 2);
+ comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
}
static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
- cs35l41_generic_fixup(cdc, action, "i2c", "CSC3551", 4);
+ comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
}
static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action)
{
- cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 2);
+ comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
}
static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action)
{
- cs35l41_generic_fixup(codec, action, "spi", "CSC3551", 4);
+ comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
}
static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
int action)
{
- cs35l41_generic_fixup(cdc, action, "i2c", "CLSA0100", 2);
+ comp_generic_fixup(cdc, action, "i2c", "CLSA0100", "-%s:00-cs35l41-hda.%d", 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);
+ comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2);
+}
+
+static void cs35l56_fixup_spi_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+ comp_generic_fixup(cdc, action, "spi", "CSC3556", "-%s:00-cs35l56-hda.%d", 4);
}
static void tas2781_fixup_i2c(struct hda_codec *cdc,
const struct hda_fixup *fix, int action)
{
- tas2781_generic_fixup(cdc, action, "i2c", "TIAS2781");
+ comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
}
static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
const struct hda_fixup *fix, int action)
{
- tas2781_generic_fixup(cdc, action, "i2c", "INT8866");
+ comp_generic_fixup(cdc, action, "i2c", "INT8866", "-%s:00", 1);
}
/* for alc295_fixup_hp_top_speakers */
@@ -7478,6 +7317,7 @@ enum {
ALC2XX_FIXUP_HEADSET_MIC,
ALC289_FIXUP_DELL_CS35L41_SPI_2,
ALC294_FIXUP_CS35L41_I2C_2,
+ ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED,
};
/* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -9655,6 +9495,12 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = cs35l41_fixup_i2c_two,
},
+ [ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = cs35l56_fixup_spi_four,
+ .chained = true,
+ .chain_id = ALC285_FIXUP_HP_GPIO_LED,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -9947,9 +9793,21 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+ SND_PCI_QUIRK(0x103c, 0x8a28, "HP Envy 13", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a29, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2b, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2c, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2d, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
@@ -9959,8 +9817,10 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8ad8, "HP 800 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+ SND_PCI_QUIRK(0x103c, 0x8b3a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8b3f, "HP mt440 Mobile Thin Client U91", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
@@ -9988,11 +9848,35 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+ SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8bdf, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be0, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be1, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be2, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be3, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be5, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be6, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be7, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be8, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre 14", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c49, "HP Elite x360 830 2-in-1 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c4f, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c50, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c51, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC245_FIXUP_CS35L56_SPI_4_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8c66, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c67, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c68, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8c6a, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
@@ -10006,6 +9890,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+ SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2),
+ SND_PCI_QUIRK(0x103c, 0x8cde, "HP Spectre", ALC287_FIXUP_CS35L41_I2C_2),
SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
@@ -10127,6 +10013,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+ SND_PCI_QUIRK(0x10ec, 0x12f6, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_HEADSET_MODE),
SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
@@ -12674,6 +12561,7 @@ MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Realtek HD-audio codec");
+MODULE_IMPORT_NS(SND_HDA_SCODEC_COMPONENT);
static struct hda_codec_driver realtek_driver = {
.id = snd_hda_id_realtek,