Blame view

sound/arm/aaci.c 25.2 KB
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  /*
   *  linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver
   *
   *  Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   *
   *  Documentation: ARM DDI 0173B
   */
  #include <linux/module.h>
  #include <linux/delay.h>
  #include <linux/init.h>
  #include <linux/ioport.h>
  #include <linux/device.h>
  #include <linux/spinlock.h>
  #include <linux/interrupt.h>
  #include <linux/err.h>
a62c80e55   Russell King   [ARM] Move AMBA i...
20
  #include <linux/amba/bus.h>
88cdca9c7   Russell King   ALSA: AACI cleanup
21
  #include <linux/io.h>
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
22

cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
23
24
25
26
27
28
29
  #include <sound/core.h>
  #include <sound/initval.h>
  #include <sound/ac97_codec.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
  
  #include "aaci.h"
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
30
31
  
  #define DRIVER_NAME	"aaci-pl041"
250c7a61c   Russell King   ALSA: AACI: fix t...
32
  #define FRAME_PERIOD_US	21
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
33
34
35
36
  /*
   * PM support is not complete.  Turn it off.
   */
  #undef CONFIG_PM
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
37
  static void aaci_ac97_select_codec(struct aaci *aaci, struct snd_ac97 *ac97)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
38
39
40
41
42
43
44
45
46
47
48
  {
  	u32 v, maincr = aaci->maincr | MAINCR_SCRA(ac97->num);
  
  	/*
  	 * Ensure that the slot 1/2 RX registers are empty.
  	 */
  	v = readl(aaci->base + AACI_SLFR);
  	if (v & SLFR_2RXV)
  		readl(aaci->base + AACI_SL2RX);
  	if (v & SLFR_1RXV)
  		readl(aaci->base + AACI_SL1RX);
7c289385b   Russell King   ALSA: AACI: allow...
49
50
51
52
53
  	if (maincr != readl(aaci->base + AACI_MAINCR)) {
  		writel(maincr, aaci->base + AACI_MAINCR);
  		readl(aaci->base + AACI_MAINCR);
  		udelay(1);
  	}
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
54
55
56
57
58
59
60
61
62
63
64
  }
  
  /*
   * P29:
   *  The recommended use of programming the external codec through slot 1
   *  and slot 2 data is to use the channels during setup routines and the
   *  slot register at any other time.  The data written into slot 1, slot 2
   *  and slot 12 registers is transmitted only when their corresponding
   *  SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR
   *  register.
   */
14d178a14   Kevin Hilman   [ARM] 4140/1: AAC...
65
66
  static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
  			    unsigned short val)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
67
68
  {
  	struct aaci *aaci = ac97->private_data;
250c7a61c   Russell King   ALSA: AACI: fix t...
69
  	int timeout;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
70
71
72
73
  	u32 v;
  
  	if (ac97->num >= 4)
  		return;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
74
  	mutex_lock(&aaci->ac97_sem);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
75
76
77
78
79
80
81
82
83
  
  	aaci_ac97_select_codec(aaci, ac97);
  
  	/*
  	 * P54: You must ensure that AACI_SL2TX is always written
  	 * to, if required, before data is written to AACI_SL1TX.
  	 */
  	writel(val << 4, aaci->base + AACI_SL2TX);
  	writel(reg << 12, aaci->base + AACI_SL1TX);
250c7a61c   Russell King   ALSA: AACI: fix t...
84
85
86
87
88
  	/* Initially, wait one frame period */
  	udelay(FRAME_PERIOD_US);
  
  	/* And then wait an additional eight frame periods for it to be sent */
  	timeout = FRAME_PERIOD_US * 8;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
89
  	do {
250c7a61c   Russell King   ALSA: AACI: fix t...
90
  		udelay(1);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
91
  		v = readl(aaci->base + AACI_SLFR);
f6f35bbe7   Roel Kluin   [ARM] AACI: timeo...
92
  	} while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout);
14d178a14   Kevin Hilman   [ARM] 4140/1: AAC...
93

69058cd6d   Russell King   ALSA: AACI: fix t...
94
  	if (v & (SLFR_1TXB|SLFR_2TXB))
14d178a14   Kevin Hilman   [ARM] 4140/1: AAC...
95
96
97
  		dev_err(&aaci->dev->dev,
  			"timeout waiting for write to complete
  ");
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
98

12aa75790   Ingo Molnar   [ALSA] semaphore ...
99
  	mutex_unlock(&aaci->ac97_sem);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
100
101
102
103
104
  }
  
  /*
   * Read an AC'97 register.
   */
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
105
  static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
106
107
  {
  	struct aaci *aaci = ac97->private_data;
250c7a61c   Russell King   ALSA: AACI: fix t...
108
  	int timeout, retries = 10;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
109
110
111
112
  	u32 v;
  
  	if (ac97->num >= 4)
  		return ~0;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
113
  	mutex_lock(&aaci->ac97_sem);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
114
115
116
117
118
119
120
  
  	aaci_ac97_select_codec(aaci, ac97);
  
  	/*
  	 * Write the register address to slot 1.
  	 */
  	writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX);
250c7a61c   Russell King   ALSA: AACI: fix t...
121
122
123
124
125
  	/* Initially, wait one frame period */
  	udelay(FRAME_PERIOD_US);
  
  	/* And then wait an additional eight frame periods for it to be sent */
  	timeout = FRAME_PERIOD_US * 8;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
126
  	do {
250c7a61c   Russell King   ALSA: AACI: fix t...
127
  		udelay(1);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
128
  		v = readl(aaci->base + AACI_SLFR);
f6f35bbe7   Roel Kluin   [ARM] AACI: timeo...
129
  	} while ((v & SLFR_1TXB) && --timeout);
14d178a14   Kevin Hilman   [ARM] 4140/1: AAC...
130

