Version:  2.0.40 2.2.26 2.4.37 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1

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/gpio.h>
 14 #include <linux/module.h>
 15 #include <linux/of.h>
 16 #include <linux/of_gpio.h>
 17 #include <linux/platform_device.h>
 18 #include <linux/string.h>
 19 #include <sound/jack.h>
 20 #include <sound/simple_card.h>
 21 #include <sound/soc-dai.h>
 22 #include <sound/soc.h>
 23 
 24 struct simple_card_data {
 25         struct snd_soc_card snd_card;
 26         struct simple_dai_props {
 27                 struct asoc_simple_dai cpu_dai;
 28                 struct asoc_simple_dai codec_dai;
 29         } *dai_props;
 30         unsigned int mclk_fs;
 31         int gpio_hp_det;
 32         int gpio_hp_det_invert;
 33         int gpio_mic_det;
 34         int gpio_mic_det_invert;
 35         struct snd_soc_dai_link dai_link[];     /* dynamically allocated */
 36 };
 37 
 38 #define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
 39 #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
 40 #define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
 41 
 42 static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
 43 {
 44         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 45         struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
 46         struct simple_dai_props *dai_props =
 47                 &priv->dai_props[rtd - rtd->card->rtd];
 48         int ret;
 49 
 50         ret = clk_prepare_enable(dai_props->cpu_dai.clk);
 51         if (ret)
 52                 return ret;
 53         
 54         ret = clk_prepare_enable(dai_props->codec_dai.clk);
 55         if (ret)
 56                 clk_disable_unprepare(dai_props->cpu_dai.clk);
 57 
 58         return ret;
 59 }
 60 
 61 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
 62 {
 63         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 64         struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
 65         struct simple_dai_props *dai_props =
 66                 &priv->dai_props[rtd - rtd->card->rtd];
 67 
 68         clk_disable_unprepare(dai_props->cpu_dai.clk);
 69 
 70         clk_disable_unprepare(dai_props->codec_dai.clk);
 71 }
 72 
 73 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
 74                                       struct snd_pcm_hw_params *params)
 75 {
 76         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 77         struct snd_soc_dai *codec_dai = rtd->codec_dai;
 78         struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
 79         unsigned int mclk;
 80         int ret = 0;
 81 
 82         if (priv->mclk_fs) {
 83                 mclk = params_rate(params) * priv->mclk_fs;
 84                 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
 85                                              SND_SOC_CLOCK_IN);
 86         }
 87 
 88         return ret;
 89 }
 90 
 91 static struct snd_soc_ops asoc_simple_card_ops = {
 92         .startup = asoc_simple_card_startup,
 93         .shutdown = asoc_simple_card_shutdown,
 94         .hw_params = asoc_simple_card_hw_params,
 95 };
 96 
 97 static struct snd_soc_jack simple_card_hp_jack;
 98 static struct snd_soc_jack_pin simple_card_hp_jack_pins[] = {
 99         {
100                 .pin = "Headphones",
101                 .mask = SND_JACK_HEADPHONE,
102         },
103 };
104 static struct snd_soc_jack_gpio simple_card_hp_jack_gpio = {
105         .name = "Headphone detection",
106         .report = SND_JACK_HEADPHONE,
107         .debounce_time = 150,
108 };
109 
110 static struct snd_soc_jack simple_card_mic_jack;
111 static struct snd_soc_jack_pin simple_card_mic_jack_pins[] = {
112         {
113                 .pin = "Mic Jack",
114                 .mask = SND_JACK_MICROPHONE,
115         },
116 };
117 static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = {
118         .name = "Mic detection",
119         .report = SND_JACK_MICROPHONE,
120         .debounce_time = 150,
121 };
122 
123 static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
124                                        struct asoc_simple_dai *set)
125 {
126         int ret;
127 
128         if (set->sysclk) {
129                 ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0);
130                 if (ret && ret != -ENOTSUPP) {
131                         dev_err(dai->dev, "simple-card: set_sysclk error\n");
132                         goto err;
133                 }
134         }
135 
136         if (set->slots) {
137                 ret = snd_soc_dai_set_tdm_slot(dai, 0, 0,
138                                                 set->slots,
139                                                 set->slot_width);
140                 if (ret && ret != -ENOTSUPP) {
141                         dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
142                         goto err;
143                 }
144         }
145 
146         ret = 0;
147 
148 err:
149         return ret;
150 }
151 
152 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
153 {
154         struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
155         struct snd_soc_dai *codec = rtd->codec_dai;
156         struct snd_soc_dai *cpu = rtd->cpu_dai;
157         struct simple_dai_props *dai_props;
158         int num, ret;
159 
160         num = rtd - rtd->card->rtd;
161         dai_props = &priv->dai_props[num];
162         ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
163         if (ret < 0)
164                 return ret;
165 
166         ret = __asoc_simple_card_dai_init(cpu, &dai_props->cpu_dai);
167         if (ret < 0)
168                 return ret;
169 
170         if (gpio_is_valid(priv->gpio_hp_det)) {
171                 snd_soc_card_jack_new(rtd->card, "Headphones",
172                                       SND_JACK_HEADPHONE,
173                                       &simple_card_hp_jack,
174                                       simple_card_hp_jack_pins,
175                                       ARRAY_SIZE(simple_card_hp_jack_pins));
176 
177                 simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det;
178                 simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert;
179                 snd_soc_jack_add_gpios(&simple_card_hp_jack, 1,
180                                        &simple_card_hp_jack_gpio);
181         }
182 
183         if (gpio_is_valid(priv->gpio_mic_det)) {
184                 snd_soc_card_jack_new(rtd->card, "Mic Jack",
185                                       SND_JACK_MICROPHONE,
186                                       &simple_card_mic_jack,
187                                       simple_card_mic_jack_pins,
188                                       ARRAY_SIZE(simple_card_mic_jack_pins));
189                 simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det;
190                 simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert;
191                 snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
192                                        &simple_card_mic_jack_gpio);
193         }
194         return 0;
195 }
196 
197 static int
198 asoc_simple_card_sub_parse_of(struct device_node *np,
199                               struct asoc_simple_dai *dai,
200                               struct device_node **p_node,
201                               const char **name,
202                               int *args_count)
203 {
204         struct of_phandle_args args;
205         struct clk *clk;
206         u32 val;
207         int ret;
208 
209         /*
210          * Get node via "sound-dai = <&phandle port>"
211          * it will be used as xxx_of_node on soc_bind_dai_link()
212          */
213         ret = of_parse_phandle_with_args(np, "sound-dai",
214                                          "#sound-dai-cells", 0, &args);
215         if (ret)
216                 return ret;
217 
218         *p_node = args.np;
219 
220         if (args_count)
221                 *args_count = args.args_count;
222 
223         /* Get dai->name */
224         ret = snd_soc_of_get_dai_name(np, name);
225         if (ret < 0)
226                 return ret;
227 
228         /* Parse TDM slot */
229         ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width);
230         if (ret)
231                 return ret;
232 
233         /*
234          * Parse dai->sysclk come from "clocks = <&xxx>"
235          * (if system has common clock)
236          *  or "system-clock-frequency = <xxx>"
237          *  or device's module clock.
238          */
239         if (of_property_read_bool(np, "clocks")) {
240                 clk = of_clk_get(np, 0);
241                 if (IS_ERR(clk)) {
242                         ret = PTR_ERR(clk);
243                         return ret;
244                 }
245 
246                 dai->sysclk = clk_get_rate(clk);
247                 dai->clk = clk;
248         } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) {
249                 dai->sysclk = val;
250         } else {
251                 clk = of_clk_get(args.np, 0);
252                 if (!IS_ERR(clk))
253                         dai->sysclk = clk_get_rate(clk);
254         }
255 
256         return 0;
257 }
258 
259 static int asoc_simple_card_parse_daifmt(struct device_node *node,
260                                          struct simple_card_data *priv,
261                                          struct device_node *codec,
262                                          char *prefix, int idx)
263 {
264         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
265         struct device *dev = simple_priv_to_dev(priv);
266         struct device_node *bitclkmaster = NULL;
267         struct device_node *framemaster = NULL;
268         unsigned int daifmt;
269 
270         daifmt = snd_soc_of_parse_daifmt(node, prefix,
271                                          &bitclkmaster, &framemaster);
272         daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
273 
274         if (strlen(prefix) && !bitclkmaster && !framemaster) {
275                 /*
276                  * No dai-link level and master setting was not found from
277                  * sound node level, revert back to legacy DT parsing and
278                  * take the settings from codec node.
279                  */
280                 dev_dbg(dev, "Revert to legacy daifmt parsing\n");
281 
282                 daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) |
283                         (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
284         } else {
285                 if (codec == bitclkmaster)
286                         daifmt |= (codec == framemaster) ?
287                                 SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
288                 else
289                         daifmt |= (codec == framemaster) ?
290                                 SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
291         }
292 
293         dai_link->dai_fmt = daifmt;
294 
295         of_node_put(bitclkmaster);
296         of_node_put(framemaster);
297 
298         return 0;
299 }
300 
301 static int asoc_simple_card_dai_link_of(struct device_node *node,
302                                         struct simple_card_data *priv,
303                                         int idx,
304                                         bool is_top_level_node)
305 {
306         struct device *dev = simple_priv_to_dev(priv);
307         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
308         struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
309         struct device_node *cpu = NULL;
310         struct device_node *codec = NULL;
311         char *name;
312         char prop[128];
313         char *prefix = "";
314         int ret, cpu_args;
315 
316         /* For single DAI link & old style of DT node */
317         if (is_top_level_node)
318                 prefix = "simple-audio-card,";
319 
320         snprintf(prop, sizeof(prop), "%scpu", prefix);
321         cpu = of_get_child_by_name(node, prop);
322 
323         snprintf(prop, sizeof(prop), "%scodec", prefix);
324         codec = of_get_child_by_name(node, prop);
325 
326         if (!cpu || !codec) {
327                 ret = -EINVAL;
328                 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
329                 goto dai_link_of_err;
330         }
331 
332         ret = asoc_simple_card_parse_daifmt(node, priv,
333                                             codec, prefix, idx);
334         if (ret < 0)
335                 goto dai_link_of_err;
336 
337         ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai,
338                                             &dai_link->cpu_of_node,
339                                             &dai_link->cpu_dai_name,
340                                             &cpu_args);
341         if (ret < 0)
342                 goto dai_link_of_err;
343 
344         ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai,
345                                             &dai_link->codec_of_node,
346                                             &dai_link->codec_dai_name, NULL);
347         if (ret < 0)
348                 goto dai_link_of_err;
349 
350         if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
351                 ret = -EINVAL;
352                 goto dai_link_of_err;
353         }
354 
355         /* Simple Card assumes platform == cpu */
356         dai_link->platform_of_node = dai_link->cpu_of_node;
357 
358         /* DAI link name is created from CPU/CODEC dai name */
359         name = devm_kzalloc(dev,
360                             strlen(dai_link->cpu_dai_name)   +
361                             strlen(dai_link->codec_dai_name) + 2,
362                             GFP_KERNEL);
363         if (!name) {
364                 ret = -ENOMEM;
365                 goto dai_link_of_err;
366         }
367 
368         sprintf(name, "%s-%s", dai_link->cpu_dai_name,
369                                 dai_link->codec_dai_name);
370         dai_link->name = dai_link->stream_name = name;
371         dai_link->ops = &asoc_simple_card_ops;
372         dai_link->init = asoc_simple_card_dai_init;
373 
374         dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
375         dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
376         dev_dbg(dev, "\tcpu : %s / %d\n",
377                 dai_link->cpu_dai_name,
378                 dai_props->cpu_dai.sysclk);
379         dev_dbg(dev, "\tcodec : %s / %d\n",
380                 dai_link->codec_dai_name,
381                 dai_props->codec_dai.sysclk);
382 
383         /*
384          * In soc_bind_dai_link() will check cpu name after
385          * of_node matching if dai_link has cpu_dai_name.
386          * but, it will never match if name was created by
387          * fmt_single_name() remove cpu_dai_name if cpu_args
388          * was 0. See:
389          *      fmt_single_name()
390          *      fmt_multiple_name()
391          */
392         if (!cpu_args)
393                 dai_link->cpu_dai_name = NULL;
394 
395 dai_link_of_err:
396         of_node_put(cpu);
397         of_node_put(codec);
398 
399         return ret;
400 }
401 
402 static int asoc_simple_card_parse_of(struct device_node *node,
403                                      struct simple_card_data *priv)
404 {
405         struct device *dev = simple_priv_to_dev(priv);
406         enum of_gpio_flags flags;
407         u32 val;
408         int ret;
409 
410         if (!node)
411                 return -EINVAL;
412 
413         /* Parse the card name from DT */
414         snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name");
415 
416         /* The off-codec widgets */
417         if (of_property_read_bool(node, "simple-audio-card,widgets")) {
418                 ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
419                                         "simple-audio-card,widgets");
420                 if (ret)
421                         return ret;
422         }
423 
424         /* DAPM routes */
425         if (of_property_read_bool(node, "simple-audio-card,routing")) {
426                 ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
427                                         "simple-audio-card,routing");
428                 if (ret)
429                         return ret;
430         }
431 
432         /* Factor to mclk, used in hw_params() */
433         ret = of_property_read_u32(node, "simple-audio-card,mclk-fs", &val);
434         if (ret == 0)
435                 priv->mclk_fs = val;
436 
437         dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ?
438                 priv->snd_card.name : "");
439 
440         /* Single/Muti DAI link(s) & New style of DT node */
441         if (of_get_child_by_name(node, "simple-audio-card,dai-link")) {
442                 struct device_node *np = NULL;
443                 int i = 0;
444 
445                 for_each_child_of_node(node, np) {
446                         dev_dbg(dev, "\tlink %d:\n", i);
447                         ret = asoc_simple_card_dai_link_of(np, priv,
448                                                            i, false);
449                         if (ret < 0) {
450                                 of_node_put(np);
451                                 return ret;
452                         }
453                         i++;
454                 }
455         } else {
456                 /* For single DAI link & old style of DT node */
457                 ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
458                 if (ret < 0)
459                         return ret;
460         }
461 
462         priv->gpio_hp_det = of_get_named_gpio_flags(node,
463                                 "simple-audio-card,hp-det-gpio", 0, &flags);
464         priv->gpio_hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW);
465         if (priv->gpio_hp_det == -EPROBE_DEFER)
466                 return -EPROBE_DEFER;
467 
468         priv->gpio_mic_det = of_get_named_gpio_flags(node,
469                                 "simple-audio-card,mic-det-gpio", 0, &flags);
470         priv->gpio_mic_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW);
471         if (priv->gpio_mic_det == -EPROBE_DEFER)
472                 return -EPROBE_DEFER;
473 
474         if (!priv->snd_card.name)
475                 priv->snd_card.name = priv->snd_card.dai_link->name;
476 
477         return 0;
478 }
479 
480 /* Decrease the reference count of the device nodes */
481 static int asoc_simple_card_unref(struct snd_soc_card *card)
482 {
483         struct snd_soc_dai_link *dai_link;
484         int num_links;
485 
486         for (num_links = 0, dai_link = card->dai_link;
487              num_links < card->num_links;
488              num_links++, dai_link++) {
489                 of_node_put(dai_link->cpu_of_node);
490                 of_node_put(dai_link->codec_of_node);
491         }
492         return 0;
493 }
494 
495 static int asoc_simple_card_probe(struct platform_device *pdev)
496 {
497         struct simple_card_data *priv;
498         struct snd_soc_dai_link *dai_link;
499         struct device_node *np = pdev->dev.of_node;
500         struct device *dev = &pdev->dev;
501         int num_links, ret;
502 
503         /* Get the number of DAI links */
504         if (np && of_get_child_by_name(np, "simple-audio-card,dai-link"))
505                 num_links = of_get_child_count(np);
506         else
507                 num_links = 1;
508 
509         /* Allocate the private data and the DAI link array */
510         priv = devm_kzalloc(dev,
511                         sizeof(*priv) + sizeof(*dai_link) * num_links,
512                         GFP_KERNEL);
513         if (!priv)
514                 return -ENOMEM;
515 
516         /* Init snd_soc_card */
517         priv->snd_card.owner = THIS_MODULE;
518         priv->snd_card.dev = dev;
519         dai_link = priv->dai_link;
520         priv->snd_card.dai_link = dai_link;
521         priv->snd_card.num_links = num_links;
522 
523         priv->gpio_hp_det = -ENOENT;
524         priv->gpio_mic_det = -ENOENT;
525 
526         /* Get room for the other properties */
527         priv->dai_props = devm_kzalloc(dev,
528                         sizeof(*priv->dai_props) * num_links,
529                         GFP_KERNEL);
530         if (!priv->dai_props)
531                 return -ENOMEM;
532 
533         if (np && of_device_is_available(np)) {
534 
535                 ret = asoc_simple_card_parse_of(np, priv);
536                 if (ret < 0) {
537                         if (ret != -EPROBE_DEFER)
538                                 dev_err(dev, "parse error %d\n", ret);
539                         goto err;
540                 }
541 
542         } else {
543                 struct asoc_simple_card_info *cinfo;
544 
545                 cinfo = dev->platform_data;
546                 if (!cinfo) {
547                         dev_err(dev, "no info for asoc-simple-card\n");
548                         return -EINVAL;
549                 }
550 
551                 if (!cinfo->name ||
552                     !cinfo->codec_dai.name ||
553                     !cinfo->codec ||
554                     !cinfo->platform ||
555                     !cinfo->cpu_dai.name) {
556                         dev_err(dev, "insufficient asoc_simple_card_info settings\n");
557                         return -EINVAL;
558                 }
559 
560                 priv->snd_card.name     = (cinfo->card) ? cinfo->card : cinfo->name;
561                 dai_link->name          = cinfo->name;
562                 dai_link->stream_name   = cinfo->name;
563                 dai_link->platform_name = cinfo->platform;
564                 dai_link->codec_name    = cinfo->codec;
565                 dai_link->cpu_dai_name  = cinfo->cpu_dai.name;
566                 dai_link->codec_dai_name = cinfo->codec_dai.name;
567                 dai_link->dai_fmt       = cinfo->daifmt;
568                 dai_link->init          = asoc_simple_card_dai_init;
569                 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
570                                         sizeof(priv->dai_props->cpu_dai));
571                 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
572                                         sizeof(priv->dai_props->codec_dai));
573 
574         }
575 
576         snd_soc_card_set_drvdata(&priv->snd_card, priv);
577 
578         ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
579         if (ret >= 0)
580                 return ret;
581 
582 err:
583         asoc_simple_card_unref(&priv->snd_card);
584         return ret;
585 }
586 
587 static int asoc_simple_card_remove(struct platform_device *pdev)
588 {
589         struct snd_soc_card *card = platform_get_drvdata(pdev);
590         struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
591 
592         if (gpio_is_valid(priv->gpio_hp_det))
593                 snd_soc_jack_free_gpios(&simple_card_hp_jack, 1,
594                                         &simple_card_hp_jack_gpio);
595         if (gpio_is_valid(priv->gpio_mic_det))
596                 snd_soc_jack_free_gpios(&simple_card_mic_jack, 1,
597                                         &simple_card_mic_jack_gpio);
598 
599         return asoc_simple_card_unref(card);
600 }
601 
602 static const struct of_device_id asoc_simple_of_match[] = {
603         { .compatible = "simple-audio-card", },
604         {},
605 };
606 MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
607 
608 static struct platform_driver asoc_simple_card = {
609         .driver = {
610                 .name = "asoc-simple-card",
611                 .of_match_table = asoc_simple_of_match,
612         },
613         .probe = asoc_simple_card_probe,
614         .remove = asoc_simple_card_remove,
615 };
616 
617 module_platform_driver(asoc_simple_card);
618 
619 MODULE_ALIAS("platform:asoc-simple-card");
620 MODULE_LICENSE("GPL");
621 MODULE_DESCRIPTION("ASoC Simple Sound Card");
622 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
623 

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