From 0611f2ea4688e3650f4382c5fafde4f2c5b4c044 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 8 Sep 2026 11:13:18 +0800 Subject: [PATCH 1/5] ASoC: soc-acpi: add companion flag to snd_soc_acpi_endpoint To identify the endpoint is for companion amp. Signed-off-by: Bard Liao --- include/sound/soc-acpi.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/sound/soc-acpi.h b/include/sound/soc-acpi.h index 2ee303b791dc84..116f8d65993ba7 100644 --- a/include/sound/soc-acpi.h +++ b/include/sound/soc-acpi.h @@ -96,12 +96,14 @@ struct snd_soc_acpi_mach_params { * struct snd_soc_acpi_endpoint - endpoint descriptor * @num: endpoint number (mandatory, unique per device) * @aggregated: 0 (independent) or 1 (logically grouped) + * @companion: 0 (independent) or 1 (within a companion amp group) * @group_position: zero-based order (only when @aggregated is 1) - * @group_id: platform-unique group identifier (only when @aggregrated is 1) + * @group_id: platform-unique group identifier (only when @aggregrated or companion is 1) */ struct snd_soc_acpi_endpoint { u8 num; u8 aggregated; + u8 companion; u8 group_position; u8 group_id; }; From 483617b651da7b7defe782b7f5027a86a8efb75e Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 29 Oct 2026 08:48:28 +0800 Subject: [PATCH 2/5] ASoC: sdw_utils: add companion amp support Add asoc_sdw_companion_amp_endpoint struct to help machine driver to create codec to codec dai links for SoundWire companion amps. Signed-off-by: Bard Liao --- include/sound/soc_sdw_utils.h | 12 ++- sound/soc/amd/acp/acp-sdw-legacy-mach.c | 17 +++- sound/soc/amd/acp/acp-sdw-sof-mach.c | 17 +++- sound/soc/intel/boards/sof_sdw.c | 111 +++++++++++++++++++++++- sound/soc/sdw_utils/soc_sdw_utils.c | 90 +++++++++++++++---- 5 files changed, 219 insertions(+), 28 deletions(-) diff --git a/include/sound/soc_sdw_utils.h b/include/sound/soc_sdw_utils.h index 418466438ea1cb..f65e71917748c4 100644 --- a/include/sound/soc_sdw_utils.h +++ b/include/sound/soc_sdw_utils.h @@ -30,6 +30,7 @@ */ #define SOC_SDW_SIDECAR_AMPS BIT(16) #define SOC_SDW_CODEC_MIC BIT(17) +#define SOC_SDW_COMPANION_AMPS BIT(18) #define SOC_SDW_UNUSED_DAI_ID -1 #define SOC_SDW_JACK_OUT_DAI_ID 0 @@ -128,6 +129,11 @@ struct asoc_sdw_dailink { struct list_head endpoints; }; +struct asoc_sdw_companion_amp_endpoint { + struct asoc_sdw_endpoint *main_amp; + struct list_head comp_ends; +}; + extern struct asoc_sdw_codec_info codec_info_list[]; int asoc_sdw_get_codec_info_list_count(void); @@ -176,10 +182,13 @@ int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *d const struct snd_soc_ops *ops); int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, - int *num_devs, int *num_ends, int *num_aux); + int *num_devs, int *num_ends, int *num_aux, int *num_comp_amps); struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks, const struct snd_soc_acpi_endpoint *new); +int asoc_sdw_find_amp_endpoints(struct asoc_sdw_dailink *dailink, + struct asoc_sdw_endpoint **amp_ends, + int max_ends); int asoc_sdw_get_dai_type(u32 type); int asoc_sdw_parse_sdw_endpoints(struct device *dev, @@ -187,6 +196,7 @@ int asoc_sdw_parse_sdw_endpoints(struct device *dev, struct snd_soc_aux_dev *soc_aux, struct asoc_sdw_dailink *soc_dais, struct asoc_sdw_endpoint *soc_ends, + struct asoc_sdw_companion_amp_endpoint *comp_ends, int *num_devs); int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd); diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c index a8b62817b2344e..0a6d1d91a5c4fa 100644 --- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -415,9 +415,11 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) struct device *dev = card->dev; int sdw_be_num = 0, dmic_num = 0; struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); + struct asoc_sdw_companion_amp_endpoint *sof_comp_ends; struct snd_soc_aux_dev *soc_aux; struct snd_soc_codec_conf *codec_conf; struct snd_soc_dai_link *dai_links; + int num_comp_amps = 0; int num_devs = 0; int num_ends = 0; int num_aux = 0; @@ -425,8 +427,9 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) int num_links; int be_id = 0; int ret; + int i; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux, &num_comp_amps); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; @@ -442,7 +445,7 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) /* One per endpoint, ie. each DAI on each codec/amp */ struct asoc_sdw_endpoint *soc_ends __free(kfree) = - kzalloc_objs(*soc_ends, num_ends); + kzalloc_objs(*soc_ends, num_ends + num_comp_amps); if (!soc_ends) return -ENOMEM; @@ -450,7 +453,15 @@ static int soc_card_dai_links_create(struct snd_soc_card *card) if (!soc_aux) return -ENOMEM; - ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, &num_confs); + sof_comp_ends = devm_kcalloc(dev, num_comp_amps, sizeof(*sof_comp_ends), GFP_KERNEL); + if (!sof_comp_ends) + return -ENOMEM; + + for (i = 0; i < num_comp_amps; i++) + INIT_LIST_HEAD(&sof_comp_ends[i].comp_ends); + + ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, soc_aux, soc_dais, soc_ends, sof_comp_ends, + &num_confs); if (ret < 0) return ret; diff --git a/sound/soc/amd/acp/acp-sdw-sof-mach.c b/sound/soc/amd/acp/acp-sdw-sof-mach.c index ec3e1f5f1052c5..73a6b71ac95397 100644 --- a/sound/soc/amd/acp/acp-sdw-sof-mach.c +++ b/sound/soc/amd/acp/acp-sdw-sof-mach.c @@ -280,9 +280,11 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int sdw_be_num = 0, dmic_num = 0; struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + struct asoc_sdw_companion_amp_endpoint *sof_comp_ends; struct snd_soc_aux_dev *sof_aux; struct snd_soc_codec_conf *codec_conf; struct snd_soc_dai_link *dai_links; + int num_comp_amps = 0; int num_devs = 0; int num_ends = 0; int num_aux = 0; @@ -290,8 +292,9 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int num_links; int be_id = 0; int ret; + int i; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux, &num_comp_amps); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; @@ -306,7 +309,7 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) /* One per endpoint, ie. each DAI on each codec/amp */ struct asoc_sdw_endpoint *sof_ends __free(kfree) = - kzalloc_objs(*sof_ends, num_ends); + kzalloc_objs(*sof_ends, num_ends + num_comp_amps); if (!sof_ends) return -ENOMEM; @@ -314,7 +317,15 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) if (!sof_aux) return -ENOMEM; - ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs); + sof_comp_ends = devm_kcalloc(dev, num_comp_amps, sizeof(*sof_comp_ends), GFP_KERNEL); + if (!sof_comp_ends) + return -ENOMEM; + + for (i = 0; i < num_comp_amps; i++) + INIT_LIST_HEAD(&sof_comp_ends[i].comp_ends); + + ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, sof_comp_ends, + &num_confs); if (ret < 0) return ret; diff --git a/sound/soc/intel/boards/sof_sdw.c b/sound/soc/intel/boards/sof_sdw.c index b263f554dcc9a9..09ec3eb99cf49e 100644 --- a/sound/soc/intel/boards/sof_sdw.c +++ b/sound/soc/intel/boards/sof_sdw.c @@ -1225,6 +1225,89 @@ static int create_bt_dailinks(struct snd_soc_card *card, return 0; } +static const struct snd_soc_pcm_stream asoc_sdw_bridge_params = { + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, +}; + +static const struct snd_soc_dai_link bridge_dai_template = { + .name = "SDW Companion Amp", + .stream_name = "Companion Amp", + .c2c_params = &asoc_sdw_bridge_params, + .num_c2c_params = 1, +}; + +static int create_sdw_comp_dailinks(struct snd_soc_card *card, + struct snd_soc_dai_link **dai_links, int *be_id, + struct asoc_sdw_companion_amp_endpoint *comp_ends, + int comp_ends_num) +{ + struct device *dev = card->dev; + struct asoc_sdw_endpoint *end; + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link_component *codecs; + struct snd_soc_dai_link_component *cpus; + char *name; + int num_codecs; + int i; + + for (i = 0; i < comp_ends_num; i++) { + if (!comp_ends[i].main_amp || list_empty(&comp_ends[i].comp_ends)) { + dev_err(dev, "companion amp group %d: missing main amp or companion amps\n", i); + return -EINVAL; + } + + num_codecs = 0; + list_for_each_entry(end, &comp_ends[i].comp_ends, list) + num_codecs++; + + cpus = devm_kzalloc(dev, sizeof(*cpus), GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + codecs = devm_kcalloc(dev, num_codecs, sizeof(*codecs), GFP_KERNEL); + if (!codecs) + return -ENOMEM; + + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!platform) + return -ENOMEM; + + name = devm_kasprintf(dev, GFP_KERNEL, "SDW Companion Amp %d", i); + if (!name) + return -ENOMEM; + + cpus[0].name = comp_ends[i].main_amp->codec_name; + cpus[0].dai_name = comp_ends[i].main_amp->dai_info->dai_name; + + num_codecs = 0; + list_for_each_entry(end, &comp_ends[i].comp_ends, list) { + codecs[num_codecs].name = end->codec_name; + codecs[num_codecs].dai_name = end->dai_info->dai_name; + num_codecs++; + } + + **dai_links = bridge_dai_template; + (*dai_links)->name = name; + (*dai_links)->stream_name = name; + (*dai_links)->cpus = cpus; + (*dai_links)->num_cpus = 1; + (*dai_links)->codecs = codecs; + (*dai_links)->num_codecs = num_codecs; + (*dai_links)->platforms = platform; + (*dai_links)->num_platforms = 1; + (*dai_links)++; + } + + dev_dbg(dev, "Added SDW Companion AMP Codec to Codec link\n"); + + return 0; +} + static int create_echoref_dailink(struct snd_soc_card *card, struct snd_soc_dai_link **dai_links, int *be_id) { @@ -1261,11 +1344,13 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) struct asoc_sdw_mc_private *ctx = snd_soc_card_get_drvdata(card); struct intel_mc_ctx *intel_ctx = (struct intel_mc_ctx *)ctx->private; struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; + struct asoc_sdw_companion_amp_endpoint *sof_comp_ends; struct snd_soc_codec_conf *codec_conf; struct asoc_sdw_codec_info *ssp_info; struct asoc_sdw_endpoint *sof_ends; struct asoc_sdw_dailink *sof_dais; struct snd_soc_aux_dev *sof_aux; + int num_comp_amps = 0; int num_devs = 0; int num_ends = 0; int num_aux = 0; @@ -1276,8 +1361,9 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) int hdmi_num; unsigned long ssp_mask; int ret; + int i; - ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux); + ret = asoc_sdw_count_sdw_endpoints(card, &num_devs, &num_ends, &num_aux, &num_comp_amps); if (ret < 0) { dev_err(dev, "failed to count devices/endpoints: %d\n", ret); return ret; @@ -1307,7 +1393,17 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) goto err_dai; } - ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, &num_confs); + sof_comp_ends = devm_kcalloc(dev, num_comp_amps, sizeof(*sof_comp_ends), GFP_KERNEL); + if (!sof_comp_ends) { + ret = -ENOMEM; + goto err_dai; + } + + for (i = 0; i < num_comp_amps; i++) + INIT_LIST_HEAD(&sof_comp_ends[i].comp_ends); + + ret = asoc_sdw_parse_sdw_endpoints(dev, ctx, sof_aux, sof_dais, sof_ends, sof_comp_ends, + &num_confs); if (ret < 0) goto err_end; @@ -1366,8 +1462,8 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) * This should be the last DAI link and it is expected both for monolithic * and functional SOF topologies to support echo reference. */ - num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num + 1; - dai_links = devm_kcalloc(dev, num_links, sizeof(*dai_links), GFP_KERNEL); + num_links = sdw_be_num + ssp_num + dmic_num + hdmi_num + bt_num + num_comp_amps + 1; + dai_links = devm_kcalloc(dev, num_links + 1, sizeof(*dai_links), GFP_KERNEL); if (!dai_links) { ret = -ENOMEM; goto err_end; @@ -1415,6 +1511,13 @@ static int sof_card_dai_links_create(struct snd_soc_card *card) goto err_end; } + /* Companion amp */ + if (num_comp_amps) { + ret = create_sdw_comp_dailinks(card, &dai_links, &be_id, sof_comp_ends, + num_comp_amps); + if (ret) + goto err_end; + } /* dummy echo ref link. keep this as the last DAI link. The DAI link ID does not matter */ ret = create_echoref_dailink(card, &dai_links, &be_id); if (ret) { diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 7a19de75f32b53..2d45744a1dfa3a 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -2269,12 +2269,13 @@ static int is_sdca_aux_dev_present(struct device *dev, } int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, - int *num_devs, int *num_ends, int *num_aux) + int *num_devs, int *num_ends, int *num_aux, int *num_comp_amps) { struct device *dev = card->dev; struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; const struct snd_soc_acpi_link_adr *adr_link; + u32 companion_amp_mask = 0; int i, j, ret; for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { @@ -2284,7 +2285,20 @@ int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; struct asoc_sdw_codec_info *codec_info; - *num_ends += adr_dev->num_endpoints; + for (j = 0; j < adr_dev->num_endpoints; j++) { + /* Skip companion amps */ + if (adr_dev->endpoints[j].companion) { + if (adr_dev->endpoints[j].group_id >= + BITS_PER_TYPE(companion_amp_mask)) { + dev_err(dev, "invalid companion group_id %d\n", + adr_dev->endpoints[j].group_id); + return -EINVAL; + } + companion_amp_mask |= BIT(adr_dev->endpoints[j].group_id); + continue; + } + (*num_ends)++; + } codec_info = asoc_sdw_find_codec_info_part(adr_dev->adr); if (!codec_info) @@ -2301,6 +2315,7 @@ int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, } } + *num_comp_amps = hweight32(companion_amp_mask); dev_dbg(dev, "Found %d devices with %d endpoints\n", *num_devs, *num_ends); return 0; @@ -2412,16 +2427,30 @@ int asoc_sdw_parse_sdw_endpoints(struct device *dev, struct snd_soc_aux_dev *soc_aux, struct asoc_sdw_dailink *soc_dais, struct asoc_sdw_endpoint *soc_ends, + struct asoc_sdw_companion_amp_endpoint *comp_ends, int *num_devs) { struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); struct snd_soc_acpi_mach_params *mach_params = &mach->mach_params; const struct snd_soc_acpi_link_adr *adr_link; struct asoc_sdw_endpoint *soc_end = soc_ends; + u32 companion_amp_mask = 0; int num_dais = 0; int i, j; int ret; + /* Get companion_amp_mask to calculate the companion amp group array index */ + for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { + for (i = 0; i < adr_link->num_adr; i++) { + const struct snd_soc_acpi_adr_device *adr_dev = &adr_link->adr_d[i]; + + for (j = 0; j < adr_dev->num_endpoints; j++) { + if (adr_dev->endpoints[j].companion) + companion_amp_mask |= BIT(adr_dev->endpoints[j].group_id); + } + } + } + for (adr_link = mach_params->links; adr_link->num_adr; adr_link++) { int num_link_dailinks = 0; @@ -2492,9 +2521,50 @@ int asoc_sdw_parse_sdw_endpoints(struct device *dev, int stream; adr_end = &adr_dev->endpoints[j]; + 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; + } dai_info = &codec_info->dais[adr_end->num]; - soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end); + codec_name = asoc_sdw_get_codec_name(dev, dai_info, + adr_link, i); + if (IS_ERR(codec_name)) + return PTR_ERR(codec_name); + if (!codec_name) + return -ENOMEM; + + if (adr_end->companion) { + struct asoc_sdw_endpoint *comp_end; + int comp_index; + + comp_index = hweight32(companion_amp_mask & + (BIT(adr_end->group_id) - 1)); + + comp_end = devm_kcalloc(dev, 1, sizeof(*comp_end), + GFP_KERNEL); + if (!comp_end) + return -ENOMEM; + comp_end->name_prefix = adr_dev->name_prefix; + + comp_end->link_mask = adr_link->mask; + comp_end->codec_name = codec_name; + comp_end->codec_info = codec_info; + comp_end->dai_info = dai_info; + + /* group_position = 0 is the main amp */ + if (!adr_end->group_position) + comp_ends[comp_index].main_amp = comp_end; + else + list_add_tail(&comp_end->list, + &comp_ends[comp_index].comp_ends); + + continue; + } + + soc_dai = asoc_sdw_find_dailink(soc_dais, adr_end); /* * quirk should have higher priority than the sdca properties * in the BIOS. We can't always check the DAI quirk because we @@ -2538,13 +2608,6 @@ int asoc_sdw_parse_sdw_endpoints(struct device *dev, 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) { @@ -2565,13 +2628,6 @@ int asoc_sdw_parse_sdw_endpoints(struct device *dev, num_link_dailinks += !!list_empty(&soc_dai->endpoints); list_add_tail(&soc_end->list, &soc_dai->endpoints); - codec_name = asoc_sdw_get_codec_name(dev, dai_info, - adr_link, i); - if (IS_ERR(codec_name)) - return PTR_ERR(codec_name); - if (!codec_name) - return -ENOMEM; - dev_dbg(dev, "Adding prefix %s for %s\n", adr_dev->name_prefix, codec_name); From e205b792f53dbad8d978196e8b9222c6c1e33f06 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 8 Sep 2026 10:58:14 +0800 Subject: [PATCH 3/5] soundwire: add companion stream support The companion stream is from peripheral to peripheral and all peripherals need to use the same SoundWire frame area to transfer the stream data. Signed-off-by: Bard Liao --- drivers/soundwire/generic_bandwidth_allocation.c | 3 +++ include/linux/soundwire/sdw.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/soundwire/generic_bandwidth_allocation.c b/drivers/soundwire/generic_bandwidth_allocation.c index 29d9fcef8c709b..1db5423a419fe7 100644 --- a/drivers/soundwire/generic_bandwidth_allocation.c +++ b/drivers/soundwire/generic_bandwidth_allocation.c @@ -70,6 +70,9 @@ void sdw_compute_slave_ports(struct sdw_master_runtime *m_rt, port_bo += bps * ch; slave_total_ch += ch; + + if (m_rt->stream->type == SDW_STREAM_COMPANION) + port_bo = t_data->block_offset; } if (m_rt->direction == SDW_DATA_DIR_TX && diff --git a/include/linux/soundwire/sdw.h b/include/linux/soundwire/sdw.h index 326db122bbe6ea..0228ec1eae4c62 100644 --- a/include/linux/soundwire/sdw.h +++ b/include/linux/soundwire/sdw.h @@ -162,6 +162,7 @@ enum sdw_stream_type { SDW_STREAM_PCM = 0, SDW_STREAM_PDM = 1, SDW_STREAM_BPT = 2, + SDW_STREAM_COMPANION = 3, }; /** From a783cc2c3fdef1712f4f2bd5ed3f62b99f0232d3 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 8 Sep 2026 11:34:15 +0800 Subject: [PATCH 4/5] ASoC: SOF: Intel: skip companion amp dai The companion amp dai links should not be created by the default machine driver. We will create a mach table for the config that companion amp is used. Signed-off-by: Bard Liao --- sound/soc/sof/intel/hda.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index e1815bfe358b5d..efe3d3ac58a95e 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -1209,8 +1209,13 @@ static struct snd_soc_acpi_adr_device *find_acpi_adr_device(struct device *dev, return NULL; } for (j = 0; j < codec_info_list[i].dai_num; j++) { - /* Check if the endpoint is present by the SDCA DisCo table */ - if (!is_endpoint_present(sdw_device, codec_info_list[i].dais[j].dai_type)) + /* + * Check if the endpoint is present by the SDCA DisCo table. Also skip the + * companion amp endpoints. The companion amp endpoints should be added in + * the mach table if it is present. + */ + if (!is_endpoint_present(sdw_device, codec_info_list[i].dais[j].dai_type) || + (codec_info_list[i].dais[j].quirk & SOC_SDW_COMPANION_AMPS)) continue; endpoints[ep_index].num = j; From e890ae06f45ed01fe1b7ca6d679130e61946ed22 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 8 Sep 2026 11:29:38 +0800 Subject: [PATCH 5/5] TEST: ASoC: soc_sdw_utils: add componion amp dai for rt712 and rt1320 Add the componion amp dai info for rt712 and rt1320. This commit is only for testing which is not a correct information. Signed-off-by: Bard Liao --- sound/soc/sdw_utils/soc_sdw_utils.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 2d45744a1dfa3a..4f0a32562095c8 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -370,8 +370,16 @@ struct asoc_sdw_codec_info codec_info_list[] = { .quirk = SOC_SDW_CODEC_MIC, .quirk_exclude = true, }, + /* Companion amp */ + { + .direction = {true, true}, + .dai_name = "rt712-sdca-aif4", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .quirk = SOC_SDW_COMPANION_AMPS, + }, }, - .dai_num = 3, + .dai_num = 4, }, { .vendor_id = 0x025d, @@ -535,8 +543,16 @@ struct asoc_sdw_codec_info codec_info_list[] = { .widgets = generic_dmic_widgets, .num_widgets = ARRAY_SIZE(generic_dmic_widgets), }, + /* Companion amp */ + { + .direction = {true, true}, + .dai_name = "rt1320-aif3", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_AMP_IN_DAI_ID}, + .quirk = SOC_SDW_COMPANION_AMPS, + }, }, - .dai_num = 2, + .dai_num = 3, }, { .vendor_id = 0x025d,