1 // SPDX-License-Identifier: GPL-2.0
3 // ASoC machine driver for Snow boards
6 #include <linux/module.h>
7 #include <linux/platform_device.h>
9 #include <sound/pcm_params.h>
10 #include <sound/soc.h>
14 #define FIN_PLL_RATE 24000000
16 SND_SOC_DAILINK_DEFS(links
,
17 DAILINK_COMP_ARRAY(COMP_EMPTY()),
18 DAILINK_COMP_ARRAY(COMP_EMPTY()),
19 DAILINK_COMP_ARRAY(COMP_EMPTY()));
22 struct snd_soc_dai_link dai_link
;
23 struct clk
*clk_i2s_bus
;
26 static int snow_card_hw_params(struct snd_pcm_substream
*substream
,
27 struct snd_pcm_hw_params
*params
)
29 static const unsigned int pll_rate
[] = {
30 73728000U, 67737602U, 49152000U, 45158401U, 32768001U
32 struct snd_soc_pcm_runtime
*rtd
= snd_soc_substream_to_rtd(substream
);
33 struct snow_priv
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
34 int bfs
, psr
, rfs
, bitwidth
;
35 unsigned long int rclk
;
36 long int freq
= -EINVAL
;
39 bitwidth
= snd_pcm_format_width(params_format(params
));
41 dev_err(rtd
->card
->dev
, "Invalid bit-width: %d\n", bitwidth
);
45 if (bitwidth
!= 16 && bitwidth
!= 24) {
46 dev_err(rtd
->card
->dev
, "Unsupported bit-width: %d\n", bitwidth
);
52 switch (params_rate(params
)) {
75 rclk
= params_rate(params
) * rfs
;
77 for (psr
= 8; psr
> 0; psr
/= 2) {
78 for (i
= 0; i
< ARRAY_SIZE(pll_rate
); i
++) {
79 if ((pll_rate
[i
] - rclk
* psr
) <= 2) {
86 dev_err(rtd
->card
->dev
, "Unsupported RCLK rate: %lu\n", rclk
);
90 ret
= clk_set_rate(priv
->clk_i2s_bus
, freq
);
92 dev_err(rtd
->card
->dev
, "I2S bus clock rate set failed\n");
99 static const struct snd_soc_ops snow_card_ops
= {
100 .hw_params
= snow_card_hw_params
,
103 static int snow_late_probe(struct snd_soc_card
*card
)
105 struct snd_soc_pcm_runtime
*rtd
;
106 struct snd_soc_dai
*codec_dai
;
108 rtd
= snd_soc_get_pcm_runtime(card
, &card
->dai_link
[0]);
110 /* In the multi-codec case codec_dais 0 is MAX98095 and 1 is HDMI. */
111 codec_dai
= snd_soc_rtd_to_codec(rtd
, 0);
113 /* Set the MCLK rate for the codec */
114 return snd_soc_dai_set_sysclk(codec_dai
, 0,
115 FIN_PLL_RATE
, SND_SOC_CLOCK_IN
);
118 static struct snd_soc_card snow_snd
= {
120 .owner
= THIS_MODULE
,
121 .late_probe
= snow_late_probe
,
124 static int snow_probe(struct platform_device
*pdev
)
126 struct device
*dev
= &pdev
->dev
;
127 struct snd_soc_card
*card
= &snow_snd
;
128 struct device_node
*cpu
, *codec
;
129 struct snd_soc_dai_link
*link
;
130 struct snow_priv
*priv
;
133 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
137 link
= &priv
->dai_link
;
139 link
->dai_fmt
= SND_SOC_DAIFMT_I2S
| SND_SOC_DAIFMT_NB_NF
|
140 SND_SOC_DAIFMT_CBS_CFS
;
142 link
->name
= "Primary";
143 link
->stream_name
= link
->name
;
145 link
->cpus
= links_cpus
;
146 link
->num_cpus
= ARRAY_SIZE(links_cpus
);
147 link
->codecs
= links_codecs
;
148 link
->num_codecs
= ARRAY_SIZE(links_codecs
);
149 link
->platforms
= links_platforms
;
150 link
->num_platforms
= ARRAY_SIZE(links_platforms
);
152 card
->dai_link
= link
;
156 /* Try new DT bindings with HDMI support first. */
157 cpu
= of_get_child_by_name(dev
->of_node
, "cpu");
160 link
->ops
= &snow_card_ops
;
162 link
->cpus
->of_node
= of_parse_phandle(cpu
, "sound-dai", 0);
165 if (!link
->cpus
->of_node
) {
166 dev_err(dev
, "Failed parsing cpu/sound-dai property\n");
170 codec
= of_get_child_by_name(dev
->of_node
, "codec");
171 ret
= snd_soc_of_get_dai_link_codecs(dev
, codec
, link
);
175 of_node_put(link
->cpus
->of_node
);
176 dev_err(dev
, "Failed parsing codec node\n");
180 priv
->clk_i2s_bus
= of_clk_get_by_name(link
->cpus
->of_node
,
182 if (IS_ERR(priv
->clk_i2s_bus
)) {
183 snd_soc_of_put_dai_link_codecs(link
);
184 of_node_put(link
->cpus
->of_node
);
185 return PTR_ERR(priv
->clk_i2s_bus
);
188 link
->codecs
->dai_name
= "HiFi";
190 link
->cpus
->of_node
= of_parse_phandle(dev
->of_node
,
191 "samsung,i2s-controller", 0);
192 if (!link
->cpus
->of_node
) {
193 dev_err(dev
, "i2s-controller property parse error\n");
197 link
->codecs
->of_node
= of_parse_phandle(dev
->of_node
,
198 "samsung,audio-codec", 0);
199 if (!link
->codecs
->of_node
) {
200 of_node_put(link
->cpus
->of_node
);
201 dev_err(dev
, "audio-codec property parse error\n");
206 link
->platforms
->of_node
= link
->cpus
->of_node
;
208 /* Update card-name if provided through DT, else use default name */
209 snd_soc_of_parse_card_name(card
, "samsung,model");
211 snd_soc_card_set_drvdata(card
, priv
);
213 ret
= devm_snd_soc_register_card(dev
, card
);
215 return dev_err_probe(&pdev
->dev
, ret
,
216 "snd_soc_register_card failed\n");
221 static void snow_remove(struct platform_device
*pdev
)
223 struct snow_priv
*priv
= platform_get_drvdata(pdev
);
224 struct snd_soc_dai_link
*link
= &priv
->dai_link
;
226 of_node_put(link
->cpus
->of_node
);
227 of_node_put(link
->codecs
->of_node
);
228 snd_soc_of_put_dai_link_codecs(link
);
230 clk_put(priv
->clk_i2s_bus
);
233 static const struct of_device_id snow_of_match
[] = {
234 { .compatible
= "google,snow-audio-max98090", },
235 { .compatible
= "google,snow-audio-max98091", },
236 { .compatible
= "google,snow-audio-max98095", },
239 MODULE_DEVICE_TABLE(of
, snow_of_match
);
241 static struct platform_driver snow_driver
= {
243 .name
= "snow-audio",
244 .pm
= &snd_soc_pm_ops
,
245 .of_match_table
= snow_of_match
,
248 .remove
= snow_remove
,
251 module_platform_driver(snow_driver
);
253 MODULE_DESCRIPTION("ALSA SoC Audio machine driver for Snow");
254 MODULE_LICENSE("GPL");