69058cd6d   Russell King   ALSA: AACI: fix t...
131
  	if (v & SLFR_1TXB) {
14d178a14   Kevin Hilman   [ARM] 4140/1: AAC...
132
133
134
135
136
  		dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy
  ");
  		v = ~0;
  		goto out;
  	}
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
137

250c7a61c   Russell King   ALSA: AACI: fix t...
138
139
  	/* Now wait for the response frame */
  	udelay(FRAME_PERIOD_US);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
140

250c7a61c   Russell King   ALSA: AACI: fix t...
141
142
  	/* And then wait an additional eight frame periods for data */
  	timeout = FRAME_PERIOD_US * 8;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
143
  	do {
250c7a61c   Russell King   ALSA: AACI: fix t...
144
  		udelay(1);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
145
146
  		cond_resched();
  		v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
f6f35bbe7   Roel Kluin   [ARM] AACI: timeo...
147
  	} while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
148

69058cd6d   Russell King   ALSA: AACI: fix t...
149
  	if (v != (SLFR_1RXV|SLFR_2RXV)) {
14d178a14   Kevin Hilman   [ARM] 4140/1: AAC...
150
151
  		dev_err(&aaci->dev->dev, "timeout on RX valid
  ");
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
152
  		v = ~0;
14d178a14   Kevin Hilman   [ARM] 4140/1: AAC...
153
  		goto out;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
154
  	}
14d178a14   Kevin Hilman   [ARM] 4140/1: AAC...
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  	do {
  		v = readl(aaci->base + AACI_SL1RX) >> 12;
  		if (v == reg) {
  			v = readl(aaci->base + AACI_SL2RX) >> 4;
  			break;
  		} else if (--retries) {
  			dev_warn(&aaci->dev->dev,
  				 "ac97 read back fail.  retry
  ");
  			continue;
  		} else {
  			dev_warn(&aaci->dev->dev,
  				"wrong ac97 register read back (%x != %x)
  ",
  				v, reg);
  			v = ~0;
  		}
  	} while (retries);
   out:
12aa75790   Ingo Molnar   [ALSA] semaphore ...
174
  	mutex_unlock(&aaci->ac97_sem);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
175
176
  	return v;
  }
d6a89fefa   Russell King   ALSA: AACI: switc...
177
178
  static inline void
  aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
179
180
181
182
183
  {
  	u32 val;
  	int timeout = 5000;
  
  	do {
250c7a61c   Russell King   ALSA: AACI: fix t...
184
  		udelay(1);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
185
  		val = readl(aacirun->base + AACI_SR);
d6a89fefa   Russell King   ALSA: AACI: switc...
186
  	} while (val & mask && timeout--);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
187
188
189
190
191
192
193
  }
  
  
  
  /*
   * Interrupt support.
   */
62578cbfa   Kevin Hilman   [ARM] 4138/1: AAC...
194
  static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
195
  {
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
196
197
198
199
200
201
202
203
204
205
206
207
208
209
  	if (mask & ISR_ORINTR) {
  		dev_warn(&aaci->dev->dev, "RX overrun on chan %d
  ", channel);
  		writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR);
  	}
  
  	if (mask & ISR_RXTOINTR) {
  		dev_warn(&aaci->dev->dev, "RX timeout on chan %d
  ", channel);
  		writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR);
  	}
  
  	if (mask & ISR_RXINTR) {
  		struct aaci_runtime *aacirun = &aaci->capture;
ea51d0b16   Russell King   ALSA: AACI: no ne...
210
  		bool period_elapsed = false;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
211
212
213
  		void *ptr;
  
  		if (!aacirun->substream || !aacirun->start) {
898eb71cb   Joe Perches   Add missing newli...
214
215
  			dev_warn(&aaci->dev->dev, "RX interrupt???
  ");
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
216
217
218
  			writel(0, aacirun->base + AACI_IE);
  			return;
  		}
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
219

d6a89fefa   Russell King   ALSA: AACI: switc...
220
221
222
  		spin_lock(&aacirun->lock);
  
  		ptr = aacirun->ptr;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
223
  		do {
5d350cba4   Russell King   ALSA: AACI: make ...
224
  			unsigned int len = aacirun->fifo_bytes;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
225
226
227
228
  			u32 val;
  
  			if (aacirun->bytes <= 0) {
  				aacirun->bytes += aacirun->period;
ea51d0b16   Russell King   ALSA: AACI: no ne...
229
  				period_elapsed = true;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
  			}
  			if (!(aacirun->cr & CR_EN))
  				break;
  
  			val = readl(aacirun->base + AACI_SR);
  			if (!(val & SR_RXHF))
  				break;
  			if (!(val & SR_RXFF))
  				len >>= 1;
  
  			aacirun->bytes -= len;
  
  			/* reading 16 bytes at a time */
  			for( ; len > 0; len -= 16) {
  				asm(
  					"ldmia	%1, {r0, r1, r2, r3}
  \t"
  					"stmia	%0!, {r0, r1, r2, r3}"
  					: "+r" (ptr)
  					: "r" (aacirun->fifo)
  					: "r0", "r1", "r2", "r3", "cc");
  
  				if (ptr >= aacirun->end)
  					ptr = aacirun->start;
  			}
  		} while(1);
d6a89fefa   Russell King   ALSA: AACI: switc...
256

41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
257
  		aacirun->ptr = ptr;
d6a89fefa   Russell King   ALSA: AACI: switc...
258
259
  
  		spin_unlock(&aacirun->lock);
ea51d0b16   Russell King   ALSA: AACI: no ne...
260
261
262
  
  		if (period_elapsed)
  			snd_pcm_period_elapsed(aacirun->substream);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
263
  	}
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
264
  	if (mask & ISR_URINTR) {
62578cbfa   Kevin Hilman   [ARM] 4138/1: AAC...
265
266
267
  		dev_dbg(&aaci->dev->dev, "TX underrun on chan %d
  ", channel);
  		writel(ICLR_TXUEC1 << channel, aaci->base + AACI_INTCLR);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
268
269
270
271
  	}
  
  	if (mask & ISR_TXINTR) {
  		struct aaci_runtime *aacirun = &aaci->playback;
ea51d0b16   Russell King   ALSA: AACI: no ne...
272
  		bool period_elapsed = false;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
273
274
275
  		void *ptr;
  
  		if (!aacirun->substream || !aacirun->start) {
898eb71cb   Joe Perches   Add missing newli...
276
277
  			dev_warn(&aaci->dev->dev, "TX interrupt???
  ");
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
278
279
280
  			writel(0, aacirun->base + AACI_IE);
  			return;
  		}
d6a89fefa   Russell King   ALSA: AACI: switc...
281
  		spin_lock(&aacirun->lock);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
282
283
  		ptr = aacirun->ptr;
  		do {
5d350cba4   Russell King   ALSA: AACI: make ...
284
  			unsigned int len = aacirun->fifo_bytes;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
285
286
287
288
  			u32 val;
  
  			if (aacirun->bytes <= 0) {
  				aacirun->bytes += aacirun->period;
ea51d0b16   Russell King   ALSA: AACI: no ne...
289
  				period_elapsed = true;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
290
  			}
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
291
  			if (!(aacirun->cr & CR_EN))
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  				break;
  
  			val = readl(aacirun->base + AACI_SR);
  			if (!(val & SR_TXHE))
  				break;
  			if (!(val & SR_TXFE))
  				len >>= 1;
  
  			aacirun->bytes -= len;
  
  			/* writing 16 bytes at a time */
  			for ( ; len > 0; len -= 16) {
  				asm(
  					"ldmia	%0!, {r0, r1, r2, r3}
  \t"
  					"stmia	%1, {r0, r1, r2, r3}"
  					: "+r" (ptr)
  					: "r" (aacirun->fifo)
  					: "r0", "r1", "r2", "r3", "cc");
  
  				if (ptr >= aacirun->end)
  					ptr = aacirun->start;
  			}
  		} while (1);
  
  		aacirun->ptr = ptr;
d6a89fefa   Russell King   ALSA: AACI: switc...
318
319
  
  		spin_unlock(&aacirun->lock);
ea51d0b16   Russell King   ALSA: AACI: no ne...
320
321
322
  
  		if (period_elapsed)
  			snd_pcm_period_elapsed(aacirun->substream);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
323
324
  	}
  }
7d12e780e   David Howells   IRQ: Maintain reg...
325
  static irqreturn_t aaci_irq(int irq, void *devid)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
326
327
328
329
  {
  	struct aaci *aaci = devid;
  	u32 mask;
  	int i;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
330
331
332
333
334
  	mask = readl(aaci->base + AACI_ALLINTS);
  	if (mask) {
  		u32 m = mask;
  		for (i = 0; i < 4; i++, m >>= 7) {
  			if (m & 0x7f) {
62578cbfa   Kevin Hilman   [ARM] 4138/1: AAC...
335
  				aaci_fifo_irq(aaci, i, m);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
336
337
338
  			}
  		}
  	}
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
339
340
341
342
343
344
345
346
347
  
  	return mask ? IRQ_HANDLED : IRQ_NONE;
  }
  
  
  
  /*
   * ALSA support.
   */
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
348
  static struct snd_pcm_hardware aaci_hw_info = {
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
349
350
351
352
353
354
355
356
357
358
359
  	.info			= SNDRV_PCM_INFO_MMAP |
  				  SNDRV_PCM_INFO_MMAP_VALID |
  				  SNDRV_PCM_INFO_INTERLEAVED |
  				  SNDRV_PCM_INFO_BLOCK_TRANSFER |
  				  SNDRV_PCM_INFO_RESUME,
  
  	/*
  	 * ALSA doesn't support 18-bit or 20-bit packed into 32-bit
  	 * words.  It also doesn't support 12-bit at all.
  	 */
  	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
6ca867c82   Russell King   ALSA: AACI: simpl...
360
  	/* rates are setup from the AC'97 codec */
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
361
  	.channels_min		= 2,
e831d80b4   Russell King   ALSA: AACI: fix n...
362
  	.channels_max		= 2,
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
363
364
365
366
367
368
  	.buffer_bytes_max	= 64 * 1024,
  	.period_bytes_min	= 256,
  	.period_bytes_max	= PAGE_SIZE,
  	.periods_min		= 4,
  	.periods_max		= PAGE_SIZE / 16,
  };
e831d80b4   Russell King   ALSA: AACI: fix n...
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  /*
   * We can support two and four channel audio.  Unfortunately
   * six channel audio requires a non-standard channel ordering:
   *   2 -> FL(3), FR(4)
   *   4 -> FL(3), FR(4), SL(7), SR(8)
   *   6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required)
   *        FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual)
   * This requires an ALSA configuration file to correct.
   */
  static int aaci_rule_channels(struct snd_pcm_hw_params *p,
  	struct snd_pcm_hw_rule *rule)
  {
  	static unsigned int channel_list[] = { 2, 4, 6 };
  	struct aaci *aaci = rule->private;
  	unsigned int mask = 1 << 0, slots;
  
  	/* pcms[0] is the our 5.1 PCM instance. */
  	slots = aaci->ac97_bus->pcms[0].r[0].slots;
  	if (slots & (1 << AC97_SLOT_PCM_SLEFT)) {
  		mask |= 1 << 1;
  		if (slots & (1 << AC97_SLOT_LFE))
  			mask |= 1 << 2;
  	}
  
  	return snd_interval_list(hw_param_interval(p, rule->var),
  				 ARRAY_SIZE(channel_list), channel_list, mask);
  }
  
  static int aaci_pcm_open(struct snd_pcm_substream *substream)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
398
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
399
  	struct snd_pcm_runtime *runtime = substream->runtime;
e831d80b4   Russell King   ALSA: AACI: fix n...
400
401
  	struct aaci *aaci = substream->private_data;
  	struct aaci_runtime *aacirun;
b60fb519d   Russell King   ALSA: AACI: fix m...
402
  	int ret = 0;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
403

e831d80b4   Russell King   ALSA: AACI: fix n...
404
405
406
407
408
  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  		aacirun = &aaci->playback;
  	} else {
  		aacirun = &aaci->capture;
  	}
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
409
410
411
  	aacirun->substream = substream;
  	runtime->private_data = aacirun;
  	runtime->hw = aaci_hw_info;
6ca867c82   Russell King   ALSA: AACI: simpl...
412
413
  	runtime->hw.rates = aacirun->pcm->rates;
  	snd_pcm_limit_hw_rates(runtime);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
414

e831d80b4   Russell King   ALSA: AACI: fix n...
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  		runtime->hw.channels_max = 6;
  
  		/* Add rule describing channel dependency. */
  		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
  					  SNDRV_PCM_HW_PARAM_CHANNELS,
  					  aaci_rule_channels, aaci,
  					  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
  		if (ret)
  			return ret;
  
  		if (aacirun->pcm->r[1].slots)
  			snd_ac97_pcm_double_rate_rules(runtime);
  	}
a08d56583   Russell King   ALSA: AACI: add d...
429

cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
430
  	/*
5d350cba4   Russell King   ALSA: AACI: make ...
431
432
433
  	 * ALSA wants the byte-size of the FIFOs.  As we only support
  	 * 16-bit samples, this is twice the FIFO depth irrespective
  	 * of whether it's in compact mode or not.
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
434
  	 */
5d350cba4   Russell King   ALSA: AACI: make ...
435
  	runtime->hw.fifo_size = aaci->fifo_depth * 2;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
436

b60fb519d   Russell King   ALSA: AACI: fix m...
437
438
439
  	mutex_lock(&aaci->irq_lock);
  	if (!aaci->users++) {
  		ret = request_irq(aaci->dev->irq[0], aaci_irq,
88e24c3a4   Yong Zhang   sound: irq: Remov...
440
  			   IRQF_SHARED, DRIVER_NAME, aaci);
b60fb519d   Russell King   ALSA: AACI: fix m...
441
442
443
444
  		if (ret != 0)
  			aaci->users--;
  	}
  	mutex_unlock(&aaci->irq_lock);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
445

cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
446
447
448
449
450
451
452
  	return ret;
  }
  
  
  /*
   * Common ALSA stuff
   */
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
453
  static int aaci_pcm_close(struct snd_pcm_substream *substream)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
454
455
456
  {
  	struct aaci *aaci = substream->private_data;
  	struct aaci_runtime *aacirun = substream->runtime->private_data;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
457
  	WARN_ON(aacirun->cr & CR_EN);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
458
459
  
  	aacirun->substream = NULL;
b60fb519d   Russell King   ALSA: AACI: fix m...
460
461
462
463
464
  
  	mutex_lock(&aaci->irq_lock);
  	if (!--aaci->users)
  		free_irq(aaci->dev->irq[0], aaci);
  	mutex_unlock(&aaci->irq_lock);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
465
466
467
  
  	return 0;
  }
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
468
  static int aaci_pcm_hw_free(struct snd_pcm_substream *substream)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
469
470
471
472
473
474
  {
  	struct aaci_runtime *aacirun = substream->runtime->private_data;
  
  	/*
  	 * This must not be called with the device enabled.
  	 */
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
475
  	WARN_ON(aacirun->cr & CR_EN);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
476
477
478
479
480
481
482
483
  
  	if (aacirun->pcm_open)
  		snd_ac97_pcm_close(aacirun->pcm);
  	aacirun->pcm_open = 0;
  
  	/*
  	 * Clear out the DMA and any allocated buffers.
  	 */
d67973222   Takashi Iwai   ALSA: Remove old ...
484
  	snd_pcm_lib_free_pages(substream);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
485
486
487
  
  	return 0;
  }
58e8a4741   Russell King   ALSA: AACI: fix c...
488
489
490
491
492
493
  /* Channel to slot mask */
  static const u32 channels_to_slotmask[] = {
  	[2] = CR_SL3 | CR_SL4,
  	[4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8,
  	[6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9,
  };
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
494
  static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
495
  			      struct snd_pcm_hw_params *params)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
496
  {
58e8a4741   Russell King   ALSA: AACI: fix c...
497
498
499
500
  	struct aaci_runtime *aacirun = substream->runtime->private_data;
  	unsigned int channels = params_channels(params);
  	unsigned int rate = params_rate(params);
  	int dbl = rate > 48000;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
501
502
503
  	int err;
  
  	aaci_pcm_hw_free(substream);
4acd57c3d   Russell King   ALSA: AACI: fix A...
504
505
506
507
  	if (aacirun->pcm_open) {
  		snd_ac97_pcm_close(aacirun->pcm);
  		aacirun->pcm_open = 0;
  	}
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
508

58e8a4741   Russell King   ALSA: AACI: fix c...
509
510
511
  	/* channels is already limited to 2, 4, or 6 by aaci_rule_channels */
  	if (dbl && channels != 2)
  		return -EINVAL;
d67973222   Takashi Iwai   ALSA: Remove old ...
512
513
  	err = snd_pcm_lib_malloc_pages(substream,
  				       params_buffer_bytes(params));
4e30b6910   Russell King   ALSA: AACI: clean...
514
  	if (err >= 0) {
58e8a4741   Russell King   ALSA: AACI: fix c...
515
  		struct aaci *aaci = substream->private_data;
a08d56583   Russell King   ALSA: AACI: add d...
516

58e8a4741   Russell King   ALSA: AACI: fix c...
517
  		err = snd_ac97_pcm_open(aacirun->pcm, rate, channels,
a08d56583   Russell King   ALSA: AACI: add d...
518
  					aacirun->pcm->r[dbl].slots);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
519

4e30b6910   Russell King   ALSA: AACI: clean...
520
  		aacirun->pcm_open = err == 0;
d3aee7996   Russell King   ALSA: AACI: facto...
521
  		aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16;
58e8a4741   Russell King   ALSA: AACI: fix c...
522
  		aacirun->cr |= channels_to_slotmask[channels + dbl * 2];
d3aee7996   Russell King   ALSA: AACI: facto...
523

5d350cba4   Russell King   ALSA: AACI: make ...
524
525
526
527
528
529
  		/*
  		 * fifo_bytes is the number of bytes we transfer to/from
  		 * the FIFO, including padding.  So that's x4.  As we're
  		 * in compact mode, the FIFO is half the size.
  		 */
  		aacirun->fifo_bytes = aaci->fifo_depth * 4 / 2;
4e30b6910   Russell King   ALSA: AACI: clean...
530
  	}
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
531

cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
532
533
  	return err;
  }
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
534
  static int aaci_pcm_prepare(struct snd_pcm_substream *substream)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
535
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
536
  	struct snd_pcm_runtime *runtime = substream->runtime;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
537
  	struct aaci_runtime *aacirun = runtime->private_data;
c0dea82c3   Russell King   ALSA: AACI: use s...
538
  	aacirun->period	= snd_pcm_lib_period_bytes(substream);
4e30b6910   Russell King   ALSA: AACI: clean...
539
  	aacirun->start	= runtime->dma_area;
88cdca9c7   Russell King   ALSA: AACI cleanup
540
  	aacirun->end	= aacirun->start + snd_pcm_lib_buffer_bytes(substream);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
541
  	aacirun->ptr	= aacirun->start;
c0dea82c3   Russell King   ALSA: AACI: use s...
542
  	aacirun->bytes	= aacirun->period;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
543
544
545
  
  	return 0;
  }
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
546
  static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
547
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
548
  	struct snd_pcm_runtime *runtime = substream->runtime;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
549
550
551
552
553
  	struct aaci_runtime *aacirun = runtime->private_data;
  	ssize_t bytes = aacirun->ptr - aacirun->start;
  
  	return bytes_to_frames(runtime, bytes);
  }
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
554
555
556
557
  
  /*
   * Playback specific ALSA stuff
   */
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
558
559
560
561
562
563
564
  static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun)
  {
  	u32 ie;
  
  	ie = readl(aacirun->base + AACI_IE);
  	ie &= ~(IE_URIE|IE_TXIE);
  	writel(ie, aacirun->base + AACI_IE);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
565
  	aacirun->cr &= ~CR_EN;
d6a89fefa   Russell King   ALSA: AACI: switc...
566
  	aaci_chan_wait_ready(aacirun, SR_TXB);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
567
568
569
570
571
572
  	writel(aacirun->cr, aacirun->base + AACI_TXCR);
  }
  
  static void aaci_pcm_playback_start(struct aaci_runtime *aacirun)
  {
  	u32 ie;
d6a89fefa   Russell King   ALSA: AACI: switc...
573
  	aaci_chan_wait_ready(aacirun, SR_TXB);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
574
  	aacirun->cr |= CR_EN;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
575
576
577
578
579
580
  
  	ie = readl(aacirun->base + AACI_IE);
  	ie |= IE_URIE | IE_TXIE;
  	writel(ie, aacirun->base + AACI_IE);
  	writel(aacirun->cr, aacirun->base + AACI_TXCR);
  }
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
581
  static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
