WIP FPC-III support
[linux/fpc-iii.git] / sound / soc / rockchip / rk3399_gru_sound.c
blobe2d52d8d0ff99f68976b4317a13192510a598974
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
5 * Copyright (c) 2016, ROCKCHIP CORPORATION. All rights reserved.
6 */
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"
27 #define DRV_NAME "rk3399-gru-sound"
29 #define SOUND_FS 256
31 static unsigned int dmic_wakeup_delay;
33 static struct snd_soc_jack rockchip_sound_jack;
35 /* Headset jack detection DAPM pins */
36 static struct snd_soc_jack_pin rockchip_sound_jack_pins[] = {
38 .pin = "Headphones",
39 .mask = SND_JACK_HEADPHONE,
42 .pin = "Headset Mic",
43 .mask = SND_JACK_MICROPHONE,
48 static 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),
56 static 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"),
64 static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
65 struct snd_pcm_hw_params *params)
67 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
68 unsigned int mclk;
69 int ret;
71 mclk = params_rate(params) * SOUND_FS;
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;
80 return 0;
83 static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
84 struct snd_pcm_hw_params *params)
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;
92 mclk = params_rate(params) * SOUND_FS;
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;
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;
109 /* Wait for DMIC stable */
110 msleep(dmic_wakeup_delay);
112 return 0;
115 static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
116 struct snd_pcm_hw_params *params)
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;
123 /* in bypass mode, the mclk has to be one of the frequencies below */
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;
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;
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;
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;
164 return 0;
167 static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
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;
173 /* We need default MCLK and PLL settings for the accessory detection */
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;
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;
187 /* Enable Headset and 4 Buttons Jack detection */
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));
196 if (ret) {
197 dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
198 return ret;
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);
210 da7219_aad_jack_det(component, &rockchip_sound_jack);
212 return 0;
215 static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,
216 struct snd_pcm_hw_params *params)
218 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
219 unsigned int mclk;
220 int ret;
222 mclk = params_rate(params) * SOUND_FS;
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;
231 /* Wait for DMIC stable */
232 msleep(dmic_wakeup_delay);
234 return 0;
237 static int rockchip_sound_startup(struct snd_pcm_substream *substream)
239 struct snd_pcm_runtime *runtime = substream->runtime;
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);
246 static const struct snd_soc_ops rockchip_sound_max98357a_ops = {
247 .startup = rockchip_sound_startup,
248 .hw_params = rockchip_sound_max98357a_hw_params,
251 static const struct snd_soc_ops rockchip_sound_rt5514_ops = {
252 .startup = rockchip_sound_startup,
253 .hw_params = rockchip_sound_rt5514_hw_params,
256 static const struct snd_soc_ops rockchip_sound_da7219_ops = {
257 .startup = rockchip_sound_startup,
258 .hw_params = rockchip_sound_da7219_hw_params,
261 static const struct snd_soc_ops rockchip_sound_dmic_ops = {
262 .startup = rockchip_sound_startup,
263 .hw_params = rockchip_sound_dmic_hw_params,
266 static 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),
275 enum {
276 DAILINK_CDNDP,
277 DAILINK_DA7219,
278 DAILINK_DMIC,
279 DAILINK_MAX98357A,
280 DAILINK_RT5514,
281 DAILINK_RT5514_DSP,
284 SND_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()));
289 SND_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()));
294 SND_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()));
299 SND_SOC_DAILINK_DEFS(max98357a,
300 DAILINK_COMP_ARRAY(COMP_EMPTY()),
301 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
302 DAILINK_COMP_ARRAY(COMP_EMPTY()));
304 SND_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()));
309 SND_SOC_DAILINK_DEFS(rt5514_dsp,
310 DAILINK_COMP_ARRAY(COMP_EMPTY()),
311 DAILINK_COMP_ARRAY(COMP_DUMMY()),
312 DAILINK_COMP_ARRAY(COMP_EMPTY()));
314 static 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),
322 [DAILINK_DA7219] = {
323 .name = "DA7219",
324 .stream_name = "DA7219 PCM",
325 .init = rockchip_sound_da7219_init,
326 .ops = &rockchip_sound_da7219_ops,
327 /* set da7219 as slave */
328 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
329 SND_SOC_DAIFMT_CBS_CFS,
330 SND_SOC_DAILINK_REG(da7219),
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),
340 [DAILINK_MAX98357A] = {
341 .name = "MAX98357A",
342 .stream_name = "MAX98357A PCM",
343 .ops = &rockchip_sound_max98357a_ops,
344 /* set max98357a as slave */
345 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
346 SND_SOC_DAIFMT_CBS_CFS,
347 SND_SOC_DAILINK_REG(max98357a),
349 [DAILINK_RT5514] = {
350 .name = "RT5514",
351 .stream_name = "RT5514 PCM",
352 .ops = &rockchip_sound_rt5514_ops,
353 /* set rt5514 as slave */
354 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
355 SND_SOC_DAIFMT_CBS_CFS,
356 SND_SOC_DAILINK_REG(rt5514),
358 /* RT5514 DSP for voice wakeup via spi bus */
359 [DAILINK_RT5514_DSP] = {
360 .name = "RT5514 DSP",
361 .stream_name = "Wake on Voice",
362 SND_SOC_DAILINK_REG(rt5514_dsp),
366 static const struct snd_soc_dapm_route rockchip_sound_cdndp_routes[] = {
367 /* Output */
368 {"HDMI", NULL, "TX"},
371 static const struct snd_soc_dapm_route rockchip_sound_da7219_routes[] = {
372 /* Output */
373 {"Headphones", NULL, "HPL"},
374 {"Headphones", NULL, "HPR"},
376 /* Input */
377 {"MIC", NULL, "Headset Mic"},
380 static const struct snd_soc_dapm_route rockchip_sound_dmic_routes[] = {
381 /* Input */
382 {"DMic", NULL, "Int Mic"},
385 static const struct snd_soc_dapm_route rockchip_sound_max98357a_routes[] = {
386 /* Output */
387 {"Speakers", NULL, "Speaker"},
390 static const struct snd_soc_dapm_route rockchip_sound_rt5514_routes[] = {
391 /* Input */
392 {"DMIC1L", NULL, "Int Mic"},
393 {"DMIC1R", NULL, "Int Mic"},
396 struct rockchip_sound_route {
397 const struct snd_soc_dapm_route *routes;
398 int num_routes;
401 static 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),
406 [DAILINK_DA7219] = {
407 .routes = rockchip_sound_da7219_routes,
408 .num_routes = ARRAY_SIZE(rockchip_sound_da7219_routes),
410 [DAILINK_DMIC] = {
411 .routes = rockchip_sound_dmic_routes,
412 .num_routes = ARRAY_SIZE(rockchip_sound_dmic_routes),
414 [DAILINK_MAX98357A] = {
415 .routes = rockchip_sound_max98357a_routes,
416 .num_routes = ARRAY_SIZE(rockchip_sound_max98357a_routes),
418 [DAILINK_RT5514] = {
419 .routes = rockchip_sound_rt5514_routes,
420 .num_routes = ARRAY_SIZE(rockchip_sound_rt5514_routes),
422 [DAILINK_RT5514_DSP] = {},
425 struct dailink_match_data {
426 const char *compatible;
427 struct bus_type *bus_type;
430 static const struct dailink_match_data dailink_match[] = {
431 [DAILINK_CDNDP] = {
432 .compatible = "rockchip,rk3399-cdn-dp",
434 [DAILINK_DA7219] = {
435 .compatible = "dlg,da7219",
437 [DAILINK_DMIC] = {
438 .compatible = "dmic-codec",
440 [DAILINK_MAX98357A] = {
441 .compatible = "maxim,max98357a",
443 [DAILINK_RT5514] = {
444 .compatible = "realtek,rt5514",
445 .bus_type = &i2c_bus_type,
447 [DAILINK_RT5514_DSP] = {
448 .compatible = "realtek,rt5514",
449 .bus_type = &spi_bus_type,
453 static int rockchip_sound_codec_node_match(struct device_node *np_codec)
455 struct device *dev;
456 int i;
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;
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);
471 return i;
473 return -1;
476 static int rockchip_sound_of_parse_dais(struct device *dev,
477 struct snd_soc_card *card)
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;
486 card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
487 GFP_KERNEL);
488 if (!card->dai_link)
489 return -ENOMEM;
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;
500 np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);
501 np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);
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;
511 if (!of_device_is_available(np_codec))
512 continue;
514 index = rockchip_sound_codec_node_match(np_codec);
515 if (index < 0)
516 continue;
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;
530 if (!np_cpu) {
531 dev_err(dev, "Missing 'rockchip,cpu' for %s\n",
532 rockchip_dais[index].name);
533 return -EINVAL;
536 dai = &card->dai_link[card->num_links++];
537 *dai = rockchip_dais[index];
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;
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;
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;
556 return 0;
559 static int rockchip_sound_probe(struct platform_device *pdev)
561 struct snd_soc_card *card = &rockchip_sound_card;
562 int ret;
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;
570 /* Set DMIC wakeup delay */
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");
579 card->dev = &pdev->dev;
580 return devm_snd_soc_register_card(&pdev->dev, card);
583 static const struct of_device_id rockchip_sound_of_match[] = {
584 { .compatible = "rockchip,rk3399-gru-sound", },
588 static 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
599 module_platform_driver(rockchip_sound_driver);
601 MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
602 MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
603 MODULE_LICENSE("GPL v2");
604 MODULE_ALIAS("platform:" DRV_NAME);
605 MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);