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