582
  {
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
583
584
585
  	struct aaci_runtime *aacirun = substream->runtime->private_data;
  	unsigned long flags;
  	int ret = 0;
d6a89fefa   Russell King   ALSA: AACI: switc...
586
  	spin_lock_irqsave(&aacirun->lock, flags);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  		aaci_pcm_playback_start(aacirun);
  		break;
  
  	case SNDRV_PCM_TRIGGER_RESUME:
  		aaci_pcm_playback_start(aacirun);
  		break;
  
  	case SNDRV_PCM_TRIGGER_STOP:
  		aaci_pcm_playback_stop(aacirun);
  		break;
  
  	case SNDRV_PCM_TRIGGER_SUSPEND:
  		aaci_pcm_playback_stop(aacirun);
  		break;
  
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  		break;
  
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  		break;
  
  	default:
  		ret = -EINVAL;
  	}
d6a89fefa   Russell King   ALSA: AACI: switc...
613
614
  
  	spin_unlock_irqrestore(&aacirun->lock, flags);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
615
616
617
  
  	return ret;
  }
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
618
  static struct snd_pcm_ops aaci_playback_ops = {
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
619
  	.open		= aaci_pcm_open,
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
620
621
  	.close		= aaci_pcm_close,
  	.ioctl		= snd_pcm_lib_ioctl,
58e8a4741   Russell King   ALSA: AACI: fix c...
622
  	.hw_params	= aaci_pcm_hw_params,
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
623
624
625
626
  	.hw_free	= aaci_pcm_hw_free,
  	.prepare	= aaci_pcm_prepare,
  	.trigger	= aaci_pcm_playback_trigger,
  	.pointer	= aaci_pcm_pointer,
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
627
  };
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
628
629
630
  static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun)
  {
  	u32 ie;
d6a89fefa   Russell King   ALSA: AACI: switc...
631
  	aaci_chan_wait_ready(aacirun, SR_RXB);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
632
633
634
635
636
637
  
  	ie = readl(aacirun->base + AACI_IE);
  	ie &= ~(IE_ORIE | IE_RXIE);
  	writel(ie, aacirun->base+AACI_IE);
  
  	aacirun->cr &= ~CR_EN;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
638

41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
639
640
641
642
643
644
  	writel(aacirun->cr, aacirun->base + AACI_RXCR);
  }
  
  static void aaci_pcm_capture_start(struct aaci_runtime *aacirun)
  {
  	u32 ie;
d6a89fefa   Russell King   ALSA: AACI: switc...
645
  	aaci_chan_wait_ready(aacirun, SR_RXB);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
646
647
648
649
650
651
652
653
654
655
656
657
658
  
  #ifdef DEBUG
  	/* RX Timeout value: bits 28:17 in RXCR */
  	aacirun->cr |= 0xf << 17;
  #endif
  
  	aacirun->cr |= CR_EN;
  	writel(aacirun->cr, aacirun->base + AACI_RXCR);
  
  	ie = readl(aacirun->base + AACI_IE);
  	ie |= IE_ORIE |IE_RXIE; // overrun and rx interrupt -- half full
  	writel(ie, aacirun->base + AACI_IE);
  }
