mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/4] ASoC: support the ASUS ROG Xbox Ally X20 audio
@ 2026-11-04 22:57 Matthew Schwartz
  2026-11-04 22:58 ` [PATCH v3 1/4] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA Matthew Schwartz
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Matthew Schwartz @ 2026-11-04 22:57 UTC (permalink / raw)
  To: broonie
  Cc: Matthew Schwartz, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
	Vijendar Mukunda, Venkata Prasad Potturu, Oder Chiou,
	Shenghao Ding, Kevin Lu, Baojun Xu, Sen Wang, Cezary Rojewski,
	Peter Ujfalusi, Bard Liao, Kai Vehmanen, Pierre-Louis Bossart,
	linux-sound, linux-kernel

The ASUS ROG Xbox Ally X20 (RC74XA) moves from the HDA codec and TAS2781
amps of the earlier ROG Ally models to SoundWire on ACP 7.0, with two
TAS2783 amps on link 0 and an RT721 on link 1. Its BIOS marks the ACP as
legacy DMIC only, no machine table entry matches the link layout, and
its TAS2783 firmware in linux-firmware uses the four-field name that
carries the BIOS speaker ID, so the speakers do not work today.

Patches 1 to 3 cover that: the ACP config override so the SoundWire
links are probed, the machine entry, and the speaker ID firmware name.
Patch 4 makes rt721-sdca wait for its power domains to reach PS0, which
removes a burst of full scale samples at the start of headset mic
capture.

Tested on an RC74XA with speaker playback on both amps, headphones, jack
detection, both microphones and suspend.

Changes in v3:
- Dropped the sdw_utils DisCo port list patch, including the hunk Bard
  commented on. With patches 1 and 2 the RC74XA probes the AMD legacy
  machine driver, which skips the amp reference capture link since
  commit 9867312e9fd2 ("ASoC: amd: acp-legacy-mach: skip dai link for
  amp reference stream"), so the SmartAmp capture PCM that failed on
  every open is not created. That commit was already in the base of v1
  and v2, and I had only seen the failure on a kernel without it.
  Pierre-Louis's suggestion to set the TAS2783 ports in the driver still
  applies where the amp reference stream is used, and will follow
  separately along with his point about the data port ranges in the
  regmap callbacks.
- Picked up Pierre-Louis's Reviewed-by on patch 4 (was 5).

Changes in v2:
- Patch 3: try the firmware names in a fixed order, the four-field name
  when SPEAKER_ID is present, then SSID-LINK-0xUID and SSID-LINK-UID,
  so a board with the variable but three-field firmware still loads the
  0x name. Read SPEAKER_ID once at probe into a u32 and only use it
  when it is four bytes. With no PCI parent, try the generic name once
  instead of twice. (Mark, Sashiko)
- Patch 4: only honor empty port lists for codecs whose driver takes its
  ports from DisCo, currently TAS2783. (Mark) Take the stream name and
  DAI link ID from an endpoint that is part of the stream, only run init
  for those endpoints, count the AMD legacy amp capture endpoints by
  their effective direction, and skip an endpoint left with no
  direction. Check the endpoint number against dai_num before using
  its DAI info. (Sashiko) Dropped Vijendar's Reviewed-by because of
  these changes.
- Picked up Vijendar's Reviewed-by on patches 1 and 2.

v2: https://lore.kernel.org/r/20261103200540.3863272-1-matthew.schwartz@linux.dev
v1: https://lore.kernel.org/r/20261016232416.2628603-1-matthew.schwartz@linux.dev

Matthew Schwartz (4):
  ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA
  ASoC: amd: acp: add ACP70 SoundWire machine entry for ASUS RC74XA
  ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name
  ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up

 sound/soc/amd/acp-config.c               |   7 ++
 sound/soc/amd/acp/amd-acp70-acpi-match.c |  44 ++++++++
 sound/soc/codecs/Kconfig                 |   1 +
 sound/soc/codecs/rt721-sdca-sdw.c        |  17 ++++
 sound/soc/codecs/rt721-sdca.c            |  33 ++++++
 sound/soc/codecs/rt721-sdca.h            |   1 +
 sound/soc/codecs/tas2783-sdw.c           | 123 ++++++++++++++++-------
 7 files changed, 187 insertions(+), 39 deletions(-)


base-commit: 2450a9bcd3423612f614ea15ff44966fed189191
-- 
2.56.0


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

* [PATCH v3 1/4] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA
  2026-11-04 22:57 [PATCH v3 0/4] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
@ 2026-11-04 22:58 ` Matthew Schwartz
  2026-11-04 22:58 ` [PATCH v3 2/4] ASoC: amd: acp: add ACP70 SoundWire machine entry for " Matthew Schwartz
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Matthew Schwartz @ 2026-11-04 22:58 UTC (permalink / raw)
  To: broonie
  Cc: Matthew Schwartz, Vijendar Mukunda, Venkata Prasad Potturu,
	Liam Girdwood, Jaroslav Kysela, Takashi Iwai, linux-sound,
	linux-kernel

The ROG Xbox Ally X20 (RC74XA) BIOS reports acp-audio-config-flag 0x10
(FLAG_AMD_LEGACY_ONLY_DMIC) in the ACP _DSD. snd_pci_ps then rejects
the device, so the SoundWire links carrying the two TAS2783 amps and
the RT721 are never scanned.

Add the board to the ACP70 flag override table so snd_pci_ps probes.

Reviewed-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
---
 sound/soc/amd/acp-config.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/sound/soc/amd/acp-config.c b/sound/soc/amd/acp-config.c
index 2fb9789cac0ac..858bb51fa0383 100644
--- a/sound/soc/amd/acp-config.c
+++ b/sound/soc/amd/acp-config.c
@@ -105,6 +105,13 @@ static const struct dmi_system_id acp70_acpi_flag_override_table[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Dell 14S DS14265"),
 		},
 	},
+	{
+		/* ASUS ROG Xbox Ally X20 (Strix Point, ACP 7.0) */
+		.matches = {
+			DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."),
+			DMI_MATCH(DMI_BOARD_NAME, "RC74XA"),
+		},
+	},
 	{}
 };
 
-- 
2.56.0


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

* [PATCH v3 2/4] ASoC: amd: acp: add ACP70 SoundWire machine entry for ASUS RC74XA
  2026-11-04 22:57 [PATCH v3 0/4] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
  2026-11-04 22:58 ` [PATCH v3 1/4] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA Matthew Schwartz
