]> asedeno.scripts.mit.edu Git - linux.git/blob - sound/soc/generic/simple-card-utils.c
ASoC: simple-card-util: support snd_soc_dai_link_component style for platform
[linux.git] / sound / soc / generic / simple-card-utils.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // simple-card-utils.c
4 //
5 // Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6
7 #include <linux/clk.h>
8 #include <linux/gpio.h>
9 #include <linux/gpio/consumer.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/of_gpio.h>
13 #include <linux/of_graph.h>
14 #include <sound/jack.h>
15 #include <sound/simple_card_utils.h>
16
17 void asoc_simple_card_convert_fixup(struct asoc_simple_card_data *data,
18                                     struct snd_pcm_hw_params *params)
19 {
20         struct snd_interval *rate = hw_param_interval(params,
21                                                 SNDRV_PCM_HW_PARAM_RATE);
22         struct snd_interval *channels = hw_param_interval(params,
23                                                 SNDRV_PCM_HW_PARAM_CHANNELS);
24
25         if (data->convert_rate)
26                 rate->min =
27                 rate->max = data->convert_rate;
28
29         if (data->convert_channels)
30                 channels->min =
31                 channels->max = data->convert_channels;
32 }
33 EXPORT_SYMBOL_GPL(asoc_simple_card_convert_fixup);
34
35 void asoc_simple_card_parse_convert(struct device *dev, char *prefix,
36                                     struct asoc_simple_card_data *data)
37 {
38         struct device_node *np = dev->of_node;
39         char prop[128];
40
41         if (!prefix)
42                 prefix = "";
43
44         /* sampling rate convert */
45         snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-rate");
46         of_property_read_u32(np, prop, &data->convert_rate);
47
48         /* channels transfer */
49         snprintf(prop, sizeof(prop), "%s%s", prefix, "convert-channels");
50         of_property_read_u32(np, prop, &data->convert_channels);
51
52         dev_dbg(dev, "convert_rate     %d\n", data->convert_rate);
53         dev_dbg(dev, "convert_channels %d\n", data->convert_channels);
54 }
55 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_convert);
56
57 int asoc_simple_card_parse_daifmt(struct device *dev,
58                                   struct device_node *node,
59                                   struct device_node *codec,
60                                   char *prefix,
61                                   unsigned int *retfmt)
62 {
63         struct device_node *bitclkmaster = NULL;
64         struct device_node *framemaster = NULL;
65         unsigned int daifmt;
66
67         daifmt = snd_soc_of_parse_daifmt(node, prefix,
68                                          &bitclkmaster, &framemaster);
69         daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
70
71         if (!bitclkmaster && !framemaster) {
72                 /*
73                  * No dai-link level and master setting was not found from
74                  * sound node level, revert back to legacy DT parsing and
75                  * take the settings from codec node.
76                  */
77                 dev_dbg(dev, "Revert to legacy daifmt parsing\n");
78
79                 daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) |
80                         (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
81         } else {
82                 if (codec == bitclkmaster)
83                         daifmt |= (codec == framemaster) ?
84                                 SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
85                 else
86                         daifmt |= (codec == framemaster) ?
87                                 SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
88         }
89
90         of_node_put(bitclkmaster);
91         of_node_put(framemaster);
92
93         *retfmt = daifmt;
94
95         dev_dbg(dev, "format : %04x\n", daifmt);
96
97         return 0;
98 }
99 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt);
100
101 int asoc_simple_card_set_dailink_name(struct device *dev,
102                                       struct snd_soc_dai_link *dai_link,
103                                       const char *fmt, ...)
104 {
105         va_list ap;
106         char *name = NULL;
107         int ret = -ENOMEM;
108
109         va_start(ap, fmt);
110         name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap);
111         va_end(ap);
112
113         if (name) {
114                 ret = 0;
115
116                 dai_link->name          = name;
117                 dai_link->stream_name   = name;
118
119                 dev_dbg(dev, "name : %s\n", name);
120         }
121
122         return ret;
123 }
124 EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name);
125
126 int asoc_simple_card_parse_card_name(struct snd_soc_card *card,
127                                      char *prefix)
128 {
129         int ret;
130
131         if (!prefix)
132                 prefix = "";
133
134         /* Parse the card name from DT */
135         ret = snd_soc_of_parse_card_name(card, "label");
136         if (ret < 0 || !card->name) {
137                 char prop[128];
138
139                 snprintf(prop, sizeof(prop), "%sname", prefix);
140                 ret = snd_soc_of_parse_card_name(card, prop);
141                 if (ret < 0)
142                         return ret;
143         }
144
145         if (!card->name && card->dai_link)
146                 card->name = card->dai_link->name;
147
148         dev_dbg(card->dev, "Card Name: %s\n", card->name ? card->name : "");
149
150         return 0;
151 }
152 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name);
153
154 static void asoc_simple_card_clk_register(struct asoc_simple_dai *dai,
155                                           struct clk *clk)
156 {
157         dai->clk = clk;
158 }
159
160 int asoc_simple_card_clk_enable(struct asoc_simple_dai *dai)
161 {
162         return clk_prepare_enable(dai->clk);
163 }
164 EXPORT_SYMBOL_GPL(asoc_simple_card_clk_enable);
165
166 void asoc_simple_card_clk_disable(struct asoc_simple_dai *dai)
167 {
168         clk_disable_unprepare(dai->clk);
169 }
170 EXPORT_SYMBOL_GPL(asoc_simple_card_clk_disable);
171
172 int asoc_simple_card_parse_clk(struct device *dev,
173                                struct device_node *node,
174                                struct device_node *dai_of_node,
175                                struct asoc_simple_dai *simple_dai,
176                                const char *dai_name,
177                                struct snd_soc_dai_link_component *dlc)
178 {
179         struct clk *clk;
180         u32 val;
181
182         /*
183          * Use snd_soc_dai_link_component instead of legacy style.
184          * It is only for codec, but cpu will be supported in the future.
185          * see
186          *      soc-core.c :: snd_soc_init_multicodec()
187          */
188         if (dlc) {
189                 dai_of_node     = dlc->of_node;
190                 dai_name        = dlc->dai_name;
191         }
192
193         /*
194          * Parse dai->sysclk come from "clocks = <&xxx>"
195          * (if system has common clock)
196          *  or "system-clock-frequency = <xxx>"
197          *  or device's module clock.
198          */
199         clk = devm_get_clk_from_child(dev, node, NULL);
200         if (!IS_ERR(clk)) {
201                 simple_dai->sysclk = clk_get_rate(clk);
202
203                 asoc_simple_card_clk_register(simple_dai, clk);
204         } else if (!of_property_read_u32(node, "system-clock-frequency", &val)) {
205                 simple_dai->sysclk = val;
206         } else {
207                 clk = devm_get_clk_from_child(dev, dai_of_node, NULL);
208                 if (!IS_ERR(clk))
209                         simple_dai->sysclk = clk_get_rate(clk);
210         }
211
212         if (of_property_read_bool(node, "system-clock-direction-out"))
213                 simple_dai->clk_direction = SND_SOC_CLOCK_OUT;
214
215         dev_dbg(dev, "%s : sysclk = %d, direction %d\n", dai_name,
216                 simple_dai->sysclk, simple_dai->clk_direction);
217
218         return 0;
219 }
220 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_clk);
221
222 int asoc_simple_card_parse_dai(struct device_node *node,
223                                     struct snd_soc_dai_link_component *dlc,
224                                     struct device_node **dai_of_node,
225                                     const char **dai_name,
226                                     const char *list_name,
227                                     const char *cells_name,
228                                     int *is_single_link)
229 {
230         struct of_phandle_args args;
231         int ret;
232
233         if (!node)
234                 return 0;
235
236         /*
237          * Use snd_soc_dai_link_component instead of legacy style.
238          * It is only for codec, but cpu will be supported in the future.
239          * see
240          *      soc-core.c :: snd_soc_init_multicodec()
241          */
242         if (dlc) {
243                 dai_name        = &dlc->dai_name;
244                 dai_of_node     = &dlc->of_node;
245         }
246
247         /*
248          * Get node via "sound-dai = <&phandle port>"
249          * it will be used as xxx_of_node on soc_bind_dai_link()
250          */
251         ret = of_parse_phandle_with_args(node, list_name, cells_name, 0, &args);
252         if (ret)
253                 return ret;
254
255         /* Get dai->name */
256         if (dai_name) {
257                 ret = snd_soc_of_get_dai_name(node, dai_name);
258                 if (ret < 0)
259                         return ret;
260         }
261
262         *dai_of_node = args.np;
263
264         if (is_single_link)
265                 *is_single_link = !args.args_count;
266
267         return 0;
268 }
269 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_dai);
270
271 static int asoc_simple_card_get_dai_id(struct device_node *ep)
272 {
273         struct device_node *node;
274         struct device_node *endpoint;
275         int i, id;
276         int ret;
277
278         ret = snd_soc_get_dai_id(ep);
279         if (ret != -ENOTSUPP)
280                 return ret;
281
282         node = of_graph_get_port_parent(ep);
283
284         /*
285          * Non HDMI sound case, counting port/endpoint on its DT
286          * is enough. Let's count it.
287          */
288         i = 0;
289         id = -1;
290         for_each_endpoint_of_node(node, endpoint) {
291                 if (endpoint == ep)
292                         id = i;
293                 i++;
294         }
295
296         of_node_put(node);
297
298         if (id < 0)
299                 return -ENODEV;
300
301         return id;
302 }
303
304 int asoc_simple_card_parse_graph_dai(struct device_node *ep,
305                                      struct snd_soc_dai_link_component *dlc,
306                                      struct device_node **dai_of_node,
307                                      const char **dai_name)
308 {
309         struct device_node *node;
310         struct of_phandle_args args;
311         int ret;
312
313         /*
314          * Use snd_soc_dai_link_component instead of legacy style.
315          * It is only for codec, but cpu will be supported in the future.
316          * see
317          *      soc-core.c :: snd_soc_init_multicodec()
318          */
319         if (dlc) {
320                 dai_name        = &dlc->dai_name;
321                 dai_of_node     = &dlc->of_node;
322         }
323
324         if (!ep)
325                 return 0;
326         if (!dai_name)
327                 return 0;
328
329         node = of_graph_get_port_parent(ep);
330
331         /* Get dai->name */
332         args.np         = node;
333         args.args[0]    = asoc_simple_card_get_dai_id(ep);
334         args.args_count = (of_graph_get_endpoint_count(node) > 1);
335
336         ret = snd_soc_get_dai_name(&args, dai_name);
337         if (ret < 0)
338                 return ret;
339
340         *dai_of_node = node;
341
342         return 0;
343 }
344 EXPORT_SYMBOL_GPL(asoc_simple_card_parse_graph_dai);
345
346 int asoc_simple_card_init_dai(struct snd_soc_dai *dai,
347                               struct asoc_simple_dai *simple_dai)
348 {
349         int ret;
350
351         if (simple_dai->sysclk) {
352                 ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
353                                              simple_dai->clk_direction);
354                 if (ret && ret != -ENOTSUPP) {
355                         dev_err(dai->dev, "simple-card: set_sysclk error\n");
356                         return ret;
357                 }
358         }
359
360         if (simple_dai->slots) {
361                 ret = snd_soc_dai_set_tdm_slot(dai,
362                                                simple_dai->tx_slot_mask,
363                                                simple_dai->rx_slot_mask,
364                                                simple_dai->slots,
365                                                simple_dai->slot_width);
366                 if (ret && ret != -ENOTSUPP) {
367                         dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
368                         return ret;
369                 }
370         }
371
372         return 0;
373 }
374 EXPORT_SYMBOL_GPL(asoc_simple_card_init_dai);
375
376 int asoc_simple_card_canonicalize_dailink(struct snd_soc_dai_link *dai_link)
377 {
378         /* Assumes platform == cpu */
379         if (dai_link->platform) {
380                 if (!dai_link->platform->of_node)
381                         dai_link->platform->of_node = dai_link->cpu_of_node;
382         } else {
383                 if (!dai_link->platform_of_node)
384                         dai_link->platform_of_node = dai_link->cpu_of_node;
385         }
386         return 0;
387
388 }
389 EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_dailink);
390
391 void asoc_simple_card_canonicalize_cpu(struct snd_soc_dai_link *dai_link,
392                                        int is_single_links)
393 {
394         /*
395          * In soc_bind_dai_link() will check cpu name after
396          * of_node matching if dai_link has cpu_dai_name.
397          * but, it will never match if name was created by
398          * fmt_single_name() remove cpu_dai_name if cpu_args
399          * was 0. See:
400          *      fmt_single_name()
401          *      fmt_multiple_name()
402          */
403         if (is_single_links)
404                 dai_link->cpu_dai_name = NULL;
405 }
406 EXPORT_SYMBOL_GPL(asoc_simple_card_canonicalize_cpu);
407
408 int asoc_simple_card_clean_reference(struct snd_soc_card *card)
409 {
410         struct snd_soc_dai_link *dai_link;
411         int num_links;
412
413         for (num_links = 0, dai_link = card->dai_link;
414              num_links < card->num_links;
415              num_links++, dai_link++) {
416                 of_node_put(dai_link->cpu_of_node);
417                 of_node_put(dai_link->codecs->of_node);
418         }
419         return 0;
420 }
421 EXPORT_SYMBOL_GPL(asoc_simple_card_clean_reference);
422
423 int asoc_simple_card_of_parse_routing(struct snd_soc_card *card,
424                                       char *prefix,
425                                       int optional)
426 {
427         struct device_node *node = card->dev->of_node;
428         char prop[128];
429
430         if (!prefix)
431                 prefix = "";
432
433         snprintf(prop, sizeof(prop), "%s%s", prefix, "routing");
434
435         if (!of_property_read_bool(node, prop)) {
436                 if (optional)
437                         return 0;
438                 return -EINVAL;
439         }
440
441         return snd_soc_of_parse_audio_routing(card, prop);
442 }
443 EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_routing);
444
445 int asoc_simple_card_of_parse_widgets(struct snd_soc_card *card,
446                                       char *prefix)
447 {
448         struct device_node *node = card->dev->of_node;
449         char prop[128];
450
451         if (!prefix)
452                 prefix = "";
453
454         snprintf(prop, sizeof(prop), "%s%s", prefix, "widgets");
455
456         if (of_property_read_bool(node, prop))
457                 return snd_soc_of_parse_audio_simple_widgets(card, prop);
458
459         /* no widgets is not error */
460         return 0;
461 }
462 EXPORT_SYMBOL_GPL(asoc_simple_card_of_parse_widgets);
463
464 int asoc_simple_card_init_jack(struct snd_soc_card *card,
465                                struct asoc_simple_jack *sjack,
466                                int is_hp, char *prefix)
467 {
468         struct device *dev = card->dev;
469         enum of_gpio_flags flags;
470         char prop[128];
471         char *pin_name;
472         char *gpio_name;
473         int mask;
474         int det;
475
476         if (!prefix)
477                 prefix = "";
478
479         sjack->gpio.gpio = -ENOENT;
480
481         if (is_hp) {
482                 snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
483                 pin_name        = "Headphones";
484                 gpio_name       = "Headphone detection";
485                 mask            = SND_JACK_HEADPHONE;
486         } else {
487                 snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
488                 pin_name        = "Mic Jack";
489                 gpio_name       = "Mic detection";
490                 mask            = SND_JACK_MICROPHONE;
491         }
492
493         det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags);
494         if (det == -EPROBE_DEFER)
495                 return -EPROBE_DEFER;
496
497         if (gpio_is_valid(det)) {
498                 sjack->pin.pin          = pin_name;
499                 sjack->pin.mask         = mask;
500
501                 sjack->gpio.name        = gpio_name;
502                 sjack->gpio.report      = mask;
503                 sjack->gpio.gpio        = det;
504                 sjack->gpio.invert      = !!(flags & OF_GPIO_ACTIVE_LOW);
505                 sjack->gpio.debounce_time = 150;
506
507                 snd_soc_card_jack_new(card, pin_name, mask,
508                                       &sjack->jack,
509                                       &sjack->pin, 1);
510
511                 snd_soc_jack_add_gpios(&sjack->jack, 1,
512                                        &sjack->gpio);
513         }
514
515         return 0;
516 }
517 EXPORT_SYMBOL_GPL(asoc_simple_card_init_jack);
518
519 /* Module information */
520 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
521 MODULE_DESCRIPTION("ALSA SoC Simple Card Utils");
522 MODULE_LICENSE("GPL v2");