2 * ASoC simple sound card support
4 * Copyright (C) 2012 Renesas Solutions Corp.
5 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 #include <linux/clk.h>
12 #include <linux/device.h>
13 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/string.h>
17 #include <sound/simple_card.h>
18 #include <sound/soc-dai.h>
19 #include <sound/soc.h>
21 struct simple_card_data
{
22 struct snd_soc_card snd_card
;
23 struct simple_dai_props
{
24 struct asoc_simple_dai cpu_dai
;
25 struct asoc_simple_dai codec_dai
;
28 struct snd_soc_dai_link dai_link
[]; /* dynamically allocated */
31 #define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
33 static int asoc_simple_card_hw_params(struct snd_pcm_substream
*substream
,
34 struct snd_pcm_hw_params
*params
)
36 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
37 struct snd_soc_dai
*codec_dai
= rtd
->codec_dai
;
38 struct simple_card_data
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
43 mclk
= params_rate(params
) * priv
->mclk_fs
;
44 ret
= snd_soc_dai_set_sysclk(codec_dai
, 0, mclk
,
51 static struct snd_soc_ops asoc_simple_card_ops
= {
52 .hw_params
= asoc_simple_card_hw_params
,
55 static int __asoc_simple_card_dai_init(struct snd_soc_dai
*dai
,
56 struct asoc_simple_dai
*set
)
61 ret
= snd_soc_dai_set_fmt(dai
, set
->fmt
);
62 if (ret
&& ret
!= -ENOTSUPP
) {
63 dev_err(dai
->dev
, "simple-card: set_fmt error\n");
69 ret
= snd_soc_dai_set_sysclk(dai
, 0, set
->sysclk
, 0);
70 if (ret
&& ret
!= -ENOTSUPP
) {
71 dev_err(dai
->dev
, "simple-card: set_sysclk error\n");
77 ret
= snd_soc_dai_set_tdm_slot(dai
, 0, 0,
80 if (ret
&& ret
!= -ENOTSUPP
) {
81 dev_err(dai
->dev
, "simple-card: set_tdm_slot error\n");
92 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime
*rtd
)
94 struct simple_card_data
*priv
= snd_soc_card_get_drvdata(rtd
->card
);
95 struct snd_soc_dai
*codec
= rtd
->codec_dai
;
96 struct snd_soc_dai
*cpu
= rtd
->cpu_dai
;
97 struct simple_dai_props
*dai_props
;
100 num
= rtd
- rtd
->card
->rtd
;
101 dai_props
= &priv
->dai_props
[num
];
102 ret
= __asoc_simple_card_dai_init(codec
, &dai_props
->codec_dai
);
106 ret
= __asoc_simple_card_dai_init(cpu
, &dai_props
->cpu_dai
);
114 asoc_simple_card_sub_parse_of(struct device_node
*np
,
115 struct asoc_simple_dai
*dai
,
116 struct device_node
**p_node
,
120 struct of_phandle_args args
;
126 * Get node via "sound-dai = <&phandle port>"
127 * it will be used as xxx_of_node on soc_bind_dai_link()
129 ret
= of_parse_phandle_with_args(np
, "sound-dai",
130 "#sound-dai-cells", 0, &args
);
137 *args_count
= args
.args_count
;
140 ret
= snd_soc_of_get_dai_name(np
, name
);
145 ret
= snd_soc_of_parse_tdm_slot(np
, &dai
->slots
, &dai
->slot_width
);
150 * Parse dai->sysclk come from "clocks = <&xxx>"
151 * (if system has common clock)
152 * or "system-clock-frequency = <xxx>"
153 * or device's module clock.
155 if (of_property_read_bool(np
, "clocks")) {
156 clk
= of_clk_get(np
, 0);
162 dai
->sysclk
= clk_get_rate(clk
);
163 } else if (!of_property_read_u32(np
, "system-clock-frequency", &val
)) {
166 clk
= of_clk_get(args
.np
, 0);
168 dai
->sysclk
= clk_get_rate(clk
);
174 static int asoc_simple_card_dai_link_of(struct device_node
*node
,
175 struct simple_card_data
*priv
,
176 struct snd_soc_dai_link
*dai_link
,
177 struct simple_dai_props
*dai_props
,
178 bool is_top_level_node
)
180 struct device
*dev
= simple_priv_to_dev(priv
);
181 struct device_node
*np
= NULL
;
182 struct device_node
*bitclkmaster
= NULL
;
183 struct device_node
*framemaster
= NULL
;
190 /* For single DAI link & old style of DT node */
191 if (is_top_level_node
)
192 prefix
= "simple-audio-card,";
194 daifmt
= snd_soc_of_parse_daifmt(node
, prefix
,
195 &bitclkmaster
, &framemaster
);
196 daifmt
&= ~SND_SOC_DAIFMT_MASTER_MASK
;
198 snprintf(prop
, sizeof(prop
), "%scpu", prefix
);
199 np
= of_get_child_by_name(node
, prop
);
202 dev_err(dev
, "%s: Can't find %s DT node\n", __func__
, prop
);
203 goto dai_link_of_err
;
206 ret
= asoc_simple_card_sub_parse_of(np
, &dai_props
->cpu_dai
,
207 &dai_link
->cpu_of_node
,
208 &dai_link
->cpu_dai_name
,
211 goto dai_link_of_err
;
213 dai_props
->cpu_dai
.fmt
= daifmt
;
214 switch (((np
== bitclkmaster
) << 4) | (np
== framemaster
)) {
216 dai_props
->cpu_dai
.fmt
|= SND_SOC_DAIFMT_CBS_CFS
;
219 dai_props
->cpu_dai
.fmt
|= SND_SOC_DAIFMT_CBS_CFM
;
222 dai_props
->cpu_dai
.fmt
|= SND_SOC_DAIFMT_CBM_CFS
;
225 dai_props
->cpu_dai
.fmt
|= SND_SOC_DAIFMT_CBM_CFM
;
230 snprintf(prop
, sizeof(prop
), "%scodec", prefix
);
231 np
= of_get_child_by_name(node
, prop
);
234 dev_err(dev
, "%s: Can't find %s DT node\n", __func__
, prop
);
235 goto dai_link_of_err
;
238 ret
= asoc_simple_card_sub_parse_of(np
, &dai_props
->codec_dai
,
239 &dai_link
->codec_of_node
,
240 &dai_link
->codec_dai_name
, NULL
);
242 goto dai_link_of_err
;
244 if (strlen(prefix
) && !bitclkmaster
&& !framemaster
) {
246 * No DAI link level and master setting was found
247 * from sound node level, revert back to legacy DT
248 * parsing and take the settings from codec node.
250 dev_dbg(dev
, "%s: Revert to legacy daifmt parsing\n",
252 dai_props
->cpu_dai
.fmt
= dai_props
->codec_dai
.fmt
=
253 snd_soc_of_parse_daifmt(np
, NULL
, NULL
, NULL
) |
254 (daifmt
& ~SND_SOC_DAIFMT_CLOCK_MASK
);
256 dai_props
->codec_dai
.fmt
= daifmt
;
257 switch (((np
== bitclkmaster
) << 4) | (np
== framemaster
)) {
259 dai_props
->codec_dai
.fmt
|= SND_SOC_DAIFMT_CBM_CFM
;
262 dai_props
->codec_dai
.fmt
|= SND_SOC_DAIFMT_CBM_CFS
;
265 dai_props
->codec_dai
.fmt
|= SND_SOC_DAIFMT_CBS_CFM
;
268 dai_props
->codec_dai
.fmt
|= SND_SOC_DAIFMT_CBS_CFS
;
273 if (!dai_link
->cpu_dai_name
|| !dai_link
->codec_dai_name
) {
275 goto dai_link_of_err
;
278 /* Simple Card assumes platform == cpu */
279 dai_link
->platform_of_node
= dai_link
->cpu_of_node
;
281 /* DAI link name is created from CPU/CODEC dai name */
282 name
= devm_kzalloc(dev
,
283 strlen(dai_link
->cpu_dai_name
) +
284 strlen(dai_link
->codec_dai_name
) + 2,
286 sprintf(name
, "%s-%s", dai_link
->cpu_dai_name
,
287 dai_link
->codec_dai_name
);
288 dai_link
->name
= dai_link
->stream_name
= name
;
289 dai_link
->ops
= &asoc_simple_card_ops
;
290 dai_link
->init
= asoc_simple_card_dai_init
;
292 dev_dbg(dev
, "\tname : %s\n", dai_link
->stream_name
);
293 dev_dbg(dev
, "\tcpu : %s / %04x / %d\n",
294 dai_link
->cpu_dai_name
,
295 dai_props
->cpu_dai
.fmt
,
296 dai_props
->cpu_dai
.sysclk
);
297 dev_dbg(dev
, "\tcodec : %s / %04x / %d\n",
298 dai_link
->codec_dai_name
,
299 dai_props
->codec_dai
.fmt
,
300 dai_props
->codec_dai
.sysclk
);
303 * In soc_bind_dai_link() will check cpu name after
304 * of_node matching if dai_link has cpu_dai_name.
305 * but, it will never match if name was created by
306 * fmt_single_name() remove cpu_dai_name if cpu_args
309 * fmt_multiple_name()
312 dai_link
->cpu_dai_name
= NULL
;
318 of_node_put(bitclkmaster
);
320 of_node_put(framemaster
);
324 static int asoc_simple_card_parse_of(struct device_node
*node
,
325 struct simple_card_data
*priv
)
327 struct device
*dev
= simple_priv_to_dev(priv
);
328 struct snd_soc_dai_link
*dai_link
= priv
->snd_card
.dai_link
;
329 struct simple_dai_props
*dai_props
= priv
->dai_props
;
336 /* Parse the card name from DT */
337 snd_soc_of_parse_card_name(&priv
->snd_card
, "simple-audio-card,name");
339 /* The off-codec widgets */
340 if (of_property_read_bool(node
, "simple-audio-card,widgets")) {
341 ret
= snd_soc_of_parse_audio_simple_widgets(&priv
->snd_card
,
342 "simple-audio-card,widgets");
348 if (of_property_read_bool(node
, "simple-audio-card,routing")) {
349 ret
= snd_soc_of_parse_audio_routing(&priv
->snd_card
,
350 "simple-audio-card,routing");
355 /* Factor to mclk, used in hw_params() */
356 ret
= of_property_read_u32(node
, "simple-audio-card,mclk-fs", &val
);
360 dev_dbg(dev
, "New simple-card: %s\n", priv
->snd_card
.name
?
361 priv
->snd_card
.name
: "");
363 /* Single/Muti DAI link(s) & New style of DT node */
364 if (of_get_child_by_name(node
, "simple-audio-card,dai-link")) {
365 struct device_node
*np
= NULL
;
368 for_each_child_of_node(node
, np
) {
369 dev_dbg(dev
, "\tlink %d:\n", i
);
370 ret
= asoc_simple_card_dai_link_of(np
, priv
,
381 /* For single DAI link & old style of DT node */
382 ret
= asoc_simple_card_dai_link_of(node
, priv
,
383 dai_link
, dai_props
, true);
388 if (!priv
->snd_card
.name
)
389 priv
->snd_card
.name
= priv
->snd_card
.dai_link
->name
;
394 /* Decrease the reference count of the device nodes */
395 static int asoc_simple_card_unref(struct platform_device
*pdev
)
397 struct snd_soc_card
*card
= platform_get_drvdata(pdev
);
398 struct snd_soc_dai_link
*dai_link
;
399 struct device_node
*np
;
402 for (num_links
= 0, dai_link
= card
->dai_link
;
403 num_links
< card
->num_links
;
404 num_links
++, dai_link
++) {
405 np
= (struct device_node
*) dai_link
->cpu_of_node
;
408 np
= (struct device_node
*) dai_link
->codec_of_node
;
415 static int asoc_simple_card_probe(struct platform_device
*pdev
)
417 struct simple_card_data
*priv
;
418 struct snd_soc_dai_link
*dai_link
;
419 struct device_node
*np
= pdev
->dev
.of_node
;
420 struct device
*dev
= &pdev
->dev
;
423 /* Get the number of DAI links */
424 if (np
&& of_get_child_by_name(np
, "simple-audio-card,dai-link"))
425 num_links
= of_get_child_count(np
);
429 /* Allocate the private data and the DAI link array */
430 priv
= devm_kzalloc(dev
,
431 sizeof(*priv
) + sizeof(*dai_link
) * num_links
,
436 /* Init snd_soc_card */
437 priv
->snd_card
.owner
= THIS_MODULE
;
438 priv
->snd_card
.dev
= dev
;
439 dai_link
= priv
->dai_link
;
440 priv
->snd_card
.dai_link
= dai_link
;
441 priv
->snd_card
.num_links
= num_links
;
443 /* Get room for the other properties */
444 priv
->dai_props
= devm_kzalloc(dev
,
445 sizeof(*priv
->dai_props
) * num_links
,
447 if (!priv
->dai_props
)
450 if (np
&& of_device_is_available(np
)) {
452 ret
= asoc_simple_card_parse_of(np
, priv
);
454 if (ret
!= -EPROBE_DEFER
)
455 dev_err(dev
, "parse error %d\n", ret
);
460 struct asoc_simple_card_info
*cinfo
;
462 cinfo
= dev
->platform_data
;
464 dev_err(dev
, "no info for asoc-simple-card\n");
469 !cinfo
->codec_dai
.name
||
472 !cinfo
->cpu_dai
.name
) {
473 dev_err(dev
, "insufficient asoc_simple_card_info settings\n");
477 priv
->snd_card
.name
= (cinfo
->card
) ? cinfo
->card
: cinfo
->name
;
478 dai_link
->name
= cinfo
->name
;
479 dai_link
->stream_name
= cinfo
->name
;
480 dai_link
->platform_name
= cinfo
->platform
;
481 dai_link
->codec_name
= cinfo
->codec
;
482 dai_link
->cpu_dai_name
= cinfo
->cpu_dai
.name
;
483 dai_link
->codec_dai_name
= cinfo
->codec_dai
.name
;
484 dai_link
->init
= asoc_simple_card_dai_init
;
485 memcpy(&priv
->dai_props
->cpu_dai
, &cinfo
->cpu_dai
,
486 sizeof(priv
->dai_props
->cpu_dai
));
487 memcpy(&priv
->dai_props
->codec_dai
, &cinfo
->codec_dai
,
488 sizeof(priv
->dai_props
->codec_dai
));
490 priv
->dai_props
->cpu_dai
.fmt
|= cinfo
->daifmt
;
491 priv
->dai_props
->codec_dai
.fmt
|= cinfo
->daifmt
;
494 snd_soc_card_set_drvdata(&priv
->snd_card
, priv
);
496 ret
= devm_snd_soc_register_card(&pdev
->dev
, &priv
->snd_card
);
499 asoc_simple_card_unref(pdev
);
503 static const struct of_device_id asoc_simple_of_match
[] = {
504 { .compatible
= "simple-audio-card", },
507 MODULE_DEVICE_TABLE(of
, asoc_simple_of_match
);
509 static struct platform_driver asoc_simple_card
= {
511 .name
= "asoc-simple-card",
512 .owner
= THIS_MODULE
,
513 .of_match_table
= asoc_simple_of_match
,
515 .probe
= asoc_simple_card_probe
,
518 module_platform_driver(asoc_simple_card
);
520 MODULE_ALIAS("platform:asoc-simple-card");
521 MODULE_LICENSE("GPL");
522 MODULE_DESCRIPTION("ASoC Simple Sound Card");
523 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");