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