Linux ACPI
 help / color / mirror / Atom feed
* [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion
@ 2026-07-29  9:33 Marco Giunta
  2026-07-29  9:33 ` [PATCH v2 1/3] ACPI/platform: add AWDZ8399 to serial-multi-instantiate Marco Giunta
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Marco Giunta @ 2026-07-29  9:33 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Jaroslav Kysela, Liam Girdwood, Mark Brown, linux-kernel,
	linux-sound, Rafael J. Wysocki, Len Brown, Hans de Goede,
	Ilpo Järvinen, linux-acpi, platform-driver-x86, Weidong Wang,
	Nadim Kobeissi, Xia Yun'an, Munzir Taha, Yakov Till,
	Marco Giunta

This is v2 of the AW88399 HDA side codec driver series. Patches 1-5
from v1 (ASoC library preparation) were applied by Mark Brown and
merged into tiwai/sound via broonie/sound. This series contains the
remaining three patches.

Changes since v1:
* Fixed memory leak of acpi_subsystem_id string on probe error paths
  by switching to devm_kstrdup (bug reported by Sashiko, confirmed
  by Takashi Iwai)
* Added Acked-by tags from Rafael J. Wysocki and Ilpo Järvinen
  for the ACPI/platform changes

Patch 1 registers the AWINIC ACPI HID "AWDZ8399" with the ACPI
scan ignore list and the serial-multi-instantiate driver.

Patch 2 adds the HDA side codec driver: I2C bus driver and core
driver with HDA component binding, playback hooks, power management,
and per-model quirk matching.

Patch 3 enables the driver on Lenovo Legion Pro models with Realtek
ALC287 fixups and AW88399 per-model quirks.

Link to v1: https://lore.kernel.org/linux-sound/DS7PR19MB77247D9AD698CF0FF37DB58BFCC62@DS7PR19MB7724.namprd19.prod.outlook.com/T/#t

Marco Giunta (3):
  ACPI/platform: add AWDZ8399 to serial-multi-instantiate
  ALSA: hda/scodec: add AW88399 HDA side codec driver
  ALSA: hda/realtek: enable AW88399 on Lenovo Legion Pro

 drivers/acpi/scan.c                           |   1 +
 .../platform/x86/serial-multi-instantiate.c   |  10 +
 sound/hda/codecs/realtek/alc269.c             |  50 +++
 sound/hda/codecs/side-codecs/Kconfig          |  18 +
 sound/hda/codecs/side-codecs/Makefile         |   4 +
 sound/hda/codecs/side-codecs/aw88399_hda.c    | 372 ++++++++++++++++++
 sound/hda/codecs/side-codecs/aw88399_hda.h    |  36 ++
 .../hda/codecs/side-codecs/aw88399_hda_i2c.c  |  54 +++
 8 files changed, 545 insertions(+)
 create mode 100644 sound/hda/codecs/side-codecs/aw88399_hda.c
 create mode 100644 sound/hda/codecs/side-codecs/aw88399_hda.h
 create mode 100644 sound/hda/codecs/side-codecs/aw88399_hda_i2c.c


base-commit: 882fbdfafa8a373c1b544db6a9839c5c8a0d7780
-- 
2.55.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v2 1/3] ACPI/platform: add AWDZ8399 to serial-multi-instantiate
  2026-07-29  9:33 [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion Marco Giunta
@ 2026-07-29  9:33 ` Marco Giunta
  2026-07-29  9:33 ` [PATCH v2 2/3] ALSA: hda/scodec: add AW88399 HDA side codec driver Marco Giunta
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Marco Giunta @ 2026-07-29  9:33 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Jaroslav Kysela, Liam Girdwood, Mark Brown, linux-kernel,
	linux-sound, Rafael J. Wysocki, Len Brown, Hans de Goede,
	Ilpo Järvinen, linux-acpi, platform-driver-x86, Weidong Wang,
	Nadim Kobeissi, Xia Yun'an, Munzir Taha, Yakov Till,
	Marco Giunta

Register the AWINIC AW88399 ACPI hardware ID "AWDZ8399" with the
serial-multi-instantiate driver and add it to the ACPI scan ignore
list so that the two I2C amplifier instances on Lenovo Legion laptops
are enumerated as separate I2C client devices rather than a single
ACPI platform device.

The SMI node creates two instances named "aw88399-hda" with
IRQ_RESOURCE_AUTO, matching the pattern used by CS35L41.

Tested-by: Nadim Kobeissi <nadim@symbolic.software>
Tested-by: Xia Yun'an <imitoy@imitoy.top>
Tested-by: Munzir Taha <munzirtaha@gmail.com>
Acked-by: Rafael J. Wysocki (Intel) <rafael@kernel.org>
Acked-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Co-developed-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Marco Giunta <marco_giunta@outlook.it>
---
 drivers/acpi/scan.c                             |  1 +
 drivers/platform/x86/serial-multi-instantiate.c | 10 ++++++++++
 2 files changed, 11 insertions(+)

diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 9a7ac2eb9ce0..4f4552b1551b 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1752,6 +1752,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
 	 * by the drivers/platform/x86/serial-multi-instantiate.c driver, which
 	 * knows which client device id to use for each resource.
 	 */
+		{"AWDZ8399", },
 		{"BSG1160", },
 		{"BSG2150", },
 		{"CSC3551", },
diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c
index 1a369334f9cb..3e89fcdd45f7 100644
--- a/drivers/platform/x86/serial-multi-instantiate.c
+++ b/drivers/platform/x86/serial-multi-instantiate.c
@@ -307,6 +307,15 @@ static void smi_remove(struct platform_device *pdev)
 	smi_devs_unregister(smi);
 }
 
+static const struct smi_node aw88399_hda = {
+	.instances = {
+		{ "aw88399-hda", IRQ_RESOURCE_AUTO, 0 },
+		{ "aw88399-hda", IRQ_RESOURCE_AUTO, 0 },
+		{}
+	},
+	.bus_type = SMI_AUTO_DETECT,
+};
+
 static const struct smi_node bsg1160_data = {
 	.instances = {
 		{ "bmc150_accel", IRQ_RESOURCE_GPIO, 0 },
@@ -405,6 +414,7 @@ static const struct smi_node tas2781_hda = {
  * drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
  */
 static const struct acpi_device_id smi_acpi_ids[] = {
+	{ "AWDZ8399", (unsigned long)&aw88399_hda },
 	{ "BSG1160", (unsigned long)&bsg1160_data },
 	{ "BSG2150", (unsigned long)&bsg2150_data },
 	{ "CSC3551", (unsigned long)&cs35l41_hda },
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v2 2/3] ALSA: hda/scodec: add AW88399 HDA side codec driver
  2026-07-29  9:33 [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion Marco Giunta
  2026-07-29  9:33 ` [PATCH v2 1/3] ACPI/platform: add AWDZ8399 to serial-multi-instantiate Marco Giunta
@ 2026-07-29  9:33 ` Marco Giunta
  2026-07-29  9:33 ` [PATCH v2 3/3] ALSA: hda/realtek: enable AW88399 on Lenovo Legion Pro Marco Giunta
  2026-07-30  9:30 ` [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion Takashi Iwai
  3 siblings, 0 replies; 5+ messages in thread
From: Marco Giunta @ 2026-07-29  9:33 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Jaroslav Kysela, Liam Girdwood, Mark Brown, linux-kernel,
	linux-sound, Rafael J. Wysocki, Len Brown, Hans de Goede,
	Ilpo Järvinen, linux-acpi, platform-driver-x86, Weidong Wang,
	Nadim Kobeissi, Xia Yun'an, Munzir Taha, Yakov Till,
	Marco Giunta

Add an HDA side codec driver for the AWINIC AW88399 smart amplifier,
enabling its use as a companion amplifier on HDA systems where the
chip is connected via I2C to the host and driven alongside a primary
HDA codec (such as Realtek ALC287).

The driver is structured after the existing side codec drivers:

* aw88399_hda_i2c.c: I2C bus driver matching ACPI HID "AWDZ8399" and
  serial-multi-instantiate device name "aw88399-hda".
  Creates the regmap and passes it to the shared probe function,
  following the CS35L41/CS35L56/TAS2781 pattern.

* aw88399_hda.c: Core driver implementing HDA component binding,
  playback hooks (using the shared library's start/stop functions),
  ACPI subsystem ID retrieval, and runtime/system power management.
  Includes per-model quirk infrastructure using ACPI subsystem ID
  matching; the quirk table is empty in this patch and populated in
  the next patch along with the corresponding Realtek fixups that
  activate the driver.

The driver includes <sound/aw88399.h> for shared definitions and
depends on SND_SOC_AW88399_LIB for chip initialization, firmware
loading, and playback control, avoiding any dependency on the full
ASoC codec module.

Tested-by: Nadim Kobeissi <nadim@symbolic.software>
Tested-by: Xia Yun'an <imitoy@imitoy.top>
Tested-by: Munzir Taha <munzirtaha@gmail.com>
Co-developed-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Marco Giunta <marco_giunta@outlook.it>
---
 sound/hda/codecs/side-codecs/Kconfig          |  18 +
 sound/hda/codecs/side-codecs/Makefile         |   4 +
 sound/hda/codecs/side-codecs/aw88399_hda.c    | 330 ++++++++++++++++++
 sound/hda/codecs/side-codecs/aw88399_hda.h    |  36 ++
 .../hda/codecs/side-codecs/aw88399_hda_i2c.c  |  54 +++
 5 files changed, 442 insertions(+)
 create mode 100644 sound/hda/codecs/side-codecs/aw88399_hda.c
 create mode 100644 sound/hda/codecs/side-codecs/aw88399_hda.h
 create mode 100644 sound/hda/codecs/side-codecs/aw88399_hda_i2c.c

diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
index 1cfd83e251e4..f90f1dfcec68 100644
--- a/sound/hda/codecs/side-codecs/Kconfig
+++ b/sound/hda/codecs/side-codecs/Kconfig
@@ -13,6 +13,24 @@ config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
 	  Documentation/dev-tools/kunit/.
 	  If in doubt, say "N".
 
+config SND_HDA_SCODEC_AW88399
+	tristate
+	select SND_HDA_GENERIC
+
+config SND_HDA_SCODEC_AW88399_I2C
+	tristate "Build AW88399 HD-audio side codec support for I2C Bus"
+	depends on I2C
+	depends on ACPI
+	depends on SND_SOC
+	select SND_HDA_SCODEC_AW88399
+	select SND_SOC_AW88399_LIB
+	help
+	  Say Y or M here to include AW88399 I2C HD-audio side codec support
+	  in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+	depends on SND_HDA=y && SND_HDA_SCODEC_AW88399_I2C=m
+
 config SND_HDA_SCODEC_CS35L41
 	tristate
 	select SND_HDA_GENERIC
diff --git a/sound/hda/codecs/side-codecs/Makefile b/sound/hda/codecs/side-codecs/Makefile
index 245e84f6a121..7dd010c68f78 100644
--- a/sound/hda/codecs/side-codecs/Makefile
+++ b/sound/hda/codecs/side-codecs/Makefile
@@ -3,6 +3,8 @@ subdir-ccflags-y += -I$(src)/../../common
 
 snd-hda-cirrus-scodec-y :=	cirrus_scodec.o
 snd-hda-cirrus-scodec-test-y :=	cirrus_scodec_test.o
+snd-hda-scodec-aw88399-y :=	aw88399_hda.o
+snd-hda-scodec-aw88399-i2c-y :=	aw88399_hda_i2c.o
 snd-hda-scodec-cs35l41-y :=	cs35l41_hda.o cs35l41_hda_property.o
 snd-hda-scodec-cs35l41-i2c-y :=	cs35l41_hda_i2c.o
 snd-hda-scodec-cs35l41-spi-y :=	cs35l41_hda_spi.o
@@ -16,6 +18,8 @@ snd-hda-scodec-tas2781-spi-y :=	tas2781_hda_spi.o
 
 obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o
 obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.o
+obj-$(CONFIG_SND_HDA_SCODEC_AW88399) += snd-hda-scodec-aw88399.o
+obj-$(CONFIG_SND_HDA_SCODEC_AW88399_I2C) += snd-hda-scodec-aw88399-i2c.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda.c b/sound/hda/codecs/side-codecs/aw88399_hda.c
new file mode 100644
index 000000000000..ed57d9a4a39d
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/aw88399_hda.c
@@ -0,0 +1,330 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// AW88399 HDA side codec driver
+//
+// Based on cs35l41_hda.c and aw88399.c
+//
+
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/string.h>
+#include <sound/hda_codec.h>
+#include "../generic.h"
+#include "hda_component.h"
+#include "aw88399_hda.h"
+
+#define AW88399_HDA_I2C_BASE_ADDR	0x34
+
+static void aw88399_hda_playback_hook(struct device *dev, int action)
+{
+	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+	struct aw88399 *core = aw88399->core;
+	int ret = 0;
+
+	dev_dbg(aw88399->dev, "Playback action: %d\n", action);
+
+	switch (action) {
+	case HDA_GEN_PCM_ACT_OPEN:
+		pm_runtime_get_sync(dev);
+		aw88399->playing = true;
+		break;
+	case HDA_GEN_PCM_ACT_PREPARE:
+		if (core)
+			aw88399_start(core, AW88399_SYNC_START);
+		break;
+	case HDA_GEN_PCM_ACT_CLEANUP:
+		if (aw88399->aw_dev)
+			ret = aw88399_stop(aw88399->aw_dev);
+		if (ret)
+			dev_err(aw88399->dev, "Failed to stop amplifier: %d\n", ret);
+		break;
+	case HDA_GEN_PCM_ACT_CLOSE:
+		if (aw88399->aw_dev)
+			aw88399_stop(aw88399->aw_dev);
+		aw88399->playing = false;
+		pm_runtime_mark_last_busy(dev);
+		pm_runtime_put_autosuspend(dev);
+		break;
+	default:
+		dev_warn(aw88399->dev, "Unsupported action: %d\n", action);
+		break;
+	}
+}
+
+static int aw88399_hda_bind(struct device *dev, struct device *master, void *master_data)
+{
+	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+	struct hda_component_parent *parent = master_data;
+	struct hda_component *comp;
+
+	comp = hda_component_from_index(parent, aw88399->index);
+	if (!comp)
+		return -EINVAL;
+
+	if (comp->dev)
+		return -EBUSY;
+
+	comp->dev = dev;
+
+	strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+
+	comp->playback_hook = aw88399_hda_playback_hook;
+
+	dev_info(aw88399->dev,
+		 "AW88399 Bound - SSID: %s, channel: %d\n",
+		 aw88399->acpi_subsystem_id, aw88399->channel);
+
+	return 0;
+}
+
+static void aw88399_hda_unbind(struct device *dev, struct device *master, void *master_data)
+{
+	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+	struct hda_component_parent *parent = master_data;
+	struct hda_component *comp;
+
+	comp = hda_component_from_index(parent, aw88399->index);
+	if (comp && (comp->dev == dev))
+		memset(comp, 0, sizeof(*comp));
+
+	dev_dbg(aw88399->dev, "Unbound from HDA codec\n");
+}
+
+static const struct component_ops aw88399_hda_comp_ops = {
+	.bind = aw88399_hda_bind,
+	.unbind = aw88399_hda_unbind,
+};
+
+static int aw88399_hda_index_from_i2c(struct aw88399_hda *aw88399)
+{
+	return to_i2c_client(aw88399->dev)->addr - AW88399_HDA_I2C_BASE_ADDR;
+}
+
+static int aw88399_hda_init(struct aw88399_hda *aw88399)
+{
+	struct device *dev = aw88399->dev;
+	struct i2c_client *i2c = to_i2c_client(dev);
+	struct aw88399 *core;
+	int ret;
+
+	core = devm_kzalloc(dev, sizeof(*core), GFP_KERNEL);
+	if (!core)
+		return -ENOMEM;
+
+	mutex_init(&core->lock);
+	core->reset_gpio = aw88399->reset_gpio;
+	core->regmap = aw88399->regmap;
+	core->bsts_unreliable = aw88399->bsts_unreliable;
+
+	aw88399_hw_reset(core);
+
+	ret = aw88399_init(core, i2c, aw88399->regmap);
+	if (ret)
+		return ret;
+
+	/* Set channel BEFORE loading firmware so ACF parser sees correct value */
+	if (core->aw_pa)
+		aw88399_dev_set_channel(core, aw88399->channel);
+
+	ret = aw88399_request_firmware_file(core);
+	if (ret)
+		return ret;
+
+	aw88399->core = core;
+	aw88399->aw_dev = core->aw_pa;
+
+	return 0;
+}
+
+struct aw88399_prop_model {
+	const char *ssid;
+	int (*apply_prop)(struct aw88399_hda *aw88399);
+};
+
+static const struct aw88399_prop_model aw88399_prop_model_table[] = {
+	{ }
+};
+
+static int aw88399_hda_acpi_probe(struct aw88399_hda *aw88399)
+{
+	struct acpi_device *adev;
+	struct device *physdev;
+	const char *sub;
+	const struct aw88399_prop_model *model;
+
+	aw88399->index = aw88399_hda_index_from_i2c(aw88399);
+	aw88399->channel = aw88399->index;
+	aw88399->acpi_subsystem_id = NULL;
+
+	adev = acpi_dev_get_first_match_dev("AWDZ8399", NULL, -1);
+	if (!adev) {
+		dev_err(aw88399->dev, "Failed to find an ACPI device for AWDZ8399\n");
+		return -ENODEV;
+	}
+
+	physdev = get_device(acpi_get_first_physical_node(adev));
+	acpi_dev_put(adev);
+	if (!physdev)
+		return -ENODEV;
+
+	sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
+	put_device(physdev);
+	if (IS_ERR_OR_NULL(sub))
+		return 0;
+
+	aw88399->acpi_subsystem_id = devm_kstrdup(aw88399->dev, sub, GFP_KERNEL);
+	kfree(sub);
+	if (!aw88399->acpi_subsystem_id)
+		return -ENOMEM;
+
+	for (model = aw88399_prop_model_table; model->ssid; model++) {
+		if (!strcasecmp(model->ssid, aw88399->acpi_subsystem_id)) {
+			dev_info(aw88399->dev,
+				 "Applying properties for SSID %s\n",
+				 aw88399->acpi_subsystem_id);
+			return model->apply_prop(aw88399);
+		}
+	}
+
+	return 0;
+}
+
+int aw88399_hda_probe(struct device *dev, struct regmap *regmap)
+{
+	struct aw88399_hda *aw88399;
+	int ret;
+
+	aw88399 = devm_kzalloc(dev, sizeof(*aw88399), GFP_KERNEL);
+	if (!aw88399)
+		return -ENOMEM;
+
+	if (IS_ERR(regmap))
+		return dev_err_probe(dev, PTR_ERR(regmap), "Failed to obtain regmap\n");
+
+	aw88399->dev = dev;
+	aw88399->regmap = regmap;
+	dev_set_drvdata(dev, aw88399);
+
+	aw88399->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
+	if (IS_ERR(aw88399->reset_gpio))
+		return dev_err_probe(dev, PTR_ERR(aw88399->reset_gpio),
+				     "Failed to get reset GPIO\n");
+
+	ret = aw88399_hda_acpi_probe(aw88399);
+	if (ret)
+		return dev_err_probe(dev, ret, "ACPI probe failed\n");
+
+	ret = aw88399_hda_init(aw88399);
+	if (ret)
+		return dev_err_probe(dev, ret, "Chip initialization failed\n");
+
+	/* Enable runtime PM */
+	pm_runtime_set_autosuspend_delay(dev, 3000);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_set_active(dev);
+	pm_runtime_enable(dev);
+
+	ret = component_add(dev, &aw88399_hda_comp_ops);
+	if (ret) {
+		pm_runtime_disable(dev);
+		return dev_err_probe(dev, ret, "Failed to register component\n");
+	}
+
+	dev_info(dev, "AW88399 HDA side codec registered successfully\n");
+
+	return 0;
+}
+EXPORT_SYMBOL_NS_GPL(aw88399_hda_probe, "SND_HDA_SCODEC_AW88399");
+
+void aw88399_hda_remove(struct device *dev)
+{
+	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+
+	pm_runtime_disable(dev);
+
+	if (aw88399->aw_dev)
+		aw88399_stop(aw88399->aw_dev);
+
+	component_del(dev, &aw88399_hda_comp_ops);
+
+	dev_dbg(aw88399->dev, "AW88399 HDA side codec removed\n");
+}
+EXPORT_SYMBOL_NS_GPL(aw88399_hda_remove, "SND_HDA_SCODEC_AW88399");
+
+static int aw88399_hda_runtime_suspend(struct device *dev)
+{
+	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+
+	dev_dbg(aw88399->dev, "Runtime suspend\n");
+
+	if (aw88399->aw_dev && aw88399->playing)
+		aw88399_stop(aw88399->aw_dev);
+
+	return 0;
+}
+
+static int aw88399_hda_runtime_resume(struct device *dev)
+{
+	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+
+	dev_dbg(aw88399->dev, "Runtime resume\n");
+
+	if (aw88399->core && aw88399->aw_dev && aw88399->playing)
+		aw88399_start(aw88399->core, AW88399_SYNC_START);
+
+	return 0;
+}
+
+static int aw88399_hda_system_suspend(struct device *dev)
+{
+	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+	int ret;
+
+	dev_dbg(aw88399->dev, "System suspend\n");
+
+	if (aw88399->aw_dev && aw88399->playing)
+		aw88399_stop(aw88399->aw_dev);
+
+	if (aw88399->core)
+		aw88399->core->fw_needs_reload = true;
+
+	ret = pm_runtime_force_suspend(dev);
+	if (ret)
+		dev_err(aw88399->dev, "Runtime force suspend failed: %d\n", ret);
+
+	return ret;
+}
+
+static int aw88399_hda_system_resume(struct device *dev)
+{
+	struct aw88399_hda *aw88399 = dev_get_drvdata(dev);
+	int ret;
+
+	dev_dbg(aw88399->dev, "System resume\n");
+
+	if (aw88399->aw_dev)
+		aw88399_hw_reset(aw88399->core);
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret)
+		dev_err(aw88399->dev, "Runtime force resume failed: %d\n", ret);
+
+	return ret;
+}
+
+const struct dev_pm_ops aw88399_hda_pm_ops = {
+	RUNTIME_PM_OPS(aw88399_hda_runtime_suspend, aw88399_hda_runtime_resume, NULL)
+	SYSTEM_SLEEP_PM_OPS(aw88399_hda_system_suspend, aw88399_hda_system_resume)
+};
+EXPORT_SYMBOL_NS_GPL(aw88399_hda_pm_ops, "SND_HDA_SCODEC_AW88399");
+
+MODULE_DESCRIPTION("AW88399 HDA driver");
+MODULE_AUTHOR("Yakov Till <yakov.till@gmail.com>");
+MODULE_AUTHOR("Marco Giunta <marco_giunta@outlook.it>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("aw88399_acf.bin");
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda.h b/sound/hda/codecs/side-codecs/aw88399_hda.h
new file mode 100644
index 000000000000..ca0aa5279298
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/aw88399_hda.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * AW88399 HDA side codec driver
+ */
+
+#ifndef __AW88399_HDA_H__
+#define __AW88399_HDA_H__
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <sound/aw88399.h>
+
+struct aw88399;
+struct aw_device;
+
+struct aw88399_hda {
+	struct device *dev;
+	struct regmap *regmap;
+	struct gpio_desc *reset_gpio;
+	struct aw_device *aw_dev;
+	struct aw88399 *core;
+	bool bsts_unreliable;
+
+	const char *acpi_subsystem_id;
+	int index;
+	int channel;
+
+	bool playing;
+};
+
+int aw88399_hda_probe(struct device *dev, struct regmap *regmap);
+void aw88399_hda_remove(struct device *dev);
+
+extern const struct dev_pm_ops aw88399_hda_pm_ops;
+
+#endif /* __AW88399_HDA_H__ */
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c b/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c
new file mode 100644
index 000000000000..186e13adbc6c
--- /dev/null
+++ b/sound/hda/codecs/side-codecs/aw88399_hda_i2c.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// AW88399 HDA I2C driver
+//
+// Based on cs35l41_hda_i2c.c
+//
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "aw88399_hda.h"
+
+static int aw88399_hda_i2c_probe(struct i2c_client *clt)
+{
+	if (!strstr(dev_name(&clt->dev), "AWDZ8399"))
+		return -ENODEV;
+
+	return aw88399_hda_probe(&clt->dev,
+				 devm_regmap_init_i2c(clt, &aw88399_remap_config));
+}
+
+static void aw88399_hda_i2c_remove(struct i2c_client *clt)
+{
+	aw88399_hda_remove(&clt->dev);
+}
+
+static const struct i2c_device_id aw88399_hda_i2c_id[] = {
+	{ .name = "aw88399-hda" },
+	{ }
+};
+
+static const struct acpi_device_id aw88399_acpi_hda_match[] = {
+	{ "AWDZ8399", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, aw88399_acpi_hda_match);
+
+static struct i2c_driver aw88399_hda_i2c_driver = {
+	.driver = {
+		.name		= "aw88399-hda",
+		.acpi_match_table = aw88399_acpi_hda_match,
+		.pm		= &aw88399_hda_pm_ops,
+	},
+	.probe		= aw88399_hda_i2c_probe,
+	.remove		= aw88399_hda_i2c_remove,
+	.id_table	= aw88399_hda_i2c_id,
+};
+module_i2c_driver(aw88399_hda_i2c_driver);
+
+MODULE_DESCRIPTION("HDA AW88399 I2C driver");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_AW88399");
+MODULE_AUTHOR("Yakov Till <yakov.till@gmail.com>");
+MODULE_LICENSE("GPL");
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v2 3/3] ALSA: hda/realtek: enable AW88399 on Lenovo Legion Pro
  2026-07-29  9:33 [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion Marco Giunta
  2026-07-29  9:33 ` [PATCH v2 1/3] ACPI/platform: add AWDZ8399 to serial-multi-instantiate Marco Giunta
  2026-07-29  9:33 ` [PATCH v2 2/3] ALSA: hda/scodec: add AW88399 HDA side codec driver Marco Giunta
@ 2026-07-29  9:33 ` Marco Giunta
  2026-07-30  9:30 ` [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion Takashi Iwai
  3 siblings, 0 replies; 5+ messages in thread
From: Marco Giunta @ 2026-07-29  9:33 UTC (permalink / raw)
  To: Takashi Iwai
  Cc: Jaroslav Kysela, Liam Girdwood, Mark Brown, linux-kernel,
	linux-sound, Rafael J. Wysocki, Len Brown, Hans de Goede,
	Ilpo Järvinen, linux-acpi, platform-driver-x86, Weidong Wang,
	Nadim Kobeissi, Xia Yun'an, Munzir Taha, Yakov Till,
	Marco Giunta

Enable audio output through the AW88399 woofer amplifiers on Lenovo
Legion laptops by adding the necessary Realtek ALC287 fixups and
AW88399 per-model quirks.

Realtek fixups (alc269.c):

* ALC287_FIXUP_AW88399_I2C_2: registers the AW88399 as a two-instance
  I2C companion codec using comp_generic_fixup, matching ACPI HID
  "AWDZ8399".

* ALC287_FIXUP_LENOVO_LEGION_AW88399: forces DAC 0x02 for the bass
  speaker pin 0x17, as the default DAC 0x06 lacks volume controls.
  Also applies internal microphone boost calibration via
  alc269_fixup_limit_int_mic_boost and disables unused pin 0x1d
  to match the Windows driver's pin configuration.
  Chained to ALC287_FIXUP_AW88399_I2C_2.

Per-model quirks (aw88399_hda.c):

* Channel swap: the I2C wiring on these Legion models is reversed
  (0x34 is physically the right speaker, 0x35 is the left). The
  quirk swaps the channel assignment to correct L/R audio.

* BSTS status bypass: the AW88399's boost-finished status bit (BSTS,
  SYSST register bit 9) does not reliably assert on this hardware.
  Register dumps during normal playback show both amplifiers
  reporting BSTS=0 on both channels despite clean audio output.
  The quirk sets the bsts_unreliable flag, introduced in
  commit b4530a3e4895 ("ASoC: aw88399: add per-instance BSTS status bypass flag"),
  so the startup status check skips the BSTS requirement
  on these devices.

The R9000P ADR10 entries use HDA_CODEC_QUIRK and are placed before
the existing SND_PCI_QUIRK for 17aa:38bb (Yoga S780-14.5 Air) to
ensure the codec SSID match takes priority over the shared PCI SSID,
following the pattern established by e.g.
commit 0f3a822ae225 ("ALSA: hda/realtek: Fix quirk matching for Legion Pro 7"),
commit dd074f04e046 ("ALSA: hda/realtek: Fix Legion 7 16ITHG6 speaker amp binding").
All other entries also use HDA_CODEC_QUIRK for consistency.

Supported models (Lenovo vendor ID 0x17aa):

* 0x3906: Legion Pro 7i 16IAX10H / Y9000P IAX10 (Intel)
* 0x3907: Legion Pro 7i 16IAX10H / Y9000P IAX10 (Intel)
* 0x3927: Legion R9000P ADR10 (AMD)
* 0x3928: Legion R9000P ADR10 (AMD)
* 0x3938: Legion Pro 7 16AFR10H (AMD)
* 0x3939: Legion Pro 7 16AFR10H (AMD)

Tested-by: Nadim Kobeissi <nadim@symbolic.software>
Tested-by: Xia Yun'an <imitoy@imitoy.top>
Tested-by: Munzir Taha <munzirtaha@gmail.com>
Co-developed-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Yakov Till <yakov.till@gmail.com>
Signed-off-by: Marco Giunta <marco_giunta@outlook.it>
---
 sound/hda/codecs/realtek/alc269.c          | 50 ++++++++++++++++++++++
 sound/hda/codecs/side-codecs/aw88399_hda.c | 42 ++++++++++++++++++
 2 files changed, 92 insertions(+)

diff --git a/sound/hda/codecs/realtek/alc269.c b/sound/hda/codecs/realtek/alc269.c
index 6b3c1d529bd1..6384620a2062 100644
--- a/sound/hda/codecs/realtek/alc269.c
+++ b/sound/hda/codecs/realtek/alc269.c
@@ -3262,6 +3262,34 @@ static void find_cirrus_companion_amps(struct hda_codec *cdc)
 	comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count);
 }
 
+static void aw88399_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+	comp_generic_fixup(cdc, action, "i2c", "AWDZ8399", "-%s:00-aw88399-hda.%d", 2);
+}
+
+static void alc287_fixup_legion_16iax10h_aw88399(struct hda_codec *codec,
+						 const struct hda_fixup *fix, int action)
+{
+	static const struct hda_pintbl pincfgs[] = {
+		{ 0x1d, 0x411111f0 }, /* unused bogus pin */
+		{ }
+	};
+
+	/*
+	 * Force DAC 0x02 for the bass speaker 0x17, as the default 0x06 lacks volume controls.
+	 */
+	static const hda_nid_t conn[] = { 0x02 };
+
+	alc269_fixup_limit_int_mic_boost(codec, fix, action);
+
+	switch (action) {
+	case HDA_FIXUP_ACT_PRE_PROBE:
+		snd_hda_apply_pincfgs(codec, pincfgs);
+		snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+		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);
@@ -4231,6 +4259,8 @@ enum {
 	ALC236_FIXUP_DELL_HP_POP_NOISE,
 	ALC274_FIXUP_HP_89E9_GPIO,
 	ALC274_FIXUP_HP_VERBS,
+	ALC287_FIXUP_AW88399_I2C_2,
+	ALC287_FIXUP_LENOVO_LEGION_AW88399,
 };
 
 /* A special fixup for Lenovo C940 and Yoga Duet 7;
@@ -6917,6 +6947,16 @@ static const struct hda_fixup alc269_fixups[] = {
 		.chained = true,
 		.chain_id = ALC274_FIXUP_HP_89E9_GPIO,
 	},
+	[ALC287_FIXUP_AW88399_I2C_2] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = aw88399_fixup_i2c_two,
+	},
+	[ALC287_FIXUP_LENOVO_LEGION_AW88399] = {
+		.type = HDA_FIXUP_FUNC,
+		.v.func = alc287_fixup_legion_16iax10h_aw88399,
+		.chained = true,
+		.chain_id = ALC287_FIXUP_AW88399_I2C_2,
+	},
 };
 
 static const struct hda_quirk alc269_fixup_tbl[] = {
@@ -7975,6 +8015,11 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x38b8, "Yoga S780-14.5 proX AMD YC Dual", ALC287_FIXUP_TAS2781_I2C),
 	SND_PCI_QUIRK(0x17aa, 0x38b9, "Yoga S780-14.5 proX AMD LX Dual", ALC287_FIXUP_TAS2781_I2C),
 	SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C),
+	/* Legion R9000P ADR10 shares PCI SSID 17aa:38bb with Yoga S780-14.5 Air AMD quad AAC;
+	 * use codec SSID to distinguish them
+	 */
+	HDA_CODEC_QUIRK(0x17aa, 0x3927, "Legion R9000P ADR10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+	HDA_CODEC_QUIRK(0x17aa, 0x3928, "Legion R9000P ADR10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
 	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),
 	SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual", ALC287_FIXUP_TAS2781_I2C),
@@ -8002,6 +8047,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x38fc, "Lenovo Yoga Pro 7 15ASH11", ALC287_FIXUP_LENOVO_YOGA_PRO7),
 	SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C),
 	SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
+	HDA_CODEC_QUIRK(0x17aa, 0x3906, "Legion Pro 7i 16IAX10H / Y9000P IAX10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+	HDA_CODEC_QUIRK(0x17aa, 0x3907, "Legion Pro 7i 16IAX10H / Y9000P IAX10", ALC287_FIXUP_LENOVO_LEGION_AW88399),
 	SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
 	SND_PCI_QUIRK(0x17aa, 0x3911, "Lenovo Yoga Pro 7 14IAH10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
 	SND_PCI_QUIRK(0x17aa, 0x3912, "Lenovo Xiaoxin 14 GT", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
@@ -8011,6 +8058,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
 	SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TXNW2781_I2C),
 	SND_PCI_QUIRK(0x17aa, 0x3929, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
 	SND_PCI_QUIRK(0x17aa, 0x392b, "Thinkbook 13x Gen 5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+	HDA_CODEC_QUIRK(0x17aa, 0x3938, "Legion Pro 7 16AFR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
+	HDA_CODEC_QUIRK(0x17aa, 0x3939, "Legion Pro 7 16AFR10H", ALC287_FIXUP_LENOVO_LEGION_AW88399),
 	HDA_CODEC_QUIRK(0x17aa, 0x394c, "Lenovo Yoga Slim 7 14AGP11", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
 	SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
 	SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
@@ -8314,6 +8363,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
 	{.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"},
 	{.id = ALC245_FIXUP_BASS_HP_DAC, .name = "alc245-fixup-bass-hp-dac"},
 	{.id = ALC256_FIXUP_HONOR_MRB_XXX_M1020_AUDIO, .name = "alc256-honor-mrb-xxx-m1020-audio"},
+	{.id = ALC287_FIXUP_LENOVO_LEGION_AW88399, .name = "alc287-lenovo-legion-aw88399"},
 	{}
 };
 #define ALC225_STANDARD_PINS \
diff --git a/sound/hda/codecs/side-codecs/aw88399_hda.c b/sound/hda/codecs/side-codecs/aw88399_hda.c
index ed57d9a4a39d..42de68faddbc 100644
--- a/sound/hda/codecs/side-codecs/aw88399_hda.c
+++ b/sound/hda/codecs/side-codecs/aw88399_hda.c
@@ -140,12 +140,54 @@ static int aw88399_hda_init(struct aw88399_hda *aw88399)
 	return 0;
 }
 
+static int aw88399_swap_channels(struct aw88399_hda *aw88399)
+{
+	/*
+	 * Certain Lenovo Legion laptops have their
+	 * I2C wiring reversed: 0x34 is physically the right speaker,
+	 * 0x35 is the left. Swap channels to correct L/R assignment.
+	 * This is a model-specific hardware wiring issue, not a driver bug.
+	 */
+	aw88399->channel = 1 - aw88399->channel;
+	dev_dbg(aw88399->dev,
+		"Channel swap applied: index %d -> channel %d\n",
+		aw88399->index, aw88399->channel);
+	return 0;
+}
+
+static int aw88399_skip_bsts_check(struct aw88399_hda *aw88399)
+{
+	/*
+	 * BSTS (boost-finished) status bit does not reliably report on
+	 * some hardware. On certain Lenovo Legion laptops, both amps
+	 * report BSTS=0 (boost not finished) during normal playback
+	 * despite clean audio output. Skip BSTS in the startup status
+	 * check to avoid false init failures.
+	 */
+	aw88399->bsts_unreliable = true;
+	dev_dbg(aw88399->dev, "BSTS status check disabled\n");
+	return 0;
+}
+
+static int aw88399_apply_legion_quirks(struct aw88399_hda *aw88399)
+{
+	aw88399_swap_channels(aw88399);
+	aw88399_skip_bsts_check(aw88399);
+	return 0;
+}
+
 struct aw88399_prop_model {
 	const char *ssid;
 	int (*apply_prop)(struct aw88399_hda *aw88399);
 };
 
 static const struct aw88399_prop_model aw88399_prop_model_table[] = {
+	{ "17AA3906", aw88399_apply_legion_quirks },
+	{ "17AA3907", aw88399_apply_legion_quirks },
+	{ "17AA3927", aw88399_apply_legion_quirks },
+	{ "17AA3928", aw88399_apply_legion_quirks },
+	{ "17AA3938", aw88399_apply_legion_quirks },
+	{ "17AA3939", aw88399_apply_legion_quirks },
 	{ }
 };
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion
  2026-07-29  9:33 [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion Marco Giunta
                   ` (2 preceding siblings ...)
  2026-07-29  9:33 ` [PATCH v2 3/3] ALSA: hda/realtek: enable AW88399 on Lenovo Legion Pro Marco Giunta
@ 2026-07-30  9:30 ` Takashi Iwai
  3 siblings, 0 replies; 5+ messages in thread
From: Takashi Iwai @ 2026-07-30  9:30 UTC (permalink / raw)
  To: Marco Giunta
  Cc: Takashi Iwai, Jaroslav Kysela, Liam Girdwood, Mark Brown,
	linux-kernel, linux-sound, Rafael J. Wysocki, Len Brown,
	Hans de Goede, Ilpo Järvinen, linux-acpi,
	platform-driver-x86, Weidong Wang, Nadim Kobeissi, Xia Yun'an,
	Munzir Taha, Yakov Till

On Wed, 29 Jul 2026 11:33:12 +0200,
Marco Giunta wrote:
> 
> This is v2 of the AW88399 HDA side codec driver series. Patches 1-5
> from v1 (ASoC library preparation) were applied by Mark Brown and
> merged into tiwai/sound via broonie/sound. This series contains the
> remaining three patches.
> 
> Changes since v1:
> * Fixed memory leak of acpi_subsystem_id string on probe error paths
>   by switching to devm_kstrdup (bug reported by Sashiko, confirmed
>   by Takashi Iwai)
> * Added Acked-by tags from Rafael J. Wysocki and Ilpo Järvinen
>   for the ACPI/platform changes
> 
> Patch 1 registers the AWINIC ACPI HID "AWDZ8399" with the ACPI
> scan ignore list and the serial-multi-instantiate driver.
> 
> Patch 2 adds the HDA side codec driver: I2C bus driver and core
> driver with HDA component binding, playback hooks, power management,
> and per-model quirk matching.
> 
> Patch 3 enables the driver on Lenovo Legion Pro models with Realtek
> ALC287 fixups and AW88399 per-model quirks.
> 
> Link to v1: https://lore.kernel.org/linux-sound/DS7PR19MB77247D9AD698CF0FF37DB58BFCC62@DS7PR19MB7724.namprd19.prod.outlook.com/T/#t
> 
> Marco Giunta (3):
>   ACPI/platform: add AWDZ8399 to serial-multi-instantiate
>   ALSA: hda/scodec: add AW88399 HDA side codec driver
>   ALSA: hda/realtek: enable AW88399 on Lenovo Legion Pro

Now applied all 3 patches to for-next branch.
If any, let's fix on top of this.


Thanks!

Takashi

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-07-30  9:31 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-29  9:33 [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion Marco Giunta
2026-07-29  9:33 ` [PATCH v2 1/3] ACPI/platform: add AWDZ8399 to serial-multi-instantiate Marco Giunta
2026-07-29  9:33 ` [PATCH v2 2/3] ALSA: hda/scodec: add AW88399 HDA side codec driver Marco Giunta
2026-07-29  9:33 ` [PATCH v2 3/3] ALSA: hda/realtek: enable AW88399 on Lenovo Legion Pro Marco Giunta
2026-07-30  9:30 ` [PATCH v2 0/3] ALSA: hda: Add AW88399 HDA side codec driver for Lenovo Legion Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox