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 SND_SOC_DAILINK_DEFS(uda134x
,
205 DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
206 DAILINK_COMP_ARRAY(COMP_CODEC("uda134x-codec", "uda134x-hifi")),
207 DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
209 static struct snd_soc_dai_link s3c24xx_uda134x_dai_link
= {
211 .stream_name
= "UDA134X",
212 .dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
213 SND_SOC_DAIFMT_CBS_CFS
,
214 .ops
= &s3c24xx_uda134x_ops
,
215 SND_SOC_DAILINK_REG(uda134x
),
218 static struct snd_soc_card snd_soc_s3c24xx_uda134x
= {
219 .name
= "S3C24XX_UDA134X",
220 .owner
= THIS_MODULE
,
221 .dai_link
= &s3c24xx_uda134x_dai_link
,
225 static int s3c24xx_uda134x_probe(struct platform_device
*pdev
)
227 struct snd_soc_card
*card
= &snd_soc_s3c24xx_uda134x
;
228 struct s3c24xx_uda134x
*priv
;
231 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
235 mutex_init(&priv
->clk_lock
);
237 card
->dev
= &pdev
->dev
;
238 snd_soc_card_set_drvdata(card
, priv
);
240 ret
= devm_snd_soc_register_card(&pdev
->dev
, card
);
242 dev_err(&pdev
->dev
, "failed to register card: %d\n", ret
);
247 static struct platform_driver s3c24xx_uda134x_driver
= {
248 .probe
= s3c24xx_uda134x_probe
,
250 .name
= "s3c24xx_uda134x",
253 module_platform_driver(s3c24xx_uda134x_driver
);
255 MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
256 MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
257 MODULE_LICENSE("GPL");