1 // SPDX-License-Identifier: GPL-2.0
3 // Copyright (C) 2017 Samsung Electronics Co., Ltd.
6 #include <linux/clk-provider.h>
8 #include <linux/module.h>
10 #include <sound/pcm_params.h>
15 struct snd_soc_card card
;
16 struct clk
*clk_i2s_bus
;
19 /* Spinlock protecting fields below */
21 unsigned int be_sample_rate
;
25 static int odroid_card_fe_startup(struct snd_pcm_substream
*substream
)
27 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
29 snd_pcm_hw_constraint_single(runtime
, SNDRV_PCM_HW_PARAM_CHANNELS
, 2);
34 static int odroid_card_fe_hw_params(struct snd_pcm_substream
*substream
,
35 struct snd_pcm_hw_params
*params
)
37 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
38 struct odroid_priv
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
42 spin_lock_irqsave(&priv
->lock
, flags
);
43 if (priv
->be_active
&& priv
->be_sample_rate
!= params_rate(params
))
45 spin_unlock_irqrestore(&priv
->lock
, flags
);
50 static const struct snd_soc_ops odroid_card_fe_ops
= {
51 .startup
= odroid_card_fe_startup
,
52 .hw_params
= odroid_card_fe_hw_params
,
55 static int odroid_card_be_hw_params(struct snd_pcm_substream
*substream
,
56 struct snd_pcm_hw_params
*params
)
58 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
59 struct odroid_priv
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
60 unsigned int pll_freq
, rclk_freq
, rfs
;
64 switch (params_rate(params
)) {
66 pll_freq
= 196608001U;
71 pll_freq
= 180633609U;
77 pll_freq
= 196608001U;
84 ret
= clk_set_rate(priv
->clk_i2s_bus
, pll_freq
/ 2 + 1);
89 * We add 2 to the rclk_freq value in order to avoid too low clock
90 * frequency values due to the EPLL output frequency not being exact
91 * multiple of the audio sampling rate.
93 rclk_freq
= params_rate(params
) * rfs
+ 2;
95 ret
= clk_set_rate(priv
->sclk_i2s
, rclk_freq
);
99 if (rtd
->dai_link
->num_codecs
> 1) {
100 struct snd_soc_dai
*codec_dai
= snd_soc_rtd_to_codec(rtd
, 1);
102 ret
= snd_soc_dai_set_sysclk(codec_dai
, 0, rclk_freq
,
108 spin_lock_irqsave(&priv
->lock
, flags
);
109 priv
->be_sample_rate
= params_rate(params
);
110 spin_unlock_irqrestore(&priv
->lock
, flags
);
115 static int odroid_card_be_trigger(struct snd_pcm_substream
*substream
, int cmd
)
117 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
118 struct odroid_priv
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
121 spin_lock_irqsave(&priv
->lock
, flags
);
124 case SNDRV_PCM_TRIGGER_START
:
125 case SNDRV_PCM_TRIGGER_RESUME
:
126 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
127 priv
->be_active
= true;
130 case SNDRV_PCM_TRIGGER_STOP
:
131 case SNDRV_PCM_TRIGGER_SUSPEND
:
132 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
133 priv
->be_active
= false;
137 spin_unlock_irqrestore(&priv
->lock
, flags
);
142 static const struct snd_soc_ops odroid_card_be_ops
= {
143 .hw_params
= odroid_card_be_hw_params
,
144 .trigger
= odroid_card_be_trigger
,
147 /* DAPM routes for backward compatibility with old DTS */
148 static const struct snd_soc_dapm_route odroid_dapm_routes
[] = {
149 { "I2S Playback", NULL
, "Mixer DAI TX" },
150 { "HiFi Playback", NULL
, "Mixer DAI TX" },
153 SND_SOC_DAILINK_DEFS(primary
,
154 DAILINK_COMP_ARRAY(COMP_EMPTY()),
155 DAILINK_COMP_ARRAY(COMP_DUMMY()),
156 DAILINK_COMP_ARRAY(COMP_PLATFORM("3830000.i2s")));
158 SND_SOC_DAILINK_DEFS(mixer
,
159 DAILINK_COMP_ARRAY(COMP_DUMMY()),
160 DAILINK_COMP_ARRAY(COMP_EMPTY()));
162 SND_SOC_DAILINK_DEFS(secondary
,
163 DAILINK_COMP_ARRAY(COMP_EMPTY()),
164 DAILINK_COMP_ARRAY(COMP_DUMMY()),
165 DAILINK_COMP_ARRAY(COMP_PLATFORM("3830000.i2s-sec")));
167 static struct snd_soc_dai_link odroid_card_dais
[] = {
169 /* Primary FE <-> BE link */
170 .ops
= &odroid_card_fe_ops
,
172 .stream_name
= "Primary",
175 SND_SOC_DAILINK_REG(primary
),
177 /* BE <-> CODECs link */
179 .ops
= &odroid_card_be_ops
,
182 .dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
183 SND_SOC_DAIFMT_CBS_CFS
,
184 SND_SOC_DAILINK_REG(mixer
),
186 /* Secondary FE <-> BE link */
187 .ops
= &odroid_card_fe_ops
,
189 .stream_name
= "Secondary",
192 SND_SOC_DAILINK_REG(secondary
),
196 static int odroid_audio_probe(struct platform_device
*pdev
)
198 struct device
*dev
= &pdev
->dev
;
199 struct device_node
*cpu_dai
= NULL
;
200 struct device_node
*cpu
, *codec
;
201 struct odroid_priv
*priv
;
202 struct snd_soc_card
*card
;
203 struct snd_soc_dai_link
*link
, *codec_link
;
204 int num_pcms
, ret
, i
;
206 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
213 card
->owner
= THIS_MODULE
;
214 card
->fully_routed
= true;
216 spin_lock_init(&priv
->lock
);
217 snd_soc_card_set_drvdata(card
, priv
);
219 ret
= snd_soc_of_parse_card_name(card
, "model");
223 if (of_property_present(dev
->of_node
, "samsung,audio-widgets")) {
224 ret
= snd_soc_of_parse_audio_simple_widgets(card
,
225 "samsung,audio-widgets");
231 if (of_property_present(dev
->of_node
, "audio-routing"))
232 ret
= snd_soc_of_parse_audio_routing(card
, "audio-routing");
233 else if (of_property_present(dev
->of_node
, "samsung,audio-routing"))
234 ret
= snd_soc_of_parse_audio_routing(card
, "samsung,audio-routing");
238 card
->dai_link
= odroid_card_dais
;
239 card
->num_links
= ARRAY_SIZE(odroid_card_dais
);
241 cpu
= of_get_child_by_name(dev
->of_node
, "cpu");
242 codec
= of_get_child_by_name(dev
->of_node
, "codec");
243 link
= card
->dai_link
;
244 codec_link
= &card
->dai_link
[1];
247 * For backwards compatibility create the secondary CPU DAI link only
248 * if there are 2 CPU DAI entries in the cpu sound-dai property in DT.
249 * Also add required DAPM routes not available in old DTS.
251 num_pcms
= of_count_phandle_with_args(cpu
, "sound-dai",
254 card
->dapm_routes
= odroid_dapm_routes
;
255 card
->num_dapm_routes
= ARRAY_SIZE(odroid_dapm_routes
);
259 for (i
= 0; i
< num_pcms
; i
++, link
+= 2) {
260 ret
= snd_soc_of_get_dai_name(cpu
, &link
->cpus
->dai_name
, i
);
265 cpu_dai
= of_parse_phandle(cpu
, "sound-dai", 0);
274 ret
= snd_soc_of_get_dai_link_codecs(dev
, codec
, codec_link
);
276 goto err_put_cpu_dai
;
278 /* Set capture capability only for boards with the MAX98090 CODEC */
279 if (codec_link
->num_codecs
> 1) {
280 card
->dai_link
[0].playback_only
= 0;
281 card
->dai_link
[1].playback_only
= 0;
284 priv
->sclk_i2s
= of_clk_get_by_name(cpu_dai
, "i2s_opclk1");
285 if (IS_ERR(priv
->sclk_i2s
)) {
286 ret
= PTR_ERR(priv
->sclk_i2s
);
287 goto err_put_cpu_dai
;
290 priv
->clk_i2s_bus
= of_clk_get_by_name(cpu_dai
, "iis");
291 if (IS_ERR(priv
->clk_i2s_bus
)) {
292 ret
= PTR_ERR(priv
->clk_i2s_bus
);
296 ret
= devm_snd_soc_register_card(dev
, card
);
298 dev_err_probe(dev
, ret
, "snd_soc_register_card() failed\n");
299 goto err_put_clk_i2s
;
302 of_node_put(cpu_dai
);
307 clk_put(priv
->clk_i2s_bus
);
309 clk_put(priv
->sclk_i2s
);
311 of_node_put(cpu_dai
);
312 snd_soc_of_put_dai_link_codecs(codec_link
);
318 static void odroid_audio_remove(struct platform_device
*pdev
)
320 struct odroid_priv
*priv
= platform_get_drvdata(pdev
);
322 snd_soc_of_put_dai_link_codecs(&priv
->card
.dai_link
[1]);
323 clk_put(priv
->sclk_i2s
);
324 clk_put(priv
->clk_i2s_bus
);
327 static const struct of_device_id odroid_audio_of_match
[] = {
328 { .compatible
= "hardkernel,odroid-xu3-audio" },
329 { .compatible
= "hardkernel,odroid-xu4-audio" },
330 { .compatible
= "samsung,odroid-xu3-audio" },
331 { .compatible
= "samsung,odroid-xu4-audio" },
334 MODULE_DEVICE_TABLE(of
, odroid_audio_of_match
);
336 static struct platform_driver odroid_audio_driver
= {
338 .name
= "odroid-audio",
339 .of_match_table
= odroid_audio_of_match
,
340 .pm
= &snd_soc_pm_ops
,
342 .probe
= odroid_audio_probe
,
343 .remove
= odroid_audio_remove
,
345 module_platform_driver(odroid_audio_driver
);
347 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
348 MODULE_DESCRIPTION("Odroid XU3/XU4 audio support");
349 MODULE_LICENSE("GPL v2");