[PATCH 17/18] ASoC: SOF: topology: Make widget binding IPC agnostic

Ranjani Sridharan ranjani.sridharan at linux.intel.com
Mon Mar 14 21:05:19 CET 2022


Make widget binding in the topology parser IPC agnostic by introducing a
new op, bind_event, in struct ipc_tplg_widget_ops. Also set the op
for all widget types in the IPC3 topology ops.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao at linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi at linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
---
 sound/soc/sof/ipc3-topology.c | 192 +++++++++++++++++++++++++++++-
 sound/soc/sof/topology.c      | 217 ++--------------------------------
 2 files changed, 202 insertions(+), 207 deletions(-)

diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index 96553d103c85..ea1311192877 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -8,6 +8,7 @@
 //
 
 #include <uapi/sound/sof/tokens.h>
+#include <sound/pcm_params.h>
 #include "sof-priv.h"
 #include "sof-audio.h"
 #include "ops.h"
@@ -1698,6 +1699,194 @@ static int sof_ipc3_control_free(struct snd_sof_dev *sdev, struct snd_sof_contro
 	return sof_ipc_tx_message(sdev->ipc, fcomp.hdr.cmd, &fcomp, sizeof(fcomp), NULL, 0);
 }
 
+/* send pcm params ipc */
+static int sof_ipc3_keyword_detect_pcm_params(struct snd_sof_widget *swidget, int dir)
+{
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_ipc_pcm_params_reply ipc_params_reply;
+	struct snd_pcm_hw_params *params;
+	struct sof_ipc_pcm_params pcm;
+	struct snd_sof_pcm *spcm;
+	int ret;
+
+	/* get runtime PCM params using widget's stream name */
+	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
+	if (!spcm) {
+		dev_err(scomp->dev, "Cannot find PCM for %s\n", swidget->widget->name);
+		return -EINVAL;
+	}
+
+	params = &spcm->params[dir];
+
+	/* set IPC PCM params */
+	memset(&pcm, 0, sizeof(pcm));
+	pcm.hdr.size = sizeof(pcm);
+	pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
+	pcm.comp_id = swidget->comp_id;
+	pcm.params.hdr.size = sizeof(pcm.params);
+	pcm.params.direction = dir;
+	pcm.params.sample_valid_bytes = params_width(params) >> 3;
+	pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
+	pcm.params.rate = params_rate(params);
+	pcm.params.channels = params_channels(params);
+	pcm.params.host_period_bytes = params_period_bytes(params);
+
+	/* set format */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16:
+		pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
+		break;
+	case SNDRV_PCM_FORMAT_S24:
+		pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
+		break;
+	case SNDRV_PCM_FORMAT_S32:
+		pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	/* send IPC to the DSP */
+	ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
+				 &ipc_params_reply, sizeof(ipc_params_reply));
+	if (ret < 0)
+		dev_err(scomp->dev, "%s: PCM params failed for %s\n", __func__,
+			swidget->widget->name);
+
+	return ret;
+}
+
+ /* send stream trigger ipc */
+static int sof_ipc3_keyword_detect_trigger(struct snd_sof_widget *swidget, int cmd)
+{
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_ipc_stream stream;
+	struct sof_ipc_reply reply;
+	int ret;
+
+	/* set IPC stream params */
+	stream.hdr.size = sizeof(stream);
+	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd;
+	stream.comp_id = swidget->comp_id;
+
+	/* send IPC to the DSP */
+	ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
+				 sizeof(stream), &reply, sizeof(reply));
+	if (ret < 0)
+		dev_err(scomp->dev, "%s: Failed to trigger %s\n", __func__, swidget->widget->name);
+
+	return ret;
+}
+
+static int sof_ipc3_keyword_dapm_event(struct snd_soc_dapm_widget *w,
+				       struct snd_kcontrol *k, int event)
+{
+	struct snd_sof_widget *swidget = w->dobj.private;
+	struct snd_soc_component *scomp;
+	int stream = SNDRV_PCM_STREAM_CAPTURE;
+	struct snd_sof_pcm *spcm;
+	int ret = 0;
+
+	if (!swidget)
+		return 0;
+
+	scomp = swidget->scomp;
+
+	dev_dbg(scomp->dev, "received event %d for widget %s\n",
+		event, w->name);
+
+	/* get runtime PCM params using widget's stream name */
+	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
+	if (!spcm) {
+		dev_err(scomp->dev, "%s: Cannot find PCM for %s\n", __func__,
+			swidget->widget->name);
+		return -EINVAL;
+	}
+
+	/* process events */
+	switch (event) {
+	case SND_SOC_DAPM_PRE_PMU:
+		if (spcm->stream[stream].suspend_ignored) {
+			dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
+			return 0;
+		}
+
+		/* set pcm params */
+		ret = sof_ipc3_keyword_detect_pcm_params(swidget, stream);
+		if (ret < 0) {
+			dev_err(scomp->dev, "%s: Failed to set pcm params for widget %s\n",
+				__func__, swidget->widget->name);
+			break;
+		}
+
+		/* start trigger */
+		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
+		if (ret < 0)
+			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
+				swidget->widget->name);
+		break;
+	case SND_SOC_DAPM_POST_PMD:
+		if (spcm->stream[stream].suspend_ignored) {
+			dev_dbg(scomp->dev,
+				"POST_PMD event ignored, KWD pipeline will remain RUNNING\n");
+			return 0;
+		}
+
+		/* stop trigger */
+		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
+		if (ret < 0)
+			dev_err(scomp->dev, "%s: Failed to trigger widget %s\n", __func__,
+				swidget->widget->name);
+
+		/* pcm free */
+		ret = sof_ipc3_keyword_detect_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
+		if (ret < 0)
+			dev_err(scomp->dev, "%s: Failed to free PCM for widget %s\n", __func__,
+				swidget->widget->name);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/* event handlers for keyword detect component */
+static const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
+	{SOF_KEYWORD_DETECT_DAPM_EVENT, sof_ipc3_keyword_dapm_event},
+};
+
+static int sof_ipc3_widget_bind_event(struct snd_soc_component *scomp,
+				      struct snd_sof_widget *swidget, u16 event_type)
+{
+	struct sof_ipc_comp *ipc_comp;
+
+	/* validate widget event type */
+	switch (event_type) {
+	case SOF_KEYWORD_DETECT_DAPM_EVENT:
+		/* only KEYWORD_DETECT comps should handle this */
+		if (swidget->id != snd_soc_dapm_effect)
+			break;
+
+		ipc_comp = swidget->private;
+		if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT)
+			break;
+
+		/* bind event to keyword detect comp */
+		return snd_soc_tplg_widget_bind_event(swidget->widget, sof_kwd_events,
+						      ARRAY_SIZE(sof_kwd_events), event_type);
+	default:
+		break;
+	}
+
+	dev_err(scomp->dev, "Invalid event type %d for widget %s\n", event_type,
+		swidget->widget->name);
+
+	return -EINVAL;
+}
+
 /* token list for each topology object */
 static enum sof_tokens host_token_list[] = {
 	SOF_CORE_TOKENS,
@@ -1790,7 +1979,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY
 				 comp_generic_token_list, ARRAY_SIZE(comp_generic_token_list),
 				 NULL},
 	[snd_soc_dapm_effect] = {sof_widget_update_ipc_comp_process, sof_ipc3_widget_free_comp,
-				 process_token_list, ARRAY_SIZE(process_token_list), NULL},
+				 process_token_list, ARRAY_SIZE(process_token_list),
+				 sof_ipc3_widget_bind_event},
 };
 
 static const struct sof_ipc_tplg_ops ipc3_tplg_ops = {
diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c
index f7adf058a768..70677a36c304 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -14,7 +14,6 @@
 #include <linux/firmware.h>
 #include <linux/workqueue.h>
 #include <sound/tlv.h>
-#include <sound/pcm_params.h>
 #include <uapi/sound/sof/tokens.h>
 #include "sof-priv.h"
 #include "sof-audio.h"
@@ -135,171 +134,6 @@ int sof_update_ipc_object(struct snd_soc_component *scomp, void *object, enum so
 	return 0;
 }
 
-/* send pcm params ipc */
-static int ipc_pcm_params(struct snd_sof_widget *swidget, int dir)
-{
-	struct sof_ipc_pcm_params_reply ipc_params_reply;
-	struct snd_soc_component *scomp = swidget->scomp;
-	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
-	struct sof_ipc_pcm_params pcm;
-	struct snd_pcm_hw_params *params;
-	struct snd_sof_pcm *spcm;
-	int ret;
-
-	memset(&pcm, 0, sizeof(pcm));
-
-	/* get runtime PCM params using widget's stream name */
-	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
-	if (!spcm) {
-		dev_err(scomp->dev, "error: cannot find PCM for %s\n",
-			swidget->widget->name);
-		return -EINVAL;
-	}
-
-	params = &spcm->params[dir];
-
-	/* set IPC PCM params */
-	pcm.hdr.size = sizeof(pcm);
-	pcm.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | SOF_IPC_STREAM_PCM_PARAMS;
-	pcm.comp_id = swidget->comp_id;
-	pcm.params.hdr.size = sizeof(pcm.params);
-	pcm.params.direction = dir;
-	pcm.params.sample_valid_bytes = params_width(params) >> 3;
-	pcm.params.buffer_fmt = SOF_IPC_BUFFER_INTERLEAVED;
-	pcm.params.rate = params_rate(params);
-	pcm.params.channels = params_channels(params);
-	pcm.params.host_period_bytes = params_period_bytes(params);
-
-	/* set format */
-	switch (params_format(params)) {
-	case SNDRV_PCM_FORMAT_S16:
-		pcm.params.frame_fmt = SOF_IPC_FRAME_S16_LE;
-		break;
-	case SNDRV_PCM_FORMAT_S24:
-		pcm.params.frame_fmt = SOF_IPC_FRAME_S24_4LE;
-		break;
-	case SNDRV_PCM_FORMAT_S32:
-		pcm.params.frame_fmt = SOF_IPC_FRAME_S32_LE;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	/* send IPC to the DSP */
-	ret = sof_ipc_tx_message(sdev->ipc, pcm.hdr.cmd, &pcm, sizeof(pcm),
-				 &ipc_params_reply, sizeof(ipc_params_reply));
-	if (ret < 0)
-		dev_err(scomp->dev, "error: pcm params failed for %s\n",
-			swidget->widget->name);
-
-	return ret;
-}
-
- /* send stream trigger ipc */
-static int ipc_trigger(struct snd_sof_widget *swidget, int cmd)
-{
-	struct snd_soc_component *scomp = swidget->scomp;
-	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
-	struct sof_ipc_stream stream;
-	struct sof_ipc_reply reply;
-	int ret;
-
-	/* set IPC stream params */
-	stream.hdr.size = sizeof(stream);
-	stream.hdr.cmd = SOF_IPC_GLB_STREAM_MSG | cmd;
-	stream.comp_id = swidget->comp_id;
-
-	/* send IPC to the DSP */
-	ret = sof_ipc_tx_message(sdev->ipc, stream.hdr.cmd, &stream,
-				 sizeof(stream), &reply, sizeof(reply));
-	if (ret < 0)
-		dev_err(scomp->dev, "error: failed to trigger %s\n",
-			swidget->widget->name);
-
-	return ret;
-}
-
-static int sof_keyword_dapm_event(struct snd_soc_dapm_widget *w,
-				  struct snd_kcontrol *k, int event)
-{
-	struct snd_sof_widget *swidget = w->dobj.private;
-	struct snd_soc_component *scomp;
-	int stream = SNDRV_PCM_STREAM_CAPTURE;
-	struct snd_sof_pcm *spcm;
-	int ret = 0;
-
-	if (!swidget)
-		return 0;
-
-	scomp = swidget->scomp;
-
-	dev_dbg(scomp->dev, "received event %d for widget %s\n",
-		event, w->name);
-
-	/* get runtime PCM params using widget's stream name */
-	spcm = snd_sof_find_spcm_name(scomp, swidget->widget->sname);
-	if (!spcm) {
-		dev_err(scomp->dev, "error: cannot find PCM for %s\n",
-			swidget->widget->name);
-		return -EINVAL;
-	}
-
-	/* process events */
-	switch (event) {
-	case SND_SOC_DAPM_PRE_PMU:
-		if (spcm->stream[stream].suspend_ignored) {
-			dev_dbg(scomp->dev, "PRE_PMU event ignored, KWD pipeline is already RUNNING\n");
-			return 0;
-		}
-
-		/* set pcm params */
-		ret = ipc_pcm_params(swidget, stream);
-		if (ret < 0) {
-			dev_err(scomp->dev,
-				"error: failed to set pcm params for widget %s\n",
-				swidget->widget->name);
-			break;
-		}
-
-		/* start trigger */
-		ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_START);
-		if (ret < 0)
-			dev_err(scomp->dev,
-				"error: failed to trigger widget %s\n",
-				swidget->widget->name);
-		break;
-	case SND_SOC_DAPM_POST_PMD:
-		if (spcm->stream[stream].suspend_ignored) {
-			dev_dbg(scomp->dev, "POST_PMD even ignored, KWD pipeline will remain RUNNING\n");
-			return 0;
-		}
-
-		/* stop trigger */
-		ret = ipc_trigger(swidget, SOF_IPC_STREAM_TRIG_STOP);
-		if (ret < 0)
-			dev_err(scomp->dev,
-				"error: failed to trigger widget %s\n",
-				swidget->widget->name);
-
-		/* pcm free */
-		ret = ipc_trigger(swidget, SOF_IPC_STREAM_PCM_FREE);
-		if (ret < 0)
-			dev_err(scomp->dev,
-				"error: failed to trigger widget %s\n",
-				swidget->widget->name);
-		break;
-	default:
-		break;
-	}
-
-	return ret;
-}
-
-/* event handlers for keyword detect component */
-static const struct snd_soc_tplg_widget_events sof_kwd_events[] = {
-	{SOF_KEYWORD_DETECT_DAPM_EVENT, sof_keyword_dapm_event},
-};
-
 static inline int get_tlv_data(const int *p, int tlv[TLV_ITEMS])
 {
 	/* we only support dB scale TLV type at the moment */
@@ -1323,38 +1157,6 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s
 	return ret;
 }
 
-static int sof_widget_bind_event(struct snd_soc_component *scomp,
-				 struct snd_sof_widget *swidget,
-				 u16 event_type)
-{
-	struct sof_ipc_comp *ipc_comp;
-
-	/* validate widget event type */
-	switch (event_type) {
-	case SOF_KEYWORD_DETECT_DAPM_EVENT:
-		/* only KEYWORD_DETECT comps should handle this */
-		if (swidget->id != snd_soc_dapm_effect)
-			break;
-
-		ipc_comp = swidget->private;
-		if (ipc_comp && ipc_comp->type != SOF_COMP_KEYWORD_DETECT)
-			break;
-
-		/* bind event to keyword detect comp */
-		return snd_soc_tplg_widget_bind_event(swidget->widget,
-						      sof_kwd_events,
-						      ARRAY_SIZE(sof_kwd_events),
-						      event_type);
-	default:
-		break;
-	}
-
-	dev_err(scomp->dev,
-		"error: invalid event type %d for widget %s\n",
-		event_type, swidget->widget->name);
-	return -EINVAL;
-}
-
 static int sof_get_token_value(u32 token_id, struct snd_sof_tuple *tuples, int num_tuples)
 {
 	int i;
@@ -1486,14 +1288,17 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
 
 	/* bind widget to external event */
 	if (tw->event_type) {
-		ret = sof_widget_bind_event(scomp, swidget,
-					    le16_to_cpu(tw->event_type));
-		if (ret) {
-			dev_err(scomp->dev, "error: widget event binding failed\n");
-			kfree(swidget->private);
-			kfree(swidget->tuples);
-			kfree(swidget);
-			return ret;
+		if (widget_ops[w->id].bind_event) {
+			ret = widget_ops[w->id].bind_event(scomp, swidget,
+							   le16_to_cpu(tw->event_type));
+			if (ret) {
+				dev_err(scomp->dev, "widget event binding failed for %s\n",
+					swidget->widget->name);
+				kfree(swidget->private);
+				kfree(swidget->tuples);
+				kfree(swidget);
+				return ret;
+			}
 		}
 	}
 
-- 
2.25.1



More information about the Alsa-devel mailing list