xref: /linux/sound/soc/kirkwood/kirkwood-i2s.c (revision c894ec016c9d0418dd832202225a8c64f450d71e)
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 
34 /* These registers are relative to the second register region -
35  * audio pll configuration.
36  */
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
46 
47 /* Bit below belongs to SoC control register corresponding to the third
48  * register region.
49  */
50 #define A38X_SPDIF_MODE_ENABLE			BIT(27)
51 
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)
55 {
56 	struct device_node *np = pdev->dev.of_node;
57 	u32 reg_val;
58 	int i;
59 
60 	priv->pll_config = devm_platform_ioremap_resource_byname(pdev, "pll_regs");
61 	if (IS_ERR(priv->pll_config))
62 		return -ENOMEM;
63 
64 	priv->soc_control = devm_platform_ioremap_resource_byname(pdev, "soc_ctrl");
65 	if (IS_ERR(priv->soc_control))
66 		return -ENOMEM;
67 
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");
73 	} else {
74 		reg_val &= ~A38X_SPDIF_MODE_ENABLE;
75 		dev_info(&pdev->dev, "using I2S mode\n");
76 	}
77 	writel(reg_val, priv->soc_control);
78 
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;
83 	}
84 
85 	return 0;
86 }
87 
88 static inline void armada_38x_set_pll(void __iomem *base, unsigned long rate)
89 {
90 	u32 reg_val;
91 	u16 freq_offset = 0x22b0;
92 	u8 audio_postdiv, fb_clk_div = 0x1d;
93 
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);
99 
100 	udelay(1);
101 
102 	/* Update PLL parameters */
103 	switch (rate) {
104 	default:
105 	case 44100:
106 		freq_offset = 0x735;
107 		fb_clk_div = 0x1b;
108 		audio_postdiv = 0xc;
109 		break;
110 	case 48000:
111 		audio_postdiv = 0xc;
112 		break;
113 	case 96000:
114 		audio_postdiv = 0x6;
115 		break;
116 	case 192000:
117 		audio_postdiv = 0x3;
118 		break;
119 	}
120 
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);
125 
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);
130 
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);
135 
136 	udelay(1);
137 
138 	/* Disable reset */
139 	reg_val |= A38X_PLL_SW_RESET;
140 	writel(reg_val, base + A38X_PLL_CONF_REG1);
141 
142 	/* Wait 50us for PLL to lock */
143 	udelay(50);
144 
145 	/* Restore frequency offset value validity */
146 	reg_val |= A38X_PLL_FREQ_OFFSET_VALID;
147 	writel(reg_val, base + A38X_PLL_CONF_REG1);
148 }
149 
150 static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
151 		unsigned int fmt)
152 {
153 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
154 	unsigned long mask;
155 	unsigned long value;
156 
157 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
158 	case SND_SOC_DAIFMT_RIGHT_J:
159 		mask = KIRKWOOD_I2S_CTL_RJ;
160 		break;
161 	case SND_SOC_DAIFMT_LEFT_J:
162 		mask = KIRKWOOD_I2S_CTL_LJ;
163 		break;
164 	case SND_SOC_DAIFMT_I2S:
165 		mask = KIRKWOOD_I2S_CTL_I2S;
166 		break;
167 	default:
168 		return -EINVAL;
169 	}
170 
171 	/*
172 	 * Set same format for playback and record
173 	 * This avoids some troubles.
174 	 */
175 	value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
176 	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
177 	value |= mask;
178 	writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
179 
180 	value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
181 	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
182 	value |= mask;
183 	writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
184 
185 	return 0;
186 }
187 
188 static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
189 {
190 	unsigned long value;
191 
192 	value = KIRKWOOD_DCO_CTL_OFFSET_0;
193 	switch (rate) {
194 	default:
195 	case 44100:
196 		value |= KIRKWOOD_DCO_CTL_FREQ_11;
197 		break;
198 	case 48000:
199 		value |= KIRKWOOD_DCO_CTL_FREQ_12;
200 		break;
201 	case 96000:
202 		value |= KIRKWOOD_DCO_CTL_FREQ_24;
203 		break;
204 	}
205 	writel(value, io + KIRKWOOD_DCO_CTL);
206 
207 	/* wait for dco locked */
208 	do {
209 		cpu_relax();
210 		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
211 		value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
212 	} while (value == 0);
213 }
214 
215 static void kirkwood_set_rate(struct snd_soc_dai *dai,
216 	struct kirkwood_dma_data *priv, unsigned long rate)
217 {
218 	uint32_t clks_ctrl;
219 
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",
224 			__func__, rate);
225 		if (priv->pll_config)
226 			armada_38x_set_pll(priv->pll_config, rate);
227 		else
228 			kirkwood_set_dco(priv->io, rate);
229 
230 		clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
231 	} else {
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);
237 
238 		clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
239 	}
240 	writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
241 }
242 
243 static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
244 		struct snd_soc_dai *dai)
245 {
246 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
247 
248 	snd_soc_dai_set_dma_data(dai, substream, priv);
249 	return 0;
250 }
251 
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)
255 {
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;
260 
261 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
262 		i2s_reg = KIRKWOOD_I2S_PLAYCTL;
263 	} else {
264 		i2s_reg = KIRKWOOD_I2S_RECCTL;
265 	}
266 
267 	kirkwood_set_rate(dai, priv, params_rate(params));
268 
269 	i2s_value = readl(priv->io+i2s_reg);
270 	i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
271 
272 	/*
273 	 * Size settings in play/rec i2s control regs and play/rec control
274 	 * regs must be the same.
275 	 */
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;
285 		break;
286 	/*
287 	 * doesn't work... S20_3LE != kirkwood 20bit format ?
288 	 *
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;
295 		break;
296 	*/
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;
305 		break;
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;
312 		break;
313 	default:
314 		return -EINVAL;
315 	}
316 
317 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
318 		if (params_channels(params) == 1)
319 			ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
320 		else
321 			ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
322 
323 		priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
324 				    KIRKWOOD_PLAYCTL_ENABLE_MASK |
325 				    KIRKWOOD_PLAYCTL_SIZE_MASK);
326 		priv->ctl_play |= ctl_play;
327 	} else {
328 		priv->ctl_rec &= ~(KIRKWOOD_RECCTL_ENABLE_MASK |
329 				   KIRKWOOD_RECCTL_SIZE_MASK);
330 		priv->ctl_rec |= ctl_rec;
331 	}
332 
333 	writel(i2s_value, priv->io+i2s_reg);
334 
335 	return 0;
336 }
337 
338 static unsigned kirkwood_i2s_play_mute(unsigned ctl)
339 {
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;
344 	return ctl;
345 }
346 
347 static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
348 				int cmd, struct snd_soc_dai *dai)
349 {
350 	struct snd_pcm_runtime *runtime = substream->runtime;
351 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
352 	uint32_t ctl, value;
353 
354 	ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
355 	if ((ctl & KIRKWOOD_PLAYCTL_ENABLE_MASK) == 0) {
356 		unsigned timeout = 5000;
357 		/*
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.
361 		 */
362 		do {
363 			value = ctl;
364 			ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
365 			if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY))
366 				break;
367 			udelay(1);
368 		} while (timeout--);
369 
370 		if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)
371 			dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n",
372 				   ctl);
373 	}
374 
375 	switch (cmd) {
376 	case SNDRV_PCM_TRIGGER_START:
377 		/* configure */
378 		ctl = priv->ctl_play;
379 		if (dai->id == 0)
380 			ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN;	/* i2s */
381 		else
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);
386 
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);
392 		}
393 
394 		/* enable playback */
395 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
396 		break;
397 
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);
403 
404 		value = readl(priv->io + KIRKWOOD_INT_MASK);
405 		value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
406 		writel(value, priv->io + KIRKWOOD_INT_MASK);
407 
408 		/* disable all playbacks */
409 		ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
410 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
411 		break;
412 
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);
418 		break;
419 
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);
426 		break;
427 
428 	default:
429 		return -EINVAL;
430 	}
431 
432 	return 0;
433 }
434 
435 static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
436 				int cmd, struct snd_soc_dai *dai)
437 {
438 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
439 	uint32_t ctl, value;
440 
441 	value = readl(priv->io + KIRKWOOD_RECCTL);
442 
443 	switch (cmd) {
444 	case SNDRV_PCM_TRIGGER_START:
445 		/* configure */
446 		ctl = priv->ctl_rec;
447 		if (dai->id == 0)
448 			ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN;	/* i2s */
449 		else
450 			ctl &= ~KIRKWOOD_RECCTL_I2S_EN;		/* spdif */
451 
452 		value = ctl & ~KIRKWOOD_RECCTL_ENABLE_MASK;
453 		writel(value, priv->io + KIRKWOOD_RECCTL);
454 
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);
459 
460 		/* enable record */
461 		writel(ctl, priv->io + KIRKWOOD_RECCTL);
462 		break;
463 
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);
469 
470 		value = readl(priv->io + KIRKWOOD_INT_MASK);
471 		value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
472 		writel(value, priv->io + KIRKWOOD_INT_MASK);
473 
474 		/* disable all records */
475 		value = readl(priv->io + KIRKWOOD_RECCTL);
476 		value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
477 		writel(value, priv->io + KIRKWOOD_RECCTL);
478 		break;
479 
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);
485 		break;
486 
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);
492 		break;
493 
494 	default:
495 		return -EINVAL;
496 	}
497 
498 	return 0;
499 }
500 
501 static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
502 			       struct snd_soc_dai *dai)
503 {
504 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
505 		return kirkwood_i2s_play_trigger(substream, cmd, dai);
506 	else
507 		return kirkwood_i2s_rec_trigger(substream, cmd, dai);
508 
509 	return 0;
510 }
511 
512 static int kirkwood_i2s_init(struct kirkwood_dma_data *priv)
513 {
514 	unsigned long value;
515 	unsigned int reg_data;
516 
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);
521 
522 	reg_data = readl(priv->io + 0x1200);
523 	reg_data &= (~(0x333FF8));
524 	reg_data |= 0x111D18;
525 	writel(reg_data, priv->io + 0x1200);
526 
527 	msleep(500);
528 
529 	reg_data = readl(priv->io + 0x1200);
530 	reg_data &= (~(0x333FF8));
531 	reg_data |= 0x111D18;
532 	writel(reg_data, priv->io + 0x1200);
533 
534 	/* disable playback/record */
535 	value = readl(priv->io + KIRKWOOD_PLAYCTL);
536 	value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
537 	writel(value, priv->io + KIRKWOOD_PLAYCTL);
538 
539 	value = readl(priv->io + KIRKWOOD_RECCTL);
540 	value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
541 	writel(value, priv->io + KIRKWOOD_RECCTL);
542 
543 	return 0;
544 
545 }
546 
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,
552 };
553 
554 static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = {
555     {
556 	.name = "i2s",
557 	.id = 0,
558 	.playback = {
559 		.channels_min = 1,
560 		.channels_max = 2,
561 		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
562 				SNDRV_PCM_RATE_96000,
563 		.formats = KIRKWOOD_I2S_FORMATS,
564 	},
565 	.capture = {
566 		.channels_min = 1,
567 		.channels_max = 2,
568 		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
569 				SNDRV_PCM_RATE_96000,
570 		.formats = KIRKWOOD_I2S_FORMATS,
571 	},
572 	.ops = &kirkwood_i2s_dai_ops,
573     },
574     {
575 	.name = "spdif",
576 	.id = 1,
577 	.playback = {
578 		.channels_min = 1,
579 		.channels_max = 2,
580 		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
581 				SNDRV_PCM_RATE_96000,
582 		.formats = KIRKWOOD_SPDIF_FORMATS,
583 	},
584 	.capture = {
585 		.channels_min = 1,
586 		.channels_max = 2,
587 		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
588 				SNDRV_PCM_RATE_96000,
589 		.formats = KIRKWOOD_SPDIF_FORMATS,
590 	},
591 	.ops = &kirkwood_i2s_dai_ops,
592     },
593 };
594 
595 static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = {
596     {
597 	.name = "i2s",
598 	.id = 0,
599 	.playback = {
600 		.channels_min = 1,
601 		.channels_max = 2,
602 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
603 		.rate_min = 5512,
604 		.rate_max = 192000,
605 		.formats = KIRKWOOD_I2S_FORMATS,
606 	},
607 	.capture = {
608 		.channels_min = 1,
609 		.channels_max = 2,
610 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
611 		.rate_min = 5512,
612 		.rate_max = 192000,
613 		.formats = KIRKWOOD_I2S_FORMATS,
614 	},
615 	.ops = &kirkwood_i2s_dai_ops,
616     },
617     {
618 	.name = "spdif",
619 	.id = 1,
620 	.playback = {
621 		.channels_min = 1,
622 		.channels_max = 2,
623 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
624 		.rate_min = 5512,
625 		.rate_max = 192000,
626 		.formats = KIRKWOOD_SPDIF_FORMATS,
627 	},
628 	.capture = {
629 		.channels_min = 1,
630 		.channels_max = 2,
631 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
632 		.rate_min = 5512,
633 		.rate_max = 192000,
634 		.formats = KIRKWOOD_SPDIF_FORMATS,
635 	},
636 	.ops = &kirkwood_i2s_dai_ops,
637     },
638 };
639 
640 static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
641 {
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;
646 	int err;
647 
648 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
649 	if (!priv)
650 		return -ENOMEM;
651 
652 	dev_set_drvdata(&pdev->dev, priv);
653 
654 	if (of_device_is_compatible(np, "marvell,armada-380-audio"))
655 		priv->io = devm_platform_ioremap_resource_byname(pdev, "i2s_regs");
656 	else
657 		priv->io = devm_platform_ioremap_resource(pdev, 0);
658 	if (IS_ERR(priv->io))
659 		return PTR_ERR(priv->io);
660 
661 	priv->irq = platform_get_irq(pdev, 0);
662 	if (priv->irq < 0)
663 		return priv->irq;
664 
665 	if (of_device_is_compatible(np, "marvell,armada-380-audio")) {
666 		err = armada_38x_i2s_init_quirk(pdev, priv, soc_dai);
667 		if (err < 0)
668 			return err;
669 		/* Set initial pll frequency */
670 		armada_38x_set_pll(priv->pll_config, 44100);
671 	}
672 
673 	if (np) {
674 		priv->burst = 128;		/* might be 32 or 128 */
675 	} else if (data) {
676 		priv->burst = data->burst;
677 	} else {
678 		dev_err(&pdev->dev, "no DT nor platform data ?!\n");
679 		return -EINVAL;
680 	}
681 
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);
686 	}
687 
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;
692 	} else {
693 		if (clk_is_match(priv->extclk, priv->clk)) {
694 			devm_clk_put(&pdev->dev, priv->extclk);
695 			priv->extclk = ERR_PTR(-EINVAL);
696 		} else {
697 			dev_info(&pdev->dev, "found external clock\n");
698 			clk_prepare_enable(priv->extclk);
699 			soc_dai = kirkwood_i2s_dai_extclk;
700 		}
701 	}
702 
703 	err = clk_prepare_enable(priv->clk);
704 	if (err < 0)
705 		return err;
706 
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;
710 
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;
715 	} else {
716 		priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
717 		priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
718 	}
719 
720 	err = snd_soc_register_component(&pdev->dev, &kirkwood_soc_component,
721 					 soc_dai, 2);
722 	if (err) {
723 		dev_err(&pdev->dev, "snd_soc_register_component failed\n");
724 		goto err_component;
725 	}
726 
727 	kirkwood_i2s_init(priv);
728 
729 	return 0;
730 
731  err_component:
732 	if (!IS_ERR(priv->extclk))
733 		clk_disable_unprepare(priv->extclk);
734 	clk_disable_unprepare(priv->clk);
735 
736 	return err;
737 }
738 
739 static void kirkwood_i2s_dev_remove(struct platform_device *pdev)
740 {
741 	struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
742 
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);
747 }
748 
749 #ifdef CONFIG_OF
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" },
755 	{ }
756 };
757 MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
758 #endif
759 
760 static struct platform_driver kirkwood_i2s_driver = {
761 	.probe  = kirkwood_i2s_dev_probe,
762 	.remove_new = kirkwood_i2s_dev_remove,
763 	.driver = {
764 		.name = DRV_NAME,
765 		.of_match_table = of_match_ptr(mvebu_audio_of_match),
766 	},
767 };
768 
769 module_platform_driver(kirkwood_i2s_driver);
770 
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");
776