xref: /linux/sound/soc/kirkwood/kirkwood-i2s.c (revision 4d2097e51795b760c392d3fbc6ca6b6f77c83419)
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>
25eb632318SJean-Francois Moine #include <linux/of.h>
26eb632318SJean-Francois Moine 
27f9b95980Sapatard@mandriva.com #include "kirkwood.h"
28f9b95980Sapatard@mandriva.com 
2964ddf1f8SRussell King #define DRV_NAME	"mvebu-audio"
30f9b95980Sapatard@mandriva.com 
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 
361c195ddbSJean-Francois Moine #define KIRKWOOD_SPDIF_FORMATS \
371c195ddbSJean-Francois Moine 	(SNDRV_PCM_FMTBIT_S16_LE | \
381c195ddbSJean-Francois Moine 	 SNDRV_PCM_FMTBIT_S24_LE)
391c195ddbSJean-Francois Moine 
40f9b95980Sapatard@mandriva.com static int kirkwood_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
41f9b95980Sapatard@mandriva.com 		unsigned int fmt)
42f9b95980Sapatard@mandriva.com {
43f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(cpu_dai);
44f9b95980Sapatard@mandriva.com 	unsigned long mask;
45f9b95980Sapatard@mandriva.com 	unsigned long value;
46f9b95980Sapatard@mandriva.com 
47f9b95980Sapatard@mandriva.com 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
48f9b95980Sapatard@mandriva.com 	case SND_SOC_DAIFMT_RIGHT_J:
49f9b95980Sapatard@mandriva.com 		mask = KIRKWOOD_I2S_CTL_RJ;
50f9b95980Sapatard@mandriva.com 		break;
51f9b95980Sapatard@mandriva.com 	case SND_SOC_DAIFMT_LEFT_J:
52f9b95980Sapatard@mandriva.com 		mask = KIRKWOOD_I2S_CTL_LJ;
53f9b95980Sapatard@mandriva.com 		break;
54f9b95980Sapatard@mandriva.com 	case SND_SOC_DAIFMT_I2S:
55f9b95980Sapatard@mandriva.com 		mask = KIRKWOOD_I2S_CTL_I2S;
56f9b95980Sapatard@mandriva.com 		break;
57f9b95980Sapatard@mandriva.com 	default:
58f9b95980Sapatard@mandriva.com 		return -EINVAL;
59f9b95980Sapatard@mandriva.com 	}
60f9b95980Sapatard@mandriva.com 
61f9b95980Sapatard@mandriva.com 	/*
62f9b95980Sapatard@mandriva.com 	 * Set same format for playback and record
63f9b95980Sapatard@mandriva.com 	 * This avoids some troubles.
64f9b95980Sapatard@mandriva.com 	 */
65f9b95980Sapatard@mandriva.com 	value = readl(priv->io+KIRKWOOD_I2S_PLAYCTL);
66f9b95980Sapatard@mandriva.com 	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
67f9b95980Sapatard@mandriva.com 	value |= mask;
68f9b95980Sapatard@mandriva.com 	writel(value, priv->io+KIRKWOOD_I2S_PLAYCTL);
69f9b95980Sapatard@mandriva.com 
70f9b95980Sapatard@mandriva.com 	value = readl(priv->io+KIRKWOOD_I2S_RECCTL);
71f9b95980Sapatard@mandriva.com 	value &= ~KIRKWOOD_I2S_CTL_JUST_MASK;
72f9b95980Sapatard@mandriva.com 	value |= mask;
73f9b95980Sapatard@mandriva.com 	writel(value, priv->io+KIRKWOOD_I2S_RECCTL);
74f9b95980Sapatard@mandriva.com 
75f9b95980Sapatard@mandriva.com 	return 0;
76f9b95980Sapatard@mandriva.com }
77f9b95980Sapatard@mandriva.com 
78f9b95980Sapatard@mandriva.com static inline void kirkwood_set_dco(void __iomem *io, unsigned long rate)
79f9b95980Sapatard@mandriva.com {
80f9b95980Sapatard@mandriva.com 	unsigned long value;
81f9b95980Sapatard@mandriva.com 
82f9b95980Sapatard@mandriva.com 	value = KIRKWOOD_DCO_CTL_OFFSET_0;
83f9b95980Sapatard@mandriva.com 	switch (rate) {
84f9b95980Sapatard@mandriva.com 	default:
85f9b95980Sapatard@mandriva.com 	case 44100:
86f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_DCO_CTL_FREQ_11;
87f9b95980Sapatard@mandriva.com 		break;
88f9b95980Sapatard@mandriva.com 	case 48000:
89f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_DCO_CTL_FREQ_12;
90f9b95980Sapatard@mandriva.com 		break;
91f9b95980Sapatard@mandriva.com 	case 96000:
92f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_DCO_CTL_FREQ_24;
93f9b95980Sapatard@mandriva.com 		break;
94f9b95980Sapatard@mandriva.com 	}
95f9b95980Sapatard@mandriva.com 	writel(value, io + KIRKWOOD_DCO_CTL);
96f9b95980Sapatard@mandriva.com 
97f9b95980Sapatard@mandriva.com 	/* wait for dco locked */
98f9b95980Sapatard@mandriva.com 	do {
99f9b95980Sapatard@mandriva.com 		cpu_relax();
100f9b95980Sapatard@mandriva.com 		value = readl(io + KIRKWOOD_DCO_SPCR_STATUS);
1012424d458SRussell King 		value &= KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK;
102f9b95980Sapatard@mandriva.com 	} while (value == 0);
103f9b95980Sapatard@mandriva.com }
104f9b95980Sapatard@mandriva.com 
105363589bfSRussell King static void kirkwood_set_rate(struct snd_soc_dai *dai,
106363589bfSRussell King 	struct kirkwood_dma_data *priv, unsigned long rate)
107363589bfSRussell King {
108363589bfSRussell King 	uint32_t clks_ctrl;
109363589bfSRussell King 
1101f1b6579SJean-Francois Moine 	if (IS_ERR(priv->extclk)) {
1118a537f85SJean-Francois Moine 		/* use internal dco for the supported rates
1128a537f85SJean-Francois Moine 		 * defined in kirkwood_i2s_dai */
113363589bfSRussell King 		dev_dbg(dai->dev, "%s: dco set rate = %lu\n",
114363589bfSRussell King 			__func__, rate);
115363589bfSRussell King 		kirkwood_set_dco(priv->io, rate);
116363589bfSRussell King 
117363589bfSRussell King 		clks_ctrl = KIRKWOOD_MCLK_SOURCE_DCO;
1188a537f85SJean-Francois Moine 	} else {
1198a537f85SJean-Francois Moine 		/* use the external clock for the other rates
1208a537f85SJean-Francois Moine 		 * defined in kirkwood_i2s_dai_extclk */
121363589bfSRussell King 		dev_dbg(dai->dev, "%s: extclk set rate = %lu -> %lu\n",
122363589bfSRussell King 			__func__, rate, 256 * rate);
123363589bfSRussell King 		clk_set_rate(priv->extclk, 256 * rate);
124363589bfSRussell King 
125363589bfSRussell King 		clks_ctrl = KIRKWOOD_MCLK_SOURCE_EXTCLK;
126363589bfSRussell King 	}
127363589bfSRussell King 	writel(clks_ctrl, priv->io + KIRKWOOD_CLOCKS_CTRL);
128363589bfSRussell King }
129363589bfSRussell King 
130f0fba2adSLiam Girdwood static int kirkwood_i2s_startup(struct snd_pcm_substream *substream,
131f0fba2adSLiam Girdwood 		struct snd_soc_dai *dai)
132f0fba2adSLiam Girdwood {
133f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
134f0fba2adSLiam Girdwood 
135f0fba2adSLiam Girdwood 	snd_soc_dai_set_dma_data(dai, substream, priv);
136f0fba2adSLiam Girdwood 	return 0;
137f0fba2adSLiam Girdwood }
138f0fba2adSLiam Girdwood 
139f9b95980Sapatard@mandriva.com static int kirkwood_i2s_hw_params(struct snd_pcm_substream *substream,
140f9b95980Sapatard@mandriva.com 				 struct snd_pcm_hw_params *params,
141f9b95980Sapatard@mandriva.com 				 struct snd_soc_dai *dai)
142f9b95980Sapatard@mandriva.com {
143f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
144d8d11ba5SRussell King 	uint32_t ctl_play, ctl_rec;
145d8d11ba5SRussell King 	unsigned int i2s_reg;
146d8d11ba5SRussell King 	unsigned long i2s_value;
147f9b95980Sapatard@mandriva.com 
148f9b95980Sapatard@mandriva.com 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
149f9b95980Sapatard@mandriva.com 		i2s_reg = KIRKWOOD_I2S_PLAYCTL;
150f9b95980Sapatard@mandriva.com 	} else {
151f9b95980Sapatard@mandriva.com 		i2s_reg = KIRKWOOD_I2S_RECCTL;
152f9b95980Sapatard@mandriva.com 	}
153f9b95980Sapatard@mandriva.com 
154363589bfSRussell King 	kirkwood_set_rate(dai, priv, params_rate(params));
155f9b95980Sapatard@mandriva.com 
156f9b95980Sapatard@mandriva.com 	i2s_value = readl(priv->io+i2s_reg);
157f9b95980Sapatard@mandriva.com 	i2s_value &= ~KIRKWOOD_I2S_CTL_SIZE_MASK;
158f9b95980Sapatard@mandriva.com 
159f9b95980Sapatard@mandriva.com 	/*
160f9b95980Sapatard@mandriva.com 	 * Size settings in play/rec i2s control regs and play/rec control
161f9b95980Sapatard@mandriva.com 	 * regs must be the same.
162f9b95980Sapatard@mandriva.com 	 */
163f9b95980Sapatard@mandriva.com 	switch (params_format(params)) {
164f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S16_LE:
165f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_16;
166d8d11ba5SRussell King 		ctl_play = KIRKWOOD_PLAYCTL_SIZE_16_C |
16775b9b65eSJean-Francois Moine 			   KIRKWOOD_PLAYCTL_I2S_EN |
16875b9b65eSJean-Francois Moine 			   KIRKWOOD_PLAYCTL_SPDIF_EN;
169d8d11ba5SRussell King 		ctl_rec = KIRKWOOD_RECCTL_SIZE_16_C |
17075b9b65eSJean-Francois Moine 			  KIRKWOOD_RECCTL_I2S_EN |
17175b9b65eSJean-Francois Moine 			  KIRKWOOD_RECCTL_SPDIF_EN;
172f9b95980Sapatard@mandriva.com 		break;
173f9b95980Sapatard@mandriva.com 	/*
174f9b95980Sapatard@mandriva.com 	 * doesn't work... S20_3LE != kirkwood 20bit format ?
175f9b95980Sapatard@mandriva.com 	 *
176f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S20_3LE:
177f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_20;
178d8d11ba5SRussell King 		ctl_play = KIRKWOOD_PLAYCTL_SIZE_20 |
179d8d11ba5SRussell King 			   KIRKWOOD_PLAYCTL_I2S_EN;
180d8d11ba5SRussell King 		ctl_rec = KIRKWOOD_RECCTL_SIZE_20 |
181d8d11ba5SRussell King 			  KIRKWOOD_RECCTL_I2S_EN;
182f9b95980Sapatard@mandriva.com 		break;
183f9b95980Sapatard@mandriva.com 	*/
184f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S24_LE:
185f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_24;
186d8d11ba5SRussell King 		ctl_play = KIRKWOOD_PLAYCTL_SIZE_24 |
18775b9b65eSJean-Francois Moine 			   KIRKWOOD_PLAYCTL_I2S_EN |
18875b9b65eSJean-Francois Moine 			   KIRKWOOD_PLAYCTL_SPDIF_EN;
189d8d11ba5SRussell King 		ctl_rec = KIRKWOOD_RECCTL_SIZE_24 |
19075b9b65eSJean-Francois Moine 			  KIRKWOOD_RECCTL_I2S_EN |
19175b9b65eSJean-Francois Moine 			  KIRKWOOD_RECCTL_SPDIF_EN;
192f9b95980Sapatard@mandriva.com 		break;
193f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_FORMAT_S32_LE:
194f9b95980Sapatard@mandriva.com 		i2s_value |= KIRKWOOD_I2S_CTL_SIZE_32;
195d8d11ba5SRussell King 		ctl_play = KIRKWOOD_PLAYCTL_SIZE_32 |
196d8d11ba5SRussell King 			   KIRKWOOD_PLAYCTL_I2S_EN;
197d8d11ba5SRussell King 		ctl_rec = KIRKWOOD_RECCTL_SIZE_32 |
198d8d11ba5SRussell King 			  KIRKWOOD_RECCTL_I2S_EN;
199f9b95980Sapatard@mandriva.com 		break;
200f9b95980Sapatard@mandriva.com 	default:
201f9b95980Sapatard@mandriva.com 		return -EINVAL;
202f9b95980Sapatard@mandriva.com 	}
203dfe4c936Sarnaud.patard@rtp-net.org 
204dfe4c936Sarnaud.patard@rtp-net.org 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
205dfe4c936Sarnaud.patard@rtp-net.org 		if (params_channels(params) == 1)
206d8d11ba5SRussell King 			ctl_play |= KIRKWOOD_PLAYCTL_MONO_BOTH;
207dfe4c936Sarnaud.patard@rtp-net.org 		else
208d8d11ba5SRussell King 			ctl_play |= KIRKWOOD_PLAYCTL_MONO_OFF;
209d8d11ba5SRussell King 
210d8d11ba5SRussell King 		priv->ctl_play &= ~(KIRKWOOD_PLAYCTL_MONO_MASK |
211db43b16fSRussell King 				    KIRKWOOD_PLAYCTL_ENABLE_MASK |
212d8d11ba5SRussell King 				    KIRKWOOD_PLAYCTL_SIZE_MASK);
213d8d11ba5SRussell King 		priv->ctl_play |= ctl_play;
214d8d11ba5SRussell King 	} else {
21567721906SRussell King 		priv->ctl_rec &= ~(KIRKWOOD_RECCTL_ENABLE_MASK |
21667721906SRussell King 				   KIRKWOOD_RECCTL_SIZE_MASK);
217d8d11ba5SRussell King 		priv->ctl_rec |= ctl_rec;
218dfe4c936Sarnaud.patard@rtp-net.org 	}
219dfe4c936Sarnaud.patard@rtp-net.org 
220f9b95980Sapatard@mandriva.com 	writel(i2s_value, priv->io+i2s_reg);
221f9b95980Sapatard@mandriva.com 
222f9b95980Sapatard@mandriva.com 	return 0;
223f9b95980Sapatard@mandriva.com }
224f9b95980Sapatard@mandriva.com 
2252fbc3821SRussell King static unsigned kirkwood_i2s_play_mute(unsigned ctl)
2262fbc3821SRussell King {
2272fbc3821SRussell King 	if (!(ctl & KIRKWOOD_PLAYCTL_I2S_EN))
2282fbc3821SRussell King 		ctl |= KIRKWOOD_PLAYCTL_I2S_MUTE;
2292fbc3821SRussell King 	if (!(ctl & KIRKWOOD_PLAYCTL_SPDIF_EN))
2302fbc3821SRussell King 		ctl |= KIRKWOOD_PLAYCTL_SPDIF_MUTE;
2312fbc3821SRussell King 	return ctl;
2322fbc3821SRussell King }
2332fbc3821SRussell King 
234f9b95980Sapatard@mandriva.com static int kirkwood_i2s_play_trigger(struct snd_pcm_substream *substream,
235f9b95980Sapatard@mandriva.com 				int cmd, struct snd_soc_dai *dai)
236f9b95980Sapatard@mandriva.com {
237f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
238982b604bSRussell King 	uint32_t ctl, value;
239f9b95980Sapatard@mandriva.com 
240982b604bSRussell King 	ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
241*4d2097e5SRussell King 	if ((ctl & KIRKWOOD_PLAYCTL_ENABLE_MASK) == 0) {
242982b604bSRussell King 		unsigned timeout = 5000;
243f9b95980Sapatard@mandriva.com 		/*
244982b604bSRussell King 		 * The Armada510 spec says that if we enter pause mode, the
245982b604bSRussell King 		 * busy bit must be read back as clear _twice_.  Make sure
246982b604bSRussell King 		 * we respect that otherwise we get DMA underruns.
247f9b95980Sapatard@mandriva.com 		 */
248982b604bSRussell King 		do {
249982b604bSRussell King 			value = ctl;
250982b604bSRussell King 			ctl = readl(priv->io + KIRKWOOD_PLAYCTL);
251982b604bSRussell King 			if (!((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY))
252982b604bSRussell King 				break;
253982b604bSRussell King 			udelay(1);
254982b604bSRussell King 		} while (timeout--);
255982b604bSRussell King 
256982b604bSRussell King 		if ((ctl | value) & KIRKWOOD_PLAYCTL_PLAY_BUSY)
257982b604bSRussell King 			dev_notice(dai->dev, "timed out waiting for busy to deassert: %08x\n",
258982b604bSRussell King 				   ctl);
259982b604bSRussell King 	}
260f9b95980Sapatard@mandriva.com 
2614f6f1478SJean-Francois Moine 	switch (cmd) {
2624f6f1478SJean-Francois Moine 	case SNDRV_PCM_TRIGGER_START:
2634f6f1478SJean-Francois Moine 		/* configure */
2644f6f1478SJean-Francois Moine 		ctl = priv->ctl_play;
26575b9b65eSJean-Francois Moine 		if (dai->id == 0)
26675b9b65eSJean-Francois Moine 			ctl &= ~KIRKWOOD_PLAYCTL_SPDIF_EN;	/* i2s */
26775b9b65eSJean-Francois Moine 		else
26875b9b65eSJean-Francois Moine 			ctl &= ~KIRKWOOD_PLAYCTL_I2S_EN;	/* spdif */
2692fbc3821SRussell King 		ctl = kirkwood_i2s_play_mute(ctl);
270db43b16fSRussell King 		value = ctl & ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
271d8d11ba5SRussell King 		writel(value, priv->io + KIRKWOOD_PLAYCTL);
272d8d11ba5SRussell King 
273d8d11ba5SRussell King 		/* enable interrupts */
274f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
275f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_INT_CAUSE_PLAY_BYTES;
276f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
277f9b95980Sapatard@mandriva.com 
278d8d11ba5SRussell King 		/* enable playback */
279982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
280f9b95980Sapatard@mandriva.com 		break;
281f9b95980Sapatard@mandriva.com 
282f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_STOP:
283f9b95980Sapatard@mandriva.com 		/* stop audio, disable interrupts */
28475b9b65eSJean-Francois Moine 		ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
28575b9b65eSJean-Francois Moine 				KIRKWOOD_PLAYCTL_SPDIF_MUTE;
286982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
287f9b95980Sapatard@mandriva.com 
288f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
289f9b95980Sapatard@mandriva.com 		value &= ~KIRKWOOD_INT_CAUSE_PLAY_BYTES;
290f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
291f9b95980Sapatard@mandriva.com 
292f9b95980Sapatard@mandriva.com 		/* disable all playbacks */
293db43b16fSRussell King 		ctl &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
294982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
295f9b95980Sapatard@mandriva.com 		break;
296f9b95980Sapatard@mandriva.com 
297f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
298f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_SUSPEND:
29975b9b65eSJean-Francois Moine 		ctl |= KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
30075b9b65eSJean-Francois Moine 				KIRKWOOD_PLAYCTL_SPDIF_MUTE;
301982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
302f9b95980Sapatard@mandriva.com 		break;
303f9b95980Sapatard@mandriva.com 
304f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_RESUME:
305f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
30675b9b65eSJean-Francois Moine 		ctl &= ~(KIRKWOOD_PLAYCTL_PAUSE | KIRKWOOD_PLAYCTL_I2S_MUTE |
30775b9b65eSJean-Francois Moine 				KIRKWOOD_PLAYCTL_SPDIF_MUTE);
3082fbc3821SRussell King 		ctl = kirkwood_i2s_play_mute(ctl);
309982b604bSRussell King 		writel(ctl, priv->io + KIRKWOOD_PLAYCTL);
310f9b95980Sapatard@mandriva.com 		break;
311f9b95980Sapatard@mandriva.com 
312f9b95980Sapatard@mandriva.com 	default:
313f9b95980Sapatard@mandriva.com 		return -EINVAL;
314f9b95980Sapatard@mandriva.com 	}
315f9b95980Sapatard@mandriva.com 
316f9b95980Sapatard@mandriva.com 	return 0;
317f9b95980Sapatard@mandriva.com }
318f9b95980Sapatard@mandriva.com 
319f9b95980Sapatard@mandriva.com static int kirkwood_i2s_rec_trigger(struct snd_pcm_substream *substream,
320f9b95980Sapatard@mandriva.com 				int cmd, struct snd_soc_dai *dai)
321f9b95980Sapatard@mandriva.com {
322f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = snd_soc_dai_get_drvdata(dai);
323d8d11ba5SRussell King 	uint32_t ctl, value;
324f9b95980Sapatard@mandriva.com 
325f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_RECCTL);
326f9b95980Sapatard@mandriva.com 
327f9b95980Sapatard@mandriva.com 	switch (cmd) {
328f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_START:
329d8d11ba5SRussell King 		/* configure */
330d8d11ba5SRussell King 		ctl = priv->ctl_rec;
33175b9b65eSJean-Francois Moine 		if (dai->id == 0)
33275b9b65eSJean-Francois Moine 			ctl &= ~KIRKWOOD_RECCTL_SPDIF_EN;	/* i2s */
33375b9b65eSJean-Francois Moine 		else
33475b9b65eSJean-Francois Moine 			ctl &= ~KIRKWOOD_RECCTL_I2S_EN;		/* spdif */
33575b9b65eSJean-Francois Moine 
33652b896cfSRussell King 		value = ctl & ~KIRKWOOD_RECCTL_ENABLE_MASK;
337d8d11ba5SRussell King 		writel(value, priv->io + KIRKWOOD_RECCTL);
338d8d11ba5SRussell King 
339d8d11ba5SRussell King 		/* enable interrupts */
340f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
341f9b95980Sapatard@mandriva.com 		value |= KIRKWOOD_INT_CAUSE_REC_BYTES;
342f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
343f9b95980Sapatard@mandriva.com 
344d8d11ba5SRussell King 		/* enable record */
345d8d11ba5SRussell King 		writel(ctl, priv->io + KIRKWOOD_RECCTL);
346f9b95980Sapatard@mandriva.com 		break;
347f9b95980Sapatard@mandriva.com 
348f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_STOP:
349f9b95980Sapatard@mandriva.com 		/* stop audio, disable interrupts */
350f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
351b424ec95Sarnaud.patard@rtp-net.org 		value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
352f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
353f9b95980Sapatard@mandriva.com 
354f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_INT_MASK);
355f9b95980Sapatard@mandriva.com 		value &= ~KIRKWOOD_INT_CAUSE_REC_BYTES;
356f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_INT_MASK);
357f9b95980Sapatard@mandriva.com 
358f9b95980Sapatard@mandriva.com 		/* disable all records */
359f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
36052b896cfSRussell King 		value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
361f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
362f9b95980Sapatard@mandriva.com 		break;
363f9b95980Sapatard@mandriva.com 
364f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
365f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_SUSPEND:
366f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
367b424ec95Sarnaud.patard@rtp-net.org 		value |= KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE;
368f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
369f9b95980Sapatard@mandriva.com 		break;
370f9b95980Sapatard@mandriva.com 
371f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_RESUME:
372f9b95980Sapatard@mandriva.com 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
373f9b95980Sapatard@mandriva.com 		value = readl(priv->io + KIRKWOOD_RECCTL);
374b424ec95Sarnaud.patard@rtp-net.org 		value &= ~(KIRKWOOD_RECCTL_PAUSE | KIRKWOOD_RECCTL_MUTE);
375f9b95980Sapatard@mandriva.com 		writel(value, priv->io + KIRKWOOD_RECCTL);
376f9b95980Sapatard@mandriva.com 		break;
377f9b95980Sapatard@mandriva.com 
378f9b95980Sapatard@mandriva.com 	default:
379f9b95980Sapatard@mandriva.com 		return -EINVAL;
380f9b95980Sapatard@mandriva.com 	}
381f9b95980Sapatard@mandriva.com 
382f9b95980Sapatard@mandriva.com 	return 0;
383f9b95980Sapatard@mandriva.com }
384f9b95980Sapatard@mandriva.com 
385f9b95980Sapatard@mandriva.com static int kirkwood_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
386f9b95980Sapatard@mandriva.com 			       struct snd_soc_dai *dai)
387f9b95980Sapatard@mandriva.com {
388f9b95980Sapatard@mandriva.com 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
389f9b95980Sapatard@mandriva.com 		return kirkwood_i2s_play_trigger(substream, cmd, dai);
390f9b95980Sapatard@mandriva.com 	else
391f9b95980Sapatard@mandriva.com 		return kirkwood_i2s_rec_trigger(substream, cmd, dai);
392f9b95980Sapatard@mandriva.com 
393f9b95980Sapatard@mandriva.com 	return 0;
394f9b95980Sapatard@mandriva.com }
395f9b95980Sapatard@mandriva.com 
39675b9b65eSJean-Francois Moine static int kirkwood_i2s_init(struct kirkwood_dma_data *priv)
397f9b95980Sapatard@mandriva.com {
398f9b95980Sapatard@mandriva.com 	unsigned long value;
399f9b95980Sapatard@mandriva.com 	unsigned int reg_data;
400f9b95980Sapatard@mandriva.com 
401f9b95980Sapatard@mandriva.com 	/* put system in a "safe" state : */
402f9b95980Sapatard@mandriva.com 	/* disable audio interrupts */
403f9b95980Sapatard@mandriva.com 	writel(0xffffffff, priv->io + KIRKWOOD_INT_CAUSE);
404f9b95980Sapatard@mandriva.com 	writel(0, priv->io + KIRKWOOD_INT_MASK);
405f9b95980Sapatard@mandriva.com 
406f9b95980Sapatard@mandriva.com 	reg_data = readl(priv->io + 0x1200);
407f9b95980Sapatard@mandriva.com 	reg_data &= (~(0x333FF8));
408f9b95980Sapatard@mandriva.com 	reg_data |= 0x111D18;
409f9b95980Sapatard@mandriva.com 	writel(reg_data, priv->io + 0x1200);
410f9b95980Sapatard@mandriva.com 
411f9b95980Sapatard@mandriva.com 	msleep(500);
412f9b95980Sapatard@mandriva.com 
413f9b95980Sapatard@mandriva.com 	reg_data = readl(priv->io + 0x1200);
414f9b95980Sapatard@mandriva.com 	reg_data &= (~(0x333FF8));
415f9b95980Sapatard@mandriva.com 	reg_data |= 0x111D18;
416f9b95980Sapatard@mandriva.com 	writel(reg_data, priv->io + 0x1200);
417f9b95980Sapatard@mandriva.com 
418f9b95980Sapatard@mandriva.com 	/* disable playback/record */
419f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_PLAYCTL);
420db43b16fSRussell King 	value &= ~KIRKWOOD_PLAYCTL_ENABLE_MASK;
421f9b95980Sapatard@mandriva.com 	writel(value, priv->io + KIRKWOOD_PLAYCTL);
422f9b95980Sapatard@mandriva.com 
423f9b95980Sapatard@mandriva.com 	value = readl(priv->io + KIRKWOOD_RECCTL);
42452b896cfSRussell King 	value &= ~KIRKWOOD_RECCTL_ENABLE_MASK;
425f9b95980Sapatard@mandriva.com 	writel(value, priv->io + KIRKWOOD_RECCTL);
426f9b95980Sapatard@mandriva.com 
427f9b95980Sapatard@mandriva.com 	return 0;
428f9b95980Sapatard@mandriva.com 
429f9b95980Sapatard@mandriva.com }
430f9b95980Sapatard@mandriva.com 
43185e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops kirkwood_i2s_dai_ops = {
432f0fba2adSLiam Girdwood 	.startup	= kirkwood_i2s_startup,
433f9b95980Sapatard@mandriva.com 	.trigger	= kirkwood_i2s_trigger,
434f9b95980Sapatard@mandriva.com 	.hw_params      = kirkwood_i2s_hw_params,
435f9b95980Sapatard@mandriva.com 	.set_fmt        = kirkwood_i2s_set_fmt,
436f9b95980Sapatard@mandriva.com };
437f9b95980Sapatard@mandriva.com 
43875b9b65eSJean-Francois Moine static struct snd_soc_dai_driver kirkwood_i2s_dai[2] = {
43975b9b65eSJean-Francois Moine     {
44075b9b65eSJean-Francois Moine 	.name = "i2s",
44175b9b65eSJean-Francois Moine 	.id = 0,
442f9b95980Sapatard@mandriva.com 	.playback = {
443f9b95980Sapatard@mandriva.com 		.channels_min = 1,
444f9b95980Sapatard@mandriva.com 		.channels_max = 2,
4459e12cbd9SMark Brown 		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
4469e12cbd9SMark Brown 				SNDRV_PCM_RATE_96000,
447363589bfSRussell King 		.formats = KIRKWOOD_I2S_FORMATS,
448363589bfSRussell King 	},
449f9b95980Sapatard@mandriva.com 	.capture = {
450f9b95980Sapatard@mandriva.com 		.channels_min = 1,
451f9b95980Sapatard@mandriva.com 		.channels_max = 2,
4529e12cbd9SMark Brown 		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
4539e12cbd9SMark Brown 				SNDRV_PCM_RATE_96000,
454363589bfSRussell King 		.formats = KIRKWOOD_I2S_FORMATS,
455363589bfSRussell King 	},
456363589bfSRussell King 	.ops = &kirkwood_i2s_dai_ops,
45775b9b65eSJean-Francois Moine     },
45875b9b65eSJean-Francois Moine     {
45975b9b65eSJean-Francois Moine 	.name = "spdif",
46075b9b65eSJean-Francois Moine 	.id = 1,
46175b9b65eSJean-Francois Moine 	.playback = {
46275b9b65eSJean-Francois Moine 		.channels_min = 1,
46375b9b65eSJean-Francois Moine 		.channels_max = 2,
46475b9b65eSJean-Francois Moine 		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
46575b9b65eSJean-Francois Moine 				SNDRV_PCM_RATE_96000,
4661c195ddbSJean-Francois Moine 		.formats = KIRKWOOD_SPDIF_FORMATS,
46775b9b65eSJean-Francois Moine 	},
46875b9b65eSJean-Francois Moine 	.capture = {
46975b9b65eSJean-Francois Moine 		.channels_min = 1,
47075b9b65eSJean-Francois Moine 		.channels_max = 2,
47175b9b65eSJean-Francois Moine 		.rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
47275b9b65eSJean-Francois Moine 				SNDRV_PCM_RATE_96000,
4731c195ddbSJean-Francois Moine 		.formats = KIRKWOOD_SPDIF_FORMATS,
47475b9b65eSJean-Francois Moine 	},
47575b9b65eSJean-Francois Moine 	.ops = &kirkwood_i2s_dai_ops,
47675b9b65eSJean-Francois Moine     },
477363589bfSRussell King };
478363589bfSRussell King 
47975b9b65eSJean-Francois Moine static struct snd_soc_dai_driver kirkwood_i2s_dai_extclk[2] = {
48075b9b65eSJean-Francois Moine     {
48175b9b65eSJean-Francois Moine 	.name = "i2s",
48275b9b65eSJean-Francois Moine 	.id = 0,
483363589bfSRussell King 	.playback = {
484363589bfSRussell King 		.channels_min = 1,
485363589bfSRussell King 		.channels_max = 2,
48602fc17c1SJean-Francois Moine 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
48702fc17c1SJean-Francois Moine 		.rate_min = 5512,
48802fc17c1SJean-Francois Moine 		.rate_max = 192000,
489363589bfSRussell King 		.formats = KIRKWOOD_I2S_FORMATS,
490363589bfSRussell King 	},
491363589bfSRussell King 	.capture = {
492363589bfSRussell King 		.channels_min = 1,
493363589bfSRussell King 		.channels_max = 2,
49402fc17c1SJean-Francois Moine 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
49502fc17c1SJean-Francois Moine 		.rate_min = 5512,
49602fc17c1SJean-Francois Moine 		.rate_max = 192000,
497363589bfSRussell King 		.formats = KIRKWOOD_I2S_FORMATS,
498363589bfSRussell King 	},
499f9b95980Sapatard@mandriva.com 	.ops = &kirkwood_i2s_dai_ops,
50075b9b65eSJean-Francois Moine     },
50175b9b65eSJean-Francois Moine     {
50275b9b65eSJean-Francois Moine 	.name = "spdif",
50375b9b65eSJean-Francois Moine 	.id = 1,
50475b9b65eSJean-Francois Moine 	.playback = {
50575b9b65eSJean-Francois Moine 		.channels_min = 1,
50675b9b65eSJean-Francois Moine 		.channels_max = 2,
50702fc17c1SJean-Francois Moine 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
50802fc17c1SJean-Francois Moine 		.rate_min = 5512,
50902fc17c1SJean-Francois Moine 		.rate_max = 192000,
5101c195ddbSJean-Francois Moine 		.formats = KIRKWOOD_SPDIF_FORMATS,
51175b9b65eSJean-Francois Moine 	},
51275b9b65eSJean-Francois Moine 	.capture = {
51375b9b65eSJean-Francois Moine 		.channels_min = 1,
51475b9b65eSJean-Francois Moine 		.channels_max = 2,
51502fc17c1SJean-Francois Moine 		.rates = SNDRV_PCM_RATE_CONTINUOUS,
51602fc17c1SJean-Francois Moine 		.rate_min = 5512,
51702fc17c1SJean-Francois Moine 		.rate_max = 192000,
5181c195ddbSJean-Francois Moine 		.formats = KIRKWOOD_SPDIF_FORMATS,
51975b9b65eSJean-Francois Moine 	},
52075b9b65eSJean-Francois Moine 	.ops = &kirkwood_i2s_dai_ops,
52175b9b65eSJean-Francois Moine     },
522f9b95980Sapatard@mandriva.com };
523f9b95980Sapatard@mandriva.com 
52483d85f53SKuninori Morimoto static const struct snd_soc_component_driver kirkwood_i2s_component = {
52583d85f53SKuninori Morimoto 	.name		= DRV_NAME,
52683d85f53SKuninori Morimoto };
52783d85f53SKuninori Morimoto 
52834e15fbdSBill Pemberton static int kirkwood_i2s_dev_probe(struct platform_device *pdev)
529f9b95980Sapatard@mandriva.com {
530363589bfSRussell King 	struct kirkwood_asoc_platform_data *data = pdev->dev.platform_data;
53175b9b65eSJean-Francois Moine 	struct snd_soc_dai_driver *soc_dai = kirkwood_i2s_dai;
532f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv;
533363589bfSRussell King 	struct resource *mem;
534eb632318SJean-Francois Moine 	struct device_node *np = pdev->dev.of_node;
535f9b95980Sapatard@mandriva.com 	int err;
536f9b95980Sapatard@mandriva.com 
537dbc517bfSRussell King 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
538f9b95980Sapatard@mandriva.com 	if (!priv) {
539f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "allocation failed\n");
540dbc517bfSRussell King 		return -ENOMEM;
541f9b95980Sapatard@mandriva.com 	}
542f0fba2adSLiam Girdwood 	dev_set_drvdata(&pdev->dev, priv);
543f9b95980Sapatard@mandriva.com 
544f9b95980Sapatard@mandriva.com 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
545b25b5aa0SThierry Reding 	priv->io = devm_ioremap_resource(&pdev->dev, mem);
546b25b5aa0SThierry Reding 	if (IS_ERR(priv->io))
547b25b5aa0SThierry Reding 		return PTR_ERR(priv->io);
548f9b95980Sapatard@mandriva.com 
549f9b95980Sapatard@mandriva.com 	priv->irq = platform_get_irq(pdev, 0);
550f9b95980Sapatard@mandriva.com 	if (priv->irq <= 0) {
551f9b95980Sapatard@mandriva.com 		dev_err(&pdev->dev, "platform_get_irq failed\n");
552dbc517bfSRussell King 		return -ENXIO;
553f9b95980Sapatard@mandriva.com 	}
554f9b95980Sapatard@mandriva.com 
555eb632318SJean-Francois Moine 	if (np) {
556eb632318SJean-Francois Moine 		priv->burst = 128;		/* might be 32 or 128 */
557eb632318SJean-Francois Moine 	} else if (data) {
558eb632318SJean-Francois Moine 		priv->burst = data->burst;
559eb632318SJean-Francois Moine 	} else {
560eb632318SJean-Francois Moine 		dev_err(&pdev->dev, "no DT nor platform data ?!\n");
561dbc517bfSRussell King 		return -EINVAL;
562f9b95980Sapatard@mandriva.com 	}
563f9b95980Sapatard@mandriva.com 
564eb632318SJean-Francois Moine 	priv->clk = devm_clk_get(&pdev->dev, np ? "internal" : NULL);
565e919c716SAndrew Lunn 	if (IS_ERR(priv->clk)) {
566e919c716SAndrew Lunn 		dev_err(&pdev->dev, "no clock\n");
567dbc517bfSRussell King 		return PTR_ERR(priv->clk);
568e919c716SAndrew Lunn 	}
569dbc517bfSRussell King 
570dbc517bfSRussell King 	err = clk_prepare_enable(priv->clk);
571dbc517bfSRussell King 	if (err < 0)
572dbc517bfSRussell King 		return err;
573e919c716SAndrew Lunn 
5744734dc96SMark Brown 	priv->extclk = devm_clk_get(&pdev->dev, "extclk");
57584aac6c7SJean-Francois Moine 	if (IS_ERR(priv->extclk)) {
57684aac6c7SJean-Francois Moine 		if (PTR_ERR(priv->extclk) == -EPROBE_DEFER)
57784aac6c7SJean-Francois Moine 			return -EPROBE_DEFER;
57884aac6c7SJean-Francois Moine 	} else {
579d8d11ba5SRussell King 		if (priv->extclk == priv->clk) {
580af64d734SRussell King 			devm_clk_put(&pdev->dev, priv->extclk);
581d8d11ba5SRussell King 			priv->extclk = ERR_PTR(-EINVAL);
582d8d11ba5SRussell King 		} else {
583d8d11ba5SRussell King 			dev_info(&pdev->dev, "found external clock\n");
584d8d11ba5SRussell King 			clk_prepare_enable(priv->extclk);
58599d8d3baSJean-Francois Moine 			soc_dai = kirkwood_i2s_dai_extclk;
586d8d11ba5SRussell King 		}
587d8d11ba5SRussell King 	}
588d8d11ba5SRussell King 
589d8d11ba5SRussell King 	/* Some sensible defaults - this reflects the powerup values */
590d8d11ba5SRussell King 	priv->ctl_play = KIRKWOOD_PLAYCTL_SIZE_24;
591d8d11ba5SRussell King 	priv->ctl_rec = KIRKWOOD_RECCTL_SIZE_24;
592d8d11ba5SRussell King 
593d8d11ba5SRussell King 	/* Select the burst size */
594eb632318SJean-Francois Moine 	if (priv->burst == 32) {
595d8d11ba5SRussell King 		priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_32;
596d8d11ba5SRussell King 		priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_32;
597d8d11ba5SRussell King 	} else {
598d8d11ba5SRussell King 		priv->ctl_play |= KIRKWOOD_PLAYCTL_BURST_128;
599d8d11ba5SRussell King 		priv->ctl_rec |= KIRKWOOD_RECCTL_BURST_128;
600d8d11ba5SRussell King 	}
601d8d11ba5SRussell King 
60283d85f53SKuninori Morimoto 	err = snd_soc_register_component(&pdev->dev, &kirkwood_i2s_component,
60375b9b65eSJean-Francois Moine 					 soc_dai, 2);
60464ddf1f8SRussell King 	if (err) {
60583d85f53SKuninori Morimoto 		dev_err(&pdev->dev, "snd_soc_register_component failed\n");
60664ddf1f8SRussell King 		goto err_component;
60764ddf1f8SRussell King 	}
608baffab28SSimon Baatz 
60964ddf1f8SRussell King 	err = snd_soc_register_platform(&pdev->dev, &kirkwood_soc_platform);
61064ddf1f8SRussell King 	if (err) {
61164ddf1f8SRussell King 		dev_err(&pdev->dev, "snd_soc_register_platform failed\n");
61264ddf1f8SRussell King 		goto err_platform;
61364ddf1f8SRussell King 	}
61475b9b65eSJean-Francois Moine 
61575b9b65eSJean-Francois Moine 	kirkwood_i2s_init(priv);
61675b9b65eSJean-Francois Moine 
61764ddf1f8SRussell King 	return 0;
61864ddf1f8SRussell King  err_platform:
61964ddf1f8SRussell King 	snd_soc_unregister_component(&pdev->dev);
62064ddf1f8SRussell King  err_component:
6214734dc96SMark Brown 	if (!IS_ERR(priv->extclk))
622363589bfSRussell King 		clk_disable_unprepare(priv->extclk);
623baffab28SSimon Baatz 	clk_disable_unprepare(priv->clk);
624f9b95980Sapatard@mandriva.com 
625f9b95980Sapatard@mandriva.com 	return err;
626f9b95980Sapatard@mandriva.com }
627f9b95980Sapatard@mandriva.com 
62834e15fbdSBill Pemberton static int kirkwood_i2s_dev_remove(struct platform_device *pdev)
629f9b95980Sapatard@mandriva.com {
630f0fba2adSLiam Girdwood 	struct kirkwood_dma_data *priv = dev_get_drvdata(&pdev->dev);
631f0fba2adSLiam Girdwood 
63264ddf1f8SRussell King 	snd_soc_unregister_platform(&pdev->dev);
63383d85f53SKuninori Morimoto 	snd_soc_unregister_component(&pdev->dev);
634e919c716SAndrew Lunn 
6354734dc96SMark Brown 	if (!IS_ERR(priv->extclk))
636363589bfSRussell King 		clk_disable_unprepare(priv->extclk);
637e919c716SAndrew Lunn 	clk_disable_unprepare(priv->clk);
638f0fba2adSLiam Girdwood 
639f9b95980Sapatard@mandriva.com 	return 0;
640f9b95980Sapatard@mandriva.com }
641f9b95980Sapatard@mandriva.com 
642eb632318SJean-Francois Moine #ifdef CONFIG_OF
643eb632318SJean-Francois Moine static struct of_device_id mvebu_audio_of_match[] = {
644d098b2f0SThomas Petazzoni 	{ .compatible = "marvell,kirkwood-audio" },
645d098b2f0SThomas Petazzoni 	{ .compatible = "marvell,dove-audio" },
6469a0d5113SThomas Petazzoni 	{ .compatible = "marvell,armada370-audio" },
647eb632318SJean-Francois Moine 	{ }
648eb632318SJean-Francois Moine };
649eb632318SJean-Francois Moine MODULE_DEVICE_TABLE(of, mvebu_audio_of_match);
650eb632318SJean-Francois Moine #endif
651eb632318SJean-Francois Moine 
652f9b95980Sapatard@mandriva.com static struct platform_driver kirkwood_i2s_driver = {
653f9b95980Sapatard@mandriva.com 	.probe  = kirkwood_i2s_dev_probe,
65434e15fbdSBill Pemberton 	.remove = kirkwood_i2s_dev_remove,
655f9b95980Sapatard@mandriva.com 	.driver = {
656f9b95980Sapatard@mandriva.com 		.name = DRV_NAME,
657f9b95980Sapatard@mandriva.com 		.owner = THIS_MODULE,
658eb632318SJean-Francois Moine 		.of_match_table = of_match_ptr(mvebu_audio_of_match),
659f9b95980Sapatard@mandriva.com 	},
660f9b95980Sapatard@mandriva.com };
661f9b95980Sapatard@mandriva.com 
66241b10225SAxel Lin module_platform_driver(kirkwood_i2s_driver);
663f9b95980Sapatard@mandriva.com 
664f9b95980Sapatard@mandriva.com /* Module information */
66569737897SArnaud Patard (Rtp) MODULE_AUTHOR("Arnaud Patard, <arnaud.patard@rtp-net.org>");
666f9b95980Sapatard@mandriva.com MODULE_DESCRIPTION("Kirkwood I2S SoC Interface");
667f9b95980Sapatard@mandriva.com MODULE_LICENSE("GPL");
66864ddf1f8SRussell King MODULE_ALIAS("platform:mvebu-audio");
669