Blame view

sound/arm/aaci.c 24.8 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.
   */
db566fb98   Bhumika Goyal   ALSA: arm: make s...
348
  static const 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;
  }
28f054802   Arvind Yadav   ALSA: arm: consti...
618
  static const 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;
  }
28f054802   Arvind Yadav   ALSA: arm: consti...
713
  static const 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
b13a71492   Ulf Hansson   ALSA: AACI: Conve...
728
  static int aaci_do_suspend(struct snd_card *card)
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;
  }
b13a71492   Ulf Hansson   ALSA: AACI: Conve...
735
  static int aaci_do_resume(struct snd_card *card)
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;
  }
b13a71492   Ulf Hansson   ALSA: AACI: Conve...
740
  static int aaci_suspend(struct device *dev)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
741
  {
b13a71492   Ulf Hansson   ALSA: AACI: Conve...
742
  	struct snd_card *card = dev_get_drvdata(dev);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
743
744
  	return card ? aaci_do_suspend(card) : 0;
  }
b13a71492   Ulf Hansson   ALSA: AACI: Conve...
745
  static int aaci_resume(struct device *dev)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
746
  {
b13a71492   Ulf Hansson   ALSA: AACI: Conve...
747
  	struct snd_card *card = dev_get_drvdata(dev);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
748
749
  	return card ? aaci_do_resume(card) : 0;
  }
b13a71492   Ulf Hansson   ALSA: AACI: Conve...
750
751
752
  
  static SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
  #define AACI_DEV_PM_OPS (&aaci_dev_pm_ops)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
753
  #else
b13a71492   Ulf Hansson   ALSA: AACI: Conve...
754
  #define AACI_DEV_PM_OPS NULL
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
755
  #endif
