xref: /linux/sound/soc/kirkwood/kirkwood-i2s.c (revision b424ec953344e0ea612a8cc2d8e59742a0273ac1)
1f9b95980Sapatard@mandriva.com /*
2f9b95980Sapatard@mandriva.com  * kirkwood-i2s.c
3f9b95980Sapatard@mandriva.com  *
4f9b95980Sapatard@mandriva.com  * (c) 2010 Arnaud Patard <apatard@mandriva.com>
5f9b95980Sapatard@mandriva.com  *
6f9b95980Sapatard@mandriva.com  *  This program is free software; you can redistribute  it and/or modify it
7f9b95980Sapatard@mandriva.com  *  under  the terms of  the GNU General  Public License as published by the
8f9b95980Sapatard@mandriva.com  *  Free Software Foundation;  either version 2 of the  License, or (at your
9f9b95980Sapatard@mandriva.com  *  option) any later version.
10f9b95980Sapatard@mandriva.com  */
11f9b95980Sapatard@mandriva.com 
12f9b95980Sapatard@mandriva.com #include <linux/init.h>
13f9b95980Sapatard@mandriva.com #include <linux/module.h>
14f9b95980Sapatard@mandriva.com #include <linux/platform_device.h>
15f9b95980Sapatard@mandriva.com #include <linux/io.h>
16f9b95980Sapatard@mandriva.com #include <linux/slab.h>
17f9b95980Sapatard@mandriva.com #include <linux/mbus.h>
18f9b95980Sapatard@mandriva.com #include <linux/delay.h>
19f9b95980Sapatard@mandriva.com #include <sound/pcm.h>
20f9b95980Sapatard@mandriva.com #include <sound/pcm_params.h>
21f9b95980Sapatard@mandriva.com #include <sound/soc.h>
22f9b95980Sapatard@mandriva.com #include <plat/audio.h>
23f9b95980Sapatard@mandriva.com #include "kirkwood-i2s.h"
24f9b95980Sapatard@mandriva.com #include "kirkwood.h"
25f9b95980Sapatard@mandriva.com 
26f9b95980Sapatard@mandriva.com #define DRV_NAME	"kirkwood-i2s"
27f9b95980Sapatard@mandriva.com 
28f9b95980Sapatard@mandriva.com #define KIRKWOOD_I2S_RATES \
29f9b95980Sapatard@mandriva.com 	(SNDRV_PCM_RATE_44100 | \
30f9b95980Sapatard@mandriva.com 	 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
31f9b95980Sapatard@mandriva.com #define KIRKWOOD_I2S_FORMATS \
32f9b95980Sapatard@mandriva.com 	(SNDRV_PCM_FMTBIT_S16_LE | \
33f9b95980Sapatard@mandriva.com 	 SNDRV_PCM_FMTBIT_S24_LE | \
34f9b95980Sapatard@mandriva.com 	 SNDRV_PCM_FMTBIT_S32_LE)
35f9b95980Sapatard@mandriva.com 
36f9b95980Sapatard@mandriva.com 
37f9b95980Sapatard@mandriva.com struct snd_soc_dai kirkwood_i2s_dai;
38f9b95980Sapatard@mandriva.com static struct kirkwood_dma_data *priv;
39f9b95980Sapatard@mandriva.com 
40f9b95980Sapatard@mandriva.com static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
41f9b95980Sapatard@mandriva.com 		unsigned int fmt)
42f9b95980Sapatard@mandriva.com {
43f9b95980Sapatard@mandriva.com 	unsigned long mask;
44f9b95980Sapatard@mandriva.com 	unsigned long value;
45f9b95980Sapatard@mandriva.com 
46f9b95980Sapatard@mandriva.com 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
47f9b95980Sapatard@mandriva.com 	case SND_SOC_DAIFMT_RIGHT_J:
48f9b95980Sapatard@mandriva.com 		mask = KIRKWOOD_I2S_CTL_RJ;
49f9b95980Sapatard@mandriva.com 		break;
50f9b95980Sapatard@mandriva.com 	case SND_SOC_DAIFMT_LEFT_J:
51f9b95980Sapatard@mandriva.com 		mask = KIRKWOOD_I2S_CTL_LJ;
52f9b95980Sapatard@mandriva.com 		break;
53f9b95980Sapatard@mandriva.com 	case SND_SOC_DAIFMT_I2S:
54f9b95980Sapatard@mandriva.com 		mask = KIRKWOOD_I2S_CTL_I2S;
55f9b95980Sapatard@mandriva.com 		break;
56f9b95980Sapatard@mandriva.com 	default:
57f9b95980Sapatard@mandriva.com 		return -EINVAL;
58f9b95980Sapatard@mandriva.com 	}
59f9b95980Sapatard@mandriva.com 
60f9b95980Sapatard@mandriva.com 	/*
61f9b95980Sapatard@mandriva.com 	 * Set same format for playback and record
62f9b95980Sapatard@mandriva.com 	 * This avoids some troubles.
63f9b95980Sapatard@mandriva.com 	 */
64f9b95980Sapatard@mandriva.com 	value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
65f9b95980Sapatard@mandriva.com 	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
66f9b95980Sapatard@mandriva.com 	value |= mask;
67f9b95980Sapatard@mandriva.com 	writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
68f9b95980Sapatard@mandriva.com 
69f9b95980Sapatard@mandriva.com 	value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
70f9b95980Sapatard@mandriva.com 	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
71f9b95980Sapatard@mandriva.com 	value |= mask;
72f9b95980Sapatard@mandriva.com 	writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
73f9b95980Sapatard@mandriva.com 
74f9b95980Sapatard@mandriva.com 	return 0;
75f9b95980Sapatard@mandriva.com }
76f9b95980Sapatard@mandriva.com 
77f9b95980Sapatard@mandriva.com static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
78f9b95980Sapatard@mandriva.com {
79f9b95980Sapatard@mandriva.com 	unsigned long value;
80f9b95980Sapatard@mandriva.com 
81f9b95980Sapatard@mandriva.com 	value = KIRKWOOD_DCO_CTL_OFFSET_0;
82f9b95980Sapatard@mandriva.com 	switch (rate) {
83f9b95980Sapatard@mandriva.com 	default:
84f9b95980Sapatard@mandriva.com 	case 44100:
85f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_DCO_CTL_FREQ_11;
86f9b95980Sapatard@mandriva.com 		break;
87f9b95980Sapatard@mandriva.com 	case 48000:
88f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_DCO_CTL_FREQ_12;
89f9b95980Sapatard@mandriva.com 		break;
90f9b95980Sapatard@mandriva.com 	case 96000:
91f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_DCO_CTL_FREQ_24;
92f9b95980Sapatard@mandriva.com 		break;
93f9b95980Sapatard@mandriva.com 	}
94f9b95980Sapatard@mandriva.com 	writel(value, io + KIRKWOOD_DCO_CTL);
95f9b95980Sapatard@mandriva.com 
96f9b95980Sapatard@mandriva.com 	/* wait for dco locked */
97f9b95980Sapatard@mandriva.com 	do {
98f9b95980Sapatard@mandriva.com 		cpu_relax();
99f9b95980Sapatard@mandriva.com 		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
100f9b95980Sapatard@mandriva.com 		value &= KIRKWOOD_DCO_SPCR_STATUS;
101f9b95980Sapatard@mandriva.com 	} while (value == 0);
102f9b95980Sapatard@mandriva.com }
103f9b95980Sapatard@mandriva.com 
104f9b95980Sapatard@mandriva.com static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
105f9b95980Sapatard@mandriva.com 				 struct snd_pcm_hw_params *params,
106f9b95980Sapatard@mandriva.com 				 struct snd_soc_dai *dai)
107f9b95980Sapatard@mandriva.com {
108f9b95980Sapatard@mandriva.com 	unsigned int i2s_reg, reg;
109f9b95980Sapatard@mandriva.com 	unsigned long i2s_value, value;
110f9b95980Sapatard@mandriva.com 
111f9b95980Sapatard@mandriva.com 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
112f9b95980Sapatard@mandriva.com 		i2s_reg = KIRKWOOD_I2S_PLAYCTL;
113f9b95980Sapatard@mandriva.com 		reg = KIRKWOOD_PLAYCTL;
114f9b95980Sapatard@mandriva.com 	} else {
115f9b95980Sapatard@mandriva.com 		i2s_reg = KIRKWOOD_I2S_RECCTL;
116f9b95980Sapatard@mandriva.com 		reg = KIRKWOOD_RECCTL;
117f9b95980Sapatard@mandriva.com 	}
118f9b95980Sapatard@mandriva.com 
119f9b95980Sapatard@mandriva.com 	/* set dco conf */
120f9b95980Sapatard@mandriva.com 	kirkwood_set_dco(priv->io, params_rate(params));
121f9b95980Sapatard@mandriva.com 
122f9b95980Sapatard@mandriva.com 	i2s_value = readl(priv->io+i2s_reg);
123f9b95980Sapatard@mandriva.com 	i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
124f9b95980Sapatard@mandriva.com 
125f9b95980Sapatard@mandriva.com 	value = readl(priv->io+reg);
126f9b95980Sapatard@mandriva.com 	value &= ~KIRKWOOD_PLAYCTL_SIZE_MASK;
127f9b95980Sapatard@mandriva.com 
128f9b95980Sapatard@mandriva.com 	/*
129f9b95980Sapatard@mandriva.com 	 * Size settings in play/rec i2s control regs and play/rec control
130f9b95980Sapatard@mandriva.com 	 * regs must be the same.
131f9b95980Sapatard@mandriva.com 	 */
132f9b95980Sapatard@mandriva.com 	switch (params_format(params)) {
133f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S16_LE:
134f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
135f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_PLAYCTL_SIZE_16_C;
136f9b95980Sapatard@mandriva.com 		break;
137f9b95980Sapatard@mandriva.com 	/*
138f9b95980Sapatard@mandriva.com 	 * doesn't work... S20_3LE != kirkwood 20bit format ?
139f9b95980Sapatard@mandriva.com 	 *
140f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S20_3LE:
141f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
142f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_PLAYCTL_SIZE_20;
143f9b95980Sapatard@mandriva.com 		break;
144f9b95980Sapatard@mandriva.com 	*/
145f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S24_LE:
146f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
147f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_PLAYCTL_SIZE_24;
148f9b95980Sapatard@mandriva.com 		break;
149f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S32_LE:
150f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
151f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_PLAYCTL_SIZE_32;
152f9b95980Sapatard@mandriva.com 		break;
153f9b95980Sapatard@mandriva.com 	default:
154f9b95980Sapatard@mandriva.com 		return -EINVAL;
155f9b95980Sapatard@mandriva.com 	}
156dfe4c936Sarnaud.patard@rtp-net.org 
157dfe4c936Sarnaud.patard@rtp-net.org 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
158dfe4c936Sarnaud.patard@rtp-net.org 		value &= ~KIRKWOOD_PLAYCTL_MONO_MASK;
159dfe4c936Sarnaud.patard@rtp-net.org 		if (params_channels(params) == 1)
160dfe4c936Sarnaud.patard@rtp-net.org 			value |= KIRKWOOD_PLAYCTL_MONO_BOTH;
161dfe4c936Sarnaud.patard@rtp-net.org 		else
162dfe4c936Sarnaud.patard@rtp-net.org 			value |= KIRKWOOD_PLAYCTL_MONO_OFF;
163dfe4c936Sarnaud.patard@rtp-net.org 	}
164dfe4c936Sarnaud.patard@rtp-net.org 
165f9b95980Sapatard@mandriva.com 	writel(i2s_value, priv->io+i2s_reg);
166f9b95980Sapatard@mandriva.com 	writel(value, priv->io+reg);
167f9b95980Sapatard@mandriva.com 
168f9b95980Sapatard@mandriva.com 	return 0;
169f9b95980Sapatard@mandriva.com }
170f9b95980Sapatard@mandriva.com 
171f9b95980Sapatard@mandriva.com static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
172f9b95980Sapatard@mandriva.com 				int cmd, struct snd_soc_dai *dai)
173f9b95980Sapatard@mandriva.com {
174f9b95980Sapatard@mandriva.com 	unsigned long value;
175f9b95980Sapatard@mandriva.com 
176f9b95980Sapatard@mandriva.com 	/*
177f9b95980Sapatard@mandriva.com 	 * specs says KIRKWOOD_PLAYCTL must be read 2 times before
178f9b95980Sapatard@mandriva.com 	 * changing it. So read 1 time here and 1 later.
179f9b95980Sapatard@mandriva.com 	 */
180f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_PLAYCTL);
181f9b95980Sapatard@mandriva.com 
182f9b95980Sapatard@mandriva.com 	switch (cmd) {
183f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_START:
184f9b95980Sapatard@mandriva.com 		/* stop audio, enable interrupts */
185f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_PLAYCTL);
186f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_PLAYCTL_PAUSE;
187f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_PLAYCTL);
188f9b95980Sapatard@mandriva.com 
189f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
190f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
191f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
192f9b95980Sapatard@mandriva.com 
193f9b95980Sapatard@mandriva.com 		/* configure audio & enable i2s playback */
194f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_PLAYCTL);
195f9b95980Sapatard@mandriva.com 		value &= ~KIRKWOOD_PLAYCTL_BURST_MASK;
196*b424ec95Sarnaud.patard@rtp-net.org 		value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE
197*b424ec95Sarnaud.patard@rtp-net.org 				| KIRKWOOD_PLAYCTL_SPDIF_EN);
198f9b95980Sapatard@mandriva.com 
199f9b95980Sapatard@mandriva.com 		if (priv->burst == 32)
200f9b95980Sapatard@mandriva.com 			value |= KIRKWOOD_PLAYCTL_BURST_32;
201f9b95980Sapatard@mandriva.com 		else
202f9b95980Sapatard@mandriva.com 			value |= KIRKWOOD_PLAYCTL_BURST_128;
203f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_PLAYCTL_I2S_EN;
204f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_PLAYCTL);
205f9b95980Sapatard@mandriva.com 		break;
206f9b95980Sapatard@mandriva.com 
207f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_STOP:
208f9b95980Sapatard@mandriva.com 		/* stop audio, disable interrupts */
209f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_PLAYCTL);
210*b424ec95Sarnaud.patard@rtp-net.org 		value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
211f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_PLAYCTL);
212f9b95980Sapatard@mandriva.com 
213f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
214f9b95980Sapatard@mandriva.com 		value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
215f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
216f9b95980Sapatard@mandriva.com 
217f9b95980Sapatard@mandriva.com 		/* disable all playbacks */
218f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_PLAYCTL);
219f9b95980Sapatard@mandriva.com 		value &= ~(KIRKWOOD_PLAYCTL_I2S_EN | KIRKWOOD_PLAYCTL_SPDIF_EN);
220f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_PLAYCTL);
221f9b95980Sapatard@mandriva.com 		break;
222f9b95980Sapatard@mandriva.com 
223f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
224f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_SUSPEND:
225f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_PLAYCTL);
226*b424ec95Sarnaud.patard@rtp-net.org 		value |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE;
227f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_PLAYCTL);
228f9b95980Sapatard@mandriva.com 		break;
229f9b95980Sapatard@mandriva.com 
230f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_RESUME:
231f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
232f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_PLAYCTL);
233*b424ec95Sarnaud.patard@rtp-net.org 		value &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE);
234f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_PLAYCTL);
235f9b95980Sapatard@mandriva.com 		break;
236f9b95980Sapatard@mandriva.com 
237f9b95980Sapatard@mandriva.com 	default:
238f9b95980Sapatard@mandriva.com 		return -EINVAL;
239f9b95980Sapatard@mandriva.com 	}
240f9b95980Sapatard@mandriva.com 
241f9b95980Sapatard@mandriva.com 	return 0;
242f9b95980Sapatard@mandriva.com }
243f9b95980Sapatard@mandriva.com 
244f9b95980Sapatard@mandriva.com static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
245f9b95980Sapatard@mandriva.com 				int cmd, struct snd_soc_dai *dai)
246f9b95980Sapatard@mandriva.com {
247f9b95980Sapatard@mandriva.com 	unsigned long value;
248f9b95980Sapatard@mandriva.com 
249f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_RECCTL);
250f9b95980Sapatard@mandriva.com 
251f9b95980Sapatard@mandriva.com 	switch (cmd) {
252f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_START:
253f9b95980Sapatard@mandriva.com 		/* stop audio, enable interrupts */
254f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
255f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_RECCTL_PAUSE;
256f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
257f9b95980Sapatard@mandriva.com 
258f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
259f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
260f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
261f9b95980Sapatard@mandriva.com 
262f9b95980Sapatard@mandriva.com 		/* configure audio & enable i2s record */
263f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
264f9b95980Sapatard@mandriva.com 		value &= ~KIRKWOOD_RECCTL_BURST_MASK;
265f9b95980Sapatard@mandriva.com 		value &= ~KIRKWOOD_RECCTL_MONO;
266*b424ec95Sarnaud.patard@rtp-net.org 		value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE
267*b424ec95Sarnaud.patard@rtp-net.org 			| KIRKWOOD_RECCTL_SPDIF_EN);
268f9b95980Sapatard@mandriva.com 
269f9b95980Sapatard@mandriva.com 		if (priv->burst == 32)
270f9b95980Sapatard@mandriva.com 			value |= KIRKWOOD_RECCTL_BURST_32;
271f9b95980Sapatard@mandriva.com 		else
272f9b95980Sapatard@mandriva.com 			value |= KIRKWOOD_RECCTL_BURST_128;
273f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_RECCTL_I2S_EN;
274f9b95980Sapatard@mandriva.com 
275f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
276f9b95980Sapatard@mandriva.com 		break;
277f9b95980Sapatard@mandriva.com 
278f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_STOP:
279f9b95980Sapatard@mandriva.com 		/* stop audio, disable interrupts */
280f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
281*b424ec95Sarnaud.patard@rtp-net.org 		value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
282f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
283f9b95980Sapatard@mandriva.com 
284f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
285f9b95980Sapatard@mandriva.com 		value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
286f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
287f9b95980Sapatard@mandriva.com 
288f9b95980Sapatard@mandriva.com 		/* disable all records */
289f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
290f9b95980Sapatard@mandriva.com 		value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
291f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
292f9b95980Sapatard@mandriva.com 		break;
293f9b95980Sapatard@mandriva.com 
294f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
295f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_SUSPEND:
296f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
297*b424ec95Sarnaud.patard@rtp-net.org 		value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
298f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
299f9b95980Sapatard@mandriva.com 		break;
300f9b95980Sapatard@mandriva.com 
301f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_RESUME:
302f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
303f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
304*b424ec95Sarnaud.patard@rtp-net.org 		value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
305f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
306f9b95980Sapatard@mandriva.com 		break;
307f9b95980Sapatard@mandriva.com 
308f9b95980Sapatard@mandriva.com 	default:
309f9b95980Sapatard@mandriva.com 		return -EINVAL;
310f9b95980Sapatard@mandriva.com 	}
311f9b95980Sapatard@mandriva.com 
312f9b95980Sapatard@mandriva.com 	return 0;
313f9b95980Sapatard@mandriva.com }
314f9b95980Sapatard@mandriva.com 
315f9b95980Sapatard@mandriva.com static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
316f9b95980Sapatard@mandriva.com 			       struct snd_soc_dai *dai)
317f9b95980Sapatard@mandriva.com {
318f9b95980Sapatard@mandriva.com 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
319f9b95980Sapatard@mandriva.com 		return kirkwood_i2s_play_trigger(substream, cmd, dai);
320f9b95980Sapatard@mandriva.com 	else
321f9b95980Sapatard@mandriva.com 		return kirkwood_i2s_rec_trigger(substream, cmd, dai);
322f9b95980Sapatard@mandriva.com 
323f9b95980Sapatard@mandriva.com 	return 0;
324f9b95980Sapatard@mandriva.com }
325f9b95980Sapatard@mandriva.com 
326f9b95980Sapatard@mandriva.com static int kirkwood_i2s_probe(struct platform_device *pdev,
327f9b95980Sapatard@mandriva.com 			     struct snd_soc_dai *dai)
328f9b95980Sapatard@mandriva.com {
329f9b95980Sapatard@mandriva.com 	unsigned long value;
330f9b95980Sapatard@mandriva.com 	unsigned int reg_data;
331f9b95980Sapatard@mandriva.com 
332f9b95980Sapatard@mandriva.com 	/* put system in a "safe" state : */
333f9b95980Sapatard@mandriva.com 	/* disable audio interrupts */
334f9b95980Sapatard@mandriva.com 	writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
335f9b95980Sapatard@mandriva.com 	writel(0, priv->io + KIRKWOOD_INT_MASK);
336f9b95980Sapatard@mandriva.com 
337f9b95980Sapatard@mandriva.com 	reg_data = readl(priv->io + 0x1200);
338f9b95980Sapatard@mandriva.com 	reg_data &= (~(0x333FF8));
339f9b95980Sapatard@mandriva.com 	reg_data |= 0x111D18;
340f9b95980Sapatard@mandriva.com 	writel(reg_data, priv->io + 0x1200);
341f9b95980Sapatard@mandriva.com 
342f9b95980Sapatard@mandriva.com 	msleep(500);
343f9b95980Sapatard@mandriva.com 
344f9b95980Sapatard@mandriva.com 	reg_data = readl(priv->io + 0x1200);
345f9b95980Sapatard@mandriva.com 	reg_data &= (~(0x333FF8));
346f9b95980Sapatard@mandriva.com 	reg_data |= 0x111D18;
347f9b95980Sapatard@mandriva.com 	writel(reg_data, priv->io + 0x1200);
348f9b95980Sapatard@mandriva.com 
349f9b95980Sapatard@mandriva.com 	/* disable playback/record */
350f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_PLAYCTL);
351f9b95980Sapatard@mandriva.com 	value &= ~(KIRKWOOD_PLAYCTL_I2S_EN|KIRKWOOD_PLAYCTL_SPDIF_EN);
352f9b95980Sapatard@mandriva.com 	writel(value, priv->io + KIRKWOOD_PLAYCTL);
353f9b95980Sapatard@mandriva.com 
354f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_RECCTL);
355f9b95980Sapatard@mandriva.com 	value &= ~(KIRKWOOD_RECCTL_I2S_EN | KIRKWOOD_RECCTL_SPDIF_EN);
356f9b95980Sapatard@mandriva.com 	writel(value, priv->io + KIRKWOOD_RECCTL);
357f9b95980Sapatard@mandriva.com 
358f9b95980Sapatard@mandriva.com 	return 0;
359f9b95980Sapatard@mandriva.com 
360f9b95980Sapatard@mandriva.com }
361f9b95980Sapatard@mandriva.com 
362f9b95980Sapatard@mandriva.com static void kirkwood_i2s_remove(struct platform_device *pdev,
363f9b95980Sapatard@mandriva.com 				struct snd_soc_dai *dai)
364f9b95980Sapatard@mandriva.com {
365f9b95980Sapatard@mandriva.com }
366f9b95980Sapatard@mandriva.com 
367f9b95980Sapatard@mandriva.com static struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
368f9b95980Sapatard@mandriva.com 	.trigger	= kirkwood_i2s_trigger,
369f9b95980Sapatard@mandriva.com 	.hw_params      = kirkwood_i2s_hw_params,
370f9b95980Sapatard@mandriva.com 	.set_fmt        = kirkwood_i2s_set_fmt,
371f9b95980Sapatard@mandriva.com };
372f9b95980Sapatard@mandriva.com 
373f9b95980Sapatard@mandriva.com 
374f9b95980Sapatard@mandriva.com struct snd_soc_dai kirkwood_i2s_dai = {
375f9b95980Sapatard@mandriva.com 	.name = DRV_NAME,
376f9b95980Sapatard@mandriva.com 	.id = 0,
377f9b95980Sapatard@mandriva.com 	.probe = kirkwood_i2s_probe,
378f9b95980Sapatard@mandriva.com 	.remove = kirkwood_i2s_remove,
379f9b95980Sapatard@mandriva.com 	.playback = {
380f9b95980Sapatard@mandriva.com 		.channels_min = 1,
381f9b95980Sapatard@mandriva.com 		.channels_max = 2,
382f9b95980Sapatard@mandriva.com 		.rates = KIRKWOOD_I2S_RATES,
383f9b95980Sapatard@mandriva.com 		.formats = KIRKWOOD_I2S_FORMATS,},
384f9b95980Sapatard@mandriva.com 	.capture = {
385f9b95980Sapatard@mandriva.com 		.channels_min = 1,
386f9b95980Sapatard@mandriva.com 		.channels_max = 2,
387f9b95980Sapatard@mandriva.com 		.rates = KIRKWOOD_I2S_RATES,
388f9b95980Sapatard@mandriva.com 		.formats = KIRKWOOD_I2S_FORMATS,},
389f9b95980Sapatard@mandriva.com 	.ops = &kirkwood_i2s_dai_ops,
390f9b95980Sapatard@mandriva.com };
391f9b95980Sapatard@mandriva.com EXPORT_SYMBOL_GPL(kirkwood_i2s_dai);
392f9b95980Sapatard@mandriva.com 
393f9b95980Sapatard@mandriva.com static __devinit int kirkwood_i2s_dev_probe(struct platform_device *pdev)
394f9b95980Sapatard@mandriva.com {
395f9b95980Sapatard@mandriva.com 	struct resource *mem;
396f9b95980Sapatard@mandriva.com 	struct kirkwood_asoc_platform_data *data =
397f9b95980Sapatard@mandriva.com 		pdev->dev.platform_data;
398f9b95980Sapatard@mandriva.com 	int err;
399f9b95980Sapatard@mandriva.com 
400f9b95980Sapatard@mandriva.com 	priv = kzalloc(sizeof(struct kirkwood_dma_data), GFP_KERNEL);
401f9b95980Sapatard@mandriva.com 	if (!priv) {
402f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "allocation failed\n");
403f9b95980Sapatard@mandriva.com 		err = -ENOMEM;
404f9b95980Sapatard@mandriva.com 		goto error;
405f9b95980Sapatard@mandriva.com 	}
406f9b95980Sapatard@mandriva.com 
407f9b95980Sapatard@mandriva.com 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
408f9b95980Sapatard@mandriva.com 	if (!mem) {
409f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "platform_get_resource failed\n");
410f9b95980Sapatard@mandriva.com 		err = -ENXIO;
411f9b95980Sapatard@mandriva.com 		goto err_alloc;
412f9b95980Sapatard@mandriva.com 	}
413f9b95980Sapatard@mandriva.com 
414f9b95980Sapatard@mandriva.com 	priv->mem = request_mem_region(mem->start, SZ_16K, DRV_NAME);
415f9b95980Sapatard@mandriva.com 	if (!priv->mem) {
416f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "request_mem_region failed\n");
417f9b95980Sapatard@mandriva.com 		err = -EBUSY;
418f9b95980Sapatard@mandriva.com 		goto error;
419f9b95980Sapatard@mandriva.com 	}
420f9b95980Sapatard@mandriva.com 
421f9b95980Sapatard@mandriva.com 	priv->io = ioremap(priv->mem->start, SZ_16K);
422f9b95980Sapatard@mandriva.com 	if (!priv->io) {
423f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "ioremap failed\n");
424f9b95980Sapatard@mandriva.com 		err = -ENOMEM;
425f9b95980Sapatard@mandriva.com 		goto err_iomem;
426f9b95980Sapatard@mandriva.com 	}
427f9b95980Sapatard@mandriva.com 
428f9b95980Sapatard@mandriva.com 	priv->irq = platform_get_irq(pdev, 0);
429f9b95980Sapatard@mandriva.com 	if (priv->irq <= 0) {
430f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "platform_get_irq failed\n");
431f9b95980Sapatard@mandriva.com 		err = -ENXIO;
432f9b95980Sapatard@mandriva.com 		goto err_ioremap;
433f9b95980Sapatard@mandriva.com 	}
434f9b95980Sapatard@mandriva.com 
435f9b95980Sapatard@mandriva.com 	if (!data || !data->dram) {
436f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "no platform data ?!\n");
437f9b95980Sapatard@mandriva.com 		err = -EINVAL;
438f9b95980Sapatard@mandriva.com 		goto err_ioremap;
439f9b95980Sapatard@mandriva.com 	}
440f9b95980Sapatard@mandriva.com 
441f9b95980Sapatard@mandriva.com 	priv->dram = data->dram;
442f9b95980Sapatard@mandriva.com 	priv->burst = data->burst;
443f9b95980Sapatard@mandriva.com 
444f9b95980Sapatard@mandriva.com 	kirkwood_i2s_dai.capture.dma_data = priv;
445f9b95980Sapatard@mandriva.com 	kirkwood_i2s_dai.playback.dma_data = priv;
446f9b95980Sapatard@mandriva.com 
447f9b95980Sapatard@mandriva.com 	return snd_soc_register_dai(&kirkwood_i2s_dai);
448f9b95980Sapatard@mandriva.com 
449f9b95980Sapatard@mandriva.com err_ioremap:
450f9b95980Sapatard@mandriva.com 	iounmap(priv->io);
451f9b95980Sapatard@mandriva.com err_iomem:
452f9b95980Sapatard@mandriva.com 	release_mem_region(priv->mem->start, SZ_16K);
453f9b95980Sapatard@mandriva.com err_alloc:
454f9b95980Sapatard@mandriva.com 	kfree(priv);
455f9b95980Sapatard@mandriva.com error:
456f9b95980Sapatard@mandriva.com 	return err;
457f9b95980Sapatard@mandriva.com }
458f9b95980Sapatard@mandriva.com 
459f9b95980Sapatard@mandriva.com static __devexit int kirkwood_i2s_dev_remove(struct platform_device *pdev)
460f9b95980Sapatard@mandriva.com {
461f9b95980Sapatard@mandriva.com 	if (priv) {
462f9b95980Sapatard@mandriva.com 		iounmap(priv->io);
463f9b95980Sapatard@mandriva.com 		release_mem_region(priv->mem->start, SZ_16K);
464f9b95980Sapatard@mandriva.com 		kfree(priv);
465f9b95980Sapatard@mandriva.com 	}
466f9b95980Sapatard@mandriva.com 	snd_soc_unregister_dai(&kirkwood_i2s_dai);
467f9b95980Sapatard@mandriva.com 	return 0;
468f9b95980Sapatard@mandriva.com }
469f9b95980Sapatard@mandriva.com 
470f9b95980Sapatard@mandriva.com static struct platform_driver kirkwood_i2s_driver = {
471f9b95980Sapatard@mandriva.com 	.probe  = kirkwood_i2s_dev_probe,
472f9b95980Sapatard@mandriva.com 	.remove = kirkwood_i2s_dev_remove,
473f9b95980Sapatard@mandriva.com 	.driver = {
474f9b95980Sapatard@mandriva.com 		.name = DRV_NAME,
475f9b95980Sapatard@mandriva.com 		.owner = THIS_MODULE,
476f9b95980Sapatard@mandriva.com 	},
477f9b95980Sapatard@mandriva.com };
478f9b95980Sapatard@mandriva.com 
479f9b95980Sapatard@mandriva.com static int __init kirkwood_i2s_init(void)
480f9b95980Sapatard@mandriva.com {
481f9b95980Sapatard@mandriva.com 	return platform_driver_register(&kirkwood_i2s_driver);
482f9b95980Sapatard@mandriva.com }
483f9b95980Sapatard@mandriva.com module_init(kirkwood_i2s_init);
484f9b95980Sapatard@mandriva.com 
485f9b95980Sapatard@mandriva.com static void __exit kirkwood_i2s_exit(void)
486f9b95980Sapatard@mandriva.com {
487f9b95980Sapatard@mandriva.com 	platform_driver_unregister(&kirkwood_i2s_driver);
488f9b95980Sapatard@mandriva.com }
489f9b95980Sapatard@mandriva.com module_exit(kirkwood_i2s_exit);
490f9b95980Sapatard@mandriva.com 
491f9b95980Sapatard@mandriva.com /* Module information */
492f9b95980Sapatard@mandriva.com MODULE_AUTHOR("Arnaud Patard, <apatard@mandriva.com>");
493f9b95980Sapatard@mandriva.com MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
494f9b95980Sapatard@mandriva.com MODULE_LICENSE("GPL");
495f9b95980Sapatard@mandriva.com MODULE_ALIAS("platform:kirkwood-i2s");
496