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