xref: /openbmc/linux/sound/soc/rockchip/rk3399_gru_sound.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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