rk2928: add audio codec.
[firefly-linux-kernel-4.4.55.git] / sound / soc / codecs / rk2928_codec.c
1 /*
2  * rk2928_codec.c ALSA SoC RK2928 codec driver
3  *
4  * Copyright 2012 Rockchip
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * version 2 as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18  * 02110-1301 USA
19  *
20  */
21
22 #include <linux/module.h>
23 #include <linux/moduleparam.h>
24 #include <linux/init.h>
25 #include <linux/delay.h>
26 #include <linux/pm.h>
27 #include <linux/gpio.h>
28 #include <linux/platform_device.h>
29 #include <linux/slab.h>
30
31 #include <asm/io.h>
32
33 #include <sound/core.h>
34 #include <sound/pcm.h>
35 #include <sound/pcm_params.h>
36 #include <sound/soc.h>
37 #include <sound/initval.h>
38 #include <sound/tlv.h>
39
40 #include "rk2928_codec.h"
41
42 static struct rk2928_codec_data {
43         struct device   *dev;
44         struct clk              *hclk;
45         int                     regbase;
46         int                             regbase_phy;
47         int                             regsize_phy;
48         int     mute;
49 } rk2928_data;
50
51 static const struct snd_soc_dapm_widget rk2928_dapm_widgets[] = {
52         SND_SOC_DAPM_DAC("DACL", "HIFI Playback", CODEC_REG_POWER, 5, 1),
53         SND_SOC_DAPM_DAC("DACR", "HIFI Playback", CODEC_REG_POWER, 4, 1),
54         SND_SOC_DAPM_PGA("DACL Amp", CODEC_REG_DAC_GAIN, 2, 0, NULL, 0),
55         SND_SOC_DAPM_PGA("DACR Amp", CODEC_REG_DAC_GAIN, 0, 0, NULL, 0),
56         SND_SOC_DAPM_OUT_DRV("DACL Drv", CODEC_REG_DAC_MUTE, 1, 1, NULL, 0),
57         SND_SOC_DAPM_OUT_DRV("DACR Drv", CODEC_REG_DAC_MUTE, 0, 1, NULL, 0),
58         SND_SOC_DAPM_OUTPUT("SPKL"),
59         SND_SOC_DAPM_OUTPUT("SPKR"),
60         SND_SOC_DAPM_ADC("ADCL", "HIFI Capture", CODEC_REG_POWER, 3, 1),
61         SND_SOC_DAPM_ADC("ADCR", "HIFI Capture", CODEC_REG_POWER, 2, 1),
62         SND_SOC_DAPM_INPUT("MICL"),
63         SND_SOC_DAPM_INPUT("MICR"),
64 };
65
66 static const struct snd_soc_dapm_route rk2928_audio_map[] = {
67         {"DACL Drv", "DACL Amp", "DACL"},
68         {"DACR Drv", "DACR Amp", "DACR"},
69         {"SPKL", NULL, "DACL Drv"},
70         {"SPKR", NULL, "DACR Drv"},
71         {"ADCL", NULL, "MICL"},
72         {"ADCR", NULL, "MICR"},
73 };
74
75 void codec_set_spk(bool on)
76 {
77         
78 }
79
80 static unsigned int rk2928_read(struct snd_soc_codec *codec, unsigned int reg)
81 {       
82         return readl(rk2928_data.regbase + reg);
83 }
84
85 static int rk2928_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int value)
86 {
87         DBG("%s reg 0x%02x value 0x%02x", __FUNCTION__, reg, value);
88         writel(value, rk2928_data.regbase + reg);
89         return 0;
90 }
91
92 static int rk2928_write_mask(struct snd_soc_codec *codec, unsigned int reg, 
93                                         unsigned int mask, unsigned int value)
94 {
95         unsigned int regvalue = rk2928_read(codec, reg);
96         
97         DBG("%s reg 0x%02x mask 0x%02x value 0x%02x", __FUNCTION__, reg, mask, value);
98         
99         regvalue &= ~mask;
100         regvalue |= mask & value;
101         return rk2928_write(codec, reg, regvalue);
102 }
103
104 static int rk2928_audio_hw_params(struct snd_pcm_substream *substream,
105                                     struct snd_pcm_hw_params *params,
106                                     struct snd_soc_dai *dai)
107 {
108 //      struct snd_soc_pcm_runtime *rtd = substream->private_data;
109 //      struct snd_soc_codec *codec = rtd->codec;
110 //      struct rk2928_codec_data *priv = snd_soc_codec_get_drvdata(codec);
111         
112         DBG("%s", __FUNCTION__);
113
114         return 0;
115 }
116
117 static int rk2928_audio_trigger(struct snd_pcm_substream *substream, int cmd,
118                                 struct snd_soc_dai *dai)
119 {
120 //      struct snd_soc_pcm_runtime *rtd = substream->private_data;
121 //      struct snd_soc_codec *codec = rtd->codec;
122 //      struct rk2928_codec_data *priv = snd_soc_codec_get_drvdata(codec);
123         int err = 0;
124
125         DBG("%s cmd 0x%x", __FUNCTION__, cmd);
126         
127         switch (cmd) {
128                 case SNDRV_PCM_TRIGGER_START:
129                 case SNDRV_PCM_TRIGGER_RESUME:
130                 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
131                         break;
132                 case SNDRV_PCM_TRIGGER_STOP:
133                 case SNDRV_PCM_TRIGGER_SUSPEND:
134                 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
135                         break;
136                 default:
137                         err = -EINVAL;
138         }
139         return err;
140 }
141
142 static int rk2928_audio_startup(struct snd_pcm_substream *substream,
143                                   struct snd_soc_dai *dai)
144 {
145 //      struct snd_soc_pcm_runtime *rtd = substream->private_data;
146 //      struct snd_soc_codec *codec = rtd->codec;
147         DBG("%s", __FUNCTION__);
148         return 0;
149 }
150
151 static int rk2928_set_bias_level(struct snd_soc_codec *codec,
152                               enum snd_soc_bias_level level)
153 {
154         DBG("%s level %d", __FUNCTION__, level);
155         
156         if(codec == NULL)
157                 return -1;
158                 
159         switch(level)
160         {
161                 case SND_SOC_BIAS_ON:
162                         break;
163                 case SND_SOC_BIAS_PREPARE:
164                         rk2928_write_mask(codec, CODEC_REG_POWER, m_PD_MIC_BIAS | m_PD_CODEC, v_PD_MIC_BIAS(0) | v_PD_CODEC(0));
165                         break;
166                 case SND_SOC_BIAS_STANDBY:
167                 case SND_SOC_BIAS_OFF:
168                         rk2928_write(codec, CODEC_REG_POWER, v_PWR_OFF);
169                         break;
170                 default:
171                         return -1;
172         }
173         codec->dapm.bias_level = level;
174         return 0;
175 }
176
177 static int rk2928_probe(struct snd_soc_codec *codec)
178 {
179         struct platform_device *pdev = to_platform_device(codec->dev);
180         struct snd_soc_dapm_context *dapm = &codec->dapm;
181         struct resource *res, *mem;
182         int ret;
183         
184         DBG("%s", __FUNCTION__);
185         
186         snd_soc_codec_set_drvdata(codec, &rk2928_data);
187         
188         rk2928_data.dev = &pdev->dev;
189         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
190         if (!res) {
191                 dev_err(&pdev->dev, "Unable to get register resource\n");
192                 ret = -ENXIO;
193                 goto err0;
194         }
195         rk2928_data.regbase_phy = res->start;
196         rk2928_data.regsize_phy = (res->end - res->start) + 1;
197         mem = request_mem_region(res->start, (res->end - res->start) + 1, pdev->name);
198         if (!mem)
199         {
200         dev_err(&pdev->dev, "failed to request mem region for rk2928 codec\n");
201         ret = -ENOENT;
202         goto err0;
203         }
204
205         
206         rk2928_data.regbase = (int)ioremap(res->start, (res->end - res->start) + 1);
207         if (!rk2928_data.regbase) {
208                 dev_err(&pdev->dev, "cannot ioremap acodec registers\n");
209                 ret = -ENXIO;
210                 goto err1;
211         }
212         
213         rk2928_write(codec, CODEC_REG_DAC_MUTE, v_MUTE_DAC(1));
214         rk2928_write(codec, CODEC_REG_DAC_GAIN, v_GAIN_DAC(DAC_GAIN_3DB_P));
215         rk2928_set_bias_level(codec, SND_SOC_BIAS_OFF);
216         
217         snd_soc_dapm_new_controls(dapm, rk2928_dapm_widgets,
218                         ARRAY_SIZE(rk2928_dapm_widgets));
219         snd_soc_dapm_add_routes(dapm, rk2928_audio_map, ARRAY_SIZE(rk2928_audio_map));
220         
221         return 0;
222         
223 err1:
224         release_mem_region(res->start,(res->end - res->start) + 1);
225 //      clk_disable(rk2928_data.hclk);
226 err0:
227         DBG("%s failed", __FUNCTION__);
228         return ret;
229 }
230
231 static int rk2928_remove(struct snd_soc_codec *codec)
232 {
233         return 0;
234 }
235
236 static int rk2928_suspend(struct snd_soc_codec *codec, pm_message_t state)
237 {
238         DBG("%s", __FUNCTION__);
239         rk2928_set_bias_level(codec, SND_SOC_BIAS_OFF);
240         return 0;
241 }
242
243 static int rk2928_resume(struct snd_soc_codec *codec)
244 {
245         DBG("%s", __FUNCTION__);
246         rk2928_write(codec, CODEC_REG_POWER, v_PD_ADC(1) | v_PD_DAC(1) | v_PD_MIC_BIAS(1));
247         return 0;
248 }
249
250 static struct snd_soc_codec_driver rk2928_audio_codec_drv = {
251         .probe = rk2928_probe,
252         .remove = rk2928_remove,
253         .suspend = rk2928_suspend,
254         .resume = rk2928_resume,
255         .read = rk2928_read,
256         .write = rk2928_write,
257         .set_bias_level = rk2928_set_bias_level,
258 };
259
260 static struct snd_soc_dai_ops rk2928_audio_codec_ops = {
261         .hw_params = rk2928_audio_hw_params,
262         .trigger = rk2928_audio_trigger,
263         .startup = rk2928_audio_startup,
264 };
265
266 static struct snd_soc_dai_driver rk2928_codec_dai = {
267         .name = "rk2928-codec",
268         .playback = {
269                 .stream_name = "HIFI Playback",
270                 .channels_min = 1,
271                 .channels_max = 2,
272                 .rates = SNDRV_PCM_RATE_8000_48000,
273                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | 
274                         SNDRV_PCM_FMTBIT_S24_LE,
275         },
276         .capture = {
277                 .stream_name = "HIFI Capture",
278                 .channels_min = 1,
279                 .channels_max = 2,
280                 .rates = SNDRV_PCM_RATE_8000_48000,
281                 .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE,
282         },
283         .ops = &rk2928_audio_codec_ops,
284 };
285
286 static __devinit int rk2928_codec_probe(struct platform_device *pdev)
287 {
288         int r;
289         
290         DBG("%s", __FUNCTION__);
291         
292         /* Register ASoC codec DAI */
293         r = snd_soc_register_codec(&pdev->dev, &rk2928_audio_codec_drv,
294                                         &rk2928_codec_dai, 1);
295         if (r) {
296                 dev_err(&pdev->dev, "can't register ASoC rk2928 audio codec\n");
297                 return r;
298         }
299         
300         DBG("%s success", __FUNCTION__);
301         return 0;
302         
303 }
304
305 static int __devexit rk2928_codec_remove(struct platform_device *pdev)
306 {
307         snd_soc_unregister_codec(&pdev->dev);
308         return 0;
309 }
310
311 static struct platform_driver rk2928_codec_driver = {
312         .probe          = rk2928_codec_probe,
313         .remove         = __devexit_p(rk2928_codec_remove),
314         .driver         = {
315                 .name   = "rk2928-codec",
316                 .owner  = THIS_MODULE,
317         },
318 };
319
320 static int __init rk2928_codec_init(void)
321 {
322         return platform_driver_register(&rk2928_codec_driver);
323 }
324 module_init(rk2928_codec_init);
325
326 static void __exit rk2928_codec_exit(void)
327 {
328         #ifdef CODEC_I2C_MODE
329         i2c_del_driver(&rk2928_codec_driver);
330         #else
331         platform_driver_unregister(&rk2928_codec_driver);
332         #endif
333 }
334 module_exit(rk2928_codec_exit);
335
336 MODULE_DESCRIPTION("ASoC RK2928 codec driver");
337 MODULE_LICENSE("GPL");