Version:  2.0.40 2.2.26 2.4.37 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10

Linux/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 #include <linux/module.h>
 17 
 18 #include <sound/soc.h>
 19 #include <sound/s3c24xx_uda134x.h>
 20 
 21 #include "regs-iis.h"
 22 #include "s3c24xx-i2s.h"
 23 
 24 struct s3c24xx_uda134x {
 25         struct clk *xtal;
 26         struct clk *pclk;
 27         struct mutex clk_lock;
 28         int clk_users;
 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 unsigned int rates[33 * 2];
 46 #ifdef ENFORCE_RATES
 47 static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
 48         .count  = ARRAY_SIZE(rates),
 49         .list   = rates,
 50         .mask   = 0,
 51 };
 52 #endif
 53 
 54 static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
 55 {
 56         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 57         struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
 58         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
 59         int ret = 0;
 60 
 61         mutex_lock(&priv->clk_lock);
 62 
 63         if (priv->clk_users == 0) {
 64                 priv->xtal = clk_get(rtd->dev, "xtal");
 65                 if (IS_ERR(priv->xtal)) {
 66                         dev_err(rtd->dev, "%s cannot get xtal\n", __func__);
 67                         ret = PTR_ERR(priv->xtal);
 68                 } else {
 69                         priv->pclk = clk_get(cpu_dai->dev, "iis");
 70                         if (IS_ERR(priv->pclk)) {
 71                                 dev_err(rtd->dev, "%s cannot get pclk\n",
 72                                         __func__);
 73                                 clk_put(priv->xtal);
 74                                 ret = PTR_ERR(priv->pclk);
 75                         }
 76                 }
 77                 if (!ret) {
 78                         int i, j;
 79 
 80                         for (i = 0; i < 2; i++) {
 81                                 int fs = i ? 256 : 384;
 82 
 83                                 rates[i*33] = clk_get_rate(priv->xtal) / fs;
 84                                 for (j = 1; j < 33; j++)
 85                                         rates[i*33 + j] = clk_get_rate(priv->pclk) /
 86                                                 (j * fs);
 87                         }
 88                 }
 89         }
 90         priv->clk_users += 1;
 91         mutex_unlock(&priv->clk_lock);
 92 
 93         if (!ret) {
 94 #ifdef ENFORCE_RATES
 95                 ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
 96                                                  SNDRV_PCM_HW_PARAM_RATE,
 97                                                  &hw_constraints_rates);
 98                 if (ret < 0)
 99                         dev_err(rtd->dev, "%s cannot set constraints\n",
100                                 __func__);
101 #endif
102         }
103         return ret;
104 }
105 
106 static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
107 {
108         struct snd_soc_pcm_runtime *rtd = substream->private_data;
109         struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
110 
111         mutex_lock(&priv->clk_lock);
112         priv->clk_users -= 1;
113         if (priv->clk_users == 0) {
114                 clk_put(priv->xtal);
115                 priv->xtal = NULL;
116                 clk_put(priv->pclk);
117                 priv->pclk = NULL;
118         }
119         mutex_unlock(&priv->clk_lock);
120 }
121 
122 static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
123                                         struct snd_pcm_hw_params *params)
124 {
125         struct snd_soc_pcm_runtime *rtd = substream->private_data;
126         struct snd_soc_dai *codec_dai = rtd->codec_dai;
127         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
128         unsigned int clk = 0;
129         int ret = 0;
130         int clk_source, fs_mode;
131         unsigned long rate = params_rate(params);
132         long err, cerr;
133         unsigned int div;
134         int i, bi;
135 
136         err = 999999;
137         bi = 0;
138         for (i = 0; i < 2*33; i++) {
139                 cerr = rates[i] - rate;
140                 if (cerr < 0)
141                         cerr = -cerr;
142                 if (cerr < err) {
143                         err = cerr;
144                         bi = i;
145                 }
146         }
147         if (bi / 33 == 1)
148                 fs_mode = S3C2410_IISMOD_256FS;
149         else
150                 fs_mode = S3C2410_IISMOD_384FS;
151         if (bi % 33 == 0) {
152                 clk_source = S3C24XX_CLKSRC_MPLL;
153                 div = 1;
154         } else {
155                 clk_source = S3C24XX_CLKSRC_PCLK;
156                 div = bi % 33;
157         }
158 
159         dev_dbg(rtd->dev, "%s desired rate %lu, %d\n", __func__, rate, bi);
160 
161         clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
162 
163         dev_dbg(rtd->dev, "%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                 dev_err(rtd->dev, "effective frequency too different "
170                                   "from desired (%ld%%)\n", err * 100 / rate);
171                 return -EINVAL;
172         }
173 
174         ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
175                         SND_SOC_CLOCK_IN);
176         if (ret < 0)
177                 return ret;
178 
179         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
180         if (ret < 0)
181                 return ret;
182 
183         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
184                         S3C2410_IISMOD_32FS);
185         if (ret < 0)
186                 return ret;
187 
188         ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
189                         S3C24XX_PRESCALE(div, div));
190         if (ret < 0)
191                 return ret;
192 
193         /* set the codec system clock for DAC and ADC */
194         ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
195                         SND_SOC_CLOCK_OUT);
196         if (ret < 0)
197                 return ret;
198 
199         return 0;
200 }
201 
202 static struct snd_soc_ops s3c24xx_uda134x_ops = {
203         .startup = s3c24xx_uda134x_startup,
204         .shutdown = s3c24xx_uda134x_shutdown,
205         .hw_params = s3c24xx_uda134x_hw_params,
206 };
207 
208 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
209         .name = "UDA134X",
210         .stream_name = "UDA134X",
211         .codec_name = "uda134x-codec",
212         .codec_dai_name = "uda134x-hifi",
213         .cpu_dai_name = "s3c24xx-iis",
214         .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
215                    SND_SOC_DAIFMT_CBS_CFS,
216         .ops = &s3c24xx_uda134x_ops,
217         .platform_name  = "s3c24xx-iis",
218 };
219 
220 static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
221         .name = "S3C24XX_UDA134X",
222         .owner = THIS_MODULE,
223         .dai_link = &s3c24xx_uda134x_dai_link,
224         .num_links = 1,
225 };
226 
227 static int s3c24xx_uda134x_probe(struct platform_device *pdev)
228 {
229         struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;
230         struct s3c24xx_uda134x *priv;
231         int ret;
232 
233         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
234         if (!priv)
235                 return -ENOMEM;
236 
237         mutex_init(&priv->clk_lock);
238 
239         card->dev = &pdev->dev;
240         platform_set_drvdata(pdev, card);
241         snd_soc_card_set_drvdata(card, priv);
242 
243         ret = devm_snd_soc_register_card(&pdev->dev, card);
244         if (ret)
245                 dev_err(&pdev->dev, "failed to register card: %d\n", ret);
246 
247         return ret;
248 }
249 
250 static struct platform_driver s3c24xx_uda134x_driver = {
251         .probe  = s3c24xx_uda134x_probe,
252         .driver = {
253                 .name = "s3c24xx_uda134x",
254         },
255 };
256 module_platform_driver(s3c24xx_uda134x_driver);
257 
258 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
259 MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
260 MODULE_LICENSE("GPL");
261 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us