18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci//
38c2ecf20Sopenharmony_ci// Copyright (c) 2019 BayLibre, SAS.
48c2ecf20Sopenharmony_ci// Author: Jerome Brunet <jbrunet@baylibre.com>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/module.h>
78c2ecf20Sopenharmony_ci#include <sound/pcm_params.h>
88c2ecf20Sopenharmony_ci#include <sound/soc.h>
98c2ecf20Sopenharmony_ci#include <sound/soc-dai.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "meson-codec-glue.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_cistatic struct snd_soc_dapm_widget *
148c2ecf20Sopenharmony_cimeson_codec_glue_get_input(struct snd_soc_dapm_widget *w)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	struct snd_soc_dapm_path *p = NULL;
178c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *in;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	snd_soc_dapm_widget_for_each_source_path(w, p) {
208c2ecf20Sopenharmony_ci		if (!p->connect)
218c2ecf20Sopenharmony_ci			continue;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci		/* Check that we still are in the same component */
248c2ecf20Sopenharmony_ci		if (snd_soc_dapm_to_component(w->dapm) !=
258c2ecf20Sopenharmony_ci		    snd_soc_dapm_to_component(p->source->dapm))
268c2ecf20Sopenharmony_ci			continue;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci		if (p->source->id == snd_soc_dapm_dai_in)
298c2ecf20Sopenharmony_ci			return p->source;
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci		in = meson_codec_glue_get_input(p->source);
328c2ecf20Sopenharmony_ci		if (in)
338c2ecf20Sopenharmony_ci			return in;
348c2ecf20Sopenharmony_ci	}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	return NULL;
378c2ecf20Sopenharmony_ci}
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic void meson_codec_glue_input_set_data(struct snd_soc_dai *dai,
408c2ecf20Sopenharmony_ci					    struct meson_codec_glue_input *data)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	dai->playback_dma_data = data;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_cistruct meson_codec_glue_input *
468c2ecf20Sopenharmony_cimeson_codec_glue_input_get_data(struct snd_soc_dai *dai)
478c2ecf20Sopenharmony_ci{
488c2ecf20Sopenharmony_ci	return dai->playback_dma_data;
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(meson_codec_glue_input_get_data);
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_cistatic struct meson_codec_glue_input *
538c2ecf20Sopenharmony_cimeson_codec_glue_output_get_input_data(struct snd_soc_dapm_widget *w)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct snd_soc_dapm_widget *in =
568c2ecf20Sopenharmony_ci		meson_codec_glue_get_input(w);
578c2ecf20Sopenharmony_ci	struct snd_soc_dai *dai;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	if (WARN_ON(!in))
608c2ecf20Sopenharmony_ci		return NULL;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	dai = in->priv;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	return meson_codec_glue_input_get_data(dai);
658c2ecf20Sopenharmony_ci}
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ciint meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
688c2ecf20Sopenharmony_ci				     struct snd_pcm_hw_params *params,
698c2ecf20Sopenharmony_ci				     struct snd_soc_dai *dai)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct meson_codec_glue_input *data =
728c2ecf20Sopenharmony_ci		meson_codec_glue_input_get_data(dai);
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
758c2ecf20Sopenharmony_ci	data->params.rate_min = params_rate(params);
768c2ecf20Sopenharmony_ci	data->params.rate_max = params_rate(params);
778c2ecf20Sopenharmony_ci	data->params.formats = 1ULL << (__force int) params_format(params);
788c2ecf20Sopenharmony_ci	data->params.channels_min = params_channels(params);
798c2ecf20Sopenharmony_ci	data->params.channels_max = params_channels(params);
808c2ecf20Sopenharmony_ci	data->params.sig_bits = dai->driver->playback.sig_bits;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	return 0;
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(meson_codec_glue_input_hw_params);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciint meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai,
878c2ecf20Sopenharmony_ci				   unsigned int fmt)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct meson_codec_glue_input *data =
908c2ecf20Sopenharmony_ci		meson_codec_glue_input_get_data(dai);
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* Save the source stream format for the downstream link */
938c2ecf20Sopenharmony_ci	data->fmt = fmt;
948c2ecf20Sopenharmony_ci	return 0;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(meson_codec_glue_input_set_fmt);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ciint meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
998c2ecf20Sopenharmony_ci				    struct snd_soc_dai *dai)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
1028c2ecf20Sopenharmony_ci	struct meson_codec_glue_input *in_data =
1038c2ecf20Sopenharmony_ci		meson_codec_glue_output_get_input_data(dai->capture_widget);
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (!in_data)
1068c2ecf20Sopenharmony_ci		return -ENODEV;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	if (WARN_ON(!rtd->dai_link->params)) {
1098c2ecf20Sopenharmony_ci		dev_warn(dai->dev, "codec2codec link expected\n");
1108c2ecf20Sopenharmony_ci		return -EINVAL;
1118c2ecf20Sopenharmony_ci	}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* Replace link params with the input params */
1148c2ecf20Sopenharmony_ci	rtd->dai_link->params = &in_data->params;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (!in_data->fmt)
1178c2ecf20Sopenharmony_ci		return 0;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
1208c2ecf20Sopenharmony_ci}
1218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(meson_codec_glue_output_startup);
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ciint meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai)
1248c2ecf20Sopenharmony_ci{
1258c2ecf20Sopenharmony_ci	struct meson_codec_glue_input *data;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	data = kzalloc(sizeof(*data), GFP_KERNEL);
1288c2ecf20Sopenharmony_ci	if (!data)
1298c2ecf20Sopenharmony_ci		return -ENOMEM;
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	meson_codec_glue_input_set_data(dai, data);
1328c2ecf20Sopenharmony_ci	return 0;
1338c2ecf20Sopenharmony_ci}
1348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_probe);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ciint meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct meson_codec_glue_input *data =
1398c2ecf20Sopenharmony_ci		meson_codec_glue_input_get_data(dai);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	kfree(data);
1428c2ecf20Sopenharmony_ci	return 0;
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_remove);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ciMODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
1478c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Amlogic Codec Glue Helpers");
1488c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
1498c2ecf20Sopenharmony_ci
150