8a371840f   Russell King   [ARM] Fix ARM AAC...
659
660
  static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
  {
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
661
662
663
  	struct aaci_runtime *aacirun = substream->runtime->private_data;
  	unsigned long flags;
  	int ret = 0;
d6a89fefa   Russell King   ALSA: AACI: switc...
664
  	spin_lock_irqsave(&aacirun->lock, flags);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  		aaci_pcm_capture_start(aacirun);
  		break;
  
  	case SNDRV_PCM_TRIGGER_RESUME:
  		aaci_pcm_capture_start(aacirun);
  		break;
  
  	case SNDRV_PCM_TRIGGER_STOP:
  		aaci_pcm_capture_stop(aacirun);
  		break;
  
  	case SNDRV_PCM_TRIGGER_SUSPEND:
  		aaci_pcm_capture_stop(aacirun);
  		break;
  
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  		break;
  
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  		break;
  
  	default:
  		ret = -EINVAL;
  	}
d6a89fefa   Russell King   ALSA: AACI: switc...
692
  	spin_unlock_irqrestore(&aacirun->lock, flags);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
693
694
695
  
  	return ret;
  }
8a371840f   Russell King   [ARM] Fix ARM AAC...
696
  static int aaci_pcm_capture_prepare(struct snd_pcm_substream *substream)
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
  {
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct aaci *aaci = substream->private_data;
  
  	aaci_pcm_prepare(substream);
  
  	/* allow changing of sample rate */
  	aaci_ac97_write(aaci->ac97, AC97_EXTENDED_STATUS, 0x0001); /* VRA */
  	aaci_ac97_write(aaci->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
  	aaci_ac97_write(aaci->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate);
  
  	/* Record select: Mic: 0, Aux: 3, Line: 4 */
  	aaci_ac97_write(aaci->ac97, AC97_REC_SEL, 0x0404);
  
  	return 0;
  }
8a371840f   Russell King   [ARM] Fix ARM AAC...
713
  static struct snd_pcm_ops aaci_capture_ops = {
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
714
715
716
  	.open		= aaci_pcm_open,
  	.close		= aaci_pcm_close,
  	.ioctl		= snd_pcm_lib_ioctl,
58e8a4741   Russell King   ALSA: AACI: fix c...
717
  	.hw_params	= aaci_pcm_hw_params,
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
718
719
720
721
  	.hw_free	= aaci_pcm_hw_free,
  	.prepare	= aaci_pcm_capture_prepare,
  	.trigger	= aaci_pcm_capture_trigger,
  	.pointer	= aaci_pcm_pointer,
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
722
  };
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
723
724
725
726
727
  
  /*
   * Power Management.
   */
  #ifdef CONFIG_PM
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
728
  static int aaci_do_suspend(struct snd_card *card, unsigned int state)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
729
730
  {
  	struct aaci *aaci = card->private_data;
792a6c518   Takashi Iwai   [ALSA] Fix PM sup...
731
732
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
  	snd_pcm_suspend_all(aaci->pcm);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
733
734
  	return 0;
  }
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
735
  static int aaci_do_resume(struct snd_card *card, unsigned int state)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
736
  {
792a6c518   Takashi Iwai   [ALSA] Fix PM sup...
737
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
738
739
  	return 0;
  }
e36d394de   Richard Purdie   [PATCH] Fix up so...
740
  static int aaci_suspend(struct amba_device *dev, pm_message_t state)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
741
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
742
  	struct snd_card *card = amba_get_drvdata(dev);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
743
744
745
746
747
  	return card ? aaci_do_suspend(card) : 0;
  }
  
  static int aaci_resume(struct amba_device *dev)
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
748
  	struct snd_card *card = amba_get_drvdata(dev);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
