ASoC: ac108: Fix changed interface
[platform/kernel/linux-rpi.git] / sound / soc / seeed / seeed-voicecard.c
1 /*
2  * SEEED voice card
3  *
4  * (C) Copyright 2017-2018
5  * Seeed Technology Co., Ltd. <www.seeedstudio.com>
6  *
7  * base on ASoC simple sound card support
8  *
9  * Copyright (C) 2012 Renesas Solutions Corp.
10  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License version 2 as
14  * published by the Free Software Foundation.
15  */
16 /* #undef DEBUG */
17 #include <linux/version.h>
18 #include <linux/clk.h>
19 #include <linux/device.h>
20 #include <linux/gpio.h>
21 #include <linux/module.h>
22 #include <linux/of.h>
23 #include <linux/of_gpio.h>
24 #include <linux/platform_device.h>
25 #include <linux/string.h>
26 #include <sound/soc.h>
27 #include <sound/soc-dai.h>
28 #include <sound/simple_card_utils.h>
29 //#include <sound/soc/codecs/ac10x.h>
30 #include "../codecs/ac10x.h"
31
32
33 /*
34  * single codec:
35  *      0 - allow multi codec
36  *      1 - yes
37  */
38 #define _SINGLE_CODEC           1
39
40 struct seeed_card_data {
41         struct snd_soc_card snd_card;
42         struct seeed_dai_props {
43                 struct asoc_simple_dai cpu_dai;
44                 struct asoc_simple_dai codec_dai;
45                 unsigned int mclk_fs;
46         } *dai_props;
47         unsigned int mclk_fs;
48         unsigned channels_playback_default;
49         unsigned channels_playback_override;
50         unsigned channels_capture_default;
51         unsigned channels_capture_override;
52         struct snd_soc_dai_link *dai_link;
53         #if CONFIG_AC10X_TRIG_LOCK
54         spinlock_t lock;
55         #endif
56         struct work_struct work_codec_clk;
57         #define TRY_STOP_MAX    3
58         int try_stop;
59 };
60
61 struct seeed_card_info {
62         const char *name;
63         const char *card;
64         const char *codec;
65         const char *platform;
66
67         unsigned int daifmt;
68         struct asoc_simple_dai cpu_dai;
69         struct asoc_simple_dai codec_dai;
70 };
71
72 #define seeed_priv_to_dev(priv) ((priv)->snd_card.dev)
73 #define seeed_priv_to_link(priv, i) ((priv)->snd_card.dai_link + (i))
74 #define seeed_priv_to_props(priv, i) ((priv)->dai_props + (i))
75
76 #define DAI     "sound-dai"
77 #define CELL    "#sound-dai-cells"
78 #define PREFIX  "seeed-voice-card,"
79
80 #define _SET_CLOCK_CNT          2
81 static int (* _set_clock[_SET_CLOCK_CNT])(int y_start_n_stop);
82
83 static int seeed_voice_card_startup(struct snd_pcm_substream *substream)
84 {
85         struct snd_soc_pcm_runtime *rtd = substream->private_data;
86         struct seeed_card_data *priv =  snd_soc_card_get_drvdata(rtd->card);
87         struct seeed_dai_props *dai_props =
88                 seeed_priv_to_props(priv, rtd->num);
89         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
90         int ret;
91
92         ret = clk_prepare_enable(dai_props->cpu_dai.clk);
93         if (ret)
94                 return ret;
95
96         ret = clk_prepare_enable(dai_props->codec_dai.clk);
97         if (ret)
98                 clk_disable_unprepare(dai_props->cpu_dai.clk);
99
100         if (cpu_dai->driver->playback.channels_min) {
101                 priv->channels_playback_default = cpu_dai->driver->playback.channels_min;
102         }
103         if (cpu_dai->driver->capture.channels_min) {
104                 priv->channels_capture_default = cpu_dai->driver->capture.channels_min;
105         }
106         cpu_dai->driver->playback.channels_min = priv->channels_playback_override;
107         cpu_dai->driver->playback.channels_max = priv->channels_playback_override;
108         cpu_dai->driver->capture.channels_min = priv->channels_capture_override;
109         cpu_dai->driver->capture.channels_max = priv->channels_capture_override;
110
111         return ret;
112 }
113
114 static void seeed_voice_card_shutdown(struct snd_pcm_substream *substream)
115 {
116         struct snd_soc_pcm_runtime *rtd = substream->private_data;
117         struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0);
118         struct seeed_card_data *priv =  snd_soc_card_get_drvdata(rtd->card);
119         struct seeed_dai_props *dai_props =
120                 seeed_priv_to_props(priv, rtd->num);
121         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
122
123         cpu_dai->driver->playback.channels_min = priv->channels_playback_default;
124         cpu_dai->driver->playback.channels_max = priv->channels_playback_default;
125         cpu_dai->driver->capture.channels_min = priv->channels_capture_default;
126         cpu_dai->driver->capture.channels_max = priv->channels_capture_default;
127
128         clk_disable_unprepare(dai_props->cpu_dai.clk);
129
130         clk_disable_unprepare(dai_props->codec_dai.clk);
131
132         if (dai->stream_active[SNDRV_PCM_STREAM_CAPTURE] &&
133             substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
134                 return;
135
136         /* interrupt environment */
137         if (in_irq() || in_nmi() || in_serving_softirq()) {
138                 priv->try_stop = 0;
139                 if (0 != schedule_work(&priv->work_codec_clk)) {
140                 }
141         } else {
142                 if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](0);
143                 if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0);
144         }
145 }
146
147 static int seeed_voice_card_hw_params(struct snd_pcm_substream *substream,
148                                       struct snd_pcm_hw_params *params)
149 {
150         struct snd_soc_pcm_runtime *rtd = substream->private_data;
151         struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
152         struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
153         struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
154         struct seeed_dai_props *dai_props =
155                 seeed_priv_to_props(priv, rtd->num);
156         unsigned int mclk, mclk_fs = 0;
157         int ret = 0;
158
159         if (priv->mclk_fs)
160                 mclk_fs = priv->mclk_fs;
161         else if (dai_props->mclk_fs)
162                 mclk_fs = dai_props->mclk_fs;
163
164         if (mclk_fs) {
165                 mclk = params_rate(params) * mclk_fs;
166                 ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
167                                              SND_SOC_CLOCK_IN);
168                 if (ret && ret != -ENOTSUPP)
169                         goto err;
170
171                 ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
172                                              SND_SOC_CLOCK_OUT);
173                 if (ret && ret != -ENOTSUPP)
174                         goto err;
175         }
176
177         return 0;
178 err:
179         return ret;
180 }
181
182 int seeed_voice_card_prepare(struct snd_pcm_substream *substream)
183 {
184         struct snd_soc_pcm_runtime *rtd = substream->private_data;
185         struct seeed_card_data *priv = snd_soc_card_get_drvdata(rtd->card);
186
187         if (cancel_work_sync(&priv->work_codec_clk) != 0) {}
188
189         #if CONFIG_AC10X_TRIG_LOCK
190         /* I know it will degrades performance, but I have no choice */
191         spin_lock_irqsave(&priv->lock, flags);
192         #endif
193         if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) _set_clock[SNDRV_PCM_STREAM_CAPTURE](1);
194         if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) _set_clock[SNDRV_PCM_STREAM_PLAYBACK](1);
195         #if CONFIG_AC10X_TRIG_LOCK
196         spin_unlock_irqrestore(&priv->lock, flags);
197         #endif
198
199         return 0;
200 }
201
202 int seeed_voice_card_register_set_clock(int stream, int (*set_clock)(int)) {
203         if (! _set_clock[stream]) {
204                 _set_clock[stream] = set_clock;
205         }
206         return 0;
207 }
208 EXPORT_SYMBOL(seeed_voice_card_register_set_clock);
209
210 /*
211  * work_cb_codec_clk: clear audio codec inner clock.
212  */
213 static void work_cb_codec_clk(struct work_struct *work)
214 {
215         struct seeed_card_data *priv = container_of(work, struct seeed_card_data, work_codec_clk);
216         int r = 0;
217
218         if (_set_clock[SNDRV_PCM_STREAM_CAPTURE]) {
219                 r = r || _set_clock[SNDRV_PCM_STREAM_CAPTURE](0);
220         }
221         if (_set_clock[SNDRV_PCM_STREAM_PLAYBACK]) {
222                 r = r || _set_clock[SNDRV_PCM_STREAM_PLAYBACK](0);
223         }
224
225         if (r && priv->try_stop++ < TRY_STOP_MAX) {
226                 if (0 != schedule_work(&priv->work_codec_clk)) {}
227         }
228         return;
229 }
230
231 static struct snd_soc_ops seeed_voice_card_ops = {
232         .startup = seeed_voice_card_startup,
233         .shutdown = seeed_voice_card_shutdown,
234         .hw_params = seeed_voice_card_hw_params,
235         .prepare = seeed_voice_card_prepare,
236 };
237
238 static int asoc_card_parse_dai(struct device_node *node,
239                                 struct snd_soc_dai_link_component *dlc,
240                                 int *is_single_link)
241 {
242         struct of_phandle_args args;
243         int ret;
244
245         if (!node)
246                 return 0;
247
248         ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args);
249         if (ret)
250                 return ret;
251
252         ret = snd_soc_of_get_dai_name(node, &dlc->dai_name);
253         if (ret < 0)
254                 return ret;
255
256         dlc->of_node = args.np;
257
258         if (is_single_link)
259                 *is_single_link = !args.args_count;
260
261         return 0;
262 }
263
264 static int asoc_card_init_dai(struct snd_soc_dai *dai,
265                                      struct asoc_simple_dai *simple_dai)
266 {
267         int ret;
268
269         if (!simple_dai)
270                 return 0;
271
272         if (simple_dai->sysclk) {
273                 ret = snd_soc_dai_set_sysclk(dai, 0, simple_dai->sysclk,
274                                              simple_dai->clk_direction);
275                 if (ret && ret != -ENOTSUPP) {
276                         dev_err(dai->dev, "simple-card: set_sysclk error\n");
277                         return ret;
278                 }
279         }
280
281         if (simple_dai->slots) {
282                 ret = snd_soc_dai_set_tdm_slot(dai,
283                                                simple_dai->tx_slot_mask,
284                                                simple_dai->rx_slot_mask,
285                                                simple_dai->slots,
286                                                simple_dai->slot_width);
287                 if (ret && ret != -ENOTSUPP) {
288                         dev_err(dai->dev, "simple-card: set_tdm_slot error\n");
289                         return ret;
290                 }
291         }
292
293         return 0;
294 }
295
296 static int seeed_voice_card_dai_init(struct snd_soc_pcm_runtime *rtd)
297 {
298         struct seeed_card_data *priv =  snd_soc_card_get_drvdata(rtd->card);
299         struct snd_soc_dai *codec = asoc_rtd_to_codec(rtd, 0);
300         struct snd_soc_dai *cpu = asoc_rtd_to_cpu(rtd, 0);
301         struct seeed_dai_props *dai_props =
302                 seeed_priv_to_props(priv, rtd->num);
303         int ret;
304
305         ret = asoc_card_init_dai(codec, &dai_props->codec_dai);
306         if (ret < 0)
307                 return ret;
308
309         ret = asoc_card_init_dai(cpu, &dai_props->cpu_dai);
310         if (ret < 0)
311                 return ret;
312
313         return 0;
314 }
315
316 static int seeed_voice_card_dai_link_of(struct device_node *node,
317                                         struct seeed_card_data *priv,
318                                         int idx,
319                                         bool is_top_level_node)
320 {
321         struct device *dev = seeed_priv_to_dev(priv);
322         struct snd_soc_dai_link *dai_link = seeed_priv_to_link(priv, idx);
323         struct seeed_dai_props *dai_props = seeed_priv_to_props(priv, idx);
324         struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
325         struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
326         struct device_node *cpu = NULL;
327         struct device_node *plat = NULL;
328         struct device_node *codec = NULL;
329         char prop[128];
330         char *prefix = "";
331         int ret, single_cpu;
332
333         /* For single DAI link & old style of DT node */
334         if (is_top_level_node)
335                 prefix = PREFIX;
336
337         snprintf(prop, sizeof(prop), "%scpu", prefix);
338         cpu = of_get_child_by_name(node, prop);
339
340         snprintf(prop, sizeof(prop), "%splat", prefix);
341         plat = of_get_child_by_name(node, prop);
342
343         snprintf(prop, sizeof(prop), "%scodec", prefix);
344         codec = of_get_child_by_name(node, prop);
345
346         if (!cpu || !codec) {
347                 ret = -EINVAL;
348                 dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
349                 goto dai_link_of_err;
350         }
351
352         ret = asoc_simple_parse_daifmt(dev, node, codec,
353                                             prefix, &dai_link->dai_fmt);
354         if (ret < 0)
355                 goto dai_link_of_err;
356
357         of_property_read_u32(node, "mclk-fs", &dai_props->mclk_fs);
358
359         ret = asoc_card_parse_dai(cpu, dai_link->cpus, &single_cpu);
360         if (ret < 0)
361                 goto dai_link_of_err;
362
363         #if _SINGLE_CODEC
364         ret = asoc_card_parse_dai(codec, dai_link->codecs, NULL);
365         if (ret < 0)
366                 goto dai_link_of_err;
367         #else
368         ret = snd_soc_of_get_dai_link_codecs(dev, codec, dai_link);
369         if (ret < 0) {
370                 dev_err(dev, "parse codec info error %d\n", ret);
371                 goto dai_link_of_err;
372         }
373         dev_dbg(dev, "dai_link num_codecs = %d\n", dai_link->num_codecs);
374         #endif
375
376         ret = asoc_card_parse_dai(plat, dai_link->platforms, NULL);
377         if (ret < 0)
378                 goto dai_link_of_err;
379
380         ret = snd_soc_of_parse_tdm_slot(cpu,    &cpu_dai->tx_slot_mask,
381                                                 &cpu_dai->rx_slot_mask,
382                                                 &cpu_dai->slots,
383                                                 &cpu_dai->slot_width);
384        dev_dbg(dev, "cpu_dai : slot,width,tx,rx = %d,%d,%d,%d\n",
385                         cpu_dai->slots, cpu_dai->slot_width,
386                         cpu_dai->tx_slot_mask, cpu_dai->rx_slot_mask
387                         );
388         if (ret < 0)
389                 goto dai_link_of_err;
390
391         ret = snd_soc_of_parse_tdm_slot(codec,  &codec_dai->tx_slot_mask,
392                                                 &codec_dai->rx_slot_mask,
393                                                 &codec_dai->slots,
394                                                 &codec_dai->slot_width);
395         if (ret < 0)
396                 goto dai_link_of_err;
397
398         #if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
399         ret = asoc_simple_parse_clk_cpu(cpu, dai_link, cpu_dai);
400         #else
401         ret = asoc_simple_parse_clk_cpu(dev, cpu, dai_link, cpu_dai);
402         #endif
403         if (ret < 0)
404                 goto dai_link_of_err;
405
406         #if LINUX_VERSION_CODE <= KERNEL_VERSION(4,10,0)
407         ret = asoc_simple_parse_clk_codec(codec, dai_link, codec_dai);
408         #else
409         ret = asoc_simple_parse_clk_codec(dev, codec, dai_link, codec_dai);
410         #endif
411         if (ret < 0)
412                 goto dai_link_of_err;
413
414         #if _SINGLE_CODEC
415         asoc_simple_canonicalize_platform(dai_link);
416         #endif
417
418         ret = asoc_simple_set_dailink_name(dev, dai_link,
419                                                 "%s-%s",
420                                                 dai_link->cpus->dai_name,
421                                                 #if _SINGLE_CODEC
422                                                 dai_link->codecs->dai_name
423                                                 #else
424                                                 dai_link->codecs[0].dai_name
425                                                 #endif
426         );
427         if (ret < 0)
428                 goto dai_link_of_err;
429
430         dai_link->ops = &seeed_voice_card_ops;
431         dai_link->init = seeed_voice_card_dai_init;
432
433         dev_dbg(dev, "\tname : %s\n", dai_link->stream_name);
434         dev_dbg(dev, "\tformat : %04x\n", dai_link->dai_fmt);
435         dev_dbg(dev, "\tcpu : %s / %d\n",
436                 dai_link->cpus->dai_name,
437                 dai_props->cpu_dai.sysclk);
438         dev_dbg(dev, "\tcodec : %s / %d\n",
439                 #if _SINGLE_CODEC
440                 dai_link->codecs->dai_name,
441                 #else
442                 dai_link->codecs[0].dai_name,
443                 #endif
444                 dai_props->codec_dai.sysclk);
445
446         asoc_simple_canonicalize_cpu(dai_link, single_cpu);
447
448 dai_link_of_err:
449         of_node_put(cpu);
450         of_node_put(codec);
451
452         return ret;
453 }
454
455 static int seeed_voice_card_parse_aux_devs(struct device_node *node,
456                                            struct seeed_card_data *priv)
457 {
458         struct device *dev = seeed_priv_to_dev(priv);
459         struct device_node *aux_node;
460         int i, n, len;
461
462         if (!of_find_property(node, PREFIX "aux-devs", &len))
463                 return 0;               /* Ok to have no aux-devs */
464
465         n = len / sizeof(__be32);
466         if (n <= 0)
467                 return -EINVAL;
468
469         priv->snd_card.aux_dev = devm_kzalloc(dev,
470                         n * sizeof(*priv->snd_card.aux_dev), GFP_KERNEL);
471         if (!priv->snd_card.aux_dev)
472                 return -ENOMEM;
473
474         for (i = 0; i < n; i++) {
475                 aux_node = of_parse_phandle(node, PREFIX "aux-devs", i);
476                 if (!aux_node)
477                         return -EINVAL;
478                 priv->snd_card.aux_dev[i].dlc.of_node = aux_node;
479         }
480
481         priv->snd_card.num_aux_devs = n;
482         return 0;
483 }
484
485 static int seeed_voice_card_parse_of(struct device_node *node,
486                                      struct seeed_card_data *priv)
487 {
488         struct device *dev = seeed_priv_to_dev(priv);
489         struct device_node *dai_link;
490         int ret;
491
492         if (!node)
493                 return -EINVAL;
494
495         dai_link = of_get_child_by_name(node, PREFIX "dai-link");
496
497         /* The off-codec widgets */
498         if (of_property_read_bool(node, PREFIX "widgets")) {
499                 ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card,
500                                         PREFIX "widgets");
501                 if (ret)
502                         goto card_parse_end;
503         }
504
505         /* DAPM routes */
506         if (of_property_read_bool(node, PREFIX "routing")) {
507                 ret = snd_soc_of_parse_audio_routing(&priv->snd_card,
508                                         PREFIX "routing");
509                 if (ret)
510                         goto card_parse_end;
511         }
512
513         /* Factor to mclk, used in hw_params() */
514         of_property_read_u32(node, PREFIX "mclk-fs", &priv->mclk_fs);
515
516         /* Single/Muti DAI link(s) & New style of DT node */
517         if (dai_link) {
518                 struct device_node *np = NULL;
519                 int i = 0;
520
521                 for_each_child_of_node(node, np) {
522                         dev_dbg(dev, "\tlink %d:\n", i);
523                         ret = seeed_voice_card_dai_link_of(np, priv,
524                                                            i, false);
525                         if (ret < 0) {
526                                 of_node_put(np);
527                                 goto card_parse_end;
528                         }
529                         i++;
530                 }
531         } else {
532                 /* For single DAI link & old style of DT node */
533                 ret = seeed_voice_card_dai_link_of(node, priv, 0, true);
534                 if (ret < 0)
535                         goto card_parse_end;
536         }
537
538         ret = asoc_simple_parse_card_name(&priv->snd_card, PREFIX);
539         if (ret < 0)
540                 goto card_parse_end;
541
542         ret = seeed_voice_card_parse_aux_devs(node, priv);
543
544         priv->channels_playback_default  = 0;
545         priv->channels_playback_override = 2;
546         priv->channels_capture_default   = 0;
547         priv->channels_capture_override  = 2;
548         of_property_read_u32(node, PREFIX "channels-playback-default",
549                                     &priv->channels_playback_default);
550         of_property_read_u32(node, PREFIX "channels-playback-override",
551                                     &priv->channels_playback_override);
552         of_property_read_u32(node, PREFIX "channels-capture-default",
553                                     &priv->channels_capture_default);
554         of_property_read_u32(node, PREFIX "channels-capture-override",
555                                     &priv->channels_capture_override);
556
557 card_parse_end:
558         of_node_put(dai_link);
559
560         return ret;
561 }
562
563 static int seeed_voice_card_probe(struct platform_device *pdev)
564 {
565         struct seeed_card_data *priv;
566         struct snd_soc_dai_link *dai_link;
567         struct snd_soc_dai_link_component *compnent;
568         struct seeed_dai_props *dai_props;
569         struct device_node *np = pdev->dev.of_node;
570         struct device *dev = &pdev->dev;
571         int num, ret;
572
573         /* Get the number of DAI links */
574         if (np && of_get_child_by_name(np, PREFIX "dai-link"))
575                 num = of_get_child_count(np);
576         else
577                 num = 1;
578
579         /* Allocate the private data and the DAI link array */
580         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
581         if (!priv)
582                 return -ENOMEM;
583
584         dai_props = devm_kzalloc(dev, sizeof(*dai_props) * num, GFP_KERNEL);
585         dai_link  = devm_kzalloc(dev, sizeof(*dai_link)  * num, GFP_KERNEL);
586         if (!dai_props || !dai_link)
587                 return -ENOMEM;
588
589         compnent = devm_kzalloc(dev, 3 * sizeof(*compnent), GFP_KERNEL);
590         if (!compnent)
591                 return -ENOMEM;
592
593         dai_link->cpus            = &compnent[0];
594         dai_link->num_cpus        = 1;
595         dai_link->codecs          = &compnent[1];
596         dai_link->num_codecs      = 1;
597         dai_link->platforms       = &compnent[2];
598         dai_link->num_platforms   = 1;
599
600         priv->dai_props                 = dai_props;
601         priv->dai_link                  = dai_link;
602
603         /* Init snd_soc_card */
604         priv->snd_card.owner            = THIS_MODULE;
605         priv->snd_card.dev              = dev;
606         priv->snd_card.dai_link         = priv->dai_link;
607         priv->snd_card.num_links        = num;
608
609         if (np && of_device_is_available(np)) {
610                 ret = seeed_voice_card_parse_of(np, priv);
611                 if (ret < 0) {
612                         if (ret != -EPROBE_DEFER)
613                                 dev_err(dev, "parse error %d\n", ret);
614                         goto err;
615                 }
616         } else {
617                 struct seeed_card_info *cinfo;
618
619                 cinfo = dev->platform_data;
620                 if (!cinfo) {
621                         dev_err(dev, "no info for seeed-voice-card\n");
622                         return -EINVAL;
623                 }
624
625                 if (!cinfo->name ||
626                     !cinfo->codec_dai.name ||
627                     !cinfo->codec ||
628                     !cinfo->platform ||
629                     !cinfo->cpu_dai.name) {
630                         dev_err(dev, "insufficient seeed_voice_card_info settings\n");
631                         return -EINVAL;
632                 }
633
634                 priv->snd_card.name     = (cinfo->card) ? cinfo->card : cinfo->name;
635                 dai_link->name          = cinfo->name;
636                 dai_link->stream_name   = cinfo->name;
637                 dai_link->platforms->name = cinfo->platform;
638                 dai_link->codecs->dai_name = cinfo->codec;
639                 dai_link->cpus->dai_name = cinfo->cpu_dai.name;
640                 dai_link->codecs->dai_name = cinfo->codec_dai.name;
641                 dai_link->dai_fmt       = cinfo->daifmt;
642                 dai_link->init          = seeed_voice_card_dai_init;
643                 memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai,
644                                         sizeof(priv->dai_props->cpu_dai));
645                 memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai,
646                                         sizeof(priv->dai_props->codec_dai));
647         }
648
649         snd_soc_card_set_drvdata(&priv->snd_card, priv);
650
651         #if CONFIG_AC10X_TRIG_LOCK
652         spin_lock_init(&priv->lock);
653         #endif
654
655         INIT_WORK(&priv->work_codec_clk, work_cb_codec_clk);
656
657         ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card);
658         if (ret >= 0)
659                 return ret;
660
661 err:
662         asoc_simple_clean_reference(&priv->snd_card);
663
664         return ret;
665 }
666
667 static int seeed_voice_card_remove(struct platform_device *pdev)
668 {
669         struct snd_soc_card *card = platform_get_drvdata(pdev);
670         struct seeed_card_data *priv = snd_soc_card_get_drvdata(card);
671
672         if (cancel_work_sync(&priv->work_codec_clk) != 0) {
673         }
674         return asoc_simple_clean_reference(card);
675 }
676
677 static const struct of_device_id seeed_voice_of_match[] = {
678         { .compatible = "seeed-voicecard", },
679         {},
680 };
681 MODULE_DEVICE_TABLE(of, seeed_voice_of_match);
682
683 static struct platform_driver seeed_voice_card = {
684         .driver = {
685                 .name = "seeed-voicecard",
686                 .pm = &snd_soc_pm_ops,
687                 .of_match_table = seeed_voice_of_match,
688         },
689         .probe = seeed_voice_card_probe,
690         .remove = seeed_voice_card_remove,
691 };
692
693 module_platform_driver(seeed_voice_card);
694
695 MODULE_ALIAS("platform:seeed-voice-card");
696 MODULE_LICENSE("GPL v2");
697 MODULE_DESCRIPTION("ASoC SEEED Voice Card");
698 MODULE_AUTHOR("PeterYang<linsheng.yang@seeed.cc>");