@ 2026-11-04 22:58 ` Matthew Schwartz
  2026-11-04 22:58 ` [PATCH v3 3/4] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name Matthew Schwartz
  2026-11-04 22:58 ` [PATCH v3 4/4] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz
  3 siblings, 0 replies; 5+ messages in thread
From: Matthew Schwartz @ 2026-11-04 22:58 UTC (permalink / raw)
  To: broonie
  Cc: Matthew Schwartz, Vijendar Mukunda, Venkata Prasad Potturu,
	Liam Girdwood, Jaroslav Kysela, Takashi Iwai, linux-sound,
	linux-kernel

The ROG Xbox Ally X20 (RC74XA) has two TAS2783 amps on link 0 with
unique IDs 0x8 and 0xB and an RT721 on link 1. No table entry describes
that layout, so machine selection falls through to acp70_rt721_only and
routes speaker playback to the unused RT721 amp endpoint.

Add a two-link entry ahead of acp70_rt721_only with the RT721 limited
to its jack and DMIC endpoints.

Reviewed-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
---
 sound/soc/amd/acp/amd-acp70-acpi-match.c | 44 ++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/sound/soc/amd/acp/amd-acp70-acpi-match.c b/sound/soc/amd/acp/amd-acp70-acpi-match.c
index c2f0479301ebd..0c1a7a70ce146 100644
--- a/sound/soc/amd/acp/amd-acp70-acpi-match.c
+++ b/sound/soc/amd/acp/amd-acp70-acpi-match.c
@@ -739,6 +739,45 @@ static const struct snd_soc_acpi_link_adr acp70_tas2783x2_l0u9c_rt712_vb_l1u0[]
 	{}
 };
 
+static const struct snd_soc_acpi_adr_device tas2783x2_l0u8b_adr[] = {
+	{
+		.adr = 0x0000380102000001ull,
+		.num_endpoints = 1,
+		.endpoints = &spk_l_endpoint,
+		.name_prefix = "tas2783-1",
+	},
+	{
+		.adr = 0x00003B0102000001ull,
+		.num_endpoints = 1,
+		.endpoints = &spk_r_endpoint,
+		.name_prefix = "tas2783-2",
+	},
+};
+
+static const struct snd_soc_acpi_adr_device rt721_l1u0_jack_dmic_adr[] = {
+	{
+		.adr = 0x000130025D072101ull,
+		.num_endpoints = ARRAY_SIZE(jack_dmic_endpoints),
+		.endpoints = jack_dmic_endpoints,
+		.name_prefix = "rt721",
+	}
+};
+
+/* ASUS ROG Xbox Ally X20 (RC74XA) */
+static const struct snd_soc_acpi_link_adr acp70_tas2783x2_l0u8b_rt721_l1u0[] = {
+	{
+		.mask = BIT(0),
+		.num_adr = ARRAY_SIZE(tas2783x2_l0u8b_adr),
+		.adr_d = tas2783x2_l0u8b_adr,
+	},
+	{
+		.mask = BIT(1),
+		.num_adr = ARRAY_SIZE(rt721_l1u0_jack_dmic_adr),
+		.adr_d = rt721_l1u0_jack_dmic_adr,
+	},
+	{}
+};
+
 static const struct snd_soc_acpi_endpoint rt721_endpoints[] = {
 	{ /* Jack Playback/Capture Endpoint (AIF1) */
 		.num = 0,
@@ -906,6 +945,11 @@ struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[] = {
 		.links = acp70_rt721_l1u0_tas2783x2_l1u8b,
 		.drv_name = "amd_sdw",
 	},
+	{
+		.link_mask = BIT(0) | BIT(1),
+		.links = acp70_tas2783x2_l0u8b_rt721_l1u0,
+		.drv_name = "amd_sdw",
+	},
 	{
 		.link_mask = BIT(1),
 		.links = acp70_rt721_only,
-- 
2.56.0


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

* [PATCH v3 3/4] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name
  2026-11-04 22:57 [PATCH v3 0/4] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
  2026-11-04 22:58 ` [PATCH v3 1/4] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA Matthew Schwartz
  2026-11-04 22:58 ` [PATCH v3 2/4] ASoC: amd: acp: add ACP70 SoundWire machine entry for " Matthew Schwartz
@ 2026-11-04 22:58 ` Matthew Schwartz
  2026-11-04 22:58 ` [PATCH v3 4/4] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz
  3 siblings, 0 replies; 5+ messages in thread
From: Matthew Schwartz @ 2026-11-04 22:58 UTC (permalink / raw)
  To: broonie
  Cc: Matthew Schwartz, Shenghao Ding, Kevin Lu, Baojun Xu, Sen Wang,
	Liam Girdwood, Jaroslav Kysela, Takashi Iwai, linux-sound,
	linux-kernel

Some boards have TAS2783 firmware in linux-firmware named
SSID-SPKID-LINK-0xUID.bin, with a speaker ID ahead of the link ID (the
HP 8EA1 has its amps on link 0 and ships 8EA1-{0,1}-0-0x*.bin). The
driver only builds the three-field SSID-LINK-0xUID name, so these boards
never load firmware. On the ASUS ROG Xbox Ally X20 (SSID 1954) the BIOS
provides the speaker ID in a 4-byte SPEAKER_ID EFI variable, and only
the four-field 1954-*-*-0x*.bin files exist.

Read SPEAKER_ID once at probe and try the firmware names in a fixed
order: the four-field name when the variable is present, then the
current SSID-LINK-0xUID name and the unprefixed SSID-LINK-UID one.
Boards without the variable keep the current names and order.

Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
---
 sound/soc/codecs/tas2783-sdw.c | 123 ++++++++++++++++++++++-----------
 1 file changed, 84 insertions(+), 39 deletions(-)

diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index a57230e01f755..02fe74d457bfc 100644
--- a/sound/soc/codecs/tas2783-sdw.c
+++ b/sound/soc/codecs/tas2783-sdw.c
@@ -46,6 +46,8 @@
 #define TAS2783_PROBE_TIMEOUT 5000
 #define TAS2783_CALI_GUID EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, \
 				   0x09, 0x43, 0xa3, 0xf4, 0x31, 0x0a, 0x92)
+#define TAS2783_SPKID_GUID EFI_GUID(0xaa61eaaf, 0x6e83, 0x7523, 0xb0, \
+				    0xd0, 0x7d, 0xf7, 0x4b, 0xb2, 0x4a, 0x81)
 
 static const u32 tas2783_cali_reg[] = {
 	TAS2783_CAL_R0,
@@ -102,8 +104,13 @@ struct tas2783_prv {
 	wait_queue_head_t fw_wait;
 	bool fw_dl_task_done;
 	bool fw_dl_success;
-	/* use fallback fw name */
-	bool fw_use_fallback;
+	/* the file for the firmware name being tried is missing */
+	bool fw_missing;
+#if IS_ENABLED(CONFIG_PCI)
+	/* UEFI speaker ID */
+	u32 spk_id;
+	bool spk_id_valid;
+#endif
 };
 
 static const struct reg_default tas2783_reg_default[] = {
@@ -757,19 +764,11 @@ static void tas2783_fw_ready(const struct firmware *fmw, void *context)
 		goto out;
 	}
 
-	/* firmware binary not found*/
+	/* firmware binary not found, tas_io_init() tries the next name */
 	if (!fmw || !fmw->data) {
-		if (!tas_dev->fw_use_fallback) {
-			tas_dev->fw_use_fallback = true;
-			dev_info(tas_dev->dev,
-				"Failed to read preferred fw binary: %s, attempting fallback binary load\n",
-				tas_dev->rca_binaryname);
-		} else {
-			dev_err(tas_dev->dev,
-				"Failed to read fallback fw binary %s\n",
-				tas_dev->rca_binaryname);
-		}
-
+		tas_dev->fw_missing = true;
+		dev_info(tas_dev->dev, "Failed to read fw binary %s\n",
+			 tas_dev->rca_binaryname);
 		ret = -EINVAL;
 		goto out;
 	}
@@ -1156,42 +1155,79 @@ static const struct dev_pm_ops tas2783_sdca_pm = {
 	RUNTIME_PM_OPS(tas2783_sdca_dev_suspend, tas2783_sdca_dev_resume, NULL)
 };
 
-static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t size)
+#if IS_ENABLED(CONFIG_PCI)
+/* BIOS speaker ID that selects the SSID-SPKID-LINK-UID firmware name */
+static int tas2783_get_spk_id(u32 *spk_id)
+{
+	efi_guid_t guid = TAS2783_SPKID_GUID;
+	unsigned long size = sizeof(*spk_id);
+	efi_status_t status;
+
+	if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE))
+		return -ENOENT;
+
+	status = efi.get_variable(L"SPEAKER_ID", &guid, NULL, &size, spk_id);
+	if (status != EFI_SUCCESS || size != sizeof(*spk_id))
+		return -ENOENT;
+
+	return 0;
+}
+#endif
+
+/*
+ * Firmware names in the order they are tried: SSID-SPKID-LINK-0xUID when the
+ * BIOS has a speaker ID, then SSID-LINK-0xUID and SSID-LINK-UID.
+ */
+static bool tas_generate_fw_name(struct sdw_slave *slave, unsigned int idx,
+				 char *name, size_t size)
 {
 	struct sdw_bus *bus = slave->bus;
 	u8 unique_id = slave->id.unique_id;
-	bool pci_found = false;
 #if IS_ENABLED(CONFIG_PCI)
-	struct device *dev = &slave->dev;
 	struct tas2783_prv *tas_dev = dev_get_drvdata(&slave->dev);
-	struct pci_dev *pci = NULL;
-	const char *fw_uid_prefix = tas_dev->fw_use_fallback ? "" : "0x";
-
-	for (; dev; dev = dev->parent) {
-		if (dev->bus == &pci_bus_type) {
-			pci = to_pci_dev(dev);
-			scnprintf(name, size, "%04X-%1X-%s%1X.bin",
-				  pci->subsystem_device, bus->link_id,
-				  fw_uid_prefix, unique_id);
-			pci_found = true;
-			break;
+	struct device *dev;
+
+	for (dev = &slave->dev; dev; dev = dev->parent) {
+		u16 ssid;
+
+		if (dev->bus != &pci_bus_type)
+			continue;
+
+		ssid = to_pci_dev(dev)->subsystem_device;
+		if (!tas_dev->spk_id_valid)
+			idx++;
+
+		switch (idx) {
+		case 0:
+			scnprintf(name, size, "%04X-%X-%1X-0x%1X.bin", ssid,
+				  tas_dev->spk_id, bus->link_id, unique_id);
+			return true;
+		case 1:
+			scnprintf(name, size, "%04X-%1X-0x%1X.bin", ssid,
+				  bus->link_id, unique_id);
+			return true;
+		case 2:
+			scnprintf(name, size, "%04X-%1X-%1X.bin", ssid,
+				  bus->link_id, unique_id);
+			return true;
+		default:
+			return false;
 		}
 	}
 #endif
 
-	if (!pci_found)
-		scnprintf(name, size, "tas2783-%1X-%1X.bin",
-			  bus->link_id, unique_id);
+	if (idx)
+		return false;
+
+	scnprintf(name, size, "tas2783-%1X-%1X.bin", bus->link_id, unique_id);
+	return true;
 }
 
-static s32 tas_fw_load(struct tas2783_prv *tas_dev, struct sdw_slave *slave)
+static s32 tas_fw_load(struct tas2783_prv *tas_dev)
 {
 	s32 ret;
 	u8 unique_id = tas_dev->sdw_peripheral->id.unique_id;
 
-	tas_generate_fw_name(slave, tas_dev->rca_binaryname,
-			     sizeof(tas_dev->rca_binaryname));
-
 	tas_dev->fw_dl_task_done = false;
 	ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT,
 				      tas_dev->rca_binaryname, tas_dev->dev,
@@ -1216,6 +1252,7 @@ static s32 tas_fw_load(struct tas2783_prv *tas_dev, struct sdw_slave *slave)
 static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
 {
 	struct tas2783_prv *tas_dev = dev_get_drvdata(dev);
+	unsigned int i;
 	s32 ret;
 
 	if (tas_dev->hw_init)
@@ -1230,10 +1267,15 @@ static s32 tas_io_init(struct device *dev, struct sdw_slave *slave)
 	}
 	usleep_range(2000, 2200);
 
-	tas_dev->fw_use_fallback = false;
-	ret = tas_fw_load(tas_dev, slave);
-	if (!ret && tas_dev->fw_use_fallback)
-		ret = tas_fw_load(tas_dev, slave);
+	for (i = 0; tas_generate_fw_name(slave, i, tas_dev->rca_binaryname,
+					 sizeof(tas_dev->rca_binaryname)); i++) {
+		tas_dev->fw_missing = false;
+		ret = tas_fw_load(tas_dev);
+		if (ret || !tas_dev->fw_missing)
+			break;
+	}
+	if (tas_dev->fw_missing)
+		dev_err(dev, "no firmware binary found\n");
 
 	if (!ret) {
 		if (tas_dev->sa_func_data)
@@ -1427,6 +1469,9 @@ static s32 tas_sdw_probe(struct sdw_slave *peripheral,
 	tas_dev->fw_version = 0;
 	mutex_init(&tas_dev->calib_lock);
 	mutex_init(&tas_dev->pde_lock);
+#if IS_ENABLED(CONFIG_PCI)
+	tas_dev->spk_id_valid = !tas2783_get_spk_id(&tas_dev->spk_id);
+#endif
 
 	init_waitqueue_head(&tas_dev->fw_wait);
 	dev_set_drvdata(dev, tas_dev);
-- 
2.56.0


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

* [PATCH v3 4/4] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up
  2026-11-04 22:57 [PATCH v3 0/4] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
                   ` (2 preceding siblings ...)
  2026-11-04 22:58 ` [PATCH v3 3/4] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name Matthew Schwartz
@ 2026-11-04 22:58 ` Matthew Schwartz
  3 siblings, 0 replies; 5+ messages in thread
