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