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