1 // SPDX-License-Identifier: GPL-2.0
3 // Modifications by Christian Pellegrin <chripell@evolware.org>
5 // s3c24xx_uda134x.c - S3C24XX_UDA134X ALSA SoC Audio board driver
7 // Copyright 2007 Dension Audio Systems Ltd.
8 // Author: Zoltan Devai
10 #include <linux/clk.h>
11 #include <linux/gpio.h>
12 #include <linux/module.h>
14 #include <sound/soc.h>
15 #include <sound/s3c24xx_uda134x.h>
18 #include "s3c24xx-i2s.h"
20 struct s3c24xx_uda134x {
23 struct mutex clk_lock;
27 /* #define ENFORCE_RATES 1 */
29 Unfortunately the S3C24XX in master mode has a limited capacity of
30 generating the clock for the codec. If you define this only rates
31 that are really available will be enforced. But be careful, most
32 user level application just want the usual sampling frequencies (8,
33 11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
34 operation for embedded systems. So if you aren't very lucky or your
35 hardware engineer wasn't very forward-looking it's better to leave
36 this undefined. If you do so an approximate value for the requested
37 sampling rate in the range -/+ 5% will be chosen. If this in not
38 possible an error will be returned.
41 static unsigned int rates[33 * 2];
43 static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
44 .count = ARRAY_SIZE(rates),
50 static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
52 struct snd_soc_pcm_runtime *rtd = substream->private_data;
53 struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
54 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
57 mutex_lock(&priv->clk_lock);
59 if (priv->clk_users == 0) {
60 priv->xtal = clk_get(rtd->dev, "xtal");
61 if (IS_ERR(priv->xtal)) {
62 dev_err(rtd->dev, "%s cannot get xtal\n", __func__);
63 ret = PTR_ERR(priv->xtal);
65 priv->pclk = clk_get(cpu_dai->dev, "iis");
66 if (IS_ERR(priv->pclk)) {
67 dev_err(rtd->dev, "%s cannot get pclk\n",
70 ret = PTR_ERR(priv->pclk);
76 for (i = 0; i < 2; i++) {
77 int fs = i ? 256 : 384;
79 rates[i*33] = clk_get_rate(priv->xtal) / fs;
80 for (j = 1; j < 33; j++)
81 rates[i*33 + j] = clk_get_rate(priv->pclk) /
87 mutex_unlock(&priv->clk_lock);
91 ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
92 SNDRV_PCM_HW_PARAM_RATE,
93 &hw_constraints_rates);
95 dev_err(rtd->dev, "%s cannot set constraints\n",
102 static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
104 struct snd_soc_pcm_runtime *rtd = substream->private_data;
105 struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
107 mutex_lock(&priv->clk_lock);
108 priv->clk_users -= 1;
109 if (priv->clk_users == 0) {
115 mutex_unlock(&priv->clk_lock);
118 static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
119 struct snd_pcm_hw_params *params)
121 struct snd_soc_pcm_runtime *rtd = substream->private_data;
122 struct snd_soc_dai *codec_dai = rtd->codec_dai;
123 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
124 unsigned int clk = 0;
126 int clk_source, fs_mode;
127 unsigned long rate = params_rate(params);
134 for (i = 0; i < 2*33; i++) {
135 cerr = rates[i] - rate;
144 fs_mode = S3C2410_IISMOD_256FS;
146 fs_mode = S3C2410_IISMOD_384FS;
148 clk_source = S3C24XX_CLKSRC_MPLL;
151 clk_source = S3C24XX_CLKSRC_PCLK;
155 dev_dbg(rtd->dev, "%s desired rate %lu, %d\n", __func__, rate, bi);
157 clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
159 dev_dbg(rtd->dev, "%s will use: %s %s %d sysclk %d err %ld\n", __func__,
160 fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
161 clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
164 if ((err * 100 / rate) > 5) {
165 dev_err(rtd->dev, "effective frequency too different "
166 "from desired (%ld%%)\n", err * 100 / rate);
170 ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
175 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
179 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
180 S3C2410_IISMOD_32FS);
184 ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
185 S3C24XX_PRESCALE(div, div));
189 /* set the codec system clock for DAC and ADC */
190 ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
198 static const struct snd_soc_ops s3c24xx_uda134x_ops = {
199 .startup = s3c24xx_uda134x_startup,
200 .shutdown = s3c24xx_uda134x_shutdown,
201 .hw_params = s3c24xx_uda134x_hw_params,
204 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
206 .stream_name = "UDA134X",
207 .codec_name = "uda134x-codec",
208 .codec_dai_name = "uda134x-hifi",
209 .cpu_dai_name = "s3c24xx-iis",
210 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
211 SND_SOC_DAIFMT_CBS_CFS,
212 .ops = &s3c24xx_uda134x_ops,
213 .platform_name = "s3c24xx-iis",
216 static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
217 .name = "S3C24XX_UDA134X",
218 .owner = THIS_MODULE,
219 .dai_link = &s3c24xx_uda134x_dai_link,
223 static int s3c24xx_uda134x_probe(struct platform_device *pdev)
225 struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;
226 struct s3c24xx_uda134x *priv;
229 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
233 mutex_init(&priv->clk_lock);
235 card->dev = &pdev->dev;
236 snd_soc_card_set_drvdata(card, priv);
238 ret = devm_snd_soc_register_card(&pdev->dev, card);
240 dev_err(&pdev->dev, "failed to register card: %d\n", ret);
245 static struct platform_driver s3c24xx_uda134x_driver = {
246 .probe = s3c24xx_uda134x_probe,
248 .name = "s3c24xx_uda134x",
251 module_platform_driver(s3c24xx_uda134x_driver);
253 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
254 MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
255 MODULE_LICENSE("GPL");