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