Merge branch 'linus' into cont_syslog
[safe/jmp/linux-2.6] / 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 #define MAX9485_MCLK_FREQ_225792 0x32
46 #define MAX9485_MCLK_FREQ_245760 0x33
47
48 static void set_max9485_clk(char clk)
49 {
50         i2c_master_send(max9486_client, &clk, 1);
51 }
52
53 static void raumfeld_enable_audio(bool en)
54 {
55         if (en) {
56                 gpio_set_value(GPIO_MCLK_RESET, 1);
57
58                 /* wait some time to let the clocks become stable */
59                 msleep(100);
60
61                 gpio_set_value(GPIO_SPDIF_RESET, 1);
62                 gpio_set_value(GPIO_CODEC_RESET, 1);
63         } else {
64                 gpio_set_value(GPIO_MCLK_RESET, 0);
65                 gpio_set_value(GPIO_SPDIF_RESET, 0);
66                 gpio_set_value(GPIO_CODEC_RESET, 0);
67         }
68 }
69
70 /* CS4270 */
71 static int raumfeld_cs4270_startup(struct snd_pcm_substream *substream)
72 {
73         struct snd_soc_pcm_runtime *rtd = substream->private_data;
74         struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
75
76         /* set freq to 0 to enable all possible codec sample rates */
77         return snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
78 }
79
80 static void raumfeld_cs4270_shutdown(struct snd_pcm_substream *substream)
81 {
82         struct snd_soc_pcm_runtime *rtd = substream->private_data;
83         struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
84
85         /* set freq to 0 to enable all possible codec sample rates */
86         snd_soc_dai_set_sysclk(codec_dai, 0, 0, 0);
87 }
88
89 static int raumfeld_cs4270_hw_params(struct snd_pcm_substream *substream,
90                                      struct snd_pcm_hw_params *params)
91 {
92         struct snd_soc_pcm_runtime *rtd = substream->private_data;
93         struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
94         struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
95         unsigned int fmt, clk = 0;
96         int ret = 0;
97
98         switch (params_rate(params)) {
99         case 44100:
100                 set_max9485_clk(MAX9485_MCLK_FREQ_112896);
101                 clk = 11289600;
102                 break;
103         case 48000:
104                 set_max9485_clk(MAX9485_MCLK_FREQ_122880);
105                 clk = 12288000;
106                 break;
107         case 88200:
108                 set_max9485_clk(MAX9485_MCLK_FREQ_225792);
109                 clk = 22579200;
110                 break;
111         case 96000:
112                 set_max9485_clk(MAX9485_MCLK_FREQ_245760);
113                 clk = 24576000;
114                 break;
115         default:
116                 return -EINVAL;
117         }
118
119         fmt = SND_SOC_DAIFMT_I2S |
120               SND_SOC_DAIFMT_NB_NF |
121               SND_SOC_DAIFMT_CBS_CFS;
122
123         /* setup the CODEC DAI */
124         ret = snd_soc_dai_set_fmt(codec_dai, fmt);
125         if (ret < 0)
126                 return ret;
127
128         ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 0);
129         if (ret < 0)
130                 return ret;
131
132         /* setup the CPU DAI */
133         ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
134         if (ret < 0)
135                 return ret;
136
137         ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
138         if (ret < 0)
139                 return ret;
140
141         ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
142         if (ret < 0)
143                 return ret;
144
145         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
146         if (ret < 0)
147                 return ret;
148
149         return 0;
150 }
151
152 static struct snd_soc_ops raumfeld_cs4270_ops = {
153         .startup = raumfeld_cs4270_startup,
154         .shutdown = raumfeld_cs4270_shutdown,
155         .hw_params = raumfeld_cs4270_hw_params,
156 };
157
158 static int raumfeld_line_suspend(struct platform_device *pdev, pm_message_t state)
159 {
160         raumfeld_enable_audio(false);
161         return 0;
162 }
163
164 static int raumfeld_line_resume(struct platform_device *pdev)
165 {
166         raumfeld_enable_audio(true);
167         return 0;
168 }
169
170 static struct snd_soc_dai_link raumfeld_line_dai = {
171         .name           = "CS4270",
172         .stream_name    = "CS4270",
173         .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP1],
174         .codec_dai      = &cs4270_dai,
175         .ops            = &raumfeld_cs4270_ops,
176 };
177
178 static struct snd_soc_card snd_soc_line_raumfeld = {
179         .name           = "Raumfeld analog",
180         .platform       = &pxa2xx_soc_platform,
181         .dai_link       = &raumfeld_line_dai,
182         .suspend_post   = raumfeld_line_suspend,
183         .resume_pre     = raumfeld_line_resume,
184         .num_links      = 1,
185 };
186
187
188 /* AK4104 */
189
190 static int raumfeld_ak4104_hw_params(struct snd_pcm_substream *substream,
191                                      struct snd_pcm_hw_params *params)
192 {
193         struct snd_soc_pcm_runtime *rtd = substream->private_data;
194         struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
195         struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
196         int fmt, ret = 0, clk = 0;
197
198         switch (params_rate(params)) {
199         case 44100:
200                 set_max9485_clk(MAX9485_MCLK_FREQ_112896);
201                 clk = 11289600;
202                 break;
203         case 48000:
204                 set_max9485_clk(MAX9485_MCLK_FREQ_122880);
205                 clk = 12288000;
206                 break;
207         case 88200:
208                 set_max9485_clk(MAX9485_MCLK_FREQ_225792);
209                 clk = 22579200;
210                 break;
211         case 96000:
212                 set_max9485_clk(MAX9485_MCLK_FREQ_245760);
213                 clk = 24576000;
214                 break;
215         default:
216                 return -EINVAL;
217         }
218
219         fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF;
220
221         /* setup the CODEC DAI */
222         ret = snd_soc_dai_set_fmt(codec_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
223         if (ret < 0)
224                 return ret;
225
226         /* setup the CPU DAI */
227         ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, clk);
228         if (ret < 0)
229                 return ret;
230
231         ret = snd_soc_dai_set_fmt(cpu_dai, fmt | SND_SOC_DAIFMT_CBS_CFS);
232         if (ret < 0)
233                 return ret;
234
235         ret = snd_soc_dai_set_clkdiv(cpu_dai, PXA_SSP_DIV_SCR, 4);
236         if (ret < 0)
237                 return ret;
238
239         ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_EXT, clk, 1);
240         if (ret < 0)
241                 return ret;
242
243         return 0;
244 }
245
246 static struct snd_soc_ops raumfeld_ak4104_ops = {
247         .hw_params = raumfeld_ak4104_hw_params,
248 };
249
250 static struct snd_soc_dai_link raumfeld_spdif_dai = {
251         .name           = "ak4104",
252         .stream_name    = "Playback",
253         .cpu_dai        = &pxa_ssp_dai[PXA_DAI_SSP2],
254         .codec_dai      = &ak4104_dai,
255         .ops            = &raumfeld_ak4104_ops,
256 };
257
258 static struct snd_soc_card snd_soc_spdif_raumfeld = {
259         .name           = "Raumfeld S/PDIF",
260         .platform       = &pxa2xx_soc_platform,
261         .dai_link       = &raumfeld_spdif_dai,
262         .num_links      = 1
263 };
264
265 /* raumfeld_audio audio subsystem */
266 static struct snd_soc_device raumfeld_line_devdata = {
267         .card = &snd_soc_line_raumfeld,
268         .codec_dev = &soc_codec_device_cs4270,
269 };
270
271 static struct snd_soc_device raumfeld_spdif_devdata = {
272         .card = &snd_soc_spdif_raumfeld,
273         .codec_dev = &soc_codec_device_ak4104,
274 };
275
276 static struct platform_device *raumfeld_audio_line_device;
277 static struct platform_device *raumfeld_audio_spdif_device;
278
279 static int __init raumfeld_audio_init(void)
280 {
281         int ret;
282
283         if (!machine_is_raumfeld_speaker() &&
284             !machine_is_raumfeld_connector())
285                 return 0;
286
287         max9486_client = i2c_new_device(i2c_get_adapter(0),
288                                         &max9486_hwmon_info);
289
290         if (!max9486_client)
291                 return -ENOMEM;
292
293         set_max9485_clk(MAX9485_MCLK_FREQ_122880);
294
295         /* LINE */
296         raumfeld_audio_line_device = platform_device_alloc("soc-audio", 0);
297         if (!raumfeld_audio_line_device)
298                 return -ENOMEM;
299
300         platform_set_drvdata(raumfeld_audio_line_device,
301                              &raumfeld_line_devdata);
302         raumfeld_line_devdata.dev = &raumfeld_audio_line_device->dev;
303         ret = platform_device_add(raumfeld_audio_line_device);
304         if (ret)
305                 platform_device_put(raumfeld_audio_line_device);
306
307         /* no S/PDIF on Speakers */
308         if (machine_is_raumfeld_speaker())
309                 return ret;
310
311         /* S/PDIF */
312         raumfeld_audio_spdif_device = platform_device_alloc("soc-audio", 1);
313         if (!raumfeld_audio_spdif_device) {
314                 platform_device_put(raumfeld_audio_line_device);
315                 return -ENOMEM;
316         }
317
318         platform_set_drvdata(raumfeld_audio_spdif_device,
319                              &raumfeld_spdif_devdata);
320         raumfeld_spdif_devdata.dev = &raumfeld_audio_spdif_device->dev;
321         ret = platform_device_add(raumfeld_audio_spdif_device);
322         if (ret) {
323                 platform_device_put(raumfeld_audio_line_device);
324                 platform_device_put(raumfeld_audio_spdif_device);
325         }
326
327         raumfeld_enable_audio(true);
328
329         return ret;
330 }
331
332 static void __exit raumfeld_audio_exit(void)
333 {
334         raumfeld_enable_audio(false);
335
336         platform_device_unregister(raumfeld_audio_line_device);
337
338         if (machine_is_raumfeld_connector())
339                 platform_device_unregister(raumfeld_audio_spdif_device);
340
341         i2c_unregister_device(max9486_client);
342
343         gpio_free(GPIO_MCLK_RESET);
344         gpio_free(GPIO_CODEC_RESET);
345         gpio_free(GPIO_SPDIF_RESET);
346 }
347
348 module_init(raumfeld_audio_init);
349 module_exit(raumfeld_audio_exit);
350
351 /* Module information */
352 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
353 MODULE_DESCRIPTION("Raumfeld audio SoC");
354 MODULE_LICENSE("GPL");