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