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/da7219-aad.h"
25 #include "../codecs/rt5514.h"
26 
27 #define DRV_NAME "rk3399-gru-sound"
28 
29 #define SOUND_FS	256
30 
31 static unsigned int dmic_wakeup_delay;
32 
33 static struct snd_soc_jack rockchip_sound_jack;
34 
35 /* Headset jack detection DAPM pins */
36 static 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 
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),
54 };
55 
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"),
62 };
63 
rockchip_sound_max98357a_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)64 static 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 
rockchip_sound_rt5514_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)83 static 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 	/* Wait for DMIC stable */
110 	msleep(dmic_wakeup_delay);
111 
112 	return 0;
113 }
114 
rockchip_sound_da7219_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)115 static 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 	/* 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;
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 
rockchip_sound_da7219_init(struct snd_soc_pcm_runtime * rtd)167 static 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 	/* 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;
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 	/* 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));
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 
rockchip_sound_dmic_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)215 static 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 	/* Wait for DMIC stable */
232 	msleep(dmic_wakeup_delay);
233 
234 	return 0;
235 }
236 
rockchip_sound_startup(struct snd_pcm_substream * substream)237 static 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 
246 static const struct snd_soc_ops rockchip_sound_max98357a_ops = {
247 	.startup = rockchip_sound_startup,
248 	.hw_params = rockchip_sound_max98357a_hw_params,
249 };
250 
251 static const struct snd_soc_ops rockchip_sound_rt5514_ops = {
252 	.startup = rockchip_sound_startup,
253 	.hw_params = rockchip_sound_rt5514_hw_params,
254 };
255 
256 static const struct snd_soc_ops rockchip_sound_da7219_ops = {
257 	.startup = rockchip_sound_startup,
258 	.hw_params = rockchip_sound_da7219_hw_params,
259 };
260 
261 static const struct snd_soc_ops rockchip_sound_dmic_ops = {
262 	.startup = rockchip_sound_startup,
263 	.hw_params = rockchip_sound_dmic_hw_params,
264 };
265 
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),
273 };
274 
275 enum {
276 	DAILINK_CDNDP,
277 	DAILINK_DA7219,
278 	DAILINK_DMIC,
279 	DAILINK_MAX98357A,
280 	DAILINK_RT5514,
281 	DAILINK_RT5514_DSP,
282 };
283 
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()));
288 
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()));
293 
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()));
298 
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()));
303 
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()));
308 
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()));
313 
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),
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 		/* 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),
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 		/* 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),
348 	},
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),
357 	},
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),
363 	},
364 };
365 
366 static const struct snd_soc_dapm_route rockchip_sound_cdndp_routes[] = {
367 	/* Output */
368 	{"HDMI", NULL, "TX"},
369 };
370 
371 static const struct snd_soc_dapm_route rockchip_sound_da7219_routes[] = {
372 	/* Output */
373 	{"Headphones", NULL, "HPL"},
374 	{"Headphones", NULL, "HPR"},
375 
376 	/* Input */
377 	{"MIC", NULL, "Headset Mic"},
378 };
379 
380 static const struct snd_soc_dapm_route rockchip_sound_dmic_routes[] = {
381 	/* Input */
382 	{"DMic", NULL, "Int Mic"},
383 };
384 
385 static const struct snd_soc_dapm_route rockchip_sound_max98357a_routes[] = {
386 	/* Output */
387 	{"Speakers", NULL, "Speaker"},
388 };
389 
390 static const struct snd_soc_dapm_route rockchip_sound_rt5514_routes[] = {
391 	/* Input */
392 	{"DMIC1L", NULL, "Int Mic"},
393 	{"DMIC1R", NULL, "Int Mic"},
394 };
395 
396 struct rockchip_sound_route {
397 	const struct snd_soc_dapm_route *routes;
398 	int num_routes;
399 };
400 
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),
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 
425 struct dailink_match_data {
426 	const char *compatible;
427 	struct bus_type *bus_type;
428 };
429 
430 static 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 
rockchip_sound_codec_node_match(struct device_node * np_codec)453 static 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 
rockchip_sound_of_parse_dais(struct device * dev,struct snd_soc_card * card)476 static 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 
rockchip_sound_probe(struct platform_device * pdev)559 static 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 	/* 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");
577 	}
578 
579 	card->dev = &pdev->dev;
580 	return devm_snd_soc_register_card(&pdev->dev, card);
581 }
582 
583 static const struct of_device_id rockchip_sound_of_match[] = {
584 	{ .compatible = "rockchip,rk3399-gru-sound", },
585 	{},
586 };
587 
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
596 	},
597 };
598 
599 module_platform_driver(rockchip_sound_driver);
600 
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);
606