xref: /OK3568_Linux_fs/kernel/sound/soc/meson/meson-codec-glue.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Copyright (c) 2019 BayLibre, SAS.
4*4882a593Smuzhiyun // Author: Jerome Brunet <jbrunet@baylibre.com>
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/module.h>
7*4882a593Smuzhiyun #include <sound/pcm_params.h>
8*4882a593Smuzhiyun #include <sound/soc.h>
9*4882a593Smuzhiyun #include <sound/soc-dai.h>
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include "meson-codec-glue.h"
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun static struct snd_soc_dapm_widget *
meson_codec_glue_get_input(struct snd_soc_dapm_widget * w)14*4882a593Smuzhiyun meson_codec_glue_get_input(struct snd_soc_dapm_widget *w)
15*4882a593Smuzhiyun {
16*4882a593Smuzhiyun 	struct snd_soc_dapm_path *p = NULL;
17*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *in;
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun 	snd_soc_dapm_widget_for_each_source_path(w, p) {
20*4882a593Smuzhiyun 		if (!p->connect)
21*4882a593Smuzhiyun 			continue;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 		/* Check that we still are in the same component */
24*4882a593Smuzhiyun 		if (snd_soc_dapm_to_component(w->dapm) !=
25*4882a593Smuzhiyun 		    snd_soc_dapm_to_component(p->source->dapm))
26*4882a593Smuzhiyun 			continue;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 		if (p->source->id == snd_soc_dapm_dai_in)
29*4882a593Smuzhiyun 			return p->source;
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 		in = meson_codec_glue_get_input(p->source);
32*4882a593Smuzhiyun 		if (in)
33*4882a593Smuzhiyun 			return in;
34*4882a593Smuzhiyun 	}
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	return NULL;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
meson_codec_glue_input_set_data(struct snd_soc_dai * dai,struct meson_codec_glue_input * data)39*4882a593Smuzhiyun static void meson_codec_glue_input_set_data(struct snd_soc_dai *dai,
40*4882a593Smuzhiyun 					    struct meson_codec_glue_input *data)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	dai->playback_dma_data = data;
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun struct meson_codec_glue_input *
meson_codec_glue_input_get_data(struct snd_soc_dai * dai)46*4882a593Smuzhiyun meson_codec_glue_input_get_data(struct snd_soc_dai *dai)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun 	return dai->playback_dma_data;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(meson_codec_glue_input_get_data);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun static struct meson_codec_glue_input *
meson_codec_glue_output_get_input_data(struct snd_soc_dapm_widget * w)53*4882a593Smuzhiyun meson_codec_glue_output_get_input_data(struct snd_soc_dapm_widget *w)
54*4882a593Smuzhiyun {
55*4882a593Smuzhiyun 	struct snd_soc_dapm_widget *in =
56*4882a593Smuzhiyun 		meson_codec_glue_get_input(w);
57*4882a593Smuzhiyun 	struct snd_soc_dai *dai;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	if (WARN_ON(!in))
60*4882a593Smuzhiyun 		return NULL;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	dai = in->priv;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	return meson_codec_glue_input_get_data(dai);
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun 
meson_codec_glue_input_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)67*4882a593Smuzhiyun int meson_codec_glue_input_hw_params(struct snd_pcm_substream *substream,
68*4882a593Smuzhiyun 				     struct snd_pcm_hw_params *params,
69*4882a593Smuzhiyun 				     struct snd_soc_dai *dai)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	struct meson_codec_glue_input *data =
72*4882a593Smuzhiyun 		meson_codec_glue_input_get_data(dai);
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	data->params.rates = snd_pcm_rate_to_rate_bit(params_rate(params));
75*4882a593Smuzhiyun 	data->params.rate_min = params_rate(params);
76*4882a593Smuzhiyun 	data->params.rate_max = params_rate(params);
77*4882a593Smuzhiyun 	data->params.formats = 1ULL << (__force int) params_format(params);
78*4882a593Smuzhiyun 	data->params.channels_min = params_channels(params);
79*4882a593Smuzhiyun 	data->params.channels_max = params_channels(params);
80*4882a593Smuzhiyun 	data->params.sig_bits = dai->driver->playback.sig_bits;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	return 0;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(meson_codec_glue_input_hw_params);
85*4882a593Smuzhiyun 
meson_codec_glue_input_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)86*4882a593Smuzhiyun int meson_codec_glue_input_set_fmt(struct snd_soc_dai *dai,
87*4882a593Smuzhiyun 				   unsigned int fmt)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	struct meson_codec_glue_input *data =
90*4882a593Smuzhiyun 		meson_codec_glue_input_get_data(dai);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	/* Save the source stream format for the downstream link */
93*4882a593Smuzhiyun 	data->fmt = fmt;
94*4882a593Smuzhiyun 	return 0;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(meson_codec_glue_input_set_fmt);
97*4882a593Smuzhiyun 
meson_codec_glue_output_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)98*4882a593Smuzhiyun int meson_codec_glue_output_startup(struct snd_pcm_substream *substream,
99*4882a593Smuzhiyun 				    struct snd_soc_dai *dai)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
102*4882a593Smuzhiyun 	struct meson_codec_glue_input *in_data =
103*4882a593Smuzhiyun 		meson_codec_glue_output_get_input_data(dai->capture_widget);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	if (!in_data)
106*4882a593Smuzhiyun 		return -ENODEV;
107*4882a593Smuzhiyun 
108*4882a593Smuzhiyun 	if (WARN_ON(!rtd->dai_link->params)) {
109*4882a593Smuzhiyun 		dev_warn(dai->dev, "codec2codec link expected\n");
110*4882a593Smuzhiyun 		return -EINVAL;
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	/* Replace link params with the input params */
114*4882a593Smuzhiyun 	rtd->dai_link->params = &in_data->params;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	if (!in_data->fmt)
117*4882a593Smuzhiyun 		return 0;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	return snd_soc_runtime_set_dai_fmt(rtd, in_data->fmt);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(meson_codec_glue_output_startup);
122*4882a593Smuzhiyun 
meson_codec_glue_input_dai_probe(struct snd_soc_dai * dai)123*4882a593Smuzhiyun int meson_codec_glue_input_dai_probe(struct snd_soc_dai *dai)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	struct meson_codec_glue_input *data;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	data = kzalloc(sizeof(*data), GFP_KERNEL);
128*4882a593Smuzhiyun 	if (!data)
129*4882a593Smuzhiyun 		return -ENOMEM;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	meson_codec_glue_input_set_data(dai, data);
132*4882a593Smuzhiyun 	return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_probe);
135*4882a593Smuzhiyun 
meson_codec_glue_input_dai_remove(struct snd_soc_dai * dai)136*4882a593Smuzhiyun int meson_codec_glue_input_dai_remove(struct snd_soc_dai *dai)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct meson_codec_glue_input *data =
139*4882a593Smuzhiyun 		meson_codec_glue_input_get_data(dai);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	kfree(data);
142*4882a593Smuzhiyun 	return 0;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(meson_codec_glue_input_dai_remove);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
147*4882a593Smuzhiyun MODULE_DESCRIPTION("Amlogic Codec Glue Helpers");
148*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
149*4882a593Smuzhiyun 
150