newton:cs42l52 only support 44.1k sample rate
[firefly-linux-kernel-4.4.55.git] / sound / soc / rk29 / rk29_cs42l52.c
1 /*
2  * rk29_cs42l52.c  --  SoC audio for rockchip
3  *
4  * Driver for rockchip cs42l52 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 <linux/clk.h>
17 #include <sound/core.h>
18 #include <sound/pcm.h>
19 #include <sound/soc.h>
20 #include <sound/soc-dapm.h>
21 #include <asm/io.h>
22 #include <mach/hardware.h>
23 #include <mach/rk29_iomap.h>
24 #include "../codecs/cs42l52.h"
25 #include "rk29_pcm.h"
26 #include "rk29_i2s.h"
27
28 #if 0
29 #define DBG(x...)       printk(KERN_INFO x)
30 #else
31 #define DBG(x...)
32 #endif
33
34
35 static int rk29_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->dai->codec_dai;
40         struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
41         unsigned int pll_out = 0; 
42         unsigned int lrclk = 0;
43                 int div_bclk,div_mclk;
44                 struct clk      *general_pll;
45         int ret;
46           
47         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);    
48         /*by Vincent Hsiung for EQ Vol Change*/
49         #define HW_PARAMS_FLAG_EQVOL_ON 0x21
50         #define HW_PARAMS_FLAG_EQVOL_OFF 0x22
51         if ((params->flags == HW_PARAMS_FLAG_EQVOL_ON)||(params->flags == HW_PARAMS_FLAG_EQVOL_OFF))
52         {
53                 ret = codec_dai->ops->hw_params(substream, params, codec_dai); //by Vincent
54                 DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
55         }
56         else
57         {       
58             /* set codec DAI configuration */
59             #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
60             ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
61                             SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
62             #endif      
63             #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
64             ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
65                             SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
66             #endif
67             if (ret < 0)
68               return ret; 
69
70             /* set cpu DAI configuration */
71             #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) 
72             ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
73                             SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
74             #endif      
75             #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
76             ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
77                             SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
78
79             #endif              
80             if (ret < 0)
81               return ret;
82         }
83                 DBG("Enter:%s, rate=%d\n",__FUNCTION__,params_rate(params));
84
85         switch(params_rate(params)) {
86         case 8000:
87         case 16000:
88         case 24000:
89         case 32000:
90         case 48000:
91                 pll_out = 12288000;
92                 break;
93         case 11025:
94         case 22050:
95         case 44100:
96                 pll_out = 11289600;
97                 break;
98         default:
99                 DBG("Enter:%s, Error rate=%d\n",__FUNCTION__,params_rate(params));
100                 return -EINVAL;
101                 break;
102         }
103
104                 //pll_out = 12000000;
105
106         #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) 
107                 pll_out = 11289600;
108                 snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0);
109                 snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
110         #endif
111
112         #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE)
113                 general_pll=clk_get(NULL, "general_pll");
114                 if(clk_get_rate(general_pll)>260000000)
115                 {
116                         div_bclk=(pll_out/4)/params_rate(params)-1;
117                         //div_bclk= 63;
118                         div_mclk= 3;
119                 }
120                 else if(clk_get_rate(general_pll)>130000000)
121                 {
122                         div_bclk=(pll_out/2)/params_rate(params)-1;
123                         div_mclk=1;
124                 }
125                 else
126                 {
127                         pll_out=pll_out/4;
128                         div_bclk=(pll_out)/params_rate(params)-1;
129                         div_mclk=0;
130                 }
131                 DBG("func is%s,gpll=%ld,pll_out=%ld,div_mclk=%ld,div_bclk=%ld\n",
132                         __FUNCTION__,clk_get_rate(general_pll),pll_out,div_mclk,div_bclk);
133
134                 //snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, 0);
135                 snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
136         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK,div_bclk);
137         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, div_mclk);
138         DBG("Enter:%s, LRCK=%d\n",__FUNCTION__,(pll_out/4)/params_rate(params));
139         #endif
140
141         
142         return 0;
143 }
144
145 static const struct snd_soc_dapm_widget cs42l52_dapm_widgets[] = {
146         SND_SOC_DAPM_LINE("Audio Out", NULL),
147         SND_SOC_DAPM_LINE("Line in", NULL),
148         SND_SOC_DAPM_MIC("Micn", NULL),
149         SND_SOC_DAPM_MIC("Micp", NULL),
150 };
151
152 static const struct snd_soc_dapm_route audio_map[]= {
153         
154         {"Audio Out", NULL, "HPA"},
155         {"Audio Out", NULL, "HPB"},
156         {"Line in", NULL, "INPUT1A"},
157         {"Line in", NULL, "INPUT1B"},
158         {"Micn", NULL, "INPUT2A"},
159         {"Micp", NULL, "INPUT2B"},
160 };
161
162 /*
163  * Logic for a cs42l52 as connected on a rockchip board.
164  */
165 static int rk29_cs42l52_init(struct snd_soc_codec *codec)
166 {
167         struct snd_soc_dai *codec_dai = &codec->dai[0];
168         int ret;
169           
170         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
171 #if 0
172         /* Add specific widgets */
173         snd_soc_dapm_new_controls(codec, cs42l52_dapm_widgets,
174                                   ARRAY_SIZE(cs42l52_dapm_widgets));
175
176
177         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
178         /* Set up specific audio path audio_mapnects */
179         snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
180 #endif          
181
182         snd_soc_dapm_nc_pin(codec, "INPUT1A");
183         snd_soc_dapm_nc_pin(codec, "INPUT2A");
184
185         snd_soc_dapm_nc_pin(codec, "INPUT3A");
186         snd_soc_dapm_nc_pin(codec, "INPUT4A");
187
188         snd_soc_dapm_nc_pin(codec, "INPUT1B");
189         snd_soc_dapm_nc_pin(codec, "INPUT2B");
190         snd_soc_dapm_nc_pin(codec, "INPUT3B");
191         snd_soc_dapm_nc_pin(codec, "INPUT4B");
192         snd_soc_dapm_nc_pin(codec, "MICB");
193         
194         snd_soc_dapm_sync(codec);
195                 
196         return 0;
197 }
198
199 static struct snd_soc_ops rk29_ops = {
200           .hw_params = rk29_hw_params,
201 };
202
203 static struct snd_soc_dai_link rk29_dai = {
204           .name = "CS42L52",
205           .stream_name = "CS42L52 PCM",
206           .cpu_dai = &rk29_i2s_dai[0],
207           .codec_dai = &soc_cs42l52_dai,
208           .init = rk29_cs42l52_init,
209           .ops = &rk29_ops,
210 };
211
212 static struct snd_soc_card snd_soc_card_rk29 = {
213           .name = "RK29_CS42L52",
214           .platform = &rk29_soc_platform,
215           .dai_link = &rk29_dai,
216           .num_links = 1,
217 };
218
219
220 static struct snd_soc_device rk29_snd_devdata = {
221           .card = &snd_soc_card_rk29,
222           .codec_dev = &soc_codec_dev_cs42l52,
223 };
224
225 static struct platform_device *rk29_snd_device;
226
227 static int __init audio_card_init(void)
228 {
229         int ret =0;     
230         DBG("Enter::%s----%d\n",__FUNCTION__, __LINE__);
231         rk29_snd_device = platform_device_alloc("soc-audio", -1);
232         if (!rk29_snd_device) {
233                   DBG("platform device allocation failed\n");
234                   ret = -ENOMEM;
235                   return ret;
236         }
237         platform_set_drvdata(rk29_snd_device, &rk29_snd_devdata);
238         rk29_snd_devdata.dev = &rk29_snd_device->dev;
239         ret = platform_device_add(rk29_snd_device);
240         if (ret) {
241                 DBG("platform device add failed\n");
242                 platform_device_put(rk29_snd_device);
243         }
244         return ret;
245 }
246
247 static void __exit audio_card_exit(void)
248 {
249         platform_device_unregister(rk29_snd_device);
250 }
251
252 module_init(audio_card_init);
253 module_exit(audio_card_exit);
254 /* Module information */
255 MODULE_AUTHOR("rockchip");
256 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
257 MODULE_LICENSE("GPL");