diff --git a/sound/soc/intel/common/sof-function-topology-lib.c b/sound/soc/intel/common/sof-function-topology-lib.c index 0daa7d83808be6..2f2c902ef90ce9 100644 --- a/sound/soc/intel/common/sof-function-topology-lib.c +++ b/sound/soc/intel/common/sof-function-topology-lib.c @@ -19,6 +19,7 @@ enum tplg_device_id { TPLG_DEVICE_SDCA_MIC, TPLG_DEVICE_INTEL_PCH_DMIC, TPLG_DEVICE_HDMI, + TPLG_DEVICE_LOOPBACK_VIRTUAL, TPLG_DEVICE_MAX }; @@ -81,7 +82,15 @@ int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_ } else if (strstr(dai_link->name, "iDisp")) { tplg_dev = TPLG_DEVICE_HDMI; tplg_dev_name = "hdmi-pcm5"; - + } else if (strstr(dai_link->name, "Loopback_Virtual")) { + tplg_dev = TPLG_DEVICE_LOOPBACK_VIRTUAL; + /* + * Mark the LOOPBACK_VIRTUAL device but no need to create the + * LOOPBACK_VIRTUAL topology. Just to avoid the dai_link is not supported + * error. + */ + tplg_mask |= BIT(tplg_dev); + continue; } else { /* The dai link is not supported by separated tplg yet */ dev_dbg(card->dev, diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 17d00f868d411f..773aa2399b5439 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -23,6 +23,13 @@ static bool disable_function_topology; module_param(disable_function_topology, bool, 0444); MODULE_PARM_DESC(disable_function_topology, "Disable function topology loading"); +#define MAX_USER_TPLG_COUNT 5 + +static char *user_topologies[MAX_USER_TPLG_COUNT]; +static int user_tplg_cnt; +module_param_array(user_topologies, charp, &user_tplg_cnt, 0444); +MODULE_PARM_DESC(index, "Topology list for virtual loop DAI link"); + #define COMP_ID_UNASSIGNED 0xffffffff /* * Constants used in the computation of linear volume gain @@ -2590,6 +2597,40 @@ int snd_sof_load_topology(struct snd_soc_component *scomp, const char *file) } } + /* Loading user defined topologies */ + for (i = 0; i < user_tplg_cnt; i++) { + const char *user_topology = devm_kasprintf(scomp->dev, GFP_KERNEL, "%s/%s", + tplg_filename_prefix, + user_topologies[i]); + + dev_info(scomp->dev, "loading user topology %d: %s\n", i, user_topology); + ret = request_firmware(&fw, user_topology, scomp->dev); + if (ret < 0) { + /* + * snd_soc_tplg_component_remove(scomp) will be called + * if snd_soc_tplg_component_load(scomp) failed and all + * objects in the scomp will be removed. No need to call + * snd_soc_tplg_component_remove(scomp) here. + */ + dev_err(scomp->dev, "tplg request firmware %s failed err: %d\n", + tplg_files[i], ret); + goto out; + } + + if (sdev->dspless_mode_selected) + ret = snd_soc_tplg_component_load(scomp, &sof_dspless_tplg_ops, fw); + else + ret = snd_soc_tplg_component_load(scomp, &sof_tplg_ops, fw); + + release_firmware(fw); + + if (ret < 0) { + dev_err(scomp->dev, "tplg %s component load failed %d\n", + tplg_files[i], ret); + goto out; + } + } + /* call sof_complete when topologies are loaded successfully */ ret = sof_complete(scomp);