xref: /linux/sound/soc/kirkwood/kirkwood-i2s.c (revision d8d11ba566761625e2b5ab716dca920725f3dc0b)
1f9b95980Sapatard@mandriva.com /*
2f9b95980Sapatard@mandriva.com  * kirkwood-i2s.c
3f9b95980Sapatard@mandriva.com  *
4f9b95980Sapatard@mandriva.com  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
569737897SArnaud Patard (Rtp)  * (c) 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
6f9b95980Sapatard@mandriva.com  *
7f9b95980Sapatard@mandriva.com  *  This program is free software; you can redistribute  it and/or modify it
8f9b95980Sapatard@mandriva.com  *  under  the terms of  the GNU General  Public License as published by the
9f9b95980Sapatard@mandriva.com  *  Free Software Foundation;  either version 2 of the  License, or (at your
10f9b95980Sapatard@mandriva.com  *  option) any later version.
11f9b95980Sapatard@mandriva.com  */
12f9b95980Sapatard@mandriva.com 
13f9b95980Sapatard@mandriva.com #include <linux/init.h>
14f9b95980Sapatard@mandriva.com #include <linux/module.h>
15f9b95980Sapatard@mandriva.com #include <linux/platform_device.h>
16f9b95980Sapatard@mandriva.com #include <linux/io.h>
17f9b95980Sapatard@mandriva.com #include <linux/slab.h>
18f9b95980Sapatard@mandriva.com #include <linux/mbus.h>
19f9b95980Sapatard@mandriva.com #include <linux/delay.h>
20e919c716SAndrew Lunn #include <linux/clk.h>
21f9b95980Sapatard@mandriva.com #include <sound/pcm.h>
22f9b95980Sapatard@mandriva.com #include <sound/pcm_params.h>
23f9b95980Sapatard@mandriva.com #include <sound/soc.h>
24c02cecb9SArnd Bergmann #include <linux/platform_data/asoc-kirkwood.h>
25f9b95980Sapatard@mandriva.com #include "kirkwood.h"
26f9b95980Sapatard@mandriva.com 
27f9b95980Sapatard@mandriva.com #define DRV_NAME	"kirkwood-i2s"
28f9b95980Sapatard@mandriva.com 
29f9b95980Sapatard@mandriva.com #define KIRKWOOD_I2S_RATES \
30f9b95980Sapatard@mandriva.com 	(SNDRV_PCM_RATE_44100 | \
31f9b95980Sapatard@mandriva.com 	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
32f9b95980Sapatard@mandriva.com #define KIRKWOOD_I2S_FORMATS \
33f9b95980Sapatard@mandriva.com 	(SNDRV_PCM_FMTBIT_S16_LE | \
34f9b95980Sapatard@mandriva.com 	 SNDRV_PCM_FMTBIT_S24_LE | \
35f9b95980Sapatard@mandriva.com 	 SNDRV_PCM_FMTBIT_S32_LE)
36f9b95980Sapatard@mandriva.com 
37f9b95980Sapatard@mandriva.com static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
38f9b95980Sapatard@mandriva.com 		unsigned int fmt)
39f9b95980Sapatard@mandriva.com {
40f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
41f9b95980Sapatard@mandriva.com 	unsigned long mask;
42f9b95980Sapatard@mandriva.com 	unsigned long value;
43f9b95980Sapatard@mandriva.com 
44f9b95980Sapatard@mandriva.com 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
45f9b95980Sapatard@mandriva.com 	case SND_SOC_DAIFMT_RIGHT_J:
46f9b95980Sapatard@mandriva.com 		mask = KIRKWOOD_I2S_CTL_RJ;
47f9b95980Sapatard@mandriva.com 		break;
48f9b95980Sapatard@mandriva.com 	case SND_SOC_DAIFMT_LEFT_J:
49f9b95980Sapatard@mandriva.com 		mask = KIRKWOOD_I2S_CTL_LJ;
50f9b95980Sapatard@mandriva.com 		break;
51f9b95980Sapatard@mandriva.com 	case SND_SOC_DAIFMT_I2S:
52f9b95980Sapatard@mandriva.com 		mask = KIRKWOOD_I2S_CTL_I2S;
53f9b95980Sapatard@mandriva.com 		break;
54f9b95980Sapatard@mandriva.com 	default:
55f9b95980Sapatard@mandriva.com 		return -EINVAL;
56f9b95980Sapatard@mandriva.com 	}
57f9b95980Sapatard@mandriva.com 
58f9b95980Sapatard@mandriva.com 	/*
59f9b95980Sapatard@mandriva.com 	 * Set same format for playback and record
60f9b95980Sapatard@mandriva.com 	 * This avoids some troubles.
61f9b95980Sapatard@mandriva.com 	 */
62f9b95980Sapatard@mandriva.com 	value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
63f9b95980Sapatard@mandriva.com 	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
64f9b95980Sapatard@mandriva.com 	value |= mask;
65f9b95980Sapatard@mandriva.com 	writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
66f9b95980Sapatard@mandriva.com 
67f9b95980Sapatard@mandriva.com 	value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
68f9b95980Sapatard@mandriva.com 	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
69f9b95980Sapatard@mandriva.com 	value |= mask;
70f9b95980Sapatard@mandriva.com 	writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
71f9b95980Sapatard@mandriva.com 
72f9b95980Sapatard@mandriva.com 	return 0;
73f9b95980Sapatard@mandriva.com }
74f9b95980Sapatard@mandriva.com 
75f9b95980Sapatard@mandriva.com static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
76f9b95980Sapatard@mandriva.com {
77f9b95980Sapatard@mandriva.com 	unsigned long value;
78f9b95980Sapatard@mandriva.com 
79f9b95980Sapatard@mandriva.com 	value = KIRKWOOD_DCO_CTL_OFFSET_0;
80f9b95980Sapatard@mandriva.com 	switch (rate) {
81f9b95980Sapatard@mandriva.com 	default:
82f9b95980Sapatard@mandriva.com 	case 44100:
83f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_DCO_CTL_FREQ_11;
84f9b95980Sapatard@mandriva.com 		break;
85f9b95980Sapatard@mandriva.com 	case 48000:
86f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_DCO_CTL_FREQ_12;
87f9b95980Sapatard@mandriva.com 		break;
88f9b95980Sapatard@mandriva.com 	case 96000:
89f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_DCO_CTL_FREQ_24;
90f9b95980Sapatard@mandriva.com 		break;
91f9b95980Sapatard@mandriva.com 	}
92f9b95980Sapatard@mandriva.com 	writel(value, io + KIRKWOOD_DCO_CTL);
93f9b95980Sapatard@mandriva.com 
94f9b95980Sapatard@mandriva.com 	/* wait for dco locked */
95f9b95980Sapatard@mandriva.com 	do {
96f9b95980Sapatard@mandriva.com 		cpu_relax();
97f9b95980Sapatard@mandriva.com 		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
982424d458SRussell King 		value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
99f9b95980Sapatard@mandriva.com 	} while (value == 0);
100f9b95980Sapatard@mandriva.com }
101f9b95980Sapatard@mandriva.com 
102f0fba2adSLiam Girdwood static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
103f0fba2adSLiam Girdwood 		struct snd_soc_dai *dai)
104f0fba2adSLiam Girdwood {
105f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
106f0fba2adSLiam Girdwood 
107f0fba2adSLiam Girdwood 	snd_soc_dai_set_dma_data(dai, substream, priv);
108f0fba2adSLiam Girdwood 	return 0;
109f0fba2adSLiam Girdwood }
110f0fba2adSLiam Girdwood 
111f9b95980Sapatard@mandriva.com static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
112f9b95980Sapatard@mandriva.com 				 struct snd_pcm_hw_params *params,
113f9b95980Sapatard@mandriva.com 				 struct snd_soc_dai *dai)
114f9b95980Sapatard@mandriva.com {
115f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
116*d8d11ba5SRussell King 	uint32_t ctl_play, ctl_rec;
117*d8d11ba5SRussell King 	unsigned int i2s_reg;
118*d8d11ba5SRussell King 	unsigned long i2s_value;
119f9b95980Sapatard@mandriva.com 
120f9b95980Sapatard@mandriva.com 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
121f9b95980Sapatard@mandriva.com 		i2s_reg = KIRKWOOD_I2S_PLAYCTL;
122f9b95980Sapatard@mandriva.com 	} else {
123f9b95980Sapatard@mandriva.com 		i2s_reg = KIRKWOOD_I2S_RECCTL;
124f9b95980Sapatard@mandriva.com 	}
125f9b95980Sapatard@mandriva.com 
126f9b95980Sapatard@mandriva.com 	/* set dco conf */
127f9b95980Sapatard@mandriva.com 	kirkwood_set_dco(priv->io, params_rate(params));
128f9b95980Sapatard@mandriva.com 
129f9b95980Sapatard@mandriva.com 	i2s_value = readl(priv->io+i2s_reg);
130f9b95980Sapatard@mandriva.com 	i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
131f9b95980Sapatard@mandriva.com 
132f9b95980Sapatard@mandriva.com 	/*
133f9b95980Sapatard@mandriva.com 	 * Size settings in play/rec i2s control regs and play/rec control
134f9b95980Sapatard@mandriva.com 	 * regs must be the same.
135f9b95980Sapatard@mandriva.com 	 */
136f9b95980Sapatard@mandriva.com 	switch (params_format(params)) {
137f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S16_LE:
138f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
139*d8d11ba5SRussell King 		ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
140*d8d11ba5SRussell King 			   KIRKWOOD_PLAYCTL_I2S_EN;
141*d8d11ba5SRussell King 		ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
142*d8d11ba5SRussell King 			  KIRKWOOD_RECCTL_I2S_EN;
143f9b95980Sapatard@mandriva.com 		break;
144f9b95980Sapatard@mandriva.com 	/*
145f9b95980Sapatard@mandriva.com 	 * doesn't work... S20_3LE != kirkwood 20bit format ?
146f9b95980Sapatard@mandriva.com 	 *
147f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S20_3LE:
148f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
149*d8d11ba5SRussell King 		ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
150*d8d11ba5SRussell King 			   KIRKWOOD_PLAYCTL_I2S_EN;
151*d8d11ba5SRussell King 		ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
152*d8d11ba5SRussell King 			  KIRKWOOD_RECCTL_I2S_EN;
153f9b95980Sapatard@mandriva.com 		break;
154f9b95980Sapatard@mandriva.com 	*/
155f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S24_LE:
156f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
157*d8d11ba5SRussell King 		ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
158*d8d11ba5SRussell King 			   KIRKWOOD_PLAYCTL_I2S_EN;
159*d8d11ba5SRussell King 		ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
160*d8d11ba5SRussell King 			  KIRKWOOD_RECCTL_I2S_EN;
161f9b95980Sapatard@mandriva.com 		break;
162f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S32_LE:
163f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
164*d8d11ba5SRussell King 		ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
165*d8d11ba5SRussell King 			   KIRKWOOD_PLAYCTL_I2S_EN;
166*d8d11ba5SRussell King 		ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
167*d8d11ba5SRussell King 			  KIRKWOOD_RECCTL_I2S_EN;
168f9b95980Sapatard@mandriva.com 		break;
169f9b95980Sapatard@mandriva.com 	default:
170f9b95980Sapatard@mandriva.com 		return -EINVAL;
171f9b95980Sapatard@mandriva.com 	}
172dfe4c936Sarnaud.patard@rtp-net.org 
173dfe4c936Sarnaud.patard@rtp-net.org 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
174dfe4c936Sarnaud.patard@rtp-net.org 		if (params_channels(params) == 1)
175*d8d11ba5SRussell King 			ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
176dfe4c936Sarnaud.patard@rtp-net.org 		else
177*d8d11ba5SRussell King 			ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
178*d8d11ba5SRussell King 
179*d8d11ba5SRussell King 		priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
180*d8d11ba5SRussell King 				    KIRKWOOD_PLAYCTL_I2S_EN |
181*d8d11ba5SRussell King 				    KIRKWOOD_PLAYCTL_SPDIF_EN |
182*d8d11ba5SRussell King 				    KIRKWOOD_PLAYCTL_SIZE_MASK);
183*d8d11ba5SRussell King 		priv->ctl_play |= ctl_play;
184*d8d11ba5SRussell King 	} else {
185*d8d11ba5SRussell King 		priv->ctl_rec &= ~KIRKWOOD_RECCTL_SIZE_MASK;
186*d8d11ba5SRussell King 		priv->ctl_rec |= ctl_rec;
187dfe4c936Sarnaud.patard@rtp-net.org 	}
188dfe4c936Sarnaud.patard@rtp-net.org 
189f9b95980Sapatard@mandriva.com 	writel(i2s_value, priv->io+i2s_reg);
190f9b95980Sapatard@mandriva.com 
191f9b95980Sapatard@mandriva.com 	return 0;
192f9b95980Sapatard@mandriva.com }
193f9b95980Sapatard@mandriva.com 
194f9b95980Sapatard@mandriva.com static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
195f9b95980Sapatard@mandriva.com 				int cmd, struct snd_soc_dai *dai)
196f9b95980Sapatard@mandriva.com {
197f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
198982b604bSRussell King 	uint32_t ctl, value;
199f9b95980Sapatard@mandriva.com 
200982b604bSRussell King 	ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
201982b604bSRussell King 	if (ctl & KIRKWOOD_PLAYCTL_PAUSE) {
202982b604bSRussell King 		unsigned timeout = 5000;
203f9b95980Sapatard@mandriva.com 		/*
204982b604bSRussell King 		 * The Armada510 spec says that if we enter pause mode, the
205982b604bSRussell King 		 * busy bit must be read back as clear _twice_.  Make sure
206982b604bSRussell King 		 * we respect that otherwise we get DMA underruns.
207f9b95980Sapatard@mandriva.com 		 */
208982b604bSRussell King 		do {
209982b604bSRussell King 			value = ctl;
210982b604bSRussell King 			ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
211982b604bSRussell King 			if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY))
212982b604bSRussell King 				break;
213982b604bSRussell King 			udelay(1);
214982b604bSRussell King 		} while (timeout--);
215982b604bSRussell King 
216982b604bSRussell King 		if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)
217982b604bSRussell King 			dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n",
218982b604bSRussell King 				   ctl);
219982b604bSRussell King 	}
220f9b95980Sapatard@mandriva.com 
221f9b95980Sapatard@mandriva.com 	switch (cmd) {
222f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_START:
223*d8d11ba5SRussell King 		/* configure */
224*d8d11ba5SRussell King 		ctl = priv->ctl_play;
225*d8d11ba5SRussell King 		value = ctl & ~(KIRKWOOD_PLAYCTL_I2S_EN |
226*d8d11ba5SRussell King 				KIRKWOOD_PLAYCTL_SPDIF_EN);
227*d8d11ba5SRussell King 		writel(value, priv->io + KIRKWOOD_PLAYCTL);
228*d8d11ba5SRussell King 
229*d8d11ba5SRussell King 		/* enable interrupts */
230f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
231f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
232f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
233f9b95980Sapatard@mandriva.com 
234*d8d11ba5SRussell King 		/* enable playback */
235982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
236f9b95980Sapatard@mandriva.com 		break;
237f9b95980Sapatard@mandriva.com 
238f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_STOP:
239f9b95980Sapatard@mandriva.com 		/* stop audio, disable interrupts */
240982b604bSRussell King 		ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
241982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
242f9b95980Sapatard@mandriva.com 
243f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
244f9b95980Sapatard@mandriva.com 		value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
245f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
246f9b95980Sapatard@mandriva.com 
247f9b95980Sapatard@mandriva.com 		/* disable all playbacks */
248982b604bSRussell King 		ctl &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
249982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
250f9b95980Sapatard@mandriva.com 		break;
251f9b95980Sapatard@mandriva.com 
252f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
253f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_SUSPEND:
254982b604bSRussell King 		ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
255982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
256f9b95980Sapatard@mandriva.com 		break;
257f9b95980Sapatard@mandriva.com 
258f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_RESUME:
259f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
260982b604bSRussell King 		ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
261982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
262f9b95980Sapatard@mandriva.com 		break;
263f9b95980Sapatard@mandriva.com 
264f9b95980Sapatard@mandriva.com 	default:
265f9b95980Sapatard@mandriva.com 		return -EINVAL;
266f9b95980Sapatard@mandriva.com 	}
267f9b95980Sapatard@mandriva.com 
268f9b95980Sapatard@mandriva.com 	return 0;
269f9b95980Sapatard@mandriva.com }
270f9b95980Sapatard@mandriva.com 
271f9b95980Sapatard@mandriva.com static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
272f9b95980Sapatard@mandriva.com 				int cmd, struct snd_soc_dai *dai)
273f9b95980Sapatard@mandriva.com {
274f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
275*d8d11ba5SRussell King 	uint32_t ctl, value;
276f9b95980Sapatard@mandriva.com 
277f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_RECCTL);
278f9b95980Sapatard@mandriva.com 
279f9b95980Sapatard@mandriva.com 	switch (cmd) {
280f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_START:
281*d8d11ba5SRussell King 		/* configure */
282*d8d11ba5SRussell King 		ctl = priv->ctl_rec;
283*d8d11ba5SRussell King 		value = ctl & ~KIRKWOOD_RECCTL_I2S_EN;
284*d8d11ba5SRussell King 		writel(value, priv->io + KIRKWOOD_RECCTL);
285*d8d11ba5SRussell King 
286*d8d11ba5SRussell King 		/* enable interrupts */
287f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
288f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
289f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
290f9b95980Sapatard@mandriva.com 
291*d8d11ba5SRussell King 		/* enable record */
292*d8d11ba5SRussell King 		writel(ctl, priv->io + KIRKWOOD_RECCTL);
293f9b95980Sapatard@mandriva.com 		break;
294f9b95980Sapatard@mandriva.com 
295f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_STOP:
296f9b95980Sapatard@mandriva.com 		/* stop audio, disable interrupts */
297f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
298b424ec95Sarnaud.patard@rtp-net.org 		value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
299f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
300f9b95980Sapatard@mandriva.com 
301f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
302f9b95980Sapatard@mandriva.com 		value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
303f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
304f9b95980Sapatard@mandriva.com 
305f9b95980Sapatard@mandriva.com 		/* disable all records */
306f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
307f9b95980Sapatard@mandriva.com 		value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
308f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
309f9b95980Sapatard@mandriva.com 		break;
310f9b95980Sapatard@mandriva.com 
311f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
312f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_SUSPEND:
313f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
314b424ec95Sarnaud.patard@rtp-net.org 		value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
315f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
316f9b95980Sapatard@mandriva.com 		break;
317f9b95980Sapatard@mandriva.com 
318f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_RESUME:
319f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
320f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
321b424ec95Sarnaud.patard@rtp-net.org 		value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
322f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
323f9b95980Sapatard@mandriva.com 		break;
324f9b95980Sapatard@mandriva.com 
325f9b95980Sapatard@mandriva.com 	default:
326f9b95980Sapatard@mandriva.com 		return -EINVAL;
327f9b95980Sapatard@mandriva.com 	}
328f9b95980Sapatard@mandriva.com 
329f9b95980Sapatard@mandriva.com 	return 0;
330f9b95980Sapatard@mandriva.com }
331f9b95980Sapatard@mandriva.com 
332f9b95980Sapatard@mandriva.com static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
333f9b95980Sapatard@mandriva.com 			       struct snd_soc_dai *dai)
334f9b95980Sapatard@mandriva.com {
335f9b95980Sapatard@mandriva.com 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
336f9b95980Sapatard@mandriva.com 		return kirkwood_i2s_play_trigger(substream, cmd, dai);
337f9b95980Sapatard@mandriva.com 	else
338f9b95980Sapatard@mandriva.com 		return kirkwood_i2s_rec_trigger(substream, cmd, dai);
339f9b95980Sapatard@mandriva.com 
340f9b95980Sapatard@mandriva.com 	return 0;
341f9b95980Sapatard@mandriva.com }
342f9b95980Sapatard@mandriva.com 
343f0fba2adSLiam Girdwood static int kirkwood_i2s_probe(struct snd_soc_dai *dai)
344f9b95980Sapatard@mandriva.com {
345f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
346f9b95980Sapatard@mandriva.com 	unsigned long value;
347f9b95980Sapatard@mandriva.com 	unsigned int reg_data;
348f9b95980Sapatard@mandriva.com 
349f9b95980Sapatard@mandriva.com 	/* put system in a "safe" state : */
350f9b95980Sapatard@mandriva.com 	/* disable audio interrupts */
351f9b95980Sapatard@mandriva.com 	writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
352f9b95980Sapatard@mandriva.com 	writel(0, priv->io + KIRKWOOD_INT_MASK);
353f9b95980Sapatard@mandriva.com 
354f9b95980Sapatard@mandriva.com 	reg_data = readl(priv->io + 0x1200);
355f9b95980Sapatard@mandriva.com 	reg_data &= (~(0x333FF8));
356f9b95980Sapatard@mandriva.com 	reg_data |= 0x111D18;
357f9b95980Sapatard@mandriva.com 	writel(reg_data, priv->io + 0x1200);
358f9b95980Sapatard@mandriva.com 
359f9b95980Sapatard@mandriva.com 	msleep(500);
360f9b95980Sapatard@mandriva.com 
361f9b95980Sapatard@mandriva.com 	reg_data = readl(priv->io + 0x1200);
362f9b95980Sapatard@mandriva.com 	reg_data &= (~(0x333FF8));
363f9b95980Sapatard@mandriva.com 	reg_data |= 0x111D18;
364f9b95980Sapatard@mandriva.com 	writel(reg_data, priv->io + 0x1200);
365f9b95980Sapatard@mandriva.com 
366f9b95980Sapatard@mandriva.com 	/* disable playback/record */
367f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_PLAYCTL);
368f9b95980Sapatard@mandriva.com 	value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
369f9b95980Sapatard@mandriva.com 	writel(value, priv->io + KIRKWOOD_PLAYCTL);
370f9b95980Sapatard@mandriva.com 
371f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_RECCTL);
372f9b95980Sapatard@mandriva.com 	value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
373f9b95980Sapatard@mandriva.com 	writel(value, priv->io + KIRKWOOD_RECCTL);
374f9b95980Sapatard@mandriva.com 
375f9b95980Sapatard@mandriva.com 	return 0;
376f9b95980Sapatard@mandriva.com 
377f9b95980Sapatard@mandriva.com }
378f9b95980Sapatard@mandriva.com 
379f0fba2adSLiam Girdwood static int kirkwood_i2s_remove(struct snd_soc_dai *dai)
380f9b95980Sapatard@mandriva.com {
381f0fba2adSLiam Girdwood 	return 0;
382f9b95980Sapatard@mandriva.com }
383f9b95980Sapatard@mandriva.com 
38485e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
385f0fba2adSLiam Girdwood 	.startup	= kirkwood_i2s_startup,
386f9b95980Sapatard@mandriva.com 	.trigger	= kirkwood_i2s_trigger,
387f9b95980Sapatard@mandriva.com 	.hw_params      = kirkwood_i2s_hw_params,
388f9b95980Sapatard@mandriva.com 	.set_fmt        = kirkwood_i2s_set_fmt,
389f9b95980Sapatard@mandriva.com };
390f9b95980Sapatard@mandriva.com 
391f9b95980Sapatard@mandriva.com 
392f0fba2adSLiam Girdwood static struct snd_soc_dai_driver kirkwood_i2s_dai = {
393f9b95980Sapatard@mandriva.com 	.probe = kirkwood_i2s_probe,
394f9b95980Sapatard@mandriva.com 	.remove = kirkwood_i2s_remove,
395f9b95980Sapatard@mandriva.com 	.playback = {
396f9b95980Sapatard@mandriva.com 		.channels_min = 1,
397f9b95980Sapatard@mandriva.com 		.channels_max = 2,
398f9b95980Sapatard@mandriva.com 		.rates = KIRKWOOD_I2S_RATES,
399f9b95980Sapatard@mandriva.com 		.formats = KIRKWOOD_I2S_FORMATS,},
400f9b95980Sapatard@mandriva.com 	.capture = {
401f9b95980Sapatard@mandriva.com 		.channels_min = 1,
402f9b95980Sapatard@mandriva.com 		.channels_max = 2,
403f9b95980Sapatard@mandriva.com 		.rates = KIRKWOOD_I2S_RATES,
404f9b95980Sapatard@mandriva.com 		.formats = KIRKWOOD_I2S_FORMATS,},
405f9b95980Sapatard@mandriva.com 	.ops = &kirkwood_i2s_dai_ops,
406f9b95980Sapatard@mandriva.com };
407f9b95980Sapatard@mandriva.com 
408f9b95980Sapatard@mandriva.com static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
409f9b95980Sapatard@mandriva.com {
410f9b95980Sapatard@mandriva.com 	struct resource *mem;
411f9b95980Sapatard@mandriva.com 	struct kirkwood_asoc_platform_data *data =
412f9b95980Sapatard@mandriva.com 		pdev->dev.platform_data;
413f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv;
414f9b95980Sapatard@mandriva.com 	int err;
415f9b95980Sapatard@mandriva.com 
416dbc517bfSRussell King 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
417f9b95980Sapatard@mandriva.com 	if (!priv) {
418f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "allocation failed\n");
419dbc517bfSRussell King 		return -ENOMEM;
420f9b95980Sapatard@mandriva.com 	}
421f0fba2adSLiam Girdwood 	dev_set_drvdata(&pdev->dev, priv);
422f9b95980Sapatard@mandriva.com 
423f9b95980Sapatard@mandriva.com 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
424f9b95980Sapatard@mandriva.com 	if (!mem) {
425f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "platform_get_resource failed\n");
426dbc517bfSRussell King 		return -ENXIO;
427f9b95980Sapatard@mandriva.com 	}
428f9b95980Sapatard@mandriva.com 
429dbc517bfSRussell King 	priv->io = devm_request_and_ioremap(&pdev->dev, mem);
430f9b95980Sapatard@mandriva.com 	if (!priv->io) {
431dbc517bfSRussell King 		dev_err(&pdev->dev, "devm_request_and_ioremap failed\n");
432dbc517bfSRussell King 		return -ENOMEM;
433f9b95980Sapatard@mandriva.com 	}
434f9b95980Sapatard@mandriva.com 
435f9b95980Sapatard@mandriva.com 	priv->irq = platform_get_irq(pdev, 0);
436f9b95980Sapatard@mandriva.com 	if (priv->irq <= 0) {
437f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "platform_get_irq failed\n");
438dbc517bfSRussell King 		return -ENXIO;
439f9b95980Sapatard@mandriva.com 	}
440f9b95980Sapatard@mandriva.com 
441d4d9820bSAxel Lin 	if (!data) {
442f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "no platform data ?!\n");
443dbc517bfSRussell King 		return -EINVAL;
444f9b95980Sapatard@mandriva.com 	}
445f9b95980Sapatard@mandriva.com 
446f9b95980Sapatard@mandriva.com 	priv->burst = data->burst;
447f9b95980Sapatard@mandriva.com 
448dbc517bfSRussell King 	priv->clk = devm_clk_get(&pdev->dev, NULL);
449e919c716SAndrew Lunn 	if (IS_ERR(priv->clk)) {
450e919c716SAndrew Lunn 		dev_err(&pdev->dev, "no clock\n");
451dbc517bfSRussell King 		return PTR_ERR(priv->clk);
452e919c716SAndrew Lunn 	}
453dbc517bfSRussell King 
454dbc517bfSRussell King 	err = clk_prepare_enable(priv->clk);
455dbc517bfSRussell King 	if (err < 0)
456dbc517bfSRussell King 		return err;
457e919c716SAndrew Lunn 
458*d8d11ba5SRussell King 	priv->extclk = clk_get(&pdev->dev, "extclk");
459*d8d11ba5SRussell King 	if (!IS_ERR(priv->extclk)) {
460*d8d11ba5SRussell King 		if (priv->extclk == priv->clk) {
461*d8d11ba5SRussell King 			clk_put(priv->extclk);
462*d8d11ba5SRussell King 			priv->extclk = ERR_PTR(-EINVAL);
463*d8d11ba5SRussell King 		} else {
464*d8d11ba5SRussell King 			dev_info(&pdev->dev, "found external clock\n");
465*d8d11ba5SRussell King 			clk_prepare_enable(priv->extclk);
466*d8d11ba5SRussell King 			soc_dai = &kirkwood_i2s_dai_extclk;
467*d8d11ba5SRussell King 		}
468*d8d11ba5SRussell King 	}
469*d8d11ba5SRussell King 
470*d8d11ba5SRussell King 	/* Some sensible defaults - this reflects the powerup values */
471*d8d11ba5SRussell King 	priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24;
472*d8d11ba5SRussell King 	priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
473*d8d11ba5SRussell King 
474*d8d11ba5SRussell King 	/* Select the burst size */
475*d8d11ba5SRussell King 	if (data->burst == 32) {
476*d8d11ba5SRussell King 		priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
477*d8d11ba5SRussell King 		priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
478*d8d11ba5SRussell King 	} else {
479*d8d11ba5SRussell King 		priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
480*d8d11ba5SRussell King 		priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
481*d8d11ba5SRussell King 	}
482*d8d11ba5SRussell King 
483baffab28SSimon Baatz 	err = snd_soc_register_dai(&pdev->dev, &kirkwood_i2s_dai);
484baffab28SSimon Baatz 	if (!err)
485baffab28SSimon Baatz 		return 0;
486baffab28SSimon Baatz 	dev_err(&pdev->dev, "snd_soc_register_dai failed\n");
487baffab28SSimon Baatz 
488baffab28SSimon Baatz 	clk_disable_unprepare(priv->clk);
489f9b95980Sapatard@mandriva.com 
490f9b95980Sapatard@mandriva.com 	return err;
491f9b95980Sapatard@mandriva.com }
492f9b95980Sapatard@mandriva.com 
493f9b95980Sapatard@mandriva.com static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
494f9b95980Sapatard@mandriva.com {
495f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
496f0fba2adSLiam Girdwood 
497f0fba2adSLiam Girdwood 	snd_soc_unregister_dai(&pdev->dev);
498e919c716SAndrew Lunn 
499e919c716SAndrew Lunn 	clk_disable_unprepare(priv->clk);
500f0fba2adSLiam Girdwood 
501f9b95980Sapatard@mandriva.com 	return 0;
502f9b95980Sapatard@mandriva.com }
503f9b95980Sapatard@mandriva.com 
504f9b95980Sapatard@mandriva.com static struct platform_driver kirkwood_i2s_driver = {
505f9b95980Sapatard@mandriva.com 	.probe  = kirkwood_i2s_dev_probe,
50648860e40SAxel Lin 	.remove = __devexit_p(kirkwood_i2s_dev_remove),
507f9b95980Sapatard@mandriva.com 	.driver = {
508f9b95980Sapatard@mandriva.com 		.name = DRV_NAME,
509f9b95980Sapatard@mandriva.com 		.owner = THIS_MODULE,
510f9b95980Sapatard@mandriva.com 	},
511f9b95980Sapatard@mandriva.com };
512f9b95980Sapatard@mandriva.com 
51341b10225SAxel Lin module_platform_driver(kirkwood_i2s_driver);
514f9b95980Sapatard@mandriva.com 
515f9b95980Sapatard@mandriva.com /* Module information */
51669737897SArnaud Patard (Rtp) MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
517f9b95980Sapatard@mandriva.com MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
518f9b95980Sapatard@mandriva.com MODULE_LICENSE("GPL");
519f9b95980Sapatard@mandriva.com MODULE_ALIAS("platform:kirkwood-i2s");
520