749
750
751
752
753
754
755
756
757
758
759
  	return card ? aaci_do_resume(card) : 0;
  }
  #else
  #define aaci_do_suspend		NULL
  #define aaci_do_resume		NULL
  #define aaci_suspend		NULL
  #define aaci_resume		NULL
  #endif
  
  
  static struct ac97_pcm ac97_defs[] __devinitdata = {
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
760
  	[0] = {	/* Front PCM */
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
761
762
763
764
765
766
767
768
769
770
  		.exclusive = 1,
  		.r = {
  			[0] = {
  				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
  					  (1 << AC97_SLOT_PCM_RIGHT) |
  					  (1 << AC97_SLOT_PCM_CENTER) |
  					  (1 << AC97_SLOT_PCM_SLEFT) |
  					  (1 << AC97_SLOT_PCM_SRIGHT) |
  					  (1 << AC97_SLOT_LFE),
  			},
a08d56583   Russell King   ALSA: AACI: add d...
771
772
773
774
775
776
  			[1] = {
  				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
  					  (1 << AC97_SLOT_PCM_RIGHT) |
  					  (1 << AC97_SLOT_PCM_LEFT_0) |
  					  (1 << AC97_SLOT_PCM_RIGHT_0),
  			},
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
  		},
  	},
  	[1] = {	/* PCM in */
  		.stream = 1,
  		.exclusive = 1,
  		.r = {
  			[0] = {
  				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
  					  (1 << AC97_SLOT_PCM_RIGHT),
  			},
  		},
  	},
  	[2] = {	/* Mic in */
  		.stream = 1,
  		.exclusive = 1,
  		.r = {
  			[0] = {
  				.slots	= (1 << AC97_SLOT_MIC),
  			},
  		},
  	}
  };
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
799
  static struct snd_ac97_bus_ops aaci_bus_ops = {
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
800
801
802
803
804
805
  	.write	= aaci_ac97_write,
  	.read	= aaci_ac97_read,
  };
  
  static int __devinit aaci_probe_ac97(struct aaci *aaci)
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
806
807
808
  	struct snd_ac97_template ac97_template;
  	struct snd_ac97_bus *ac97_bus;
  	struct snd_ac97 *ac97;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
