1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * ALSA SoC Audio Layer - Rockchip Multi-DAIS driver
4 *
5 * Copyright (c) 2018 Rockchip Electronics Co. Ltd.
6 * Author: Sugar Zhang <sugar.zhang@rock-chips.com>
7 *
8 */
9
10 #include <linux/module.h>
11 #include <linux/mfd/syscon.h>
12 #include <linux/of_device.h>
13 #include <linux/pm_runtime.h>
14 #include <sound/pcm_params.h>
15 #include <sound/soc.h>
16
17 #include "rockchip_multi_dais.h"
18
19 #define BITCLOCK_INV_STR "bitclock-inversion"
20 #define FRAME_INV_STR "frame-inversion"
21 #define BITCLOCK_MASTER_STR "bitclock-master"
22 #define FRAME_MASTER_STR "frame-master"
23 #define DAIS_DRV_NAME "rockchip-mdais"
24 #define RK3308_GRF_SOC_CON2 0x308
25
to_info(struct snd_soc_dai * dai)26 static inline struct rk_mdais_dev *to_info(struct snd_soc_dai *dai)
27 {
28 return snd_soc_dai_get_drvdata(dai);
29 }
30
hw_refine_channels(struct snd_pcm_hw_params * params,unsigned int channel)31 static void hw_refine_channels(struct snd_pcm_hw_params *params,
32 unsigned int channel)
33 {
34 struct snd_interval *c =
35 hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
36
37 c->min = channel;
38 c->max = channel;
39 }
40
rockchip_mdais_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)41 static int rockchip_mdais_hw_params(struct snd_pcm_substream *substream,
42 struct snd_pcm_hw_params *params,
43 struct snd_soc_dai *dai)
44 {
45 struct rk_mdais_dev *mdais = to_info(dai);
46 struct snd_pcm_hw_params *cparams;
47 struct snd_soc_dai *child;
48 unsigned int *channel_maps;
49 int ret = 0, i = 0;
50
51 cparams = kmemdup(params, sizeof(*params), GFP_KERNEL);
52 if (IS_ERR(cparams))
53 return PTR_ERR(cparams);
54
55 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
56 channel_maps = mdais->playback_channel_maps;
57 else
58 channel_maps = mdais->capture_channel_maps;
59
60 for (i = 0; i < mdais->num_dais; i++) {
61 child = mdais->dais[i].dai;
62 if (channel_maps[i])
63 hw_refine_channels(cparams, channel_maps[i]);
64 if (child->driver->ops && child->driver->ops->hw_params) {
65 ret = child->driver->ops->hw_params(substream, cparams, child);
66 if (ret < 0) {
67 dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
68 dai->name, ret);
69 return ret;
70 }
71 }
72 }
73
74 kfree(cparams);
75 return 0;
76 }
77
rockchip_mdais_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)78 static int rockchip_mdais_trigger(struct snd_pcm_substream *substream,
79 int cmd, struct snd_soc_dai *dai)
80 {
81 struct rk_mdais_dev *mdais = to_info(dai);
82 struct snd_soc_dai *child;
83 unsigned int *channel_maps;
84 int ret = 0, i = 0;
85
86 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
87 channel_maps = mdais->playback_channel_maps;
88 else
89 channel_maps = mdais->capture_channel_maps;
90
91 for (i = 0; i < mdais->num_dais; i++) {
92 /* skip DAIs which have no channel mapping */
93 if (!channel_maps[i])
94 continue;
95
96 child = mdais->dais[i].dai;
97 if (child->driver->ops && child->driver->ops->trigger) {
98 ret = child->driver->ops->trigger(substream,
99 cmd, child);
100 if (ret < 0)
101 return ret;
102 }
103 }
104
105 return 0;
106 }
107
rockchip_mdais_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)108 static int rockchip_mdais_startup(struct snd_pcm_substream *substream,
109 struct snd_soc_dai *dai)
110 {
111 struct rk_mdais_dev *mdais = to_info(dai);
112 struct snd_soc_dai *child;
113 int ret = 0, i = 0;
114
115 for (i = 0; i < mdais->num_dais; i++) {
116 child = mdais->dais[i].dai;
117 if (child->driver->ops && child->driver->ops->startup) {
118 ret = child->driver->ops->startup(substream, child);
119 if (ret < 0)
120 return ret;
121 }
122 }
123
124 return 0;
125 }
126
rockchip_mdais_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)127 static void rockchip_mdais_shutdown(struct snd_pcm_substream *substream,
128 struct snd_soc_dai *dai)
129 {
130 struct rk_mdais_dev *mdais = to_info(dai);
131 struct snd_soc_dai *child;
132 int i = 0;
133
134 for (i = 0; i < mdais->num_dais; i++) {
135 child = mdais->dais[i].dai;
136 if (child->driver->ops && child->driver->ops->shutdown) {
137 child->driver->ops->shutdown(substream, child);
138 }
139 }
140 }
141
rockchip_mdais_prepare(struct snd_pcm_substream * substream,struct snd_soc_dai * dai)142 static int rockchip_mdais_prepare(struct snd_pcm_substream *substream,
143 struct snd_soc_dai *dai)
144 {
145 struct rk_mdais_dev *mdais = to_info(dai);
146 struct snd_soc_dai *child;
147 int ret = 0, i = 0;
148
149 for (i = 0; i < mdais->num_dais; i++) {
150 child = mdais->dais[i].dai;
151 if (child->driver->ops && child->driver->ops->prepare) {
152 ret = child->driver->ops->prepare(substream, child);
153 if (ret < 0)
154 return ret;
155 }
156 }
157
158 return 0;
159 }
160
rockchip_mdais_set_sysclk(struct snd_soc_dai * cpu_dai,int clk_id,unsigned int freq,int dir)161 static int rockchip_mdais_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
162 unsigned int freq, int dir)
163 {
164 struct rk_mdais_dev *mdais = to_info(cpu_dai);
165 struct snd_soc_dai *child;
166 int ret, i = 0;
167
168 for (i = 0; i < mdais->num_dais; i++) {
169 child = mdais->dais[i].dai;
170 ret = snd_soc_dai_set_sysclk(child, clk_id, freq, dir);
171 if (ret && ret != -ENOTSUPP)
172 return ret;
173 }
174
175 return 0;
176 }
177
rockchip_mdais_set_fmt(struct snd_soc_dai * cpu_dai,unsigned int fmt)178 static int rockchip_mdais_set_fmt(struct snd_soc_dai *cpu_dai,
179 unsigned int fmt)
180 {
181 struct rk_mdais_dev *mdais = to_info(cpu_dai);
182 struct snd_soc_dai *child;
183 unsigned int dai_fmt;
184 int ret, i = 0;
185
186 for (i = 0; i < mdais->num_dais; i++) {
187 child = mdais->dais[i].dai;
188 dai_fmt = fmt;
189 if (mdais->dais[i].fmt_msk) {
190 dai_fmt &= ~(mdais->dais[i].fmt_msk);
191 dai_fmt |= mdais->dais[i].fmt;
192 }
193 ret = snd_soc_dai_set_fmt(child, dai_fmt);
194 if (ret && ret != -ENOTSUPP)
195 return ret;
196 }
197
198 return 0;
199 }
200
rockchip_mdais_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)201 static int rockchip_mdais_tdm_slot(struct snd_soc_dai *dai,
202 unsigned int tx_mask, unsigned int rx_mask,
203 int slots, int slot_width)
204 {
205 struct rk_mdais_dev *mdais = to_info(dai);
206 struct snd_soc_dai *child;
207 int ret, i = 0;
208
209 for (i = 0; i < mdais->num_dais; i++) {
210 child = mdais->dais[i].dai;
211 ret = snd_soc_dai_set_tdm_slot(child, tx_mask, rx_mask,
212 slots, slot_width);
213 if (ret && ret != -ENOTSUPP)
214 return ret;
215 }
216
217 return 0;
218 }
219
rockchip_mdais_dai_probe(struct snd_soc_dai * dai)220 static int rockchip_mdais_dai_probe(struct snd_soc_dai *dai)
221 {
222 struct rk_mdais_dev *mdais = to_info(dai);
223 struct snd_soc_dai *child;
224 int ret, i = 0;
225
226 for (i = 0; i < mdais->num_dais; i++) {
227 child = mdais->dais[i].dai;
228 if (!child->probed && child->driver->probe) {
229 child->component->card = dai->component->card;
230 ret = child->driver->probe(child);
231 if (ret < 0) {
232 dev_err(child->dev,
233 "ASoC: failed to probe DAI %s: %d\n",
234 child->name, ret);
235 return ret;
236 }
237 dai->probed = 1;
238 }
239 }
240
241 return 0;
242 }
243
244 static const struct snd_soc_dai_ops rockchip_mdais_dai_ops = {
245 .hw_params = rockchip_mdais_hw_params,
246 .set_sysclk = rockchip_mdais_set_sysclk,
247 .set_fmt = rockchip_mdais_set_fmt,
248 .set_tdm_slot = rockchip_mdais_tdm_slot,
249 .trigger = rockchip_mdais_trigger,
250 .startup = rockchip_mdais_startup,
251 .shutdown = rockchip_mdais_shutdown,
252 .prepare = rockchip_mdais_prepare,
253 };
254
255 static const struct snd_soc_component_driver rockchip_mdais_component = {
256 .name = DAIS_DRV_NAME,
257 };
258
259 static const struct of_device_id rockchip_mdais_match[] = {
260 { .compatible = "rockchip,multi-dais", },
261 { .compatible = "rockchip,rk3308-multi-dais", },
262 {},
263 };
264
rockchip_mdais_find_dai(struct device_node * np)265 static struct snd_soc_dai *rockchip_mdais_find_dai(struct device_node *np)
266 {
267 struct snd_soc_dai_link_component dai_component = { 0 };
268
269 dai_component.of_node = np;
270
271 return snd_soc_find_dai_with_mutex(&dai_component);
272 }
273
mdais_runtime_suspend(struct device * dev)274 static int mdais_runtime_suspend(struct device *dev)
275 {
276 struct rk_mdais_dev *mdais = dev_get_drvdata(dev);
277 struct snd_soc_dai *child;
278 int i = 0;
279
280 for (i = 0; i < mdais->num_dais; i++) {
281 child = mdais->dais[i].dai;
282 pm_runtime_put(child->dev);
283 }
284
285 return 0;
286 }
287
mdais_runtime_resume(struct device * dev)288 static int mdais_runtime_resume(struct device *dev)
289 {
290 struct rk_mdais_dev *mdais = dev_get_drvdata(dev);
291 struct snd_soc_dai *child;
292 int i = 0;
293
294 for (i = 0; i < mdais->num_dais; i++) {
295 child = mdais->dais[i].dai;
296 pm_runtime_get_sync(child->dev);
297 }
298
299 return 0;
300 }
301
mdais_read_prop_array(struct device_node * node,const char * propname,unsigned int * array,int num)302 static int mdais_read_prop_array(struct device_node *node,
303 const char *propname,
304 unsigned int *array, int num)
305 {
306 int ret = 0;
307
308 memset(array, 0, sizeof(*array) * num);
309 if (of_property_read_bool(node, propname)) {
310 ret = of_property_read_u32_array(node, propname, array, num);
311 if (ret)
312 ret = -EINVAL;
313 } else {
314 ret = -EINVAL;
315 }
316
317 return ret;
318 }
319
mdais_parse_daifmt(struct device_node * node,struct rk_dai * dais,int num_dai)320 static void mdais_parse_daifmt(struct device_node *node, struct rk_dai *dais,
321 int num_dai)
322 {
323 unsigned int cinv[MAX_DAIS], finv[MAX_DAIS];
324 unsigned int cmst[MAX_DAIS], fmst[MAX_DAIS];
325 unsigned int format = 0, format_mask = 0;
326 int i = 0, ret = 0;
327
328 ret = mdais_read_prop_array(node, BITCLOCK_INV_STR, cinv, num_dai);
329 if (!ret)
330 format_mask |= SND_SOC_DAIFMT_INV_MASK;
331 ret = mdais_read_prop_array(node, FRAME_INV_STR, finv, num_dai);
332 if (!ret)
333 format_mask |= SND_SOC_DAIFMT_INV_MASK;
334 ret = mdais_read_prop_array(node, BITCLOCK_MASTER_STR, cmst, num_dai);
335 if (!ret)
336 format_mask |= SND_SOC_DAIFMT_MASTER_MASK;
337 ret = mdais_read_prop_array(node, FRAME_MASTER_STR, fmst, num_dai);
338 if (!ret)
339 format_mask |= SND_SOC_DAIFMT_MASTER_MASK;
340
341 for (i = 0; i < num_dai; i++) {
342 format = 0;
343
344 switch ((cinv[i] << 4) + finv[i]) {
345 case 0x11:
346 format |= SND_SOC_DAIFMT_IB_IF;
347 break;
348 case 0x10:
349 format |= SND_SOC_DAIFMT_IB_NF;
350 break;
351 case 0x01:
352 format |= SND_SOC_DAIFMT_NB_IF;
353 break;
354 default:
355 /* SND_SOC_DAIFMT_NB_NF is default */
356 break;
357 }
358
359 switch ((!cmst[i] << 4) + !fmst[i]) {
360 case 0x11:
361 format |= SND_SOC_DAIFMT_CBM_CFM;
362 break;
363 case 0x10:
364 format |= SND_SOC_DAIFMT_CBM_CFS;
365 break;
366 case 0x01:
367 format |= SND_SOC_DAIFMT_CBS_CFM;
368 break;
369 default:
370 format |= SND_SOC_DAIFMT_CBS_CFS;
371 break;
372 }
373
374 dais[i].fmt = format & format_mask;
375 dais[i].fmt_msk = format_mask;
376 }
377 }
378
rockchip_mdais_dai_prepare(struct platform_device * pdev,struct snd_soc_dai_driver ** soc_dai)379 static int rockchip_mdais_dai_prepare(struct platform_device *pdev,
380 struct snd_soc_dai_driver **soc_dai)
381 {
382 struct snd_soc_dai_driver rockchip_mdais_dai = {
383 .probe = rockchip_mdais_dai_probe,
384 .playback = {
385 .stream_name = "Playback",
386 .channels_min = 2,
387 .channels_max = 32,
388 .rates = SNDRV_PCM_RATE_8000_192000,
389 .formats = (SNDRV_PCM_FMTBIT_S8 |
390 SNDRV_PCM_FMTBIT_S16_LE |
391 SNDRV_PCM_FMTBIT_S20_3LE |
392 SNDRV_PCM_FMTBIT_S24_LE |
393 SNDRV_PCM_FMTBIT_S32_LE),
394 },
395 .capture = {
396 .stream_name = "Capture",
397 .channels_min = 2,
398 .channels_max = 32,
399 .rates = SNDRV_PCM_RATE_8000_192000,
400 .formats = (SNDRV_PCM_FMTBIT_S8 |
401 SNDRV_PCM_FMTBIT_S16_LE |
402 SNDRV_PCM_FMTBIT_S20_3LE |
403 SNDRV_PCM_FMTBIT_S24_LE |
404 SNDRV_PCM_FMTBIT_S32_LE),
405 },
406 .ops = &rockchip_mdais_dai_ops,
407 };
408
409 *soc_dai = devm_kmemdup(&pdev->dev, &rockchip_mdais_dai,
410 sizeof(rockchip_mdais_dai), GFP_KERNEL);
411 if (!(*soc_dai))
412 return -ENOMEM;
413
414 return 0;
415 }
416
mdais_fixup_dai(struct snd_soc_dai_driver * soc_dai,struct rk_mdais_dev * mdais)417 static void mdais_fixup_dai(struct snd_soc_dai_driver *soc_dai,
418 struct rk_mdais_dev *mdais)
419 {
420 int i, tch, rch;
421 unsigned int *tx_maps, *rx_maps;
422
423 tch = 0;
424 rch = 0;
425 tx_maps = mdais->playback_channel_maps;
426 rx_maps = mdais->capture_channel_maps;
427 for (i = 0; i < mdais->num_dais; i++) {
428 tch += tx_maps[i];
429 rch += rx_maps[i];
430 }
431
432 soc_dai->playback.channels_min = tch;
433 soc_dai->playback.channels_max = tch;
434 soc_dai->capture.channels_min = rch;
435 soc_dai->capture.channels_max = rch;
436 }
437
rockchip_mdais_probe(struct platform_device * pdev)438 static int rockchip_mdais_probe(struct platform_device *pdev)
439 {
440 struct device_node *np = pdev->dev.of_node;
441 struct platform_device *sub_pdev;
442 struct rk_mdais_dev *mdais;
443 struct device_node *node;
444 struct snd_soc_dai_driver *soc_dai;
445 struct rk_dai *dais;
446 unsigned int *map;
447 int count, mp_count;
448 int ret = 0, i = 0;
449
450 ret = rockchip_mdais_dai_prepare(pdev, &soc_dai);
451 if (ret < 0)
452 return ret;
453
454 mdais = devm_kzalloc(&pdev->dev, sizeof(*mdais), GFP_KERNEL);
455 if (!mdais)
456 return -ENOMEM;
457
458 count = of_count_phandle_with_args(np, "dais", NULL);
459 if (count < 0 || count > MAX_DAIS)
460 return -EINVAL;
461
462 mp_count = of_property_count_u32_elems(np, "capture,channel-mapping");
463 if (mp_count != count)
464 return -EINVAL;
465 mp_count = of_property_count_u32_elems(np, "playback,channel-mapping");
466 if (mp_count != count)
467 return -EINVAL;
468
469 mdais->num_dais = count;
470 dais = devm_kcalloc(&pdev->dev, count,
471 sizeof(*dais), GFP_KERNEL);
472 if (!dais)
473 return -ENOMEM;
474
475 map = devm_kcalloc(&pdev->dev, count,
476 sizeof(*map), GFP_KERNEL);
477 if (!map)
478 return -ENOMEM;
479 ret = of_property_read_u32_array(np, "capture,channel-mapping",
480 map, count);
481 if (ret)
482 return -EINVAL;
483 mdais->capture_channel_maps = map;
484 map = devm_kcalloc(&pdev->dev, count,
485 sizeof(*map), GFP_KERNEL);
486 if (!map)
487 return -ENOMEM;
488 ret = of_property_read_u32_array(np, "playback,channel-mapping",
489 map, count);
490 if (ret)
491 return -EINVAL;
492 mdais->playback_channel_maps = map;
493
494 for (i = 0; i < count; i++) {
495 node = of_parse_phandle(np, "dais", i);
496 sub_pdev = of_find_device_by_node(node);
497 if (!sub_pdev) {
498 dev_err(&pdev->dev, "fail to find subnode dev\n");
499 return -ENODEV;
500 }
501 dais[i].of_node = node;
502 dais[i].dev = &sub_pdev->dev;
503 dais[i].dai = rockchip_mdais_find_dai(node);
504 if (!dais[i].dai)
505 return -EPROBE_DEFER;
506 }
507
508 mdais_parse_daifmt(np, dais, count);
509 mdais_fixup_dai(soc_dai, mdais);
510
511 if (of_device_is_compatible(np, "rockchip,rk3308-multi-dais")) {
512 struct regmap *grf;
513 const char *name;
514 unsigned int i2s0_fmt = 0, i2s1_fmt = 0;
515
516 for (i = 0; i < count; i++) {
517 name = dev_name(dais[i].dev);
518 if (strstr(name, "ff300000"))
519 i2s0_fmt = dais[i].fmt;
520 else if (strstr(name, "ff310000"))
521 i2s1_fmt = dais[i].fmt;
522 }
523 i2s0_fmt &= SND_SOC_DAIFMT_MASTER_MASK;
524 i2s1_fmt &= SND_SOC_DAIFMT_MASTER_MASK;
525
526 if ((i2s0_fmt == SND_SOC_DAIFMT_CBS_CFS &&
527 i2s1_fmt == SND_SOC_DAIFMT_CBM_CFM) ||
528 (i2s0_fmt == SND_SOC_DAIFMT_CBM_CFM &&
529 i2s1_fmt == SND_SOC_DAIFMT_CBS_CFS)) {
530 grf = syscon_regmap_lookup_by_phandle(np,
531 "rockchip,grf");
532 if (IS_ERR(grf))
533 return PTR_ERR(grf);
534
535 dev_info(&pdev->dev, "enable i2s 16ch ctrl en\n");
536 regmap_write(grf, RK3308_GRF_SOC_CON2,
537 BIT(14) << 16 | BIT(14));
538 }
539 }
540
541 mdais->dais = dais;
542 mdais->dev = &pdev->dev;
543 dev_set_drvdata(&pdev->dev, mdais);
544
545 pm_runtime_enable(&pdev->dev);
546 if (!pm_runtime_enabled(&pdev->dev)) {
547 ret = mdais_runtime_resume(&pdev->dev);
548 if (ret)
549 goto err_pm_disable;
550 }
551
552 ret = devm_snd_soc_register_component(&pdev->dev,
553 &rockchip_mdais_component,
554 soc_dai, 1);
555
556 if (ret) {
557 dev_err(&pdev->dev, "could not register dai: %d\n", ret);
558 goto err_suspend;
559 }
560
561 ret = snd_dmaengine_mpcm_register(mdais);
562 if (ret) {
563 dev_err(&pdev->dev, "Could not register PCM\n");
564 return ret;
565 }
566
567 return 0;
568
569 err_suspend:
570 if (!pm_runtime_status_suspended(&pdev->dev))
571 mdais_runtime_resume(&pdev->dev);
572 err_pm_disable:
573 pm_runtime_disable(&pdev->dev);
574
575 return ret;
576 }
577
rockchip_mdais_remove(struct platform_device * pdev)578 static int rockchip_mdais_remove(struct platform_device *pdev)
579 {
580 snd_dmaengine_mpcm_unregister(&pdev->dev);
581 pm_runtime_disable(&pdev->dev);
582 if (!pm_runtime_status_suspended(&pdev->dev))
583 mdais_runtime_suspend(&pdev->dev);
584
585 return 0;
586 }
587
588 static const struct dev_pm_ops rockchip_mdais_pm_ops = {
589 SET_RUNTIME_PM_OPS(mdais_runtime_suspend, mdais_runtime_resume,
590 NULL)
591 };
592
593 static struct platform_driver rockchip_mdais_driver = {
594 .probe = rockchip_mdais_probe,
595 .remove = rockchip_mdais_remove,
596 .driver = {
597 .name = DAIS_DRV_NAME,
598 .of_match_table = of_match_ptr(rockchip_mdais_match),
599 .pm = &rockchip_mdais_pm_ops,
600 },
601 };
602 module_platform_driver(rockchip_mdais_driver);
603
604 MODULE_DESCRIPTION("ROCKCHIP MULTI-DAIS ASoC Interface");
605 MODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>");
606 MODULE_LICENSE("GPL v2");
607 MODULE_ALIAS("platform:" DAIS_DRV_NAME);
608 MODULE_DEVICE_TABLE(of, rockchip_mdais_match);
609