4 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
5 * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
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.
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/platform_device.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>
29 #define DRV_NAME "mvebu-audio"
31 #define KIRKWOOD_I2S_FORMATS \
32 (SNDRV_PCM_FMTBIT_S16_LE | \
33 SNDRV_PCM_FMTBIT_S24_LE | \
34 SNDRV_PCM_FMTBIT_S32_LE)
36 #define KIRKWOOD_SPDIF_FORMATS \
37 (SNDRV_PCM_FMTBIT_S16_LE | \
38 SNDRV_PCM_FMTBIT_S24_LE)
40 static int kirkwood_i2s_set_fmt(struct snd_soc_dai
*cpu_dai
,
43 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
47 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
48 case SND_SOC_DAIFMT_RIGHT_J
:
49 mask
= KIRKWOOD_I2S_CTL_RJ
;
51 case SND_SOC_DAIFMT_LEFT_J
:
52 mask
= KIRKWOOD_I2S_CTL_LJ
;
54 case SND_SOC_DAIFMT_I2S
:
55 mask
= KIRKWOOD_I2S_CTL_I2S
;
62 * Set same format for playback and record
63 * This avoids some troubles.
65 value
= readl(priv
->io
+KIRKWOOD_I2S_PLAYCTL
);
66 value
&= ~KIRKWOOD_I2S_CTL_JUST_MASK
;
68 writel(value
, priv
->io
+KIRKWOOD_I2S_PLAYCTL
);
70 value
= readl(priv
->io
+KIRKWOOD_I2S_RECCTL
);
71 value
&= ~KIRKWOOD_I2S_CTL_JUST_MASK
;
73 writel(value
, priv
->io
+KIRKWOOD_I2S_RECCTL
);
78 static inline void kirkwood_set_dco(void __iomem
*io
, unsigned long rate
)
82 value
= KIRKWOOD_DCO_CTL_OFFSET_0
;
86 value
|= KIRKWOOD_DCO_CTL_FREQ_11
;
89 value
|= KIRKWOOD_DCO_CTL_FREQ_12
;
92 value
|= KIRKWOOD_DCO_CTL_FREQ_24
;
95 writel(value
, io
+ KIRKWOOD_DCO_CTL
);
97 /* wait for dco locked */
100 value
= readl(io
+ KIRKWOOD_DCO_SPCR_STATUS
);
101 value
&= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK
;
102 } while (value
== 0);
105 static void kirkwood_set_rate(struct snd_soc_dai
*dai
,
106 struct kirkwood_dma_data
*priv
, unsigned long rate
)
110 if (IS_ERR(priv
->extclk
)) {
111 /* use internal dco for the supported rates
112 * defined in kirkwood_i2s_dai */
113 dev_dbg(dai
->dev
, "%s: dco set rate = %lu\n",
115 kirkwood_set_dco(priv
->io
, rate
);
117 clks_ctrl
= KIRKWOOD_MCLK_SOURCE_DCO
;
119 /* use the external clock for the other rates
120 * defined in kirkwood_i2s_dai_extclk */
121 dev_dbg(dai
->dev
, "%s: extclk set rate = %lu -> %lu\n",
122 __func__
, rate
, 256 * rate
);
123 clk_set_rate(priv
->extclk
, 256 * rate
);
125 clks_ctrl
= KIRKWOOD_MCLK_SOURCE_EXTCLK
;
127 writel(clks_ctrl
, priv
->io
+ KIRKWOOD_CLOCKS_CTRL
);
130 static int kirkwood_i2s_startup(struct snd_pcm_substream
*substream
,
131 struct snd_soc_dai
*dai
)
133 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
135 snd_soc_dai_set_dma_data(dai
, substream
, priv
);
139 static int kirkwood_i2s_hw_params(struct snd_pcm_substream
*substream
,
140 struct snd_pcm_hw_params
*params
,
141 struct snd_soc_dai
*dai
)
143 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
144 uint32_t ctl_play
, ctl_rec
;
145 unsigned int i2s_reg
;
146 unsigned long i2s_value
;
148 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
149 i2s_reg
= KIRKWOOD_I2S_PLAYCTL
;
151 i2s_reg
= KIRKWOOD_I2S_RECCTL
;
154 kirkwood_set_rate(dai
, priv
, params_rate(params
));
156 i2s_value
= readl(priv
->io
+i2s_reg
);
157 i2s_value
&= ~KIRKWOOD_I2S_CTL_SIZE_MASK
;
160 * Size settings in play/rec i2s control regs and play/rec control
161 * regs must be the same.
163 switch (params_format(params
)) {
164 case SNDRV_PCM_FORMAT_S16_LE
:
165 i2s_value
|= KIRKWOOD_I2S_CTL_SIZE_16
;
166 ctl_play
= KIRKWOOD_PLAYCTL_SIZE_16_C
|
167 KIRKWOOD_PLAYCTL_I2S_EN
|
168 KIRKWOOD_PLAYCTL_SPDIF_EN
;
169 ctl_rec
= KIRKWOOD_RECCTL_SIZE_16_C
|
170 KIRKWOOD_RECCTL_I2S_EN
|
171 KIRKWOOD_RECCTL_SPDIF_EN
;
174 * doesn't work... S20_3LE != kirkwood 20bit format ?
176 case SNDRV_PCM_FORMAT_S20_3LE:
177 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
178 ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
179 KIRKWOOD_PLAYCTL_I2S_EN;
180 ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
181 KIRKWOOD_RECCTL_I2S_EN;
184 case SNDRV_PCM_FORMAT_S24_LE
:
185 i2s_value
|= KIRKWOOD_I2S_CTL_SIZE_24
;
186 ctl_play
= KIRKWOOD_PLAYCTL_SIZE_24
|
187 KIRKWOOD_PLAYCTL_I2S_EN
|
188 KIRKWOOD_PLAYCTL_SPDIF_EN
;
189 ctl_rec
= KIRKWOOD_RECCTL_SIZE_24
|
190 KIRKWOOD_RECCTL_I2S_EN
|
191 KIRKWOOD_RECCTL_SPDIF_EN
;
193 case SNDRV_PCM_FORMAT_S32_LE
:
194 i2s_value
|= KIRKWOOD_I2S_CTL_SIZE_32
;
195 ctl_play
= KIRKWOOD_PLAYCTL_SIZE_32
|
196 KIRKWOOD_PLAYCTL_I2S_EN
;
197 ctl_rec
= KIRKWOOD_RECCTL_SIZE_32
|
198 KIRKWOOD_RECCTL_I2S_EN
;
204 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
205 if (params_channels(params
) == 1)
206 ctl_play
|= KIRKWOOD_PLAYCTL_MONO_BOTH
;
208 ctl_play
|= KIRKWOOD_PLAYCTL_MONO_OFF
;
210 priv
->ctl_play
&= ~(KIRKWOOD_PLAYCTL_MONO_MASK
|
211 KIRKWOOD_PLAYCTL_ENABLE_MASK
|
212 KIRKWOOD_PLAYCTL_SIZE_MASK
);
213 priv
->ctl_play
|= ctl_play
;
215 priv
->ctl_rec
&= ~(KIRKWOOD_RECCTL_ENABLE_MASK
|
216 KIRKWOOD_RECCTL_SIZE_MASK
);
217 priv
->ctl_rec
|= ctl_rec
;
220 writel(i2s_value
, priv
->io
+i2s_reg
);
225 static unsigned kirkwood_i2s_play_mute(unsigned ctl
)
227 if (!(ctl
& KIRKWOOD_PLAYCTL_I2S_EN
))
228 ctl
|= KIRKWOOD_PLAYCTL_I2S_MUTE
;
229 if (!(ctl
& KIRKWOOD_PLAYCTL_SPDIF_EN
))
230 ctl
|= KIRKWOOD_PLAYCTL_SPDIF_MUTE
;
234 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream
*substream
,
235 int cmd
, struct snd_soc_dai
*dai
)
237 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
238 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
241 ctl
= readl(priv
->io
+ KIRKWOOD_PLAYCTL
);
242 if ((ctl
& KIRKWOOD_PLAYCTL_ENABLE_MASK
) == 0) {
243 unsigned timeout
= 5000;
245 * The Armada510 spec says that if we enter pause mode, the
246 * busy bit must be read back as clear _twice_. Make sure
247 * we respect that otherwise we get DMA underruns.
251 ctl
= readl(priv
->io
+ KIRKWOOD_PLAYCTL
);
252 if (!((ctl
| value
) & KIRKWOOD_PLAYCTL_PLAY_BUSY
))
257 if ((ctl
| value
) & KIRKWOOD_PLAYCTL_PLAY_BUSY
)
258 dev_notice(dai
->dev
, "timed out waiting for busy to deassert: %08x\n",
263 case SNDRV_PCM_TRIGGER_START
:
265 ctl
= priv
->ctl_play
;
267 ctl
&= ~KIRKWOOD_PLAYCTL_SPDIF_EN
; /* i2s */
269 ctl
&= ~KIRKWOOD_PLAYCTL_I2S_EN
; /* spdif */
270 ctl
= kirkwood_i2s_play_mute(ctl
);
271 value
= ctl
& ~KIRKWOOD_PLAYCTL_ENABLE_MASK
;
272 writel(value
, priv
->io
+ KIRKWOOD_PLAYCTL
);
274 /* enable interrupts */
275 if (!runtime
->no_period_wakeup
) {
276 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
277 value
|= KIRKWOOD_INT_CAUSE_PLAY_BYTES
;
278 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
281 /* enable playback */
282 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
285 case SNDRV_PCM_TRIGGER_STOP
:
286 /* stop audio, disable interrupts */
287 ctl
|= KIRKWOOD_PLAYCTL_PAUSE
| KIRKWOOD_PLAYCTL_I2S_MUTE
|
288 KIRKWOOD_PLAYCTL_SPDIF_MUTE
;
289 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
291 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
292 value
&= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES
;
293 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
295 /* disable all playbacks */
296 ctl
&= ~KIRKWOOD_PLAYCTL_ENABLE_MASK
;
297 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
300 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
301 case SNDRV_PCM_TRIGGER_SUSPEND
:
302 ctl
|= KIRKWOOD_PLAYCTL_PAUSE
| KIRKWOOD_PLAYCTL_I2S_MUTE
|
303 KIRKWOOD_PLAYCTL_SPDIF_MUTE
;
304 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
307 case SNDRV_PCM_TRIGGER_RESUME
:
308 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
309 ctl
&= ~(KIRKWOOD_PLAYCTL_PAUSE
| KIRKWOOD_PLAYCTL_I2S_MUTE
|
310 KIRKWOOD_PLAYCTL_SPDIF_MUTE
);
311 ctl
= kirkwood_i2s_play_mute(ctl
);
312 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
322 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream
*substream
,
323 int cmd
, struct snd_soc_dai
*dai
)
325 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
328 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
331 case SNDRV_PCM_TRIGGER_START
:
335 ctl
&= ~KIRKWOOD_RECCTL_SPDIF_EN
; /* i2s */
337 ctl
&= ~KIRKWOOD_RECCTL_I2S_EN
; /* spdif */
339 value
= ctl
& ~KIRKWOOD_RECCTL_ENABLE_MASK
;
340 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
342 /* enable interrupts */
343 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
344 value
|= KIRKWOOD_INT_CAUSE_REC_BYTES
;
345 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
348 writel(ctl
, priv
->io
+ KIRKWOOD_RECCTL
);
351 case SNDRV_PCM_TRIGGER_STOP
:
352 /* stop audio, disable interrupts */
353 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
354 value
|= KIRKWOOD_RECCTL_PAUSE
| KIRKWOOD_RECCTL_MUTE
;
355 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
357 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
358 value
&= ~KIRKWOOD_INT_CAUSE_REC_BYTES
;
359 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
361 /* disable all records */
362 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
363 value
&= ~KIRKWOOD_RECCTL_ENABLE_MASK
;
364 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
367 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
368 case SNDRV_PCM_TRIGGER_SUSPEND
:
369 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
370 value
|= KIRKWOOD_RECCTL_PAUSE
| KIRKWOOD_RECCTL_MUTE
;
371 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
374 case SNDRV_PCM_TRIGGER_RESUME
:
375 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
376 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
377 value
&= ~(KIRKWOOD_RECCTL_PAUSE
| KIRKWOOD_RECCTL_MUTE
);
378 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
388 static int kirkwood_i2s_trigger(struct snd_pcm_substream
*substream
, int cmd
,
389 struct snd_soc_dai
*dai
)
391 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
392 return kirkwood_i2s_play_trigger(substream
, cmd
, dai
);
394 return kirkwood_i2s_rec_trigger(substream
, cmd
, dai
);
399 static int kirkwood_i2s_init(struct kirkwood_dma_data
*priv
)
402 unsigned int reg_data
;
404 /* put system in a "safe" state : */
405 /* disable audio interrupts */
406 writel(0xffffffff, priv
->io
+ KIRKWOOD_INT_CAUSE
);
407 writel(0, priv
->io
+ KIRKWOOD_INT_MASK
);
409 reg_data
= readl(priv
->io
+ 0x1200);
410 reg_data
&= (~(0x333FF8));
411 reg_data
|= 0x111D18;
412 writel(reg_data
, priv
->io
+ 0x1200);
416 reg_data
= readl(priv
->io
+ 0x1200);
417 reg_data
&= (~(0x333FF8));
418 reg_data
|= 0x111D18;
419 writel(reg_data
, priv
->io
+ 0x1200);
421 /* disable playback/record */
422 value
= readl(priv
->io
+ KIRKWOOD_PLAYCTL
);
423 value
&= ~KIRKWOOD_PLAYCTL_ENABLE_MASK
;
424 writel(value
, priv
->io
+ KIRKWOOD_PLAYCTL
);
426 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
427 value
&= ~KIRKWOOD_RECCTL_ENABLE_MASK
;
428 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
434 static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops
= {
435 .startup
= kirkwood_i2s_startup
,
436 .trigger
= kirkwood_i2s_trigger
,
437 .hw_params
= kirkwood_i2s_hw_params
,
438 .set_fmt
= kirkwood_i2s_set_fmt
,
441 static struct snd_soc_dai_driver kirkwood_i2s_dai
[2] = {
448 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
449 SNDRV_PCM_RATE_96000
,
450 .formats
= KIRKWOOD_I2S_FORMATS
,
455 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
456 SNDRV_PCM_RATE_96000
,
457 .formats
= KIRKWOOD_I2S_FORMATS
,
459 .ops
= &kirkwood_i2s_dai_ops
,
467 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
468 SNDRV_PCM_RATE_96000
,
469 .formats
= KIRKWOOD_SPDIF_FORMATS
,
474 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
475 SNDRV_PCM_RATE_96000
,
476 .formats
= KIRKWOOD_SPDIF_FORMATS
,
478 .ops
= &kirkwood_i2s_dai_ops
,
482 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk
[2] = {
489 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
492 .formats
= KIRKWOOD_I2S_FORMATS
,
497 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
500 .formats
= KIRKWOOD_I2S_FORMATS
,
502 .ops
= &kirkwood_i2s_dai_ops
,
510 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
513 .formats
= KIRKWOOD_SPDIF_FORMATS
,
518 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
521 .formats
= KIRKWOOD_SPDIF_FORMATS
,
523 .ops
= &kirkwood_i2s_dai_ops
,
527 static const struct snd_soc_component_driver kirkwood_i2s_component
= {
531 static int kirkwood_i2s_dev_probe(struct platform_device
*pdev
)
533 struct kirkwood_asoc_platform_data
*data
= pdev
->dev
.platform_data
;
534 struct snd_soc_dai_driver
*soc_dai
= kirkwood_i2s_dai
;
535 struct kirkwood_dma_data
*priv
;
536 struct resource
*mem
;
537 struct device_node
*np
= pdev
->dev
.of_node
;
540 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
542 dev_err(&pdev
->dev
, "allocation failed\n");
545 dev_set_drvdata(&pdev
->dev
, priv
);
547 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
548 priv
->io
= devm_ioremap_resource(&pdev
->dev
, mem
);
549 if (IS_ERR(priv
->io
))
550 return PTR_ERR(priv
->io
);
552 priv
->irq
= platform_get_irq(pdev
, 0);
553 if (priv
->irq
<= 0) {
554 dev_err(&pdev
->dev
, "platform_get_irq failed\n");
559 priv
->burst
= 128; /* might be 32 or 128 */
561 priv
->burst
= data
->burst
;
563 dev_err(&pdev
->dev
, "no DT nor platform data ?!\n");
567 priv
->clk
= devm_clk_get(&pdev
->dev
, np
? "internal" : NULL
);
568 if (IS_ERR(priv
->clk
)) {
569 dev_err(&pdev
->dev
, "no clock\n");
570 return PTR_ERR(priv
->clk
);
573 err
= clk_prepare_enable(priv
->clk
);
577 priv
->extclk
= devm_clk_get(&pdev
->dev
, "extclk");
578 if (IS_ERR(priv
->extclk
)) {
579 if (PTR_ERR(priv
->extclk
) == -EPROBE_DEFER
)
580 return -EPROBE_DEFER
;
582 if (clk_is_match(priv
->extclk
, priv
->clk
)) {
583 devm_clk_put(&pdev
->dev
, priv
->extclk
);
584 priv
->extclk
= ERR_PTR(-EINVAL
);
586 dev_info(&pdev
->dev
, "found external clock\n");
587 clk_prepare_enable(priv
->extclk
);
588 soc_dai
= kirkwood_i2s_dai_extclk
;
592 /* Some sensible defaults - this reflects the powerup values */
593 priv
->ctl_play
= KIRKWOOD_PLAYCTL_SIZE_24
;
594 priv
->ctl_rec
= KIRKWOOD_RECCTL_SIZE_24
;
596 /* Select the burst size */
597 if (priv
->burst
== 32) {
598 priv
->ctl_play
|= KIRKWOOD_PLAYCTL_BURST_32
;
599 priv
->ctl_rec
|= KIRKWOOD_RECCTL_BURST_32
;
601 priv
->ctl_play
|= KIRKWOOD_PLAYCTL_BURST_128
;
602 priv
->ctl_rec
|= KIRKWOOD_RECCTL_BURST_128
;
605 err
= snd_soc_register_component(&pdev
->dev
, &kirkwood_i2s_component
,
608 dev_err(&pdev
->dev
, "snd_soc_register_component failed\n");
612 err
= snd_soc_register_platform(&pdev
->dev
, &kirkwood_soc_platform
);
614 dev_err(&pdev
->dev
, "snd_soc_register_platform failed\n");
618 kirkwood_i2s_init(priv
);
622 snd_soc_unregister_component(&pdev
->dev
);
624 if (!IS_ERR(priv
->extclk
))
625 clk_disable_unprepare(priv
->extclk
);
626 clk_disable_unprepare(priv
->clk
);
631 static int kirkwood_i2s_dev_remove(struct platform_device
*pdev
)
633 struct kirkwood_dma_data
*priv
= dev_get_drvdata(&pdev
->dev
);
635 snd_soc_unregister_platform(&pdev
->dev
);
636 snd_soc_unregister_component(&pdev
->dev
);
638 if (!IS_ERR(priv
->extclk
))
639 clk_disable_unprepare(priv
->extclk
);
640 clk_disable_unprepare(priv
->clk
);
646 static const struct of_device_id mvebu_audio_of_match
[] = {
647 { .compatible
= "marvell,kirkwood-audio" },
648 { .compatible
= "marvell,dove-audio" },
649 { .compatible
= "marvell,armada370-audio" },
652 MODULE_DEVICE_TABLE(of
, mvebu_audio_of_match
);
655 static struct platform_driver kirkwood_i2s_driver
= {
656 .probe
= kirkwood_i2s_dev_probe
,
657 .remove
= kirkwood_i2s_dev_remove
,
660 .of_match_table
= of_match_ptr(mvebu_audio_of_match
),
664 module_platform_driver(kirkwood_i2s_driver
);
666 /* Module information */
667 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
668 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
669 MODULE_LICENSE("GPL");
670 MODULE_ALIAS("platform:mvebu-audio");