Skip to content

Commit 0720941

Browse files
committed
ASoC: SOF: sof-audio: Add support for hostless pipelines
This patch introduces the implementation of hostless pipelines in the SOF driver by leveraging virtual widgets for DAPM. Hostless pipelines are used in scenarios where audio data does not originate from or terminate at the host, such as internal DSP processing pipelines or feedback loops. The implementation includes: - Support for virtual widgets in the topology to represent hostless pipelines. These virtual widgets are solely for the purpose of propagating the hw_params confirguation to the codec in the absence of a AIF component - Virtual widgets are treated as checkpoints to stop propagating widget setup/free in the SOF driver. This patch updates the logic to the widget setup and free routines to handle virtual widgets and the rest of pipeline downstream from a virtual widget. An example of a hostless pipeline in topology is: Virtual input widget -> ToneGen -> mixin -> mixout -> gain -> DAI widget This change enables the SOF driver to handle pipelines that are entirely internal to the DSP, improving support for use cases like sidetone, amplifier feedback, and other DSP-only processing scenarios. Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
1 parent dde271f commit 0720941

File tree

1 file changed

+65
-24
lines changed

1 file changed

+65
-24
lines changed

sound/soc/sof/sof-audio.c

Lines changed: 65 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,19 @@
1313
#include "sof-audio.h"
1414
#include "ops.h"
1515

16+
/*
17+
* Check is a DAI widget is an aggregated DAI. Aggregated DAI's have names ending in numbers
18+
* starting with 0 and only the first DAI needs to be set up in the firmware. The rest of
19+
* the aggregated DAI's are represented in the topology graph for completeness but do not
20+
* need any firmware configuration.
21+
*/
22+
static bool is_aggregated_dai(struct snd_sof_widget *swidget)
23+
{
24+
return (WIDGET_IS_DAI(swidget->id) &&
25+
isdigit(swidget->widget->name[strlen(swidget->widget->name) - 1]) &&
26+
swidget->widget->name[strlen(swidget->widget->name) - 1] != '0');
27+
}
28+
1629
static bool is_virtual_widget(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
1730
const char *func)
1831
{
@@ -412,6 +425,10 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg
412425
struct snd_soc_dapm_path *p;
413426

414427
if (is_virtual_widget(sdev, widget, __func__))
428+
goto sink_unprepare;
429+
430+
/* skip aggregated DAIs */
431+
if (!swidget || is_aggregated_dai(swidget))
415432
return;
416433

417434
/* skip if the widget is in use or if it is already unprepared */
@@ -452,12 +469,16 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
452469
int ret;
453470

454471
if (is_virtual_widget(sdev, widget, __func__))
455-
return 0;
472+
goto sink_prepare;
456473

457474
widget_ops = tplg_ops ? tplg_ops->widget : NULL;
458475
if (!widget_ops)
459476
return 0;
460477

478+
/* skip aggregated DAIs */
479+
if (!swidget || is_aggregated_dai(swidget))
480+
return 0;
481+
461482
if (!swidget || !widget_ops[widget->id].ipc_prepare || swidget->prepared)
462483
goto sink_prepare;
463484

@@ -506,18 +527,23 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap
506527
{
507528
struct snd_soc_dapm_widget_list *list = spcm->stream[dir].list;
508529
struct snd_soc_dapm_path *p;
530+
struct snd_sof_widget *swidget;
509531
int err;
510532
int ret = 0;
511533

512534
if (is_virtual_widget(sdev, widget, __func__))
513-
return 0;
535+
goto sink_free;
514536

515-
if (widget->dobj.private) {
516-
err = sof_widget_free(sdev, widget->dobj.private);
517-
if (err < 0)
518-
ret = err;
519-
}
537+
swidget = widget->dobj.private;
520538

539+
/* skip aggregated DAIs */
540+
if (!swidget || is_aggregated_dai(swidget))
541+
return 0;
542+
543+
err = sof_widget_free(sdev, widget->dobj.private);
544+
if (err < 0)
545+
ret = err;
546+
sink_free:
521547
/* free all widgets in the sink paths even in case of error to keep use counts balanced */
522548
snd_soc_dapm_widget_for_each_sink_path(widget, p) {
523549
if (!p->walking) {
@@ -552,11 +578,15 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d
552578
int ret;
553579

554580
if (is_virtual_widget(sdev, widget, __func__))
555-
return 0;
581+
goto sink_setup;
556582

557583
if (swidget) {
558584
int i;
559585

586+
/* skip aggregated DAIs */
587+
if (!swidget || is_aggregated_dai(swidget))
588+
return 0;
589+
560590
ret = sof_widget_setup(sdev, widget->dobj.private);
561591
if (ret < 0)
562592
return ret;
@@ -619,11 +649,10 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm,
619649
return 0;
620650

621651
for_each_dapm_widgets(list, i, widget) {
622-
if (is_virtual_widget(sdev, widget, __func__))
623-
continue;
624652

625-
/* starting widget for playback is AIF type */
626-
if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_aif_in)
653+
/* starting widget for playback is of AIF or snd_soc_dapm_input type */
654+
if (dir == SNDRV_PCM_STREAM_PLAYBACK && (widget->id != snd_soc_dapm_aif_in &&
655+
widget->id != snd_soc_dapm_input))
627656
continue;
628657

629658
/* starting widget for capture is DAI type */
@@ -904,29 +933,41 @@ struct snd_sof_widget *snd_sof_find_swidget(struct snd_soc_component *scomp,
904933
return NULL;
905934
}
906935

907-
/* find widget by stream name and direction */
908-
struct snd_sof_widget *
909-
snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
910-
const char *pcm_name, int dir)
936+
static struct snd_sof_widget *snd_sof_find_swidget_sname_type(struct snd_soc_component *scomp,
937+
const char *sname,
938+
enum snd_soc_dapm_type type)
911939
{
912940
struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
913941
struct snd_sof_widget *swidget;
914-
enum snd_soc_dapm_type type;
915-
916-
if (dir == SNDRV_PCM_STREAM_PLAYBACK)
917-
type = snd_soc_dapm_aif_in;
918-
else
919-
type = snd_soc_dapm_aif_out;
920942

921943
list_for_each_entry(swidget, &sdev->widget_list, list) {
922-
if (!strcmp(pcm_name, swidget->widget->sname) &&
923-
swidget->id == type)
944+
if (!strcmp(sname, swidget->widget->sname) && swidget->id == type)
924945
return swidget;
925946
}
926947

927948
return NULL;
928949
}
929950

951+
/* find widget by stream name and direction */
952+
struct snd_sof_widget *
953+
snd_sof_find_swidget_sname(struct snd_soc_component *scomp,
954+
const char *pcm_name, int dir)
955+
{
956+
if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
957+
struct snd_sof_widget *swidget;
958+
959+
/* first look for an aif_in type widget */
960+
swidget = snd_sof_find_swidget_sname_type(scomp, pcm_name, snd_soc_dapm_aif_in);
961+
if (swidget)
962+
return swidget;
963+
964+
/* if not found, look for an input type widget */
965+
return snd_sof_find_swidget_sname_type(scomp, pcm_name, snd_soc_dapm_input);
966+
}
967+
968+
return snd_sof_find_swidget_sname_type(scomp, pcm_name, snd_soc_dapm_aif_out);
969+
}
970+
930971
struct snd_sof_dai *snd_sof_find_dai(struct snd_soc_component *scomp,
931972
const char *name)
932973
{

0 commit comments

Comments
 (0)