1
2
3
4
5
6
7
8#include <linux/module.h>
9#include <linux/platform_device.h>
10#include <linux/slab.h>
11#include <linux/gpio.h>
12#include <linux/of_gpio.h>
13#include <linux/delay.h>
14#include <linux/spi/spi.h>
15#include <linux/i2c.h>
16#include <linux/input.h>
17#include <sound/core.h>
18#include <sound/jack.h>
19#include <sound/pcm.h>
20#include <sound/pcm_params.h>
21#include <sound/soc.h>
22#include "rockchip_i2s.h"
23#include "../codecs/da7219.h"
24#include "../codecs/da7219-aad.h"
25#include "../codecs/rt5514.h"
26
27#define DRV_NAME "rk3399-gru-sound"
28
29#define SOUND_FS 256
30
31static unsigned int dmic_wakeup_delay;
32
33static struct snd_soc_jack rockchip_sound_jack;
34
35
36static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = {
37 {
38 .pin = "Headphones",
39 .mask = SND_JACK_HEADPHONE,
40 },
41 {
42 .pin = "Headset Mic",
43 .mask = SND_JACK_MICROPHONE,
44 },
45
46};
47
48static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
49 SND_SOC_DAPM_HP("Headphones", NULL),
50 SND_SOC_DAPM_SPK("Speakers", NULL),
51 SND_SOC_DAPM_MIC("Headset Mic", NULL),
52 SND_SOC_DAPM_MIC("Int Mic", NULL),
53 SND_SOC_DAPM_LINE("HDMI", NULL),
54};
55
56static const struct snd_kcontrol_new rockchip_controls[] = {
57 SOC_DAPM_PIN_SWITCH("Headphones"),
58 SOC_DAPM_PIN_SWITCH("Speakers"),
59 SOC_DAPM_PIN_SWITCH("Headset Mic"),
60 SOC_DAPM_PIN_SWITCH("Int Mic"),
61 SOC_DAPM_PIN_SWITCH("HDMI"),
62};
63
64static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
65 struct snd_pcm_hw_params *params)
66{
67 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
68 unsigned int mclk;
69 int ret;
70
71 mclk = params_rate(params) * SOUND_FS;
72
73 ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, 0);
74 if (ret) {
75 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
76 __func__, mclk, ret);
77 return ret;
78 }
79
80 return 0;
81}
82
83static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
84 struct snd_pcm_hw_params *params)
85{
86 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
87 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
88 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
89 unsigned int mclk;
90 int ret;
91
92 mclk = params_rate(params) * SOUND_FS;
93
94 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
95 SND_SOC_CLOCK_OUT);
96 if (ret < 0) {
97 dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
98 return ret;
99 }
100
101 ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
102 mclk, SND_SOC_CLOCK_IN);
103 if (ret) {
104 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
105 __func__, params_rate(params) * 512, ret);
106 return ret;
107 }
108
109
110 msleep(dmic_wakeup_delay);
111
112 return 0;
113}
114
115static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
116 struct snd_pcm_hw_params *params)
117{
118 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
119 struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
120 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
121 int mclk, ret;
122
123
124 switch (params_rate(params)) {
125 case 8000:
126 case 16000:
127 case 24000:
128 case 32000:
129 case 48000:
130 case 64000:
131 case 96000:
132 mclk = 12288000;
133 break;
134 case 11025:
135 case 22050:
136 case 44100:
137 case 88200:
138 mclk = 11289600;
139 break;
140 default:
141 return -EINVAL;
142 }
143
144 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
145 SND_SOC_CLOCK_OUT);
146 if (ret < 0) {
147 dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
148 return ret;
149 }
150
151 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
152 SND_SOC_CLOCK_IN);
153 if (ret < 0) {
154 dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
155 return ret;
156 }
157
158 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
159 if (ret < 0) {
160 dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
161 return ret;
162 }
163
164 return 0;
165}
166
167static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
168{
169 struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component;
170 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
171 int ret;
172
173
174 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 12288000,
175 SND_SOC_CLOCK_IN);
176 if (ret < 0) {
177 dev_err(codec_dai->dev, "Init can't set codec clock in %d\n", ret);
178 return ret;
179 }
180
181 ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
182 if (ret < 0) {
183 dev_err(codec_dai->dev, "Init can't set pll sysclk mclk %d\n", ret);
184 return ret;
185 }
186
187
188 ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
189 SND_JACK_HEADSET | SND_JACK_LINEOUT |
190 SND_JACK_BTN_0 | SND_JACK_BTN_1 |
191 SND_JACK_BTN_2 | SND_JACK_BTN_3,
192 &rockchip_sound_jack,
193 rockchip_sound_jack_pins,
194 ARRAY_SIZE(rockchip_sound_jack_pins));
195
196 if (ret) {
197 dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
198 return ret;
199 }
200
201 snd_jack_set_key(
202 rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
203 snd_jack_set_key(
204 rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
205 snd_jack_set_key(
206 rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
207 snd_jack_set_key(
208 rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
209
210 da7219_aad_jack_det(component, &rockchip_sound_jack);
211
212 return 0;
213}
214
215static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,
216 struct snd_pcm_hw_params *params)
217{
218 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
219 unsigned int mclk;
220 int ret;
221
222 mclk = params_rate(params) * SOUND_FS;
223
224 ret = snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd, 0), 0, mclk, 0);
225 if (ret) {
226 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
227 __func__, mclk, ret);
228 return ret;
229 }
230
231
232 msleep(dmic_wakeup_delay);
233
234 return 0;
235}
236
237static int rockchip_sound_startup(struct snd_pcm_substream *substream)
238{
239 struct snd_pcm_runtime *runtime = substream->runtime;
240
241 runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE;
242 return snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
243 8000, 96000);
244}
245
246static const struct snd_soc_ops rockchip_sound_max98357a_ops = {
247 .startup = rockchip_sound_startup,
248 .hw_params = rockchip_sound_max98357a_hw_params,
249};
250
251static const struct snd_soc_ops rockchip_sound_rt5514_ops = {
252 .startup = rockchip_sound_startup,
253 .hw_params = rockchip_sound_rt5514_hw_params,
254};
255
256static const struct snd_soc_ops rockchip_sound_da7219_ops = {
257 .startup = rockchip_sound_startup,
258 .hw_params = rockchip_sound_da7219_hw_params,
259};
260
261static const struct snd_soc_ops rockchip_sound_dmic_ops = {
262 .startup = rockchip_sound_startup,
263 .hw_params = rockchip_sound_dmic_hw_params,
264};
265
266static struct snd_soc_card rockchip_sound_card = {
267 .name = "rk3399-gru-sound",
268 .owner = THIS_MODULE,
269 .dapm_widgets = rockchip_dapm_widgets,
270 .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
271 .controls = rockchip_controls,
272 .num_controls = ARRAY_SIZE(rockchip_controls),
273};
274
275enum {
276 DAILINK_CDNDP,
277 DAILINK_DA7219,
278 DAILINK_DMIC,
279 DAILINK_MAX98357A,
280 DAILINK_RT5514,
281 DAILINK_RT5514_DSP,
282};
283
284SND_SOC_DAILINK_DEFS(cdndp,
285 DAILINK_COMP_ARRAY(COMP_EMPTY()),
286 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "spdif-hifi")),
287 DAILINK_COMP_ARRAY(COMP_EMPTY()));
288
289SND_SOC_DAILINK_DEFS(da7219,
290 DAILINK_COMP_ARRAY(COMP_EMPTY()),
291 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "da7219-hifi")),
292 DAILINK_COMP_ARRAY(COMP_EMPTY()));
293
294SND_SOC_DAILINK_DEFS(dmic,
295 DAILINK_COMP_ARRAY(COMP_EMPTY()),
296 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "dmic-hifi")),
297 DAILINK_COMP_ARRAY(COMP_EMPTY()));
298
299SND_SOC_DAILINK_DEFS(max98357a,
300 DAILINK_COMP_ARRAY(COMP_EMPTY()),
301 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
302 DAILINK_COMP_ARRAY(COMP_EMPTY()));
303
304SND_SOC_DAILINK_DEFS(rt5514,
305 DAILINK_COMP_ARRAY(COMP_EMPTY()),
306 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "rt5514-aif1")),
307 DAILINK_COMP_ARRAY(COMP_EMPTY()));
308
309SND_SOC_DAILINK_DEFS(rt5514_dsp,
310 DAILINK_COMP_ARRAY(COMP_EMPTY()),
311 DAILINK_COMP_ARRAY(COMP_DUMMY()),
312 DAILINK_COMP_ARRAY(COMP_EMPTY()));
313
314static const struct snd_soc_dai_link rockchip_dais[] = {
315 [DAILINK_CDNDP] = {
316 .name = "DP",
317 .stream_name = "DP PCM",
318 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
319 SND_SOC_DAIFMT_CBS_CFS,
320 SND_SOC_DAILINK_REG(cdndp),
321 },
322 [DAILINK_DA7219] = {
323 .name = "DA7219",
324 .stream_name = "DA7219 PCM",
325 .init = rockchip_sound_da7219_init,
326 .ops = &rockchip_sound_da7219_ops,
327
328 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
329 SND_SOC_DAIFMT_CBS_CFS,
330 SND_SOC_DAILINK_REG(da7219),
331 },
332 [DAILINK_DMIC] = {
333 .name = "DMIC",
334 .stream_name = "DMIC PCM",
335 .ops = &rockchip_sound_dmic_ops,
336 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
337 SND_SOC_DAIFMT_CBS_CFS,
338 SND_SOC_DAILINK_REG(dmic),
339 },
340 [DAILINK_MAX98357A] = {
341 .name = "MAX98357A",
342 .stream_name = "MAX98357A PCM",
343 .ops = &rockchip_sound_max98357a_ops,
344
345 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
346 SND_SOC_DAIFMT_CBS_CFS,
347 SND_SOC_DAILINK_REG(max98357a),
348 },
349 [DAILINK_RT5514] = {
350 .name = "RT5514",
351 .stream_name = "RT5514 PCM",
352 .ops = &rockchip_sound_rt5514_ops,
353
354 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
355 SND_SOC_DAIFMT_CBS_CFS,
356 SND_SOC_DAILINK_REG(rt5514),
357 },
358
359 [DAILINK_RT5514_DSP] = {
360 .name = "RT5514 DSP",
361 .stream_name = "Wake on Voice",
362 SND_SOC_DAILINK_REG(rt5514_dsp),
363 },
364};
365
366static const struct snd_soc_dapm_route rockchip_sound_cdndp_routes[] = {
367
368 {"HDMI", NULL, "TX"},
369};
370
371static const struct snd_soc_dapm_route rockchip_sound_da7219_routes[] = {
372
373 {"Headphones", NULL, "HPL"},
374 {"Headphones", NULL, "HPR"},
375
376
377 {"MIC", NULL, "Headset Mic"},
378};
379
380static const struct snd_soc_dapm_route rockchip_sound_dmic_routes[] = {
381
382 {"DMic", NULL, "Int Mic"},
383};
384
385static const struct snd_soc_dapm_route rockchip_sound_max98357a_routes[] = {
386
387 {"Speakers", NULL, "Speaker"},
388};
389
390static const struct snd_soc_dapm_route rockchip_sound_rt5514_routes[] = {
391
392 {"DMIC1L", NULL, "Int Mic"},
393 {"DMIC1R", NULL, "Int Mic"},
394};
395
396struct rockchip_sound_route {
397 const struct snd_soc_dapm_route *routes;
398 int num_routes;
399};
400
401static const struct rockchip_sound_route rockchip_routes[] = {
402 [DAILINK_CDNDP] = {
403 .routes = rockchip_sound_cdndp_routes,
404 .num_routes = ARRAY_SIZE(rockchip_sound_cdndp_routes),
405 },
406 [DAILINK_DA7219] = {
407 .routes = rockchip_sound_da7219_routes,
408 .num_routes = ARRAY_SIZE(rockchip_sound_da7219_routes),
409 },
410 [DAILINK_DMIC] = {
411 .routes = rockchip_sound_dmic_routes,
412 .num_routes = ARRAY_SIZE(rockchip_sound_dmic_routes),
413 },
414 [DAILINK_MAX98357A] = {
415 .routes = rockchip_sound_max98357a_routes,
416 .num_routes = ARRAY_SIZE(rockchip_sound_max98357a_routes),
417 },
418 [DAILINK_RT5514] = {
419 .routes = rockchip_sound_rt5514_routes,
420 .num_routes = ARRAY_SIZE(rockchip_sound_rt5514_routes),
421 },
422 [DAILINK_RT5514_DSP] = {},
423};
424
425struct dailink_match_data {
426 const char *compatible;
427 struct bus_type *bus_type;
428};
429
430static const struct dailink_match_data dailink_match[] = {
431 [DAILINK_CDNDP] = {
432 .compatible = "rockchip,rk3399-cdn-dp",
433 },
434 [DAILINK_DA7219] = {
435 .compatible = "dlg,da7219",
436 },
437 [DAILINK_DMIC] = {
438 .compatible = "dmic-codec",
439 },
440 [DAILINK_MAX98357A] = {
441 .compatible = "maxim,max98357a",
442 },
443 [DAILINK_RT5514] = {
444 .compatible = "realtek,rt5514",
445 .bus_type = &i2c_bus_type,
446 },
447 [DAILINK_RT5514_DSP] = {
448 .compatible = "realtek,rt5514",
449 .bus_type = &spi_bus_type,
450 },
451};
452
453static int rockchip_sound_codec_node_match(struct device_node *np_codec)
454{
455 struct device *dev;
456 int i;
457
458 for (i = 0; i < ARRAY_SIZE(dailink_match); i++) {
459 if (!of_device_is_compatible(np_codec,
460 dailink_match[i].compatible))
461 continue;
462
463 if (dailink_match[i].bus_type) {
464 dev = bus_find_device_by_of_node(dailink_match[i].bus_type,
465 np_codec);
466 if (!dev)
467 continue;
468 put_device(dev);
469 }
470
471 return i;
472 }
473 return -1;
474}
475
476static int rockchip_sound_of_parse_dais(struct device *dev,
477 struct snd_soc_card *card)
478{
479 struct device_node *np_cpu, *np_cpu0, *np_cpu1;
480 struct device_node *np_codec;
481 struct snd_soc_dai_link *dai;
482 struct snd_soc_dapm_route *routes;
483 int i, index;
484 int num_routes;
485
486 card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
487 GFP_KERNEL);
488 if (!card->dai_link)
489 return -ENOMEM;
490
491 num_routes = 0;
492 for (i = 0; i < ARRAY_SIZE(rockchip_routes); i++)
493 num_routes += rockchip_routes[i].num_routes;
494 routes = devm_kcalloc(dev, num_routes, sizeof(*routes),
495 GFP_KERNEL);
496 if (!routes)
497 return -ENOMEM;
498 card->dapm_routes = routes;
499
500 np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);
501 np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);
502
503 card->num_dapm_routes = 0;
504 card->num_links = 0;
505 for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {
506 np_codec = of_parse_phandle(dev->of_node,
507 "rockchip,codec", i);
508 if (!np_codec)
509 break;
510
511 if (!of_device_is_available(np_codec))
512 continue;
513
514 index = rockchip_sound_codec_node_match(np_codec);
515 if (index < 0)
516 continue;
517
518 switch (index) {
519 case DAILINK_CDNDP:
520 np_cpu = np_cpu1;
521 break;
522 case DAILINK_RT5514_DSP:
523 np_cpu = np_codec;
524 break;
525 default:
526 np_cpu = np_cpu0;
527 break;
528 }
529
530 if (!np_cpu) {
531 dev_err(dev, "Missing 'rockchip,cpu' for %s\n",
532 rockchip_dais[index].name);
533 return -EINVAL;
534 }
535
536 dai = &card->dai_link[card->num_links++];
537 *dai = rockchip_dais[index];
538
539 if (!dai->codecs->name)
540 dai->codecs->of_node = np_codec;
541 dai->platforms->of_node = np_cpu;
542 dai->cpus->of_node = np_cpu;
543
544 if (card->num_dapm_routes + rockchip_routes[index].num_routes >
545 num_routes) {
546 dev_err(dev, "Too many routes\n");
547 return -EINVAL;
548 }
549
550 memcpy(routes + card->num_dapm_routes,
551 rockchip_routes[index].routes,
552 rockchip_routes[index].num_routes * sizeof(*routes));
553 card->num_dapm_routes += rockchip_routes[index].num_routes;
554 }
555
556 return 0;
557}
558
559static int rockchip_sound_probe(struct platform_device *pdev)
560{
561 struct snd_soc_card *card = &rockchip_sound_card;
562 int ret;
563
564 ret = rockchip_sound_of_parse_dais(&pdev->dev, card);
565 if (ret < 0) {
566 dev_err(&pdev->dev, "Failed to parse dais: %d\n", ret);
567 return ret;
568 }
569
570
571 ret = device_property_read_u32(&pdev->dev, "dmic-wakeup-delay-ms",
572 &dmic_wakeup_delay);
573 if (ret) {
574 dmic_wakeup_delay = 0;
575 dev_dbg(&pdev->dev,
576 "no optional property 'dmic-wakeup-delay-ms' found, default: no delay\n");
577 }
578
579 card->dev = &pdev->dev;
580 return devm_snd_soc_register_card(&pdev->dev, card);
581}
582
583static const struct of_device_id rockchip_sound_of_match[] = {
584 { .compatible = "rockchip,rk3399-gru-sound", },
585 {},
586};
587
588static struct platform_driver rockchip_sound_driver = {
589 .probe = rockchip_sound_probe,
590 .driver = {
591 .name = DRV_NAME,
592 .of_match_table = rockchip_sound_of_match,
593#ifdef CONFIG_PM
594 .pm = &snd_soc_pm_ops,
595#endif
596 },
597};
598
599module_platform_driver(rockchip_sound_driver);
600
601MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
602MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
603MODULE_LICENSE("GPL v2");
604MODULE_ALIAS("platform:" DRV_NAME);
605MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);
606