xref: /openbmc/linux/sound/soc/meson/meson-codec-glue.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
19c29fd9bSJerome Brunet // SPDX-License-Identifier: GPL-2.0
29c29fd9bSJerome Brunet //
39c29fd9bSJerome Brunet // Copyright (c) 2019 BayLibre, SAS.
49c29fd9bSJerome Brunet // Author: Jerome Brunet <jbrunet@baylibre.com>
59c29fd9bSJerome Brunet 
69c29fd9bSJerome Brunet #include <linux/module.h>
79c29fd9bSJerome Brunet #include <sound/pcm_params.h>
89c29fd9bSJerome Brunet #include <sound/soc.h>
99c29fd9bSJerome Brunet #include <sound/soc-dai.h>
109c29fd9bSJerome Brunet 
119c29fd9bSJerome Brunet #include "meson-codec-glue.h"
129c29fd9bSJerome Brunet 
139c29fd9bSJerome Brunet static struct snd_soc_dapm_widget *
meson_codec_glue_get_input(struct snd_soc_dapm_widget * w)149c29fd9bSJerome Brunet meson_codec_glue_get_input(struct snd_soc_dapm_widget *w)
159c29fd9bSJerome Brunet {
167188b28fSPierre-Louis Bossart 	struct snd_soc_dapm_path *p;
179c29fd9bSJerome Brunet 	struct snd_soc_dapm_widget *in;
189c29fd9bSJerome Brunet 
199c29fd9bSJerome Brunet 	snd_soc_dapm_widget_for_each_source_path(w, p) {
209c29fd9bSJerome Brunet 		if (!p->connect)
219c29fd9bSJerome Brunet 			continue;
229c29fd9bSJerome Brunet 
239c29fd9bSJerome Brunet 		/* Check that we still are in the same component */
249c29fd9bSJerome Brunet 		if (snd_soc_dapm_to_component(w->dapm) !=
259c29fd9bSJerome Brunet 		    snd_soc_dapm_to_component(p->source->dapm))
269c29fd9bSJerome Brunet 			continue;
279c29fd9bSJerome Brunet 
289c29fd9bSJerome Brunet 		if (p->source->id == snd_soc_dapm_dai_in)
299c29fd9bSJerome Brunet 			return p->source;
309c29fd9bSJerome Brunet 
319c29fd9bSJerome Brunet 		in = meson_codec_glue_get_input(p->source);
329c29fd9bSJerome Brunet 		if (in)
339c29fd9bSJerome Brunet 			return in;
349c29fd9bSJerome Brunet 	}
359c29fd9bSJerome Brunet 
369c29fd9bSJerome Brunet 	return NULL;
379c29fd9bSJerome Brunet }
389c29fd9bSJerome Brunet 
meson_codec_glue_input_set_data(struct snd_soc_dai * dai,struct meson_codec_glue_input * data)399c29fd9bSJerome Brunet static void meson_codec_glue_input_set_data(struct snd_soc_dai *dai,
409c29fd9bSJerome Brunet 					    struct meson_codec_glue_input *data)
419c29fd9bSJerome Brunet {
42c765cedaSKuninori Morimoto 	snd_soc_dai_dma_data_set_playback(dai, data);
439c29fd9bSJerome Brunet }
449c29fd9bSJerome Brunet 
459c29fd9bSJerome Brunet struct meson_codec_glue_input *
meson_codec_glue_input_get_data(struct snd_soc_dai * dai)469c29fd9bSJerome Brunet meson_codec_glue_input_get_data(struct snd_soc_dai *dai)
479c29fd9bSJerome Brunet {
48c765cedaSKuninori Morimoto 	return snd_soc_dai_dma_data_get_playback(dai);
499c29fd9bSJerome Brunet }
509c29fd9bSJerome Brunet EXPORT_SYMBOL_GPL(meson_codec_glue_input_get_data);
519c29fd9bSJerome Brunet 
529c29fd9bSJerome Brunet static struct meson_codec_glue_input *
meson_codec_glue_output_get_input_data(struct snd_soc_dapm_widget * w)539c29fd9bSJerome Brunet meson_codec_glue_output_get_input_data(struct snd_soc_dapm_widget *w)
549c29fd9bSJerome Brunet {
559c29fd9bSJerome Brunet 	struct snd_soc_dapm_widget *in =
569c29fd9bSJerome Brunet 		meson_codec_glue_get_input(w);
579c29fd9bSJerome Brunet 	struct snd_soc_dai *dai;
589c29fd9bSJerome Brunet 
599c29fd9bSJerome Brunet 	if (WARN_ON(!in))
609c29fd9bSJerome Brunet 		return NULL;
619c29fd9bSJerome Brunet 
629c29fd9bSJerome Brunet 	dai = in->priv;
639c29fd9bSJerome Brunet 
649c29fd9bSJerome Brunet 	return meson_codec_glue_input_get_data(dai);
659c29fd9bSJerome Brunet }
669c29fd9bSJerome Brunet 
meson_codec_glue_input_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)679c29fd9bSJerome Brunet int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
689c29fd9bSJerome Brunet 				     struct snd_pcm_hw_params *params,
699c29fd9bSJerome Brunet 				     struct snd_soc_dai *dai)
709c29fd9bSJerome Brunet {
719c29fd9bSJerome Brunet 	struct meson_codec_glue_input *data =
729c29fd9bSJerome Brunet 		meson_codec_glue_input_get_data(dai);
739c29fd9bSJerome Brunet 
749c29fd9bSJerome Brunet 	data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
759c29fd9bSJerome Brunet 	data->params.rate_min = params_rate(params);
769c29fd9bSJerome Brunet 	data->params.rate_max = params_rate(params);
773cd23f02SJerome Brunet 	data->params.formats = 1ULL << (__force int) params_format(params);
789c29fd9bSJerome Brunet 	data->params.channels_min = params_channels(params);
799c29fd9bSJerome Brunet 	data->params.channels_max = params_channels(params);
809c29fd9bSJerome Brunet 	data->params.sig_bits = dai->driver->playback.sig_bits;
819c29fd9bSJerome Brunet 
829c29fd9bSJerome Brunet 	return 0;
839c29fd9bSJerome Brunet }
849c29fd9bSJerome Brunet EXPORT_SYMBOL_GPL(meson_codec_glue_input_hw_params);
859c29fd9bSJerome Brunet 
meson_codec_glue_input_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)869c29fd9bSJerome Brunet int meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai,
879c29fd9bSJerome Brunet 				   unsigned int fmt)
889c29fd9bSJerome Brunet {
899c29fd9bSJerome Brunet 	struct meson_codec_glue_input *data =
909c29fd9bSJerome Brunet 		meson_codec_glue_input_get_data(dai);
919c29fd9bSJerome Brunet 
929c29fd9bSJerome Brunet 	/* Save the source stream format for the downstream link */
939c29fd9bSJerome Brunet 	data->fmt = fmt;
949c29fd9bSJerome Brunet 	return 0;
959c29fd9bSJerome Brunet }
969c29fd9bSJerome Brunet EXPORT_SYMBOL_GPL(meson_codec_glue_input_set_fmt);
979c29fd9bSJerome Brunet 
meson_codec_glue_output_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)989c29fd9bSJerome Brunet int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
999c29fd9bSJerome Brunet 				    struct snd_soc_dai *dai)
1009c29fd9bSJerome Brunet {
101371a014dSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
102c765cedaSKuninori Morimoto 	struct snd_soc_dapm_widget *w = snd_soc_dai_get_widget_capture(dai);
103c765cedaSKuninori Morimoto 	struct meson_codec_glue_input *in_data = meson_codec_glue_output_get_input_data(w);
1049c29fd9bSJerome Brunet 
1059c29fd9bSJerome Brunet 	if (!in_data)
1069c29fd9bSJerome Brunet 		return -ENODEV;
1079c29fd9bSJerome Brunet 
108*433f4a16SKuninori Morimoto 	if (WARN_ON(!rtd->dai_link->c2c_params)) {
1099c29fd9bSJerome Brunet 		dev_warn(dai->dev, "codec2codec link expected\n");
1109c29fd9bSJerome Brunet 		return -EINVAL;
1119c29fd9bSJerome Brunet 	}
1129c29fd9bSJerome Brunet 
1139c29fd9bSJerome Brunet 	/* Replace link params with the input params */
114*433f4a16SKuninori Morimoto 	rtd->dai_link->c2c_params = &in_data->params;
115*433f4a16SKuninori Morimoto 	rtd->dai_link->num_c2c_params = 1;
1169c29fd9bSJerome Brunet 
1179c29fd9bSJerome Brunet 	return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
1189c29fd9bSJerome Brunet }
1199c29fd9bSJerome Brunet EXPORT_SYMBOL_GPL(meson_codec_glue_output_startup);
1209c29fd9bSJerome Brunet 
meson_codec_glue_input_dai_probe(struct snd_soc_dai * dai)1219c29fd9bSJerome Brunet int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai)
1229c29fd9bSJerome Brunet {
1239c29fd9bSJerome Brunet 	struct meson_codec_glue_input *data;
1249c29fd9bSJerome Brunet 
1259c29fd9bSJerome Brunet 	data = kzalloc(sizeof(*data), GFP_KERNEL);
1269c29fd9bSJerome Brunet 	if (!data)
1279c29fd9bSJerome Brunet 		return -ENOMEM;
1289c29fd9bSJerome Brunet 
1299c29fd9bSJerome Brunet 	meson_codec_glue_input_set_data(dai, data);
1309c29fd9bSJerome Brunet 	return 0;
1319c29fd9bSJerome Brunet }
1329c29fd9bSJerome Brunet EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_probe);
1339c29fd9bSJerome Brunet 
meson_codec_glue_input_dai_remove(struct snd_soc_dai * dai)1349c29fd9bSJerome Brunet int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai)
1359c29fd9bSJerome Brunet {
1369c29fd9bSJerome Brunet 	struct meson_codec_glue_input *data =
1379c29fd9bSJerome Brunet 		meson_codec_glue_input_get_data(dai);
1389c29fd9bSJerome Brunet 
1399c29fd9bSJerome Brunet 	kfree(data);
1409c29fd9bSJerome Brunet 	return 0;
1419c29fd9bSJerome Brunet }
1429c29fd9bSJerome Brunet EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_remove);
1439c29fd9bSJerome Brunet 
1449c29fd9bSJerome Brunet MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
1459c29fd9bSJerome Brunet MODULE_DESCRIPTION("Amlogic Codec Glue Helpers");
1469c29fd9bSJerome Brunet MODULE_LICENSE("GPL v2");
1479c29fd9bSJerome Brunet 
148