From 8a2e4a734f5ecbc48a3227c8ad68c12a71272c79 Mon Sep 17 00:00:00 2001
From: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Date: Mon, 14 Mar 2022 13:05:09 -0700
Subject: [PATCH] ASoC: SOF: topology: Make pga widget parsing IPC agnostic
Mime-version: 1.0
Content-type: text/plain; charset=UTF-8
Content-transfer-encoding: 8bit
Git-commit: 8a2e4a734f5ecbc48a3227c8ad68c12a71272c79
Patch-mainline: v5.18-rc1
References: jsc#PED-850

Define the list of tokens pertaining to the pga type widgets, parse and
save them as part of the swidget tuples array. Once topology parsing is
complete, these tokens will be applied to create the IPC structure for the
pga component based on the topology widget_setup op in ipc3_tplg_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-9-ranjani.sridharan@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 sound/soc/sof/ipc3-topology.c | 78 ++++++++++++++++++++++++++++++
 sound/soc/sof/topology.c      | 91 +++--------------------------------
 2 files changed, 86 insertions(+), 83 deletions(-)

diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c
index e05d6b816fac..517ba84eb4c4 100644
--- a/sound/soc/sof/ipc3-topology.c
+++ b/sound/soc/sof/ipc3-topology.c
@@ -43,6 +43,14 @@ static const struct sof_topology_token pipeline_tokens[] = {
 
 };
 
+/* volume */
+static const struct sof_topology_token volume_tokens[] = {
+	{SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc_comp_volume, ramp)},
+	{SOF_TKN_VOLUME_RAMP_STEP_MS, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+		offsetof(struct sof_ipc_comp_volume, initial_ramp)},
+};
+
 /* PCM */
 static const struct sof_topology_token pcm_tokens[] = {
 	{SOF_TKN_PCM_DMAC_CONFIG, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -80,6 +88,7 @@ static const struct sof_token_info ipc3_token_list[SOF_TOKEN_COUNT] = {
 	[SOF_CORE_TOKENS] = {"Core tokens", core_tokens, ARRAY_SIZE(core_tokens)},
 	[SOF_COMP_EXT_TOKENS] = {"AFE tokens", comp_ext_tokens, ARRAY_SIZE(comp_ext_tokens)},
 	[SOF_BUFFER_TOKENS] = {"Buffer tokens", buffer_tokens, ARRAY_SIZE(buffer_tokens)},
+	[SOF_VOLUME_TOKENS] = {"Volume tokens", volume_tokens, ARRAY_SIZE(volume_tokens)},
 };
 
 /**
@@ -281,6 +290,66 @@ static int sof_ipc3_widget_setup_comp_buffer(struct snd_sof_widget *swidget)
 	return 0;
 }
 
+/*
+ * PGA Topology
+ */
+
+static int sof_ipc3_widget_setup_comp_pga(struct snd_sof_widget *swidget)
+{
+	struct snd_soc_component *scomp = swidget->scomp;
+	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+	struct sof_ipc_comp_volume *volume;
+	struct snd_sof_control *scontrol;
+	size_t ipc_size = sizeof(*volume);
+	int min_step, max_step;
+	int ret;
+
+	volume = sof_comp_alloc(swidget, &ipc_size, swidget->pipeline_id);
+	if (!volume)
+		return -ENOMEM;
+
+	swidget->private = volume;
+
+	/* configure volume IPC message */
+	volume->comp.type = SOF_COMP_VOLUME;
+	volume->config.hdr.size = sizeof(volume->config);
+
+	/* parse one set of volume tokens */
+	ret = sof_update_ipc_object(scomp, volume, SOF_VOLUME_TOKENS, swidget->tuples,
+				    swidget->num_tuples, sizeof(*volume), 1);
+	if (ret < 0)
+		goto err;
+
+	/* parse one set of comp tokens */
+	ret = sof_update_ipc_object(scomp, &volume->config, SOF_COMP_TOKENS,
+				    swidget->tuples, swidget->num_tuples,
+				    sizeof(volume->config), 1);
+	if (ret < 0)
+		goto err;
+
+	dev_dbg(scomp->dev, "loaded PGA %s\n", swidget->widget->name);
+	sof_dbg_comp_config(scomp, &volume->config);
+
+	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
+		if (scontrol->comp_id == swidget->comp_id &&
+		    scontrol->volume_table) {
+			min_step = scontrol->min_volume_step;
+			max_step = scontrol->max_volume_step;
+			volume->min_value = scontrol->volume_table[min_step];
+			volume->max_value = scontrol->volume_table[max_step];
+			volume->channels = scontrol->num_channels;
+			break;
+		}
+	}
+
+	return 0;
+err:
+	kfree(swidget->private);
+	swidget->private = NULL;
+
+	return ret;
+}
+
 /* token list for each topology object */
 static enum sof_tokens host_token_list[] = {
 	SOF_CORE_TOKENS,
@@ -300,6 +369,13 @@ static enum sof_tokens pipeline_token_list[] = {
 	SOF_SCHED_TOKENS,
 };
 
+static enum sof_tokens pga_token_list[] = {
+	SOF_CORE_TOKENS,
+	SOF_COMP_EXT_TOKENS,
+	SOF_VOLUME_TOKENS,
+	SOF_COMP_TOKENS,
+};
+
 static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TYPE_COUNT] = {
 	[snd_soc_dapm_aif_in] =  {sof_ipc3_widget_setup_comp_host, sof_ipc3_widget_free_comp,
 				  host_token_list, ARRAY_SIZE(host_token_list), NULL},
@@ -309,6 +385,8 @@ static const struct sof_ipc_tplg_widget_ops tplg_ipc3_widget_ops[SND_SOC_DAPM_TY
 				 buffer_token_list, ARRAY_SIZE(buffer_token_list), NULL},
 	[snd_soc_dapm_scheduler] = {sof_ipc3_widget_setup_comp_pipeline, sof_ipc3_widget_free_comp,
 				    pipeline_token_list, ARRAY_SIZE(pipeline_token_list), NULL},
+	[snd_soc_dapm_pga] = {sof_ipc3_widget_setup_comp_pga, sof_ipc3_widget_free_comp,
+			      pga_token_list, ARRAY_SIZE(pga_token_list), NULL},
 };
 
 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 88214ec2df5a..bd62658629f5 100644
--- a/sound/soc/sof/topology.c
+++ b/sound/soc/sof/topology.c
@@ -629,15 +629,6 @@ static const struct sof_topology_token dai_link_tokens[] = {
 		offsetof(struct sof_ipc_dai_config, dai_index)},
 };
 
