* [PATCH v2 1/5] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA
2026-11-03 20:05 [PATCH v2 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
@ 2026-11-03 20:05 ` Matthew Schwartz
2026-11-03 20:05 ` [PATCH v2 2/5] ASoC: amd: acp: add ACP70 SoundWire machine entry for " Matthew Schwartz
` (3 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Matthew Schwartz @ 2026-11-03 20:05 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] 9+ messages in thread* [PATCH v2 2/5] ASoC: amd: acp: add ACP70 SoundWire machine entry for ASUS RC74XA
2026-11-03 20:05 [PATCH v2 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
2026-11-03 20:05 ` [PATCH v2 1/5] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA Matthew Schwartz
@ 2026-11-03 20:05 ` Matthew Schwartz
2026-11-03 20:05 ` [PATCH v2 3/5] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name Matthew Schwartz
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Matthew Schwartz @ 2026-11-03 20:05 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] 9+ messages in thread* [PATCH v2 3/5] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name
2026-11-03 20:05 [PATCH v2 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
2026-11-03 20:05 ` [PATCH v2 1/5] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA Matthew Schwartz
2026-11-03 20:05 ` [PATCH v2 2/5] ASoC: amd: acp: add ACP70 SoundWire machine entry for " Matthew Schwartz
@ 2026-11-03 20:05 ` Matthew Schwartz
2026-11-03 20:05 ` [PATCH v2 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links Matthew Schwartz
2026-11-03 20:05 ` [PATCH v2 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz
4 siblings, 0 replies; 9+ messages in thread
From: Matthew Schwartz @ 2026-11-03 20:05 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] 9+ messages in thread* [PATCH v2 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links
2026-11-03 20:05 [PATCH v2 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
` (2 preceding siblings ...)
2026-11-03 20:05 ` [PATCH v2 3/5] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name Matthew Schwartz
@ 2026-11-03 20:05 ` Matthew Schwartz
2026-11-04 3:01 ` Liao, Bard
2026-11-04 11:36 ` Pierre-Louis Bossart
2026-11-03 20:05 ` [PATCH v2 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz
4 siblings, 2 replies; 9+ messages in thread
From: Matthew Schwartz @ 2026-11-03 20:05 UTC (permalink / raw)
To: broonie
Cc: Matthew Schwartz, Liam Girdwood, Jaroslav Kysela, Takashi Iwai,
Vijendar Mukunda, Venkata Prasad Potturu, Cezary Rojewski,
Peter Ujfalusi, Bard Liao, Kai Vehmanen, Pierre-Louis Bossart,
linux-sound, linux-kernel
The codec_info tables give each DAI a fixed direction, so a TAS2783
always gets an amp feedback capture link. The ASUS ROG Xbox Ally X20
BIOS declares mipi-sdw-source-port-list as 0 for both of its TAS2783s,
so the capture port has no DisCo properties and every open of the
SmartAmp capture PCM fails in sdw_program_slave_port_params() with
-EINVAL. The PCM is probed at session start, which logs a burst of
transport errors on every boot, and the same failure is reported on the
ASUS ProArt PX13.
Store the effective direction in each endpoint and, for codecs whose
driver takes its ports from the DisCo port lists, drop a direction when
the peripheral declares an empty list for it, and skip the endpoint when
neither direction is left. Other codecs keep the table direction, as
many of their drivers use fixed port masks. Since endpoints in one group
can now differ, the machine drivers take the stream name and DAI link ID
from an endpoint that is part of the stream, and only count and
initialize those endpoints.
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
---
include/sound/soc_sdw_utils.h | 16 +++++++
sound/soc/amd/acp/acp-sdw-legacy-mach.c | 9 ++--
sound/soc/amd/acp/acp-sdw-sof-mach.c | 7 ++-
sound/soc/intel/boards/sof_sdw.c | 7 ++-
sound/soc/sdw_utils/soc_sdw_utils.c | 60 ++++++++++++++++++++-----
5 files changed, 76 insertions(+), 23 deletions(-)
diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h
index 418466438ea1c..be7403c89901b 100644
--- a/include/sound/soc_sdw_utils.h
+++ b/include/sound/soc_sdw_utils.h
@@ -97,6 +97,8 @@ struct asoc_sdw_codec_info {
const int aux_num;
/* Force AMP-style name_prefix handling (append AMP index) even if MIC/Jack DAIs exist */
const bool is_amp;
+ /* The driver takes its ports from the DisCo port lists */
+ const bool disco_ports;
int (*codec_card_late_probe)(struct snd_soc_card *card);
@@ -114,6 +116,7 @@ struct asoc_sdw_endpoint {
const char *codec_name;
const char *name_prefix;
bool include_sidecar;
+ bool direction[2]; /* dai_info direction limited by the DisCo port lists */
struct asoc_sdw_codec_info *codec_info;
const struct asoc_sdw_dai_info *dai_info;
@@ -128,6 +131,19 @@ struct asoc_sdw_dailink {
struct list_head endpoints;
};
+/* First endpoint of a DAI link that takes part in the stream */
+static inline struct asoc_sdw_endpoint *
+asoc_sdw_first_endpoint(struct asoc_sdw_dailink *soc_dai, int stream)
+{
+ struct asoc_sdw_endpoint *soc_end;
+
+ list_for_each_entry(soc_end, &soc_dai->endpoints, list)
+ if (soc_end->direction[stream])
+ return soc_end;
+
+ return NULL;
+}
+
extern struct asoc_sdw_codec_info codec_info_list[];
int asoc_sdw_get_codec_info_list_count(void);
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index a8b62817b2344..84b602e12f8ce 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -196,8 +196,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
if (!soc_dai->num_devs[stream])
continue;
- soc_end = list_first_entry(&soc_dai->endpoints,
- struct asoc_sdw_endpoint, list);
+ soc_end = asoc_sdw_first_endpoint(soc_dai, stream);
*be_id = soc_end->dai_info->dailink[stream];
if (*be_id < 0) {
@@ -262,7 +261,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
return -ENOMEM;
list_for_each_entry(soc_end, &soc_dai->endpoints, list) {
- if (!soc_end->dai_info->direction[stream])
+ if (!soc_end->direction[stream])
continue;
/*
@@ -307,7 +306,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
(*dai_links)->ch_maps = codec_maps;
list_for_each_entry(soc_end, &soc_dai->endpoints, list) {
- if (soc_end->dai_info->init)
+ if (soc_end->direction[stream] && soc_end->dai_info->init)
soc_end->dai_info->init(card, *dai_links,
soc_end->codec_info,
playback);
@@ -472,7 +471,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card)
continue;
list_for_each_entry(e, &d->endpoints, list) {
- if (e->dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] &&
+ if (e->direction[SNDRV_PCM_STREAM_CAPTURE] &&
e->dai_info->dai_type == SOC_SDW_DAI_TYPE_AMP)
d->num_devs[SNDRV_PCM_STREAM_CAPTURE]--;
}
diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c
index ec3e1f5f1052c..c3cccb75f2349 100644
--- a/sound/soc/amd/acp/acp-sdw-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c
@@ -112,8 +112,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
if (!sof_dai->num_devs[stream])
continue;
- sof_end = list_first_entry(&sof_dai->endpoints,
- struct asoc_sdw_endpoint, list);
+ sof_end = asoc_sdw_first_endpoint(sof_dai, stream);
*be_id = sof_end->dai_info->dailink[stream];
if (*be_id < 0) {
@@ -177,7 +176,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
return -ENOMEM;
list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
- if (!sof_end->dai_info->direction[stream])
+ if (!sof_end->direction[stream])
continue;
int link_num = ffs(sof_end->link_mask) - 1;
@@ -215,7 +214,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
(*dai_links)->ch_maps = codec_maps;
list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
- if (sof_end->dai_info->init)
+ if (sof_end->direction[stream] && sof_end->dai_info->init)
sof_end->dai_info->init(card, *dai_links,
sof_end->codec_info,
playback);
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index 72fe013fffe86..bb96186146f85 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -939,8 +939,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
if (!sof_dai->num_devs[stream])
continue;
- sof_end = list_first_entry(&sof_dai->endpoints,
- struct asoc_sdw_endpoint, list);
+ sof_end = asoc_sdw_first_endpoint(sof_dai, stream);
*be_id = sof_end->dai_info->dailink[stream];
if (*be_id < 0) {
@@ -973,7 +972,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
return -ENOMEM;
list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
- if (!sof_end->dai_info->direction[stream])
+ if (!sof_end->direction[stream])
continue;
if (cur_link != sof_end->link_mask) {
@@ -1020,7 +1019,7 @@ static int create_sdw_dailink(struct snd_soc_card *card,
(*dai_links)->ch_maps = codec_maps;
list_for_each_entry(sof_end, &sof_dai->endpoints, list) {
- if (sof_end->dai_info->init)
+ if (sof_end->direction[stream] && sof_end->dai_info->init)
sof_end->dai_info->init(card, *dai_links,
sof_end->codec_info,
playback);
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index 7a19de75f32b5..ae14b4be66818 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -248,6 +248,7 @@ struct asoc_sdw_codec_info codec_info_list[] = {
.part_id = 0x0000, /* TAS2783A */
.name_prefix = "tas2783",
.is_amp = true,
+ .disco_ports = true,
.dais = {
{
.direction = {true, true},
@@ -2407,6 +2408,32 @@ static int is_sdca_endpoint_present(struct device *dev,
return 0;
}
+/* A DisCo port list that is present but empty means the stream cannot run */
+static bool asoc_sdw_has_ports(struct device *dev,
+ const struct snd_soc_acpi_link_adr *adr_link,
+ int adr_index, int stream)
+{
+ const char *prop = stream == SNDRV_PCM_STREAM_PLAYBACK ?
+ "mipi-sdw-sink-port-list" : "mipi-sdw-source-port-list";
+ const char *sdw_codec_name;
+ struct device *sdw_dev;
+ u32 ports;
+ int ret;
+
+ sdw_codec_name = _asoc_sdw_get_codec_name(dev, adr_link, adr_index);
+ if (!sdw_codec_name)
+ return true;
+
+ sdw_dev = bus_find_device_by_name(&sdw_bus_type, NULL, sdw_codec_name);
+ if (!sdw_dev)
+ return true;
+
+ ret = device_property_read_u32(sdw_dev, prop, &ports);
+ put_device(sdw_dev);
+
+ return ret || ports;
+}
+
int asoc_sdw_parse_sdw_endpoints(struct device *dev,
struct asoc_sdw_mc_private *ctx,
struct snd_soc_aux_dev *soc_aux,
@@ -2493,6 +2520,26 @@ int asoc_sdw_parse_sdw_endpoints(struct device *dev,
adr_end = &adr_dev->endpoints[j];
dai_info = &codec_info->dais[adr_end->num];
+
+ if (adr_end->num >= codec_info->dai_num) {
+ dev_err(dev,
+ "%d is too many endpoints for codec: 0x%x\n",
+ adr_end->num, codec_info->part_id);
+ return -EINVAL;
+ }
+
+ for_each_pcm_streams(stream)
+ soc_end->direction[stream] = dai_info->direction[stream] &&
+ (!codec_info->disco_ports ||
+ asoc_sdw_has_ports(dev, adr_link, i, stream));
+
+ /* no stream can use this endpoint */
+ if (!soc_end->direction[SNDRV_PCM_STREAM_PLAYBACK] &&
+ !soc_end->direction[SNDRV_PCM_STREAM_CAPTURE]) {
+ (*num_devs)--;
+ continue;
+ }
+
soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end);
/*
@@ -2533,18 +2580,11 @@ int asoc_sdw_parse_sdw_endpoints(struct device *dev,
"Add dev: %d, 0x%llx end: %d, dai: %d, %c/%c to %s: %d\n",
ffs(adr_link->mask) - 1, adr_dev->adr,
adr_end->num, dai_info->dai_type,
- dai_info->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
- dai_info->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
+ soc_end->direction[SNDRV_PCM_STREAM_PLAYBACK] ? 'P' : '-',
+ soc_end->direction[SNDRV_PCM_STREAM_CAPTURE] ? 'C' : '-',
adr_end->aggregated ? "group" : "solo",
adr_end->group_id);
- if (adr_end->num >= codec_info->dai_num) {
- dev_err(dev,
- "%d is too many endpoints for codec: 0x%x\n",
- adr_end->num, codec_info->part_id);
- return -EINVAL;
- }
-
for_each_pcm_streams(stream) {
if (dai_info->direction[stream] &&
dai_info->dailink[stream] < 0) {
@@ -2555,7 +2595,7 @@ int asoc_sdw_parse_sdw_endpoints(struct device *dev,
return -EINVAL;
}
- if (dai_info->direction[stream]) {
+ if (soc_end->direction[stream]) {
num_dais += !soc_dai->num_devs[stream];
soc_dai->num_devs[stream]++;
soc_dai->link_mask[stream] |= adr_link->mask;
--
2.56.0
^ permalink raw reply [flat|nested] 9+ messages in thread* RE: [PATCH v2 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links
2026-11-03 20:05 ` [PATCH v2 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links Matthew Schwartz
@ 2026-11-04 3:01 ` Liao, Bard
2026-11-04 11:36 ` Pierre-Louis Bossart
1 sibling, 0 replies; 9+ messages in thread
From: Liao, Bard @ 2026-11-04 3:01 UTC (permalink / raw)
To: Matthew Schwartz, broonie
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Vijendar Mukunda,
Venkata Prasad Potturu, Rojewski, Cezary, Peter Ujfalusi,
Bard Liao, Kai Vehmanen, Pierre-Louis Bossart, linux-sound,
linux-kernel
> -----Original Message-----
> From: Matthew Schwartz <matthew.schwartz@linux.dev>
> Sent: Wednesday, November 4, 2026 4:06 AM
> To: broonie@kernel.org
> Cc: Matthew Schwartz <matthew.schwartz@linux.dev>; Liam Girdwood
> <lgirdwood@gmail.com>; Jaroslav Kysela <perex@perex.cz>; Takashi Iwai
> <tiwai@suse.com>; Vijendar Mukunda <Vijendar.Mukunda@amd.com>;
> Venkata Prasad Potturu <venkataprasad.potturu@amd.com>; Rojewski,
> Cezary <cezary.rojewski@intel.com>; Peter Ujfalusi
> <peter.ujfalusi@linux.intel.com>; Bard Liao <yung-
> chuan.liao@linux.intel.com>; Kai Vehmanen <kai.vehmanen@linux.intel.com>;
> Pierre-Louis Bossart <pierre-louis.bossart@linux.dev>; linux-
> sound@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: [PATCH v2 4/5] ASoC: sdw_utils: honor empty DisCo port lists when
> creating DAI links
>
> The codec_info tables give each DAI a fixed direction, so a TAS2783
> always gets an amp feedback capture link. The ASUS ROG Xbox Ally X20
> BIOS declares mipi-sdw-source-port-list as 0 for both of its TAS2783s,
> so the capture port has no DisCo properties and every open of the
> SmartAmp capture PCM fails in sdw_program_slave_port_params() with
> -EINVAL. The PCM is probed at session start, which logs a burst of
> transport errors on every boot, and the same failure is reported on the
> ASUS ProArt PX13.
>
> Store the effective direction in each endpoint and, for codecs whose
> driver takes its ports from the DisCo port lists, drop a direction when
> the peripheral declares an empty list for it, and skip the endpoint when
> neither direction is left. Other codecs keep the table direction, as
> many of their drivers use fixed port masks. Since endpoints in one group
> can now differ, the machine drivers take the stream name and DAI link ID
> from an endpoint that is part of the stream, and only count and
> initialize those endpoints.
>
> Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
> ---
[...]
> int asoc_sdw_parse_sdw_endpoints(struct device *dev,
> struct asoc_sdw_mc_private *ctx,
> struct snd_soc_aux_dev *soc_aux,
> @@ -2493,6 +2520,26 @@ int asoc_sdw_parse_sdw_endpoints(struct
> device *dev,
>
> adr_end = &adr_dev->endpoints[j];
> dai_info = &codec_info->dais[adr_end->num];
> +
> + if (adr_end->num >= codec_info->dai_num) {
> + dev_err(dev,
> + "%d is too many endpoints for
> codec: 0x%x\n",
> + adr_end->num, codec_info-
> >part_id);
> + return -EINVAL;
> + }
This bounds check comes after `codec_info->dais[adr_end->num]`.
Please move it before the array access to validate the index first.
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH v2 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links
2026-11-03 20:05 ` [PATCH v2 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links Matthew Schwartz
2026-11-04 3:01 ` Liao, Bard
@ 2026-11-04 11:36 ` Pierre-Louis Bossart
1 sibling, 0 replies; 9+ messages in thread
From: Pierre-Louis Bossart @ 2026-11-04 11:36 UTC (permalink / raw)
To: Matthew Schwartz, broonie
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Vijendar Mukunda,
Venkata Prasad Potturu, Cezary Rojewski, Peter Ujfalusi,
Bard Liao, Kai Vehmanen, linux-sound, linux-kernel
On 11/3/26 21:05, Matthew Schwartz wrote:
> The codec_info tables give each DAI a fixed direction, so a TAS2783
> always gets an amp feedback capture link. The ASUS ROG Xbox Ally X20
> BIOS declares mipi-sdw-source-port-list as 0 for both of its TAS2783s,
> so the capture port has no DisCo properties and every open of the
> SmartAmp capture PCM fails in sdw_program_slave_port_params() with
> -EINVAL. The PCM is probed at session start, which logs a burst of
> transport errors on every boot, and the same failure is reported on the
> ASUS ProArt PX13.
>
> Store the effective direction in each endpoint and, for codecs whose
> driver takes its ports from the DisCo port lists, drop a direction when
> the peripheral declares an empty list for it, and skip the endpoint when
> neither direction is left. Other codecs keep the table direction, as
> many of their drivers use fixed port masks. Since endpoints in one group
> can now differ, the machine drivers take the stream name and DAI link ID
> from an endpoint that is part of the stream, and only count and
> initialize those endpoints.
Can I suggest a more nuclear option, ignore all the port properties and
add them directly in the driver?
I am not aware of any other codec that relies on those properties, and
guess what they are wrong in that unique case. all other codec drivers
list the ports in their read_prop callback, e.g. .read_prop =
rt711_read_prop,
While I am at it, this TAS2783-sdw driver does some really weird things
with data ports, all the uses of
case 0x000 ... 0x080: /* Data port 0. */
case 0x100 ... 0x140: /* Data port 1. */
case 0x200 ... 0x240: /* Data port 2. */
case 0x300 ... 0x340: /* Data port 3. */
case 0x400 ... 0x440: /* Data port 4. */
case 0x500 ... 0x540: /* Data port 5. */
are not correct IMHO, the data ports are managed by the core without
using regmap.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v2 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up
2026-11-03 20:05 [PATCH v2 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
` (3 preceding siblings ...)
2026-11-03 20:05 ` [PATCH v2 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links Matthew Schwartz
@ 2026-11-03 20:05 ` Matthew Schwartz
2026-11-04 11:44 ` Pierre-Louis Bossart
4 siblings, 1 reply; 9+ messages in thread
From: Matthew Schwartz @ 2026-11-03 20:05 UTC (permalink / raw)
To: broonie
Cc: Matthew Schwartz, 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.
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] 9+ messages in thread* Re: [PATCH v2 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up
2026-11-03 20:05 ` [PATCH v2 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz
@ 2026-11-04 11:44 ` Pierre-Louis Bossart
0 siblings, 0 replies; 9+ messages in thread
From: Pierre-Louis Bossart @ 2026-11-04 11:44 UTC (permalink / raw)
To: Matthew Schwartz, broonie
Cc: Liam Girdwood, Jaroslav Kysela, Takashi Iwai, Oder Chiou,
linux-sound, linux-kernel
On 11/3/26 21:05, Matthew Schwartz wrote:
> 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.
Sounds like the right thing to do
Reviewed-by: Pierre-Louis Bossart <pierre-louis bossart@linux.dev>
IIRC there was a good regmap-related reason why we split the write to
REQUESTED_PS, and the wait on ACTUAL_PS, but the net result is that some
folks don't wait...
^ permalink raw reply [flat|nested] 9+ messages in thread