Merge tag 'lsk-android-14.05' into develop-3.10
[firefly-linux-kernel-4.4.55.git] / sound / soc / rockchip / rk_es8323.c
1 /*
2  * rk29_es8323.c  --  SoC audio for rockchip
3  *
4  * Driver for rockchip es8323 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/of.h>
17 #include <linux/of_gpio.h>
18 #include <sound/core.h>
19 #include <sound/pcm.h>
20 #include <sound/soc.h>
21 #include <sound/soc-dapm.h>
22
23 #include "../codecs/es8323.h"
24 #include "card_info.h"
25 #include "rk_pcm.h"
26 #include "rk_i2s.h"
27
28 #ifdef CONFIG_MACH_RK_FAC
29 #include <plat/config.h>
30 extern int codec_type;
31 #endif
32
33 #if 0
34 #define DBG(x...)       printk(KERN_INFO x)
35 #else
36 #define DBG(x...)
37 #endif
38
39 //static void *rk29_speaker = NULL;
40
41 static int rk29_hw_params(struct snd_pcm_substream *substream,
42         struct snd_pcm_hw_params *params)
43 {
44         struct snd_soc_pcm_runtime *rtd = substream->private_data;
45         struct snd_soc_dai *codec_dai = rtd->codec_dai;
46         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
47         unsigned int pll_out = 0, dai_fmt = rtd->card->dai_link->dai_fmt;
48         int ret;
49
50         DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);    
51
52         /* set codec DAI configuration */
53         ret = snd_soc_dai_set_fmt(codec_dai, dai_fmt);
54         if (ret < 0) {
55                 printk("%s():failed to set the format for codec side\n", __FUNCTION__);
56                 return ret;
57         }
58
59         /* set cpu DAI configuration */
60         ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
61         if (ret < 0) {
62                 printk("%s():failed to set the format for cpu side\n", __FUNCTION__);
63                 return ret;
64         }
65
66         switch(params_rate(params)) {
67         case 8000:
68         case 16000:
69         case 24000:
70         case 32000:
71         case 48000:
72                 pll_out = 12288000;
73                 break;
74         case 11025:
75         case 22050:
76         case 44100:
77                 pll_out = 11289600;
78                 break;
79         default:
80                 DBG("Enter:%s, %d, Error rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
81                 return -EINVAL;
82                 break;
83         }
84         DBG("Enter:%s, %d, rate=%d\n",__FUNCTION__,__LINE__,params_rate(params));
85         
86         if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBS_CFS) {
87                 snd_soc_dai_set_sysclk(cpu_dai, 0, pll_out, 0);
88                 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_BCLK, (pll_out/4)/params_rate(params)-1);
89                 snd_soc_dai_set_clkdiv(cpu_dai, ROCKCHIP_DIV_MCLK, 3);
90         }
91
92         DBG("Enter:%s, %d, LRCK=%d\n",__FUNCTION__,__LINE__,(pll_out/4)/params_rate(params));
93           return 0;
94 }
95
96 static const struct snd_soc_dapm_widget rk29_dapm_widgets[] = {
97         SND_SOC_DAPM_LINE("Audio Out", NULL),
98         SND_SOC_DAPM_LINE("Line in", NULL),
99         SND_SOC_DAPM_MIC("Micn", NULL),
100         SND_SOC_DAPM_MIC("Micp", NULL),
101 };
102
103 static const struct snd_soc_dapm_route audio_map[]= {
104         
105         {"Audio Out", NULL, "LOUT1"},
106         {"Audio Out", NULL, "ROUT1"},
107         {"Line in", NULL, "RINPUT1"},
108         {"Line in", NULL, "LINPUT1"},
109         {"Micn", NULL, "RINPUT2"},
110         {"Micp", NULL, "LINPUT2"},
111 };
112
113 /*
114  * Logic for a es8323 as connected on a rockchip board.
115  */
116 static int rk29_es8323_init(struct snd_soc_pcm_runtime *rtd)
117 {
118         struct snd_soc_dai *codec_dai = rtd->codec_dai;
119         struct snd_soc_codec *codec = rtd->codec;
120         struct snd_soc_dapm_context *dapm = &codec->dapm;
121         int ret;
122           
123     DBG("Enter::%s----%d\n",__FUNCTION__,__LINE__);
124     
125     ret = snd_soc_dai_set_sysclk(codec_dai, 0,
126                 /*12000000*/11289600, SND_SOC_CLOCK_IN);
127         if (ret < 0) {
128                 printk(KERN_ERR "Failed to set es8323 SYSCLK: %d\n", ret);
129                 return ret;
130         }
131         
132     /* Add specific widgets */
133 #if 0
134         snd_soc_dapm_new_controls(dapm, rk29_dapm_widgets,
135                                   ARRAY_SIZE(rk29_dapm_widgets));
136         //snd_soc_dapm_nc_pin(codec, "LOUT2");
137         //snd_soc_dapm_nc_pin(codec, "ROUT2");
138         
139     /* Set up specific audio path audio_mapnects */
140         snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
141        
142         snd_soc_dapm_sync(dapm);
143 #endif
144     return 0;
145 }
146
147 static struct snd_soc_ops rk29_ops = {
148           .hw_params = rk29_hw_params,
149 };
150
151 static struct snd_soc_dai_link rk29_dai = {
152         .name = "ES8323",
153         .stream_name = "ES8323 PCM",
154         .codec_dai_name = "ES8323 HiFi",
155         .init = rk29_es8323_init,
156         .ops = &rk29_ops,
157 };
158
159 static struct snd_soc_card rockchip_es8323_snd_card = {
160         .name = "RK_ES8323",
161         .dai_link = &rk29_dai,
162         .num_links = 1,
163 };
164
165 static int rockchip_es8323_audio_probe(struct platform_device *pdev)
166 {
167         int ret;
168         struct snd_soc_card *card = &rockchip_es8323_snd_card;
169
170         card->dev = &pdev->dev;
171
172         ret = rockchip_of_get_sound_card_info(card);
173         if (ret) {
174                 printk("%s() get sound card info failed:%d\n", __FUNCTION__, ret);
175                 return ret;
176         }
177
178         ret = snd_soc_register_card(card);
179         if (ret)
180                 printk("%s() register card failed:%d\n", __FUNCTION__, ret);
181
182         return ret;
183 }
184
185 static int rockchip_es8323_audio_remove(struct platform_device *pdev)
186 {
187         struct snd_soc_card *card = platform_get_drvdata(pdev);
188
189         snd_soc_unregister_card(card);
190
191         return 0;
192 }
193
194 #ifdef CONFIG_OF
195 static const struct of_device_id rockchip_es8323_of_match[] = {
196         { .compatible = "rockchip-es8323", },
197         {},
198 };
199 MODULE_DEVICE_TABLE(of, rockchip_es8323_of_match);
200 #endif /* CONFIG_OF */
201
202 static struct platform_driver rockchip_es8323_audio_driver = {
203         .driver         = {
204                 .name   = "rockchip-es8323",
205                 .owner  = THIS_MODULE,
206                 .pm = &snd_soc_pm_ops,
207                 .of_match_table = of_match_ptr(rockchip_es8323_of_match),
208         },
209         .probe          = rockchip_es8323_audio_probe,
210         .remove         = rockchip_es8323_audio_remove,
211 };
212
213 module_platform_driver(rockchip_es8323_audio_driver);
214
215 /* Module information */
216 MODULE_AUTHOR("rockchip");
217 MODULE_DESCRIPTION("ROCKCHIP i2s ASoC Interface");
218 MODULE_LICENSE("GPL");
219