ASoC: rockchip: Add dapm route for HDMI
[sfrench/cifs-2.6.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 rt5514_dmic_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(rt5514_dmic_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 const struct snd_soc_ops rockchip_sound_max98357a_ops = {
236         .hw_params = rockchip_sound_max98357a_hw_params,
237 };
238
239 static const struct snd_soc_ops rockchip_sound_rt5514_ops = {
240         .hw_params = rockchip_sound_rt5514_hw_params,
241 };
242
243 static const struct snd_soc_ops rockchip_sound_da7219_ops = {
244         .hw_params = rockchip_sound_da7219_hw_params,
245 };
246
247 enum {
248         DAILINK_MAX98357A,
249         DAILINK_RT5514,
250         DAILINK_DA7219,
251         DAILINK_RT5514_DSP,
252 };
253
254 #define DAILINK_ENTITIES        (DAILINK_DA7219 + 1)
255
256 static struct snd_soc_dai_link rockchip_dailinks[] = {
257         [DAILINK_MAX98357A] = {
258                 .name = "MAX98357A",
259                 .stream_name = "MAX98357A PCM",
260                 .codec_dai_name = "HiFi",
261                 .ops = &rockchip_sound_max98357a_ops,
262                 /* set max98357a as slave */
263                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
264                         SND_SOC_DAIFMT_CBS_CFS,
265         },
266         [DAILINK_RT5514] = {
267                 .name = "RT5514",
268                 .stream_name = "RT5514 PCM",
269                 .codec_dai_name = "rt5514-aif1",
270                 .ops = &rockchip_sound_rt5514_ops,
271                 /* set rt5514 as slave */
272                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
273                         SND_SOC_DAIFMT_CBS_CFS,
274         },
275         [DAILINK_DA7219] = {
276                 .name = "DA7219",
277                 .stream_name = "DA7219 PCM",
278                 .codec_dai_name = "da7219-hifi",
279                 .init = rockchip_sound_da7219_init,
280                 .ops = &rockchip_sound_da7219_ops,
281                 /* set da7219 as slave */
282                 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
283                         SND_SOC_DAIFMT_CBS_CFS,
284         },
285         /* RT5514 DSP for voice wakeup via spi bus */
286         [DAILINK_RT5514_DSP] = {
287                 .name = "RT5514 DSP",
288                 .stream_name = "Wake on Voice",
289                 .codec_name = "snd-soc-dummy",
290                 .codec_dai_name = "snd-soc-dummy-dai",
291         },
292 };
293
294 static struct snd_soc_card rockchip_sound_card = {
295         .name = "rk3399-gru-sound",
296         .owner = THIS_MODULE,
297         .dai_link = rockchip_dailinks,
298         .num_links =  ARRAY_SIZE(rockchip_dailinks),
299         .dapm_widgets = rockchip_dapm_widgets,
300         .num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
301         .dapm_routes = rockchip_dapm_routes,
302         .num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
303         .controls = rockchip_controls,
304         .num_controls = ARRAY_SIZE(rockchip_controls),
305 };
306
307 static int rockchip_sound_match_stub(struct device *dev, void *data)
308 {
309         return 1;
310 }
311
312 static int rockchip_sound_probe(struct platform_device *pdev)
313 {
314         struct snd_soc_card *card = &rockchip_sound_card;
315         struct device_node *cpu_node;
316         struct device *dev;
317         struct device_driver *drv;
318         int i, ret;
319
320         cpu_node = of_parse_phandle(pdev->dev.of_node, "rockchip,cpu", 0);
321         if (!cpu_node) {
322                 dev_err(&pdev->dev, "Property 'rockchip,cpu' missing or invalid\n");
323                 return -EINVAL;
324         }
325
326         for (i = 0; i < DAILINK_ENTITIES; i++) {
327                 rockchip_dailinks[i].platform_of_node = cpu_node;
328                 rockchip_dailinks[i].cpu_of_node = cpu_node;
329
330                 rockchip_dailinks[i].codec_of_node =
331                         of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i);
332                 if (!rockchip_dailinks[i].codec_of_node) {
333                         dev_err(&pdev->dev,
334                                 "Property[%d] 'rockchip,codec' missing or invalid\n", i);
335                         return -EINVAL;
336                 }
337         }
338
339         /**
340          * To acquire the spi driver of the rt5514 and set the dai-links names
341          * for soc_bind_dai_link
342          */
343         drv = driver_find("rt5514", &spi_bus_type);
344         if (!drv) {
345                 dev_err(&pdev->dev, "Can not find the rt5514 driver at the spi bus\n");
346                 return -EINVAL;
347         }
348
349         dev = driver_find_device(drv, NULL, NULL, rockchip_sound_match_stub);
350         if (!dev) {
351                 dev_err(&pdev->dev, "Can not find the rt5514 device\n");
352                 return -ENODEV;
353         }
354
355         /* Set DMIC delay */
356         ret = device_property_read_u32(&pdev->dev, "dmic-delay",
357                                         &rt5514_dmic_delay);
358         if (ret) {
359                 rt5514_dmic_delay = 0;
360                 dev_dbg(&pdev->dev,
361                         "no optional property 'dmic-delay' found, default: no delay\n");
362         }
363
364         rockchip_dailinks[DAILINK_RT5514_DSP].cpu_name = kstrdup_const(dev_name(dev), GFP_KERNEL);
365         rockchip_dailinks[DAILINK_RT5514_DSP].cpu_dai_name = kstrdup_const(dev_name(dev), GFP_KERNEL);
366         rockchip_dailinks[DAILINK_RT5514_DSP].platform_name = kstrdup_const(dev_name(dev), GFP_KERNEL);
367
368         card->dev = &pdev->dev;
369         platform_set_drvdata(pdev, card);
370
371         ret = devm_snd_soc_register_card(&pdev->dev, card);
372         if (ret)
373                 dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
374                         __func__, ret);
375
376         return ret;
377 }
378
379 static const struct of_device_id rockchip_sound_of_match[] = {
380         { .compatible = "rockchip,rk3399-gru-sound", },
381         {},
382 };
383
384 static struct platform_driver rockchip_sound_driver = {
385         .probe = rockchip_sound_probe,
386         .driver = {
387                 .name = DRV_NAME,
388                 .of_match_table = rockchip_sound_of_match,
389 #ifdef CONFIG_PM
390                 .pm = &snd_soc_pm_ops,
391 #endif
392         },
393 };
394
395 module_platform_driver(rockchip_sound_driver);
396
397 MODULE_AUTHOR("Xing Zheng <zhengxing@rock-chips.com>");
398 MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
399 MODULE_LICENSE("GPL v2");
400 MODULE_ALIAS("platform:" DRV_NAME);
401 MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);