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