update audio platform driver, add spdif codec dts property
[firefly-linux-kernel-4.4.55.git] / sound / soc / rockchip / rk_wm8994.c
1 /*
2  * rk29_wm8994.c  --  SoC audio for rockchip
3  *
4  * Driver for rockchip wm8994 audio
5  *  Copyright (C) 2009 lhh
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  *
12  *
13  */
14
15 #include <linux/module.h>
16 #include <linux/device.h>
17 #include <linux/of.h>
18 #include <linux/of_gpio.h>
19 #include <sound/core.h>
20 #include <sound/pcm.h>
21 #include <sound/soc.h>
22 #include <sound/soc-dapm.h>
23
24 #include "../codecs/wm8994.h"
25 #include "rk_pcm.h"
26 #include "rk29_i2s.h"
27 #include <linux/clk.h>
28
29 #if 0
30 #define DBG(x...)       printk(KERN_INFO x)
31 #else
32 #define DBG(x...)
33 #endif
34
35 static int rk29_aif1_hw_params(struct snd_pcm_substream *substream,
36         struct snd_pcm_hw_params *params)
37 {
38         struct snd_soc_pcm_runtime *rtd = substream->private_data;
39         struct snd_soc_dai *codec_dai = rtd->codec_dai;
40         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
41         unsigned int pll_out = 0; 
42         int div_bclk,div_mclk;
43         int ret;
44         struct clk      *general_pll;
45
46
47         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
48
49         /* set codec DAI configuration */
50 #if defined (CONFIG_SND_RK_CODEC_SOC_SLAVE) 
51         DBG("Set codec_dai slave\n");
52         ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
53                 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
54 #endif  
55 #if defined (CONFIG_SND_RK_CODEC_SOC_MASTER)                       
56         ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
57                 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
58         DBG("Set codec_dai master\n");
59 #endif
60         if (ret < 0)
61                 return ret; 
62
63         /* set cpu DAI configuration */
64 #if defined (CONFIG_SND_RK_CODEC_SOC_SLAVE) 
65         DBG("Set cpu_dai master\n");
66         ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
67                 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
68 #endif  
69 #if defined (CONFIG_SND_RK_CODEC_SOC_MASTER)  
70         ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
71                 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 
72         DBG("Set cpu_dai slave\n"); 
73 #endif          
74         if (ret < 0)
75                 return ret;
76
77         switch(params_rate(params)) {
78                 case 8000:
79                 case 16000:
80                 case 24000:
81                 case 32000:
82                 case 48000:
83                         pll_out = 12288000;
84                         break;
85                 case 11025:
86                 case 22050:
87                 case 44100:
88                         pll_out = 11289600;
89                         break;
90                 default:
91                         DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
92                         return -EINVAL;
93         }
94
95 //      DBG("Enter:%s, %d, rate=%d,pll_out = %d\n",__FUNCTION__,__LINE__,params_rate(params),pll_out);  
96 #ifdef CONFIG_ARCH_RK29
97         general_pll=clk_get(NULL, "general_pll");
98         if(clk_get_rate(general_pll)>260000000)
99         {
100                 div_bclk=(pll_out/4)/params_rate(params)-1;
101                 div_mclk=3;
102         }
103         else if(clk_get_rate(general_pll)>130000000)
104         {
105                 div_bclk=(pll_out/2)/params_rate(params)-1;
106                 div_mclk=1;
107         }
108         else
109         {//96M
110                 pll_out=pll_out/4;
111                 div_bclk=(pll_out)/params_rate(params)-1;
112                 div_mclk=0;
113         }
114 #else
115         div_bclk=(pll_out/4)/params_rate(params)-1;
116         div_mclk=3;
117 #endif
118
119         DBG("func is%s,gpll=%ld,pll_out=%d,div_mclk=%d\n",__FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
120         ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
121         if(ret < 0)
122         {
123                 DBG("rk29_hw_params_wm8994:failed to set the cpu sysclk for codec side\n"); 
124                 return ret;
125         }
126         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
127         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
128         DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
129
130         if(div_mclk== 3)
131         {//MCLK == 11289600 or 12288000
132                 ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, pll_out, 0);
133                 if (ret < 0) {
134                         DBG("rk29_hw_params_wm8994:failed to set the sysclk for codec side\n"); 
135                         return ret;
136                 }
137         }
138         else
139         {
140                 /* set the codec FLL */
141                 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, pll_out,
142                                 params_rate(params) * 256);
143                 if (ret < 0)
144                 {
145                         printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
146                         return ret;
147                 }
148                 /* set the codec system clock */
149                 ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1,
150                                 params_rate(params) * 256, SND_SOC_CLOCK_IN);
151                 if (ret < 0)
152                 {
153                         printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
154                         return ret;
155                 }
156         }
157
158         return 0;
159 }
160
161 static int rk29_aif2_hw_params(struct snd_pcm_substream *substream,
162         struct snd_pcm_hw_params *params)
163 {
164         struct snd_soc_pcm_runtime *rtd = substream->private_data;
165         struct snd_soc_dai *codec_dai = rtd->codec_dai;
166         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
167         unsigned int pll_out = 0; 
168         int div_bclk,div_mclk;
169         int ret;
170         struct clk      *general_pll;
171
172         //change to 8Khz
173 //      params->intervals[SNDRV_PCM_HW_PARAM_RATE - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL].min = 8000;      
174
175         DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
176         
177 //      if (params_rate(params) != 8000)
178 //              return -EINVAL;
179
180         /* set codec DAI configuration */
181         ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |
182                         SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBM_CFM);
183         if (ret < 0)
184         {
185                 printk("%s: snd_soc_dai_set_fmt err =%d\n",__FUNCTION__,ret);
186                 return ret;
187         }
188         switch(params_rate(params)) {
189                 case 8000:
190                 case 16000:
191                 case 24000:
192                 case 32000:
193                 case 48000:
194                         pll_out = 12288000;
195                         break;
196                 case 11025:
197                 case 22050:
198                 case 44100:
199                         pll_out = 11289600;
200                         break;
201                 default:
202                         DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
203                         return -EINVAL;
204         }
205         
206         general_pll=clk_get(NULL, "general_pll");
207         if(clk_get_rate(general_pll)>260000000)
208         {
209                 div_bclk=(pll_out/4)/params_rate(params)-1;
210                 div_mclk=3;
211         }
212         else if(clk_get_rate(general_pll)>130000000)
213         {
214                 div_bclk=(pll_out/2)/params_rate(params)-1;
215                 div_mclk=1;
216         }
217         else
218         {//96M
219                 pll_out=pll_out/4;
220                 div_bclk=(pll_out)/params_rate(params)-1;
221                 div_mclk=0;
222         }
223
224         DBG("func is%s,gpll=%ld,pll_out=%d,div_mclk=%d\n",
225                         __FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk);
226         
227         ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
228         if(ret < 0)
229         {
230                 DBG("rk29_hw_params_wm8994:failed to set the cpu sysclk for codec side\n"); 
231                 return ret;
232         }
233         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
234         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
235         DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
236
237         /* set the codec FLL */
238         ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, WM8994_FLL_SRC_MCLK1, pll_out,
239                         8000 * 256);
240         if (ret < 0)
241         {
242                 printk("%s: snd_soc_dai_set_pll err =%d\n",__FUNCTION__,ret);
243                 return ret;
244         }
245         /* set the codec system clock */
246         ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2,
247                         8000 * 256, SND_SOC_CLOCK_IN);
248         if (ret < 0)
249         {
250                 printk("%s: snd_soc_dai_set_sysclk err =%d\n",__FUNCTION__,ret);
251                 return ret;
252         }
253
254         return ret;
255 }
256
257
258 static const struct snd_soc_dapm_widget rk29_dapm_widgets[] = {
259         SND_SOC_DAPM_SPK("Ext Left Spk", NULL),
260         SND_SOC_DAPM_SPK("Ext Right Spk", NULL),
261         SND_SOC_DAPM_SPK("Ext Rcv", NULL),
262         SND_SOC_DAPM_HP("Headset Stereophone", NULL),
263         SND_SOC_DAPM_MIC("Headset Mic", NULL),
264         SND_SOC_DAPM_MIC("Main Mic", NULL),
265         SND_SOC_DAPM_MIC("2nd Mic", NULL),
266 //      SND_SOC_DAPM_LINE("Radio In", NULL),
267         SND_SOC_DAPM_LINE("Line In", NULL),
268         SND_SOC_DAPM_LINE("Line Out", NULL),    
269
270 };
271
272 static const struct snd_soc_dapm_route rk29_dapm_routes[] = {
273         {"Ext Left Spk", NULL, "SPKOUTLP"},
274         {"Ext Left Spk", NULL, "SPKOUTLN"},
275
276         {"Ext Right Spk", NULL, "SPKOUTRP"},
277         {"Ext Right Spk", NULL, "SPKOUTRN"},
278
279         {"Ext Rcv", NULL, "HPOUT2N"},
280         {"Ext Rcv", NULL, "HPOUT2P"},
281
282         {"Headset Stereophone", NULL, "HPOUT1L"},
283         {"Headset Stereophone", NULL, "HPOUT1R"},
284
285         {"IN1LN", NULL, "Headset Mic"},
286         {"IN1LP", NULL, "Headset Mic"},
287
288         {"IN1LN", NULL, "2nd Mic"},
289         {"IN1LP", NULL, "2nd Mic"},
290
291         {"IN1RN", NULL, "Main Mic"},
292         {"IN1RP", NULL, "Main Mic"},
293
294 //      {"IN2LN", NULL, "Radio In"},
295 //      {"IN2RN", NULL, "Radio In"},
296
297         {"IN2LP:VXRN", NULL, "Line In"},
298         {"IN2RP:VXRP", NULL, "Line In"},
299         
300         {"Line Out", NULL, "LINEOUT1N"},
301         {"Line Out", NULL, "LINEOUT1P"},
302
303 };
304
305 static int rk29_wm8994_init(struct snd_soc_pcm_runtime *rtd)
306 {
307         struct snd_soc_codec *codec = rtd->codec;
308         struct snd_soc_dapm_context *dapm = &codec->dapm;
309 //      int ret;
310         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
311
312         /* add goni specific widgets */
313         snd_soc_dapm_new_controls(dapm, rk29_dapm_widgets,
314                         ARRAY_SIZE(rk29_dapm_widgets));
315
316         /* set up goni specific audio routes */
317         snd_soc_dapm_add_routes(dapm, rk29_dapm_routes,
318                         ARRAY_SIZE(rk29_dapm_routes));
319
320         /* set endpoints to not connected */
321 //      snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN");
322 //      snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP");
323         snd_soc_dapm_nc_pin(dapm, "IN2LN");
324         snd_soc_dapm_nc_pin(dapm, "IN2RN");
325 //      snd_soc_dapm_nc_pin(dapm, "LINEOUT1N");
326 //      snd_soc_dapm_nc_pin(dapm, "LINEOUT1P");
327         snd_soc_dapm_nc_pin(dapm, "LINEOUT2N");
328         snd_soc_dapm_nc_pin(dapm, "LINEOUT2P");
329 #ifdef CONFIG_HDMI
330 extern int hdmi_is_insert(void);
331 extern void codec_set_spk(bool on);
332         if(hdmi_is_insert())
333                 codec_set_spk(false);
334 #endif
335         snd_soc_dapm_sync(dapm);
336
337         /* Headset jack detection */
338 /*      ret = snd_soc_jack_new(codec, "Headset Jack",
339                         SND_JACK_HEADSET | SND_JACK_MECHANICAL | SND_JACK_AVOUT,
340                         &jack);
341         if (ret)
342                 return ret;
343
344         ret = snd_soc_jack_add_pins(&jack, ARRAY_SIZE(jack_pins), jack_pins);
345         if (ret)
346                 return ret;
347
348         ret = snd_soc_jack_add_gpios(&jack, ARRAY_SIZE(jack_gpios), jack_gpios);
349         if (ret)
350                 return ret;
351 */
352         return 0;
353 }
354
355
356 static struct snd_soc_ops rk29_aif1_ops = {
357           .hw_params = rk29_aif1_hw_params,
358 };
359
360 static struct snd_soc_ops rk29_aif2_ops = {
361           .hw_params = rk29_aif2_hw_params,
362 };
363
364 static struct snd_soc_dai_driver voice_dai = {
365         .name = "rk29-voice-dai",
366         .id = 0,
367         .playback = {
368                 .channels_min = 1,
369                 .channels_max = 2,
370                 .rates = SNDRV_PCM_RATE_8000,
371                 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
372         .capture = {
373                 .channels_min = 1,
374                 .channels_max = 2,
375                 .rates = SNDRV_PCM_RATE_8000,
376                 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
377 };
378
379 static struct snd_soc_dai_link rk29_dai[] = {
380         {
381                 .name = "WM8994 I2S1",
382                 .stream_name = "WM8994 PCM",
383                 .codec_name = "wm8994-codec",
384                 .platform_name = "rockchip-pcm",
385 #if defined(CONFIG_SND_RK_SOC_I2S_8CH)  
386                 .cpu_dai_name = "rockchip-i2s.0",
387 #elif defined(CONFIG_SND_RK_SOC_I2S_2CH)
388                 .cpu_dai_name = "rockchip-i2s.1",
389 #endif
390                 .codec_dai_name = "wm8994-aif1",
391                 .ops = &rk29_aif1_ops,
392                 .init = rk29_wm8994_init,
393         },
394         {
395                 .name = "WM8994 I2S2",
396                 .stream_name = "WM8994 PCM",
397                 .codec_name = "wm8994-codec",
398                 .platform_name = "rockchip-pcm",
399 #if defined(CONFIG_SND_RK_SOC_I2S_8CH)  
400         .cpu_dai_name = "rockchip-i2s.0",
401 #elif defined(CONFIG_SND_RK_SOC_I2S_2CH)
402                 .cpu_dai_name = "rockchip-i2s.1",
403 #endif
404                 .codec_dai_name = "wm8994-aif2",
405                 .ops = &rk29_aif2_ops,
406         },
407 };
408
409 static struct snd_soc_card rockchip_wm8994_snd_card = {
410         .name = "RK_WM8994",
411         .dai_link = rk29_dai,
412         .num_links = ARRAY_SIZE(rk29_dai),
413 };
414
415 static int rockchip_wm8994_audio_probe(struct platform_device *pdev)
416 {
417         int ret;
418         struct snd_soc_card *card = &rockchip_wm8994_snd_card;
419
420         card->dev = &pdev->dev;
421
422         ret = snd_soc_register_card(card);
423
424         if (ret)
425                 printk("%s() register card failed:%d\n", __FUNCTION__, ret);
426
427         return ret;
428 }
429
430 static int rockchip_wm8994_audio_remove(struct platform_device *pdev)
431 {
432         struct snd_soc_card *card = platform_get_drvdata(pdev);
433
434         snd_soc_unregister_card(card);
435
436         return 0;
437 }
438
439 #ifdef CONFIG_OF
440 static const struct of_device_id rockchip_wm8994_of_match[] = {
441         { .compatible = "rockchip-wm8994", },
442         {},
443 };
444 MODULE_DEVICE_TABLE(of, rockchip_wm8994_of_match);
445 #endif /* CONFIG_OF */
446
447 static struct platform_driver rockchip_wm8994_audio_driver = {
448         .driver         = {
449                 .name   = "rockchip-wm8994",
450                 .owner  = THIS_MODULE,
451                 .of_match_table = of_match_ptr(rockchip_wm8994_of_match),
452         },
453         .probe          = rockchip_wm8994_audio_probe,
454         .remove         = rockchip_wm8994_audio_remove,
455 };
456
457 module_platform_driver(rockchip_wm8994_audio_driver);
458
459 /* Module information */
460 MODULE_AUTHOR("rockchip");
461 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
462 MODULE_LICENSE("GPL");