9b419cd41   Arvind Yadav   ALSA: aaci: const...
756
  static const struct ac97_pcm ac97_defs[] = {
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
757
  	[0] = {	/* Front PCM */
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
758
759
760
761
762
763
764
765
766
767
  		.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...
768
769
770
771
772
773
  			[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...
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
  		},
  	},
  	[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...
796
  static struct snd_ac97_bus_ops aaci_bus_ops = {
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
797
798
799
  	.write	= aaci_ac97_write,
  	.read	= aaci_ac97_read,
  };
6c9dc19c1   Bill Pemberton   ALSA: AACI: remov...
800
  static int aaci_probe_ac97(struct aaci *aaci)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
801
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
802
803
804
  	struct snd_ac97_template ac97_template;
  	struct snd_ac97_bus *ac97_bus;
  	struct snd_ac97 *ac97;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
805
806
807
808
809
810
811
812
813
814
815
816
817
  	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...
818
  	udelay(FRAME_PERIOD_US * 2);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
819
820
821
822
823
824
825
  
  	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...
826
  	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
827
828
829
830
831
832
833
  	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...
834
  	aaci->ac97 = ac97;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
835
836
837
838
839
840
841
842
843
844
845
846
  
  	/*
  	 * 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...
847
  	aaci->capture.pcm  = &ac97_bus->pcms[1];
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
848
849
850
851
  
   out:
  	return ret;
  }
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
852
  static void aaci_free_card(struct snd_card *card)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
853
854
  {
  	struct aaci *aaci = card->private_data;
ff6defa6a   Markus Elfring   ALSA: Deletion of...
855
856
  
  	iounmap(aaci->base);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
857
  }
6c9dc19c1   Bill Pemberton   ALSA: AACI: remov...
858
  static struct aaci *aaci_init_card(struct amba_device *dev)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
859
860
  {
  	struct aaci *aaci;
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
861
  	struct snd_card *card;
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
862
  	int err;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
863

4a8755801   Takashi Iwai   ALSA: arm: Conver...
864
865
  	err = snd_card_new(&dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
  			   THIS_MODULE, sizeof(struct aaci), &card);
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
866
  	if (err < 0)
631e8ad42   Takashi Iwai   ALSA: aaci - Fix ...
867
  		return NULL;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
868
869
  
  	card->private_free = aaci_free_card;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
870
871
872
873
  
  	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...
874
875
876
  		 "%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...
877
878
  
  	aaci = card->private_data;
12aa75790   Ingo Molnar   [ALSA] semaphore ...
879
  	mutex_init(&aaci->ac97_sem);
b60fb519d   Russell King   ALSA: AACI: fix m...
880
  	mutex_init(&aaci->irq_lock);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
881
882
883
884
885
886
887
888
889
  	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;
  }
6c9dc19c1   Bill Pemberton   ALSA: AACI: remov...
890
  static int aaci_init_pcm(struct aaci *aaci)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
891
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
892
  	struct snd_pcm *pcm;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
893
  	int ret;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
894
  	ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
895
896
897
898
899
900
901
902
  	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...
903
  		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops);
d67973222   Takashi Iwai   ALSA: Remove old ...
904
  		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
d49464318   Takashi Iwai   ALSA: aaci - Fix ...
905
  						      NULL, 0, 64 * 1024);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
906
907
908
909
  	}
  
  	return ret;
  }
6c9dc19c1   Bill Pemberton   ALSA: AACI: remov...
910
  static unsigned int aaci_size_fifo(struct aaci *aaci)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
911
  {
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
912
  	struct aaci_runtime *aacirun = &aaci->playback;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
913
  	int i;
5d350cba4   Russell King   ALSA: AACI: make ...
914
915
916
917
  	/*
  	 * 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...
918
  	writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
919

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

41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
923
  	writel(0, aacirun->base + AACI_TXCR);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
924
925
926
927
928
929
930
  
  	/*
  	 * 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...
931
932
  	readl(aaci->base + AACI_MAINCR);
  	udelay(1);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
933
934
935
  	writel(aaci->maincr, aaci->base + AACI_MAINCR);
  
  	/*
5d350cba4   Russell King   ALSA: AACI: make ...
936
  	 * If we hit 4096 entries, we failed.  Go back to the specified
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
937
938
939
940
941
942
943
  	 * fifo depth.
  	 */
  	if (i == 4096)
  		i = 8;
  
  	return i;
  }
6c9dc19c1   Bill Pemberton   ALSA: AACI: remov...
944
945
  static int aaci_probe(struct amba_device *dev,
  		      const struct amba_id *id)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
946
947
948
949
950
951
952
953
954
  {
  	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 ...
955
956
  	if (!aaci) {
  		ret = -ENOMEM;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
957
958
  		goto out;
  	}
dc890c2dc   Linus Walleij   [ARM] 5544/1: Tru...
959
  	aaci->base = ioremap(dev->res.start, resource_size(&dev->res));
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
960
961
962
963
964
965
966
967
  	if (!aaci->base) {
  		ret = -ENOMEM;
  		goto out;
  	}
  
  	/*
  	 * Playback uses AACI channel 0
  	 */
d6a89fefa   Russell King   ALSA: AACI: switc...
968
  	spin_lock_init(&aaci->playback.lock);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
969
970
  	aaci->playback.base = aaci->base + AACI_CSCH1;
  	aaci->playback.fifo = aaci->base + AACI_DR1;
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
971
972
973
  	/*
  	 * Capture uses AACI channel 0
  	 */
d6a89fefa   Russell King   ALSA: AACI: switc...
974
  	spin_lock_init(&aaci->capture.lock);
41762b8ca   Kevin Hilman   [ARM] 4139/1: AAC...
975
976
  	aaci->capture.base = aaci->base + AACI_CSCH1;
  	aaci->capture.fifo = aaci->base + AACI_DR1;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
977
  	for (i = 0; i < 4; i++) {
e12ba644e   Al Viro   [PATCH] iomem ann...
978
  		void __iomem *base = aaci->base + i * 0x14;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
979
980
981
982
983
984
985
986
  
  		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 ...
987
988
989
990
991
  	/*
  	 * 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...
992
993
994
  	ret = aaci_probe_ac97(aaci);
  	if (ret)
  		goto out;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
995
  	/*
f27f218cd   Catalin Marinas   [ARM] 3290/1: Fix...
996
  	 * Size the FIFOs (must be multiple of 16).
5d350cba4   Russell King   ALSA: AACI: make ...
997
  	 * This is the number of entries in the FIFO.
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
998
  	 */
5d350cba4   Russell King   ALSA: AACI: make ...
999
1000
1001
1002
1003
  	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...
1004
  		ret = -ENODEV;
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1005
  		goto out;
f27f218cd   Catalin Marinas   [ARM] 3290/1: Fix...
1006
  	}
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1007
1008
1009
1010
1011
1012
1013
  
  	ret = aaci_init_pcm(aaci);
  	if (ret)
  		goto out;
  
  	ret = snd_card_register(aaci->card);
  	if (ret == 0) {
5d350cba4   Russell King   ALSA: AACI: make ...
1014
1015
1016
1017
  		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...
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
  		amba_set_drvdata(dev, aaci->card);
  		return ret;
  	}
  
   out:
  	if (aaci)
  		snd_card_free(aaci->card);
  	amba_release_regions(dev);
  	return ret;
  }
6c9dc19c1   Bill Pemberton   ALSA: AACI: remov...
1028
  static int aaci_remove(struct amba_device *dev)
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1029
  {
ceb9e476c   Takashi Iwai   [ALSA] Remove xxx...
1030
  	struct snd_card *card = amba_get_drvdata(dev);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1031

cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
  	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...
1050
  MODULE_DEVICE_TABLE(amba, aaci_ids);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1051
1052
1053
  static struct amba_driver aaci_driver = {
  	.drv		= {
  		.name	= DRIVER_NAME,
b13a71492   Ulf Hansson   ALSA: AACI: Conve...
1054
  		.pm	= AACI_DEV_PM_OPS,
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1055
1056
  	},
  	.probe		= aaci_probe,
6c9dc19c1   Bill Pemberton   ALSA: AACI: remov...
1057
  	.remove		= aaci_remove,
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1058
1059
  	.id_table	= aaci_ids,
  };
9e5ed094c   viresh kumar   ARM: 7362/1: AMBA...
1060
  module_amba_driver(aaci_driver);
cb5a6ffc5   Russell King   [ALSA] ARM AACI p...
1061
1062
1063
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver");