4 * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
10 #include <linux/clk.h>
11 #include <linux/module.h>
13 #include <sound/simple_card_utils.h>
15 int asoc_simple_card_parse_daifmt(struct device
*dev
,
16 struct device_node
*node
,
17 struct device_node
*codec
,
21 struct device_node
*bitclkmaster
= NULL
;
22 struct device_node
*framemaster
= NULL
;
23 int prefix_len
= prefix
? strlen(prefix
) : 0;
26 daifmt
= snd_soc_of_parse_daifmt(node
, prefix
,
27 &bitclkmaster
, &framemaster
);
28 daifmt
&= ~SND_SOC_DAIFMT_MASTER_MASK
;
30 if (prefix_len
&& !bitclkmaster
&& !framemaster
) {
32 * No dai-link level and master setting was not found from
33 * sound node level, revert back to legacy DT parsing and
34 * take the settings from codec node.
36 dev_dbg(dev
, "Revert to legacy daifmt parsing\n");
38 daifmt
= snd_soc_of_parse_daifmt(codec
, NULL
, NULL
, NULL
) |
39 (daifmt
& ~SND_SOC_DAIFMT_CLOCK_MASK
);
41 if (codec
== bitclkmaster
)
42 daifmt
|= (codec
== framemaster
) ?
43 SND_SOC_DAIFMT_CBM_CFM
: SND_SOC_DAIFMT_CBM_CFS
;
45 daifmt
|= (codec
== framemaster
) ?
46 SND_SOC_DAIFMT_CBS_CFM
: SND_SOC_DAIFMT_CBS_CFS
;
49 of_node_put(bitclkmaster
);
50 of_node_put(framemaster
);
56 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt
);
58 int asoc_simple_card_set_dailink_name(struct device
*dev
,
59 struct snd_soc_dai_link
*dai_link
,
67 name
= devm_kvasprintf(dev
, GFP_KERNEL
, fmt
, ap
);
73 dai_link
->name
= name
;
74 dai_link
->stream_name
= name
;
79 EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name
);
81 int asoc_simple_card_parse_card_name(struct snd_soc_card
*card
,
87 snprintf(prop
, sizeof(prop
), "%sname", prefix
);
89 /* Parse the card name from DT */
90 ret
= snd_soc_of_parse_card_name(card
, prop
);
94 if (!card
->name
&& card
->dai_link
)
95 card
->name
= card
->dai_link
->name
;
99 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name
);
101 int asoc_simple_card_parse_clk(struct device
*dev
,
102 struct device_node
*node
,
103 struct device_node
*dai_of_node
,
104 struct asoc_simple_dai
*simple_dai
)
110 * Parse dai->sysclk come from "clocks = <&xxx>"
111 * (if system has common clock)
112 * or "system-clock-frequency = <xxx>"
113 * or device's module clock.
115 clk
= devm_get_clk_from_child(dev
, node
, NULL
);
117 simple_dai
->sysclk
= clk_get_rate(clk
);
118 simple_dai
->clk
= clk
;
119 } else if (!of_property_read_u32(node
, "system-clock-frequency", &val
)) {
120 simple_dai
->sysclk
= val
;
122 clk
= devm_get_clk_from_child(dev
, dai_of_node
, NULL
);
124 simple_dai
->sysclk
= clk_get_rate(clk
);
129 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk
);
131 int asoc_simple_card_parse_dai(struct device_node
*node
,
132 struct device_node
**dai_of_node
,
133 const char **dai_name
,
134 const char *list_name
,
135 const char *cells_name
,
138 struct of_phandle_args args
;
145 * Get node via "sound-dai = <&phandle port>"
146 * it will be used as xxx_of_node on soc_bind_dai_link()
148 ret
= of_parse_phandle_with_args(node
, list_name
, cells_name
, 0, &args
);
154 ret
= snd_soc_of_get_dai_name(node
, dai_name
);
159 *dai_of_node
= args
.np
;
162 *is_single_link
= !args
.args_count
;
166 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai
);
168 int asoc_simple_card_init_dai(struct snd_soc_dai
*dai
,
169 struct asoc_simple_dai
*simple_dai
)
173 if (simple_dai
->sysclk
) {
174 ret
= snd_soc_dai_set_sysclk(dai
, 0, simple_dai
->sysclk
, 0);
175 if (ret
&& ret
!= -ENOTSUPP
) {
176 dev_err(dai
->dev
, "simple-card: set_sysclk error\n");
181 if (simple_dai
->slots
) {
182 ret
= snd_soc_dai_set_tdm_slot(dai
,
183 simple_dai
->tx_slot_mask
,
184 simple_dai
->rx_slot_mask
,
186 simple_dai
->slot_width
);
187 if (ret
&& ret
!= -ENOTSUPP
) {
188 dev_err(dai
->dev
, "simple-card: set_tdm_slot error\n");
195 EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai
);
197 int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link
*dai_link
)
199 /* Assumes platform == cpu */
200 if (!dai_link
->platform_of_node
)
201 dai_link
->platform_of_node
= dai_link
->cpu_of_node
;
205 EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink
);
207 void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link
*dai_link
,
211 * In soc_bind_dai_link() will check cpu name after
212 * of_node matching if dai_link has cpu_dai_name.
213 * but, it will never match if name was created by
214 * fmt_single_name() remove cpu_dai_name if cpu_args
217 * fmt_multiple_name()
220 dai_link
->cpu_dai_name
= NULL
;
222 EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu
);
224 int asoc_simple_card_clean_reference(struct snd_soc_card
*card
)
226 struct snd_soc_dai_link
*dai_link
;
229 for (num_links
= 0, dai_link
= card
->dai_link
;
230 num_links
< card
->num_links
;
231 num_links
++, dai_link
++) {
232 of_node_put(dai_link
->cpu_of_node
);
233 of_node_put(dai_link
->codec_of_node
);
237 EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference
);
239 /* Module information */
240 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
241 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
242 MODULE_LICENSE("GPL v2");