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