2 * Modifications by Christian Pellegrin <chripell@evolware.org>
4 * s3c24xx_uda134x.c -- S3C24XX_UDA134X ALSA SoC Audio board driver
6 * Copyright 2007 Dension Audio Systems Ltd.
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.
14 #include <linux/clk.h>
15 #include <linux/gpio.h>
16 #include <linux/module.h>
18 #include <sound/soc.h>
19 #include <sound/s3c24xx_uda134x.h>
23 #include "s3c24xx-i2s.h"
25 /* #define ENFORCE_RATES 1 */
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.
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 */
46 static DEFINE_MUTEX(clk_lock);
48 static unsigned int rates[33 * 2];
50 static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
51 .count = ARRAY_SIZE(rates),
57 static struct platform_device *s3c24xx_uda134x_snd_device;
59 static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
61 struct snd_soc_pcm_runtime *rtd = substream->private_data;
62 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
64 struct snd_pcm_runtime *runtime = substream->runtime;
68 mutex_lock(&clk_lock);
69 pr_debug("%s %d\n", __func__, clk_users);
71 xtal = clk_get(&s3c24xx_uda134x_snd_device->dev, "xtal");
73 printk(KERN_ERR "%s cannot get xtal\n", __func__);
76 pclk = clk_get(cpu_dai->dev, "iis");
78 printk(KERN_ERR "%s cannot get pclk\n",
87 for (i = 0; i < 2; i++) {
88 int fs = i ? 256 : 384;
90 rates[i*33] = clk_get_rate(xtal) / fs;
91 for (j = 1; j < 33; j++)
92 rates[i*33 + j] = clk_get_rate(pclk) /
98 mutex_unlock(&clk_lock);
101 ret = snd_pcm_hw_constraint_list(runtime, 0,
102 SNDRV_PCM_HW_PARAM_RATE,
103 &hw_constraints_rates);
105 printk(KERN_ERR "%s cannot set constraints\n",
112 static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
114 mutex_lock(&clk_lock);
115 pr_debug("%s %d\n", __func__, clk_users);
117 if (clk_users == 0) {
123 mutex_unlock(&clk_lock);
126 static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
127 struct snd_pcm_hw_params *params)
129 struct snd_soc_pcm_runtime *rtd = substream->private_data;
130 struct snd_soc_dai *codec_dai = rtd->codec_dai;
131 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
132 unsigned int clk = 0;
134 int clk_source, fs_mode;
135 unsigned long rate = params_rate(params);
142 for (i = 0; i < 2*33; i++) {
143 cerr = rates[i] - rate;
152 fs_mode = S3C2410_IISMOD_256FS;
154 fs_mode = S3C2410_IISMOD_384FS;
156 clk_source = S3C24XX_CLKSRC_MPLL;
159 clk_source = S3C24XX_CLKSRC_PCLK;
162 pr_debug("%s desired rate %lu, %d\n", __func__, rate, bi);
164 clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
165 pr_debug("%s will use: %s %s %d sysclk %d err %ld\n", __func__,
166 fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
167 clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
170 if ((err * 100 / rate) > 5) {
171 printk(KERN_ERR "S3C24XX_UDA134X: effective frequency "
172 "too different from desired (%ld%%)\n",
177 ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
182 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
186 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
187 S3C2410_IISMOD_32FS);
191 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
192 S3C24XX_PRESCALE(div, div));
196 /* set the codec system clock for DAC and ADC */
197 ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
205 static struct snd_soc_ops s3c24xx_uda134x_ops = {
206 .startup = s3c24xx_uda134x_startup,
207 .shutdown = s3c24xx_uda134x_shutdown,
208 .hw_params = s3c24xx_uda134x_hw_params,
211 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
213 .stream_name = "UDA134X",
214 .codec_name = "uda134x-codec",
215 .codec_dai_name = "uda134x-hifi",
216 .cpu_dai_name = "s3c24xx-iis",
217 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
218 SND_SOC_DAIFMT_CBS_CFS,
219 .ops = &s3c24xx_uda134x_ops,
220 .platform_name = "s3c24xx-iis",
223 static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
224 .name = "S3C24XX_UDA134X",
225 .owner = THIS_MODULE,
226 .dai_link = &s3c24xx_uda134x_dai_link,
230 static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins;
232 static void setdat(int v)
234 gpio_set_value(s3c24xx_uda134x_l3_pins->l3_data, v > 0);
237 static void setclk(int v)
239 gpio_set_value(s3c24xx_uda134x_l3_pins->l3_clk, v > 0);
242 static void setmode(int v)
244 gpio_set_value(s3c24xx_uda134x_l3_pins->l3_mode, v > 0);
247 /* FIXME - This must be codec platform data but in which board file ?? */
248 static struct uda134x_platform_data s3c24xx_uda134x = {
262 static int s3c24xx_uda134x_setup_pin(int pin, char *fun)
264 if (gpio_request(pin, "s3c24xx_uda134x") < 0) {
265 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
266 "l3 %s pin already in use", fun);
269 gpio_direction_output(pin, 0);
273 static int s3c24xx_uda134x_probe(struct platform_device *pdev)
277 printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n");
279 s3c24xx_uda134x_l3_pins = pdev->dev.platform_data;
280 if (s3c24xx_uda134x_l3_pins == NULL) {
281 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
282 "unable to find platform data\n");
285 s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
286 s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
288 if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data,
291 if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,
293 gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
296 if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode,
298 gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
299 gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
303 s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1);
304 if (!s3c24xx_uda134x_snd_device) {
305 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: "
306 "Unable to register\n");
310 platform_set_drvdata(s3c24xx_uda134x_snd_device,
311 &snd_soc_s3c24xx_uda134x);
312 platform_device_add_data(s3c24xx_uda134x_snd_device, &s3c24xx_uda134x, sizeof(s3c24xx_uda134x));
313 ret = platform_device_add(s3c24xx_uda134x_snd_device);
315 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n");
316 platform_device_put(s3c24xx_uda134x_snd_device);
322 static int s3c24xx_uda134x_remove(struct platform_device *pdev)
324 platform_device_unregister(s3c24xx_uda134x_snd_device);
325 gpio_free(s3c24xx_uda134x_l3_pins->l3_data);
326 gpio_free(s3c24xx_uda134x_l3_pins->l3_clk);
327 gpio_free(s3c24xx_uda134x_l3_pins->l3_mode);
331 static struct platform_driver s3c24xx_uda134x_driver = {
332 .probe = s3c24xx_uda134x_probe,
333 .remove = s3c24xx_uda134x_remove,
335 .name = "s3c24xx_uda134x",
339 module_platform_driver(s3c24xx_uda134x_driver);
341 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
342 MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
343 MODULE_LICENSE("GPL");