Commit | Line | Data |
---|---|---|
1e0edd4d KM |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // Renesas R-Car SRU/SCU/SSIU/SSI support | |
4 | // | |
5 | // Copyright (C) 2013 Renesas Solutions Corp. | |
6 | // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | |
7 | // | |
8 | // Based on fsi.c | |
9 | // Kuninori Morimoto <morimoto.kuninori@renesas.com> | |
1536a968 KM |
10 | |
11 | /* | |
12 | * Renesas R-Car sound device structure | |
13 | * | |
14 | * Gen1 | |
15 | * | |
16 | * SRU : Sound Routing Unit | |
17 | * - SRC : Sampling Rate Converter | |
18 | * - CMD | |
19 | * - CTU : Channel Count Conversion Unit | |
20 | * - MIX : Mixer | |
21 | * - DVC : Digital Volume and Mute Function | |
22 | * - SSI : Serial Sound Interface | |
23 | * | |
24 | * Gen2 | |
25 | * | |
26 | * SCU : Sampling Rate Converter Unit | |
27 | * - SRC : Sampling Rate Converter | |
28 | * - CMD | |
29 | * - CTU : Channel Count Conversion Unit | |
30 | * - MIX : Mixer | |
31 | * - DVC : Digital Volume and Mute Function | |
32 | * SSIU : Serial Sound Interface Unit | |
33 | * - SSI : Serial Sound Interface | |
34 | */ | |
35 | ||
36 | /* | |
37 | * driver data Image | |
38 | * | |
39 | * rsnd_priv | |
40 | * | | |
41 | * | ** this depends on Gen1/Gen2 | |
42 | * | | |
43 | * +- gen | |
44 | * | | |
45 | * | ** these depend on data path | |
46 | * | ** gen and platform data control it | |
47 | * | | |
48 | * +- rdai[0] | |
49 | * | | sru ssiu ssi | |
50 | * | +- playback -> [mod] -> [mod] -> [mod] -> ... | |
51 | * | | | |
52 | * | | sru ssiu ssi | |
53 | * | +- capture -> [mod] -> [mod] -> [mod] -> ... | |
54 | * | | |
55 | * +- rdai[1] | |
56 | * | | sru ssiu ssi | |
57 | * | +- playback -> [mod] -> [mod] -> [mod] -> ... | |
58 | * | | | |
59 | * | | sru ssiu ssi | |
60 | * | +- capture -> [mod] -> [mod] -> [mod] -> ... | |
61 | * ... | |
62 | * | | |
63 | * | ** these control ssi | |
64 | * | | |
65 | * +- ssi | |
66 | * | | | |
67 | * | +- ssi[0] | |
68 | * | +- ssi[1] | |
69 | * | +- ssi[2] | |
70 | * | ... | |
71 | * | | |
ba9c949f | 72 | * | ** these control src |
1536a968 | 73 | * | |
ba9c949f | 74 | * +- src |
1536a968 | 75 | * | |
ba9c949f KM |
76 | * +- src[0] |
77 | * +- src[1] | |
78 | * +- src[2] | |
1536a968 KM |
79 | * ... |
80 | * | |
81 | * | |
82 | * for_each_rsnd_dai(xx, priv, xx) | |
83 | * rdai[0] => rdai[1] => rdai[2] => ... | |
84 | * | |
85 | * for_each_rsnd_mod(xx, rdai, xx) | |
86 | * [mod] => [mod] => [mod] => ... | |
87 | * | |
88 | * rsnd_dai_call(xxx, fn ) | |
89 | * [mod]->fn() -> [mod]->fn() -> [mod]->fn()... | |
90 | * | |
91 | */ | |
1f6e920f KM |
92 | |
93 | /* | |
94 | * you can enable below define if you don't need | |
95 | * DAI status debug message when debugging | |
96 | * see rsnd_dbg_dai_call() | |
97 | * | |
98 | * #define RSND_DEBUG_NO_DAI_CALL 1 | |
99 | */ | |
100 | ||
1536a968 KM |
101 | #include <linux/pm_runtime.h> |
102 | #include "rsnd.h" | |
103 | ||
dc272156 | 104 | #define RSND_RATES SNDRV_PCM_RATE_8000_192000 |
ba5d553b DT |
105 | #define RSND_FMTS (SNDRV_PCM_FMTBIT_S8 |\ |
106 | SNDRV_PCM_FMTBIT_S16_LE |\ | |
107 | SNDRV_PCM_FMTBIT_S24_LE) | |
1536a968 | 108 | |
33187fb4 | 109 | static const struct of_device_id rsnd_of_match[] = { |
e797f58e KM |
110 | { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, |
111 | { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, | |
d188e140 | 112 | { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN3 }, |
ba164a49 JW |
113 | /* Special Handling */ |
114 | { .compatible = "renesas,rcar_sound-r8a77990", .data = (void *)(RSND_GEN3 | RSND_SOC_E) }, | |
90e8e50f KM |
115 | {}, |
116 | }; | |
117 | MODULE_DEVICE_TABLE(of, rsnd_of_match); | |
118 | ||
81ad174d KM |
119 | /* |
120 | * rsnd_mod functions | |
121 | */ | |
f1df1229 KM |
122 | void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) |
123 | { | |
124 | if (mod->type != type) { | |
125 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | |
126 | struct device *dev = rsnd_priv_to_dev(priv); | |
127 | ||
c0ea089d KM |
128 | dev_warn(dev, "%s is not your expected module\n", |
129 | rsnd_mod_name(mod)); | |
f1df1229 KM |
130 | } |
131 | } | |
132 | ||
9b99e9a7 KM |
133 | struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, |
134 | struct rsnd_mod *mod) | |
d9288d0b | 135 | { |
72adc61f KM |
136 | if (!mod || !mod->ops || !mod->ops->dma_req) |
137 | return NULL; | |
d9288d0b | 138 | |
9b99e9a7 | 139 | return mod->ops->dma_req(io, mod); |
d9288d0b KM |
140 | } |
141 | ||
0246c661 | 142 | #define MOD_NAME_NUM 5 |
c0ea089d KM |
143 | #define MOD_NAME_SIZE 16 |
144 | char *rsnd_mod_name(struct rsnd_mod *mod) | |
145 | { | |
0246c661 KM |
146 | static char names[MOD_NAME_NUM][MOD_NAME_SIZE]; |
147 | static int num; | |
148 | char *name = names[num]; | |
149 | ||
150 | num++; | |
151 | if (num >= MOD_NAME_NUM) | |
152 | num = 0; | |
c0ea089d KM |
153 | |
154 | /* | |
155 | * Let's use same char to avoid pointlessness memory | |
156 | * Thus, rsnd_mod_name() should be used immediately | |
157 | * Don't keep pointer | |
158 | */ | |
159 | if ((mod)->ops->id_sub) { | |
160 | snprintf(name, MOD_NAME_SIZE, "%s[%d%d]", | |
161 | mod->ops->name, | |
162 | rsnd_mod_id(mod), | |
163 | rsnd_mod_id_sub(mod)); | |
164 | } else { | |
165 | snprintf(name, MOD_NAME_SIZE, "%s[%d]", | |
166 | mod->ops->name, | |
167 | rsnd_mod_id(mod)); | |
168 | } | |
169 | ||
170 | return name; | |
171 | } | |
172 | ||
7e7fe06d KM |
173 | u32 *rsnd_mod_get_status(struct rsnd_mod *mod, |
174 | struct rsnd_dai_stream *io, | |
5ba17b42 KM |
175 | enum rsnd_mod_type type) |
176 | { | |
177 | return &mod->status; | |
178 | } | |
179 | ||
c16015f3 KM |
180 | int rsnd_mod_id_raw(struct rsnd_mod *mod) |
181 | { | |
182 | return mod->id; | |
183 | } | |
184 | ||
185 | int rsnd_mod_id(struct rsnd_mod *mod) | |
186 | { | |
187 | if ((mod)->ops->id) | |
188 | return (mod)->ops->id(mod); | |
189 | ||
190 | return rsnd_mod_id_raw(mod); | |
191 | } | |
192 | ||
193 | int rsnd_mod_id_sub(struct rsnd_mod *mod) | |
194 | { | |
195 | if ((mod)->ops->id_sub) | |
196 | return (mod)->ops->id_sub(mod); | |
197 | ||
198 | return 0; | |
199 | } | |
200 | ||
2099bc8e KM |
201 | int rsnd_mod_init(struct rsnd_priv *priv, |
202 | struct rsnd_mod *mod, | |
5ba17b42 KM |
203 | struct rsnd_mod_ops *ops, |
204 | struct clk *clk, | |
5ba17b42 KM |
205 | enum rsnd_mod_type type, |
206 | int id) | |
cdaa3cdf | 207 | { |
2f78dd7f KM |
208 | int ret = clk_prepare(clk); |
209 | ||
210 | if (ret) | |
211 | return ret; | |
212 | ||
cdaa3cdf KM |
213 | mod->id = id; |
214 | mod->ops = ops; | |
a126021d | 215 | mod->type = type; |
85642952 | 216 | mod->clk = clk; |
2099bc8e | 217 | mod->priv = priv; |
2f78dd7f KM |
218 | |
219 | return ret; | |
220 | } | |
221 | ||
222 | void rsnd_mod_quit(struct rsnd_mod *mod) | |
223 | { | |
ed3ac14c | 224 | clk_unprepare(mod->clk); |
ea96380b | 225 | mod->clk = NULL; |
cdaa3cdf KM |
226 | } |
227 | ||
f501b7a4 KM |
228 | void rsnd_mod_interrupt(struct rsnd_mod *mod, |
229 | void (*callback)(struct rsnd_mod *mod, | |
230 | struct rsnd_dai_stream *io)) | |
231 | { | |
232 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | |
233 | struct rsnd_dai_stream *io; | |
234 | struct rsnd_dai *rdai; | |
2daf71ad | 235 | int i; |
f501b7a4 | 236 | |
2daf71ad KM |
237 | for_each_rsnd_dai(rdai, priv, i) { |
238 | io = &rdai->playback; | |
239 | if (mod == io->mod[mod->type]) | |
240 | callback(mod, io); | |
f501b7a4 | 241 | |
2daf71ad KM |
242 | io = &rdai->capture; |
243 | if (mod == io->mod[mod->type]) | |
244 | callback(mod, io); | |
f501b7a4 KM |
245 | } |
246 | } | |
247 | ||
d5bbe7de | 248 | int rsnd_io_is_working(struct rsnd_dai_stream *io) |
02299d98 | 249 | { |
02299d98 | 250 | /* see rsnd_dai_stream_init/quit() */ |
8fce974b KM |
251 | if (io->substream) |
252 | return snd_pcm_running(io->substream); | |
253 | ||
254 | return 0; | |
02299d98 KM |
255 | } |
256 | ||
b2fb31bb KM |
257 | int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io, |
258 | struct snd_pcm_hw_params *params) | |
8ec85e7f | 259 | { |
5858a7d1 | 260 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
b4c83b17 | 261 | |
b2fb31bb KM |
262 | /* |
263 | * params will be added when refine | |
264 | * see | |
265 | * __rsnd_soc_hw_rule_rate() | |
266 | * __rsnd_soc_hw_rule_channels() | |
267 | */ | |
268 | if (params) | |
269 | return params_channels(params); | |
270 | else | |
271 | return runtime->channels; | |
eed76bb8 KM |
272 | } |
273 | ||
b2fb31bb KM |
274 | int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io, |
275 | struct snd_pcm_hw_params *params) | |
eed76bb8 | 276 | { |
b2fb31bb | 277 | int chan = rsnd_runtime_channel_original_with_params(io, params); |
eed76bb8 KM |
278 | struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io); |
279 | ||
280 | if (ctu_mod) { | |
c2aaaa57 | 281 | u32 converted_chan = rsnd_io_converted_chan(io); |
eed76bb8 | 282 | |
f69f4522 KM |
283 | /* |
284 | * !! Note !! | |
285 | * | |
286 | * converted_chan will be used for CTU, | |
287 | * or TDM Split mode. | |
288 | * User shouldn't use CTU with TDM Split mode. | |
289 | */ | |
290 | if (rsnd_runtime_is_tdm_split(io)) { | |
291 | struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); | |
292 | ||
293 | dev_err(dev, "CTU and TDM Split should be used\n"); | |
294 | } | |
295 | ||
eed76bb8 KM |
296 | if (converted_chan) |
297 | return converted_chan; | |
298 | } | |
299 | ||
300 | return chan; | |
301 | } | |
302 | ||
66287def KM |
303 | int rsnd_channel_normalization(int chan) |
304 | { | |
305 | if ((chan > 8) || (chan < 0)) | |
306 | return 0; | |
307 | ||
308 | /* TDM Extend Mode needs 8ch */ | |
309 | if (chan == 6) | |
310 | chan = 8; | |
311 | ||
312 | return chan; | |
313 | } | |
314 | ||
b2fb31bb KM |
315 | int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io, |
316 | struct snd_pcm_hw_params *params) | |
eed76bb8 | 317 | { |
1ff9593d | 318 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
eed76bb8 | 319 | int chan = rsnd_io_is_play(io) ? |
b2fb31bb KM |
320 | rsnd_runtime_channel_after_ctu_with_params(io, params) : |
321 | rsnd_runtime_channel_original_with_params(io, params); | |
eed76bb8 KM |
322 | |
323 | /* Use Multi SSI */ | |
a6072802 | 324 | if (rsnd_runtime_is_multi_ssi(io)) |
1ff9593d | 325 | chan /= rsnd_rdai_ssi_lane_get(rdai); |
8ec85e7f | 326 | |
66287def | 327 | return rsnd_channel_normalization(chan); |
8ec85e7f KM |
328 | } |
329 | ||
a6072802 | 330 | int rsnd_runtime_is_multi_ssi(struct rsnd_dai_stream *io) |
eed76bb8 | 331 | { |
1ff9593d KM |
332 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
333 | int lane = rsnd_rdai_ssi_lane_get(rdai); | |
eed76bb8 KM |
334 | int chan = rsnd_io_is_play(io) ? |
335 | rsnd_runtime_channel_after_ctu(io) : | |
336 | rsnd_runtime_channel_original(io); | |
337 | ||
1ff9593d | 338 | return (chan > 2) && (lane > 1); |
eed76bb8 KM |
339 | } |
340 | ||
a6072802 | 341 | int rsnd_runtime_is_tdm(struct rsnd_dai_stream *io) |
eed76bb8 KM |
342 | { |
343 | return rsnd_runtime_channel_for_ssi(io) >= 6; | |
344 | } | |
345 | ||
f69f4522 KM |
346 | int rsnd_runtime_is_tdm_split(struct rsnd_dai_stream *io) |
347 | { | |
348 | return !!rsnd_flags_has(io, RSND_STREAM_TDM_SPLIT); | |
349 | } | |
350 | ||
d7bdbc5d | 351 | /* |
3023b384 | 352 | * ADINR function |
d7bdbc5d | 353 | */ |
3023b384 | 354 | u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) |
d7bdbc5d KM |
355 | { |
356 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | |
d7bdbc5d KM |
357 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
358 | struct device *dev = rsnd_priv_to_dev(priv); | |
d7bdbc5d | 359 | |
41acc8ec | 360 | switch (snd_pcm_format_width(runtime->format)) { |
ba5d553b DT |
361 | case 8: |
362 | return 16 << 16; | |
d7bdbc5d | 363 | case 16: |
5e7b9edd | 364 | return 8 << 16; |
41acc8ec | 365 | case 24: |
5e7b9edd | 366 | return 0 << 16; |
d7bdbc5d KM |
367 | } |
368 | ||
5e7b9edd KM |
369 | dev_warn(dev, "not supported sample bits\n"); |
370 | ||
371 | return 0; | |
d7bdbc5d KM |
372 | } |
373 | ||
4689032b KM |
374 | /* |
375 | * DALIGN function | |
376 | */ | |
377 | u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |
378 | { | |
3ce2959d | 379 | struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); |
a504b1ee | 380 | struct rsnd_mod *target; |
4689032b | 381 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
4689032b | 382 | |
8cce431a | 383 | /* |
a914e446 KM |
384 | * *Hardware* L/R and *Software* L/R are inverted for 16bit data. |
385 | * 31..16 15...0 | |
386 | * HW: [L ch] [R ch] | |
387 | * SW: [R ch] [L ch] | |
8cce431a KM |
388 | * We need to care about inversion timing to control |
389 | * Playback/Capture correctly. | |
390 | * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R | |
391 | * | |
392 | * sL/R : software L/R | |
393 | * hL/R : hardware L/R | |
394 | * (*) : conversion timing | |
395 | * | |
396 | * Playback | |
397 | * sL/R (*) hL/R hL/R hL/R hL/R hL/R | |
398 | * [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec | |
399 | * | |
400 | * Capture | |
401 | * hL/R hL/R hL/R hL/R hL/R (*) sL/R | |
402 | * codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM] | |
403 | */ | |
a504b1ee KM |
404 | if (rsnd_io_is_play(io)) { |
405 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | |
406 | ||
3ce2959d | 407 | target = src ? src : ssiu; |
a504b1ee KM |
408 | } else { |
409 | struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); | |
410 | ||
3ce2959d | 411 | target = cmd ? cmd : ssiu; |
a504b1ee KM |
412 | } |
413 | ||
ba5d553b | 414 | /* Non target mod or non 16bit needs normal DALIGN */ |
41acc8ec | 415 | if ((snd_pcm_format_width(runtime->format) != 16) || |
a914e446 | 416 | (mod != target)) |
4689032b | 417 | return 0x76543210; |
a914e446 KM |
418 | /* Target mod needs inverted DALIGN when 16bit */ |
419 | else | |
420 | return 0x67452301; | |
4689032b KM |
421 | } |
422 | ||
90431eb4 KM |
423 | u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod) |
424 | { | |
425 | enum rsnd_mod_type playback_mods[] = { | |
426 | RSND_MOD_SRC, | |
427 | RSND_MOD_CMD, | |
428 | RSND_MOD_SSIU, | |
429 | }; | |
430 | enum rsnd_mod_type capture_mods[] = { | |
431 | RSND_MOD_CMD, | |
432 | RSND_MOD_SRC, | |
433 | RSND_MOD_SSIU, | |
434 | }; | |
435 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | |
436 | struct rsnd_mod *tmod = NULL; | |
437 | enum rsnd_mod_type *mods = | |
438 | rsnd_io_is_play(io) ? | |
439 | playback_mods : capture_mods; | |
440 | int i; | |
441 | ||
442 | /* | |
443 | * This is needed for 24bit data | |
444 | * We need to shift 8bit | |
445 | * | |
446 | * Linux 24bit data is located as 0x00****** | |
447 | * HW 24bit data is located as 0x******00 | |
448 | * | |
449 | */ | |
ba5d553b | 450 | if (snd_pcm_format_width(runtime->format) != 24) |
90431eb4 | 451 | return 0; |
90431eb4 KM |
452 | |
453 | for (i = 0; i < ARRAY_SIZE(playback_mods); i++) { | |
454 | tmod = rsnd_io_to_mod(io, mods[i]); | |
455 | if (tmod) | |
456 | break; | |
457 | } | |
458 | ||
459 | if (tmod != mod) | |
460 | return 0; | |
461 | ||
462 | if (rsnd_io_is_play(io)) | |
463 | return (0 << 20) | /* shift to Left */ | |
464 | (8 << 16); /* 8bit */ | |
465 | else | |
466 | return (1 << 20) | /* shift to Right */ | |
467 | (8 << 16); /* 8bit */ | |
468 | } | |
469 | ||
1536a968 KM |
470 | /* |
471 | * rsnd_dai functions | |
472 | */ | |
b3ca3fbe KM |
473 | struct rsnd_mod *rsnd_mod_next(int *iterator, |
474 | struct rsnd_dai_stream *io, | |
475 | enum rsnd_mod_type *array, | |
476 | int array_size) | |
477 | { | |
478 | struct rsnd_mod *mod; | |
479 | enum rsnd_mod_type type; | |
480 | int max = array ? array_size : RSND_MOD_MAX; | |
481 | ||
482 | for (; *iterator < max; (*iterator)++) { | |
483 | type = (array) ? array[*iterator] : *iterator; | |
138f8786 | 484 | mod = rsnd_io_to_mod(io, type); |
b12f1e3a KM |
485 | if (mod) |
486 | return mod; | |
b3ca3fbe KM |
487 | } |
488 | ||
489 | return NULL; | |
490 | } | |
491 | ||
38587f4c KM |
492 | static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { |
493 | { | |
494 | /* CAPTURE */ | |
495 | RSND_MOD_AUDMAPP, | |
496 | RSND_MOD_AUDMA, | |
497 | RSND_MOD_DVC, | |
498 | RSND_MOD_MIX, | |
499 | RSND_MOD_CTU, | |
500 | RSND_MOD_CMD, | |
501 | RSND_MOD_SRC, | |
502 | RSND_MOD_SSIU, | |
503 | RSND_MOD_SSIM3, | |
504 | RSND_MOD_SSIM2, | |
505 | RSND_MOD_SSIM1, | |
506 | RSND_MOD_SSIP, | |
507 | RSND_MOD_SSI, | |
508 | }, { | |
509 | /* PLAYBACK */ | |
510 | RSND_MOD_AUDMAPP, | |
511 | RSND_MOD_AUDMA, | |
512 | RSND_MOD_SSIM3, | |
513 | RSND_MOD_SSIM2, | |
514 | RSND_MOD_SSIM1, | |
515 | RSND_MOD_SSIP, | |
516 | RSND_MOD_SSI, | |
517 | RSND_MOD_SSIU, | |
518 | RSND_MOD_DVC, | |
519 | RSND_MOD_MIX, | |
520 | RSND_MOD_CTU, | |
521 | RSND_MOD_CMD, | |
522 | RSND_MOD_SRC, | |
523 | }, | |
524 | }; | |
525 | ||
5f222a29 KM |
526 | static int rsnd_status_update(u32 *status, |
527 | int shift, int add, int timing) | |
528 | { | |
529 | u32 mask = 0xF << shift; | |
530 | u8 val = (*status >> shift) & 0xF; | |
531 | u8 next_val = (val + add) & 0xF; | |
532 | int func_call = (val == timing); | |
533 | ||
534 | if (next_val == 0xF) /* underflow case */ | |
535 | func_call = 0; | |
536 | else | |
537 | *status = (*status & ~mask) + (next_val << shift); | |
538 | ||
539 | return func_call; | |
540 | } | |
541 | ||
542 | #define rsnd_dai_call(fn, io, param...) \ | |
543 | ({ \ | |
f30b4ca4 | 544 | struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); \ |
5f222a29 KM |
545 | struct rsnd_mod *mod; \ |
546 | int is_play = rsnd_io_is_play(io); \ | |
547 | int ret = 0, i; \ | |
548 | enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ | |
549 | for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ | |
550 | int tmp = 0; \ | |
7e7fe06d | 551 | u32 *status = mod->ops->get_status(mod, io, types[i]); \ |
5f222a29 KM |
552 | int func_call = rsnd_status_update(status, \ |
553 | __rsnd_mod_shift_##fn, \ | |
554 | __rsnd_mod_add_##fn, \ | |
555 | __rsnd_mod_call_##fn); \ | |
c0ea089d KM |
556 | rsnd_dbg_dai_call(dev, "%s\t0x%08x %s\n", \ |
557 | rsnd_mod_name(mod), *status, \ | |
5f222a29 KM |
558 | (func_call && (mod)->ops->fn) ? #fn : ""); \ |
559 | if (func_call && (mod)->ops->fn) \ | |
560 | tmp = (mod)->ops->fn(mod, io, param); \ | |
6c92d5a2 | 561 | if (tmp && (tmp != -EPROBE_DEFER)) \ |
c0ea089d KM |
562 | dev_err(dev, "%s : %s error %d\n", \ |
563 | rsnd_mod_name(mod), #fn, tmp); \ | |
5f222a29 KM |
564 | ret |= tmp; \ |
565 | } \ | |
566 | ret; \ | |
cdaa3cdf KM |
567 | }) |
568 | ||
27924f32 KM |
569 | int rsnd_dai_connect(struct rsnd_mod *mod, |
570 | struct rsnd_dai_stream *io, | |
571 | enum rsnd_mod_type type) | |
cdaa3cdf | 572 | { |
48725e9c KM |
573 | struct rsnd_priv *priv; |
574 | struct device *dev; | |
84e95355 | 575 | |
6020779b | 576 | if (!mod) |
cdaa3cdf | 577 | return -EIO; |
cdaa3cdf | 578 | |
bfa3119c KM |
579 | if (io->mod[type] == mod) |
580 | return 0; | |
581 | ||
52dc6852 KM |
582 | if (io->mod[type]) |
583 | return -EINVAL; | |
584 | ||
48725e9c KM |
585 | priv = rsnd_mod_to_priv(mod); |
586 | dev = rsnd_priv_to_dev(priv); | |
587 | ||
27924f32 | 588 | io->mod[type] = mod; |
cdaa3cdf | 589 | |
c0ea089d KM |
590 | dev_dbg(dev, "%s is connected to io (%s)\n", |
591 | rsnd_mod_name(mod), | |
84e95355 KM |
592 | rsnd_io_is_play(io) ? "Playback" : "Capture"); |
593 | ||
cdaa3cdf KM |
594 | return 0; |
595 | } | |
596 | ||
d3a76823 | 597 | static void rsnd_dai_disconnect(struct rsnd_mod *mod, |
27924f32 KM |
598 | struct rsnd_dai_stream *io, |
599 | enum rsnd_mod_type type) | |
d3a76823 | 600 | { |
27924f32 | 601 | io->mod[type] = NULL; |
d3a76823 KM |
602 | } |
603 | ||
1ff9593d KM |
604 | int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, |
605 | int max_channels) | |
606 | { | |
607 | if (max_channels > 0) | |
608 | rdai->max_channels = max_channels; | |
609 | ||
610 | return rdai->max_channels; | |
611 | } | |
612 | ||
613 | int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, | |
614 | int ssi_lane) | |
615 | { | |
616 | if (ssi_lane > 0) | |
617 | rdai->ssi_lane = ssi_lane; | |
618 | ||
619 | return rdai->ssi_lane; | |
620 | } | |
621 | ||
fb2815f4 DT |
622 | int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width) |
623 | { | |
624 | if (width > 0) | |
625 | rdai->chan_width = width; | |
626 | ||
627 | return rdai->chan_width; | |
628 | } | |
629 | ||
710d0889 | 630 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) |
1536a968 | 631 | { |
ecba9e72 | 632 | if ((id < 0) || (id >= rsnd_rdai_nr(priv))) |
2192f81c KM |
633 | return NULL; |
634 | ||
1536a968 KM |
635 | return priv->rdai + id; |
636 | } | |
637 | ||
a0d847c3 KM |
638 | static struct snd_soc_dai_driver |
639 | *rsnd_daidrv_get(struct rsnd_priv *priv, int id) | |
640 | { | |
641 | if ((id < 0) || (id >= rsnd_rdai_nr(priv))) | |
642 | return NULL; | |
643 | ||
644 | return priv->daidrv + id; | |
645 | } | |
646 | ||
eb2535f5 | 647 | #define rsnd_dai_to_priv(dai) snd_soc_dai_get_drvdata(dai) |
1536a968 KM |
648 | static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai) |
649 | { | |
eb2535f5 | 650 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); |
1536a968 | 651 | |
710d0889 | 652 | return rsnd_rdai_get(priv, dai->id); |
1536a968 KM |
653 | } |
654 | ||
1536a968 KM |
655 | /* |
656 | * rsnd_soc_dai functions | |
657 | */ | |
75defee0 KM |
658 | void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io) |
659 | { | |
660 | struct snd_pcm_substream *substream = io->substream; | |
661 | ||
662 | /* | |
663 | * this function should be called... | |
664 | * | |
665 | * - if rsnd_dai_pointer_update() returns true | |
666 | * - without spin lock | |
667 | */ | |
668 | ||
669 | snd_pcm_period_elapsed(substream); | |
1536a968 KM |
670 | } |
671 | ||
5626ad08 | 672 | static void rsnd_dai_stream_init(struct rsnd_dai_stream *io, |
1536a968 KM |
673 | struct snd_pcm_substream *substream) |
674 | { | |
1536a968 | 675 | io->substream = substream; |
5626ad08 | 676 | } |
1536a968 | 677 | |
5626ad08 KM |
678 | static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io) |
679 | { | |
680 | io->substream = NULL; | |
1536a968 KM |
681 | } |
682 | ||
683 | static | |
684 | struct snd_soc_dai *rsnd_substream_to_dai(struct snd_pcm_substream *substream) | |
685 | { | |
686 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | |
687 | ||
688 | return rtd->cpu_dai; | |
689 | } | |
690 | ||
691 | static | |
692 | struct rsnd_dai_stream *rsnd_rdai_to_io(struct rsnd_dai *rdai, | |
693 | struct snd_pcm_substream *substream) | |
694 | { | |
695 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | |
696 | return &rdai->playback; | |
697 | else | |
698 | return &rdai->capture; | |
699 | } | |
700 | ||
701 | static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |
702 | struct snd_soc_dai *dai) | |
703 | { | |
eb2535f5 | 704 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); |
1536a968 KM |
705 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
706 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | |
1536a968 KM |
707 | int ret; |
708 | unsigned long flags; | |
709 | ||
02299d98 | 710 | spin_lock_irqsave(&priv->lock, flags); |
1536a968 KM |
711 | |
712 | switch (cmd) { | |
713 | case SNDRV_PCM_TRIGGER_START: | |
4b9c75ea | 714 | case SNDRV_PCM_TRIGGER_RESUME: |
690602fc | 715 | ret = rsnd_dai_call(init, io, priv); |
cdaa3cdf KM |
716 | if (ret < 0) |
717 | goto dai_trigger_end; | |
718 | ||
690602fc | 719 | ret = rsnd_dai_call(start, io, priv); |
cdaa3cdf KM |
720 | if (ret < 0) |
721 | goto dai_trigger_end; | |
b5b442ab KM |
722 | |
723 | ret = rsnd_dai_call(irq, io, priv, 1); | |
724 | if (ret < 0) | |
725 | goto dai_trigger_end; | |
726 | ||
1536a968 KM |
727 | break; |
728 | case SNDRV_PCM_TRIGGER_STOP: | |
4b9c75ea | 729 | case SNDRV_PCM_TRIGGER_SUSPEND: |
b5b442ab KM |
730 | ret = rsnd_dai_call(irq, io, priv, 0); |
731 | ||
732 | ret |= rsnd_dai_call(stop, io, priv); | |
cdaa3cdf | 733 | |
89e3e2c3 | 734 | ret |= rsnd_dai_call(quit, io, priv); |
cdaa3cdf | 735 | |
1536a968 KM |
736 | break; |
737 | default: | |
738 | ret = -EINVAL; | |
739 | } | |
740 | ||
741 | dai_trigger_end: | |
02299d98 | 742 | spin_unlock_irqrestore(&priv->lock, flags); |
1536a968 KM |
743 | |
744 | return ret; | |
745 | } | |
746 | ||
747 | static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |
748 | { | |
749 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | |
750 | ||
751 | /* set master/slave audio interface */ | |
752 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | |
753 | case SND_SOC_DAIFMT_CBM_CFM: | |
e1508289 | 754 | rdai->clk_master = 0; |
1536a968 KM |
755 | break; |
756 | case SND_SOC_DAIFMT_CBS_CFS: | |
e1508289 | 757 | rdai->clk_master = 1; /* codec is slave, cpu is master */ |
1536a968 KM |
758 | break; |
759 | default: | |
760 | return -EINVAL; | |
761 | } | |
762 | ||
1536a968 | 763 | /* set format */ |
22e58665 | 764 | rdai->bit_clk_inv = 0; |
1536a968 KM |
765 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
766 | case SND_SOC_DAIFMT_I2S: | |
767 | rdai->sys_delay = 0; | |
768 | rdai->data_alignment = 0; | |
1a7889ca | 769 | rdai->frm_clk_inv = 0; |
1536a968 KM |
770 | break; |
771 | case SND_SOC_DAIFMT_LEFT_J: | |
3791b3ee | 772 | case SND_SOC_DAIFMT_DSP_B: |
1536a968 KM |
773 | rdai->sys_delay = 1; |
774 | rdai->data_alignment = 0; | |
1a7889ca | 775 | rdai->frm_clk_inv = 1; |
1536a968 KM |
776 | break; |
777 | case SND_SOC_DAIFMT_RIGHT_J: | |
778 | rdai->sys_delay = 1; | |
779 | rdai->data_alignment = 1; | |
1a7889ca KM |
780 | rdai->frm_clk_inv = 1; |
781 | break; | |
3791b3ee DT |
782 | case SND_SOC_DAIFMT_DSP_A: |
783 | rdai->sys_delay = 0; | |
784 | rdai->data_alignment = 0; | |
785 | rdai->frm_clk_inv = 1; | |
786 | break; | |
1a7889ca KM |
787 | } |
788 | ||
789 | /* set clock inversion */ | |
790 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | |
791 | case SND_SOC_DAIFMT_NB_IF: | |
1a7889ca KM |
792 | rdai->frm_clk_inv = !rdai->frm_clk_inv; |
793 | break; | |
794 | case SND_SOC_DAIFMT_IB_NF: | |
795 | rdai->bit_clk_inv = !rdai->bit_clk_inv; | |
1a7889ca KM |
796 | break; |
797 | case SND_SOC_DAIFMT_IB_IF: | |
798 | rdai->bit_clk_inv = !rdai->bit_clk_inv; | |
799 | rdai->frm_clk_inv = !rdai->frm_clk_inv; | |
800 | break; | |
801 | case SND_SOC_DAIFMT_NB_NF: | |
802 | default: | |
1536a968 KM |
803 | break; |
804 | } | |
805 | ||
806 | return 0; | |
807 | } | |
808 | ||
186fadc1 KM |
809 | static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, |
810 | u32 tx_mask, u32 rx_mask, | |
811 | int slots, int slot_width) | |
812 | { | |
813 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); | |
814 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | |
815 | struct device *dev = rsnd_priv_to_dev(priv); | |
816 | ||
fb2815f4 DT |
817 | switch (slot_width) { |
818 | case 16: | |
819 | case 24: | |
820 | case 32: | |
821 | break; | |
822 | default: | |
82ab7e9a KM |
823 | /* use default */ |
824 | slot_width = 32; | |
fb2815f4 DT |
825 | } |
826 | ||
186fadc1 | 827 | switch (slots) { |
8cc03722 | 828 | case 2: |
f69f4522 | 829 | /* TDM Split Mode */ |
186fadc1 | 830 | case 6: |
8cc03722 | 831 | case 8: |
186fadc1 | 832 | /* TDM Extend Mode */ |
1ff9593d KM |
833 | rsnd_rdai_channels_set(rdai, slots); |
834 | rsnd_rdai_ssi_lane_set(rdai, 1); | |
fb2815f4 | 835 | rsnd_rdai_width_set(rdai, slot_width); |
186fadc1 KM |
836 | break; |
837 | default: | |
838 | dev_err(dev, "unsupported TDM slots (%d)\n", slots); | |
839 | return -EINVAL; | |
840 | } | |
841 | ||
842 | return 0; | |
843 | } | |
844 | ||
8cc03722 | 845 | static unsigned int rsnd_soc_hw_channels_list[] = { |
29d03ff5 | 846 | 2, 6, 8, |
8cc03722 KM |
847 | }; |
848 | ||
849 | static unsigned int rsnd_soc_hw_rate_list[] = { | |
850 | 8000, | |
851 | 11025, | |
852 | 16000, | |
853 | 22050, | |
854 | 32000, | |
855 | 44100, | |
856 | 48000, | |
857 | 64000, | |
858 | 88200, | |
859 | 96000, | |
860 | 176400, | |
861 | 192000, | |
862 | }; | |
863 | ||
fb2815f4 | 864 | static int rsnd_soc_hw_rule(struct rsnd_dai *rdai, |
8cc03722 KM |
865 | unsigned int *list, int list_num, |
866 | struct snd_interval *baseline, struct snd_interval *iv) | |
867 | { | |
868 | struct snd_interval p; | |
947f4eb5 | 869 | unsigned int rate; |
8cc03722 KM |
870 | int i; |
871 | ||
872 | snd_interval_any(&p); | |
873 | p.min = UINT_MAX; | |
874 | p.max = 0; | |
875 | ||
876 | for (i = 0; i < list_num; i++) { | |
877 | ||
878 | if (!snd_interval_test(iv, list[i])) | |
879 | continue; | |
880 | ||
fb2815f4 | 881 | rate = rsnd_ssi_clk_query(rdai, |
8cc03722 KM |
882 | baseline->min, list[i], NULL); |
883 | if (rate > 0) { | |
884 | p.min = min(p.min, list[i]); | |
885 | p.max = max(p.max, list[i]); | |
886 | } | |
887 | ||
fb2815f4 | 888 | rate = rsnd_ssi_clk_query(rdai, |
8cc03722 KM |
889 | baseline->max, list[i], NULL); |
890 | if (rate > 0) { | |
891 | p.min = min(p.min, list[i]); | |
892 | p.max = max(p.max, list[i]); | |
893 | } | |
894 | } | |
895 | ||
896 | return snd_interval_refine(iv, &p); | |
897 | } | |
898 | ||
b735662f JW |
899 | static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, |
900 | struct snd_pcm_hw_rule *rule) | |
8cc03722 KM |
901 | { |
902 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | |
903 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | |
904 | struct snd_interval ic; | |
b735662f JW |
905 | struct rsnd_dai_stream *io = rule->private; |
906 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | |
8cc03722 KM |
907 | |
908 | /* | |
909 | * possible sampling rate limitation is same as | |
910 | * 2ch if it supports multi ssi | |
b2fb31bb | 911 | * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) |
8cc03722 KM |
912 | */ |
913 | ic = *ic_; | |
b2fb31bb KM |
914 | ic.min = |
915 | ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); | |
8cc03722 | 916 | |
fb2815f4 | 917 | return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list, |
8cc03722 KM |
918 | ARRAY_SIZE(rsnd_soc_hw_rate_list), |
919 | &ic, ir); | |
920 | } | |
921 | ||
b735662f JW |
922 | static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, |
923 | struct snd_pcm_hw_rule *rule) | |
8cc03722 KM |
924 | { |
925 | struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | |
926 | struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | |
927 | struct snd_interval ic; | |
b735662f JW |
928 | struct rsnd_dai_stream *io = rule->private; |
929 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | |
8cc03722 KM |
930 | |
931 | /* | |
932 | * possible sampling rate limitation is same as | |
933 | * 2ch if it supports multi ssi | |
b2fb31bb | 934 | * and same as 8ch if TDM 6ch (see rsnd_ssi_config_init()) |
8cc03722 KM |
935 | */ |
936 | ic = *ic_; | |
b2fb31bb KM |
937 | ic.min = |
938 | ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); | |
8cc03722 | 939 | |
fb2815f4 | 940 | return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list, |
8cc03722 KM |
941 | ARRAY_SIZE(rsnd_soc_hw_channels_list), |
942 | ir, &ic); | |
943 | } | |
944 | ||
5c2e035e | 945 | static const struct snd_pcm_hardware rsnd_pcm_hardware = { |
3c9736aa KM |
946 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
947 | SNDRV_PCM_INFO_MMAP | | |
948 | SNDRV_PCM_INFO_MMAP_VALID, | |
949 | .buffer_bytes_max = 64 * 1024, | |
950 | .period_bytes_min = 32, | |
951 | .period_bytes_max = 8192, | |
952 | .periods_min = 1, | |
953 | .periods_max = 32, | |
954 | .fifo_size = 256, | |
955 | }; | |
956 | ||
957 | static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream, | |
958 | struct snd_soc_dai *dai) | |
8cc03722 KM |
959 | { |
960 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | |
3c9736aa | 961 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
8cc03722 | 962 | struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint; |
3c9736aa | 963 | struct snd_pcm_runtime *runtime = substream->runtime; |
8cc03722 KM |
964 | unsigned int max_channels = rsnd_rdai_channels_get(rdai); |
965 | int i; | |
966 | ||
b2fb31bb KM |
967 | rsnd_dai_stream_init(io, substream); |
968 | ||
8cc03722 KM |
969 | /* |
970 | * Channel Limitation | |
971 | * It depends on Platform design | |
972 | */ | |
973 | constraint->list = rsnd_soc_hw_channels_list; | |
974 | constraint->count = 0; | |
975 | constraint->mask = 0; | |
976 | ||
977 | for (i = 0; i < ARRAY_SIZE(rsnd_soc_hw_channels_list); i++) { | |
978 | if (rsnd_soc_hw_channels_list[i] > max_channels) | |
979 | break; | |
980 | constraint->count = i + 1; | |
981 | } | |
982 | ||
3c9736aa KM |
983 | snd_soc_set_runtime_hwparams(substream, &rsnd_pcm_hardware); |
984 | ||
8cc03722 KM |
985 | snd_pcm_hw_constraint_list(runtime, 0, |
986 | SNDRV_PCM_HW_PARAM_CHANNELS, constraint); | |
987 | ||
3c9736aa KM |
988 | snd_pcm_hw_constraint_integer(runtime, |
989 | SNDRV_PCM_HW_PARAM_PERIODS); | |
990 | ||
8cc03722 KM |
991 | /* |
992 | * Sampling Rate / Channel Limitation | |
993 | * It depends on Clock Master Mode | |
994 | */ | |
3c9736aa | 995 | if (rsnd_rdai_is_clk_master(rdai)) { |
b2fb31bb KM |
996 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
997 | ||
3c9736aa | 998 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
b735662f JW |
999 | rsnd_soc_hw_rule_rate, |
1000 | is_play ? &rdai->playback : &rdai->capture, | |
3c9736aa KM |
1001 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
1002 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | |
b735662f JW |
1003 | rsnd_soc_hw_rule_channels, |
1004 | is_play ? &rdai->playback : &rdai->capture, | |
3c9736aa KM |
1005 | SNDRV_PCM_HW_PARAM_RATE, -1); |
1006 | } | |
8cc03722 | 1007 | |
6ab6a247 | 1008 | return 0; |
10a9cca1 KM |
1009 | } |
1010 | ||
1011 | static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream, | |
1012 | struct snd_soc_dai *dai) | |
1013 | { | |
1014 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | |
f30b4ca4 | 1015 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); |
10a9cca1 KM |
1016 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
1017 | ||
1018 | /* | |
1019 | * call rsnd_dai_call without spinlock | |
1020 | */ | |
6ab6a247 | 1021 | rsnd_dai_call(cleanup, io, priv); |
b2fb31bb KM |
1022 | |
1023 | rsnd_dai_stream_quit(io); | |
10a9cca1 KM |
1024 | } |
1025 | ||
4d230d12 JW |
1026 | static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream, |
1027 | struct snd_soc_dai *dai) | |
1028 | { | |
1029 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); | |
1030 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | |
1031 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | |
1032 | ||
1033 | return rsnd_dai_call(prepare, io, priv); | |
1034 | } | |
1035 | ||
1536a968 | 1036 | static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { |
10a9cca1 KM |
1037 | .startup = rsnd_soc_dai_startup, |
1038 | .shutdown = rsnd_soc_dai_shutdown, | |
1536a968 KM |
1039 | .trigger = rsnd_soc_dai_trigger, |
1040 | .set_fmt = rsnd_soc_dai_set_fmt, | |
186fadc1 | 1041 | .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, |
4d230d12 | 1042 | .prepare = rsnd_soc_dai_prepare, |
1536a968 KM |
1043 | }; |
1044 | ||
2264cf2e | 1045 | static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv, |
f497c88b KM |
1046 | struct rsnd_dai_stream *io, |
1047 | struct device_node *dai_np) | |
538a4ffe KM |
1048 | { |
1049 | struct device *dev = rsnd_priv_to_dev(priv); | |
538a4ffe KM |
1050 | struct device_node *ssiu_np = rsnd_ssiu_of_node(priv); |
1051 | struct device_node *np; | |
f497c88b | 1052 | int is_play = rsnd_io_is_play(io); |
538a4ffe KM |
1053 | int i, j; |
1054 | ||
1055 | if (!ssiu_np) | |
1056 | return; | |
1057 | ||
538a4ffe KM |
1058 | /* |
1059 | * This driver assumes that it is TDM Split mode | |
1060 | * if it includes ssiu node | |
1061 | */ | |
1062 | for (i = 0;; i++) { | |
1063 | struct device_node *node = is_play ? | |
1064 | of_parse_phandle(dai_np, "playback", i) : | |
1065 | of_parse_phandle(dai_np, "capture", i); | |
1066 | ||
1067 | if (!node) | |
1068 | break; | |
1069 | ||
1070 | j = 0; | |
1071 | for_each_child_of_node(ssiu_np, np) { | |
1072 | if (np == node) { | |
1073 | rsnd_flags_set(io, RSND_STREAM_TDM_SPLIT); | |
1074 | dev_dbg(dev, "%s is part of TDM Split\n", io->name); | |
1075 | } | |
1076 | j++; | |
1077 | } | |
1078 | ||
1079 | } | |
1080 | } | |
1081 | ||
2264cf2e KM |
1082 | static void rsnd_parse_connect_simple(struct rsnd_priv *priv, |
1083 | struct rsnd_dai_stream *io, | |
1084 | struct device_node *dai_np) | |
1085 | { | |
1086 | if (!rsnd_io_to_mod_ssi(io)) | |
1087 | return; | |
1088 | ||
1089 | rsnd_parse_tdm_split_mode(priv, io, dai_np); | |
1090 | } | |
1091 | ||
beed78ae KM |
1092 | static void rsnd_parse_connect_graph(struct rsnd_priv *priv, |
1093 | struct rsnd_dai_stream *io, | |
1094 | struct device_node *endpoint) | |
1095 | { | |
1096 | struct device *dev = rsnd_priv_to_dev(priv); | |
1097 | struct device_node *remote_node = of_graph_get_remote_port_parent(endpoint); | |
1098 | ||
1099 | if (!rsnd_io_to_mod_ssi(io)) | |
1100 | return; | |
1101 | ||
1102 | /* HDMI0 */ | |
1103 | if (strstr(remote_node->full_name, "hdmi@fead0000")) { | |
1104 | rsnd_flags_set(io, RSND_STREAM_HDMI0); | |
1105 | dev_dbg(dev, "%s connected to HDMI0\n", io->name); | |
1106 | } | |
1107 | ||
1108 | /* HDMI1 */ | |
1109 | if (strstr(remote_node->full_name, "hdmi@feae0000")) { | |
1110 | rsnd_flags_set(io, RSND_STREAM_HDMI1); | |
1111 | dev_dbg(dev, "%s connected to HDMI1\n", io->name); | |
1112 | } | |
f69f4522 | 1113 | |
2264cf2e | 1114 | rsnd_parse_tdm_split_mode(priv, io, endpoint); |
beed78ae KM |
1115 | } |
1116 | ||
89b66174 KM |
1117 | void rsnd_parse_connect_common(struct rsnd_dai *rdai, |
1118 | struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), | |
1119 | struct device_node *node, | |
1120 | struct device_node *playback, | |
1121 | struct device_node *capture) | |
1122 | { | |
1123 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | |
1124 | struct device_node *np; | |
1125 | struct rsnd_mod *mod; | |
1126 | int i; | |
1127 | ||
1128 | if (!node) | |
1129 | return; | |
1130 | ||
1131 | i = 0; | |
1132 | for_each_child_of_node(node, np) { | |
1133 | mod = mod_get(priv, i); | |
1134 | if (np == playback) | |
1135 | rsnd_dai_connect(mod, &rdai->playback, mod->type); | |
1136 | if (np == capture) | |
1137 | rsnd_dai_connect(mod, &rdai->capture, mod->type); | |
1138 | i++; | |
1139 | } | |
1140 | ||
1141 | of_node_put(node); | |
1142 | } | |
1143 | ||
11d0f8ed KM |
1144 | static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv, |
1145 | int *is_graph) | |
1146 | { | |
1147 | struct device *dev = rsnd_priv_to_dev(priv); | |
1148 | struct device_node *np = dev->of_node; | |
1149 | struct device_node *dai_node; | |
1150 | struct device_node *ret; | |
1151 | ||
1152 | *is_graph = 0; | |
1153 | ||
1154 | /* | |
1155 | * parse both previous dai (= rcar_sound,dai), and | |
1156 | * graph dai (= ports/port) | |
1157 | */ | |
1158 | dai_node = of_get_child_by_name(np, RSND_NODE_DAI); | |
1159 | if (dai_node) { | |
1160 | ret = dai_node; | |
1161 | goto of_node_compatible; | |
1162 | } | |
1163 | ||
1164 | ret = np; | |
1165 | ||
1166 | dai_node = of_graph_get_next_endpoint(np, NULL); | |
1167 | if (dai_node) | |
1168 | goto of_node_graph; | |
1169 | ||
1170 | return NULL; | |
1171 | ||
1172 | of_node_graph: | |
1173 | *is_graph = 1; | |
1174 | of_node_compatible: | |
1175 | of_node_put(dai_node); | |
1176 | ||
1177 | return ret; | |
1178 | } | |
1179 | ||
e9b5daad KM |
1180 | |
1181 | #define PREALLOC_BUFFER (32 * 1024) | |
1182 | #define PREALLOC_BUFFER_MAX (32 * 1024) | |
1183 | ||
1184 | static int rsnd_preallocate_pages(struct snd_soc_pcm_runtime *rtd, | |
1185 | struct rsnd_dai_stream *io, | |
1186 | int stream) | |
1187 | { | |
1188 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | |
1189 | struct device *dev = rsnd_priv_to_dev(priv); | |
1190 | struct snd_pcm_substream *substream; | |
1191 | ||
1192 | /* | |
1193 | * use Audio-DMAC dev if we can use IPMMU | |
1194 | * see | |
1195 | * rsnd_dmaen_attach() | |
1196 | */ | |
1197 | if (io->dmac_dev) | |
1198 | dev = io->dmac_dev; | |
1199 | ||
1200 | for (substream = rtd->pcm->streams[stream].substream; | |
1201 | substream; | |
1202 | substream = substream->next) { | |
1203 | snd_pcm_lib_preallocate_pages(substream, | |
1204 | SNDRV_DMA_TYPE_DEV, | |
1205 | dev, | |
1206 | PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); | |
1207 | } | |
1208 | ||
1209 | return 0; | |
1210 | } | |
1211 | ||
1212 | static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd, | |
1213 | struct snd_soc_dai *dai) | |
1214 | { | |
1215 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | |
1216 | int ret; | |
1217 | ||
1218 | ret = rsnd_dai_call(pcm_new, &rdai->playback, rtd); | |
1219 | if (ret) | |
1220 | return ret; | |
1221 | ||
1222 | ret = rsnd_dai_call(pcm_new, &rdai->capture, rtd); | |
1223 | if (ret) | |
1224 | return ret; | |
1225 | ||
1226 | ret = rsnd_preallocate_pages(rtd, &rdai->playback, | |
1227 | SNDRV_PCM_STREAM_PLAYBACK); | |
1228 | if (ret) | |
1229 | return ret; | |
1230 | ||
1231 | ret = rsnd_preallocate_pages(rtd, &rdai->capture, | |
1232 | SNDRV_PCM_STREAM_CAPTURE); | |
1233 | if (ret) | |
1234 | return ret; | |
1235 | ||
1236 | return 0; | |
1237 | } | |
1238 | ||
4d4b334b KM |
1239 | static void __rsnd_dai_probe(struct rsnd_priv *priv, |
1240 | struct device_node *dai_np, | |
9f761183 | 1241 | int dai_i) |
90e8e50f | 1242 | { |
90e8e50f | 1243 | struct device_node *playback, *capture; |
94e2710c KM |
1244 | struct rsnd_dai_stream *io_playback; |
1245 | struct rsnd_dai_stream *io_capture; | |
4d4b334b | 1246 | struct snd_soc_dai_driver *drv; |
94e2710c | 1247 | struct rsnd_dai *rdai; |
2ea6b074 | 1248 | struct device *dev = rsnd_priv_to_dev(priv); |
4d4b334b KM |
1249 | int io_i; |
1250 | ||
1251 | rdai = rsnd_rdai_get(priv, dai_i); | |
a0d847c3 | 1252 | drv = rsnd_daidrv_get(priv, dai_i); |
4d4b334b KM |
1253 | io_playback = &rdai->playback; |
1254 | io_capture = &rdai->capture; | |
1255 | ||
1256 | snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); | |
1257 | ||
1258 | rdai->priv = priv; | |
1259 | drv->name = rdai->name; | |
1260 | drv->ops = &rsnd_soc_dai_ops; | |
e9b5daad | 1261 | drv->pcm_new = rsnd_pcm_new; |
4d4b334b | 1262 | |
9328882e | 1263 | snprintf(io_playback->name, RSND_DAI_NAME_SIZE, |
4d4b334b KM |
1264 | "DAI%d Playback", dai_i); |
1265 | drv->playback.rates = RSND_RATES; | |
1266 | drv->playback.formats = RSND_FMTS; | |
1267 | drv->playback.channels_min = 2; | |
29d03ff5 | 1268 | drv->playback.channels_max = 8; |
9328882e | 1269 | drv->playback.stream_name = io_playback->name; |
4d4b334b | 1270 | |
9328882e | 1271 | snprintf(io_capture->name, RSND_DAI_NAME_SIZE, |
4d4b334b KM |
1272 | "DAI%d Capture", dai_i); |
1273 | drv->capture.rates = RSND_RATES; | |
1274 | drv->capture.formats = RSND_FMTS; | |
1275 | drv->capture.channels_min = 2; | |
29d03ff5 | 1276 | drv->capture.channels_max = 8; |
9328882e | 1277 | drv->capture.stream_name = io_capture->name; |
4d4b334b | 1278 | |
9328882e KM |
1279 | io_playback->rdai = rdai; |
1280 | io_capture->rdai = rdai; | |
1ff9593d KM |
1281 | rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ |
1282 | rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ | |
fb2815f4 | 1283 | rsnd_rdai_width_set(rdai, 32); /* default 32bit width */ |
4d4b334b KM |
1284 | |
1285 | for (io_i = 0;; io_i++) { | |
1286 | playback = of_parse_phandle(dai_np, "playback", io_i); | |
1287 | capture = of_parse_phandle(dai_np, "capture", io_i); | |
1288 | ||
1289 | if (!playback && !capture) | |
1290 | break; | |
1291 | ||
1292 | rsnd_parse_connect_ssi(rdai, playback, capture); | |
4e7788fb | 1293 | rsnd_parse_connect_ssiu(rdai, playback, capture); |
4d4b334b KM |
1294 | rsnd_parse_connect_src(rdai, playback, capture); |
1295 | rsnd_parse_connect_ctu(rdai, playback, capture); | |
1296 | rsnd_parse_connect_mix(rdai, playback, capture); | |
1297 | rsnd_parse_connect_dvc(rdai, playback, capture); | |
1298 | ||
1299 | of_node_put(playback); | |
1300 | of_node_put(capture); | |
1301 | } | |
1302 | ||
7cc90a5c KM |
1303 | if (rsnd_ssi_is_pin_sharing(io_capture) || |
1304 | rsnd_ssi_is_pin_sharing(io_playback)) { | |
1305 | /* should have symmetric_rates if pin sharing */ | |
1306 | drv->symmetric_rates = 1; | |
1307 | } | |
1308 | ||
4d4b334b KM |
1309 | dev_dbg(dev, "%s (%s/%s)\n", rdai->name, |
1310 | rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", | |
1311 | rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); | |
1312 | } | |
1313 | ||
1314 | static int rsnd_dai_probe(struct rsnd_priv *priv) | |
1315 | { | |
1316 | struct device_node *dai_node; | |
1317 | struct device_node *dai_np; | |
1318 | struct snd_soc_dai_driver *rdrv; | |
1319 | struct device *dev = rsnd_priv_to_dev(priv); | |
1320 | struct rsnd_dai *rdai; | |
1321 | int nr; | |
11d0f8ed | 1322 | int is_graph; |
4d4b334b | 1323 | int dai_i; |
90e8e50f | 1324 | |
11d0f8ed | 1325 | dai_node = rsnd_dai_of_node(priv, &is_graph); |
4d4b334b KM |
1326 | if (is_graph) |
1327 | nr = of_graph_get_endpoint_count(dai_node); | |
1328 | else | |
1329 | nr = of_get_child_count(dai_node); | |
1330 | ||
1331 | if (!nr) | |
1332 | return -EINVAL; | |
90e8e50f | 1333 | |
a86854d0 KC |
1334 | rdrv = devm_kcalloc(dev, nr, sizeof(*rdrv), GFP_KERNEL); |
1335 | rdai = devm_kcalloc(dev, nr, sizeof(*rdai), GFP_KERNEL); | |
4d4b334b KM |
1336 | if (!rdrv || !rdai) |
1337 | return -ENOMEM; | |
90e8e50f | 1338 | |
94e2710c | 1339 | priv->rdai_nr = nr; |
2ff2ecca | 1340 | priv->daidrv = rdrv; |
94e2710c | 1341 | priv->rdai = rdai; |
90e8e50f KM |
1342 | |
1343 | /* | |
1344 | * parse all dai | |
1345 | */ | |
1346 | dai_i = 0; | |
4d4b334b | 1347 | if (is_graph) { |
7fa72cca | 1348 | for_each_endpoint_of_node(dai_node, dai_np) { |
9f761183 | 1349 | __rsnd_dai_probe(priv, dai_np, dai_i); |
beed78ae KM |
1350 | if (rsnd_is_gen3(priv)) { |
1351 | struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); | |
1352 | ||
1353 | rsnd_parse_connect_graph(priv, &rdai->playback, dai_np); | |
1354 | rsnd_parse_connect_graph(priv, &rdai->capture, dai_np); | |
1355 | } | |
7fa72cca KM |
1356 | dai_i++; |
1357 | } | |
4d4b334b | 1358 | } else { |
538a4ffe KM |
1359 | for_each_child_of_node(dai_node, dai_np) { |
1360 | __rsnd_dai_probe(priv, dai_np, dai_i); | |
1361 | if (rsnd_is_gen3(priv)) { | |
f497c88b KM |
1362 | struct rsnd_dai *rdai = rsnd_rdai_get(priv, dai_i); |
1363 | ||
1364 | rsnd_parse_connect_simple(priv, &rdai->playback, dai_np); | |
1365 | rsnd_parse_connect_simple(priv, &rdai->capture, dai_np); | |
538a4ffe KM |
1366 | } |
1367 | dai_i++; | |
1368 | } | |
1536a968 KM |
1369 | } |
1370 | ||
4d4b334b | 1371 | return 0; |
1536a968 KM |
1372 | } |
1373 | ||
1536a968 KM |
1374 | /* |
1375 | * pcm ops | |
1376 | */ | |
1536a968 KM |
1377 | static int rsnd_hw_params(struct snd_pcm_substream *substream, |
1378 | struct snd_pcm_hw_params *hw_params) | |
1379 | { | |
3b7843ff KM |
1380 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); |
1381 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | |
1382 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | |
c2aaaa57 | 1383 | struct snd_soc_pcm_runtime *fe = substream->private_data; |
3b7843ff KM |
1384 | int ret; |
1385 | ||
c2aaaa57 KM |
1386 | /* |
1387 | * rsnd assumes that it might be used under DPCM if user want to use | |
1388 | * channel / rate convert. Then, rsnd should be FE. | |
1389 | * And then, this function will be called *after* BE settings. | |
1390 | * this means, each BE already has fixuped hw_params. | |
1391 | * see | |
1392 | * dpcm_fe_dai_hw_params() | |
1393 | * dpcm_be_dai_hw_params() | |
1394 | */ | |
1395 | io->converted_rate = 0; | |
1396 | io->converted_chan = 0; | |
1397 | if (fe->dai_link->dynamic) { | |
1398 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | |
1399 | struct device *dev = rsnd_priv_to_dev(priv); | |
1400 | struct snd_soc_dpcm *dpcm; | |
1401 | struct snd_pcm_hw_params *be_params; | |
1402 | int stream = substream->stream; | |
1403 | ||
1404 | for_each_dpcm_be(fe, stream, dpcm) { | |
1405 | be_params = &dpcm->hw_params; | |
1406 | if (params_channels(hw_params) != params_channels(be_params)) | |
1407 | io->converted_chan = params_channels(be_params); | |
1408 | if (params_rate(hw_params) != params_rate(be_params)) | |
1409 | io->converted_rate = params_rate(be_params); | |
1410 | } | |
1411 | if (io->converted_chan) | |
1412 | dev_dbg(dev, "convert channels = %d\n", io->converted_chan); | |
1413 | if (io->converted_rate) | |
1414 | dev_dbg(dev, "convert rate = %d\n", io->converted_rate); | |
1415 | } | |
1416 | ||
3b7843ff KM |
1417 | ret = rsnd_dai_call(hw_params, io, substream, hw_params); |
1418 | if (ret) | |
1419 | return ret; | |
1420 | ||
1536a968 KM |
1421 | return snd_pcm_lib_malloc_pages(substream, |
1422 | params_buffer_bytes(hw_params)); | |
1423 | } | |
1424 | ||
859fd6cb TW |
1425 | static int rsnd_hw_free(struct snd_pcm_substream *substream) |
1426 | { | |
1427 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); | |
1428 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | |
1429 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | |
1430 | int ret; | |
1431 | ||
1432 | ret = rsnd_dai_call(hw_free, io, substream); | |
1433 | if (ret) | |
1434 | return ret; | |
1435 | ||
1436 | return snd_pcm_lib_free_pages(substream); | |
1437 | } | |
1438 | ||
1536a968 KM |
1439 | static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream) |
1440 | { | |
1536a968 KM |
1441 | struct snd_soc_dai *dai = rsnd_substream_to_dai(substream); |
1442 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | |
1443 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | |
07b7acb5 KM |
1444 | snd_pcm_uframes_t pointer = 0; |
1445 | ||
1446 | rsnd_dai_call(pointer, io, &pointer); | |
1536a968 | 1447 | |
07b7acb5 | 1448 | return pointer; |
1536a968 KM |
1449 | } |
1450 | ||
b23bd34c | 1451 | static const struct snd_pcm_ops rsnd_pcm_ops = { |
1536a968 KM |
1452 | .ioctl = snd_pcm_lib_ioctl, |
1453 | .hw_params = rsnd_hw_params, | |
859fd6cb | 1454 | .hw_free = rsnd_hw_free, |
1536a968 KM |
1455 | .pointer = rsnd_pointer, |
1456 | }; | |
1457 | ||
170a2497 KM |
1458 | /* |
1459 | * snd_kcontrol | |
1460 | */ | |
170a2497 KM |
1461 | static int rsnd_kctrl_info(struct snd_kcontrol *kctrl, |
1462 | struct snd_ctl_elem_info *uinfo) | |
1463 | { | |
16d44989 | 1464 | struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); |
170a2497 KM |
1465 | |
1466 | if (cfg->texts) { | |
1467 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |
1468 | uinfo->count = cfg->size; | |
1469 | uinfo->value.enumerated.items = cfg->max; | |
1470 | if (uinfo->value.enumerated.item >= cfg->max) | |
1471 | uinfo->value.enumerated.item = cfg->max - 1; | |
1472 | strlcpy(uinfo->value.enumerated.name, | |
1473 | cfg->texts[uinfo->value.enumerated.item], | |
1474 | sizeof(uinfo->value.enumerated.name)); | |
1475 | } else { | |
1476 | uinfo->count = cfg->size; | |
1477 | uinfo->value.integer.min = 0; | |
1478 | uinfo->value.integer.max = cfg->max; | |
1479 | uinfo->type = (cfg->max == 1) ? | |
1480 | SNDRV_CTL_ELEM_TYPE_BOOLEAN : | |
1481 | SNDRV_CTL_ELEM_TYPE_INTEGER; | |
1482 | } | |
1483 | ||
1484 | return 0; | |
1485 | } | |
1486 | ||
1487 | static int rsnd_kctrl_get(struct snd_kcontrol *kctrl, | |
1488 | struct snd_ctl_elem_value *uc) | |
1489 | { | |
16d44989 | 1490 | struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); |
170a2497 KM |
1491 | int i; |
1492 | ||
1493 | for (i = 0; i < cfg->size; i++) | |
1494 | if (cfg->texts) | |
1495 | uc->value.enumerated.item[i] = cfg->val[i]; | |
1496 | else | |
1497 | uc->value.integer.value[i] = cfg->val[i]; | |
1498 | ||
1499 | return 0; | |
1500 | } | |
1501 | ||
1502 | static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, | |
1503 | struct snd_ctl_elem_value *uc) | |
1504 | { | |
16d44989 | 1505 | struct rsnd_kctrl_cfg *cfg = snd_kcontrol_chip(kctrl); |
170a2497 KM |
1506 | int i, change = 0; |
1507 | ||
f0b04d8b KM |
1508 | if (!cfg->accept(cfg->io)) |
1509 | return 0; | |
1510 | ||
170a2497 KM |
1511 | for (i = 0; i < cfg->size; i++) { |
1512 | if (cfg->texts) { | |
1513 | change |= (uc->value.enumerated.item[i] != cfg->val[i]); | |
1514 | cfg->val[i] = uc->value.enumerated.item[i]; | |
1515 | } else { | |
1516 | change |= (uc->value.integer.value[i] != cfg->val[i]); | |
1517 | cfg->val[i] = uc->value.integer.value[i]; | |
1518 | } | |
1519 | } | |
1520 | ||
d7289565 | 1521 | if (change && cfg->update) |
16d44989 | 1522 | cfg->update(cfg->io, cfg->mod); |
170a2497 KM |
1523 | |
1524 | return change; | |
1525 | } | |
1526 | ||
f0b04d8b KM |
1527 | int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io) |
1528 | { | |
1529 | return 1; | |
1530 | } | |
1531 | ||
1532 | int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io) | |
1533 | { | |
1534 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | |
b5c08868 JW |
1535 | struct rsnd_priv *priv = rsnd_io_to_priv(io); |
1536 | struct device *dev = rsnd_priv_to_dev(priv); | |
f0b04d8b | 1537 | |
b5c08868 JW |
1538 | if (!runtime) { |
1539 | dev_warn(dev, "Can't update kctrl when idle\n"); | |
1540 | return 0; | |
1541 | } | |
1542 | ||
1543 | return 1; | |
f0b04d8b KM |
1544 | } |
1545 | ||
32973dcf KM |
1546 | struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg) |
1547 | { | |
1548 | cfg->cfg.val = cfg->val; | |
1549 | ||
1550 | return &cfg->cfg; | |
1551 | } | |
1552 | ||
1553 | struct rsnd_kctrl_cfg *rsnd_kctrl_init_s(struct rsnd_kctrl_cfg_s *cfg) | |
1554 | { | |
1555 | cfg->cfg.val = &cfg->val; | |
1556 | ||
1557 | return &cfg->cfg; | |
1558 | } | |
1559 | ||
f3c26ac6 KM |
1560 | const char * const volume_ramp_rate[] = { |
1561 | "128 dB/1 step", /* 00000 */ | |
1562 | "64 dB/1 step", /* 00001 */ | |
1563 | "32 dB/1 step", /* 00010 */ | |
1564 | "16 dB/1 step", /* 00011 */ | |
1565 | "8 dB/1 step", /* 00100 */ | |
1566 | "4 dB/1 step", /* 00101 */ | |
1567 | "2 dB/1 step", /* 00110 */ | |
1568 | "1 dB/1 step", /* 00111 */ | |
1569 | "0.5 dB/1 step", /* 01000 */ | |
1570 | "0.25 dB/1 step", /* 01001 */ | |
3e3c9ee1 | 1571 | "0.125 dB/1 step", /* 01010 = VOLUME_RAMP_MAX_MIX */ |
f3c26ac6 KM |
1572 | "0.125 dB/2 steps", /* 01011 */ |
1573 | "0.125 dB/4 steps", /* 01100 */ | |
1574 | "0.125 dB/8 steps", /* 01101 */ | |
1575 | "0.125 dB/16 steps", /* 01110 */ | |
1576 | "0.125 dB/32 steps", /* 01111 */ | |
1577 | "0.125 dB/64 steps", /* 10000 */ | |
1578 | "0.125 dB/128 steps", /* 10001 */ | |
1579 | "0.125 dB/256 steps", /* 10010 */ | |
1580 | "0.125 dB/512 steps", /* 10011 */ | |
1581 | "0.125 dB/1024 steps", /* 10100 */ | |
1582 | "0.125 dB/2048 steps", /* 10101 */ | |
1583 | "0.125 dB/4096 steps", /* 10110 */ | |
1584 | "0.125 dB/8192 steps", /* 10111 = VOLUME_RAMP_MAX_DVC */ | |
1585 | }; | |
1586 | ||
32973dcf KM |
1587 | int rsnd_kctrl_new(struct rsnd_mod *mod, |
1588 | struct rsnd_dai_stream *io, | |
1589 | struct snd_soc_pcm_runtime *rtd, | |
1590 | const unsigned char *name, | |
f0b04d8b | 1591 | int (*accept)(struct rsnd_dai_stream *io), |
32973dcf KM |
1592 | void (*update)(struct rsnd_dai_stream *io, |
1593 | struct rsnd_mod *mod), | |
1594 | struct rsnd_kctrl_cfg *cfg, | |
1595 | const char * const *texts, | |
1596 | int size, | |
1597 | u32 max) | |
170a2497 KM |
1598 | { |
1599 | struct snd_card *card = rtd->card->snd_card; | |
1600 | struct snd_kcontrol *kctrl; | |
1601 | struct snd_kcontrol_new knew = { | |
1602 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
1603 | .name = name, | |
1604 | .info = rsnd_kctrl_info, | |
1a497983 | 1605 | .index = rtd->num, |
170a2497 KM |
1606 | .get = rsnd_kctrl_get, |
1607 | .put = rsnd_kctrl_put, | |
170a2497 KM |
1608 | }; |
1609 | int ret; | |
1610 | ||
9c698e84 | 1611 | /* |
7aea8a9d KM |
1612 | * 1) Avoid duplicate register for DVC with MIX case |
1613 | * 2) Allow duplicate register for MIX | |
1614 | * 3) re-register if card was rebinded | |
9c698e84 KM |
1615 | */ |
1616 | list_for_each_entry(kctrl, &card->controls, list) { | |
1617 | struct rsnd_kctrl_cfg *c = kctrl->private_data; | |
1618 | ||
7aea8a9d | 1619 | if (c == cfg) |
9c698e84 KM |
1620 | return 0; |
1621 | } | |
1622 | ||
32973dcf KM |
1623 | if (size > RSND_MAX_CHANNELS) |
1624 | return -EINVAL; | |
1625 | ||
16d44989 | 1626 | kctrl = snd_ctl_new1(&knew, cfg); |
170a2497 KM |
1627 | if (!kctrl) |
1628 | return -ENOMEM; | |
1629 | ||
1630 | ret = snd_ctl_add(card, kctrl); | |
0ea617a2 | 1631 | if (ret < 0) |
170a2497 KM |
1632 | return ret; |
1633 | ||
32973dcf KM |
1634 | cfg->texts = texts; |
1635 | cfg->max = max; | |
1636 | cfg->size = size; | |
f0b04d8b | 1637 | cfg->accept = accept; |
32973dcf KM |
1638 | cfg->update = update; |
1639 | cfg->card = card; | |
1640 | cfg->kctrl = kctrl; | |
1641 | cfg->io = io; | |
16d44989 | 1642 | cfg->mod = mod; |
170a2497 KM |
1643 | |
1644 | return 0; | |
1645 | } | |
1646 | ||
1536a968 | 1647 | /* |
019ea01b | 1648 | * snd_soc_component |
1536a968 | 1649 | */ |
019ea01b | 1650 | static const struct snd_soc_component_driver rsnd_soc_component = { |
1536a968 | 1651 | .ops = &rsnd_pcm_ops, |
1536a968 KM |
1652 | .name = "rsnd", |
1653 | }; | |
1654 | ||
d3a76823 | 1655 | static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, |
f708d944 | 1656 | struct rsnd_dai_stream *io) |
d3a76823 | 1657 | { |
d3a76823 KM |
1658 | int ret; |
1659 | ||
690602fc | 1660 | ret = rsnd_dai_call(probe, io, priv); |
d3a76823 | 1661 | if (ret == -EAGAIN) { |
48d58281 | 1662 | struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); |
9b87bfb2 | 1663 | struct rsnd_mod *mod; |
48d58281 KM |
1664 | int i; |
1665 | ||
d3a76823 KM |
1666 | /* |
1667 | * Fallback to PIO mode | |
1668 | */ | |
1669 | ||
1670 | /* | |
1671 | * call "remove" for SSI/SRC/DVC | |
1672 | * SSI will be switch to PIO mode if it was DMA mode | |
1673 | * see | |
1674 | * rsnd_dma_init() | |
97463e19 | 1675 | * rsnd_ssi_fallback() |
d3a76823 | 1676 | */ |
690602fc | 1677 | rsnd_dai_call(remove, io, priv); |
d3a76823 KM |
1678 | |
1679 | /* | |
48d58281 KM |
1680 | * remove all mod from io |
1681 | * and, re connect ssi | |
d3a76823 | 1682 | */ |
9b87bfb2 KM |
1683 | for_each_rsnd_mod(i, mod, io) |
1684 | rsnd_dai_disconnect(mod, io, i); | |
48d58281 | 1685 | rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); |
d3a76823 | 1686 | |
97463e19 KM |
1687 | /* |
1688 | * fallback | |
1689 | */ | |
690602fc | 1690 | rsnd_dai_call(fallback, io, priv); |
97463e19 | 1691 | |
d3a76823 KM |
1692 | /* |
1693 | * retry to "probe". | |
1694 | * DAI has SSI which is PIO mode only now. | |
1695 | */ | |
690602fc | 1696 | ret = rsnd_dai_call(probe, io, priv); |
d3a76823 KM |
1697 | } |
1698 | ||
1699 | return ret; | |
1700 | } | |
1701 | ||
1536a968 KM |
1702 | /* |
1703 | * rsnd probe | |
1704 | */ | |
1705 | static int rsnd_probe(struct platform_device *pdev) | |
1706 | { | |
1536a968 KM |
1707 | struct rsnd_priv *priv; |
1708 | struct device *dev = &pdev->dev; | |
7681f6ac | 1709 | struct rsnd_dai *rdai; |
2ea6b074 | 1710 | int (*probe_func[])(struct rsnd_priv *priv) = { |
d1ac970f | 1711 | rsnd_gen_probe, |
288f392e | 1712 | rsnd_dma_probe, |
d1ac970f | 1713 | rsnd_ssi_probe, |
c7f69ab5 | 1714 | rsnd_ssiu_probe, |
ba9c949f | 1715 | rsnd_src_probe, |
9269e3c3 | 1716 | rsnd_ctu_probe, |
70fb1052 | 1717 | rsnd_mix_probe, |
bff58ea4 | 1718 | rsnd_dvc_probe, |
1b2ca0ad | 1719 | rsnd_cmd_probe, |
d1ac970f KM |
1720 | rsnd_adg_probe, |
1721 | rsnd_dai_probe, | |
1722 | }; | |
1723 | int ret, i; | |
1536a968 | 1724 | |
1536a968 KM |
1725 | /* |
1726 | * init priv data | |
1727 | */ | |
1728 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
0d7820d0 | 1729 | if (!priv) |
1536a968 | 1730 | return -ENODEV; |
1536a968 | 1731 | |
9f464f8e | 1732 | priv->pdev = pdev; |
6d8044b4 | 1733 | priv->flags = (unsigned long)of_device_get_match_data(dev); |
1536a968 KM |
1734 | spin_lock_init(&priv->lock); |
1735 | ||
1736 | /* | |
1737 | * init each module | |
1738 | */ | |
d1ac970f | 1739 | for (i = 0; i < ARRAY_SIZE(probe_func); i++) { |
2ea6b074 | 1740 | ret = probe_func[i](priv); |
d1ac970f KM |
1741 | if (ret) |
1742 | return ret; | |
1743 | } | |
07539c1d | 1744 | |
7681f6ac | 1745 | for_each_rsnd_dai(rdai, priv, i) { |
f708d944 | 1746 | ret = rsnd_rdai_continuance_probe(priv, &rdai->playback); |
7681f6ac | 1747 | if (ret) |
d62a3dcd | 1748 | goto exit_snd_probe; |
dfc9403b | 1749 | |
f708d944 | 1750 | ret = rsnd_rdai_continuance_probe(priv, &rdai->capture); |
7681f6ac | 1751 | if (ret) |
d62a3dcd | 1752 | goto exit_snd_probe; |
7681f6ac | 1753 | } |
4b4dab82 | 1754 | |
0b1f6ec7 KM |
1755 | dev_set_drvdata(dev, priv); |
1756 | ||
1536a968 KM |
1757 | /* |
1758 | * asoc register | |
1759 | */ | |
019ea01b | 1760 | ret = devm_snd_soc_register_component(dev, &rsnd_soc_component, |
ecba9e72 | 1761 | priv->daidrv, rsnd_rdai_nr(priv)); |
1536a968 KM |
1762 | if (ret < 0) { |
1763 | dev_err(dev, "cannot snd dai register\n"); | |
019ea01b | 1764 | goto exit_snd_probe; |
1536a968 KM |
1765 | } |
1766 | ||
1536a968 KM |
1767 | pm_runtime_enable(dev); |
1768 | ||
1769 | dev_info(dev, "probed\n"); | |
1770 | return ret; | |
1771 | ||
d62a3dcd KM |
1772 | exit_snd_probe: |
1773 | for_each_rsnd_dai(rdai, priv, i) { | |
690602fc KM |
1774 | rsnd_dai_call(remove, &rdai->playback, priv); |
1775 | rsnd_dai_call(remove, &rdai->capture, priv); | |
d62a3dcd | 1776 | } |
1536a968 | 1777 | |
6c92d5a2 KM |
1778 | /* |
1779 | * adg is very special mod which can't use rsnd_dai_call(remove), | |
1780 | * and it registers ADG clock on probe. | |
1781 | * It should be unregister if probe failed. | |
1782 | * Mainly it is assuming -EPROBE_DEFER case | |
1783 | */ | |
1784 | rsnd_adg_remove(priv); | |
1785 | ||
1536a968 KM |
1786 | return ret; |
1787 | } | |
1788 | ||
1789 | static int rsnd_remove(struct platform_device *pdev) | |
1790 | { | |
1791 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); | |
7681f6ac | 1792 | struct rsnd_dai *rdai; |
2ea6b074 | 1793 | void (*remove_func[])(struct rsnd_priv *priv) = { |
2f78dd7f | 1794 | rsnd_ssi_remove, |
c7f69ab5 | 1795 | rsnd_ssiu_remove, |
2f78dd7f | 1796 | rsnd_src_remove, |
9269e3c3 | 1797 | rsnd_ctu_remove, |
70fb1052 | 1798 | rsnd_mix_remove, |
2f78dd7f | 1799 | rsnd_dvc_remove, |
1b2ca0ad | 1800 | rsnd_cmd_remove, |
68a55024 | 1801 | rsnd_adg_remove, |
2f78dd7f | 1802 | }; |
d62a3dcd | 1803 | int ret = 0, i; |
1536a968 | 1804 | |
180d9ef5 KM |
1805 | snd_soc_disconnect_sync(&pdev->dev); |
1806 | ||
1536a968 KM |
1807 | pm_runtime_disable(&pdev->dev); |
1808 | ||
7681f6ac | 1809 | for_each_rsnd_dai(rdai, priv, i) { |
690602fc KM |
1810 | ret |= rsnd_dai_call(remove, &rdai->playback, priv); |
1811 | ret |= rsnd_dai_call(remove, &rdai->capture, priv); | |
7681f6ac | 1812 | } |
1536a968 | 1813 | |
2f78dd7f | 1814 | for (i = 0; i < ARRAY_SIZE(remove_func); i++) |
2ea6b074 | 1815 | remove_func[i](priv); |
2f78dd7f | 1816 | |
d62a3dcd | 1817 | return ret; |
1536a968 KM |
1818 | } |
1819 | ||
6f542703 | 1820 | static int __maybe_unused rsnd_suspend(struct device *dev) |
c2d31718 KM |
1821 | { |
1822 | struct rsnd_priv *priv = dev_get_drvdata(dev); | |
1823 | ||
1824 | rsnd_adg_clk_disable(priv); | |
1825 | ||
1826 | return 0; | |
1827 | } | |
1828 | ||
6f542703 | 1829 | static int __maybe_unused rsnd_resume(struct device *dev) |
c2d31718 KM |
1830 | { |
1831 | struct rsnd_priv *priv = dev_get_drvdata(dev); | |
1832 | ||
1833 | rsnd_adg_clk_enable(priv); | |
1834 | ||
1835 | return 0; | |
1836 | } | |
1837 | ||
49ebf13b | 1838 | static const struct dev_pm_ops rsnd_pm_ops = { |
f8a9a29c | 1839 | SET_SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume) |
c2d31718 KM |
1840 | }; |
1841 | ||
1536a968 KM |
1842 | static struct platform_driver rsnd_driver = { |
1843 | .driver = { | |
1844 | .name = "rcar_sound", | |
c2d31718 | 1845 | .pm = &rsnd_pm_ops, |
90e8e50f | 1846 | .of_match_table = rsnd_of_match, |
1536a968 KM |
1847 | }, |
1848 | .probe = rsnd_probe, | |
1849 | .remove = rsnd_remove, | |
1850 | }; | |
1851 | module_platform_driver(rsnd_driver); | |
1852 | ||
1e0edd4d | 1853 | MODULE_LICENSE("GPL v2"); |
1536a968 KM |
1854 | MODULE_DESCRIPTION("Renesas R-Car audio driver"); |
1855 | MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); | |
1856 | MODULE_ALIAS("platform:rcar-pcm-audio"); |