* [PATCH 1/5] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA
2026-10-16 23:24 [PATCH 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
@ 2026-10-16 23:24 ` Matthew Schwartz
2026-10-16 23:24 ` [PATCH 2/5] ASoC: amd: acp: add ACP70 SoundWire machine entry for " Matthew Schwartz
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Matthew Schwartz @ 2026-10-16 23:24 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.
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] 6+ messages in thread* [PATCH 2/5] ASoC: amd: acp: add ACP70 SoundWire machine entry for ASUS RC74XA
2026-10-16 23:24 [PATCH 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
2026-10-16 23:24 ` [PATCH 1/5] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA Matthew Schwartz
@ 2026-10-16 23:24 ` Matthew Schwartz
2026-10-16 23:24 ` [PATCH 3/5] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name Matthew Schwartz
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Matthew Schwartz @ 2026-10-16 23:24 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.
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] 6+ messages in thread* [PATCH 3/5] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name
2026-10-16 23:24 [PATCH 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
2026-10-16 23:24 ` [PATCH 1/5] ASoC: amd: acp-config: force SoundWire probe on ASUS RC74XA Matthew Schwartz
2026-10-16 23:24 ` [PATCH 2/5] ASoC: amd: acp: add ACP70 SoundWire machine entry for " Matthew Schwartz
@ 2026-10-16 23:24 ` Matthew Schwartz
2026-10-16 23:24 ` [PATCH 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links Matthew Schwartz
2026-10-16 23:24 ` [PATCH 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz
4 siblings, 0 replies; 6+ messages in thread
From: Matthew Schwartz @ 2026-10-16 23:24 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 and request the four-field name first when it is
present. Boards without the variable keep the current names, and the
unprefixed three-field name is still tried if the four-field file is
missing.
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
---
sound/soc/codecs/tas2783-sdw.c | 42 +++++++++++++++++++++++++++++++---
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/sound/soc/codecs/tas2783-sdw.c b/sound/soc/codecs/tas2783-sdw.c
index a57230e01f755..db234c54aa2ac 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,
@@ -104,6 +106,11 @@ struct tas2783_prv {
bool fw_dl_success;
/* use fallback fw name */
bool fw_use_fallback;
+#if IS_ENABLED(CONFIG_PCI)
+ /* UEFI speaker ID, read once */
+ int spk_id;
+ bool spk_id_read;
+#endif
};
static const struct reg_default tas2783_reg_default[] = {
@@ -1156,6 +1163,26 @@ static const struct dev_pm_ops tas2783_sdca_pm = {
RUNTIME_PM_OPS(tas2783_sdca_dev_suspend, tas2783_sdca_dev_resume, NULL)
};
+#if IS_ENABLED(CONFIG_PCI)
+/* BIOS speaker ID that selects the SSID-SPKID-LINK-UID firmware name */
+static int tas2783_get_spk_id(void)
+{
+ efi_guid_t guid = TAS2783_SPKID_GUID;
+ unsigned long size = sizeof(u32);
+ efi_status_t status;
+ u32 spk_id = 0;
+
+ 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)
+ return -ENOENT;
+
+ return spk_id;
+}
+#endif
+
static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t size)
{
struct sdw_bus *bus = slave->bus;
@@ -1170,9 +1197,18 @@ static void tas_generate_fw_name(struct sdw_slave *slave, char *name, size_t siz
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);
+ if (!tas_dev->spk_id_read) {
+ tas_dev->spk_id = tas2783_get_spk_id();
+ tas_dev->spk_id_read = true;
+ }
+ if (tas_dev->spk_id >= 0 && !tas_dev->fw_use_fallback)
+ scnprintf(name, size, "%04X-%X-%1X-0x%1X.bin",
+ pci->subsystem_device, tas_dev->spk_id,
+ bus->link_id, unique_id);
+ else
+ scnprintf(name, size, "%04X-%1X-%s%1X.bin",
+ pci->subsystem_device, bus->link_id,
+ fw_uid_prefix, unique_id);
pci_found = true;
break;
}
--
2.56.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links
2026-10-16 23:24 [PATCH 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
` (2 preceding siblings ...)
2026-10-16 23:24 ` [PATCH 3/5] ASoC: tas2783-sdw: use the BIOS speaker ID in the firmware name Matthew Schwartz
@ 2026-10-16 23:24 ` Matthew Schwartz
2026-10-16 23:24 ` [PATCH 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up Matthew Schwartz
4 siblings, 0 replies; 6+ messages in thread
From: Matthew Schwartz @ 2026-10-16 23:24 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 drop a direction
when the peripheral declares an empty port list for it. A missing port
list keeps the table direction, so platforms that do not describe their
ports are unaffected.
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
---
include/sound/soc_sdw_utils.h | 1 +
sound/soc/amd/acp/acp-sdw-legacy-mach.c | 2 +-
sound/soc/amd/acp/acp-sdw-sof-mach.c | 2 +-
sound/soc/intel/boards/sof_sdw.c | 2 +-
sound/soc/sdw_utils/soc_sdw_utils.c | 36 ++++++++++++++++++++++---
5 files changed, 37 insertions(+), 6 deletions(-)
diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h
index 418466438ea1c..8e247a457a7c6 100644
--- a/include/sound/soc_sdw_utils.h
+++ b/include/sound/soc_sdw_utils.h
@@ -114,6 +114,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;
diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
index a8b62817b2344..d485cee42542c 100644
--- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c
@@ -262,7 +262,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;
/*
diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c
index ec3e1f5f1052c..87e495e601bcd 100644
--- a/sound/soc/amd/acp/acp-sdw-sof-mach.c
+++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c
@@ -177,7 +177,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;
diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c
index 72fe013fffe86..42c6c262cc80e 100644
--- a/sound/soc/intel/boards/sof_sdw.c
+++ b/sound/soc/intel/boards/sof_sdw.c
@@ -973,7 +973,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) {
diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c
index 7a19de75f32b5..126ff1b2dc450 100644
--- a/sound/soc/sdw_utils/soc_sdw_utils.c
+++ b/sound/soc/sdw_utils/soc_sdw_utils.c
@@ -2407,6 +2407,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,
@@ -2529,12 +2555,16 @@ int asoc_sdw_parse_sdw_endpoints(struct device *dev,
}
}
+ for_each_pcm_streams(stream)
+ soc_end->direction[stream] = dai_info->direction[stream] &&
+ asoc_sdw_has_ports(dev, adr_link, i, stream);
+
dev_dbg(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);
@@ -2555,7 +2585,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] 6+ messages in thread* [PATCH 5/5] ASoC: rt721-sdca: wait for PDEs to reach PS0 after powering them up
2026-10-16 23:24 [PATCH 0/5] ASoC: support the ASUS ROG Xbox Ally X20 audio Matthew Schwartz
` (3 preceding siblings ...)
2026-10-16 23:24 ` [PATCH 4/5] ASoC: sdw_utils: honor empty DisCo port lists when creating DAI links Matthew Schwartz
@ 2026-10-16 23:24 ` Matthew Schwartz
4 siblings, 0 replies; 6+ messages in thread
From: Matthew Schwartz @ 2026-10-16 23:24 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] 6+ messages in thread