2 * Copyright (C) 2017 Samsung Electronics Co., Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
11 #include <linux/of_device.h>
12 #include <linux/module.h>
13 #include <sound/soc.h>
14 #include <sound/pcm_params.h>
19 struct snd_soc_card card
;
20 struct snd_soc_dai_link dai_link
;
22 struct clk
*clk_i2s_bus
;
26 static int odroid_card_startup(struct snd_pcm_substream
*substream
)
28 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
30 snd_pcm_hw_constraint_single(runtime
, SNDRV_PCM_HW_PARAM_CHANNELS
, 2);
34 static int odroid_card_hw_params(struct snd_pcm_substream
*substream
,
35 struct snd_pcm_hw_params
*params
)
37 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
38 struct odroid_priv
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
39 unsigned int pll_freq
, rclk_freq
;
42 switch (params_rate(params
)) {
45 pll_freq
= 131072006U;
50 pll_freq
= 180633609U;
55 pll_freq
= 196608001U;
61 ret
= clk_set_rate(priv
->clk_i2s_bus
, pll_freq
/ 2 + 1);
66 * We add 1 to the rclk_freq value in order to avoid too low clock
67 * frequency values due to the EPLL output frequency not being exact
68 * multiple of the audio sampling rate.
70 rclk_freq
= params_rate(params
) * 256 + 1;
72 ret
= clk_set_rate(priv
->sclk_i2s
, rclk_freq
);
76 if (rtd
->num_codecs
> 1) {
77 struct snd_soc_dai
*codec_dai
= rtd
->codec_dais
[1];
79 ret
= snd_soc_dai_set_sysclk(codec_dai
, 0, rclk_freq
,
88 static const struct snd_soc_ops odroid_card_ops
= {
89 .startup
= odroid_card_startup
,
90 .hw_params
= odroid_card_hw_params
,
93 static void odroid_put_codec_of_nodes(struct snd_soc_dai_link
*link
)
95 struct snd_soc_dai_link_component
*component
= link
->codecs
;
98 for (i
= 0; i
< link
->num_codecs
; i
++, component
++) {
99 if (!component
->of_node
)
101 of_node_put(component
->of_node
);
105 static int odroid_audio_probe(struct platform_device
*pdev
)
107 struct device
*dev
= &pdev
->dev
;
108 struct device_node
*cpu
, *codec
;
109 struct odroid_priv
*priv
;
110 struct snd_soc_dai_link
*link
;
111 struct snd_soc_card
*card
;
114 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
121 card
->owner
= THIS_MODULE
;
122 card
->fully_routed
= true;
124 snd_soc_card_set_drvdata(card
, priv
);
126 ret
= snd_soc_of_parse_card_name(card
, "model");
130 if (of_property_read_bool(dev
->of_node
, "samsung,audio-widgets")) {
131 ret
= snd_soc_of_parse_audio_simple_widgets(card
,
132 "samsung,audio-widgets");
137 if (of_property_read_bool(dev
->of_node
, "samsung,audio-routing")) {
138 ret
= snd_soc_of_parse_audio_routing(card
,
139 "samsung,audio-routing");
144 link
= &priv
->dai_link
;
146 link
->ops
= &odroid_card_ops
;
147 link
->dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
148 SND_SOC_DAIFMT_CBS_CFS
;
150 card
->dai_link
= &priv
->dai_link
;
153 cpu
= of_get_child_by_name(dev
->of_node
, "cpu");
154 codec
= of_get_child_by_name(dev
->of_node
, "codec");
156 link
->cpu_of_node
= of_parse_phandle(cpu
, "sound-dai", 0);
157 if (!link
->cpu_of_node
) {
158 dev_err(dev
, "Failed parsing cpu/sound-dai property\n");
162 ret
= snd_soc_of_get_dai_link_codecs(dev
, codec
, link
);
164 goto err_put_codec_n
;
166 link
->platform_of_node
= link
->cpu_of_node
;
168 link
->name
= "Primary";
169 link
->stream_name
= link
->name
;
172 priv
->sclk_i2s
= of_clk_get_by_name(link
->cpu_of_node
, "i2s_opclk1");
173 if (IS_ERR(priv
->sclk_i2s
)) {
174 ret
= PTR_ERR(priv
->sclk_i2s
);
178 priv
->clk_i2s_bus
= of_clk_get_by_name(link
->cpu_of_node
, "iis");
179 if (IS_ERR(priv
->clk_i2s_bus
)) {
180 ret
= PTR_ERR(priv
->clk_i2s_bus
);
184 ret
= devm_snd_soc_register_card(dev
, card
);
186 dev_err(dev
, "snd_soc_register_card() failed: %d\n", ret
);
187 goto err_put_clk_i2s
;
193 clk_put(priv
->clk_i2s_bus
);
195 clk_put(priv
->sclk_i2s
);
197 of_node_put(link
->cpu_of_node
);
199 odroid_put_codec_of_nodes(link
);
203 static int odroid_audio_remove(struct platform_device
*pdev
)
205 struct odroid_priv
*priv
= platform_get_drvdata(pdev
);
207 of_node_put(priv
->dai_link
.cpu_of_node
);
208 odroid_put_codec_of_nodes(&priv
->dai_link
);
209 clk_put(priv
->sclk_i2s
);
210 clk_put(priv
->clk_i2s_bus
);
215 static const struct of_device_id odroid_audio_of_match
[] = {
216 { .compatible
= "samsung,odroid-xu3-audio" },
217 { .compatible
= "samsung,odroid-xu4-audio"},
220 MODULE_DEVICE_TABLE(of
, odroid_audio_of_match
);
222 static struct platform_driver odroid_audio_driver
= {
224 .name
= "odroid-audio",
225 .of_match_table
= odroid_audio_of_match
,
226 .pm
= &snd_soc_pm_ops
,
228 .probe
= odroid_audio_probe
,
229 .remove
= odroid_audio_remove
,
231 module_platform_driver(odroid_audio_driver
);
233 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
234 MODULE_DESCRIPTION("Odroid XU3/XU4 audio support");
235 MODULE_LICENSE("GPL v2");