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