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