Merge remote-tracking branch 'aosp/android-3.0' into develop-3.0
[firefly-linux-kernel-4.4.55.git] / sound / soc / rk29 / rk29_rt5631.c
1 /*
2  * rk29_rt5631.c  --  SoC audio for rockchip
3  *
4  * Driver for rockchip rt5631 audio
5  *
6  *  This program is free software; you can redistribute  it and/or modify it
7  *  under  the terms of  the GNU General  Public License as published by the
8  *  Free Software Foundation;  either version 2 of the  License, or (at your
9  *  option) any later version.
10  *
11  *
12  */
13
14 #include <linux/module.h>
15 #include <linux/device.h>
16 #include <sound/core.h>
17 #include <sound/pcm.h>
18 #include <sound/soc.h>
19 #include <sound/soc-dapm.h>
20 #include <asm/io.h>
21 #include <mach/hardware.h>
22 #include <mach/rk29_iomap.h>
23 #include "../codecs/rt5631.h"
24 #include "rk29_pcm.h"
25 #include "rk29_i2s.h"
26
27 #if 0
28 #define DBG(x...)       printk(KERN_INFO x)
29 #else
30 #define DBG(x...)
31 #endif
32
33 static int rk29_hw_params(struct snd_pcm_substream *substream,
34         struct snd_pcm_hw_params *params)
35 {
36         struct snd_soc_pcm_runtime *rtd = substream->private_data;
37         struct snd_soc_dai *codec_dai = rtd->codec_dai;
38         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
39         unsigned int pll_out = 0; 
40         int ret;
41
42         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);    
43         /*by Vincent Hsiung for EQ Vol Change*/
44         #define HW_PARAMS_FLAG_EQVOL_ON 0x21
45         #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
46         if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
47         {
48                 ret = codec_dai->driver->ops->hw_params(substream, params, codec_dai); //by Vincent
49                 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
50         }
51         else
52         {
53                 
54                 /* set codec DAI configuration */
55                 #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
56                 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
57                                 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
58                 #endif  
59                 #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
60                 ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
61                                 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); 
62                 #endif
63                 if (ret < 0)
64                   return ret; 
65
66                 /* set cpu DAI configuration */
67                 #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
68                 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
69                                 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
70                 #endif  
71                 #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
72                 ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
73                                 SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); 
74                 #endif          
75                 if (ret < 0)
76                   return ret;
77
78         }
79
80
81         switch(params_rate(params)) {
82         case 8000:
83         case 16000:
84         case 24000:
85         case 32000:
86         case 48000:
87                 pll_out = 12288000;
88                 break;
89         case 11025:
90         case 22050:
91         case 44100:
92                 pll_out = 11289600;
93                 break;
94         default:
95                 DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
96                 return -EINVAL;
97                 break;
98         }
99         DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
100
101                 #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
102 #if 0           //use pll from blck
103           /*Set the pll of rt5631,the Pll source from BITCLK on CPU is master mode*/
104          //bitclk is 64fs           
105                     ret=snd_soc_dai_set_pll(codec_dai,0,params_rate(params)*64,pll_out);
106                     if (ret < 0)
107                     { 
108                        DBG("rk29_hw_params_rt5631:failed to set the pll for codec side\n"); 
109                            return ret;
110                     }
111 #endif      
112                    /*Set the system clk for codec*/
113                     ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
114                     if (ret < 0)
115                     {
116                        DBG("rk29_hw_params_rt5631:failed to set the sysclk for codec side\n"); 
117                            return ret;
118                         }           
119                 #endif
120   
121
122         #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
123                 
124                         //      snd_soc_dai_set_pll(codec_dai,0,pll_out, 22579200);
125                                 snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);                                          
126       
127         #endif
128
129
130         #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
131         snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
132         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
133         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
134         #endif
135
136         DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
137         
138         return 0;
139 }
140
141 static const struct snd_soc_dapm_widget rt5631_dapm_widgets[] = {
142         
143         SND_SOC_DAPM_MIC("Mic Jack", NULL),
144         SND_SOC_DAPM_SPK("Ext Spk", NULL),
145         SND_SOC_DAPM_HP("Headphone Jack", NULL),
146
147 };
148
149 static const struct snd_soc_dapm_route audio_map[]={
150
151         /* Mic Jack --> MIC_IN*/
152         {"Mic Bias1", NULL, "Mic Jack"},
153         {"MIC1", NULL, "Mic Bias1"},
154         /* HP_OUT --> Headphone Jack */
155         {"Headphone Jack", NULL, "HPOL"},
156         {"Headphone Jack", NULL, "HPOR"},
157         /* LINE_OUT --> Ext Speaker */
158         {"Ext Spk", NULL, "SPOL"},
159         {"Ext Spk", NULL, "SPOR"},
160
161 } ;
162
163 /*
164  * Logic for a rt5631 as connected on a rockchip board.
165  */
166 static int rk29_rt5631_init(struct snd_soc_pcm_runtime *rtd)
167 {
168         struct snd_soc_codec *codec = rtd->codec;
169         struct snd_soc_dapm_context *dapm = &codec->dapm;
170
171         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
172
173         /* Add specific widgets */
174         snd_soc_dapm_new_controls(dapm, rt5631_dapm_widgets,
175                                   ARRAY_SIZE(rt5631_dapm_widgets));
176         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
177         /* Set up specific audio path audio_mapnects */
178         snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
179         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
180         snd_soc_dapm_nc_pin(dapm, "HP_L");
181         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
182         snd_soc_dapm_nc_pin(dapm, "HP_R");
183         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
184         snd_soc_dapm_sync(dapm);
185         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
186
187         return 0;
188 }
189
190 static struct snd_soc_ops rk29_ops = {
191           .hw_params = rk29_hw_params,
192 };
193
194 static struct snd_soc_dai_link rk29_dai = {
195         .name = "RT5631",
196         .stream_name = "RT5631 PCM",
197         .codec_name = "RT5631.0-001a",
198         .platform_name = "rockchip-audio",
199         .cpu_dai_name = "rk29_i2s.0",
200         .codec_dai_name = "RT5631 HiFi",
201         .init = rk29_rt5631_init,
202         .ops = &rk29_ops,
203 };
204
205 static struct snd_soc_card snd_soc_card_rk29 = {
206         .name = "RK29_RT5631",
207         .dai_link = &rk29_dai,
208         .num_links = 1,
209 };
210
211 static struct platform_device *rk29_snd_device;
212
213 static int __init audio_card_init(void)
214 {
215         int ret =0;
216
217         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
218         rk29_snd_device = platform_device_alloc("soc-audio", -1);
219         if (!rk29_snd_device) {
220                   printk("platform device allocation failed\n");
221                   ret = -ENOMEM;
222                   return ret;
223         }
224         platform_set_drvdata(rk29_snd_device, &snd_soc_card_rk29);
225         ret = platform_device_add(rk29_snd_device);
226         if (ret) {
227                 printk("platform device add failed\n");
228                 platform_device_put(rk29_snd_device);
229         }
230         return ret;
231 }
232
233 static void __exit audio_card_exit(void)
234 {
235         platform_device_unregister(rk29_snd_device);
236 }
237
238 module_init(audio_card_init);
239 module_exit(audio_card_exit);
240 /* Module information */
241 MODULE_AUTHOR("rockchip");
242 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
243 MODULE_LICENSE("GPL");
244