1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * (c) 2010 Arnaud Patard <apatard@mandriva.com>
6 * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/platform_device.h>
13 #include <linux/slab.h>
14 #include <linux/mbus.h>
15 #include <linux/delay.h>
16 #include <linux/clk.h>
17 #include <sound/pcm.h>
18 #include <sound/pcm_params.h>
19 #include <sound/soc.h>
20 #include <linux/platform_data/asoc-kirkwood.h>
25 #define KIRKWOOD_I2S_FORMATS \
26 (SNDRV_PCM_FMTBIT_S16_LE | \
27 SNDRV_PCM_FMTBIT_S24_LE | \
28 SNDRV_PCM_FMTBIT_S32_LE)
30 #define KIRKWOOD_SPDIF_FORMATS \
31 (SNDRV_PCM_FMTBIT_S16_LE | \
32 SNDRV_PCM_FMTBIT_S24_LE)
34 /* These registers are relative to the second register region -
35 * audio pll configuration.
37 #define A38X_PLL_CONF_REG0 0x0
38 #define A38X_PLL_FB_CLK_DIV_OFFSET 10
39 #define A38X_PLL_FB_CLK_DIV_MASK 0x7fc00
40 #define A38X_PLL_CONF_REG1 0x4
41 #define A38X_PLL_FREQ_OFFSET_MASK 0xffff
42 #define A38X_PLL_FREQ_OFFSET_VALID BIT(16)
43 #define A38X_PLL_SW_RESET BIT(31)
44 #define A38X_PLL_CONF_REG2 0x8
45 #define A38X_PLL_AUDIO_POSTDIV_MASK 0x7f
47 /* Bit below belongs to SoC control register corresponding to the third
50 #define A38X_SPDIF_MODE_ENABLE BIT(27)
52 static int armada_38x_i2s_init_quirk(struct platform_device *pdev,
53 struct kirkwood_dma_data *priv,
54 struct snd_soc_dai_driver *dai_drv)
56 struct device_node *np = pdev->dev.of_node;
60 priv->pll_config = devm_platform_ioremap_resource_byname(pdev, "pll_regs");
61 if (IS_ERR(priv->pll_config))
64 priv->soc_control = devm_platform_ioremap_resource_byname(pdev, "soc_ctrl");
65 if (IS_ERR(priv->soc_control))
68 /* Select one of exceptive modes: I2S or S/PDIF */
69 reg_val = readl(priv->soc_control);
70 if (of_property_read_bool(np, "spdif-mode")) {
71 reg_val |= A38X_SPDIF_MODE_ENABLE;
72 dev_info(&pdev->dev, "using S/PDIF mode\n");
74 reg_val &= ~A38X_SPDIF_MODE_ENABLE;
75 dev_info(&pdev->dev, "using I2S mode\n");
77 writel(reg_val, priv->soc_control);
79 /* Update available rates of mclk's fs */
80 for (i = 0; i < 2; i++) {
81 dai_drv[i].playback.rates |= SNDRV_PCM_RATE_192000;
82 dai_drv[i].capture.rates |= SNDRV_PCM_RATE_192000;
88 static inline void armada_38x_set_pll(void __iomem *base, unsigned long rate)
91 u16 freq_offset = 0x22b0;
92 u8 audio_postdiv, fb_clk_div = 0x1d;
94 /* Set frequency offset value to not valid and enable PLL reset */
95 reg_val = readl(base + A38X_PLL_CONF_REG1);
96 reg_val &= ~A38X_PLL_FREQ_OFFSET_VALID;
97 reg_val &= ~A38X_PLL_SW_RESET;
98 writel(reg_val, base + A38X_PLL_CONF_REG1);
102 /* Update PLL parameters */
121 reg_val = readl(base + A38X_PLL_CONF_REG0);
122 reg_val &= ~A38X_PLL_FB_CLK_DIV_MASK;
123 reg_val |= (fb_clk_div << A38X_PLL_FB_CLK_DIV_OFFSET);
124 writel(reg_val, base + A38X_PLL_CONF_REG0);
126 reg_val = readl(base + A38X_PLL_CONF_REG2);
127 reg_val &= ~A38X_PLL_AUDIO_POSTDIV_MASK;
128 reg_val |= audio_postdiv;
129 writel(reg_val, base + A38X_PLL_CONF_REG2);
131 reg_val = readl(base + A38X_PLL_CONF_REG1);
132 reg_val &= ~A38X_PLL_FREQ_OFFSET_MASK;
133 reg_val |= freq_offset;
134 writel(reg_val, base + A38X_PLL_CONF_REG1);
139 reg_val |= A38X_PLL_SW_RESET;
140 writel(reg_val, base + A38X_PLL_CONF_REG1);
142 /* Wait 50us for PLL to lock */
145 /* Restore frequency offset value validity */
146 reg_val |= A38X_PLL_FREQ_OFFSET_VALID;
147 writel(reg_val, base + A38X_PLL_CONF_REG1);
150 static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
153 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
157 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
158 case SND_SOC_DAIFMT_RIGHT_J:
159 mask = KIRKWOOD_I2S_CTL_RJ;
161 case SND_SOC_DAIFMT_LEFT_J:
162 mask = KIRKWOOD_I2S_CTL_LJ;
164 case SND_SOC_DAIFMT_I2S:
165 mask = KIRKWOOD_I2S_CTL_I2S;
172 * Set same format for playback and record
173 * This avoids some troubles.
175 value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
176 value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
178 writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
180 value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
181 value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
183 writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
188 static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
192 value = KIRKWOOD_DCO_CTL_OFFSET_0;
196 value |= KIRKWOOD_DCO_CTL_FREQ_11;
199 value |= KIRKWOOD_DCO_CTL_FREQ_12;
202 value |= KIRKWOOD_DCO_CTL_FREQ_24;
205 writel(value, io + KIRKWOOD_DCO_CTL);
207 /* wait for dco locked */
210 value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
211 value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
212 } while (value == 0);
215 static void kirkwood_set_rate(struct snd_soc_dai *dai,
216 struct kirkwood_dma_data *priv, unsigned long rate)
220 if (IS_ERR(priv->extclk)) {
221 /* use internal dco for the supported rates
222 * defined in kirkwood_i2s_dai */
223 dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
225 if (priv->pll_config)
226 armada_38x_set_pll(priv->pll_config, rate);
228 kirkwood_set_dco(priv->io, rate);
230 clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
232 /* use the external clock for the other rates
233 * defined in kirkwood_i2s_dai_extclk */
234 dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
235 __func__, rate, 256 * rate);
236 clk_set_rate(priv->extclk, 256 * rate);
238 clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
240 writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
243 static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
244 struct snd_soc_dai *dai)
246 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
248 snd_soc_dai_set_dma_data(dai, substream, priv);
252 static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
253 struct snd_pcm_hw_params *params,
254 struct snd_soc_dai *dai)
256 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
257 uint32_t ctl_play, ctl_rec;
258 unsigned int i2s_reg;
259 unsigned long i2s_value;
261 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
262 i2s_reg = KIRKWOOD_I2S_PLAYCTL;
264 i2s_reg = KIRKWOOD_I2S_RECCTL;
267 kirkwood_set_rate(dai, priv, params_rate(params));
269 i2s_value = readl(priv->io+i2s_reg);
270 i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
273 * Size settings in play/rec i2s control regs and play/rec control
274 * regs must be the same.
276 switch (params_format(params)) {
277 case SNDRV_PCM_FORMAT_S16_LE:
278 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
279 ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
280 KIRKWOOD_PLAYCTL_I2S_EN |
281 KIRKWOOD_PLAYCTL_SPDIF_EN;
282 ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
283 KIRKWOOD_RECCTL_I2S_EN |
284 KIRKWOOD_RECCTL_SPDIF_EN;
287 * doesn't work... S20_3LE != kirkwood 20bit format ?
289 case SNDRV_PCM_FORMAT_S20_3LE:
290 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
291 ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
292 KIRKWOOD_PLAYCTL_I2S_EN;
293 ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
294 KIRKWOOD_RECCTL_I2S_EN;
297 case SNDRV_PCM_FORMAT_S24_LE:
298 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
299 ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
300 KIRKWOOD_PLAYCTL_I2S_EN |
301 KIRKWOOD_PLAYCTL_SPDIF_EN;
302 ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
303 KIRKWOOD_RECCTL_I2S_EN |
304 KIRKWOOD_RECCTL_SPDIF_EN;
306 case SNDRV_PCM_FORMAT_S32_LE:
307 i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
308 ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
309 KIRKWOOD_PLAYCTL_I2S_EN;
310 ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
311 KIRKWOOD_RECCTL_I2S_EN;
317 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
318 if (params_channels(params) == 1)
319 ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
321 ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
323 priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
324 KIRKWOOD_PLAYCTL_ENABLE_MASK |
325 KIRKWOOD_PLAYCTL_SIZE_MASK);
326 priv->ctl_play |= ctl_play;
328 priv->ctl_rec &= ~(KIRKWOOD_RECCTL_ENABLE_MASK |
329 KIRKWOOD_RECCTL_SIZE_MASK);
330 priv->ctl_rec |= ctl_rec;
333 writel(i2s_value, priv->io+i2s_reg);
338 static unsigned kirkwood_i2s_play_mute(unsigned ctl)
340 if (!(ctl & KIRKWOOD_PLAYCTL_I2S_EN))
341 ctl |= KIRKWOOD_PLAYCTL_I2S_MUTE;
342 if (!(ctl & KIRKWOOD_PLAYCTL_SPDIF_EN))
343 ctl |= KIRKWOOD_PLAYCTL_SPDIF_MUTE;
347 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
348 int cmd, struct snd_soc_dai *dai)
350 struct snd_pcm_runtime *runtime = substream->runtime;
351 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
354 ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
355 if ((ctl & KIRKWOOD_PLAYCTL_ENABLE_MASK) == 0) {
356 unsigned timeout = 5000;
358 * The Armada510 spec says that if we enter pause mode, the
359 * busy bit must be read back as clear _twice_. Make sure
360 * we respect that otherwise we get DMA underruns.
364 ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
365 if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY))
370 if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)
371 dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n",
376 case SNDRV_PCM_TRIGGER_START:
378 ctl = priv->ctl_play;
380 ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN; /* i2s */
382 ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN; /* spdif */
383 ctl = kirkwood_i2s_play_mute(ctl);
384 value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
385 writel(value, priv->io + KIRKWOOD_PLAYCTL);
387 /* enable interrupts */
388 if (!runtime->no_period_wakeup) {
389 value = readl(priv->io + KIRKWOOD_INT_MASK);
390 value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
391 writel(value, priv->io + KIRKWOOD_INT_MASK);
394 /* enable playback */
395 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
398 case SNDRV_PCM_TRIGGER_STOP:
399 /* stop audio, disable interrupts */
400 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
401 KIRKWOOD_PLAYCTL_SPDIF_MUTE;
402 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
404 value = readl(priv->io + KIRKWOOD_INT_MASK);
405 value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
406 writel(value, priv->io + KIRKWOOD_INT_MASK);
408 /* disable all playbacks */
409 ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
410 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
413 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
414 case SNDRV_PCM_TRIGGER_SUSPEND:
415 ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
416 KIRKWOOD_PLAYCTL_SPDIF_MUTE;
417 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
420 case SNDRV_PCM_TRIGGER_RESUME:
421 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
422 ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
423 KIRKWOOD_PLAYCTL_SPDIF_MUTE);
424 ctl = kirkwood_i2s_play_mute(ctl);
425 writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
435 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
436 int cmd, struct snd_soc_dai *dai)
438 struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
441 value = readl(priv->io + KIRKWOOD_RECCTL);
444 case SNDRV_PCM_TRIGGER_START:
448 ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN; /* i2s */
450 ctl &= ~KIRKWOOD_RECCTL_I2S_EN; /* spdif */
452 value = ctl & ~KIRKWOOD_RECCTL_ENABLE_MASK;
453 writel(value, priv->io + KIRKWOOD_RECCTL);
455 /* enable interrupts */
456 value = readl(priv->io + KIRKWOOD_INT_MASK);
457 value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
458 writel(value, priv->io + KIRKWOOD_INT_MASK);
461 writel(ctl, priv->io + KIRKWOOD_RECCTL);
464 case SNDRV_PCM_TRIGGER_STOP:
465 /* stop audio, disable interrupts */
466 value = readl(priv->io + KIRKWOOD_RECCTL);
467 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
468 writel(value, priv->io + KIRKWOOD_RECCTL);
470 value = readl(priv->io + KIRKWOOD_INT_MASK);
471 value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
472 writel(value, priv->io + KIRKWOOD_INT_MASK);
474 /* disable all records */
475 value = readl(priv->io + KIRKWOOD_RECCTL);
476 value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
477 writel(value, priv->io + KIRKWOOD_RECCTL);
480 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
481 case SNDRV_PCM_TRIGGER_SUSPEND:
482 value = readl(priv->io + KIRKWOOD_RECCTL);
483 value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
484 writel(value, priv->io + KIRKWOOD_RECCTL);
487 case SNDRV_PCM_TRIGGER_RESUME:
488 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
489 value = readl(priv->io + KIRKWOOD_RECCTL);
490 value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
491 writel(value, priv->io + KIRKWOOD_RECCTL);
501 static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
502 struct snd_soc_dai *dai)
504 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
505 return kirkwood_i2s_play_trigger(substream, cmd, dai);
507 return kirkwood_i2s_rec_trigger(substream, cmd, dai);
512 static int kirkwood_i2s_init(struct kirkwood_dma_data *priv)
515 unsigned int reg_data;
517 /* put system in a "safe" state : */
518 /* disable audio interrupts */
519 writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
520 writel(0, priv->io + KIRKWOOD_INT_MASK);
522 reg_data = readl(priv->io + 0x1200);
523 reg_data &= (~(0x333FF8));
524 reg_data |= 0x111D18;
525 writel(reg_data, priv->io + 0x1200);
529 reg_data = readl(priv->io + 0x1200);
530 reg_data &= (~(0x333FF8));
531 reg_data |= 0x111D18;
532 writel(reg_data, priv->io + 0x1200);
534 /* disable playback/record */
535 value = readl(priv->io + KIRKWOOD_PLAYCTL);
536 value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
537 writel(value, priv->io + KIRKWOOD_PLAYCTL);
539 value = readl(priv->io + KIRKWOOD_RECCTL);
540 value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
541 writel(value, priv->io + KIRKWOOD_RECCTL);
547 static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
548 .startup = kirkwood_i2s_startup,
549 .trigger = kirkwood_i2s_trigger,
550 .hw_params = kirkwood_i2s_hw_params,
551 .set_fmt = kirkwood_i2s_set_fmt,
554 static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = {
561 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
562 SNDRV_PCM_RATE_96000,
563 .formats = KIRKWOOD_I2S_FORMATS,
568 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
569 SNDRV_PCM_RATE_96000,
570 .formats = KIRKWOOD_I2S_FORMATS,
572 .ops = &kirkwood_i2s_dai_ops,
580 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
581 SNDRV_PCM_RATE_96000,
582 .formats = KIRKWOOD_SPDIF_FORMATS,
587 .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
588 SNDRV_PCM_RATE_96000,
589 .formats = KIRKWOOD_SPDIF_FORMATS,
591 .ops = &kirkwood_i2s_dai_ops,
595 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = {
602 .rates = SNDRV_PCM_RATE_CONTINUOUS,
605 .formats = KIRKWOOD_I2S_FORMATS,
610 .rates = SNDRV_PCM_RATE_CONTINUOUS,
613 .formats = KIRKWOOD_I2S_FORMATS,
615 .ops = &kirkwood_i2s_dai_ops,
623 .rates = SNDRV_PCM_RATE_CONTINUOUS,
626 .formats = KIRKWOOD_SPDIF_FORMATS,
631 .rates = SNDRV_PCM_RATE_CONTINUOUS,
634 .formats = KIRKWOOD_SPDIF_FORMATS,
636 .ops = &kirkwood_i2s_dai_ops,
640 static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
642 struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
643 struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai;
644 struct kirkwood_dma_data *priv;
645 struct device_node *np = pdev->dev.of_node;
648 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
652 dev_set_drvdata(&pdev->dev, priv);
654 if (of_device_is_compatible(np, "marvell,armada-380-audio"))
655 priv->io = devm_platform_ioremap_resource_byname(pdev, "i2s_regs");
657 priv->io = devm_platform_ioremap_resource(pdev, 0);
658 if (IS_ERR(priv->io))
659 return PTR_ERR(priv->io);
661 priv->irq = platform_get_irq(pdev, 0);
665 if (of_device_is_compatible(np, "marvell,armada-380-audio")) {
666 err = armada_38x_i2s_init_quirk(pdev, priv, soc_dai);
669 /* Set initial pll frequency */
670 armada_38x_set_pll(priv->pll_config, 44100);
674 priv->burst = 128; /* might be 32 or 128 */
676 priv->burst = data->burst;
678 dev_err(&pdev->dev, "no DT nor platform data ?!\n");
682 priv->clk = devm_clk_get(&pdev->dev, np ? "internal" : NULL);
683 if (IS_ERR(priv->clk)) {
684 dev_err(&pdev->dev, "no clock\n");
685 return PTR_ERR(priv->clk);
688 priv->extclk = devm_clk_get(&pdev->dev, "extclk");
689 if (IS_ERR(priv->extclk)) {
690 if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
691 return -EPROBE_DEFER;
693 if (clk_is_match(priv->extclk, priv->clk)) {
694 devm_clk_put(&pdev->dev, priv->extclk);
695 priv->extclk = ERR_PTR(-EINVAL);
697 dev_info(&pdev->dev, "found external clock\n");
698 clk_prepare_enable(priv->extclk);
699 soc_dai = kirkwood_i2s_dai_extclk;
703 err = clk_prepare_enable(priv->clk);
707 /* Some sensible defaults - this reflects the powerup values */
708 priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24;
709 priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
711 /* Select the burst size */
712 if (priv->burst == 32) {
713 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
714 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
716 priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
717 priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
720 err = snd_soc_register_component(&pdev->dev, &kirkwood_soc_component,
723 dev_err(&pdev->dev, "snd_soc_register_component failed\n");
727 kirkwood_i2s_init(priv);
732 if (!IS_ERR(priv->extclk))
733 clk_disable_unprepare(priv->extclk);
734 clk_disable_unprepare(priv->clk);
739 static void kirkwood_i2s_dev_remove(struct platform_device *pdev)
741 struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
743 snd_soc_unregister_component(&pdev->dev);
744 if (!IS_ERR(priv->extclk))
745 clk_disable_unprepare(priv->extclk);
746 clk_disable_unprepare(priv->clk);
750 static const struct of_device_id mvebu_audio_of_match[] = {
751 { .compatible = "marvell,kirkwood-audio" },
752 { .compatible = "marvell,dove-audio" },
753 { .compatible = "marvell,armada370-audio" },
754 { .compatible = "marvell,armada-380-audio" },
757 MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
760 static struct platform_driver kirkwood_i2s_driver = {
761 .probe = kirkwood_i2s_dev_probe,
762 .remove_new = kirkwood_i2s_dev_remove,
765 .of_match_table = of_match_ptr(mvebu_audio_of_match),
769 module_platform_driver(kirkwood_i2s_driver);
771 /* Module information */
772 MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
773 MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
774 MODULE_LICENSE("GPL");
775 MODULE_ALIAS("platform:mvebu-audio");