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