xref: /openbmc/linux/sound/soc/pxa/pxa2xx-i2s.c (revision 527541f9)
1 /*
2  * pxa2xx-i2s.c  --  ALSA Soc Audio Layer
3  *
4  * Copyright 2005 Wolfson Microelectronics PLC.
5  * Author: Liam Girdwood
6  *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
7  *
8  *  This program is free software; you can redistribute  it and/or modify it
9  *  under  the terms of  the GNU General  Public License as published by the
10  *  Free Software Foundation;  either version 2 of the  License, or (at your
11  *  option) any later version.
12  *
13  *  Revision history
14  *    12th Aug 2005   Initial version.
15  */
16 
17 #include <linux/init.h>
18 #include <linux/module.h>
19 #include <linux/device.h>
20 #include <linux/delay.h>
21 #include <sound/driver.h>
22 #include <sound/core.h>
23 #include <sound/pcm.h>
24 #include <sound/initval.h>
25 #include <sound/soc.h>
26 
27 #include <asm/hardware.h>
28 #include <asm/arch/pxa-regs.h>
29 #include <asm/arch/audio.h>
30 
31 #include "pxa2xx-pcm.h"
32 
33 /* used to disable sysclk if external crystal is used */
34 static int extclk;
35 module_param(extclk, int, 0);
36 MODULE_PARM_DESC(extclk, "set to 1 to disable pxa2xx i2s sysclk");
37 
38 struct pxa_i2s_port {
39 	u32 sadiv;
40 	u32 sacr0;
41 	u32 sacr1;
42 	u32 saimr;
43 	int master;
44 };
45 static struct pxa_i2s_port pxa_i2s;
46 
47 #define PXA_I2S_DAIFMT \
48 	(SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF)
49 
50 #define PXA_I2S_DIR \
51 	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
52 
53 #define PXA_I2S_RATES \
54 	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
55 	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
56 	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
57 
58 /* priv is divider */
59 static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = {
60 	/* pxa2xx I2S frame and clock master modes */
61 	{
62 		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
63 		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
64 		.pcmrate = SNDRV_PCM_RATE_8000,
65 		.pcmdir = PXA_I2S_DIR,
66 		.flags = SND_SOC_DAI_BFS_DIV,
67 		.fs = 256,
68 		.bfs = SND_SOC_FSBD(4),
69 		.priv = 0x48,
70 	},
71 	{
72 		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
73 		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
74 		.pcmrate = SNDRV_PCM_RATE_11025,
75 		.pcmdir = PXA_I2S_DIR,
76 		.flags = SND_SOC_DAI_BFS_DIV,
77 		.fs = 256,
78 		.bfs = SND_SOC_FSBD(4),
79 		.priv = 0x34,
80 	},
81 	{
82 		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
83 		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
84 		.pcmrate = SNDRV_PCM_RATE_16000,
85 		.pcmdir = PXA_I2S_DIR,
86 		.flags = SND_SOC_DAI_BFS_DIV,
87 		.fs = 256,
88 		.bfs = SND_SOC_FSBD(4),
89 		.priv = 0x24,
90 	},
91 	{
92 		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
93 		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
94 		.pcmrate = SNDRV_PCM_RATE_22050,
95 		.pcmdir = PXA_I2S_DIR,
96 		.flags = SND_SOC_DAI_BFS_DIV,
97 		.fs = 256,
98 		.bfs = SND_SOC_FSBD(4),
99 		.priv = 0x1a,
100 	},
101 	{
102 		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
103 		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
104 		.pcmrate = SNDRV_PCM_RATE_44100,
105 		.pcmdir = PXA_I2S_DIR,
106 		.flags = SND_SOC_DAI_BFS_DIV,
107 		.fs = 256,
108 		.bfs = SND_SOC_FSBD(4),
109 		.priv = 0xd,
110 	},
111 	{
112 		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
113 		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
114 		.pcmrate = SNDRV_PCM_RATE_48000,
115 		.pcmdir = PXA_I2S_DIR,
116 		.flags = SND_SOC_DAI_BFS_DIV,
117 		.fs = 256,
118 		.bfs = SND_SOC_FSBD(4),
119 		.priv = 0xc,
120 	},
121 
122 	/* pxa2xx I2S frame master and clock slave mode */
123 	{
124 		.fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS,
125 		.pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
126 		.pcmrate = PXA_I2S_RATES,
127 		.pcmdir = PXA_I2S_DIR,
128 		.fs = SND_SOC_FS_ALL,
129 		.bfs = SND_SOC_FSB(64),
130 		.priv = 0x48,
131 	},
132 };
133 
134 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
135 	.name			= "I2S PCM Stereo out",
136 	.dev_addr		= __PREG(SADR),
137 	.drcmr			= &DRCMRTXSADR,
138 	.dcmd			= DCMD_INCSRCADDR | DCMD_FLOWTRG |
139 				  DCMD_BURST32 | DCMD_WIDTH4,
140 };
141 
142 static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_in = {
143 	.name			= "I2S PCM Stereo in",
144 	.dev_addr		= __PREG(SADR),
145 	.drcmr			= &DRCMRRXSADR,
146 	.dcmd			= DCMD_INCTRGADDR | DCMD_FLOWSRC |
147 				  DCMD_BURST32 | DCMD_WIDTH4,
148 };
149 
150 static struct pxa2xx_gpio gpio_bus[] = {
151 	{ /* I2S SoC Slave */
152 		.rx = GPIO29_SDATA_IN_I2S_MD,
153 		.tx = GPIO30_SDATA_OUT_I2S_MD,
154 		.clk = GPIO28_BITCLK_IN_I2S_MD,
155 		.frm = GPIO31_SYNC_I2S_MD,
156 	},
157 	{ /* I2S SoC Master */
158 #ifdef CONFIG_PXA27x
159 		.sys = GPIO113_I2S_SYSCLK_MD,
160 #else
161 		.sys = GPIO32_SYSCLK_I2S_MD,
162 #endif
163 		.rx = GPIO29_SDATA_IN_I2S_MD,
164 		.tx = GPIO30_SDATA_OUT_I2S_MD,
165 		.clk = GPIO28_BITCLK_OUT_I2S_MD,
166 		.frm = GPIO31_SYNC_I2S_MD,
167 	},
168 };
169 
170 static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream)
171 {
172 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
173 
174 	if (!rtd->cpu_dai->active) {
175 		SACR0 |= SACR0_RST;
176 		SACR0 = 0;
177 	}
178 
179 	return 0;
180 }
181 
182 /* wait for I2S controller to be ready */
183 static int pxa_i2s_wait(void)
184 {
185 	int i;
186 
187 	/* flush the Rx FIFO */
188 	for(i = 0; i < 16; i++)
189 		SADR;
190 	return 0;
191 }
192 
193 static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
194 				struct snd_pcm_hw_params *params)
195 {
196 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
197 
198 	pxa_i2s.master = 0;
199 	if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CBS_CFS)
200 		pxa_i2s.master = 1;
201 
202 	if (pxa_i2s.master && !extclk)
203 		pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys);
204 
205 	pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx);
206 	pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
207 	pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
208 	pxa_gpio_mode(gpio_bus[pxa_i2s.master].clk);
209 	pxa_set_cken(CKEN8_I2S, 1);
210 	pxa_i2s_wait();
211 
212 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
213 		rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out;
214 	else
215 		rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in;
216 
217 	/* is port used by another stream */
218 	if (!(SACR0 & SACR0_ENB)) {
219 
220 		SACR0 = 0;
221 		SACR1 = 0;
222 		if (pxa_i2s.master)
223 			SACR0 |= SACR0_BCKD;
224 
225 		SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1);
226 
227 		if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_LEFT_J)
228 			SACR1 |= SACR1_AMSL;
229 	}
230 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
231 		SAIMR |= SAIMR_TFS;
232 	else
233 		SAIMR |= SAIMR_RFS;
234 
235 	SADIV = rtd->cpu_dai->dai_runtime.priv;
236 	return 0;
237 }
238 
239 static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
240 {
241 	int ret = 0;
242 
243 	switch (cmd) {
244 	case SNDRV_PCM_TRIGGER_START:
245 		SACR0 |= SACR0_ENB;
246 		break;
247 	case SNDRV_PCM_TRIGGER_RESUME:
248 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
249 	case SNDRV_PCM_TRIGGER_STOP:
250 	case SNDRV_PCM_TRIGGER_SUSPEND:
251 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
252 		break;
253 	default:
254 		ret = -EINVAL;
255 	}
256 
257 	return ret;
258 }
259 
260 static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream)
261 {
262 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
263 		SACR1 |= SACR1_DRPL;
264 		SAIMR &= ~SAIMR_TFS;
265 	} else {
266 		SACR1 |= SACR1_DREC;
267 		SAIMR &= ~SAIMR_RFS;
268 	}
269 
270 	if (SACR1 & (SACR1_DREC | SACR1_DRPL)) {
271 		SACR0 &= ~SACR0_ENB;
272 		pxa_i2s_wait();
273 		pxa_set_cken(CKEN8_I2S, 0);
274 	}
275 }
276 
277 #ifdef CONFIG_PM
278 static int pxa2xx_i2s_suspend(struct platform_device *dev,
279 	struct snd_soc_cpu_dai *dai)
280 {
281 	if (!dai->active)
282 		return 0;
283 
284 	/* store registers */
285 	pxa_i2s.sacr0 = SACR0;
286 	pxa_i2s.sacr1 = SACR1;
287 	pxa_i2s.saimr = SAIMR;
288 	pxa_i2s.sadiv = SADIV;
289 
290 	/* deactivate link */
291 	SACR0 &= ~SACR0_ENB;
292 	pxa_i2s_wait();
293 	return 0;
294 }
295 
296 static int pxa2xx_i2s_resume(struct platform_device *pdev,
297 	struct snd_soc_cpu_dai *dai)
298 {
299 	if (!dai->active)
300 		return 0;
301 
302 	pxa_i2s_wait();
303 
304 	SACR0 = pxa_i2s.sacr0 &= ~SACR0_ENB;
305 	SACR1 = pxa_i2s.sacr1;
306 	SAIMR = pxa_i2s.saimr;
307 	SADIV = pxa_i2s.sadiv;
308 	SACR0 |= SACR0_ENB;
309 
310 	return 0;
311 }
312 
313 #else
314 #define pxa2xx_i2s_suspend	NULL
315 #define pxa2xx_i2s_resume	NULL
316 #endif
317 
318 /* pxa2xx I2S sysclock is always 256 FS */
319 static unsigned int pxa_i2s_config_sysclk(struct snd_soc_cpu_dai *iface,
320 	struct snd_soc_clock_info *info, unsigned int clk)
321 {
322 	return info->rate << 8;
323 }
324 
325 struct snd_soc_cpu_dai pxa_i2s_dai = {
326 	.name = "pxa2xx-i2s",
327 	.id = 0,
328 	.type = SND_SOC_DAI_I2S,
329 	.suspend = pxa2xx_i2s_suspend,
330 	.resume = pxa2xx_i2s_resume,
331 	.config_sysclk = pxa_i2s_config_sysclk,
332 	.playback = {
333 		.channels_min = 2,
334 		.channels_max = 2,},
335 	.capture = {
336 		.channels_min = 2,
337 		.channels_max = 2,},
338 	.ops = {
339 		.startup = pxa2xx_i2s_startup,
340 		.shutdown = pxa2xx_i2s_shutdown,
341 		.trigger = pxa2xx_i2s_trigger,
342 		.hw_params = pxa2xx_i2s_hw_params,},
343 	.caps = {
344 		.num_modes = ARRAY_SIZE(pxa2xx_i2s_modes),
345 		.mode = pxa2xx_i2s_modes,},
346 };
347 
348 EXPORT_SYMBOL_GPL(pxa_i2s_dai);
349 
350 /* Module information */
351 MODULE_AUTHOR("Liam Girdwood, liam.girdwood@wolfsonmicro.com, www.wolfsonmicro.com");
352 MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
353 MODULE_LICENSE("GPL");
354