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 <linux/of_graph.h>
14 #include <sound/simple_card_utils.h>
16 void asoc_simple_card_convert_fixup(struct asoc_simple_card_data
*data
,
17 struct snd_pcm_hw_params
*params
)
19 struct snd_interval
*rate
= hw_param_interval(params
,
20 SNDRV_PCM_HW_PARAM_RATE
);
21 struct snd_interval
*channels
= hw_param_interval(params
,
22 SNDRV_PCM_HW_PARAM_CHANNELS
);
24 if (data
->convert_rate
)
26 rate
->max
= data
->convert_rate
;
28 if (data
->convert_channels
)
30 channels
->max
= data
->convert_channels
;
32 EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup
);
34 void asoc_simple_card_parse_convert(struct device
*dev
, char *prefix
,
35 struct asoc_simple_card_data
*data
)
37 struct device_node
*np
= dev
->of_node
;
43 /* sampling rate convert */
44 snprintf(prop
, sizeof(prop
), "%s%s", prefix
, "convert-rate");
45 of_property_read_u32(np
, prop
, &data
->convert_rate
);
47 /* channels transfer */
48 snprintf(prop
, sizeof(prop
), "%s%s", prefix
, "convert-channels");
49 of_property_read_u32(np
, prop
, &data
->convert_channels
);
51 dev_dbg(dev
, "convert_rate %d\n", data
->convert_rate
);
52 dev_dbg(dev
, "convert_channels %d\n", data
->convert_channels
);
54 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_convert
);
56 int asoc_simple_card_parse_daifmt(struct device
*dev
,
57 struct device_node
*node
,
58 struct device_node
*codec
,
62 struct device_node
*bitclkmaster
= NULL
;
63 struct device_node
*framemaster
= NULL
;
66 daifmt
= snd_soc_of_parse_daifmt(node
, prefix
,
67 &bitclkmaster
, &framemaster
);
68 daifmt
&= ~SND_SOC_DAIFMT_MASTER_MASK
;
70 if (!bitclkmaster
&& !framemaster
) {
72 * No dai-link level and master setting was not found from
73 * sound node level, revert back to legacy DT parsing and
74 * take the settings from codec node.
76 dev_dbg(dev
, "Revert to legacy daifmt parsing\n");
78 daifmt
= snd_soc_of_parse_daifmt(codec
, NULL
, NULL
, NULL
) |
79 (daifmt
& ~SND_SOC_DAIFMT_CLOCK_MASK
);
81 if (codec
== bitclkmaster
)
82 daifmt
|= (codec
== framemaster
) ?
83 SND_SOC_DAIFMT_CBM_CFM
: SND_SOC_DAIFMT_CBM_CFS
;
85 daifmt
|= (codec
== framemaster
) ?
86 SND_SOC_DAIFMT_CBS_CFM
: SND_SOC_DAIFMT_CBS_CFS
;
89 of_node_put(bitclkmaster
);
90 of_node_put(framemaster
);
94 dev_dbg(dev
, "format : %04x\n", daifmt
);
98 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt
);
100 int asoc_simple_card_set_dailink_name(struct device
*dev
,
101 struct snd_soc_dai_link
*dai_link
,
102 const char *fmt
, ...)
109 name
= devm_kvasprintf(dev
, GFP_KERNEL
, fmt
, ap
);
115 dai_link
->name
= name
;
116 dai_link
->stream_name
= name
;
118 dev_dbg(dev
, "name : %s\n", name
);
123 EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name
);
125 int asoc_simple_card_parse_card_name(struct snd_soc_card
*card
,
133 /* Parse the card name from DT */
134 ret
= snd_soc_of_parse_card_name(card
, "label");
135 if (ret
< 0 || !card
->name
) {
138 snprintf(prop
, sizeof(prop
), "%sname", prefix
);
139 ret
= snd_soc_of_parse_card_name(card
, prop
);
144 if (!card
->name
&& card
->dai_link
)
145 card
->name
= card
->dai_link
->name
;
147 dev_dbg(card
->dev
, "Card Name: %s\n", card
->name
? card
->name
: "");
151 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name
);
153 static void asoc_simple_card_clk_register(struct asoc_simple_dai
*dai
,
159 int asoc_simple_card_clk_enable(struct asoc_simple_dai
*dai
)
161 return clk_prepare_enable(dai
->clk
);
163 EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable
);
165 void asoc_simple_card_clk_disable(struct asoc_simple_dai
*dai
)
167 clk_disable_unprepare(dai
->clk
);
169 EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable
);
171 int asoc_simple_card_parse_clk(struct device
*dev
,
172 struct device_node
*node
,
173 struct device_node
*dai_of_node
,
174 struct asoc_simple_dai
*simple_dai
,
181 * Parse dai->sysclk come from "clocks = <&xxx>"
182 * (if system has common clock)
183 * or "system-clock-frequency = <xxx>"
184 * or device's module clock.
186 clk
= devm_get_clk_from_child(dev
, node
, NULL
);
188 simple_dai
->sysclk
= clk_get_rate(clk
);
190 asoc_simple_card_clk_register(simple_dai
, clk
);
191 } else if (!of_property_read_u32(node
, "system-clock-frequency", &val
)) {
192 simple_dai
->sysclk
= val
;
194 clk
= devm_get_clk_from_child(dev
, dai_of_node
, NULL
);
196 simple_dai
->sysclk
= clk_get_rate(clk
);
199 if (of_property_read_bool(node
, "system-clock-direction-out"))
200 simple_dai
->clk_direction
= SND_SOC_CLOCK_OUT
;
202 dev_dbg(dev
, "%s : sysclk = %d, direction %d\n", name
,
203 simple_dai
->sysclk
, simple_dai
->clk_direction
);
207 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk
);
209 int asoc_simple_card_parse_dai(struct device_node
*node
,
210 struct device_node
**dai_of_node
,
211 const char **dai_name
,
212 const char *list_name
,
213 const char *cells_name
,
216 struct of_phandle_args args
;
223 * Get node via "sound-dai = <&phandle port>"
224 * it will be used as xxx_of_node on soc_bind_dai_link()
226 ret
= of_parse_phandle_with_args(node
, list_name
, cells_name
, 0, &args
);
232 ret
= snd_soc_of_get_dai_name(node
, dai_name
);
237 *dai_of_node
= args
.np
;
240 *is_single_link
= !args
.args_count
;
244 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai
);
246 static int asoc_simple_card_get_dai_id(struct device_node
*ep
)
248 struct device_node
*node
;
249 struct device_node
*endpoint
;
253 ret
= snd_soc_get_dai_id(ep
);
254 if (ret
!= -ENOTSUPP
)
257 node
= of_graph_get_port_parent(ep
);
260 * Non HDMI sound case, counting port/endpoint on its DT
261 * is enough. Let's count it.
265 for_each_endpoint_of_node(node
, endpoint
) {
279 int asoc_simple_card_parse_graph_dai(struct device_node
*ep
,
280 struct device_node
**dai_of_node
,
281 const char **dai_name
)
283 struct device_node
*node
;
284 struct of_phandle_args args
;
292 node
= of_graph_get_port_parent(ep
);
296 args
.args
[0] = asoc_simple_card_get_dai_id(ep
);
297 args
.args_count
= (of_graph_get_endpoint_count(node
) > 1);
299 ret
= snd_soc_get_dai_name(&args
, dai_name
);
307 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_graph_dai
);
309 int asoc_simple_card_init_dai(struct snd_soc_dai
*dai
,
310 struct asoc_simple_dai
*simple_dai
)
314 if (simple_dai
->sysclk
) {
315 ret
= snd_soc_dai_set_sysclk(dai
, 0, simple_dai
->sysclk
,
316 simple_dai
->clk_direction
);
317 if (ret
&& ret
!= -ENOTSUPP
) {
318 dev_err(dai
->dev
, "simple-card: set_sysclk error\n");
323 if (simple_dai
->slots
) {
324 ret
= snd_soc_dai_set_tdm_slot(dai
,
325 simple_dai
->tx_slot_mask
,
326 simple_dai
->rx_slot_mask
,
328 simple_dai
->slot_width
);
329 if (ret
&& ret
!= -ENOTSUPP
) {
330 dev_err(dai
->dev
, "simple-card: set_tdm_slot error\n");
337 EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai
);
339 int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link
*dai_link
)
341 /* Assumes platform == cpu */
342 if (!dai_link
->platform_of_node
)
343 dai_link
->platform_of_node
= dai_link
->cpu_of_node
;
347 EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink
);
349 void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link
*dai_link
,
353 * In soc_bind_dai_link() will check cpu name after
354 * of_node matching if dai_link has cpu_dai_name.
355 * but, it will never match if name was created by
356 * fmt_single_name() remove cpu_dai_name if cpu_args
359 * fmt_multiple_name()
362 dai_link
->cpu_dai_name
= NULL
;
364 EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu
);
366 int asoc_simple_card_clean_reference(struct snd_soc_card
*card
)
368 struct snd_soc_dai_link
*dai_link
;
371 for (num_links
= 0, dai_link
= card
->dai_link
;
372 num_links
< card
->num_links
;
373 num_links
++, dai_link
++) {
374 of_node_put(dai_link
->cpu_of_node
);
375 of_node_put(dai_link
->codec_of_node
);
379 EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference
);
381 int asoc_simple_card_of_parse_routing(struct snd_soc_card
*card
,
385 struct device_node
*node
= card
->dev
->of_node
;
391 snprintf(prop
, sizeof(prop
), "%s%s", prefix
, "routing");
393 if (!of_property_read_bool(node
, prop
)) {
399 return snd_soc_of_parse_audio_routing(card
, prop
);
401 EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_routing
);
403 int asoc_simple_card_of_parse_widgets(struct snd_soc_card
*card
,
406 struct device_node
*node
= card
->dev
->of_node
;
412 snprintf(prop
, sizeof(prop
), "%s%s", prefix
, "widgets");
414 if (of_property_read_bool(node
, prop
))
415 return snd_soc_of_parse_audio_simple_widgets(card
, prop
);
417 /* no widgets is not error */
420 EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets
);
422 /* Module information */
423 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
424 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
425 MODULE_LICENSE("GPL v2");