Audio: delete codec_set_spk, update rk616 codec driver
[firefly-linux-kernel-4.4.55.git] / sound / soc / rockchip / rk_rt5512.c
1 /*
2  *  odroid_rt5512.c
3  *
4  *  This program is free software; you can redistribute  it and/or modify it
5  *  under  the terms of  the GNU General  Public License as published by the
6  *  Free Software Foundation;  either version 2 of the  License, or (at your
7  *  option) any later version.
8  */
9 #include <linux/module.h>
10 #include <linux/device.h>
11 #include <linux/of.h>
12 #include <linux/of_gpio.h>
13 #include <sound/core.h>
14 #include <sound/pcm.h>
15 #include <sound/soc.h>
16 #include <sound/soc-dapm.h>
17 #include <sound/jack.h>
18 #include <linux/delay.h>    
19 #include "card_info.h"
20 #include "rk_pcm.h"
21 #include "rk_i2s.h"
22 #if 1
23 #define DBG(x...)       printk(KERN_INFO x)
24 #else
25 #define DBG(x...)
26 #endif
27
28 #include "../codecs/rt5512.h"
29
30 static struct platform_device *rk29_snd_device;
31
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         unsigned int pll_div, dai_fmt = rtd->dai_link->dai_fmt;
41         int ret;
42
43         DBG("Enter::%s----%d\n", __FUNCTION__, __LINE__);
44
45         /* set codec DAI configuration */
46         ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
47         if (ret < 0) {
48                 printk("%s():failed to set the format for codec side\n", __FUNCTION__);
49                 return ret;
50         }
51
52         /* set cpu DAI configuration */
53         ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
54         if (ret < 0) {
55                 printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
56                 return ret;
57         }
58
59         switch(params_rate(params)) {
60         case 8000:
61         case 16000:
62         case 24000:
63         case 32000:
64         case 48000:
65                 pll_out = 12288000;
66                 break;
67         case 11025:
68         case 22050:
69         case 44100:
70                 pll_out = 11289600;
71                 break;
72         case 96000:
73         case 192000:    
74                 pll_out = 12288000*2;
75                 break;          
76         case 88200:
77         case 176400:    
78                 pll_out = 11289600*2;
79                 break;          
80         default:
81                 DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
82                 return -EINVAL;
83                 break;
84         }
85         if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
86                 goto skip__;
87         snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
88         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, 64-1);//bclk = 2*32*lrck; 2*32fs
89         switch(params_rate(params)) {
90         case 176400:            
91                 case 192000:
92                         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 1);  
93         DBG("Enter:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
94                 __FUNCTION__,__LINE__,pll_out,pll_out/2,params_rate(params));                   
95                         break;
96                 default:
97                         snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);  
98         DBG("default:%s, %d, MCLK=%d BCLK=%d LRCK=%d\n",
99                 __FUNCTION__,__LINE__,pll_out,pll_out/4,params_rate(params));                   
100                         break;
101         }
102
103     /*Set the system clk for codec*/
104         ret=snd_soc_dai_set_sysclk(codec_dai, 0,pll_out,SND_SOC_CLOCK_IN);
105         if (ret < 0)
106         {
107                 DBG("rk29_hw_params_rt5512:failed to set the sysclk for codec side\n"); 
108                 return ret;
109         }           
110
111     switch (params_rate(params))
112         {
113                 case 8000:
114                         pll_div = 12;
115                         break;
116                 case 16000:
117                         pll_div = 6;
118                         break;
119                 case 32000:
120                         pll_div = 3;
121                         break;
122                 case 48000:
123                         pll_div = 2;
124                         break;
125                 case 96000:
126                         pll_div = 1;
127                         break;
128                 case 11025:
129                         pll_div = 8;
130                         break;
131                 case 22050:
132                         pll_div = 4;
133                         break;
134                 case 44100:
135                         pll_div = 2;
136                         break;
137                 case 88200:
138                         pll_div = 1;
139                         break;
140                 default:
141                         printk("Not yet supported!\n");
142                         return -EINVAL;
143         }
144         ret = snd_soc_dai_set_clkdiv(codec_dai, RT5512_CLK_DIV_ID, pll_div*4);
145         if (ret < 0)
146                 return ret;     
147 skip__:
148
149         if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
150                 snd_soc_dai_set_sysclk(codec_dai,0,pll_out, SND_SOC_CLOCK_IN);
151         return 0;
152 }
153
154 //---------------------------------------------------------------------------------
155 /*
156  * rt5512 DAI operations.
157  */
158 static struct snd_soc_ops rk29_ops = {
159         .hw_params = rk29_hw_params,
160 };
161
162 static const struct snd_soc_dapm_widget rt5512_dapm_widgets[] = {
163         // Input
164         SND_SOC_DAPM_MIC("Main Mic", NULL),
165         SND_SOC_DAPM_LINE("LineIn", NULL),
166         // Output
167         SND_SOC_DAPM_SPK("Ext Spk", NULL),
168         SND_SOC_DAPM_HP("Headphone Jack", NULL),
169 };
170
171 static const struct snd_soc_dapm_route rt5512_audio_map[] = {
172         // Input
173         {"MicBias1", NULL,"Main Mic"},
174         {"Mic2", NULL, "MicBias1"},
175     {"MicBias2", NULL, "LineIn"},
176     {"Aux", NULL, "MicBias2"},
177         // Output
178         {"Ext Spk", NULL, "LSpeaker"},
179         {"Ext Spk", NULL, "RSpeaker"},
180         {"Headphone Jack", NULL, "LHeadphone"},
181         {"Headphone Jack", NULL, "RHeadphone"},
182 };
183
184 #if 0
185
186 static struct snd_soc_jack rk29_soc_jack;
187
188
189
190 static struct snd_soc_jack_gpio odroid_soc_jack_gpio[] = {
191         {
192                 .gpio = 28,
193                 .name "headset event",
194                 .report = SND_JACK_HEADSET,
195                 .debounce_time = 200,
196         },
197 };
198 #endif
199
200 #if 0
201 static int rt5512_headset_keys(struct snd_soc_jack *jack)
202 {
203         int err = 0;
204
205         err = snd_jack_set_key(jack->jack, SND_JACK_BTN_0, 0x80);
206         if (err)
207                 return err;
208
209         err = snd_jack_set_key(jack->jack, SND_JACK_BTN_1, 0x81);
210         if (err)
211                 return err;
212
213         err = snd_jack_set_key(jack->jack, SND_JACK_BTN_2, 0x82);
214         if (err)
215                 return err;
216
217         return 0;
218 }
219 #endif
220
221 static int rt5512_init(struct snd_soc_pcm_runtime *rtd)
222 {
223         struct snd_soc_codec *codec = rtd->codec;
224         struct snd_soc_dapm_context *dapm = &codec->dapm;
225         //struct rt5512_codec_chip *chip = snd_soc_codec_get_drvdata(codec);
226         //int err = 0;
227
228         snd_soc_dapm_new_controls(dapm, rt5512_dapm_widgets,
229                                 ARRAY_SIZE(rt5512_dapm_widgets));
230
231         snd_soc_dapm_add_routes(dapm, rt5512_audio_map,
232                                 ARRAY_SIZE(rt5512_audio_map));
233 #if FOR_MID
234     snd_soc_dapm_disable_pin(dapm, "Main Mic");
235         snd_soc_dapm_disable_pin(dapm, "LineIn");
236         snd_soc_dapm_disable_pin(dapm, "Ext Spk");
237         snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
238 #endif
239
240 #if 0
241         if (!chip->rt_jack)
242         {
243                 err = snd_soc_jack_new(codec, "Headset Jack" , SND_JACK_HEADSET, &rk29_soc_jack);
244                 if (err)
245                         return err;
246
247                 #if 0
248                 // How-to use gpio, just declare snd_soc_jack_gpios, then it will
249                 // help you to register a interrupt and set wakeup, and delayed schedule
250                 // work
251                 err = snd_soc_jack_add_gpios(&odroid_soc_jack, gpio_count, odroid_soc_jack_gpios);
252                 if (err)
253                         return err;
254
255                 // If  use this, when trigger, just use snd_soc_jack_get_type
256                 // then snd_soc_jack_report to send the event to upper layer
257                 err = snd_soc_jack_add_zones(&odroid_soc_jack, zone_count, tcc_soc_zones);
258                 if (err)
259                         return err;
260                 #endif
261
262                 err = rt5512_headset_keys(&rk29_soc_jack);
263                 if (err)
264                         return err;
265
266                 chip->rt_jack = &rk29_soc_jack;
267         }
268 #endif
269         snd_soc_dapm_sync(dapm);
270         return 0;
271 }
272
273 static struct snd_soc_dai_link rk29_dai[] = {
274         { /* Primary DAI i/f */
275                 .name = "RT5512 AIF1",
276                 .stream_name = "RT5512 PCM",
277                 .codec_dai_name = "RT5512-aif1",
278                 .init = rt5512_init,
279                 .ops = &rk29_ops,
280         },
281 };
282
283 static struct snd_soc_card rockchip_rt5512_snd_card = {
284         .name = "RK_RT5512",
285         .dai_link = rk29_dai,
286
287         /* If you want to use sec_fifo device,
288          * changes the num_link = 2 or ARRAY_SIZE(odroid_dai). */
289         .num_links = ARRAY_SIZE(rk29_dai),
290 };
291
292 static int rockchip_rt5512_audio_probe(struct platform_device *pdev)
293 {
294         int ret;
295         struct snd_soc_card *card = &rockchip_rt5512_snd_card;
296
297         card->dev = &pdev->dev;
298
299         ret = rockchip_of_get_sound_card_info(card);
300         if (ret) {
301                 printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
302                 return ret;
303         }
304
305         ret = snd_soc_register_card(card);
306         if (ret)
307                 printk("%s() register card failed:%d\n", __FUNCTION__, ret);
308
309         return ret;
310 }
311
312 static int rockchip_rt5512_audio_remove(struct platform_device *pdev)
313 {
314         struct snd_soc_card *card = platform_get_drvdata(pdev);
315
316         snd_soc_unregister_card(card);
317
318         return 0;
319 }
320
321 #ifdef CONFIG_OF
322 static const struct of_device_id rockchip_rt5512_of_match[] = {
323         { .compatible = "rockchip-rt5512", },
324         {},
325 };
326 MODULE_DEVICE_TABLE(of, rockchip_rt5512_of_match);
327 #endif /* CONFIG_OF */
328
329 static struct platform_driver rockchip_rt5512_audio_driver = {
330         .driver         = {
331                 .name   = "rockchip-rt5512",
332                 .owner  = THIS_MODULE,
333                 .of_match_table = of_match_ptr(rockchip_rt5512_of_match),
334         },
335         .probe          = rockchip_rt5512_audio_probe,
336         .remove         = rockchip_rt5512_audio_remove,
337 };
338
339 module_platform_driver(rockchip_rt5512_audio_driver);
340
341 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
342 MODULE_AUTHOR("cy_huang <cy_huang@richtek.com>");
343 MODULE_LICENSE("GPL");