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 static int kirkwood_i2s_set_fmt(struct snd_soc_dai
*cpu_dai
,
39 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(cpu_dai
);
43 switch (fmt
& SND_SOC_DAIFMT_FORMAT_MASK
) {
44 case SND_SOC_DAIFMT_RIGHT_J
:
45 mask
= KIRKWOOD_I2S_CTL_RJ
;
47 case SND_SOC_DAIFMT_LEFT_J
:
48 mask
= KIRKWOOD_I2S_CTL_LJ
;
50 case SND_SOC_DAIFMT_I2S
:
51 mask
= KIRKWOOD_I2S_CTL_I2S
;
58 * Set same format for playback and record
59 * This avoids some troubles.
61 value
= readl(priv
->io
+KIRKWOOD_I2S_PLAYCTL
);
62 value
&= ~KIRKWOOD_I2S_CTL_JUST_MASK
;
64 writel(value
, priv
->io
+KIRKWOOD_I2S_PLAYCTL
);
66 value
= readl(priv
->io
+KIRKWOOD_I2S_RECCTL
);
67 value
&= ~KIRKWOOD_I2S_CTL_JUST_MASK
;
69 writel(value
, priv
->io
+KIRKWOOD_I2S_RECCTL
);
74 static inline void kirkwood_set_dco(void __iomem
*io
, unsigned long rate
)
78 value
= KIRKWOOD_DCO_CTL_OFFSET_0
;
82 value
|= KIRKWOOD_DCO_CTL_FREQ_11
;
85 value
|= KIRKWOOD_DCO_CTL_FREQ_12
;
88 value
|= KIRKWOOD_DCO_CTL_FREQ_24
;
91 writel(value
, io
+ KIRKWOOD_DCO_CTL
);
93 /* wait for dco locked */
96 value
= readl(io
+ KIRKWOOD_DCO_SPCR_STATUS
);
97 value
&= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK
;
101 static void kirkwood_set_rate(struct snd_soc_dai
*dai
,
102 struct kirkwood_dma_data
*priv
, unsigned long rate
)
106 if (rate
== 44100 || rate
== 48000 || rate
== 96000) {
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",
111 kirkwood_set_dco(priv
->io
, rate
);
113 clks_ctrl
= KIRKWOOD_MCLK_SOURCE_DCO
;
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
);
121 clks_ctrl
= KIRKWOOD_MCLK_SOURCE_EXTCLK
;
123 writel(clks_ctrl
, priv
->io
+ KIRKWOOD_CLOCKS_CTRL
);
126 static int kirkwood_i2s_startup(struct snd_pcm_substream
*substream
,
127 struct snd_soc_dai
*dai
)
129 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
131 snd_soc_dai_set_dma_data(dai
, substream
, priv
);
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
)
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
;
144 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
145 i2s_reg
= KIRKWOOD_I2S_PLAYCTL
;
147 i2s_reg
= KIRKWOOD_I2S_RECCTL
;
150 kirkwood_set_rate(dai
, priv
, params_rate(params
));
152 i2s_value
= readl(priv
->io
+i2s_reg
);
153 i2s_value
&= ~KIRKWOOD_I2S_CTL_SIZE_MASK
;
156 * Size settings in play/rec i2s control regs and play/rec control
157 * regs must be the same.
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
;
168 * doesn't work... S20_3LE != kirkwood 20bit format ?
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;
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
;
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
;
196 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
) {
197 if (params_channels(params
) == 1)
198 ctl_play
|= KIRKWOOD_PLAYCTL_MONO_BOTH
;
200 ctl_play
|= KIRKWOOD_PLAYCTL_MONO_OFF
;
202 priv
->ctl_play
&= ~(KIRKWOOD_PLAYCTL_MONO_MASK
|
203 KIRKWOOD_PLAYCTL_ENABLE_MASK
|
204 KIRKWOOD_PLAYCTL_SIZE_MASK
);
205 priv
->ctl_play
|= ctl_play
;
207 priv
->ctl_rec
&= ~KIRKWOOD_RECCTL_SIZE_MASK
;
208 priv
->ctl_rec
|= ctl_rec
;
211 writel(i2s_value
, priv
->io
+i2s_reg
);
216 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream
*substream
,
217 int cmd
, struct snd_soc_dai
*dai
)
219 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
222 ctl
= readl(priv
->io
+ KIRKWOOD_PLAYCTL
);
223 if (ctl
& KIRKWOOD_PLAYCTL_PAUSE
) {
224 unsigned timeout
= 5000;
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.
232 ctl
= readl(priv
->io
+ KIRKWOOD_PLAYCTL
);
233 if (!((ctl
| value
) & KIRKWOOD_PLAYCTL_PLAY_BUSY
))
238 if ((ctl
| value
) & KIRKWOOD_PLAYCTL_PLAY_BUSY
)
239 dev_notice(dai
->dev
, "timed out waiting for busy to deassert: %08x\n",
244 case SNDRV_PCM_TRIGGER_START
:
246 ctl
= priv
->ctl_play
;
247 value
= ctl
& ~KIRKWOOD_PLAYCTL_ENABLE_MASK
;
248 writel(value
, priv
->io
+ KIRKWOOD_PLAYCTL
);
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
);
255 /* enable playback */
256 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
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
);
264 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
265 value
&= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES
;
266 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
268 /* disable all playbacks */
269 ctl
&= ~KIRKWOOD_PLAYCTL_ENABLE_MASK
;
270 writel(ctl
, priv
->io
+ KIRKWOOD_PLAYCTL
);
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
);
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
);
292 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream
*substream
,
293 int cmd
, struct snd_soc_dai
*dai
)
295 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
298 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
301 case SNDRV_PCM_TRIGGER_START
:
304 value
= ctl
& ~KIRKWOOD_RECCTL_I2S_EN
;
305 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
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
);
313 writel(ctl
, priv
->io
+ KIRKWOOD_RECCTL
);
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
);
322 value
= readl(priv
->io
+ KIRKWOOD_INT_MASK
);
323 value
&= ~KIRKWOOD_INT_CAUSE_REC_BYTES
;
324 writel(value
, priv
->io
+ KIRKWOOD_INT_MASK
);
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
);
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
);
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
);
353 static int kirkwood_i2s_trigger(struct snd_pcm_substream
*substream
, int cmd
,
354 struct snd_soc_dai
*dai
)
356 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
357 return kirkwood_i2s_play_trigger(substream
, cmd
, dai
);
359 return kirkwood_i2s_rec_trigger(substream
, cmd
, dai
);
364 static int kirkwood_i2s_probe(struct snd_soc_dai
*dai
)
366 struct kirkwood_dma_data
*priv
= snd_soc_dai_get_drvdata(dai
);
368 unsigned int reg_data
;
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
);
375 reg_data
= readl(priv
->io
+ 0x1200);
376 reg_data
&= (~(0x333FF8));
377 reg_data
|= 0x111D18;
378 writel(reg_data
, priv
->io
+ 0x1200);
382 reg_data
= readl(priv
->io
+ 0x1200);
383 reg_data
&= (~(0x333FF8));
384 reg_data
|= 0x111D18;
385 writel(reg_data
, priv
->io
+ 0x1200);
387 /* disable playback/record */
388 value
= readl(priv
->io
+ KIRKWOOD_PLAYCTL
);
389 value
&= ~KIRKWOOD_PLAYCTL_ENABLE_MASK
;
390 writel(value
, priv
->io
+ KIRKWOOD_PLAYCTL
);
392 value
= readl(priv
->io
+ KIRKWOOD_RECCTL
);
393 value
&= ~(KIRKWOOD_RECCTL_I2S_EN
| KIRKWOOD_RECCTL_SPDIF_EN
);
394 writel(value
, priv
->io
+ KIRKWOOD_RECCTL
);
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
,
408 static struct snd_soc_dai_driver kirkwood_i2s_dai
= {
409 .probe
= kirkwood_i2s_probe
,
413 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
414 SNDRV_PCM_RATE_96000
,
415 .formats
= KIRKWOOD_I2S_FORMATS
,
420 .rates
= SNDRV_PCM_RATE_44100
| SNDRV_PCM_RATE_48000
|
421 SNDRV_PCM_RATE_96000
,
422 .formats
= KIRKWOOD_I2S_FORMATS
,
424 .ops
= &kirkwood_i2s_dai_ops
,
427 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk
= {
428 .probe
= kirkwood_i2s_probe
,
432 .rates
= SNDRV_PCM_RATE_8000_192000
|
433 SNDRV_PCM_RATE_CONTINUOUS
|
435 .formats
= KIRKWOOD_I2S_FORMATS
,
440 .rates
= SNDRV_PCM_RATE_8000_192000
|
441 SNDRV_PCM_RATE_CONTINUOUS
|
443 .formats
= KIRKWOOD_I2S_FORMATS
,
445 .ops
= &kirkwood_i2s_dai_ops
,
448 static const struct snd_soc_component_driver kirkwood_i2s_component
= {
452 static int kirkwood_i2s_dev_probe(struct platform_device
*pdev
)
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
;
461 priv
= devm_kzalloc(&pdev
->dev
, sizeof(*priv
), GFP_KERNEL
);
463 dev_err(&pdev
->dev
, "allocation failed\n");
466 dev_set_drvdata(&pdev
->dev
, priv
);
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
);
473 priv
->irq
= platform_get_irq(pdev
, 0);
474 if (priv
->irq
<= 0) {
475 dev_err(&pdev
->dev
, "platform_get_irq failed\n");
480 priv
->burst
= 128; /* might be 32 or 128 */
482 priv
->burst
= data
->burst
;
484 dev_err(&pdev
->dev
, "no DT nor platform data ?!\n");
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
);
494 err
= clk_prepare_enable(priv
->clk
);
498 priv
->extclk
= devm_clk_get(&pdev
->dev
, "extclk");
499 if (!IS_ERR(priv
->extclk
)) {
500 if (priv
->extclk
== priv
->clk
) {
501 devm_clk_put(&pdev
->dev
, priv
->extclk
);
502 priv
->extclk
= ERR_PTR(-EINVAL
);
504 dev_info(&pdev
->dev
, "found external clock\n");
505 clk_prepare_enable(priv
->extclk
);
506 soc_dai
= &kirkwood_i2s_dai_extclk
;
510 /* Some sensible defaults - this reflects the powerup values */
511 priv
->ctl_play
= KIRKWOOD_PLAYCTL_SIZE_24
;
512 priv
->ctl_rec
= KIRKWOOD_RECCTL_SIZE_24
;
514 /* Select the burst size */
515 if (priv
->burst
== 32) {
516 priv
->ctl_play
|= KIRKWOOD_PLAYCTL_BURST_32
;
517 priv
->ctl_rec
|= KIRKWOOD_RECCTL_BURST_32
;
519 priv
->ctl_play
|= KIRKWOOD_PLAYCTL_BURST_128
;
520 priv
->ctl_rec
|= KIRKWOOD_RECCTL_BURST_128
;
523 err
= snd_soc_register_component(&pdev
->dev
, &kirkwood_i2s_component
,
526 dev_err(&pdev
->dev
, "snd_soc_register_component failed\n");
530 err
= snd_soc_register_platform(&pdev
->dev
, &kirkwood_soc_platform
);
532 dev_err(&pdev
->dev
, "snd_soc_register_platform failed\n");
537 snd_soc_unregister_component(&pdev
->dev
);
539 if (!IS_ERR(priv
->extclk
))
540 clk_disable_unprepare(priv
->extclk
);
541 clk_disable_unprepare(priv
->clk
);
546 static int kirkwood_i2s_dev_remove(struct platform_device
*pdev
)
548 struct kirkwood_dma_data
*priv
= dev_get_drvdata(&pdev
->dev
);
550 snd_soc_unregister_platform(&pdev
->dev
);
551 snd_soc_unregister_component(&pdev
->dev
);
553 if (!IS_ERR(priv
->extclk
))
554 clk_disable_unprepare(priv
->extclk
);
555 clk_disable_unprepare(priv
->clk
);
561 static struct of_device_id mvebu_audio_of_match
[] = {
562 { .compatible
= "marvell,kirkwood-audio" },
563 { .compatible
= "marvell,dove-audio" },
566 MODULE_DEVICE_TABLE(of
, mvebu_audio_of_match
);
569 static struct platform_driver kirkwood_i2s_driver
= {
570 .probe
= kirkwood_i2s_dev_probe
,
571 .remove
= kirkwood_i2s_dev_remove
,
574 .owner
= THIS_MODULE
,
575 .of_match_table
= of_match_ptr(mvebu_audio_of_match
),
579 module_platform_driver(kirkwood_i2s_driver
);
581 /* Module information */
582 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
583 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
584 MODULE_LICENSE("GPL");
585 MODULE_ALIAS("platform:mvebu-audio");