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