sys_swapon: fix inode locking
[pandora-kernel.git] / sound / soc / samsung / s3c24xx_uda134x.c
1 /*
2  * Modifications by Christian Pellegrin <chripell@evolware.org>
3  *
4  * s3c24xx_uda134x.c  --  S3C24XX_UDA134X ALSA SoC Audio board driver
5  *
6  * Copyright 2007 Dension Audio Systems Ltd.
7  * Author: Zoltan Devai
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include <linux/clk.h>
15 #include <linux/gpio.h>
16
17 #include <sound/soc.h>
18 #include <sound/s3c24xx_uda134x.h>
19
20 #include <plat/regs-iis.h>
21
22 #include "s3c24xx-i2s.h"
23
24 /* #define ENFORCE_RATES 1 */
25 /*
26   Unfortunately the S3C24XX in master mode has a limited capacity of
27   generating the clock for the codec. If you define this only rates
28   that are really available will be enforced. But be careful, most
29   user level application just want the usual sampling frequencies (8,
30   11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
31   operation for embedded systems. So if you aren't very lucky or your
32   hardware engineer wasn't very forward-looking it's better to leave
33   this undefined. If you do so an approximate value for the requested
34   sampling rate in the range -/+ 5% will be chosen. If this in not
35   possible an error will be returned.
36 */
37
38 static struct clk *xtal;
39 static struct clk *pclk;
40 /* this is need because we don't have a place where to keep the
41  * pointers to the clocks in each substream. We get the clocks only
42  * when we are actually using them so we don't block stuff like
43  * frequency change or oscillator power-off */
44 static int clk_users;
45 static DEFINE_MUTEX(clk_lock);
46
47 static unsigned int rates[33 * 2];
48 #ifdef ENFORCE_RATES
49 static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
50         .count  = ARRAY_SIZE(rates),
51         .list   = rates,
52         .mask   = 0,
53 };
54 #endif
55
56 static struct platform_device *s3c24xx_uda134x_snd_device;
57
58 static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
59 {
60         int ret = 0;
61 #ifdef ENFORCE_RATES
62         struct snd_pcm_runtime *runtime = substream->runtime;
63 #endif
64
65         mutex_lock(&clk_lock);
66         pr_debug("%s %d\n", __func__, clk_users);
67         if (clk_users == 0) {
68                 xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
69                 if (!xtal) {
70                         printk(KERN_ERR "%s cannot get xtal\n", __func__);
71                         ret = -EBUSY;
72                 } else {
73                         pclk = clk_get(&s3c24xx_uda134x_snd_device->dev,
74                                        "pclk");
75                         if (!pclk) {
76                                 printk(KERN_ERR "%s cannot get pclk\n",
77                                        __func__);
78                                 clk_put(xtal);
79                                 ret = -EBUSY;
80                         }
81                 }
82                 if (!ret) {
83                         int i, j;
84
85                         for (i = 0; i < 2; i++) {
86                                 int fs = i ? 256 : 384;
87
88                                 rates[i*33] = clk_get_rate(xtal) / fs;
89                                 for (j = 1; j < 33; j++)
90                                         rates[i*33 + j] = clk_get_rate(pclk) /
91                                                 (j * fs);
92                         }
93                 }
94         }
95         clk_users += 1;
96         mutex_unlock(&clk_lock);
97         if (!ret) {
98 #ifdef ENFORCE_RATES
99                 ret = snd_pcm_hw_constraint_list(runtime, 0,
100                                                  SNDRV_PCM_HW_PARAM_RATE,
101                                                  &hw_constraints_rates);
102                 if (ret < 0)
103                         printk(KERN_ERR "%s cannot set constraints\n",
104                                __func__);
105 #endif
106         }
107         return ret;
108 }
109
110 static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
111 {
112         mutex_lock(&clk_lock);
113         pr_debug("%s %d\n", __func__, clk_users);
114         clk_users -= 1;
115         if (clk_users == 0) {
116                 clk_put(xtal);
117                 xtal = NULL;
118                 clk_put(pclk);
119                 pclk = NULL;
120         }
121         mutex_unlock(&clk_lock);
122 }
123
124 static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
125                                         struct snd_pcm_hw_params *params)
126 {
127         struct snd_soc_pcm_runtime *rtd = substream->private_data;
128         struct snd_soc_dai *codec_dai = rtd->codec_dai;
129         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
130         unsigned int clk = 0;
131         int ret = 0;
132         int clk_source, fs_mode;
133         unsigned long rate = params_rate(params);
134         long err, cerr;
135         unsigned int div;
136         int i, bi;
137
138         err = 999999;
139         bi = 0;
140         for (i = 0; i < 2*33; i++) {
141                 cerr = rates[i] - rate;
142                 if (cerr < 0)
143                         cerr = -cerr;
144                 if (cerr < err) {
145                         err = cerr;
146                         bi = i;
147                 }
148         }
149         if (bi / 33 == 1)
150                 fs_mode = S3C2410_IISMOD_256FS;
151         else
152                 fs_mode = S3C2410_IISMOD_384FS;
153         if (bi % 33 == 0) {
154                 clk_source = S3C24XX_CLKSRC_MPLL;
155                 div = 1;
156         } else {
157                 clk_source = S3C24XX_CLKSRC_PCLK;
158                 div = bi % 33;
159         }
160         pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);
161
162         clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
163         pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
164                  fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
165                  clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
166                  div, clk, err);
167
168         if ((err * 100 / rate) > 5) {
169                 printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
170                        "too different from desired (%ld%%)\n",
171                        err * 100 / rate);
172                 return -EINVAL;
173         }
174
175         ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
176                         SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
177         if (ret < 0)
178                 return ret;
179
180         ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
181                         SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
182         if (ret < 0)
183                 return ret;
184
185         ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
186                         SND_SOC_CLOCK_IN);
187         if (ret < 0)
188                 return ret;
189
190         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
191         if (ret < 0)
192                 return ret;
193
194         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
195                         S3C2410_IISMOD_32FS);
196         if (ret < 0)
197                 return ret;
198
199         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
200                         S3C24XX_PRESCALE(div, div));
201         if (ret < 0)
202                 return ret;
203
204         /* set the codec system clock for DAC and ADC */
205         ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
206                         SND_SOC_CLOCK_OUT);
207         if (ret < 0)
208                 return ret;
209
210         return 0;
211 }
212
213 static struct snd_soc_ops s3c24xx_uda134x_ops = {
214         .startup = s3c24xx_uda134x_startup,
215         .shutdown = s3c24xx_uda134x_shutdown,
216         .hw_params = s3c24xx_uda134x_hw_params,
217 };
218
219 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
220         .name = "UDA134X",
221         .stream_name = "UDA134X",
222         .codec_name = "uda134x-hifi",
223         .codec_dai_name = "uda134x-hifi",
224         .cpu_dai_name = "s3c24xx-iis",
225         .ops = &s3c24xx_uda134x_ops,
226         .platform_name  = "samsung-audio",
227 };
228
229 static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
230         .name = "S3C24XX_UDA134X",
231         .dai_link = &s3c24xx_uda134x_dai_link,
232         .num_links = 1,
233 };
234
235 static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;
236
237 static void setdat(int v)
238 {
239         gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
240 }
241
242 static void setclk(int v)
243 {
244         gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
245 }
246
247 static void setmode(int v)
248 {
249         gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
250 }
251
252 /* FIXME - This must be codec platform data but in which board file ?? */
253 static struct uda134x_platform_data s3c24xx_uda134x = {
254         .l3 = {
255                 .setdat = setdat,
256                 .setclk = setclk,
257                 .setmode = setmode,
258                 .data_hold = 1,
259                 .data_setup = 1,
260                 .clock_high = 1,
261                 .mode_hold = 1,
262                 .mode = 1,
263                 .mode_setup = 1,
264         },
265 };
266
267 static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
268 {
269         if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
270                 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
271                        "l3 %s pin already in use", fun);
272                 return -EBUSY;
273         }
274         gpio_direction_output(pin, 0);
275         return 0;
276 }
277
278 static int s3c24xx_uda134x_probe(struct platform_device *pdev)
279 {
280         int ret;
281
282         printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
283
284         s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
285         if (s3c24xx_uda134x_l3_pins == NULL) {
286                 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
287                        "unable to find platform data\n");
288                 return -ENODEV;
289         }
290         s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
291         s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
292
293         if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
294                                       "data") < 0)
295                 return -EBUSY;
296         if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
297                                       "clk") < 0) {
298                 gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
299                 return -EBUSY;
300         }
301         if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
302                                       "mode") < 0) {
303                 gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
304                 gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
305                 return -EBUSY;
306         }
307
308         s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
309         if (!s3c24xx_uda134x_snd_device) {
310                 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
311                        "Unable to register\n");
312                 return -ENOMEM;
313         }
314
315         platform_set_drvdata(s3c24xx_uda134x_snd_device,
316                              &snd_soc_s3c24xx_uda134x);
317         ret = platform_device_add(s3c24xx_uda134x_snd_device);
318         if (ret) {
319                 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
320                 platform_device_put(s3c24xx_uda134x_snd_device);
321         }
322
323         return ret;
324 }
325
326 static int s3c24xx_uda134x_remove(struct platform_device *pdev)
327 {
328         platform_device_unregister(s3c24xx_uda134x_snd_device);
329         gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
330         gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
331         gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
332         return 0;
333 }
334
335 static struct platform_driver s3c24xx_uda134x_driver = {
336         .probe  = s3c24xx_uda134x_probe,
337         .remove = s3c24xx_uda134x_remove,
338         .driver = {
339                 .name = "s3c24xx_uda134x",
340                 .owner = THIS_MODULE,
341         },
342 };
343
344 static int __init s3c24xx_uda134x_init(void)
345 {
346         return platform_driver_register(&s3c24xx_uda134x_driver);
347 }
348
349 static void __exit s3c24xx_uda134x_exit(void)
350 {
351         platform_driver_unregister(&s3c24xx_uda134x_driver);
352 }
353
354
355 module_init(s3c24xx_uda134x_init);
356 module_exit(s3c24xx_uda134x_exit);
357
358 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
359 MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
360 MODULE_LICENSE("GPL");