-/* volume */
-static const struct sof_topology_token volume_tokens[] = {
-	{SOF_TKN_VOLUME_RAMP_STEP_TYPE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
-		get_token_u32, offsetof(struct sof_ipc_comp_volume, ramp)},
-	{SOF_TKN_VOLUME_RAMP_STEP_MS,
-		SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
-		offsetof(struct sof_ipc_comp_volume, initial_ramp)},
-};
-
 /* SRC */
 static const struct sof_topology_token src_tokens[] = {
 	{SOF_TKN_SRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
@@ -1878,78 +1869,6 @@ static int sof_widget_load_mux(struct snd_soc_component *scomp, int index,
 	return 0;
 }
 
-/*
- * PGA Topology
- */
-
-static int sof_widget_load_pga(struct snd_soc_component *scomp, int index,
-			       struct snd_sof_widget *swidget,
-			       struct snd_soc_tplg_dapm_widget *tw)
-{
-	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
-	struct snd_soc_tplg_private *private = &tw->priv;
-	struct sof_ipc_comp_volume *volume;
-	struct snd_sof_control *scontrol;
-	size_t ipc_size = sizeof(*volume);
-	int min_step;
-	int max_step;
-	int ret;
-
-	volume = (struct sof_ipc_comp_volume *)
-		 sof_comp_alloc(swidget, &ipc_size, index);
-	if (!volume)
-		return -ENOMEM;
-
-	if (!le32_to_cpu(tw->num_kcontrols)) {
-		dev_err(scomp->dev, "error: invalid kcontrol count %d for volume\n",
-			tw->num_kcontrols);
-		ret = -EINVAL;
-		goto err;
-	}
-
-	/* configure volume IPC message */
-	volume->comp.type = SOF_COMP_VOLUME;
-	volume->config.hdr.size = sizeof(volume->config);
-
-	ret = sof_parse_tokens(scomp, volume, volume_tokens,
-			       ARRAY_SIZE(volume_tokens), private->array,
-			       le32_to_cpu(private->size));
-	if (ret != 0) {
-		dev_err(scomp->dev, "error: parse volume tokens failed %d\n",
-			private->size);
-		goto err;
-	}
-	ret = sof_parse_tokens(scomp, &volume->config, comp_tokens,
-			       ARRAY_SIZE(comp_tokens), private->array,
-			       le32_to_cpu(private->size));
-	if (ret != 0) {
-		dev_err(scomp->dev, "error: parse volume.cfg tokens failed %d\n",
-			le32_to_cpu(private->size));
-		goto err;
-	}
-
-	sof_dbg_comp_config(scomp, &volume->config);
-
-	swidget->private = volume;
-
-	list_for_each_entry(scontrol, &sdev->kcontrol_list, list) {
-		if (scontrol->comp_id == swidget->comp_id &&
-		    scontrol->volume_table) {
-			min_step = scontrol->min_volume_step;
-			max_step = scontrol->max_volume_step;
-			volume->min_value = scontrol->volume_table[min_step];
-			volume->max_value = scontrol->volume_table[max_step];
-			volume->channels = scontrol->num_channels;
-			break;
-		}
-	}
-
-	return 0;
-err:
-	kfree(volume);
-	return ret;
-}
-
 /*
  * SRC Topology
  */
@@ -2426,8 +2345,14 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
 		ret = sof_widget_load_mixer(scomp, index, swidget, tw);
 		break;
 	case snd_soc_dapm_pga:
-		ret = sof_widget_load_pga(scomp, index, swidget, tw);
-		break;
+		if (!le32_to_cpu(tw->num_kcontrols)) {
+			dev_err(scomp->dev, "invalid kcontrol count %d for volume\n",
+				tw->num_kcontrols);
+			ret = -EINVAL;
+			break;
+		}
+
+		fallthrough;
 	case snd_soc_dapm_buffer:
 	case snd_soc_dapm_scheduler:
 	case snd_soc_dapm_aif_out:
-- 
2.35.3

