]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blob - sound/soc/rockchip/rk3399_gru_sound.c
Merge tag 'v4.14-rc1' into asoc-rockchip
[mirror_ubuntu-bionic-kernel.git] / sound / soc / rockchip / rk3399_gru_sound.c
1 /*
2 * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
3 *
4 * Copyright (c) 2016, ROCKCHIP CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/slab.h>
22 #include <linux/gpio.h>
23 #include <linux/of_gpio.h>
24 #include <linux/delay.h>
25 #include <linux/spi/spi.h>
26 #include <linux/input.h>
27 #include <sound/core.h>
28 #include <sound/jack.h>
29 #include <sound/pcm.h>
30 #include <sound/pcm_params.h>
31 #include <sound/soc.h>
32 #include "rockchip_i2s.h"
33 #include "../codecs/da7219.h"
34 #include "../codecs/da7219-aad.h"
35 #include "../codecs/rt5514.h"
36
37 #define DRV_NAME "rk3399-gru-sound"
38
39 #define SOUND_FS 256
40
41 static unsigned int dmic_wakeup_delay;
42
43 static struct snd_soc_jack rockchip_sound_jack;
44
45 static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
46 SND_SOC_DAPM_HP("Headphones", NULL),
47 SND_SOC_DAPM_SPK("Speakers", NULL),
48 SND_SOC_DAPM_MIC("Headset Mic", NULL),
49 SND_SOC_DAPM_MIC("Int Mic", NULL),
50 SND_SOC_DAPM_LINE("HDMI", NULL),
51 };
52
53 static const struct snd_soc_dapm_route rockchip_dapm_routes[] = {
54 /* Input Lines */
55 {"MIC", NULL, "Headset Mic"},
56 {"DMIC1L", NULL, "Int Mic"},
57 {"DMIC1R", NULL, "Int Mic"},
58 {"DMic", NULL, "Int Mic"},
59
60 /* Output Lines */
61 {"Headphones", NULL, "HPL"},
62 {"Headphones", NULL, "HPR"},
63 {"Speakers", NULL, "Speaker"},
64 {"HDMI", NULL, "TX"},
65 };
66
67 static const struct snd_kcontrol_new rockchip_controls[] = {
68 SOC_DAPM_PIN_SWITCH("Headphones"),
69 SOC_DAPM_PIN_SWITCH("Speakers"),
70 SOC_DAPM_PIN_SWITCH("Headset Mic"),
71 SOC_DAPM_PIN_SWITCH("Int Mic"),
72 SOC_DAPM_PIN_SWITCH("HDMI"),
73 };
74
75 static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
76 struct snd_pcm_hw_params *params)
77 {
78 struct snd_soc_pcm_runtime *rtd = substream->private_data;
79 unsigned int mclk;
80 int ret;
81
82 /* max98357a supports these sample rates */
83 switch (params_rate(params)) {
84 case 8000:
85 case 16000:
86 case 48000:
87 case 96000:
88 mclk = params_rate(params) * SOUND_FS;
89 break;
90 default:
91 dev_err(rtd->card->dev, "%s() doesn't support this sample rate: %d\n",
92 __func__, params_rate(params));
93 return -EINVAL;
94 }
95
96 ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
97 if (ret) {
98 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
99 __func__, mclk, ret);
100 return ret;
101 }
102
103 return 0;
104 }
105
106 static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
107 struct snd_pcm_hw_params *params)
108 {
109 struct snd_soc_pcm_runtime *rtd = substream->private_data;
110 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
111 struct snd_soc_dai *codec_dai = rtd->codec_dai;
112 unsigned int mclk;
113 int ret;
114
115 mclk = params_rate(params) * SOUND_FS;
116
117 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
118 SND_SOC_CLOCK_OUT);
119 if (ret < 0) {
120 dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
121 return ret;
122 }
123
124 ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
125 mclk, SND_SOC_CLOCK_IN);
126 if (ret) {
127 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
128 __func__, params_rate(params) * 512, ret);
129 return ret;
130 }
131
132 /* Wait for DMIC stable */
133 msleep(dmic_wakeup_delay);
134
135 return 0;
136 }
137
138 static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
139 struct snd_pcm_hw_params *params)
140 {
141 struct snd_soc_pcm_runtime *rtd = substream->private_data;
142 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
143 struct snd_soc_dai *codec_dai = rtd->codec_dai;
144 int mclk, ret;
145
146 /* in bypass mode, the mclk has to be one of the frequencies below */
147 switch (params_rate(params)) {
148 case 8000:
149 case 16000:
150 case 24000:
151 case 32000:
152 case 48000:
153 case 64000:
154 case 96000:
155 mclk = 12288000;
156 break;
157 case 11025:
158 case 22050:
159 case 44100:
160 case 88200:
161 mclk = 11289600;
162 break;
163 default:
164 return -EINVAL;
165 }
166
167 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
168 SND_SOC_CLOCK_OUT);
169 if (ret < 0) {
170 dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
171 return ret;
172 }
173
174 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
175 SND_SOC_CLOCK_IN);
176 if (ret < 0) {
177 dev_err(codec_dai->dev, "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, "Can't set pll sysclk mclk %d\n", ret);
184 return ret;
185 }
186
187 return 0;
188 }
189
190 static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
191 {
192 struct snd_soc_codec *codec = rtd->codec_dais[0]->codec;
193 struct snd_soc_dai *codec_dai = rtd->codec_dai;
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(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, NULL, 0);
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(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA);
223 snd_jack_set_key(
224 rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
225 snd_jack_set_key(
226 rockchip_sound_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
227 snd_jack_set_key(
228 rockchip_sound_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
229
230 da7219_aad_jack_det(codec, &rockchip_sound_jack);
231
232 return 0;
233 }
234
235 static int rockchip_sound_cdndp_hw_params(struct snd_pcm_substream *substream,
236 struct snd_pcm_hw_params *params)
237 {
238 struct snd_soc_pcm_runtime *rtd = substream->private_data;
239 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
240 struct snd_soc_dai *codec_dai = rtd->codec_dai;
241 int mclk, ret;
242
243 /* in bypass mode, the mclk has to be one of the frequencies below */
244 switch (params_rate(params)) {
245 case 8000:
246 case 16000:
247 case 24000:
248 case 32000:
249 case 48000:
250 case 64000:
251 case 96000:
252 mclk = 12288000;
253 break;
254 case 11025:
255 case 22050:
256 case 44100:
257 case 88200:
258 mclk = 11289600;
259 break;
260 default:
261 return -EINVAL;
262 }
263
264 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
265 SND_SOC_CLOCK_OUT);
266 if (ret < 0) {
267 dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
268 return ret;
269 }
270
271 return 0;
272 }
273
274 static int rockchip_sound_dmic_hw_params(struct snd_pcm_substream *substream,
275 struct snd_pcm_hw_params *params)
276 {
277 struct snd_soc_pcm_runtime *rtd = substream->private_data;
278 unsigned int mclk;
279 int ret;
280
281 mclk = params_rate(params) * SOUND_FS;
282
283 ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
284 if (ret) {
285 dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
286 __func__, mclk, ret);
287 return ret;
288 }
289
290 /* Wait for DMIC stable */
291 msleep(dmic_wakeup_delay);
292
293 return 0;
294 }
295
296 static const struct snd_soc_ops rockchip_sound_max98357a_ops = {
297 .hw_params = rockchip_sound_max98357a_hw_params,
298 };
299
300 static const struct snd_soc_ops rockchip_sound_rt5514_ops = {
301 .hw_params = rockchip_sound_rt5514_hw_params,
302 };
303
304 static const struct snd_soc_ops rockchip_sound_da7219_ops = {
305 .hw_params = rockchip_sound_da7219_hw_params,
306 };
307
308 static const struct snd_soc_ops rockchip_sound_cdndp_ops = {
309 .hw_params = rockchip_sound_cdndp_hw_params,
310 };
311
312 static const struct snd_soc_ops rockchip_sound_dmic_ops = {
313 .hw_params = rockchip_sound_dmic_hw_params,
314 };
315
316 static struct snd_soc_card rockchip_sound_card = {
317 .name = "rk3399-gru-sound",
318 .owner = THIS_MODULE,
319 .dapm_widgets = rockchip_dapm_widgets,
320 .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
321 .dapm_routes = rockchip_dapm_routes,
322 .num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
323 .controls = rockchip_controls,
324 .num_controls = ARRAY_SIZE(rockchip_controls),
325 };
326
327 enum {
328 DAILINK_CDNDP,
329 DAILINK_DA7219,
330 DAILINK_DMIC,
331 DAILINK_MAX98357A,
332 DAILINK_RT5514,
333 DAILINK_RT5514_DSP,
334 };
335
336 static const char * const dailink_compat[] = {
337 [DAILINK_CDNDP] = "rockchip,rk3399-cdn-dp",
338 [DAILINK_DA7219] = "dlg,da7219",
339 [DAILINK_DMIC] = "dmic-codec",
340 [DAILINK_MAX98357A] = "maxim,max98357a",
341 [DAILINK_RT5514] = "realtek,rt5514-i2c",
342 [DAILINK_RT5514_DSP] = "realtek,rt5514-spi",
343 };
344
345 static const struct snd_soc_dai_link rockchip_dais[] = {
346 [DAILINK_CDNDP] = {
347 .name = "DP",
348 .stream_name = "DP PCM",
349 .codec_dai_name = "i2s-hifi",
350 .ops = &rockchip_sound_cdndp_ops,
351 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
352 SND_SOC_DAIFMT_CBS_CFS,
353 },
354 [DAILINK_DA7219] = {
355 .name = "DA7219",
356 .stream_name = "DA7219 PCM",
357 .codec_dai_name = "da7219-hifi",
358 .init = rockchip_sound_da7219_init,
359 .ops = &rockchip_sound_da7219_ops,
360 /* set da7219 as slave */
361 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
362 SND_SOC_DAIFMT_CBS_CFS,
363 },
364 [DAILINK_DMIC] = {
365 .name = "DMIC",
366 .stream_name = "DMIC PCM",
367 .codec_dai_name = "dmic-hifi",
368 .ops = &rockchip_sound_dmic_ops,
369 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
370 SND_SOC_DAIFMT_CBS_CFS,
371 },
372 [DAILINK_MAX98357A] = {
373 .name = "MAX98357A",
374 .stream_name = "MAX98357A PCM",
375 .codec_dai_name = "HiFi",
376 .ops = &rockchip_sound_max98357a_ops,
377 /* set max98357a as slave */
378 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
379 SND_SOC_DAIFMT_CBS_CFS,
380 },
381 [DAILINK_RT5514] = {
382 .name = "RT5514",
383 .stream_name = "RT5514 PCM",
384 .codec_dai_name = "rt5514-aif1",
385 .ops = &rockchip_sound_rt5514_ops,
386 /* set rt5514 as slave */
387 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
388 SND_SOC_DAIFMT_CBS_CFS,
389 },
390 /* RT5514 DSP for voice wakeup via spi bus */
391 [DAILINK_RT5514_DSP] = {
392 .name = "RT5514 DSP",
393 .stream_name = "Wake on Voice",
394 .codec_dai_name = "rt5514-dsp-cpu-dai",
395 },
396 };
397
398 static int rockchip_sound_codec_node_match(struct device_node *np_codec)
399 {
400 int i;
401
402 for (i = 0; i < ARRAY_SIZE(dailink_compat); i++) {
403 if (of_device_is_compatible(np_codec, dailink_compat[i]))
404 return i;
405 }
406 return -1;
407 }
408
409 static int rockchip_sound_of_parse_dais(struct device *dev,
410 struct snd_soc_card *card)
411 {
412 struct device_node *np_cpu, *np_cpu0, *np_cpu1;
413 struct device_node *np_codec;
414 struct snd_soc_dai_link *dai;
415 int i, index;
416
417 card->dai_link = devm_kzalloc(dev, sizeof(rockchip_dais),
418 GFP_KERNEL);
419 if (!card->dai_link)
420 return -ENOMEM;
421
422 np_cpu0 = of_parse_phandle(dev->of_node, "rockchip,cpu", 0);
423 np_cpu1 = of_parse_phandle(dev->of_node, "rockchip,cpu", 1);
424
425 card->num_links = 0;
426 for (i = 0; i < ARRAY_SIZE(rockchip_dais); i++) {
427 np_codec = of_parse_phandle(dev->of_node,
428 "rockchip,codec", i);
429 if (!np_codec)
430 break;
431
432 if (!of_device_is_available(np_codec))
433 continue;
434
435 index = rockchip_sound_codec_node_match(np_codec);
436 if (index < 0)
437 continue;
438
439 np_cpu = (index == DAILINK_CDNDP) ? np_cpu1 : np_cpu0;
440 if (!np_cpu) {
441 dev_err(dev, "Missing 'rockchip,cpu' for %s\n",
442 rockchip_dais[index].name);
443 return -EINVAL;
444 }
445
446 dai = &card->dai_link[card->num_links++];
447 *dai = rockchip_dais[index];
448
449 dai->codec_of_node = np_codec;
450 dai->platform_of_node = np_cpu;
451 dai->cpu_of_node = np_cpu;
452 }
453
454 return 0;
455 }
456
457 static int rockchip_sound_probe(struct platform_device *pdev)
458 {
459 struct snd_soc_card *card = &rockchip_sound_card;
460 int ret;
461
462 ret = rockchip_sound_of_parse_dais(&pdev->dev, card);
463 if (ret < 0) {
464 dev_err(&pdev->dev, "Failed to parse dais: %d\n", ret);
465 return ret;
466 }
467
468 /* Set DMIC wakeup delay */
469 ret = device_property_read_u32(&pdev->dev, "dmic-wakeup-delay-ms",
470 &dmic_wakeup_delay);
471 if (ret) {
472 dmic_wakeup_delay = 0;
473 dev_dbg(&pdev->dev,
474 "no optional property 'dmic-wakeup-delay-ms' found, default: no delay\n");
475 }
476
477 card->dev = &pdev->dev;
478 return devm_snd_soc_register_card(&pdev->dev, card);
479 }
480
481 static const struct of_device_id rockchip_sound_of_match[] = {
482 { .compatible = "rockchip,rk3399-gru-sound", },
483 {},
484 };
485
486 static struct platform_driver rockchip_sound_driver = {
487 .probe = rockchip_sound_probe,
488 .driver = {
489 .name = DRV_NAME,
490 .of_match_table = rockchip_sound_of_match,
491 #ifdef CONFIG_PM
492 .pm = &snd_soc_pm_ops,
493 #endif
494 },
495 };
496
497 module_platform_driver(rockchip_sound_driver);
498
499 MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
500 MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
501 MODULE_LICENSE("GPL v2");
502 MODULE_ALIAS("platform:" DRV_NAME);
503 MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);