Merge remote branch 'nouveau/for-airlied' into drm-linus
[pandora-kernel.git] / sound / soc / pxa / raumfeld.c
1 /*
2  * raumfeld_audio.c  --  SoC audio for Raumfeld audio devices
3  *
4  * Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
5  *
6  * based on code from:
7  *
8  *    Wolfson Microelectronics PLC.
9  *    Openedhand Ltd.
10  *    Liam Girdwood <lrg@slimlogic.co.uk>
11  *    Richard Purdie <richard@openedhand.com>
12  *
13  * This program is free software; you can redistribute  it and/or modify it
14  * under  the terms of  the GNU General  Public License as published by the
15  * Free Software Foundation;  either version 2 of the  License, or (at your
16  * option) any later version.
17  */
18
19 #include <linux/module.h>
20 #include <linux/i2c.h>
21 #include <linux/delay.h>
22 #include <linux/gpio.h>
23 #include <sound/pcm.h>
24 #include <sound/soc.h>
25 #include <sound/soc-dapm.h>
26
27 #include <asm/mach-types.h>
28
29 #include "../codecs/cs4270.h"
30 #include "../codecs/ak4104.h"
31 #include "pxa2xx-pcm.h"
32 #include "pxa-ssp.h"
33
34 #define GPIO_SPDIF_RESET        (38)
35 #define GPIO_MCLK_RESET         (111)
36 #define GPIO_CODEC_RESET        (120)
37
38 static struct i2c_client *max9486_client;
39 static struct i2c_board_info max9486_hwmon_info = {
40         I2C_BOARD_INFO("max9485", 0x63),
41 };
42
43 #define MAX9485_MCLK_FREQ_112896 0x22
44 #define MAX9485_MCLK_FREQ_122880 0x23
45
46 static void set_max9485_clk(char clk)
47 {
48         i2c_master_send(max9486_client, &clk, 1);
49 }
50
51 static void raumfeld_enable_audio(bool en)
52 {
53         if (en) {
54                 gpio_set_value(GPIO_MCLK_RESET, 1);
55
56                 /* wait some time to let the clocks become stable */
57                 msleep(100);
58
59                 gpio_set_value(GPIO_SPDIF_RESET, 1);
60                 gpio_set_value(GPIO_CODEC_RESET, 1);
61         } else {
62                 gpio_set_value(GPIO_MCLK_RESET, 0);
63                 gpio_set_value(GPIO_SPDIF_RESET, 0);
64                 gpio_set_value(GPIO_CODEC_RESET, 0);
65         }
66 }
67
68 /* CS4270 */
69 static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
70 {
71         struct snd_soc_pcm_runtime *rtd = substream->private_data;
72         struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
73
74         set_max9485_clk(MAX9485_MCLK_FREQ_112896);
75
76         return snd_soc_dai_set_sysclk(codec_dai, 0, 11289600, 0);
77 }
78
79 static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
80                                      struct snd_pcm_hw_params *params)
81 {
82         struct snd_soc_pcm_runtime *rtd = substream->private_data;
83         struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
84         struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
85         unsigned int fmt, clk = 0;
86         int ret = 0;
87
88         switch (params_rate(params)) {
89         case 8000:
90         case 16000:
91         case 48000:
92         case 96000:
93                 set_max9485_clk(MAX9485_MCLK_FREQ_122880);
94                 clk = 12288000;
95                 break;
96         case 11025:
97         case 22050:
98         case 44100:
99         case 88200:
100                 set_max9485_clk(MAX9485_MCLK_FREQ_112896);
101                 clk = 11289600;
102                 break;
103         }
104
105         fmt = SND_SOC_DAIFMT_I2S |
106               SND_SOC_DAIFMT_NB_NF |
107               SND_SOC_DAIFMT_CBS_CFS;
108
109         /* setup the CODEC DAI */
110         ret = snd_soc_dai_set_fmt(codec_dai, fmt);
111         if (ret < 0)
112                 return ret;
113
114         ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
115         if (ret < 0)
116                 return ret;
117
118         /* setup the CPU DAI */
119         ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
120         if (ret < 0)
121                 return ret;
122
123         ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
124         if (ret < 0)
125                 return ret;
126
127         ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
128         if (ret < 0)
129                 return ret;
130
131         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1);
132         if (ret < 0)
133                 return ret;
134
135         return 0;
136 }
137
138 static struct snd_soc_ops raumfeld_cs4270_ops = {
139         .startup = raumfeld_cs4270_startup,
140         .hw_params = raumfeld_cs4270_hw_params,
141 };
142
143 static int raumfeld_line_suspend(struct platform_device *pdev, pm_message_t state)
144 {
145         raumfeld_enable_audio(false);
146         return 0;
147 }
148
149 static int raumfeld_line_resume(struct platform_device *pdev)
150 {
151         raumfeld_enable_audio(true);
152         return 0;
153 }
154
155 static struct snd_soc_dai_link raumfeld_line_dai = {
156         .name           = "CS4270",
157         .stream_name    = "CS4270",
158         .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP1],
159         .codec_dai      = &cs4270_dai,
160         .ops            = &raumfeld_cs4270_ops,
161 };
162
163 static struct snd_soc_card snd_soc_line_raumfeld = {
164         .name           = "Raumfeld analog",
165         .platform       = &pxa2xx_soc_platform,
166         .dai_link       = &raumfeld_line_dai,
167         .suspend_post   = raumfeld_line_suspend,
168         .resume_pre     = raumfeld_line_resume,
169         .num_links      = 1,
170 };
171
172
173 /* AK4104 */
174
175 static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
176                                      struct snd_pcm_hw_params *params)
177 {
178         struct snd_soc_pcm_runtime *rtd = substream->private_data;
179         struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
180         struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
181         int fmt, ret = 0, clk = 0;
182
183         switch (params_rate(params)) {
184         case 8000:
185         case 16000:
186         case 48000:
187         case 96000:
188                 set_max9485_clk(MAX9485_MCLK_FREQ_122880);
189                 clk = 12288000;
190                 break;
191         case 11025:
192         case 22050:
193         case 44100:
194         case 88200:
195                 set_max9485_clk(MAX9485_MCLK_FREQ_112896);
196                 clk = 11289600;
197                 break;
198         }
199
200         fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
201
202         /* setup the CODEC DAI */
203         ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
204         if (ret < 0)
205                 return ret;
206
207         /* setup the CPU DAI */
208         ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
209         if (ret < 0)
210                 return ret;
211
212         ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
213         if (ret < 0)
214                 return ret;
215
216         ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
217         if (ret < 0)
218                 return ret;
219
220         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, 0, 1);
221         if (ret < 0)
222                 return ret;
223
224         return 0;
225 }
226
227 static struct snd_soc_ops raumfeld_ak4104_ops = {
228         .hw_params = raumfeld_ak4104_hw_params,
229 };
230
231 static struct snd_soc_dai_link raumfeld_spdif_dai = {
232         .name           = "ak4104",
233         .stream_name    = "Playback",
234         .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP2],
235         .codec_dai      = &ak4104_dai,
236         .ops            = &raumfeld_ak4104_ops,
237 };
238
239 static struct snd_soc_card snd_soc_spdif_raumfeld = {
240         .name           = "Raumfeld S/PDIF",
241         .platform       = &pxa2xx_soc_platform,
242         .dai_link       = &raumfeld_spdif_dai,
243         .num_links      = 1
244 };
245
246 /* raumfeld_audio audio subsystem */
247 static struct snd_soc_device raumfeld_line_devdata = {
248         .card = &snd_soc_line_raumfeld,
249         .codec_dev = &soc_codec_device_cs4270,
250 };
251
252 static struct snd_soc_device raumfeld_spdif_devdata = {
253         .card = &snd_soc_spdif_raumfeld,
254         .codec_dev = &soc_codec_device_ak4104,
255 };
256
257 static struct platform_device *raumfeld_audio_line_device;
258 static struct platform_device *raumfeld_audio_spdif_device;
259
260 static int __init raumfeld_audio_init(void)
261 {
262         int ret;
263
264         if (!machine_is_raumfeld_speaker() &&
265             !machine_is_raumfeld_connector())
266                 return 0;
267
268         max9486_client = i2c_new_device(i2c_get_adapter(0),
269                                         &max9486_hwmon_info);
270
271         if (!max9486_client)
272                 return -ENOMEM;
273
274         set_max9485_clk(MAX9485_MCLK_FREQ_122880);
275
276         /* LINE */
277         raumfeld_audio_line_device = platform_device_alloc("soc-audio", 0);
278         if (!raumfeld_audio_line_device)
279                 return -ENOMEM;
280
281         platform_set_drvdata(raumfeld_audio_line_device,
282                              &raumfeld_line_devdata);
283         raumfeld_line_devdata.dev = &raumfeld_audio_line_device->dev;
284         ret = platform_device_add(raumfeld_audio_line_device);
285         if (ret)
286                 platform_device_put(raumfeld_audio_line_device);
287
288         /* no S/PDIF on Speakers */
289         if (machine_is_raumfeld_speaker())
290                 return ret;
291
292         /* S/PDIF */
293         raumfeld_audio_spdif_device = platform_device_alloc("soc-audio", 1);
294         if (!raumfeld_audio_spdif_device) {
295                 platform_device_put(raumfeld_audio_line_device);
296                 return -ENOMEM;
297         }
298
299         platform_set_drvdata(raumfeld_audio_spdif_device,
300                              &raumfeld_spdif_devdata);
301         raumfeld_spdif_devdata.dev = &raumfeld_audio_spdif_device->dev;
302         ret = platform_device_add(raumfeld_audio_spdif_device);
303         if (ret) {
304                 platform_device_put(raumfeld_audio_line_device);
305                 platform_device_put(raumfeld_audio_spdif_device);
306         }
307
308         raumfeld_enable_audio(true);
309
310         return ret;
311 }
312
313 static void __exit raumfeld_audio_exit(void)
314 {
315         raumfeld_enable_audio(false);
316
317         platform_device_unregister(raumfeld_audio_line_device);
318
319         if (machine_is_raumfeld_connector())
320                 platform_device_unregister(raumfeld_audio_spdif_device);
321
322         i2c_unregister_device(max9486_client);
323
324         gpio_free(GPIO_MCLK_RESET);
325         gpio_free(GPIO_CODEC_RESET);
326         gpio_free(GPIO_SPDIF_RESET);
327 }
328
329 module_init(raumfeld_audio_init);
330 module_exit(raumfeld_audio_exit);
331
332 /* Module information */
333 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
334 MODULE_DESCRIPTION("Raumfeld audio SoC");
335 MODULE_LICENSE("GPL");