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_node
*node
,
102 struct device_node
*dai_of_node
,
103 struct asoc_simple_dai
*simple_dai
)
109 * Parse dai->sysclk come from "clocks = <&xxx>"
110 * (if system has common clock)
111 * or "system-clock-frequency = <xxx>"
112 * or device's module clock.
114 clk
= of_clk_get(node
, 0);
116 simple_dai
->sysclk
= clk_get_rate(clk
);
117 simple_dai
->clk
= clk
;
118 } else if (!of_property_read_u32(node
, "system-clock-frequency", &val
)) {
119 simple_dai
->sysclk
= val
;
121 clk
= of_clk_get(dai_of_node
, 0);
123 simple_dai
->sysclk
= clk_get_rate(clk
);
128 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk
);
130 int asoc_simple_card_parse_dai(struct device_node
*node
,
131 struct device_node
**dai_of_node
,
132 const char **dai_name
,
133 const char *list_name
,
134 const char *cells_name
,
137 struct of_phandle_args args
;
144 * Get node via "sound-dai = <&phandle port>"
145 * it will be used as xxx_of_node on soc_bind_dai_link()
147 ret
= of_parse_phandle_with_args(node
, list_name
, cells_name
, 0, &args
);
153 ret
= snd_soc_of_get_dai_name(node
, dai_name
);
158 *dai_of_node
= args
.np
;
161 *is_single_link
= !args
.args_count
;
165 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai
);
167 int asoc_simple_card_init_dai(struct snd_soc_dai
*dai
,
168 struct asoc_simple_dai
*simple_dai
)
172 if (simple_dai
->sysclk
) {
173 ret
= snd_soc_dai_set_sysclk(dai
, 0, simple_dai
->sysclk
, 0);
174 if (ret
&& ret
!= -ENOTSUPP
) {
175 dev_err(dai
->dev
, "simple-card: set_sysclk error\n");
180 if (simple_dai
->slots
) {
181 ret
= snd_soc_dai_set_tdm_slot(dai
,
182 simple_dai
->tx_slot_mask
,
183 simple_dai
->rx_slot_mask
,
185 simple_dai
->slot_width
);
186 if (ret
&& ret
!= -ENOTSUPP
) {
187 dev_err(dai
->dev
, "simple-card: set_tdm_slot error\n");
194 EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai
);
196 int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link
*dai_link
)
198 /* Assumes platform == cpu */
199 if (!dai_link
->platform_of_node
)
200 dai_link
->platform_of_node
= dai_link
->cpu_of_node
;
204 EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink
);
206 void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link
*dai_link
,
210 * In soc_bind_dai_link() will check cpu name after
211 * of_node matching if dai_link has cpu_dai_name.
212 * but, it will never match if name was created by
213 * fmt_single_name() remove cpu_dai_name if cpu_args
216 * fmt_multiple_name()
219 dai_link
->cpu_dai_name
= NULL
;
221 EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu
);
223 int asoc_simple_card_clean_reference(struct snd_soc_card
*card
)
225 struct snd_soc_dai_link
*dai_link
;
228 for (num_links
= 0, dai_link
= card
->dai_link
;
229 num_links
< card
->num_links
;
230 num_links
++, dai_link
++) {
231 of_node_put(dai_link
->cpu_of_node
);
232 of_node_put(dai_link
->codec_of_node
);
236 EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference
);
238 /* Module information */
239 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
240 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
241 MODULE_LICENSE("GPL v2");