diff mbox series

[05/25] ASoC: meson: codec-glue: add support for capture stream

Message ID 20240314232201.2102178-6-jan.dakinevich@salutedevices.com (mailing list archive)
State New
Headers show
Series Introduce support of audio for Amlogic A1 SoC family | expand

Commit Message

Jan Dakinevich March 14, 2024, 11:21 p.m. UTC
---- >8 ----
Hope, I haven't misinterpreted the terminology and codec-glue's behavior
too much.
---- >8 ----

The glue saves stream's private data in front-end dai and then backend
dai can reach them searching backward from sink to source. For capture
stream everything left the same, but searching should be performed from
source to sink.

Signed-off-by: Jan Dakinevich <jan.dakinevich@salutedevices.com>
---
 sound/soc/meson/meson-codec-glue.c | 174 ++++++++++++++++++++++-------
 sound/soc/meson/meson-codec-glue.h |  23 ++++
 2 files changed, 158 insertions(+), 39 deletions(-)
diff mbox series

Patch

diff --git a/sound/soc/meson/meson-codec-glue.c b/sound/soc/meson/meson-codec-glue.c
index f8c5643f3cfe..da6d65e58d90 100644
--- a/sound/soc/meson/meson-codec-glue.c
+++ b/sound/soc/meson/meson-codec-glue.c
@@ -11,65 +11,94 @@ 
 #include "meson-codec-glue.h"
 
 static struct snd_soc_dapm_widget *
-meson_codec_glue_get_input(struct snd_soc_dapm_widget *w)
+meson_codec_glue_get_data_widget(struct snd_soc_dapm_widget *w, bool playback)
 {
 	struct snd_soc_dapm_path *p;
-	struct snd_soc_dapm_widget *in;
-
-	snd_soc_dapm_widget_for_each_source_path(w, p) {
+	struct snd_soc_dapm_widget *node;
+	enum snd_soc_dapm_type id = playback ? snd_soc_dapm_dai_in
+					     : snd_soc_dapm_dai_out;
+	enum snd_soc_dapm_direction dir = playback ? SND_SOC_DAPM_DIR_IN
+						   : SND_SOC_DAPM_DIR_OUT;
+	enum snd_soc_dapm_direction rdir = playback ? SND_SOC_DAPM_DIR_OUT
+						    : SND_SOC_DAPM_DIR_IN;
+
+	snd_soc_dapm_widget_for_each_path(w, rdir, p) {
 		if (!p->connect)
 			continue;
 
 		/* Check that we still are in the same component */
 		if (snd_soc_dapm_to_component(w->dapm) !=
-		    snd_soc_dapm_to_component(p->source->dapm))
+		    snd_soc_dapm_to_component(p->node[dir]->dapm))
 			continue;
 
-		if (p->source->id == snd_soc_dapm_dai_in)
-			return p->source;
+		if (p->node[dir]->id == id)
+			return p->node[dir];
 
-		in = meson_codec_glue_get_input(p->source);
-		if (in)
-			return in;
+		node = meson_codec_glue_get_data_widget(p->node[dir], playback);
+		if (node)
+			return node;
 	}
 
 	return NULL;
 }
 
-static void meson_codec_glue_input_set_data(struct snd_soc_dai *dai,
-					    struct meson_codec_glue_input *data)
+static void meson_codec_glue_set_data(struct snd_soc_dai *dai,
+				      struct meson_codec_glue_input *data,
+				      bool playback)
+{
+	int stream = playback ? SNDRV_PCM_STREAM_PLAYBACK
+			      : SNDRV_PCM_STREAM_CAPTURE;
+
+	snd_soc_dai_dma_data_set(dai, stream, data);
+}
+
+static struct meson_codec_glue_input *
+meson_codec_glue_get_data(struct snd_soc_dai *dai, bool playback)
 {
-	snd_soc_dai_dma_data_set_playback(dai, data);
+	int stream = playback ? SNDRV_PCM_STREAM_PLAYBACK
+			      : SNDRV_PCM_STREAM_CAPTURE;
+
+	return snd_soc_dai_dma_data_get(dai, stream);
 }
 
 struct meson_codec_glue_input *
 meson_codec_glue_input_get_data(struct snd_soc_dai *dai)
 {
-	return snd_soc_dai_dma_data_get_playback(dai);
+	return meson_codec_glue_get_data(dai, true);
 }
 EXPORT_SYMBOL_GPL(meson_codec_glue_input_get_data);
 