From: Matthew Schwartz @ 2026-11-04 22:58 UTC (permalink / raw)
  To: broonie
  Cc: Matthew Schwartz, Pierre-Louis Bossart, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, Oder Chiou, linux-sound,
	linux-kernel

The PDE event handlers write REQUESTED_PS and return, so DAPM unmutes
the feature unit and the stream starts while the power domain is still
transitioning. On the ASUS ROG Xbox Ally X20 the first headset mic
capture after the capture path powers down starts with about 0.45 s
pinned at full scale, and the DisCo tables give the jack function PDEs
up to 500 ms to reach PS0.

Poll ACTUAL_PS with sdca_asoc_pde_poll_actual_ps() after each power up,
like rt722 does since its DMIC pop noise fix, and use the 500 ms maximum
for the jack function PDEs. Power down is left alone because ACTUAL_PS
can stay at PS0 while the data port is still running.

Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
---
 sound/soc/codecs/Kconfig          |  1 +
 sound/soc/codecs/rt721-sdca-sdw.c | 17 ++++++++++++++++
 sound/soc/codecs/rt721-sdca.c     | 33 +++++++++++++++++++++++++++++++
 sound/soc/codecs/rt721-sdca.h     |  1 +
 4 files changed, 52 insertions(+)

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index ba59dabeeccde..133f397cc6e96 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -1978,6 +1978,7 @@ config SND_SOC_RT712_SDCA_DMIC_SDW
 config SND_SOC_RT721_SDCA_SDW
 	tristate "Realtek RT721 SDCA Codec - SDW"
 	depends on SOUNDWIRE
