rk616 codec :if do not config SPDIF,MCLK not fixed to 12M when hdmi is in
[firefly-linux-kernel-4.4.55.git] / sound / soc / rk29 / rk_rk616.c
1 /*\r
2  * rk_rk616.c  --  SoC audio for rockchip\r
3  *\r
4  * Driver for rockchip rk616 audio\r
5  *\r
6  *  This program is free software; you can redistribute  it and/or modify it\r
7  *  under  the terms of  the GNU General  Public License as published by the\r
8  *  Free Software Foundation;  either version 2 of the  License, or (at your\r
9  *  option) any later version.\r
10  *\r
11  *\r
12  */\r
13 \r
14 #include <linux/module.h>\r
15 #include <linux/device.h>\r
16 #include <sound/core.h>\r
17 #include <sound/pcm.h>\r
18 #include <sound/soc.h>\r
19 #include <sound/soc-dapm.h>\r
20 #include <asm/io.h>\r
21 #include <mach/hardware.h>\r
22 #include "../codecs/rk616_codec.h"\r
23 #include "rk29_pcm.h"\r
24 #include "rk29_i2s.h"\r
25 \r
26 #if 1\r
27 #define DBG(x...)       printk(KERN_INFO x)\r
28 #else\r
29 #define DBG(x...)\r
30 #endif\r
31 \r
32 static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {\r
33         SND_SOC_DAPM_MIC("Mic Jack", NULL),\r
34         SND_SOC_DAPM_MIC("Headset Jack", NULL), \r
35         SND_SOC_DAPM_SPK("Ext Spk", NULL),\r
36         SND_SOC_DAPM_HP("Headphone Jack", NULL),\r
37 };\r
38 \r
39 static const struct snd_soc_dapm_route rk_audio_map[]={\r
40 \r
41         /* Mic Jack --> MIC_IN*/\r
42         {"Mic1 Bias", NULL, "Mic Jack"},\r
43         {"MIC1P", NULL, "Mic1 Bias"},\r
44         {"MIC1N", NULL, "Mic1 Bias"},\r
45 \r
46         // HP MIC\r
47         {"Mic2 Bias", NULL, "Headset Jack"},\r
48         {"MIC2P", NULL, "Mic2 Bias"},\r
49         {"MIC2N", NULL, "Mic2 Bias"},\r
50 \r
51         {"Ext Spk", NULL, "SPKOUTR"},\r
52         {"Ext Spk", NULL, "SPKOUTL"},\r
53 \r
54         {"Headphone Jack", NULL, "HPOUTR"},\r
55         {"Headphone Jack", NULL, "HPOUTL"},\r
56 } ;\r
57 \r
58 static const struct snd_kcontrol_new rk_controls[] = {\r
59         SOC_DAPM_PIN_SWITCH("Mic Jack"),\r
60         SOC_DAPM_PIN_SWITCH("Headset Jack"),\r
61         SOC_DAPM_PIN_SWITCH("Ext Spk"),\r
62         SOC_DAPM_PIN_SWITCH("Headphone Jack"),\r
63 };\r
64 \r
65 static int rk616_init(struct snd_soc_pcm_runtime *rtd)\r
66 {\r
67         struct snd_soc_codec *codec = rtd->codec;\r
68         struct snd_soc_dapm_context *dapm = &codec->dapm;\r
69 \r
70         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);\r
71 \r
72         snd_soc_add_controls(codec, rk_controls,\r
73                         ARRAY_SIZE(rk_controls));\r
74 \r
75         /* Add specific widgets */\r
76         snd_soc_dapm_new_controls(dapm, rk_dapm_widgets,\r
77                                   ARRAY_SIZE(rk_dapm_widgets));\r
78         /* Set up specific audio path audio_mapnects */\r
79         snd_soc_dapm_add_routes(dapm, rk_audio_map, ARRAY_SIZE(rk_audio_map));\r
80 \r
81         snd_soc_dapm_enable_pin(dapm, "Mic Jack");\r
82         snd_soc_dapm_enable_pin(dapm, "Headset Jack");\r
83         snd_soc_dapm_enable_pin(dapm, "Ext Spk");\r
84         snd_soc_dapm_enable_pin(dapm, "Headphone Jack");\r
85 \r
86         snd_soc_dapm_sync(dapm);\r
87 \r
88         return 0;\r
89 }\r
90 \r
91 static int rk_hifi_hw_params(struct snd_pcm_substream *substream,\r
92         struct snd_pcm_hw_params *params)\r
93 {\r
94         struct snd_soc_pcm_runtime *rtd = substream->private_data;\r
95         struct snd_soc_dai *codec_dai = rtd->codec_dai;\r
96         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;\r
97         unsigned int pll_out = 0;\r
98         int ret;\r
99 \r
100         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);\r
101 \r
102         #if defined(CONFIG_SND_RK_SOC_SPDIF)\r
103         /* MCLK must be 12M when HDMI is in */\r
104         if (get_hdmi_state()) {\r
105                 DBG("%s : HDMI is in, do not set sys clk\n",__FUNCTION__);\r
106                 return 0;\r
107         }\r
108         #endif\r
109 \r
110         /* set codec DAI configuration */\r
111         #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) \r
112 \r
113         ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |\r
114                         SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);\r
115         #endif  \r
116         #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER) \r
117 \r
118         ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |\r
119                         SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM ); \r
120         #endif\r
121         if (ret < 0)\r
122                 return ret;\r
123 \r
124         /* set cpu DAI configuration */\r
125         #if defined (CONFIG_SND_RK29_CODEC_SOC_SLAVE) \r
126         ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |\r
127                         SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);\r
128         #endif  \r
129         #if defined (CONFIG_SND_RK29_CODEC_SOC_MASTER)\r
130         ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |\r
131                         SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);\r
132         #endif\r
133         if (ret < 0)\r
134                 return ret;\r
135 \r
136         switch(params_rate(params)) {\r
137                 case 8000:\r
138                 case 16000:\r
139                 case 24000:\r
140                 case 32000:\r
141                 case 48000:\r
142                         pll_out = 12288000;\r
143                         break;\r
144                 case 11025:\r
145                 case 22050:\r
146                 case 44100:\r
147                         pll_out = 11289600;\r
148                         break;\r
149                 default:\r
150                         DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));\r
151                         return -EINVAL;\r
152                         break;\r
153         }\r
154 \r
155         DBG("Enter:%s, %d, rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));\r
156 \r
157         /*Set the system clk for codec*/\r
158         ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);\r
159         if (ret < 0) {\r
160                 DBG("rk_hifi_hw_params:failed to set the sysclk for codec side\n"); \r
161                 return ret;\r
162         }\r
163 \r
164         snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);\r
165         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);\r
166         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);\r
167 \r
168         DBG("Enter:%s, %d, pll_out/4/params_rate(params) = %d \n", __FUNCTION__, __LINE__, (pll_out/4)/params_rate(params));\r
169  \r
170         return 0;\r
171 }\r
172 \r
173 static int rk_voice_hw_params(struct snd_pcm_substream *substream,\r
174         struct snd_pcm_hw_params *params)\r
175 {\r
176         struct snd_soc_pcm_runtime *rtd = substream->private_data;\r
177         struct snd_soc_dai *codec_dai = rtd->codec_dai;\r
178         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;\r
179         unsigned int pll_out = 0;\r
180         int ret;\r
181 \r
182         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);\r
183 \r
184         /* MCLK must be 12M when HDMI is in */\r
185         #if defined(CONFIG_SND_RK_SOC_SPDIF)\r
186         if (get_hdmi_state()) {\r
187                 DBG("%s : HDMI is in, do not set sys clk\n",__FUNCTION__);\r
188                 return 0;\r
189         }\r
190         #endif\r
191 \r
192         /* set codec DAI configuration */\r
193         ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A |\r
194                                 SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS);\r
195 \r
196         switch(params_rate(params)) {\r
197                 case 8000:\r
198                 case 16000:\r
199                 case 24000:\r
200                 case 32000:\r
201                 case 48000:\r
202                         pll_out = 12288000;\r
203                         break;\r
204                 case 11025:\r
205                 case 22050:\r
206                 case 44100:\r
207                         pll_out = 11289600;\r
208                         break;\r
209                 default:\r
210                         DBG("Enter:%s, %d, Error rate=%d\n", __FUNCTION__, __LINE__, params_rate(params));\r
211                         return -EINVAL;\r
212                         break;\r
213         }\r
214 \r
215         //snd_soc_dai_set_pll(codec_dai, RT5625_PLL_MCLK_TO_VSYSCLK, 0, pll_out, 24576000);\r
216 \r
217         /*Set the system clk for codec*/\r
218         ret = snd_soc_dai_set_sysclk(codec_dai, 0, pll_out, SND_SOC_CLOCK_IN);\r
219 \r
220         if (ret < 0) {\r
221                 printk("rk_voice_hw_params:failed to set the sysclk for codec side\n");\r
222                 return ret;\r
223         }\r
224 \r
225         ret = snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);\r
226 \r
227         return 0;\r
228 }\r
229 \r
230 static struct snd_soc_ops rk616_hifi_ops = {\r
231         .hw_params = rk_hifi_hw_params,\r
232 };\r
233 \r
234 static struct snd_soc_ops rk616_voice_ops = {\r
235         .hw_params = rk_voice_hw_params,\r
236 };\r
237 \r
238 static struct snd_soc_dai_link rk_dai[] = {\r
239         {\r
240                 .name = "RK616 I2S1",\r
241                 .stream_name = "RK616 PCM",\r
242                 .codec_name = "rk616-codec.4-0050",\r
243                 .platform_name = "rockchip-audio",\r
244                 .cpu_dai_name = "rk29_i2s.1",\r
245                 .codec_dai_name = "rk616-hifi",\r
246                 .init = rk616_init,\r
247                 .ops = &rk616_hifi_ops,\r
248         },\r
249         {\r
250                 .name = "RK616 I2S2",\r
251                 .stream_name = "RK616 PCM",\r
252                 .codec_name = "rk616-codec.4-0050",\r
253                 .platform_name = "rockchip-audio",\r
254                 .cpu_dai_name = "rk29_i2s.1",\r
255                 .codec_dai_name = "rk616-voice",\r
256                 .ops = &rk616_voice_ops,\r
257         },\r
258 };\r
259 \r
260 static struct snd_soc_card snd_soc_card_rk = {\r
261         .name = "RK_RK616",\r
262         .dai_link = rk_dai,\r
263         .num_links = 2,\r
264 };\r
265 \r
266 static struct platform_device *rk_snd_device;\r
267 \r
268 static int __init audio_card_init(void)\r
269 {\r
270         int ret =0;\r
271 \r
272         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);\r
273 \r
274         rk_snd_device = platform_device_alloc("soc-audio", -1);\r
275         if (!rk_snd_device) {\r
276                   printk("platform device allocation failed\n");\r
277                   return -ENOMEM;\r
278         }\r
279 \r
280         platform_set_drvdata(rk_snd_device, &snd_soc_card_rk);\r
281         ret = platform_device_add(rk_snd_device);\r
282         if (ret) {\r
283                 printk("platform device add failed\n");\r
284 \r
285                 platform_device_put(rk_snd_device);\r
286                 return ret;\r
287         }\r
288 \r
289         return ret;\r
290 }\r
291 \r
292 static void __exit audio_card_exit(void)\r
293 {\r
294         platform_device_unregister(rk_snd_device);\r
295 }\r
296 \r
297 module_init(audio_card_init);\r
298 module_exit(audio_card_exit);\r
299 /* Module information */\r
300 MODULE_AUTHOR("rockchip");\r
301 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");\r
302 MODULE_LICENSE("GPL");\r