+struct meson_codec_glue_input *
+meson_codec_glue_capture_output_get_data(struct snd_soc_dai *dai)
+{
+	return meson_codec_glue_get_data(dai, false);
+}
+EXPORT_SYMBOL_GPL(meson_codec_glue_capture_output_get_data);
+
 static struct meson_codec_glue_input *
-meson_codec_glue_output_get_input_data(struct snd_soc_dapm_widget *w)
+meson_codec_glue_data(struct snd_soc_dapm_widget *w, bool playback)
 {
-	struct snd_soc_dapm_widget *in =
-		meson_codec_glue_get_input(w);
+	struct snd_soc_dapm_widget *node =
+		meson_codec_glue_get_data_widget(w, playback);
 	struct snd_soc_dai *dai;
 
-	if (WARN_ON(!in))
+	if (WARN_ON(!node))
 		return NULL;
 
-	dai = in->priv;
+	dai = node->priv;
 
-	return meson_codec_glue_input_get_data(dai);
+	return meson_codec_glue_get_data(dai, playback);
 }
 
-int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
-				     struct snd_pcm_hw_params *params,
-				     struct snd_soc_dai *dai)
+static int meson_codec_glue_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *params,
+				      struct snd_soc_dai *dai,
+				      bool playback)
 {
 	struct meson_codec_glue_input *data =
-		meson_codec_glue_input_get_data(dai);
+		meson_codec_glue_get_data(dai, playback);
+	struct snd_soc_pcm_stream *stream = playback ? &dai->driver->playback
+						     : &dai->driver->capture;
 
 	data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
 	data->params.rate_min = params_rate(params);
@@ -77,32 +106,64 @@  int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
 	data->params.formats = 1ULL << (__force int) params_format(params);
 	data->params.channels_min = params_channels(params);
 	data->params.channels_max = params_channels(params);
-	data->params.sig_bits = dai->driver->playback.sig_bits;
+	data->params.sig_bits = stream->sig_bits;
 
 	return 0;
 }
+
+int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params,
+				     struct snd_soc_dai *dai)
+{
+	return meson_codec_glue_hw_params(substream, params, dai, true);
+}
 EXPORT_SYMBOL_GPL(meson_codec_glue_input_hw_params);
 
-int meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai,
-				   unsigned int fmt)
+int meson_codec_glue_capture_output_hw_params(struct snd_pcm_substream *substream,
+				     struct snd_pcm_hw_params *params,
+				     struct snd_soc_dai *dai)
+{
+	return meson_codec_glue_hw_params(substream, params, dai, false);
+}
+EXPORT_SYMBOL_GPL(meson_codec_glue_capture_output_hw_params);
+
+static int meson_codec_glue_set_fmt(struct snd_soc_dai *dai,
+				    unsigned int fmt,
+				    bool playback)
 {
 	struct meson_codec_glue_input *data =
-		meson_codec_glue_input_get_data(dai);
+		meson_codec_glue_get_data(dai, playback);
 
 	/* Save the source stream format for the downstream link */
 	data->fmt = fmt;
 	return 0;
 }
+
+int meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai,
+				   unsigned int fmt)
+{
+	return meson_codec_glue_set_fmt(dai, fmt, true);
+}
 EXPORT_SYMBOL_GPL(meson_codec_glue_input_set_fmt);
 