809
810
811
812
813
814
815
816
817
818
819
820
821
  	int ret;
  
  	/*
  	 * Assert AACIRESET for 2us
  	 */
  	writel(0, aaci->base + AACI_RESET);
  	udelay(2);
  	writel(RESET_NRST, aaci->base + AACI_RESET);
  
  	/*
  	 * Give the AC'97 codec more than enough time
  	 * to wake up. (42us = ~2 frames at 48kHz.)
  	 */
250c7a61c   Russell King   ALSA: AACI: fix t...
822
  	udelay(FRAME_PERIOD_US * 2);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
823
824
825
826
827
828
829
  
  	ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus);
  	if (ret)
  		goto out;
  
  	ac97_bus->clock = 48000;
  	aaci->ac97_bus = ac97_bus;
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
830
  	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
831
832
833
834
835
836
837
  	ac97_template.private_data = aaci;
  	ac97_template.num = 0;
  	ac97_template.scaps = AC97_SCAP_SKIP_MODEM;
  
  	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
  	if (ret)
  		goto out;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
838
  	aaci->ac97 = ac97;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
839
840
841
842
843
844
845
846
847
848
849
850
  
  	/*
  	 * Disable AC97 PC Beep input on audio codecs.
  	 */
  	if (ac97_is_audio(ac97))
  		snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e);
  
  	ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs);
  	if (ret)
  		goto out;
  
  	aaci->playback.pcm = &ac97_bus->pcms[0];
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
851
  	aaci->capture.pcm  = &ac97_bus->pcms[1];
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
852
853
854
855
  
   out:
  	return ret;
  }
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
856
  static void aaci_free_card(struct snd_card *card)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
