Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[firefly-linux-kernel-4.4.55.git] / sound / soc / generic / simple-card.c
1 /*
2  * ASoC simple sound card support
3  *
4  * Copyright (C) 2012 Renesas Solutions Corp.
5  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11 #include <linux/clk.h>
12 #include <linux/device.h>
13 #include <linux/module.h>
14 #include <linux/of.h>
15 #include <linux/platform_device.h>
16 #include <linux/string.h>
17 #include <sound/simple_card.h>
18 #include <sound/soc-dai.h>
19 #include <sound/soc.h>
20
21 struct simple_card_data {
22         struct snd_soc_card snd_card;
23         struct simple_dai_props {
24                 struct asoc_simple_dai cpu_dai;
25                 struct asoc_simple_dai codec_dai;
26         } *dai_props;
27         struct snd_soc_dai_link dai_link[];     /* dynamically allocated */
28 };
29
30 static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
31                                        struct asoc_simple_dai *set)
32 {
33         int ret;
34
35         if (set->fmt) {
36                 ret = snd_soc_dai_set_fmt(dai, set->fmt);
37                 if (ret && ret != -ENOTSUPP) {
38                         dev_err(dai->dev, "simple-card: set_fmt error\n");
39                         goto err;
40                 }
41         }
42
43         if (set->sysclk) {
44                 ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
45                 if (ret && ret != -ENOTSUPP) {
46                         dev_err(dai->dev, "simple-card: set_sysclk error\n");
47                         goto err;
48                 }
49         }
50
51         if (set->slots) {
52                 ret = snd_soc_dai_set_tdm_slot(dai, 0, 0,
53                                                 set->slots,
54                                                 set->slot_width);
55                 if (ret && ret != -ENOTSUPP) {
56                         dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
57                         goto err;
58                 }
59         }
60
61         ret = 0;
62
63 err:
64         return ret;
65 }
66
67 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
68 {
69         struct simple_card_data *priv =
70                                 snd_soc_card_get_drvdata(rtd->card);
71         struct snd_soc_dai *codec = rtd->codec_dai;
72         struct snd_soc_dai *cpu = rtd->cpu_dai;
73         struct simple_dai_props *dai_props;
74         int num, ret;
75
76         num = rtd - rtd->card->rtd;
77         dai_props = &priv->dai_props[num];
78         ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
79         if (ret < 0)
80                 return ret;
81
82         ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai);
83         if (ret < 0)
84                 return ret;
85
86         return 0;
87 }
88
89 static int
90 asoc_simple_card_sub_parse_of(struct device_node *np,
91                               unsigned int daifmt,
92                               struct asoc_simple_dai *dai,
93                               const struct device_node **p_node,
94                               const char **name)
95 {
96         struct device_node *node;
97         struct clk *clk;
98         int ret;
99
100         /*
101          * get node via "sound-dai = <&phandle port>"
102          * it will be used as xxx_of_node on soc_bind_dai_link()
103          */
104         node = of_parse_phandle(np, "sound-dai", 0);
105         if (!node)
106                 return -ENODEV;
107         *p_node = node;
108
109         /* get dai->name */
110         ret = snd_soc_of_get_dai_name(np, name);
111         if (ret < 0)
112                 return ret;
113
114         /* parse TDM slot */
115         ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
116         if (ret)
117                 return ret;
118
119         /*
120          * bitclock-inversion, frame-inversion
121          * bitclock-master,    frame-master
122          * and specific "format" if it has
123          */
124         dai->fmt = snd_soc_of_parse_daifmt(np, NULL);
125         dai->fmt |= daifmt;
126
127         /*
128          * dai->sysclk come from
129          *  "clocks = <&xxx>" (if system has common clock)
130          *  or "system-clock-frequency = <xxx>"
131          *  or device's module clock.
132          */
133         if (of_property_read_bool(np, "clocks")) {
134                 clk = of_clk_get(np, 0);
135                 if (IS_ERR(clk)) {
136                         ret = PTR_ERR(clk);
137                         return ret;
138                 }
139
140                 dai->sysclk = clk_get_rate(clk);
141         } else if (of_property_read_bool(np, "system-clock-frequency")) {
142                 of_property_read_u32(np,
143                                      "system-clock-frequency",
144                                      &dai->sysclk);
145         } else {
146                 clk = of_clk_get(node, 0);
147                 if (!IS_ERR(clk))
148                         dai->sysclk = clk_get_rate(clk);
149         }
150
151         return 0;
152 }
153
154 static int simple_card_cpu_codec_of(struct device_node *node,
155                                 int daifmt,
156                                 struct snd_soc_dai_link *dai_link,
157                                 struct simple_dai_props *dai_props)
158 {
159         struct device_node *np;
160         int ret;
161
162         /* CPU sub-node */
163         ret = -EINVAL;
164         np = of_get_child_by_name(node, "simple-audio-card,cpu");
165         if (np) {
166                 ret = asoc_simple_card_sub_parse_of(np, daifmt,
167                                                 &dai_props->cpu_dai,
168                                                 &dai_link->cpu_of_node,
169                                                 &dai_link->cpu_dai_name);
170                 of_node_put(np);
171         }
172         if (ret < 0)
173                 return ret;
174
175         /* CODEC sub-node */
176         ret = -EINVAL;
177         np = of_get_child_by_name(node, "simple-audio-card,codec");
178         if (np) {
179                 ret = asoc_simple_card_sub_parse_of(np, daifmt,
180                                                 &dai_props->codec_dai,
181                                                 &dai_link->codec_of_node,
182                                                 &dai_link->codec_dai_name);
183                 of_node_put(np);
184         }
185         return ret;
186 }
187
188 static int asoc_simple_card_parse_of(struct device_node *node,
189                                      struct simple_card_data *priv,
190                                      struct device *dev,
191                                      int multi)
192 {
193         struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link;
194         struct simple_dai_props *dai_props = priv->dai_props;
195         struct device_node *np;
196         char *name;
197         unsigned int daifmt;
198         int ret;
199
200         /* parsing the card name from DT */
201         snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
202
203         /* get CPU/CODEC common format via simple-audio-card,format */
204         daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") &
205                 (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK);
206
207         /* off-codec widgets */
208         if (of_property_read_bool(node, "simple-audio-card,widgets")) {
209                 ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
210                                         "simple-audio-card,widgets");
211                 if (ret)
212                         return ret;
213         }
214
215         /* DAPM routes */
216         if (of_property_read_bool(node, "simple-audio-card,routing")) {
217                 ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
218                                         "simple-audio-card,routing");
219                 if (ret)
220                         return ret;
221         }
222
223         /* loop on the DAI links */
224         np = NULL;
225         for (;;) {
226                 if (multi) {
227                         np = of_get_next_child(node, np);
228                         if (!np)
229                                 break;
230                 }
231
232                 ret = simple_card_cpu_codec_of(multi ? np : node,
233                                         daifmt, dai_link, dai_props);
234                 if (ret < 0)
235                         goto err;
236
237                 /*
238                  * overwrite cpu_dai->fmt as its DAIFMT_MASTER bit is based on CODEC
239                  * while the other bits should be identical unless buggy SW/HW design.
240                  */
241                 dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt;
242
243                 if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
244                         ret = -EINVAL;
245                         goto err;
246                 }
247
248                 /* simple-card assumes platform == cpu */
249                 dai_link->platform_of_node = dai_link->cpu_of_node;
250
251                 name = devm_kzalloc(dev,
252                                     strlen(dai_link->cpu_dai_name)   +
253                                     strlen(dai_link->codec_dai_name) + 2,
254                                     GFP_KERNEL);
255                 sprintf(name, "%s-%s", dai_link->cpu_dai_name,
256                                         dai_link->codec_dai_name);
257                 dai_link->name = dai_link->stream_name = name;
258
259                 if (!multi)
260                         break;
261
262                 dai_link++;
263                 dai_props++;
264         }
265
266         /* card name is created from CPU/CODEC dai name */
267         dai_link = priv->snd_card.dai_link;
268         if (!priv->snd_card.name)
269                 priv->snd_card.name = dai_link->name;
270
271         dev_dbg(dev, "card-name : %s\n", priv->snd_card.name);
272         dev_dbg(dev, "platform : %04x\n", daifmt);
273         dai_props = priv->dai_props;
274         dev_dbg(dev, "cpu : %s / %04x / %d\n",
275                 dai_link->cpu_dai_name,
276                 dai_props->cpu_dai.fmt,
277                 dai_props->cpu_dai.sysclk);
278         dev_dbg(dev, "codec : %s / %04x / %d\n",
279                 dai_link->codec_dai_name,
280                 dai_props->codec_dai.fmt,
281                 dai_props->codec_dai.sysclk);
282
283         return 0;
284
285 err:
286         of_node_put(np);
287         return ret;
288 }
289
290 /* update the reference count of the devices nodes at end of probe */
291 static int asoc_simple_card_unref(struct platform_device *pdev)
292 {
293         struct snd_soc_card *card = platform_get_drvdata(pdev);
294         struct snd_soc_dai_link *dai_link;
295         struct device_node *np;
296         int num_links;
297
298         for (num_links = 0, dai_link = card->dai_link;
299              num_links < card->num_links;
300              num_links++, dai_link++) {
301                 np = (struct device_node *) dai_link->cpu_of_node;
302                 if (np)
303                         of_node_put(np);
304                 np = (struct device_node *) dai_link->codec_of_node;
305                 if (np)
306                         of_node_put(np);
307         }
308         return 0;
309 }
310
311 static int asoc_simple_card_probe(struct platform_device *pdev)
312 {
313         struct simple_card_data *priv;
314         struct snd_soc_dai_link *dai_link;
315         struct device_node *np = pdev->dev.of_node;
316         struct device *dev = &pdev->dev;
317         int num_links, multi, ret;
318
319         /* get the number of DAI links */
320         if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) {
321                 num_links = of_get_child_count(np);
322                 multi = 1;
323         } else {
324                 num_links = 1;
325                 multi = 0;
326         }
327
328         /* allocate the private data and the DAI link array */
329         priv = devm_kzalloc(dev,
330                         sizeof(*priv) + sizeof(*dai_link) * num_links,
331                         GFP_KERNEL);
332         if (!priv)
333                 return -ENOMEM;
334
335         /*
336          * init snd_soc_card
337          */
338         priv->snd_card.owner = THIS_MODULE;
339         priv->snd_card.dev = dev;
340         dai_link = priv->dai_link;
341         priv->snd_card.dai_link = dai_link;
342         priv->snd_card.num_links = num_links;
343
344         /* get room for the other properties */
345         priv->dai_props = devm_kzalloc(dev,
346                         sizeof(*priv->dai_props) * num_links,
347                         GFP_KERNEL);
348         if (!priv->dai_props)
349                 return -ENOMEM;
350
351         if (np && of_device_is_available(np)) {
352
353                 ret = asoc_simple_card_parse_of(np, priv, dev, multi);
354                 if (ret < 0) {
355                         if (ret != -EPROBE_DEFER)
356                                 dev_err(dev, "parse error %d\n", ret);
357                         goto err;
358                 }
359
360                 /*
361                  * soc_bind_dai_link() will check cpu name
362                  * after of_node matching if dai_link has cpu_dai_name.
363                  * but, it will never match if name was created by fmt_single_name()
364                  * remove cpu_dai_name to escape name matching.
365                  * see
366                  *      fmt_single_name()
367                  *      fmt_multiple_name()
368                  */
369                 if (num_links == 1)
370                         dai_link->cpu_dai_name = NULL;
371
372         } else {
373                 struct asoc_simple_card_info *cinfo;
374
375                 cinfo = dev->platform_data;
376                 if (!cinfo) {
377                         dev_err(dev, "no info for asoc-simple-card\n");
378                         return -EINVAL;
379                 }
380
381                 if (!cinfo->name        ||
382                     !cinfo->codec_dai.name      ||
383                     !cinfo->codec       ||
384                     !cinfo->platform    ||
385                     !cinfo->cpu_dai.name) {
386                         dev_err(dev, "insufficient asoc_simple_card_info settings\n");
387                         return -EINVAL;
388                 }
389
390                 priv->snd_card.name     = (cinfo->card) ? cinfo->card : cinfo->name;
391                 dai_link->name          = cinfo->name;
392                 dai_link->stream_name   = cinfo->name;
393                 dai_link->platform_name = cinfo->platform;
394                 dai_link->codec_name    = cinfo->codec;
395                 dai_link->cpu_dai_name  = cinfo->cpu_dai.name;
396                 dai_link->codec_dai_name = cinfo->codec_dai.name;
397                 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
398                                         sizeof(priv->dai_props->cpu_dai));
399                 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
400                                         sizeof(priv->dai_props->codec_dai));
401
402                 priv->dai_props->cpu_dai.fmt    |= cinfo->daifmt;
403                 priv->dai_props->codec_dai.fmt  |= cinfo->daifmt;
404         }
405
406         /*
407          * init snd_soc_dai_link
408          */
409         dai_link->init = asoc_simple_card_dai_init;
410
411         snd_soc_card_set_drvdata(&priv->snd_card, priv);
412
413         ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
414
415 err:
416         asoc_simple_card_unref(pdev);
417         return ret;
418 }
419
420 static const struct of_device_id asoc_simple_of_match[] = {
421         { .compatible = "simple-audio-card", },
422         {},
423 };
424 MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
425
426 static struct platform_driver asoc_simple_card = {
427         .driver = {
428                 .name   = "asoc-simple-card",
429                 .owner = THIS_MODULE,
430                 .of_match_table = asoc_simple_of_match,
431         },
432         .probe          = asoc_simple_card_probe,
433 };
434
435 module_platform_driver(asoc_simple_card);
436
437 MODULE_ALIAS("platform:asoc-simple-card");
438 MODULE_LICENSE("GPL");
439 MODULE_DESCRIPTION("ASoC Simple Sound Card");
440 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");