-int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
-				    struct snd_soc_dai *dai)
+int meson_codec_glue_capture_output_set_fmt(struct snd_soc_dai *dai,
+				    unsigned int fmt)
+{
+	return meson_codec_glue_set_fmt(dai, fmt, false);
+}
+EXPORT_SYMBOL_GPL(meson_codec_glue_capture_output_set_fmt);
+
+static int meson_codec_glue_startup(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai,
+				    bool playback)
 {
+	int stream = playback ? SNDRV_PCM_STREAM_CAPTURE
+			      : SNDRV_PCM_STREAM_PLAYBACK;
 	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
-	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget_capture(dai);
-	struct meson_codec_glue_input *in_data = meson_codec_glue_output_get_input_data(w);
+	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget(dai, stream);
+	struct meson_codec_glue_input *data = meson_codec_glue_data(w, playback);
 
-	if (!in_data)
+	if (!data)
 		return -ENODEV;
 
 	if (WARN_ON(!rtd->dai_link->c2c_params)) {
@@ -111,14 +172,27 @@  int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
 	}
 
 	/* Replace link params with the input params */
-	rtd->dai_link->c2c_params = &in_data->params;
+	rtd->dai_link->c2c_params = &data->params;
 	rtd->dai_link->num_c2c_params = 1;
 
-	return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
+	return snd_soc_runtime_set_dai_fmt(rtd, data->fmt);
+}
+
+int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *dai)
+{
+	return meson_codec_glue_startup(substream, dai, true);
 }
 EXPORT_SYMBOL_GPL(meson_codec_glue_output_startup);
 
-int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai)
+int meson_codec_glue_capture_input_startup(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *dai)
+{
+	return meson_codec_glue_startup(substream, dai, false);
+}
+EXPORT_SYMBOL_GPL(meson_codec_glue_capture_input_startup);
+
+static int meson_codec_glue_dai_probe(struct snd_soc_dai *dai, bool playback)
 {
 	struct meson_codec_glue_input *data;
 
@@ -126,21 +200,43 @@  int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai)
 	if (!data)
 		return -ENOMEM;
 
-	meson_codec_glue_input_set_data(dai, data);
+	meson_codec_glue_set_data(dai, data, playback);
 	return 0;
 }
+
+int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai)
+{
+	return meson_codec_glue_dai_probe(dai, true);
+}
 EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_probe);
 
-int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai)
+int meson_codec_glue_capture_output_dai_probe(struct snd_soc_dai *dai)
+{
+	return meson_codec_glue_dai_probe(dai, false);
+}
+EXPORT_SYMBOL_GPL(meson_codec_glue_capture_output_dai_probe);
+
+static int meson_codec_glue_dai_remove(struct snd_soc_dai *dai, bool playback)
 {
 	struct meson_codec_glue_input *data =
-		meson_codec_glue_input_get_data(dai);
+		meson_codec_glue_get_data(dai, playback);
 
 	kfree(data);
 	return 0;
 }
+
+int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai)
+{
+	return meson_codec_glue_dai_remove(dai, true);
+}
 EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_remove);
 
+int meson_codec_glue_capture_output_dai_remove(struct snd_soc_dai *dai)
+{
+	return meson_codec_glue_dai_remove(dai, false);
+}
+EXPORT_SYMBOL_GPL(meson_codec_glue_capture_output_dai_remove);
+
 MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
 MODULE_DESCRIPTION("Amlogic Codec Glue Helpers");
 MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/meson/meson-codec-glue.h b/sound/soc/meson/meson-codec-glue.h
index 07f99446c0c6..75d20aa75638 100644
--- a/sound/soc/meson/meson-codec-glue.h
+++ b/sound/soc/meson/meson-codec-glue.h
@@ -14,6 +14,10 @@  struct meson_codec_glue_input {
 	unsigned int fmt;
 };
 
+/*
+ * Playback stream
+ */
+
 /* Input helpers */
 struct meson_codec_glue_input *
 meson_codec_glue_input_get_data(struct snd_soc_dai *dai);
@@ -29,4 +33,23 @@  int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai);
 int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai);
 
+/*
+ * Capture stream
+ */
+
+/* Output helpers */
+struct meson_codec_glue_input *
+meson_codec_glue_capture_output_get_data(struct snd_soc_dai *dai);
+int meson_codec_glue_capture_output_hw_params(struct snd_pcm_substream *substream,
+					      struct snd_pcm_hw_params *params,
+					      struct snd_soc_dai *dai);
+int meson_codec_glue_capture_output_set_fmt(struct snd_soc_dai *dai,
+					    unsigned int fmt);
+int meson_codec_glue_capture_output_dai_probe(struct snd_soc_dai *dai);
+int meson_codec_glue_capture_output_dai_remove(struct snd_soc_dai *dai);
+
+/* Input helpers */
+int meson_codec_glue_capture_input_startup(struct snd_pcm_substream *substream,
+					   struct snd_soc_dai *dai);
+
 #endif /* _MESON_CODEC_GLUE_H */