]> git.karo-electronics.de Git - karo-tx-linux.git/blob - sound/soc/kirkwood/kirkwood-i2s.c
Merge remote-tracking branch 'md/for-next'
[karo-tx-linux.git] / sound / soc / kirkwood / kirkwood-i2s.c
1 /*
2  * kirkwood-i2s.c
3  *
4  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
5  * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
6  *
7  *  This program is free software; you can redistribute  it and/or modify it
8  *  under  the terms of  the GNU General  Public License as published by the
9  *  Free Software Foundation;  either version 2 of the  License, or (at your
10  *  option) any later version.
11  */
12
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16 #include <linux/io.h>
17 #include <linux/slab.h>
18 #include <linux/mbus.h>
19 #include <linux/delay.h>
20 #include <linux/clk.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/soc.h>
24 #include <linux/platform_data/asoc-kirkwood.h>
25 #include <linux/of.h>
26
27 #include "kirkwood.h"
28
29 #define DRV_NAME        "mvebu-audio"
30
31 #define KIRKWOOD_I2S_FORMATS \
32         (SNDRV_PCM_FMTBIT_S16_LE | \
33          SNDRV_PCM_FMTBIT_S24_LE | \
34          SNDRV_PCM_FMTBIT_S32_LE)
35
36 static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
37                 unsigned int fmt)
38 {
39         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
40         unsigned long mask;
41         unsigned long value;
42
43         switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
44         case SND_SOC_DAIFMT_RIGHT_J:
45                 mask = KIRKWOOD_I2S_CTL_RJ;
46                 break;
47         case SND_SOC_DAIFMT_LEFT_J:
48                 mask = KIRKWOOD_I2S_CTL_LJ;
49                 break;
50         case SND_SOC_DAIFMT_I2S:
51                 mask = KIRKWOOD_I2S_CTL_I2S;
52                 break;
53         default:
54                 return -EINVAL;
55         }
56
57         /*
58          * Set same format for playback and record
59          * This avoids some troubles.
60          */
61         value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
62         value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
63         value |= mask;
64         writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
65
66         value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
67         value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
68         value |= mask;
69         writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
70
71         return 0;
72 }
73
74 static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
75 {
76         unsigned long value;
77
78         value = KIRKWOOD_DCO_CTL_OFFSET_0;
79         switch (rate) {
80         default:
81         case 44100:
82                 value |= KIRKWOOD_DCO_CTL_FREQ_11;
83                 break;
84         case 48000:
85                 value |= KIRKWOOD_DCO_CTL_FREQ_12;
86                 break;
87         case 96000:
88                 value |= KIRKWOOD_DCO_CTL_FREQ_24;
89                 break;
90         }
91         writel(value, io + KIRKWOOD_DCO_CTL);
92
93         /* wait for dco locked */
94         do {
95                 cpu_relax();
96                 value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
97                 value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
98         } while (value == 0);
99 }
100
101 static void kirkwood_set_rate(struct snd_soc_dai *dai,
102         struct kirkwood_dma_data *priv, unsigned long rate)
103 {
104         uint32_t clks_ctrl;
105
106         if (IS_ERR(priv->extclk)) {
107                 /* use internal dco for the supported rates
108                  * defined in kirkwood_i2s_dai */
109                 dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
110                         __func__, rate);
111                 kirkwood_set_dco(priv->io, rate);
112
113                 clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
114         } else {
115                 /* use the external clock for the other rates
116                  * defined in kirkwood_i2s_dai_extclk */
117                 dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
118                         __func__, rate, 256 * rate);
119                 clk_set_rate(priv->extclk, 256 * rate);
120
121                 clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
122         }
123         writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
124 }
125
126 static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
127                 struct snd_soc_dai *dai)
128 {
129         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
130
131         snd_soc_dai_set_dma_data(dai, substream, priv);
132         return 0;
133 }
134
135 static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
136                                  struct snd_pcm_hw_params *params,
137                                  struct snd_soc_dai *dai)
138 {
139         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
140         uint32_t ctl_play, ctl_rec;
141         unsigned int i2s_reg;
142         unsigned long i2s_value;
143
144         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
145                 i2s_reg = KIRKWOOD_I2S_PLAYCTL;
146         } else {
147                 i2s_reg = KIRKWOOD_I2S_RECCTL;
148         }
149
150         kirkwood_set_rate(dai, priv, params_rate(params));
151
152         i2s_value = readl(priv->io+i2s_reg);
153         i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
154
155         /*
156          * Size settings in play/rec i2s control regs and play/rec control
157          * regs must be the same.
158          */
159         switch (params_format(params)) {
160         case SNDRV_PCM_FORMAT_S16_LE:
161                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
162                 ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
163                            KIRKWOOD_PLAYCTL_I2S_EN;
164                 ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
165                           KIRKWOOD_RECCTL_I2S_EN;
166                 break;
167         /*
168          * doesn't work... S20_3LE != kirkwood 20bit format ?
169          *
170         case SNDRV_PCM_FORMAT_S20_3LE:
171                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
172                 ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
173                            KIRKWOOD_PLAYCTL_I2S_EN;
174                 ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
175                           KIRKWOOD_RECCTL_I2S_EN;
176                 break;
177         */
178         case SNDRV_PCM_FORMAT_S24_LE:
179                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
180                 ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
181                            KIRKWOOD_PLAYCTL_I2S_EN;
182                 ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
183                           KIRKWOOD_RECCTL_I2S_EN;
184                 break;
185         case SNDRV_PCM_FORMAT_S32_LE:
186                 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
187                 ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
188                            KIRKWOOD_PLAYCTL_I2S_EN;
189                 ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
190                           KIRKWOOD_RECCTL_I2S_EN;
191                 break;
192         default:
193                 return -EINVAL;
194         }
195
196         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
197                 if (params_channels(params) == 1)
198                         ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
199                 else
200                         ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
201
202                 priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
203                                     KIRKWOOD_PLAYCTL_ENABLE_MASK |
204                                     KIRKWOOD_PLAYCTL_SIZE_MASK);
205                 priv->ctl_play |= ctl_play;
206         } else {
207                 priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK;
208                 priv->ctl_rec |= ctl_rec;
209         }
210
211         writel(i2s_value, priv->io+i2s_reg);
212
213         return 0;
214 }
215
216 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
217                                 int cmd, struct snd_soc_dai *dai)
218 {
219         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
220         uint32_t ctl, value;
221
222         ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
223         if (ctl & KIRKWOOD_PLAYCTL_PAUSE) {
224                 unsigned timeout = 5000;
225                 /*
226                  * The Armada510 spec says that if we enter pause mode, the
227                  * busy bit must be read back as clear _twice_.  Make sure
228                  * we respect that otherwise we get DMA underruns.
229                  */
230                 do {
231                         value = ctl;
232                         ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
233                         if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY))
234                                 break;
235                         udelay(1);
236                 } while (timeout--);
237
238                 if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)
239                         dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n",
240                                    ctl);
241         }
242
243         switch (cmd) {
244         case SNDRV_PCM_TRIGGER_START:
245                 /* configure */
246                 ctl = priv->ctl_play;
247                 value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
248                 writel(value, priv->io + KIRKWOOD_PLAYCTL);
249
250                 /* enable interrupts */
251                 value = readl(priv->io + KIRKWOOD_INT_MASK);
252                 value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
253                 writel(value, priv->io + KIRKWOOD_INT_MASK);
254
255                 /* enable playback */
256                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
257                 break;
258
259         case SNDRV_PCM_TRIGGER_STOP:
260                 /* stop audio, disable interrupts */
261                 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
262                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
263
264                 value = readl(priv->io + KIRKWOOD_INT_MASK);
265                 value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
266                 writel(value, priv->io + KIRKWOOD_INT_MASK);
267
268                 /* disable all playbacks */
269                 ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
270                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
271                 break;
272
273         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
274         case SNDRV_PCM_TRIGGER_SUSPEND:
275                 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
276                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
277                 break;
278
279         case SNDRV_PCM_TRIGGER_RESUME:
280         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
281                 ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
282                 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
283                 break;
284
285         default:
286                 return -EINVAL;
287         }
288
289         return 0;
290 }
291
292 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
293                                 int cmd, struct snd_soc_dai *dai)
294 {
295         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
296         uint32_t ctl, value;
297
298         value = readl(priv->io + KIRKWOOD_RECCTL);
299
300         switch (cmd) {
301         case SNDRV_PCM_TRIGGER_START:
302                 /* configure */
303                 ctl = priv->ctl_rec;
304                 value = ctl & ~KIRKWOOD_RECCTL_I2S_EN;
305                 writel(value, priv->io + KIRKWOOD_RECCTL);
306
307                 /* enable interrupts */
308                 value = readl(priv->io + KIRKWOOD_INT_MASK);
309                 value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
310                 writel(value, priv->io + KIRKWOOD_INT_MASK);
311
312                 /* enable record */
313                 writel(ctl, priv->io + KIRKWOOD_RECCTL);
314                 break;
315
316         case SNDRV_PCM_TRIGGER_STOP:
317                 /* stop audio, disable interrupts */
318                 value = readl(priv->io + KIRKWOOD_RECCTL);
319                 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
320                 writel(value, priv->io + KIRKWOOD_RECCTL);
321
322                 value = readl(priv->io + KIRKWOOD_INT_MASK);
323                 value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
324                 writel(value, priv->io + KIRKWOOD_INT_MASK);
325
326                 /* disable all records */
327                 value = readl(priv->io + KIRKWOOD_RECCTL);
328                 value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
329                 writel(value, priv->io + KIRKWOOD_RECCTL);
330                 break;
331
332         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
333         case SNDRV_PCM_TRIGGER_SUSPEND:
334                 value = readl(priv->io + KIRKWOOD_RECCTL);
335                 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
336                 writel(value, priv->io + KIRKWOOD_RECCTL);
337                 break;
338
339         case SNDRV_PCM_TRIGGER_RESUME:
340         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
341                 value = readl(priv->io + KIRKWOOD_RECCTL);
342                 value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
343                 writel(value, priv->io + KIRKWOOD_RECCTL);
344                 break;
345
346         default:
347                 return -EINVAL;
348         }
349
350         return 0;
351 }
352
353 static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
354                                struct snd_soc_dai *dai)
355 {
356         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
357                 return kirkwood_i2s_play_trigger(substream, cmd, dai);
358         else
359                 return kirkwood_i2s_rec_trigger(substream, cmd, dai);
360
361         return 0;
362 }
363
364 static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
365 {
366         struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
367         unsigned long value;
368         unsigned int reg_data;
369
370         /* put system in a "safe" state : */
371         /* disable audio interrupts */
372         writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
373         writel(0, priv->io + KIRKWOOD_INT_MASK);
374
375         reg_data = readl(priv->io + 0x1200);
376         reg_data &= (~(0x333FF8));
377         reg_data |= 0x111D18;
378         writel(reg_data, priv->io + 0x1200);
379
380         msleep(500);
381
382         reg_data = readl(priv->io + 0x1200);
383         reg_data &= (~(0x333FF8));
384         reg_data |= 0x111D18;
385         writel(reg_data, priv->io + 0x1200);
386
387         /* disable playback/record */
388         value = readl(priv->io + KIRKWOOD_PLAYCTL);
389         value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
390         writel(value, priv->io + KIRKWOOD_PLAYCTL);
391
392         value = readl(priv->io + KIRKWOOD_RECCTL);
393         value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
394         writel(value, priv->io + KIRKWOOD_RECCTL);
395
396         return 0;
397
398 }
399
400 static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
401         .startup        = kirkwood_i2s_startup,
402         .trigger        = kirkwood_i2s_trigger,
403         .hw_params      = kirkwood_i2s_hw_params,
404         .set_fmt        = kirkwood_i2s_set_fmt,
405 };
406
407
408 static struct snd_soc_dai_driver kirkwood_i2s_dai = {
409         .probe = kirkwood_i2s_probe,
410         .playback = {
411                 .channels_min = 1,
412                 .channels_max = 2,
413                 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
414                                 SNDRV_PCM_RATE_96000,
415                 .formats = KIRKWOOD_I2S_FORMATS,
416         },
417         .capture = {
418                 .channels_min = 1,
419                 .channels_max = 2,
420                 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
421                                 SNDRV_PCM_RATE_96000,
422                 .formats = KIRKWOOD_I2S_FORMATS,
423         },
424         .ops = &kirkwood_i2s_dai_ops,
425 };
426
427 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk = {
428         .probe = kirkwood_i2s_probe,
429         .playback = {
430                 .channels_min = 1,
431                 .channels_max = 2,
432                 .rates = SNDRV_PCM_RATE_8000_192000 |
433                          SNDRV_PCM_RATE_CONTINUOUS |
434                          SNDRV_PCM_RATE_KNOT,
435                 .formats = KIRKWOOD_I2S_FORMATS,
436         },
437         .capture = {
438                 .channels_min = 1,
439                 .channels_max = 2,
440                 .rates = SNDRV_PCM_RATE_8000_192000 |
441                          SNDRV_PCM_RATE_CONTINUOUS |
442                          SNDRV_PCM_RATE_KNOT,
443                 .formats = KIRKWOOD_I2S_FORMATS,
444         },
445         .ops = &kirkwood_i2s_dai_ops,
446 };
447
448 static const struct snd_soc_component_driver kirkwood_i2s_component = {
449         .name           = DRV_NAME,
450 };
451
452 static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
453 {
454         struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
455         struct snd_soc_dai_driver *soc_dai = &kirkwood_i2s_dai;
456         struct kirkwood_dma_data *priv;
457         struct resource *mem;
458         struct device_node *np = pdev->dev.of_node;
459         int err;
460
461         priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
462         if (!priv) {
463                 dev_err(&pdev->dev, "allocation failed\n");
464                 return -ENOMEM;
465         }
466         dev_set_drvdata(&pdev->dev, priv);
467
468         mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
469         priv->io = devm_ioremap_resource(&pdev->dev, mem);
470         if (IS_ERR(priv->io))
471                 return PTR_ERR(priv->io);
472
473         priv->irq = platform_get_irq(pdev, 0);
474         if (priv->irq <= 0) {
475                 dev_err(&pdev->dev, "platform_get_irq failed\n");
476                 return -ENXIO;
477         }
478
479         if (np) {
480                 priv->burst = 128;              /* might be 32 or 128 */
481         } else if (data) {
482                 priv->burst = data->burst;
483         } else {
484                 dev_err(&pdev->dev, "no DT nor platform data ?!\n");
485                 return -EINVAL;
486         }
487
488         priv->clk = devm_clk_get(&pdev->dev, np ? "internal" : NULL);
489         if (IS_ERR(priv->clk)) {
490                 dev_err(&pdev->dev, "no clock\n");
491                 return PTR_ERR(priv->clk);
492         }
493
494         err = clk_prepare_enable(priv->clk);
495         if (err < 0)
496                 return err;
497
498         priv->extclk = devm_clk_get(&pdev->dev, "extclk");
499         if (IS_ERR(priv->extclk)) {
500                 if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
501                         return -EPROBE_DEFER;
502         } else {
503                 if (priv->extclk == priv->clk) {
504                         devm_clk_put(&pdev->dev, priv->extclk);
505                         priv->extclk = ERR_PTR(-EINVAL);
506                 } else {
507                         dev_info(&pdev->dev, "found external clock\n");
508                         clk_prepare_enable(priv->extclk);
509                         soc_dai = &kirkwood_i2s_dai_extclk;
510                 }
511         }
512
513         /* Some sensible defaults - this reflects the powerup values */
514         priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24;
515         priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
516
517         /* Select the burst size */
518         if (priv->burst == 32) {
519                 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
520                 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
521         } else {
522                 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
523                 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
524         }
525
526         err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
527                                          soc_dai, 1);
528         if (err) {
529                 dev_err(&pdev->dev, "snd_soc_register_component failed\n");
530                 goto err_component;
531         }
532
533         err = snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
534         if (err) {
535                 dev_err(&pdev->dev, "snd_soc_register_platform failed\n");
536                 goto err_platform;
537         }
538         return 0;
539  err_platform:
540         snd_soc_unregister_component(&pdev->dev);
541  err_component:
542         if (!IS_ERR(priv->extclk))
543                 clk_disable_unprepare(priv->extclk);
544         clk_disable_unprepare(priv->clk);
545
546         return err;
547 }
548
549 static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
550 {
551         struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
552
553         snd_soc_unregister_platform(&pdev->dev);
554         snd_soc_unregister_component(&pdev->dev);
555
556         if (!IS_ERR(priv->extclk))
557                 clk_disable_unprepare(priv->extclk);
558         clk_disable_unprepare(priv->clk);
559
560         return 0;
561 }
562
563 #ifdef CONFIG_OF
564 static struct of_device_id mvebu_audio_of_match[] = {
565         { .compatible = "marvell,kirkwood-audio" },
566         { .compatible = "marvell,dove-audio" },
567         { }
568 };
569 MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
570 #endif
571
572 static struct platform_driver kirkwood_i2s_driver = {
573         .probe  = kirkwood_i2s_dev_probe,
574         .remove = kirkwood_i2s_dev_remove,
575         .driver = {
576                 .name = DRV_NAME,
577                 .owner = THIS_MODULE,
578                 .of_match_table = of_match_ptr(mvebu_audio_of_match),
579         },
580 };
581
582 module_platform_driver(kirkwood_i2s_driver);
583
584 /* Module information */
585 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
586 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
587 MODULE_LICENSE("GPL");
588 MODULE_ALIAS("platform:mvebu-audio");