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_SIZE_MASK
;
216 priv
->ctl_rec
|= ctl_rec
;
219 writel(i2s_value
, priv
->io
+i2s_reg
);
224 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream
*substream
,
225 int cmd
, struct snd_soc_dai
*dai
)
227 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
230 ctl
= readl(priv
->io
+ KIRKWOOD_PLAYCTL
);
231 if (ctl
& KIRKWOOD_PLAYCTL_PAUSE
) {
232 unsigned timeout
= 5000;
234 * The Armada510 spec says that if we enter pause mode, the
235 * busy bit must be read back as clear _twice_. Make sure
236 * we respect that otherwise we get DMA underruns.
240 ctl
= readl(priv
->io
+ KIRKWOOD_PLAYCTL
);
241 if (!((ctl
| value
) & KIRKWOOD_PLAYCTL_PLAY_BUSY
))
246 if ((ctl
| value
) & KIRKWOOD_PLAYCTL_PLAY_BUSY
)
247 dev_notice(dai
->dev
, "timed out waiting for busy to deassert: %08x\n",
252 case SNDRV_PCM_TRIGGER_START
:
254 ctl
= priv
->ctl_play
;
256 ctl
&= ~KIRKWOOD_PLAYCTL_SPDIF_EN
; /* i2s */
258 ctl
&= ~KIRKWOOD_PLAYCTL_I2S_EN
; /* spdif */
260 value
= ctl
& ~KIRKWOOD_PLAYCTL_ENABLE_MASK
;
261 writel(value
, priv
->io
+ KIRKWOOD_PLAYCTL
);
263 /* enable interrupts */
264 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
265 value
|= KIRKWOOD_INT_CAUSE_PLAY_BYTES
;
266 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
268 /* enable playback */
269 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
272 case SNDRV_PCM_TRIGGER_STOP
:
273 /* stop audio, disable interrupts */
274 ctl
|= KIRKWOOD_PLAYCTL_PAUSE
| KIRKWOOD_PLAYCTL_I2S_MUTE
|
275 KIRKWOOD_PLAYCTL_SPDIF_MUTE
;
276 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
278 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
279 value
&= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES
;
280 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
282 /* disable all playbacks */
283 ctl
&= ~KIRKWOOD_PLAYCTL_ENABLE_MASK
;
284 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
287 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
288 case SNDRV_PCM_TRIGGER_SUSPEND
:
289 ctl
|= KIRKWOOD_PLAYCTL_PAUSE
| KIRKWOOD_PLAYCTL_I2S_MUTE
|
290 KIRKWOOD_PLAYCTL_SPDIF_MUTE
;
291 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
294 case SNDRV_PCM_TRIGGER_RESUME
:
295 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
296 ctl
&= ~(KIRKWOOD_PLAYCTL_PAUSE
| KIRKWOOD_PLAYCTL_I2S_MUTE
|
297 KIRKWOOD_PLAYCTL_SPDIF_MUTE
);
298 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
308 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream
*substream
,
309 int cmd
, struct snd_soc_dai
*dai
)
311 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
314 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
317 case SNDRV_PCM_TRIGGER_START
:
321 ctl
&= ~KIRKWOOD_RECCTL_SPDIF_EN
; /* i2s */
323 ctl
&= ~KIRKWOOD_RECCTL_I2S_EN
; /* spdif */
325 value
= ctl
& ~(KIRKWOOD_RECCTL_I2S_EN
|
326 KIRKWOOD_RECCTL_SPDIF_EN
);
327 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
329 /* enable interrupts */
330 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
331 value
|= KIRKWOOD_INT_CAUSE_REC_BYTES
;
332 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
335 writel(ctl
, priv
->io
+ KIRKWOOD_RECCTL
);
338 case SNDRV_PCM_TRIGGER_STOP
:
339 /* stop audio, disable interrupts */
340 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
341 value
|= KIRKWOOD_RECCTL_PAUSE
| KIRKWOOD_RECCTL_MUTE
;
342 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
344 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
345 value
&= ~KIRKWOOD_INT_CAUSE_REC_BYTES
;
346 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
348 /* disable all records */
349 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
350 value
&= ~(KIRKWOOD_RECCTL_I2S_EN
| KIRKWOOD_RECCTL_SPDIF_EN
);
351 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
354 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
355 case SNDRV_PCM_TRIGGER_SUSPEND
:
356 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
357 value
|= KIRKWOOD_RECCTL_PAUSE
| KIRKWOOD_RECCTL_MUTE
;
358 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
361 case SNDRV_PCM_TRIGGER_RESUME
:
362 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
363 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
364 value
&= ~(KIRKWOOD_RECCTL_PAUSE
| KIRKWOOD_RECCTL_MUTE
);
365 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
375 static int kirkwood_i2s_trigger(struct snd_pcm_substream
*substream
, int cmd
,
376 struct snd_soc_dai
*dai
)
378 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
379 return kirkwood_i2s_play_trigger(substream
, cmd
, dai
);
381 return kirkwood_i2s_rec_trigger(substream
, cmd
, dai
);
386 static int kirkwood_i2s_init(struct kirkwood_dma_data
*priv
)
389 unsigned int reg_data
;
391 /* put system in a "safe" state : */
392 /* disable audio interrupts */
393 writel(0xffffffff, priv
->io
+ KIRKWOOD_INT_CAUSE
);
394 writel(0, priv
->io
+ KIRKWOOD_INT_MASK
);
396 reg_data
= readl(priv
->io
+ 0x1200);
397 reg_data
&= (~(0x333FF8));
398 reg_data
|= 0x111D18;
399 writel(reg_data
, priv
->io
+ 0x1200);
403 reg_data
= readl(priv
->io
+ 0x1200);
404 reg_data
&= (~(0x333FF8));
405 reg_data
|= 0x111D18;
406 writel(reg_data
, priv
->io
+ 0x1200);
408 /* disable playback/record */
409 value
= readl(priv
->io
+ KIRKWOOD_PLAYCTL
);
410 value
&= ~KIRKWOOD_PLAYCTL_ENABLE_MASK
;
411 writel(value
, priv
->io
+ KIRKWOOD_PLAYCTL
);
413 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
414 value
&= ~(KIRKWOOD_RECCTL_I2S_EN
| KIRKWOOD_RECCTL_SPDIF_EN
);
415 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
421 static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops
= {
422 .startup
= kirkwood_i2s_startup
,
423 .trigger
= kirkwood_i2s_trigger
,
424 .hw_params
= kirkwood_i2s_hw_params
,
425 .set_fmt
= kirkwood_i2s_set_fmt
,
428 static struct snd_soc_dai_driver kirkwood_i2s_dai
[2] = {
435 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
436 SNDRV_PCM_RATE_96000
,
437 .formats
= KIRKWOOD_I2S_FORMATS
,
442 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
443 SNDRV_PCM_RATE_96000
,
444 .formats
= KIRKWOOD_I2S_FORMATS
,
446 .ops
= &kirkwood_i2s_dai_ops
,
454 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
455 SNDRV_PCM_RATE_96000
,
456 .formats
= KIRKWOOD_SPDIF_FORMATS
,
461 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
462 SNDRV_PCM_RATE_96000
,
463 .formats
= KIRKWOOD_SPDIF_FORMATS
,
465 .ops
= &kirkwood_i2s_dai_ops
,
469 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk
[2] = {
476 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
479 .formats
= KIRKWOOD_I2S_FORMATS
,
484 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
487 .formats
= KIRKWOOD_I2S_FORMATS
,
489 .ops
= &kirkwood_i2s_dai_ops
,
497 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
500 .formats
= KIRKWOOD_SPDIF_FORMATS
,
505 .rates
= SNDRV_PCM_RATE_CONTINUOUS
,
508 .formats
= KIRKWOOD_SPDIF_FORMATS
,
510 .ops
= &kirkwood_i2s_dai_ops
,
514 static const struct snd_soc_component_driver kirkwood_i2s_component
= {
518 static int kirkwood_i2s_dev_probe(struct platform_device
*pdev
)
520 struct kirkwood_asoc_platform_data
*data
= pdev
->dev
.platform_data
;
521 struct snd_soc_dai_driver
*soc_dai
= kirkwood_i2s_dai
;
522 struct kirkwood_dma_data
*priv
;
523 struct resource
*mem
;
524 struct device_node
*np
= pdev
->dev
.of_node
;
527 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
529 dev_err(&pdev
->dev
, "allocation failed\n");
532 dev_set_drvdata(&pdev
->dev
, priv
);
534 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
535 priv
->io
= devm_ioremap_resource(&pdev
->dev
, mem
);
536 if (IS_ERR(priv
->io
))
537 return PTR_ERR(priv
->io
);
539 priv
->irq
= platform_get_irq(pdev
, 0);
540 if (priv
->irq
<= 0) {
541 dev_err(&pdev
->dev
, "platform_get_irq failed\n");
546 priv
->burst
= 128; /* might be 32 or 128 */
548 priv
->burst
= data
->burst
;
550 dev_err(&pdev
->dev
, "no DT nor platform data ?!\n");
554 priv
->clk
= devm_clk_get(&pdev
->dev
, np
? "internal" : NULL
);
555 if (IS_ERR(priv
->clk
)) {
556 dev_err(&pdev
->dev
, "no clock\n");
557 return PTR_ERR(priv
->clk
);
560 err
= clk_prepare_enable(priv
->clk
);
564 priv
->extclk
= devm_clk_get(&pdev
->dev
, "extclk");
565 if (IS_ERR(priv
->extclk
)) {
566 if (PTR_ERR(priv
->extclk
) == -EPROBE_DEFER
)
567 return -EPROBE_DEFER
;
569 if (priv
->extclk
== priv
->clk
) {
570 devm_clk_put(&pdev
->dev
, priv
->extclk
);
571 priv
->extclk
= ERR_PTR(-EINVAL
);
573 dev_info(&pdev
->dev
, "found external clock\n");
574 clk_prepare_enable(priv
->extclk
);
575 soc_dai
= kirkwood_i2s_dai_extclk
;
579 /* Some sensible defaults - this reflects the powerup values */
580 priv
->ctl_play
= KIRKWOOD_PLAYCTL_SIZE_24
;
581 priv
->ctl_rec
= KIRKWOOD_RECCTL_SIZE_24
;
583 /* Select the burst size */
584 if (priv
->burst
== 32) {
585 priv
->ctl_play
|= KIRKWOOD_PLAYCTL_BURST_32
;
586 priv
->ctl_rec
|= KIRKWOOD_RECCTL_BURST_32
;
588 priv
->ctl_play
|= KIRKWOOD_PLAYCTL_BURST_128
;
589 priv
->ctl_rec
|= KIRKWOOD_RECCTL_BURST_128
;
592 err
= snd_soc_register_component(&pdev
->dev
, &kirkwood_i2s_component
,
595 dev_err(&pdev
->dev
, "snd_soc_register_component failed\n");
599 err
= snd_soc_register_platform(&pdev
->dev
, &kirkwood_soc_platform
);
601 dev_err(&pdev
->dev
, "snd_soc_register_platform failed\n");
605 kirkwood_i2s_init(priv
);
609 snd_soc_unregister_component(&pdev
->dev
);
611 if (!IS_ERR(priv
->extclk
))
612 clk_disable_unprepare(priv
->extclk
);
613 clk_disable_unprepare(priv
->clk
);
618 static int kirkwood_i2s_dev_remove(struct platform_device
*pdev
)
620 struct kirkwood_dma_data
*priv
= dev_get_drvdata(&pdev
->dev
);
622 snd_soc_unregister_platform(&pdev
->dev
);
623 snd_soc_unregister_component(&pdev
->dev
);
625 if (!IS_ERR(priv
->extclk
))
626 clk_disable_unprepare(priv
->extclk
);
627 clk_disable_unprepare(priv
->clk
);
633 static struct of_device_id mvebu_audio_of_match
[] = {
634 { .compatible
= "marvell,kirkwood-audio" },
635 { .compatible
= "marvell,dove-audio" },
636 { .compatible
= "marvell,armada370-audio" },
639 MODULE_DEVICE_TABLE(of
, mvebu_audio_of_match
);
642 static struct platform_driver kirkwood_i2s_driver
= {
643 .probe
= kirkwood_i2s_dev_probe
,
644 .remove
= kirkwood_i2s_dev_remove
,
647 .owner
= THIS_MODULE
,
648 .of_match_table
= of_match_ptr(mvebu_audio_of_match
),
652 module_platform_driver(kirkwood_i2s_driver
);
654 /* Module information */
655 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
656 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
657 MODULE_LICENSE("GPL");
658 MODULE_ALIAS("platform:mvebu-audio");