Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/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>");
441 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us