1 // SPDX-License-Identifier: GPL-2.0-only
3 * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
5 * Copyright (c) 2016, ROCKCHIP CORPORATION. All rights reserved.
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"
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
[] = {
39 .mask
= SND_JACK_HEADPHONE
,
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
);
71 mclk
= params_rate(params
) * SOUND_FS
;
73 ret
= snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd
, 0), 0, mclk
, 0);
75 dev_err(rtd
->card
->dev
, "%s() error setting sysclk to %u: %d\n",
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);
92 mclk
= params_rate(params
) * SOUND_FS
;
94 ret
= snd_soc_dai_set_sysclk(cpu_dai
, 0, mclk
,
97 dev_err(rtd
->card
->dev
, "Can't set cpu clock out %d\n", ret
);
101 ret
= snd_soc_dai_set_sysclk(codec_dai
, RT5514_SCLK_S_MCLK
,
102 mclk
, SND_SOC_CLOCK_IN
);
104 dev_err(rtd
->card
->dev
, "%s() error setting sysclk to %u: %d\n",
105 __func__
, params_rate(params
) * 512, ret
);
109 /* Wait for DMIC stable */
110 msleep(dmic_wakeup_delay
);
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);
123 /* in bypass mode, the mclk has to be one of the frequencies below */
124 switch (params_rate(params
)) {
144 ret
= snd_soc_dai_set_sysclk(cpu_dai
, 0, mclk
,
147 dev_err(codec_dai
->dev
, "Can't set cpu clock out %d\n", ret
);
151 ret
= snd_soc_dai_set_sysclk(codec_dai
, 0, mclk
,
154 dev_err(codec_dai
->dev
, "Can't set codec clock in %d\n", ret
);
158 ret
= snd_soc_dai_set_pll(codec_dai
, 0, DA7219_SYSCLK_MCLK
, 0, 0);
160 dev_err(codec_dai
->dev
, "Can't set pll sysclk mclk %d\n", ret
);
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);
173 /* We need default MCLK and PLL settings for the accessory detection */
174 ret
= snd_soc_dai_set_sysclk(codec_dai
, 0, 12288000,
177 dev_err(codec_dai
->dev
, "Init can't set codec clock in %d\n", ret
);
181 ret
= snd_soc_dai_set_pll(codec_dai
, 0, DA7219_SYSCLK_MCLK
, 0, 0);
183 dev_err(codec_dai
->dev
, "Init can't set pll sysclk mclk %d\n", 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
));
197 dev_err(rtd
->card
->dev
, "New Headset Jack failed! (%d)\n", ret
);
202 rockchip_sound_jack
.jack
, SND_JACK_BTN_0
, KEY_PLAYPAUSE
);
204 rockchip_sound_jack
.jack
, SND_JACK_BTN_1
, KEY_VOLUMEUP
);
206 rockchip_sound_jack
.jack
, SND_JACK_BTN_2
, KEY_VOLUMEDOWN
);
208 rockchip_sound_jack
.jack
, SND_JACK_BTN_3
, KEY_VOICECOMMAND
);
210 da7219_aad_jack_det(component
, &rockchip_sound_jack
);
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
);
222 mclk
= params_rate(params
) * SOUND_FS
;
224 ret
= snd_soc_dai_set_sysclk(asoc_rtd_to_cpu(rtd
, 0), 0, mclk
, 0);
226 dev_err(rtd
->card
->dev
, "%s() error setting sysclk to %u: %d\n",
227 __func__
, mclk
, ret
);
231 /* Wait for DMIC stable */
232 msleep(dmic_wakeup_delay
);
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
,
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
),
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
[] = {
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
),
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
),
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
] = {
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
),
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
[] = {
368 {"HDMI", NULL
, "TX"},
371 static const struct snd_soc_dapm_route rockchip_sound_da7219_routes
[] = {
373 {"Headphones", NULL
, "HPL"},
374 {"Headphones", NULL
, "HPR"},
377 {"MIC", NULL
, "Headset Mic"},
380 static const struct snd_soc_dapm_route rockchip_sound_dmic_routes
[] = {
382 {"DMic", NULL
, "Int Mic"},
385 static const struct snd_soc_dapm_route rockchip_sound_max98357a_routes
[] = {
387 {"Speakers", NULL
, "Speaker"},
390 static const struct snd_soc_dapm_route rockchip_sound_rt5514_routes
[] = {
392 {"DMIC1L", NULL
, "Int Mic"},
393 {"DMIC1R", NULL
, "Int Mic"},
396 struct rockchip_sound_route
{
397 const struct snd_soc_dapm_route
*routes
;
401 static const struct rockchip_sound_route rockchip_routes
[] = {
403 .routes
= rockchip_sound_cdndp_routes
,
404 .num_routes
= ARRAY_SIZE(rockchip_sound_cdndp_routes
),
407 .routes
= rockchip_sound_da7219_routes
,
408 .num_routes
= ARRAY_SIZE(rockchip_sound_da7219_routes
),
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
),
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
[] = {
432 .compatible
= "rockchip,rk3399-cdn-dp",
435 .compatible
= "dlg,da7219",
438 .compatible
= "dmic-codec",
440 [DAILINK_MAX98357A
] = {
441 .compatible
= "maxim,max98357a",
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
)
458 for (i
= 0; i
< ARRAY_SIZE(dailink_match
); i
++) {
459 if (!of_device_is_compatible(np_codec
,
460 dailink_match
[i
].compatible
))
463 if (dailink_match
[i
].bus_type
) {
464 dev
= bus_find_device_by_of_node(dailink_match
[i
].bus_type
,
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
;
486 card
->dai_link
= devm_kzalloc(dev
, sizeof(rockchip_dais
),
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
),
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;
505 for (i
= 0; i
< ARRAY_SIZE(rockchip_dais
); i
++) {
506 np_codec
= of_parse_phandle(dev
->of_node
,
507 "rockchip,codec", i
);
511 if (!of_device_is_available(np_codec
))
514 index
= rockchip_sound_codec_node_match(np_codec
);
522 case DAILINK_RT5514_DSP
:
531 dev_err(dev
, "Missing 'rockchip,cpu' for %s\n",
532 rockchip_dais
[index
].name
);
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
>
546 dev_err(dev
, "Too many routes\n");
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
;
559 static int rockchip_sound_probe(struct platform_device
*pdev
)
561 struct snd_soc_card
*card
= &rockchip_sound_card
;
564 ret
= rockchip_sound_of_parse_dais(&pdev
->dev
, card
);
566 dev_err(&pdev
->dev
, "Failed to parse dais: %d\n", ret
);
570 /* Set DMIC wakeup delay */
571 ret
= device_property_read_u32(&pdev
->dev
, "dmic-wakeup-delay-ms",
574 dmic_wakeup_delay
= 0;
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
,
592 .of_match_table
= rockchip_sound_of_match
,
594 .pm
= &snd_soc_pm_ops
,
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
);