ASoC: SOF: topology: Make widget binding IPC agnostic
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Mon, 14 Mar 2022 20:05:19 +0000 (13:05 -0700)
committerMark Brown <broonie@kernel.org>
Wed, 16 Mar 2022 16:39:12 +0000 (16:39 +0000)
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@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20220314200520.1233427-19-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/ipc3-topology.c
sound/soc/sof/topology.c

index 96553d1..ea13111 100644 (file)
@@ -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 = {
index f7adf05..70677a3 100644 (file)
@@ -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 @@ err:
        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;
+                       }
                }
        }