1 /*
2  * simple-card-core.c
3  *
4  * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
5  *
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.
9  */
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <sound/simple_card_utils.h>
13 
14 int asoc_simple_card_parse_daifmt(struct device *dev,
15 				  struct device_node *node,
16 				  struct device_node *codec,
17 				  char *prefix,
18 				  unsigned int *retfmt)
19 {
20 	struct device_node *bitclkmaster = NULL;
21 	struct device_node *framemaster = NULL;
22 	int prefix_len = prefix ? strlen(prefix) : 0;
23 	unsigned int daifmt;
24 
25 	daifmt = snd_soc_of_parse_daifmt(node, prefix,
26 					 &bitclkmaster, &framemaster);
27 	daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
28 
29 	if (prefix_len && !bitclkmaster && !framemaster) {
30 		/*
31 		 * No dai-link level and master setting was not found from
32 		 * sound node level, revert back to legacy DT parsing and
33 		 * take the settings from codec node.
34 		 */
35 		dev_dbg(dev, "Revert to legacy daifmt parsing\n");
36 
37 		daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) |
38 			(daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
39 	} else {
40 		if (codec == bitclkmaster)
41 			daifmt |= (codec == framemaster) ?
42 				SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
43 		else
44 			daifmt |= (codec == framemaster) ?
45 				SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
46 	}
47 
48 	of_node_put(bitclkmaster);
49 	of_node_put(framemaster);
50 
51 	*retfmt = daifmt;
52 
53 	return 0;
54 }
55 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt);
56 
57 int asoc_simple_card_set_dailink_name(struct device *dev,
58 				      struct snd_soc_dai_link *dai_link,
59 				      const char *fmt, ...)
60 {
61 	va_list ap;
62 	char *name = NULL;
63 	int ret = -ENOMEM;
64 
65 	va_start(ap, fmt);
66 	name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap);
67 	va_end(ap);
68 
69 	if (name) {
70 		ret = 0;
71 
72 		dai_link->name		= name;
73 		dai_link->stream_name	= name;
74 	}
75 
76 	return ret;
77 }
78 EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name);
79 
80 int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
81 				     char *prefix)
82 {
83 	char prop[128];
84 	int ret;
85 
86 	snprintf(prop, sizeof(prop), "%sname", prefix);
87 
88 	/* Parse the card name from DT */
89 	ret = snd_soc_of_parse_card_name(card, prop);
90 	if (ret < 0)
91 		return ret;
92 
93 	if (!card->name && card->dai_link)
94 		card->name = card->dai_link->name;
95 
96 	return 0;
97 }
98 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
99 
100 /* Module information */
101 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
102 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
103 MODULE_LICENSE("GPL v2");
104