1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2*4882a593Smuzhiyun //
3*4882a593Smuzhiyun // Copyright (c) 2018 BayLibre, SAS.
4*4882a593Smuzhiyun // Author: Jerome Brunet <jbrunet@baylibre.com>
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun /*
7*4882a593Smuzhiyun * This driver implements the frontend playback DAI of AXG and G12A based SoCs
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <linux/clk.h>
11*4882a593Smuzhiyun #include <linux/regmap.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/of_platform.h>
14*4882a593Smuzhiyun #include <sound/soc.h>
15*4882a593Smuzhiyun #include <sound/soc-dai.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include "axg-fifo.h"
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun #define CTRL0_FRDDR_PP_MODE BIT(30)
20*4882a593Smuzhiyun #define CTRL0_SEL1_EN_SHIFT 3
21*4882a593Smuzhiyun #define CTRL0_SEL2_SHIFT 4
22*4882a593Smuzhiyun #define CTRL0_SEL2_EN_SHIFT 7
23*4882a593Smuzhiyun #define CTRL0_SEL3_SHIFT 8
24*4882a593Smuzhiyun #define CTRL0_SEL3_EN_SHIFT 11
25*4882a593Smuzhiyun #define CTRL1_FRDDR_FORCE_FINISH BIT(12)
26*4882a593Smuzhiyun #define CTRL2_SEL1_SHIFT 0
27*4882a593Smuzhiyun #define CTRL2_SEL1_EN_SHIFT 4
28*4882a593Smuzhiyun #define CTRL2_SEL2_SHIFT 8
29*4882a593Smuzhiyun #define CTRL2_SEL2_EN_SHIFT 12
30*4882a593Smuzhiyun #define CTRL2_SEL3_SHIFT 16
31*4882a593Smuzhiyun #define CTRL2_SEL3_EN_SHIFT 20
32*4882a593Smuzhiyun
g12a_frddr_dai_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)33*4882a593Smuzhiyun static int g12a_frddr_dai_prepare(struct snd_pcm_substream *substream,
34*4882a593Smuzhiyun struct snd_soc_dai *dai)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun /* Reset the read pointer to the FIFO_INIT_ADDR */
39*4882a593Smuzhiyun regmap_update_bits(fifo->map, FIFO_CTRL1,
40*4882a593Smuzhiyun CTRL1_FRDDR_FORCE_FINISH, 0);
41*4882a593Smuzhiyun regmap_update_bits(fifo->map, FIFO_CTRL1,
42*4882a593Smuzhiyun CTRL1_FRDDR_FORCE_FINISH, CTRL1_FRDDR_FORCE_FINISH);
43*4882a593Smuzhiyun regmap_update_bits(fifo->map, FIFO_CTRL1,
44*4882a593Smuzhiyun CTRL1_FRDDR_FORCE_FINISH, 0);
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun return 0;
47*4882a593Smuzhiyun }
48*4882a593Smuzhiyun
axg_frddr_dai_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)49*4882a593Smuzhiyun static int axg_frddr_dai_startup(struct snd_pcm_substream *substream,
50*4882a593Smuzhiyun struct snd_soc_dai *dai)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
53*4882a593Smuzhiyun unsigned int val;
54*4882a593Smuzhiyun int ret;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /* Enable pclk to access registers and clock the fifo ip */
57*4882a593Smuzhiyun ret = clk_prepare_enable(fifo->pclk);
58*4882a593Smuzhiyun if (ret)
59*4882a593Smuzhiyun return ret;
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* Apply single buffer mode to the interface */
62*4882a593Smuzhiyun regmap_update_bits(fifo->map, FIFO_CTRL0, CTRL0_FRDDR_PP_MODE, 0);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun /* Use all fifo depth */
65*4882a593Smuzhiyun val = (fifo->depth / AXG_FIFO_BURST) - 1;
66*4882a593Smuzhiyun regmap_update_bits(fifo->map, FIFO_CTRL1, CTRL1_FRDDR_DEPTH_MASK,
67*4882a593Smuzhiyun CTRL1_FRDDR_DEPTH(val));
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun return 0;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun
axg_frddr_dai_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)72*4882a593Smuzhiyun static void axg_frddr_dai_shutdown(struct snd_pcm_substream *substream,
73*4882a593Smuzhiyun struct snd_soc_dai *dai)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun struct axg_fifo *fifo = snd_soc_dai_get_drvdata(dai);
76*4882a593Smuzhiyun
77*4882a593Smuzhiyun clk_disable_unprepare(fifo->pclk);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun
axg_frddr_pcm_new(struct snd_soc_pcm_runtime * rtd,struct snd_soc_dai * dai)80*4882a593Smuzhiyun static int axg_frddr_pcm_new(struct snd_soc_pcm_runtime *rtd,
81*4882a593Smuzhiyun struct snd_soc_dai *dai)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun return axg_fifo_pcm_new(rtd, SNDRV_PCM_STREAM_PLAYBACK);
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun static const struct snd_soc_dai_ops axg_frddr_ops = {
87*4882a593Smuzhiyun .startup = axg_frddr_dai_startup,
88*4882a593Smuzhiyun .shutdown = axg_frddr_dai_shutdown,
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun static struct snd_soc_dai_driver axg_frddr_dai_drv = {
92*4882a593Smuzhiyun .name = "FRDDR",
93*4882a593Smuzhiyun .playback = {
94*4882a593Smuzhiyun .stream_name = "Playback",
95*4882a593Smuzhiyun .channels_min = 1,
96*4882a593Smuzhiyun .channels_max = AXG_FIFO_CH_MAX,
97*4882a593Smuzhiyun .rates = AXG_FIFO_RATES,
98*4882a593Smuzhiyun .formats = AXG_FIFO_FORMATS,
99*4882a593Smuzhiyun },
100*4882a593Smuzhiyun .ops = &axg_frddr_ops,
101*4882a593Smuzhiyun .pcm_new = axg_frddr_pcm_new,
102*4882a593Smuzhiyun };
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun static const char * const axg_frddr_sel_texts[] = {
105*4882a593Smuzhiyun "OUT 0", "OUT 1", "OUT 2", "OUT 3", "OUT 4", "OUT 5", "OUT 6", "OUT 7",
106*4882a593Smuzhiyun };
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(axg_frddr_sel_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
109*4882a593Smuzhiyun axg_frddr_sel_texts);
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun static const struct snd_kcontrol_new axg_frddr_out_demux =
112*4882a593Smuzhiyun SOC_DAPM_ENUM("Output Sink", axg_frddr_sel_enum);
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun static const struct snd_soc_dapm_widget axg_frddr_dapm_widgets[] = {
115*4882a593Smuzhiyun SND_SOC_DAPM_DEMUX("SINK SEL", SND_SOC_NOPM, 0, 0,
116*4882a593Smuzhiyun &axg_frddr_out_demux),
117*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
118*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
119*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
120*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
121*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
122*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
123*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
124*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
125*4882a593Smuzhiyun };
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun static const struct snd_soc_dapm_route axg_frddr_dapm_routes[] = {
128*4882a593Smuzhiyun { "SINK SEL", NULL, "Playback" },
129*4882a593Smuzhiyun { "OUT 0", "OUT 0", "SINK SEL" },
130*4882a593Smuzhiyun { "OUT 1", "OUT 1", "SINK SEL" },
131*4882a593Smuzhiyun { "OUT 2", "OUT 2", "SINK SEL" },
132*4882a593Smuzhiyun { "OUT 3", "OUT 3", "SINK SEL" },
133*4882a593Smuzhiyun { "OUT 4", "OUT 4", "SINK SEL" },
134*4882a593Smuzhiyun { "OUT 5", "OUT 5", "SINK SEL" },
135*4882a593Smuzhiyun { "OUT 6", "OUT 6", "SINK SEL" },
136*4882a593Smuzhiyun { "OUT 7", "OUT 7", "SINK SEL" },
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun static const struct snd_soc_component_driver axg_frddr_component_drv = {
140*4882a593Smuzhiyun .dapm_widgets = axg_frddr_dapm_widgets,
141*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(axg_frddr_dapm_widgets),
142*4882a593Smuzhiyun .dapm_routes = axg_frddr_dapm_routes,
143*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(axg_frddr_dapm_routes),
144*4882a593Smuzhiyun .open = axg_fifo_pcm_open,
145*4882a593Smuzhiyun .close = axg_fifo_pcm_close,
146*4882a593Smuzhiyun .hw_params = axg_fifo_pcm_hw_params,
147*4882a593Smuzhiyun .hw_free = axg_fifo_pcm_hw_free,
148*4882a593Smuzhiyun .pointer = axg_fifo_pcm_pointer,
149*4882a593Smuzhiyun .trigger = axg_fifo_pcm_trigger,
150*4882a593Smuzhiyun };
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun static const struct axg_fifo_match_data axg_frddr_match_data = {
153*4882a593Smuzhiyun .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
154*4882a593Smuzhiyun .component_drv = &axg_frddr_component_drv,
155*4882a593Smuzhiyun .dai_drv = &axg_frddr_dai_drv
156*4882a593Smuzhiyun };
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun static const struct snd_soc_dai_ops g12a_frddr_ops = {
159*4882a593Smuzhiyun .prepare = g12a_frddr_dai_prepare,
160*4882a593Smuzhiyun .startup = axg_frddr_dai_startup,
161*4882a593Smuzhiyun .shutdown = axg_frddr_dai_shutdown,
162*4882a593Smuzhiyun };
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun static struct snd_soc_dai_driver g12a_frddr_dai_drv = {
165*4882a593Smuzhiyun .name = "FRDDR",
166*4882a593Smuzhiyun .playback = {
167*4882a593Smuzhiyun .stream_name = "Playback",
168*4882a593Smuzhiyun .channels_min = 1,
169*4882a593Smuzhiyun .channels_max = AXG_FIFO_CH_MAX,
170*4882a593Smuzhiyun .rates = AXG_FIFO_RATES,
171*4882a593Smuzhiyun .formats = AXG_FIFO_FORMATS,
172*4882a593Smuzhiyun },
173*4882a593Smuzhiyun .ops = &g12a_frddr_ops,
174*4882a593Smuzhiyun .pcm_new = axg_frddr_pcm_new,
175*4882a593Smuzhiyun };
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel1_enum, FIFO_CTRL0, CTRL0_SEL_SHIFT,
178*4882a593Smuzhiyun axg_frddr_sel_texts);
179*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel2_enum, FIFO_CTRL0, CTRL0_SEL2_SHIFT,
180*4882a593Smuzhiyun axg_frddr_sel_texts);
181*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(g12a_frddr_sel3_enum, FIFO_CTRL0, CTRL0_SEL3_SHIFT,
182*4882a593Smuzhiyun axg_frddr_sel_texts);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun static const struct snd_kcontrol_new g12a_frddr_out1_demux =
185*4882a593Smuzhiyun SOC_DAPM_ENUM("Output Src 1", g12a_frddr_sel1_enum);
186*4882a593Smuzhiyun static const struct snd_kcontrol_new g12a_frddr_out2_demux =
187*4882a593Smuzhiyun SOC_DAPM_ENUM("Output Src 2", g12a_frddr_sel2_enum);
188*4882a593Smuzhiyun static const struct snd_kcontrol_new g12a_frddr_out3_demux =
189*4882a593Smuzhiyun SOC_DAPM_ENUM("Output Src 3", g12a_frddr_sel3_enum);
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun static const struct snd_kcontrol_new g12a_frddr_out1_enable =
192*4882a593Smuzhiyun SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
193*4882a593Smuzhiyun CTRL0_SEL1_EN_SHIFT, 1, 0);
194*4882a593Smuzhiyun static const struct snd_kcontrol_new g12a_frddr_out2_enable =
195*4882a593Smuzhiyun SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
196*4882a593Smuzhiyun CTRL0_SEL2_EN_SHIFT, 1, 0);
197*4882a593Smuzhiyun static const struct snd_kcontrol_new g12a_frddr_out3_enable =
198*4882a593Smuzhiyun SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL0,
199*4882a593Smuzhiyun CTRL0_SEL3_EN_SHIFT, 1, 0);
200*4882a593Smuzhiyun
201*4882a593Smuzhiyun static const struct snd_soc_dapm_widget g12a_frddr_dapm_widgets[] = {
202*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0),
203*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0),
204*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0),
205*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0,
206*4882a593Smuzhiyun &g12a_frddr_out1_enable),
207*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0,
208*4882a593Smuzhiyun &g12a_frddr_out2_enable),
209*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0,
210*4882a593Smuzhiyun &g12a_frddr_out3_enable),
211*4882a593Smuzhiyun SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0,
212*4882a593Smuzhiyun &g12a_frddr_out1_demux),
213*4882a593Smuzhiyun SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0,
214*4882a593Smuzhiyun &g12a_frddr_out2_demux),
215*4882a593Smuzhiyun SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0,
216*4882a593Smuzhiyun &g12a_frddr_out3_demux),
217*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
218*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
219*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
220*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
221*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
222*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
223*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
224*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
225*4882a593Smuzhiyun };
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun static const struct snd_soc_dapm_route g12a_frddr_dapm_routes[] = {
228*4882a593Smuzhiyun { "SRC 1", NULL, "Playback" },
229*4882a593Smuzhiyun { "SRC 2", NULL, "Playback" },
230*4882a593Smuzhiyun { "SRC 3", NULL, "Playback" },
231*4882a593Smuzhiyun { "SRC 1 EN", "Switch", "SRC 1" },
232*4882a593Smuzhiyun { "SRC 2 EN", "Switch", "SRC 2" },
233*4882a593Smuzhiyun { "SRC 3 EN", "Switch", "SRC 3" },
234*4882a593Smuzhiyun { "SINK 1 SEL", NULL, "SRC 1 EN" },
235*4882a593Smuzhiyun { "SINK 2 SEL", NULL, "SRC 2 EN" },
236*4882a593Smuzhiyun { "SINK 3 SEL", NULL, "SRC 3 EN" },
237*4882a593Smuzhiyun { "OUT 0", "OUT 0", "SINK 1 SEL" },
238*4882a593Smuzhiyun { "OUT 1", "OUT 1", "SINK 1 SEL" },
239*4882a593Smuzhiyun { "OUT 2", "OUT 2", "SINK 1 SEL" },
240*4882a593Smuzhiyun { "OUT 3", "OUT 3", "SINK 1 SEL" },
241*4882a593Smuzhiyun { "OUT 4", "OUT 4", "SINK 1 SEL" },
242*4882a593Smuzhiyun { "OUT 5", "OUT 5", "SINK 1 SEL" },
243*4882a593Smuzhiyun { "OUT 6", "OUT 6", "SINK 1 SEL" },
244*4882a593Smuzhiyun { "OUT 7", "OUT 7", "SINK 1 SEL" },
245*4882a593Smuzhiyun { "OUT 0", "OUT 0", "SINK 2 SEL" },
246*4882a593Smuzhiyun { "OUT 1", "OUT 1", "SINK 2 SEL" },
247*4882a593Smuzhiyun { "OUT 2", "OUT 2", "SINK 2 SEL" },
248*4882a593Smuzhiyun { "OUT 3", "OUT 3", "SINK 2 SEL" },
249*4882a593Smuzhiyun { "OUT 4", "OUT 4", "SINK 2 SEL" },
250*4882a593Smuzhiyun { "OUT 5", "OUT 5", "SINK 2 SEL" },
251*4882a593Smuzhiyun { "OUT 6", "OUT 6", "SINK 2 SEL" },
252*4882a593Smuzhiyun { "OUT 7", "OUT 7", "SINK 2 SEL" },
253*4882a593Smuzhiyun { "OUT 0", "OUT 0", "SINK 3 SEL" },
254*4882a593Smuzhiyun { "OUT 1", "OUT 1", "SINK 3 SEL" },
255*4882a593Smuzhiyun { "OUT 2", "OUT 2", "SINK 3 SEL" },
256*4882a593Smuzhiyun { "OUT 3", "OUT 3", "SINK 3 SEL" },
257*4882a593Smuzhiyun { "OUT 4", "OUT 4", "SINK 3 SEL" },
258*4882a593Smuzhiyun { "OUT 5", "OUT 5", "SINK 3 SEL" },
259*4882a593Smuzhiyun { "OUT 6", "OUT 6", "SINK 3 SEL" },
260*4882a593Smuzhiyun { "OUT 7", "OUT 7", "SINK 3 SEL" },
261*4882a593Smuzhiyun };
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun static const struct snd_soc_component_driver g12a_frddr_component_drv = {
264*4882a593Smuzhiyun .dapm_widgets = g12a_frddr_dapm_widgets,
265*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(g12a_frddr_dapm_widgets),
266*4882a593Smuzhiyun .dapm_routes = g12a_frddr_dapm_routes,
267*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes),
268*4882a593Smuzhiyun .open = axg_fifo_pcm_open,
269*4882a593Smuzhiyun .close = axg_fifo_pcm_close,
270*4882a593Smuzhiyun .hw_params = g12a_fifo_pcm_hw_params,
271*4882a593Smuzhiyun .hw_free = axg_fifo_pcm_hw_free,
272*4882a593Smuzhiyun .pointer = axg_fifo_pcm_pointer,
273*4882a593Smuzhiyun .trigger = axg_fifo_pcm_trigger,
274*4882a593Smuzhiyun };
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun static const struct axg_fifo_match_data g12a_frddr_match_data = {
277*4882a593Smuzhiyun .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
278*4882a593Smuzhiyun .component_drv = &g12a_frddr_component_drv,
279*4882a593Smuzhiyun .dai_drv = &g12a_frddr_dai_drv
280*4882a593Smuzhiyun };
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun /* On SM1, the output selection in on CTRL2 */
283*4882a593Smuzhiyun static const struct snd_kcontrol_new sm1_frddr_out1_enable =
284*4882a593Smuzhiyun SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
285*4882a593Smuzhiyun CTRL2_SEL1_EN_SHIFT, 1, 0);
286*4882a593Smuzhiyun static const struct snd_kcontrol_new sm1_frddr_out2_enable =
287*4882a593Smuzhiyun SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
288*4882a593Smuzhiyun CTRL2_SEL2_EN_SHIFT, 1, 0);
289*4882a593Smuzhiyun static const struct snd_kcontrol_new sm1_frddr_out3_enable =
290*4882a593Smuzhiyun SOC_DAPM_SINGLE_AUTODISABLE("Switch", FIFO_CTRL2,
291*4882a593Smuzhiyun CTRL2_SEL3_EN_SHIFT, 1, 0);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel1_enum, FIFO_CTRL2, CTRL2_SEL1_SHIFT,
294*4882a593Smuzhiyun axg_frddr_sel_texts);
295*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel2_enum, FIFO_CTRL2, CTRL2_SEL2_SHIFT,
296*4882a593Smuzhiyun axg_frddr_sel_texts);
297*4882a593Smuzhiyun static SOC_ENUM_SINGLE_DECL(sm1_frddr_sel3_enum, FIFO_CTRL2, CTRL2_SEL3_SHIFT,
298*4882a593Smuzhiyun axg_frddr_sel_texts);
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun static const struct snd_kcontrol_new sm1_frddr_out1_demux =
301*4882a593Smuzhiyun SOC_DAPM_ENUM("Output Src 1", sm1_frddr_sel1_enum);
302*4882a593Smuzhiyun static const struct snd_kcontrol_new sm1_frddr_out2_demux =
303*4882a593Smuzhiyun SOC_DAPM_ENUM("Output Src 2", sm1_frddr_sel2_enum);
304*4882a593Smuzhiyun static const struct snd_kcontrol_new sm1_frddr_out3_demux =
305*4882a593Smuzhiyun SOC_DAPM_ENUM("Output Src 3", sm1_frddr_sel3_enum);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun static const struct snd_soc_dapm_widget sm1_frddr_dapm_widgets[] = {
308*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("SRC 1", NULL, 0, SND_SOC_NOPM, 0, 0),
309*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("SRC 2", NULL, 0, SND_SOC_NOPM, 0, 0),
310*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("SRC 3", NULL, 0, SND_SOC_NOPM, 0, 0),
311*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("SRC 1 EN", SND_SOC_NOPM, 0, 0,
312*4882a593Smuzhiyun &sm1_frddr_out1_enable),
313*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("SRC 2 EN", SND_SOC_NOPM, 0, 0,
314*4882a593Smuzhiyun &sm1_frddr_out2_enable),
315*4882a593Smuzhiyun SND_SOC_DAPM_SWITCH("SRC 3 EN", SND_SOC_NOPM, 0, 0,
316*4882a593Smuzhiyun &sm1_frddr_out3_enable),
317*4882a593Smuzhiyun SND_SOC_DAPM_DEMUX("SINK 1 SEL", SND_SOC_NOPM, 0, 0,
318*4882a593Smuzhiyun &sm1_frddr_out1_demux),
319*4882a593Smuzhiyun SND_SOC_DAPM_DEMUX("SINK 2 SEL", SND_SOC_NOPM, 0, 0,
320*4882a593Smuzhiyun &sm1_frddr_out2_demux),
321*4882a593Smuzhiyun SND_SOC_DAPM_DEMUX("SINK 3 SEL", SND_SOC_NOPM, 0, 0,
322*4882a593Smuzhiyun &sm1_frddr_out3_demux),
323*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 0", NULL, 0, SND_SOC_NOPM, 0, 0),
324*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 1", NULL, 0, SND_SOC_NOPM, 0, 0),
325*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 2", NULL, 0, SND_SOC_NOPM, 0, 0),
326*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 3", NULL, 0, SND_SOC_NOPM, 0, 0),
327*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 4", NULL, 0, SND_SOC_NOPM, 0, 0),
328*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 5", NULL, 0, SND_SOC_NOPM, 0, 0),
329*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 6", NULL, 0, SND_SOC_NOPM, 0, 0),
330*4882a593Smuzhiyun SND_SOC_DAPM_AIF_OUT("OUT 7", NULL, 0, SND_SOC_NOPM, 0, 0),
331*4882a593Smuzhiyun };
332*4882a593Smuzhiyun
333*4882a593Smuzhiyun static const struct snd_soc_component_driver sm1_frddr_component_drv = {
334*4882a593Smuzhiyun .dapm_widgets = sm1_frddr_dapm_widgets,
335*4882a593Smuzhiyun .num_dapm_widgets = ARRAY_SIZE(sm1_frddr_dapm_widgets),
336*4882a593Smuzhiyun .dapm_routes = g12a_frddr_dapm_routes,
337*4882a593Smuzhiyun .num_dapm_routes = ARRAY_SIZE(g12a_frddr_dapm_routes),
338*4882a593Smuzhiyun .open = axg_fifo_pcm_open,
339*4882a593Smuzhiyun .close = axg_fifo_pcm_close,
340*4882a593Smuzhiyun .hw_params = g12a_fifo_pcm_hw_params,
341*4882a593Smuzhiyun .hw_free = axg_fifo_pcm_hw_free,
342*4882a593Smuzhiyun .pointer = axg_fifo_pcm_pointer,
343*4882a593Smuzhiyun .trigger = axg_fifo_pcm_trigger,
344*4882a593Smuzhiyun };
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun static const struct axg_fifo_match_data sm1_frddr_match_data = {
347*4882a593Smuzhiyun .field_threshold = REG_FIELD(FIFO_CTRL1, 16, 23),
348*4882a593Smuzhiyun .component_drv = &sm1_frddr_component_drv,
349*4882a593Smuzhiyun .dai_drv = &g12a_frddr_dai_drv
350*4882a593Smuzhiyun };
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun static const struct of_device_id axg_frddr_of_match[] = {
353*4882a593Smuzhiyun {
354*4882a593Smuzhiyun .compatible = "amlogic,axg-frddr",
355*4882a593Smuzhiyun .data = &axg_frddr_match_data,
356*4882a593Smuzhiyun }, {
357*4882a593Smuzhiyun .compatible = "amlogic,g12a-frddr",
358*4882a593Smuzhiyun .data = &g12a_frddr_match_data,
359*4882a593Smuzhiyun }, {
360*4882a593Smuzhiyun .compatible = "amlogic,sm1-frddr",
361*4882a593Smuzhiyun .data = &sm1_frddr_match_data,
362*4882a593Smuzhiyun }, {}
363*4882a593Smuzhiyun };
364*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, axg_frddr_of_match);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun static struct platform_driver axg_frddr_pdrv = {
367*4882a593Smuzhiyun .probe = axg_fifo_probe,
368*4882a593Smuzhiyun .driver = {
369*4882a593Smuzhiyun .name = "axg-frddr",
370*4882a593Smuzhiyun .of_match_table = axg_frddr_of_match,
371*4882a593Smuzhiyun },
372*4882a593Smuzhiyun };
373*4882a593Smuzhiyun module_platform_driver(axg_frddr_pdrv);
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun MODULE_DESCRIPTION("Amlogic AXG/G12A playback fifo driver");
376*4882a593Smuzhiyun MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
377*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
378