GNU Linux-libre 4.19.264-gnu1
[releases.git] / sound / soc / generic / simple-card.c
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // ASoC simple sound card support
4 //
5 // Copyright (C) 2012 Renesas Solutions Corp.
6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
7
8 #include <linux/clk.h>
9 #include <linux/device.h>
10 #include <linux/module.h>
11 #include <linux/of.h>
12 #include <linux/platform_device.h>
13 #include <linux/string.h>
14 #include <sound/simple_card.h>
15 #include <sound/soc-dai.h>
16 #include <sound/soc.h>
17
18 struct simple_card_data {
19         struct snd_soc_card snd_card;
20         struct simple_dai_props {
21                 struct asoc_simple_dai cpu_dai;
22                 struct asoc_simple_dai codec_dai;
23                 unsigned int mclk_fs;
24         } *dai_props;
25         unsigned int mclk_fs;
26         struct asoc_simple_jack hp_jack;
27         struct asoc_simple_jack mic_jack;
28         struct snd_soc_dai_link *dai_link;
29 };
30
31 #define simple_priv_to_card(priv) (&(priv)->snd_card)
32 #define simple_priv_to_props(priv, i) ((priv)->dai_props + (i))
33 #define simple_priv_to_dev(priv) (simple_priv_to_card(priv)->dev)
34 #define simple_priv_to_link(priv, i) (simple_priv_to_card(priv)->dai_link + (i))
35
36 #define DAI     "sound-dai"
37 #define CELL    "#sound-dai-cells"
38 #define PREFIX  "simple-audio-card,"
39
40 static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
41 {
42         struct snd_soc_pcm_runtime *rtd = substream->private_data;
43         struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
44         struct simple_dai_props *dai_props =
45                 simple_priv_to_props(priv, rtd->num);
46         int ret;
47
48         ret = asoc_simple_card_clk_enable(&dai_props->cpu_dai);
49         if (ret)
50                 return ret;
51
52         ret = asoc_simple_card_clk_enable(&dai_props->codec_dai);
53         if (ret)
54                 asoc_simple_card_clk_disable(&dai_props->cpu_dai);
55
56         return ret;
57 }
58
59 static void asoc_simple_card_shutdown(struct snd_pcm_substream *substream)
60 {
61         struct snd_soc_pcm_runtime *rtd = substream->private_data;
62         struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
63         struct simple_dai_props *dai_props =
64                 simple_priv_to_props(priv, rtd->num);
65
66         asoc_simple_card_clk_disable(&dai_props->cpu_dai);
67
68         asoc_simple_card_clk_disable(&dai_props->codec_dai);
69 }
70
71 static int asoc_simple_set_clk_rate(struct asoc_simple_dai *simple_dai,
72                                     unsigned long rate)
73 {
74         if (!simple_dai->clk)
75                 return 0;
76
77         if (clk_get_rate(simple_dai->clk) == rate)
78                 return 0;
79
80         return clk_set_rate(simple_dai->clk, rate);
81 }
82
83 static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream,
84                                       struct snd_pcm_hw_params *params)
85 {
86         struct snd_soc_pcm_runtime *rtd = substream->private_data;
87         struct snd_soc_dai *codec_dai = rtd->codec_dai;
88         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
89         struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
90         struct simple_dai_props *dai_props =
91                 simple_priv_to_props(priv, rtd->num);
92         unsigned int mclk, mclk_fs = 0;
93         int ret = 0;
94
95         if (priv->mclk_fs)
96                 mclk_fs = priv->mclk_fs;
97         else if (dai_props->mclk_fs)
98                 mclk_fs = dai_props->mclk_fs;
99
100         if (mclk_fs) {
101                 mclk = params_rate(params) * mclk_fs;
102
103                 ret = asoc_simple_set_clk_rate(&dai_props->codec_dai, mclk);
104                 if (ret < 0)
105                         return ret;
106
107                 ret = asoc_simple_set_clk_rate(&dai_props->cpu_dai, mclk);
108                 if (ret < 0)
109                         return ret;
110
111                 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
112                                              SND_SOC_CLOCK_IN);
113                 if (ret && ret != -ENOTSUPP)
114                         goto err;
115
116                 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
117                                              SND_SOC_CLOCK_OUT);
118                 if (ret && ret != -ENOTSUPP)
119                         goto err;
120         }
121         return 0;
122 err:
123         return ret;
124 }
125
126 static const struct snd_soc_ops asoc_simple_card_ops = {
127         .startup = asoc_simple_card_startup,
128         .shutdown = asoc_simple_card_shutdown,
129         .hw_params = asoc_simple_card_hw_params,
130 };
131
132 static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
133 {
134         struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
135         struct snd_soc_dai *codec = rtd->codec_dai;
136         struct snd_soc_dai *cpu = rtd->cpu_dai;
137         struct simple_dai_props *dai_props =
138                 simple_priv_to_props(priv, rtd->num);
139         int ret;
140
141         ret = asoc_simple_card_init_dai(codec, &dai_props->codec_dai);
142         if (ret < 0)
143                 return ret;
144
145         ret = asoc_simple_card_init_dai(cpu, &dai_props->cpu_dai);
146         if (ret < 0)
147                 return ret;
148
149         return 0;
150 }
151
152 static int asoc_simple_card_dai_link_of(struct device_node *node,
153                                         struct simple_card_data *priv,
154                                         int idx,
155                                         bool is_top_level_node)
156 {
157         struct device *dev = simple_priv_to_dev(priv);
158         struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
159         struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
160         struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
161         struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
162         struct device_node *cpu = NULL;
163         struct device_node *plat = NULL;
164         struct device_node *codec = NULL;
165         char prop[128];
166         char *prefix = "";
167         int ret, single_cpu;
168
169         /* For single DAI link & old style of DT node */
170         if (is_top_level_node)
171                 prefix = PREFIX;
172
173         snprintf(prop, sizeof(prop), "%scpu", prefix);
174         cpu = of_get_child_by_name(node, prop);
175
176         if (!cpu) {
177                 ret = -EINVAL;
178                 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
179                 goto dai_link_of_err;
180         }
181
182         snprintf(prop, sizeof(prop), "%splat", prefix);
183         plat = of_get_child_by_name(node, prop);
184
185         snprintf(prop, sizeof(prop), "%scodec", prefix);
186         codec = of_get_child_by_name(node, prop);
187
188         if (!codec) {
189                 ret = -EINVAL;
190                 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
191                 goto dai_link_of_err;
192         }
193
194         ret = asoc_simple_card_parse_daifmt(dev, node, codec,
195                                             prefix, &dai_link->dai_fmt);
196         if (ret < 0)
197                 goto dai_link_of_err;
198
199         of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
200
201         ret = asoc_simple_card_parse_cpu(cpu, dai_link,
202                                          DAI, CELL, &single_cpu);
203         if (ret < 0)
204                 goto dai_link_of_err;
205
206         ret = asoc_simple_card_parse_codec(codec, dai_link, DAI, CELL);
207         if (ret < 0)
208                 goto dai_link_of_err;
209
210         ret = asoc_simple_card_parse_platform(plat, dai_link, DAI, CELL);
211         if (ret < 0)
212                 goto dai_link_of_err;
213
214         ret = asoc_simple_card_of_parse_tdm(cpu, cpu_dai);
215         if (ret < 0)
216                 goto dai_link_of_err;
217
218         ret = asoc_simple_card_of_parse_tdm(codec, codec_dai);
219         if (ret < 0)
220                 goto dai_link_of_err;
221
222         ret = asoc_simple_card_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
223         if (ret < 0)
224                 goto dai_link_of_err;
225
226         ret = asoc_simple_card_parse_clk_codec(dev, codec, dai_link, codec_dai);
227         if (ret < 0)
228                 goto dai_link_of_err;
229
230         ret = asoc_simple_card_canonicalize_dailink(dai_link);
231         if (ret < 0)
232                 goto dai_link_of_err;
233
234         ret = asoc_simple_card_set_dailink_name(dev, dai_link,
235                                                 "%s-%s",
236                                                 dai_link->cpu_dai_name,
237                                                 dai_link->codec_dai_name);
238         if (ret < 0)
239                 goto dai_link_of_err;
240
241         dai_link->ops = &asoc_simple_card_ops;
242         dai_link->init = asoc_simple_card_dai_init;
243
244         asoc_simple_card_canonicalize_cpu(dai_link, single_cpu);
245
246 dai_link_of_err:
247         of_node_put(cpu);
248         of_node_put(codec);
249
250         return ret;
251 }
252
253 static int asoc_simple_card_parse_aux_devs(struct device_node *node,
254                                            struct simple_card_data *priv)
255 {
256         struct device *dev = simple_priv_to_dev(priv);
257         struct device_node *aux_node;
258         struct snd_soc_card *card = simple_priv_to_card(priv);
259         int i, n, len;
260
261         if (!of_find_property(node, PREFIX "aux-devs", &len))
262                 return 0;               /* Ok to have no aux-devs */
263
264         n = len / sizeof(__be32);
265         if (n <= 0)
266                 return -EINVAL;
267
268         card->aux_dev = devm_kcalloc(dev,
269                         n, sizeof(*card->aux_dev), GFP_KERNEL);
270         if (!card->aux_dev)
271                 return -ENOMEM;
272
273         for (i = 0; i < n; i++) {
274                 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
275                 if (!aux_node)
276                         return -EINVAL;
277                 card->aux_dev[i].codec_of_node = aux_node;
278         }
279
280         card->num_aux_devs = n;
281         return 0;
282 }
283
284 static int asoc_simple_card_parse_of(struct simple_card_data *priv)
285 {
286         struct device *dev = simple_priv_to_dev(priv);
287         struct snd_soc_card *card = simple_priv_to_card(priv);
288         struct device_node *dai_link;
289         struct device_node *node = dev->of_node;
290         int ret;
291
292         if (!node)
293                 return -EINVAL;
294
295         dai_link = of_get_child_by_name(node, PREFIX "dai-link");
296
297         ret = asoc_simple_card_of_parse_widgets(card, PREFIX);
298         if (ret < 0)
299                 goto card_parse_end;
300
301         ret = asoc_simple_card_of_parse_routing(card, PREFIX, 1);
302         if (ret < 0)
303                 goto card_parse_end;
304
305         /* Factor to mclk, used in hw_params() */
306         of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
307
308         /* Single/Muti DAI link(s) & New style of DT node */
309         if (dai_link) {
310                 struct device_node *np = NULL;
311                 int i = 0;
312
313                 for_each_child_of_node(node, np) {
314                         dev_dbg(dev, "\tlink %d:\n", i);
315                         ret = asoc_simple_card_dai_link_of(np, priv,
316                                                            i, false);
317                         if (ret < 0) {
318                                 of_node_put(np);
319                                 goto card_parse_end;
320                         }
321                         i++;
322                 }
323         } else {
324                 /* For single DAI link & old style of DT node */
325                 ret = asoc_simple_card_dai_link_of(node, priv, 0, true);
326                 if (ret < 0)
327                         goto card_parse_end;
328         }
329
330         ret = asoc_simple_card_parse_card_name(card, PREFIX);
331         if (ret < 0)
332                 goto card_parse_end;
333
334         ret = asoc_simple_card_parse_aux_devs(node, priv);
335
336 card_parse_end:
337         of_node_put(dai_link);
338
339         return ret;
340 }
341
342 static int asoc_simple_soc_card_probe(struct snd_soc_card *card)
343 {
344         struct simple_card_data *priv = snd_soc_card_get_drvdata(card);
345         int ret;
346
347         ret = asoc_simple_card_init_hp(card, &priv->hp_jack, PREFIX);
348         if (ret < 0)
349                 return ret;
350
351         ret = asoc_simple_card_init_mic(card, &priv->mic_jack, PREFIX);
352         if (ret < 0)
353                 return ret;
354
355         return 0;
356 }
357
358 static int asoc_simple_card_probe(struct platform_device *pdev)
359 {
360         struct simple_card_data *priv;
361         struct snd_soc_dai_link *dai_link;
362         struct simple_dai_props *dai_props;
363         struct device *dev = &pdev->dev;
364         struct device_node *np = dev->of_node;
365         struct snd_soc_card *card;
366         int num, ret;
367
368         /* Get the number of DAI links */
369         if (np && of_get_child_by_name(np, PREFIX "dai-link"))
370                 num = of_get_child_count(np);
371         else
372                 num = 1;
373
374         /* Allocate the private data and the DAI link array */
375         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
376         if (!priv)
377                 return -ENOMEM;
378
379         dai_props = devm_kcalloc(dev, num, sizeof(*dai_props), GFP_KERNEL);
380         dai_link  = devm_kcalloc(dev, num, sizeof(*dai_link), GFP_KERNEL);
381         if (!dai_props || !dai_link)
382                 return -ENOMEM;
383
384         priv->dai_props                 = dai_props;
385         priv->dai_link                  = dai_link;
386
387         /* Init snd_soc_card */
388         card = simple_priv_to_card(priv);
389         card->owner             = THIS_MODULE;
390         card->dev               = dev;
391         card->dai_link          = priv->dai_link;
392         card->num_links         = num;
393         card->probe             = asoc_simple_soc_card_probe;
394
395         if (np && of_device_is_available(np)) {
396
397                 ret = asoc_simple_card_parse_of(priv);
398                 if (ret < 0) {
399                         if (ret != -EPROBE_DEFER)
400                                 dev_err(dev, "parse error %d\n", ret);
401                         goto err;
402                 }
403
404         } else {
405                 struct asoc_simple_card_info *cinfo;
406
407                 cinfo = dev->platform_data;
408                 if (!cinfo) {
409                         dev_err(dev, "no info for asoc-simple-card\n");
410                         return -EINVAL;
411                 }
412
413                 if (!cinfo->name ||
414                     !cinfo->codec_dai.name ||
415                     !cinfo->codec ||
416                     !cinfo->platform ||
417                     !cinfo->cpu_dai.name) {
418                         dev_err(dev, "insufficient asoc_simple_card_info settings\n");
419                         return -EINVAL;
420                 }
421
422                 card->name              = (cinfo->card) ? cinfo->card : cinfo->name;
423                 dai_link->name          = cinfo->name;
424                 dai_link->stream_name   = cinfo->name;
425                 dai_link->platform_name = cinfo->platform;
426                 dai_link->codec_name    = cinfo->codec;
427                 dai_link->cpu_dai_name  = cinfo->cpu_dai.name;
428                 dai_link->codec_dai_name = cinfo->codec_dai.name;
429                 dai_link->dai_fmt       = cinfo->daifmt;
430                 dai_link->init          = asoc_simple_card_dai_init;
431                 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
432                                         sizeof(priv->dai_props->cpu_dai));
433                 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
434                                         sizeof(priv->dai_props->codec_dai));
435         }
436
437         snd_soc_card_set_drvdata(card, priv);
438
439         ret = devm_snd_soc_register_card(dev, card);
440         if (ret < 0)
441                 goto err;
442
443         return 0;
444 err:
445         asoc_simple_card_clean_reference(card);
446
447         return ret;
448 }
449
450 static int asoc_simple_card_remove(struct platform_device *pdev)
451 {
452         struct snd_soc_card *card = platform_get_drvdata(pdev);
453
454         return asoc_simple_card_clean_reference(card);
455 }
456
457 static const struct of_device_id asoc_simple_of_match[] = {
458         { .compatible = "simple-audio-card", },
459         {},
460 };
461 MODULE_DEVICE_TABLE(of, asoc_simple_of_match);
462
463 static struct platform_driver asoc_simple_card = {
464         .driver = {
465                 .name = "asoc-simple-card",
466                 .pm = &snd_soc_pm_ops,
467                 .of_match_table = asoc_simple_of_match,
468         },
469         .probe = asoc_simple_card_probe,
470         .remove = asoc_simple_card_remove,
471 };
472
473 module_platform_driver(asoc_simple_card);
474
475 MODULE_ALIAS("platform:asoc-simple-card");
476 MODULE_LICENSE("GPL v2");
477 MODULE_DESCRIPTION("ASoC Simple Sound Card");
478 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");