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
;
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
->pll
, pll_freq
+ 1);
65 rclk_freq
= params_rate(params
) * 256 * 4;
67 ret
= clk_set_rate(priv
->rclk
, rclk_freq
);
71 if (rtd
->num_codecs
> 1) {
72 struct snd_soc_dai
*codec_dai
= rtd
->codec_dais
[1];
74 ret
= snd_soc_dai_set_sysclk(codec_dai
, 0, rclk_freq
,
83 static const struct snd_soc_ops odroid_card_ops
= {
84 .startup
= odroid_card_startup
,
85 .hw_params
= odroid_card_hw_params
,
88 static void odroid_put_codec_of_nodes(struct snd_soc_dai_link
*link
)
90 struct snd_soc_dai_link_component
*component
= link
->codecs
;
93 for (i
= 0; i
< link
->num_codecs
; i
++, component
++) {
94 if (!component
->of_node
)
96 of_node_put(component
->of_node
);
100 static int odroid_audio_probe(struct platform_device
*pdev
)
102 struct device
*dev
= &pdev
->dev
;
103 struct device_node
*cpu
, *codec
;
104 struct odroid_priv
*priv
;
105 struct snd_soc_dai_link
*link
;
106 struct snd_soc_card
*card
;
109 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
116 card
->owner
= THIS_MODULE
;
117 card
->fully_routed
= true;
119 snd_soc_card_set_drvdata(card
, priv
);
121 priv
->pll
= devm_clk_get(dev
, "epll");
122 if (IS_ERR(priv
->pll
))
123 return PTR_ERR(priv
->pll
);
125 priv
->rclk
= devm_clk_get(dev
, "i2s_rclk");
126 if (IS_ERR(priv
->rclk
))
127 return PTR_ERR(priv
->rclk
);
129 ret
= snd_soc_of_parse_card_name(card
, "model");
133 if (of_property_read_bool(dev
->of_node
, "samsung,audio-widgets")) {
134 ret
= snd_soc_of_parse_audio_simple_widgets(card
,
135 "samsung,audio-widgets");
140 if (of_property_read_bool(dev
->of_node
, "samsung,audio-routing")) {
141 ret
= snd_soc_of_parse_audio_routing(card
,
142 "samsung,audio-routing");
147 link
= &priv
->dai_link
;
149 link
->ops
= &odroid_card_ops
;
150 link
->dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
151 SND_SOC_DAIFMT_CBS_CFS
;
153 card
->dai_link
= &priv
->dai_link
;
156 cpu
= of_get_child_by_name(dev
->of_node
, "cpu");
157 codec
= of_get_child_by_name(dev
->of_node
, "codec");
159 link
->cpu_of_node
= of_parse_phandle(cpu
, "sound-dai", 0);
160 if (!link
->cpu_of_node
) {
161 dev_err(dev
, "Failed parsing cpu/sound-dai property\n");
165 ret
= snd_soc_of_get_dai_link_codecs(dev
, codec
, link
);
167 goto err_put_codec_n
;
169 link
->platform_of_node
= link
->cpu_of_node
;
171 link
->name
= "Primary";
172 link
->stream_name
= link
->name
;
174 ret
= devm_snd_soc_register_card(dev
, card
);
176 dev_err(dev
, "snd_soc_register_card() failed: %d\n", ret
);
183 of_node_put(link
->cpu_of_node
);
185 odroid_put_codec_of_nodes(link
);
189 static int odroid_audio_remove(struct platform_device
*pdev
)
191 struct odroid_priv
*priv
= platform_get_drvdata(pdev
);
193 of_node_put(priv
->dai_link
.cpu_of_node
);
194 odroid_put_codec_of_nodes(&priv
->dai_link
);
199 static const struct of_device_id odroid_audio_of_match
[] = {
200 { .compatible
= "samsung,odroid-xu3-audio" },
201 { .compatible
= "samsung,odroid-xu4-audio"},
204 MODULE_DEVICE_TABLE(of
, odroid_audio_of_match
);
206 static struct platform_driver odroid_audio_driver
= {
208 .name
= "odroid-audio",
209 .of_match_table
= odroid_audio_of_match
,
210 .pm
= &snd_soc_pm_ops
,
212 .probe
= odroid_audio_probe
,
213 .remove
= odroid_audio_remove
,
215 module_platform_driver(odroid_audio_driver
);
217 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
218 MODULE_DESCRIPTION("Odroid XU3/XU4 audio support");
219 MODULE_LICENSE("GPL v2");