857
858
859
860
861
862
863
864
865
  {
  	struct aaci *aaci = card->private_data;
  	if (aaci->base)
  		iounmap(aaci->base);
  }
  
  static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
  {
  	struct aaci *aaci;
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
866
  	struct snd_card *card;
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
867
  	int err;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
868

bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
869
870
871
  	err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
  			      THIS_MODULE, sizeof(struct aaci), &card);
  	if (err < 0)
631e8ad42   Takashi Iwai   ALSA: aaci - Fix ...
872
  		return NULL;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
873
874
  
  	card->private_free = aaci_free_card;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
875
876
877
878
  
  	strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
  	strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
  	snprintf(card->longname, sizeof(card->longname),
f006d8fc5   Russell King   ALSA: AACI: clean...
879
880
881
  		 "%s PL%03x rev%u at 0x%08llx, irq %d",
  		 card->shortname, amba_part(dev), amba_rev(dev),
  		 (unsigned long long)dev->res.start, dev->irq[0]);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
882
883
  
  	aaci = card->private_data;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
884
  	mutex_init(&aaci->ac97_sem);
b60fb519d   Russell King   ALSA: AACI: fix m...
885
  	mutex_init(&aaci->irq_lock);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
886
887
888
889
890
891
892
893
894
895
896
897
  	aaci->card = card;
  	aaci->dev = dev;
  
  	/* Set MAINCR to allow slot 1 and 2 data IO */
  	aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN |
  		       MAINCR_SL2RXEN | MAINCR_SL2TXEN;
  
  	return aaci;
  }
  
  static int __devinit aaci_init_pcm(struct aaci *aaci)
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
898
  	struct snd_pcm *pcm;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
899
  	int ret;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
900
  	ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
901
902
903
904
905
906
907
908
  	if (ret == 0) {
  		aaci->pcm = pcm;
  		pcm->private_data = aaci;
  		pcm->info_flags = 0;
  
  		strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
  
  		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
909
  		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops);
d67973222   Takashi Iwai   ALSA: Remove old ...
910
  		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
d49464318   Takashi Iwai   ALSA: aaci - Fix ...
911
  						      NULL, 0, 64 * 1024);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
912
913
914
915
916
917
918
  	}
  
  	return ret;
  }
  
  static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
  {
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
919
  	struct aaci_runtime *aacirun = &aaci->playback;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
920
  	int i;
5d350cba4   Russell King   ALSA: AACI: make ...
921
922
923
924
  	/*
  	 * Enable the channel, but don't assign it to any slots, so
  	 * it won't empty onto the AC'97 link.
  	 */
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
925
  	writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
926

41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
927
928
  	for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++)
  		writel(0, aacirun->fifo);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
929

41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
930
  	writel(0, aacirun->base + AACI_TXCR);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
931
932
933
934
935
936
937
  
  	/*
  	 * Re-initialise the AACI after the FIFO depth test, to
  	 * ensure that the FIFOs are empty.  Unfortunately, merely
  	 * disabling the channel doesn't clear the FIFO.
  	 */
  	writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR);
7c289385b   Russell King   ALSA: AACI: allow...
938
939
  	readl(aaci->base + AACI_MAINCR);
  	udelay(1);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
940
941
942
  	writel(aaci->maincr, aaci->base + AACI_MAINCR);
  
  	/*
5d350cba4   Russell King   ALSA: AACI: make ...
943
  	 * If we hit 4096 entries, we failed.  Go back to the specified
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
944
945
946
947
948
949
950
  	 * fifo depth.
  	 */
  	if (i == 4096)
  		i = 8;
  
  	return i;
  }