+	depends on SND_SOC_SDCA
 	select REGMAP_SOUNDWIRE
 	select REGMAP_SOUNDWIRE_MBQ
 
diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c
index fc34a0537d5fb..44cf9ca866c94 100644
--- a/sound/soc/codecs/rt721-sdca-sdw.c
+++ b/sound/soc/codecs/rt721-sdca-sdw.c
@@ -39,6 +39,14 @@ static bool rt721_sdca_readable_register(struct device *dev, unsigned int reg)
 		RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID,
 		RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
 	case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2:
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+		RT721_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+		RT721_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+		RT721_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41,
+		RT721_SDCA_CTL_ACTUAL_POWER_STATE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT0,
 		RT721_SDCA_CTL_FUNC_STATUS, 0):
 		return true;
@@ -64,6 +72,14 @@ static bool rt721_sdca_volatile_register(struct device *dev, unsigned int reg)
 		RT721_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... SDW_SDCA_CTL(FUNC_NUM_HID,
 		RT721_SDCA_ENT_HID01, RT721_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
 	case RT721_BUF_ADDR_HID1 ... RT721_BUF_ADDR_HID2:
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
+		RT721_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
+		RT721_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
+		RT721_SDCA_CTL_ACTUAL_POWER_STATE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41,
+		RT721_SDCA_CTL_ACTUAL_POWER_STATE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT0,
 		RT721_SDCA_CTL_FUNC_STATUS, 0):
 		return true;
@@ -595,3 +611,4 @@ module_sdw_driver(rt721_sdca_sdw_driver);
 MODULE_DESCRIPTION("ASoC RT721 SDCA SDW driver");
 MODULE_AUTHOR("Jack Yu <jack.yu@realtek.com>");
 MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_SDCA");
diff --git a/sound/soc/codecs/rt721-sdca.c b/sound/soc/codecs/rt721-sdca.c
index 9f567caecb70a..db4bf367011ec 100644
--- a/sound/soc/codecs/rt721-sdca.c
+++ b/sound/soc/codecs/rt721-sdca.c
@@ -21,6 +21,9 @@
 #include <linux/soundwire/sdw_registers.h>
 #include <linux/slab.h>
 #include <sound/soc-dapm.h>
+#include <sound/sdca.h>
+#include <sound/sdca_asoc.h>
+#include <sound/sdca_function.h>
 #include <sound/sdw.h>
 #include <sound/tlv.h>
 
@@ -1482,6 +1485,32 @@ static int rt721_sdca_fu36_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
+/* The DisCo tables give the jack function PDEs up to 500 ms for PS3 to PS0 */
+static const struct sdca_pde_delay rt721_jack_pde_delays[] = {
+	{ .from_ps = SDCA_PDE_PS3, .to_ps = SDCA_PDE_PS0, .us = 500000 },
+};
+
+/* REQUESTED_PS only starts the transition, so wait for ACTUAL_PS to reach PS0 */
+static void rt721_sdca_pde_wait_ps0(struct rt721_sdca_priv *rt721,
+				    unsigned char func, unsigned char entity)
+{
+	const struct sdca_pde_delay *delays = NULL;
+	int num_delays = 0;
+	int ret;
+
+	if (func == FUNC_NUM_JACK_CODEC) {
+		delays = rt721_jack_pde_delays;
+		num_delays = ARRAY_SIZE(rt721_jack_pde_delays);
+	}
+
+	ret = sdca_asoc_pde_poll_actual_ps(rt721->regmap, func, entity,
+					   SDCA_PDE_PS3, SDCA_PDE_PS0,
+					   delays, num_delays);
+	if (ret)
+		dev_warn(&rt721->slave->dev, "PDE 0x%x did not reach PS0: %d\n",
+			 entity, ret);
+}
+
 static int rt721_sdca_pde47_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -1495,6 +1524,7 @@ static int rt721_sdca_pde47_event(struct snd_soc_dapm_widget *w,
 		regmap_write(rt721->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40,
 				RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+		rt721_sdca_pde_wait_ps0(rt721, FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE40);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		regmap_write(rt721->regmap,
@@ -1518,6 +1548,7 @@ static int rt721_sdca_pde41_event(struct snd_soc_dapm_widget *w,
 		regmap_write(rt721->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41,
 				RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+		rt721_sdca_pde_wait_ps0(rt721, FUNC_NUM_AMP, RT721_SDCA_ENT_PDE41);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		regmap_write(rt721->regmap,
@@ -1541,6 +1572,7 @@ static int rt721_sdca_pde11_event(struct snd_soc_dapm_widget *w,
 		regmap_write(rt721->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A,
 				RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+		rt721_sdca_pde_wait_ps0(rt721, FUNC_NUM_MIC_ARRAY, RT721_SDCA_ENT_PDE2A);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		regmap_write(rt721->regmap,
@@ -1564,6 +1596,7 @@ static int rt721_sdca_pde34_event(struct snd_soc_dapm_widget *w,
 		regmap_write(rt721->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12,
 				RT721_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+		rt721_sdca_pde_wait_ps0(rt721, FUNC_NUM_JACK_CODEC, RT721_SDCA_ENT_PDE12);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		regmap_write(rt721->regmap,
diff --git a/sound/soc/codecs/rt721-sdca.h b/sound/soc/codecs/rt721-sdca.h
index cc3bce0ba5178..2ae68ce3fde28 100644
--- a/sound/soc/codecs/rt721-sdca.h
+++ b/sound/soc/codecs/rt721-sdca.h
@@ -260,6 +260,7 @@ struct rt721_sdca_dmic_kctrl_priv {
 #define RT721_SDCA_CTL_XUV				0x34
 #define RT721_SDCA_CTL_FU_CH_GAIN			0x0b
 #define RT721_SDCA_CTL_FUNC_STATUS			0x10
+#define RT721_SDCA_CTL_ACTUAL_POWER_STATE		0x10
 
 /* RT721 SDCA channel */
 #define CH_L	0x01
-- 
2.56.0


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

end of thread, other threads:[~2026-11-04 22:59 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-04 22:57 [PATCH v3 0/4] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
2026-11-04 22:58 ` [PATCH v3 1/4] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA Matthew Schwartz
2026-11-04 22:58 ` [PATCH v3 2/4] ASoC: amd: acp: add ACP70 SoundWire machine entry for " Matthew Schwartz
2026-11-04 22:58 ` [PATCH v3 3/4] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name Matthew Schwartz
2026-11-04 22:58 ` [PATCH v3 4/4] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz

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

all inboxes | Powered by JetHome®