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
52static 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
88static 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
150static 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
188static 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
215static 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
243static 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
252static 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
338static 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
347static 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
435static 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
501static 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
512static 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
547static 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
554static 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
595static 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
640static 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
739static 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
750static 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};
757MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
758#endif
759
760static 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
769module_platform_driver(kirkwood_i2s_driver);
770
771/* Module information */
772MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
773MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
774MODULE_LICENSE("GPL");
775MODULE_ALIAS("platform:mvebu-audio");
776