aa25afad2   Russell King   ARM: amba: make p...
951
952
  static int __devinit aaci_probe(struct amba_device *dev,
  	const struct amba_id *id)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
953
954
955
956
957
958
959
960
961
  {
  	struct aaci *aaci;
  	int ret, i;
  
  	ret = amba_request_regions(dev, NULL);
  	if (ret)
  		return ret;
  
  	aaci = aaci_init_card(dev);
631e8ad42   Takashi Iwai   ALSA: aaci - Fix ...
962
963
  	if (!aaci) {
  		ret = -ENOMEM;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
964
965
  		goto out;
  	}
dc890c2dc   Linus Walleij   [ARM] 5544/1: Tru...
966
  	aaci->base = ioremap(dev->res.start, resource_size(&dev->res));
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
967
968
969
970
971
972
973
974
  	if (!aaci->base) {
  		ret = -ENOMEM;
  		goto out;
  	}
  
  	/*
  	 * Playback uses AACI channel 0
  	 */
d6a89fefa   Russell King   ALSA: AACI: switc...
975
  	spin_lock_init(&aaci->playback.lock);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
976
977
  	aaci->playback.base = aaci->base + AACI_CSCH1;
  	aaci->playback.fifo = aaci->base + AACI_DR1;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
978
979
980
  	/*
  	 * Capture uses AACI channel 0
  	 */
d6a89fefa   Russell King   ALSA: AACI: switc...
981
  	spin_lock_init(&aaci->capture.lock);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
982
983
  	aaci->capture.base = aaci->base + AACI_CSCH1;
  	aaci->capture.fifo = aaci->base + AACI_DR1;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
984
  	for (i = 0; i < 4; i++) {
e12ba644e   Al Viro   [PATCH] iomem ann...
985
  		void __iomem *base = aaci->base + i * 0x14;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
986
987
988
989
990
991
992
993
  
  		writel(0, base + AACI_IE);
  		writel(0, base + AACI_TXCR);
  		writel(0, base + AACI_RXCR);
  	}
  
  	writel(0x1fff, aaci->base + AACI_INTCLR);
  	writel(aaci->maincr, aaci->base + AACI_MAINCR);
b68b58fd6   Philby John   ALSA: aaci - Fix ...
994
995
996
997
998
  	/*
  	 * Fix: ac97 read back fail errors by reading
  	 * from any arbitrary aaci register.
  	 */
  	readl(aaci->base + AACI_CSCH1);
f27f218cd   Catalin Marinas   [ARM] 3290/1: Fix...
999
1000
1001
  	ret = aaci_probe_ac97(aaci);
  	if (ret)
  		goto out;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1002
  	/*
f27f218cd   Catalin Marinas   [ARM] 3290/1: Fix...
1003
  	 * Size the FIFOs (must be multiple of 16).
5d350cba4   Russell King   ALSA: AACI: make ...
1004
  	 * This is the number of entries in the FIFO.
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1005
  	 */
5d350cba4   Russell King   ALSA: AACI: make ...
1006
1007
1008
1009
1010
  	aaci->fifo_depth = aaci_size_fifo(aaci);
  	if (aaci->fifo_depth & 15) {
  		printk(KERN_WARNING "AACI: FIFO depth %d not supported
  ",
  		       aaci->fifo_depth);
f27f218cd   Catalin Marinas   [ARM] 3290/1: Fix...
1011
  		ret = -ENODEV;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1012
  		goto out;
f27f218cd   Catalin Marinas   [ARM] 3290/1: Fix...
1013
  	}
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1014
1015
1016
1017
  
  	ret = aaci_init_pcm(aaci);
  	if (ret)
  		goto out;
a76af199d   Takashi Iwai   [ALSA] Add snd_ca...
1018
  	snd_card_set_dev(aaci->card, &dev->dev);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1019
1020
  	ret = snd_card_register(aaci->card);
  	if (ret == 0) {
5d350cba4   Russell King   ALSA: AACI: make ...
1021
1022
1023
1024
  		dev_info(&dev->dev, "%s
  ", aaci->card->longname);
  		dev_info(&dev->dev, "FIFO %u entries
  ", aaci->fifo_depth);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
  		amba_set_drvdata(dev, aaci->card);
  		return ret;
  	}
  
   out:
  	if (aaci)
  		snd_card_free(aaci->card);
  	amba_release_regions(dev);
  	return ret;
  }
  
  static int __devexit aaci_remove(struct amba_device *dev)
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
1038
  	struct snd_card *card = amba_get_drvdata(dev);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
  
  	amba_set_drvdata(dev, NULL);
  
  	if (card) {
  		struct aaci *aaci = card->private_data;
  		writel(0, aaci->base + AACI_MAINCR);
  
  		snd_card_free(card);
  		amba_release_regions(dev);
  	}
  
  	return 0;
  }
  
  static struct amba_id aaci_ids[] = {
  	{
  		.id	= 0x00041041,
  		.mask	= 0x000fffff,
  	},
  	{ 0, 0 },
  };
9d5c62732   Dave Martin   sound: aaci: Enab...
1060
  MODULE_DEVICE_TABLE(amba, aaci_ids);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
  static struct amba_driver aaci_driver = {
  	.drv		= {
  		.name	= DRIVER_NAME,
  	},
  	.probe		= aaci_probe,
  	.remove		= __devexit_p(aaci_remove),
  	.suspend	= aaci_suspend,
  	.resume		= aaci_resume,
  	.id_table	= aaci_ids,
  };
  
  static int __init aaci_init(void)
  {
  	return amba_driver_register(&aaci_driver);
  }
  
  static void __exit aaci_exit(void)
  {
  	amba_driver_unregister(&aaci_driver);
  }
  
  module_init(aaci_init);
  module_exit(aaci_exit);
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver");