diff options
Diffstat (limited to 'sound/arm/aaci.c')
-rw-r--r-- | sound/arm/aaci.c | 968 |
1 files changed, 968 insertions, 0 deletions
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c new file mode 100644 index 000000000000..08cc3ddca96f --- /dev/null +++ b/sound/arm/aaci.c | |||
@@ -0,0 +1,968 @@ | |||
1 | /* | ||
2 | * linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver | ||
3 | * | ||
4 | * Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * Documentation: ARM DDI 0173B | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/ioport.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/err.h> | ||
20 | |||
21 | #include <asm/io.h> | ||
22 | #include <asm/irq.h> | ||
23 | #include <asm/hardware/amba.h> | ||
24 | |||
25 | #include <sound/driver.h> | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/ac97_codec.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | |||
32 | #include "aaci.h" | ||
33 | #include "devdma.h" | ||
34 | |||
35 | #define DRIVER_NAME "aaci-pl041" | ||
36 | |||
37 | /* | ||
38 | * PM support is not complete. Turn it off. | ||
39 | */ | ||
40 | #undef CONFIG_PM | ||
41 | |||
42 | static void aaci_ac97_select_codec(struct aaci *aaci, ac97_t *ac97) | ||
43 | { | ||
44 | u32 v, maincr = aaci->maincr | MAINCR_SCRA(ac97->num); | ||
45 | |||
46 | /* | ||
47 | * Ensure that the slot 1/2 RX registers are empty. | ||
48 | */ | ||
49 | v = readl(aaci->base + AACI_SLFR); | ||
50 | if (v & SLFR_2RXV) | ||
51 | readl(aaci->base + AACI_SL2RX); | ||
52 | if (v & SLFR_1RXV) | ||
53 | readl(aaci->base + AACI_SL1RX); | ||
54 | |||
55 | writel(maincr, aaci->base + AACI_MAINCR); | ||
56 | } | ||
57 | |||
58 | /* | ||
59 | * P29: | ||
60 | * The recommended use of programming the external codec through slot 1 | ||
61 | * and slot 2 data is to use the channels during setup routines and the | ||
62 | * slot register at any other time. The data written into slot 1, slot 2 | ||
63 | * and slot 12 registers is transmitted only when their corresponding | ||
64 | * SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR | ||
65 | * register. | ||
66 | */ | ||
67 | static void aaci_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) | ||
68 | { | ||
69 | struct aaci *aaci = ac97->private_data; | ||
70 | u32 v; | ||
71 | |||
72 | if (ac97->num >= 4) | ||
73 | return; | ||
74 | |||
75 | down(&aaci->ac97_sem); | ||
76 | |||
77 | aaci_ac97_select_codec(aaci, ac97); | ||
78 | |||
79 | /* | ||
80 | * P54: You must ensure that AACI_SL2TX is always written | ||
81 | * to, if required, before data is written to AACI_SL1TX. | ||
82 | */ | ||
83 | writel(val << 4, aaci->base + AACI_SL2TX); | ||
84 | writel(reg << 12, aaci->base + AACI_SL1TX); | ||
85 | |||
86 | /* | ||
87 | * Wait for the transmission of both slots to complete. | ||
88 | */ | ||
89 | do { | ||
90 | v = readl(aaci->base + AACI_SLFR); | ||
91 | } while (v & (SLFR_1TXB|SLFR_2TXB)); | ||
92 | |||
93 | up(&aaci->ac97_sem); | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * Read an AC'97 register. | ||
98 | */ | ||
99 | static unsigned short aaci_ac97_read(ac97_t *ac97, unsigned short reg) | ||
100 | { | ||
101 | struct aaci *aaci = ac97->private_data; | ||
102 | u32 v; | ||
103 | |||
104 | if (ac97->num >= 4) | ||
105 | return ~0; | ||
106 | |||
107 | down(&aaci->ac97_sem); | ||
108 | |||
109 | aaci_ac97_select_codec(aaci, ac97); | ||
110 | |||
111 | /* | ||
112 | * Write the register address to slot 1. | ||
113 | */ | ||
114 | writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX); | ||
115 | |||
116 | /* | ||
117 | * Wait for the transmission to complete. | ||
118 | */ | ||
119 | do { | ||
120 | v = readl(aaci->base + AACI_SLFR); | ||
121 | } while (v & SLFR_1TXB); | ||
122 | |||
123 | /* | ||
124 | * Give the AC'97 codec more than enough time | ||
125 | * to respond. (42us = ~2 frames at 48kHz.) | ||
126 | */ | ||
127 | udelay(42); | ||
128 | |||
129 | /* | ||
130 | * Wait for slot 2 to indicate data. | ||
131 | */ | ||
132 | do { | ||
133 | cond_resched(); | ||
134 | v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV); | ||
135 | } while (v != (SLFR_1RXV|SLFR_2RXV)); | ||
136 | |||
137 | v = readl(aaci->base + AACI_SL1RX) >> 12; | ||
138 | if (v == reg) { | ||
139 | v = readl(aaci->base + AACI_SL2RX) >> 4; | ||
140 | } else { | ||
141 | dev_err(&aaci->dev->dev, | ||
142 | "wrong ac97 register read back (%x != %x)\n", | ||
143 | v, reg); | ||
144 | v = ~0; | ||
145 | } | ||
146 | |||
147 | up(&aaci->ac97_sem); | ||
148 | return v; | ||
149 | } | ||
150 | |||
151 | static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) | ||
152 | { | ||
153 | u32 val; | ||
154 | int timeout = 5000; | ||
155 | |||
156 | do { | ||
157 | val = readl(aacirun->base + AACI_SR); | ||
158 | } while (val & (SR_TXB|SR_RXB) && timeout--); | ||
159 | } | ||
160 | |||
161 | |||
162 | |||
163 | /* | ||
164 | * Interrupt support. | ||
165 | */ | ||
166 | static void aaci_fifo_irq(struct aaci *aaci, u32 mask) | ||
167 | { | ||
168 | if (mask & ISR_URINTR) { | ||
169 | writel(ICLR_TXUEC1, aaci->base + AACI_INTCLR); | ||
170 | } | ||
171 | |||
172 | if (mask & ISR_TXINTR) { | ||
173 | struct aaci_runtime *aacirun = &aaci->playback; | ||
174 | void *ptr; | ||
175 | |||
176 | if (!aacirun->substream || !aacirun->start) { | ||
177 | dev_warn(&aaci->dev->dev, "TX interrupt???"); | ||
178 | writel(0, aacirun->base + AACI_IE); | ||
179 | return; | ||
180 | } | ||
181 | |||
182 | ptr = aacirun->ptr; | ||
183 | do { | ||
184 | unsigned int len = aacirun->fifosz; | ||
185 | u32 val; | ||
186 | |||
187 | if (aacirun->bytes <= 0) { | ||
188 | aacirun->bytes += aacirun->period; | ||
189 | aacirun->ptr = ptr; | ||
190 | spin_unlock(&aaci->lock); | ||
191 | snd_pcm_period_elapsed(aacirun->substream); | ||
192 | spin_lock(&aaci->lock); | ||
193 | } | ||
194 | if (!(aacirun->cr & TXCR_TXEN)) | ||
195 | break; | ||
196 | |||
197 | val = readl(aacirun->base + AACI_SR); | ||
198 | if (!(val & SR_TXHE)) | ||
199 | break; | ||
200 | if (!(val & SR_TXFE)) | ||
201 | len >>= 1; | ||
202 | |||
203 | aacirun->bytes -= len; | ||
204 | |||
205 | /* writing 16 bytes at a time */ | ||
206 | for ( ; len > 0; len -= 16) { | ||
207 | asm( | ||
208 | "ldmia %0!, {r0, r1, r2, r3}\n\t" | ||
209 | "stmia %1, {r0, r1, r2, r3}" | ||
210 | : "+r" (ptr) | ||
211 | : "r" (aacirun->fifo) | ||
212 | : "r0", "r1", "r2", "r3", "cc"); | ||
213 | |||
214 | if (ptr >= aacirun->end) | ||
215 | ptr = aacirun->start; | ||
216 | } | ||
217 | } while (1); | ||
218 | |||
219 | aacirun->ptr = ptr; | ||
220 | } | ||
221 | } | ||
222 | |||
223 | static irqreturn_t aaci_irq(int irq, void *devid, struct pt_regs *regs) | ||
224 | { | ||
225 | struct aaci *aaci = devid; | ||
226 | u32 mask; | ||
227 | int i; | ||
228 | |||
229 | spin_lock(&aaci->lock); | ||
230 | mask = readl(aaci->base + AACI_ALLINTS); | ||
231 | if (mask) { | ||
232 | u32 m = mask; | ||
233 | for (i = 0; i < 4; i++, m >>= 7) { | ||
234 | if (m & 0x7f) { | ||
235 | aaci_fifo_irq(aaci, m); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | spin_unlock(&aaci->lock); | ||
240 | |||
241 | return mask ? IRQ_HANDLED : IRQ_NONE; | ||
242 | } | ||
243 | |||
244 | |||
245 | |||
246 | /* | ||
247 | * ALSA support. | ||
248 | */ | ||
249 | |||
250 | struct aaci_stream { | ||
251 | unsigned char codec_idx; | ||
252 | unsigned char rate_idx; | ||
253 | }; | ||
254 | |||
255 | static struct aaci_stream aaci_streams[] = { | ||
256 | [ACSTREAM_FRONT] = { | ||
257 | .codec_idx = 0, | ||
258 | .rate_idx = AC97_RATES_FRONT_DAC, | ||
259 | }, | ||
260 | [ACSTREAM_SURROUND] = { | ||
261 | .codec_idx = 0, | ||
262 | .rate_idx = AC97_RATES_SURR_DAC, | ||
263 | }, | ||
264 | [ACSTREAM_LFE] = { | ||
265 | .codec_idx = 0, | ||
266 | .rate_idx = AC97_RATES_LFE_DAC, | ||
267 | }, | ||
268 | }; | ||
269 | |||
270 | static inline unsigned int aaci_rate_mask(struct aaci *aaci, int streamid) | ||
271 | { | ||
272 | struct aaci_stream *s = aaci_streams + streamid; | ||
273 | return aaci->ac97_bus->codec[s->codec_idx]->rates[s->rate_idx]; | ||
274 | } | ||
275 | |||
276 | static unsigned int rate_list[] = { | ||
277 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, | ||
278 | 48000, 64000, 88200, 96000, 176400, 192000 | ||
279 | }; | ||
280 | |||
281 | /* | ||
282 | * Double-rate rule: we can support double rate iff channels == 2 | ||
283 | * (unimplemented) | ||
284 | */ | ||
285 | static int | ||
286 | aaci_rule_rate_by_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule) | ||
287 | { | ||
288 | struct aaci *aaci = rule->private; | ||
289 | unsigned int rate_mask = SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_5512; | ||
290 | snd_interval_t *c = hw_param_interval(p, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
291 | |||
292 | switch (c->max) { | ||
293 | case 6: | ||
294 | rate_mask &= aaci_rate_mask(aaci, ACSTREAM_LFE); | ||
295 | case 4: | ||
296 | rate_mask &= aaci_rate_mask(aaci, ACSTREAM_SURROUND); | ||
297 | case 2: | ||
298 | rate_mask &= aaci_rate_mask(aaci, ACSTREAM_FRONT); | ||
299 | } | ||
300 | |||
301 | return snd_interval_list(hw_param_interval(p, rule->var), | ||
302 | ARRAY_SIZE(rate_list), rate_list, | ||
303 | rate_mask); | ||
304 | } | ||
305 | |||
306 | static snd_pcm_hardware_t aaci_hw_info = { | ||
307 | .info = SNDRV_PCM_INFO_MMAP | | ||
308 | SNDRV_PCM_INFO_MMAP_VALID | | ||
309 | SNDRV_PCM_INFO_INTERLEAVED | | ||
310 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
311 | SNDRV_PCM_INFO_RESUME, | ||
312 | |||
313 | /* | ||
314 | * ALSA doesn't support 18-bit or 20-bit packed into 32-bit | ||
315 | * words. It also doesn't support 12-bit at all. | ||
316 | */ | ||
317 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
318 | |||
319 | /* should this be continuous or knot? */ | ||
320 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
321 | .rate_max = 48000, | ||
322 | .rate_min = 4000, | ||
323 | .channels_min = 2, | ||
324 | .channels_max = 6, | ||
325 | .buffer_bytes_max = 64 * 1024, | ||
326 | .period_bytes_min = 256, | ||
327 | .period_bytes_max = PAGE_SIZE, | ||
328 | .periods_min = 4, | ||
329 | .periods_max = PAGE_SIZE / 16, | ||
330 | }; | ||
331 | |||
332 | static int aaci_pcm_open(struct aaci *aaci, snd_pcm_substream_t *substream, | ||
333 | struct aaci_runtime *aacirun) | ||
334 | { | ||
335 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
336 | int ret; | ||
337 | |||
338 | aacirun->substream = substream; | ||
339 | runtime->private_data = aacirun; | ||
340 | runtime->hw = aaci_hw_info; | ||
341 | |||
342 | /* | ||
343 | * FIXME: ALSA specifies fifo_size in bytes. If we're in normal | ||
344 | * mode, each 32-bit word contains one sample. If we're in | ||
345 | * compact mode, each 32-bit word contains two samples, effectively | ||
346 | * halving the FIFO size. However, we don't know for sure which | ||
347 | * we'll be using at this point. We set this to the lower limit. | ||
348 | */ | ||
349 | runtime->hw.fifo_size = aaci->fifosize * 2; | ||
350 | |||
351 | /* | ||
352 | * Add rule describing hardware rate dependency | ||
353 | * on the number of channels. | ||
354 | */ | ||
355 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
356 | aaci_rule_rate_by_channels, aaci, | ||
357 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
358 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
359 | if (ret) | ||
360 | goto out; | ||
361 | |||
362 | ret = request_irq(aaci->dev->irq[0], aaci_irq, SA_SHIRQ|SA_INTERRUPT, | ||
363 | DRIVER_NAME, aaci); | ||
364 | if (ret) | ||
365 | goto out; | ||
366 | |||
367 | return 0; | ||
368 | |||
369 | out: | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | |||
374 | /* | ||
375 | * Common ALSA stuff | ||
376 | */ | ||
377 | static int aaci_pcm_close(snd_pcm_substream_t *substream) | ||
378 | { | ||
379 | struct aaci *aaci = substream->private_data; | ||
380 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
381 | |||
382 | WARN_ON(aacirun->cr & TXCR_TXEN); | ||
383 | |||
384 | aacirun->substream = NULL; | ||
385 | free_irq(aaci->dev->irq[0], aaci); | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int aaci_pcm_hw_free(snd_pcm_substream_t *substream) | ||
391 | { | ||
392 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
393 | |||
394 | /* | ||
395 | * This must not be called with the device enabled. | ||
396 | */ | ||
397 | WARN_ON(aacirun->cr & TXCR_TXEN); | ||
398 | |||
399 | if (aacirun->pcm_open) | ||
400 | snd_ac97_pcm_close(aacirun->pcm); | ||
401 | aacirun->pcm_open = 0; | ||
402 | |||
403 | /* | ||
404 | * Clear out the DMA and any allocated buffers. | ||
405 | */ | ||
406 | devdma_hw_free(NULL, substream); | ||
407 | |||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static int aaci_pcm_hw_params(snd_pcm_substream_t *substream, | ||
412 | struct aaci_runtime *aacirun, | ||
413 | snd_pcm_hw_params_t *params) | ||
414 | { | ||
415 | int err; | ||
416 | |||
417 | aaci_pcm_hw_free(substream); | ||
418 | |||
419 | err = devdma_hw_alloc(NULL, substream, | ||
420 | params_buffer_bytes(params)); | ||
421 | if (err < 0) | ||
422 | goto out; | ||
423 | |||
424 | err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), | ||
425 | params_channels(params), | ||
426 | aacirun->pcm->r[0].slots); | ||
427 | if (err) | ||
428 | goto out; | ||
429 | |||
430 | aacirun->pcm_open = 1; | ||
431 | |||
432 | out: | ||
433 | return err; | ||
434 | } | ||
435 | |||
436 | static int aaci_pcm_prepare(snd_pcm_substream_t *substream) | ||
437 | { | ||
438 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
439 | struct aaci_runtime *aacirun = runtime->private_data; | ||
440 | |||
441 | aacirun->start = (void *)runtime->dma_area; | ||
442 | aacirun->end = aacirun->start + runtime->dma_bytes; | ||
443 | aacirun->ptr = aacirun->start; | ||
444 | aacirun->period = | ||
445 | aacirun->bytes = frames_to_bytes(runtime, runtime->period_size); | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static snd_pcm_uframes_t aaci_pcm_pointer(snd_pcm_substream_t *substream) | ||
451 | { | ||
452 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
453 | struct aaci_runtime *aacirun = runtime->private_data; | ||
454 | ssize_t bytes = aacirun->ptr - aacirun->start; | ||
455 | |||
456 | return bytes_to_frames(runtime, bytes); | ||
457 | } | ||
458 | |||
459 | static int aaci_pcm_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *vma) | ||
460 | { | ||
461 | return devdma_mmap(NULL, substream, vma); | ||
462 | } | ||
463 | |||
464 | |||
465 | /* | ||
466 | * Playback specific ALSA stuff | ||
467 | */ | ||
468 | static const u32 channels_to_txmask[] = { | ||
469 | [2] = TXCR_TX3 | TXCR_TX4, | ||
470 | [4] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8, | ||
471 | [6] = TXCR_TX3 | TXCR_TX4 | TXCR_TX7 | TXCR_TX8 | TXCR_TX6 | TXCR_TX9, | ||
472 | }; | ||
473 | |||
474 | /* | ||
475 | * We can support two and four channel audio. Unfortunately | ||
476 | * six channel audio requires a non-standard channel ordering: | ||
477 | * 2 -> FL(3), FR(4) | ||
478 | * 4 -> FL(3), FR(4), SL(7), SR(8) | ||
479 | * 6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required) | ||
480 | * FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual) | ||
481 | * This requires an ALSA configuration file to correct. | ||
482 | */ | ||
483 | static unsigned int channel_list[] = { 2, 4, 6 }; | ||
484 | |||
485 | static int | ||
486 | aaci_rule_channels(snd_pcm_hw_params_t *p, snd_pcm_hw_rule_t *rule) | ||
487 | { | ||
488 | struct aaci *aaci = rule->private; | ||
489 | unsigned int chan_mask = 1 << 0, slots; | ||
490 | |||
491 | /* | ||
492 | * pcms[0] is the our 5.1 PCM instance. | ||
493 | */ | ||
494 | slots = aaci->ac97_bus->pcms[0].r[0].slots; | ||
495 | if (slots & (1 << AC97_SLOT_PCM_SLEFT)) { | ||
496 | chan_mask |= 1 << 1; | ||
497 | if (slots & (1 << AC97_SLOT_LFE)) | ||
498 | chan_mask |= 1 << 2; | ||
499 | } | ||
500 | |||
501 | return snd_interval_list(hw_param_interval(p, rule->var), | ||
502 | ARRAY_SIZE(channel_list), channel_list, | ||
503 | chan_mask); | ||
504 | } | ||
505 | |||
506 | static int aaci_pcm_playback_open(snd_pcm_substream_t *substream) | ||
507 | { | ||
508 | struct aaci *aaci = substream->private_data; | ||
509 | int ret; | ||
510 | |||
511 | /* | ||
512 | * Add rule describing channel dependency. | ||
513 | */ | ||
514 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
515 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
516 | aaci_rule_channels, aaci, | ||
517 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
518 | if (ret) | ||
519 | return ret; | ||
520 | |||
521 | return aaci_pcm_open(aaci, substream, &aaci->playback); | ||
522 | } | ||
523 | |||
524 | static int aaci_pcm_playback_hw_params(snd_pcm_substream_t *substream, | ||
525 | snd_pcm_hw_params_t *params) | ||
526 | { | ||
527 | struct aaci *aaci = substream->private_data; | ||
528 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
529 | unsigned int channels = params_channels(params); | ||
530 | int ret; | ||
531 | |||
532 | WARN_ON(channels >= ARRAY_SIZE(channels_to_txmask) || | ||
533 | !channels_to_txmask[channels]); | ||
534 | |||
535 | ret = aaci_pcm_hw_params(substream, aacirun, params); | ||
536 | |||
537 | /* | ||
538 | * Enable FIFO, compact mode, 16 bits per sample. | ||
539 | * FIXME: double rate slots? | ||
540 | */ | ||
541 | if (ret >= 0) { | ||
542 | aacirun->cr = TXCR_FEN | TXCR_COMPACT | TXCR_TSZ16; | ||
543 | aacirun->cr |= channels_to_txmask[channels]; | ||
544 | |||
545 | aacirun->fifosz = aaci->fifosize * 4; | ||
546 | if (aacirun->cr & TXCR_COMPACT) | ||
547 | aacirun->fifosz >>= 1; | ||
548 | } | ||
549 | return ret; | ||
550 | } | ||
551 | |||
552 | static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) | ||
553 | { | ||
554 | u32 ie; | ||
555 | |||
556 | ie = readl(aacirun->base + AACI_IE); | ||
557 | ie &= ~(IE_URIE|IE_TXIE); | ||
558 | writel(ie, aacirun->base + AACI_IE); | ||
559 | aacirun->cr &= ~TXCR_TXEN; | ||
560 | aaci_chan_wait_ready(aacirun); | ||
561 | writel(aacirun->cr, aacirun->base + AACI_TXCR); | ||
562 | } | ||
563 | |||
564 | static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) | ||
565 | { | ||
566 | u32 ie; | ||
567 | |||
568 | aaci_chan_wait_ready(aacirun); | ||
569 | aacirun->cr |= TXCR_TXEN; | ||
570 | |||
571 | ie = readl(aacirun->base + AACI_IE); | ||
572 | ie |= IE_URIE | IE_TXIE; | ||
573 | writel(ie, aacirun->base + AACI_IE); | ||
574 | writel(aacirun->cr, aacirun->base + AACI_TXCR); | ||
575 | } | ||
576 | |||
577 | static int aaci_pcm_playback_trigger(snd_pcm_substream_t *substream, int cmd) | ||
578 | { | ||
579 | struct aaci *aaci = substream->private_data; | ||
580 | struct aaci_runtime *aacirun = substream->runtime->private_data; | ||
581 | unsigned long flags; | ||
582 | int ret = 0; | ||
583 | |||
584 | spin_lock_irqsave(&aaci->lock, flags); | ||
585 | switch (cmd) { | ||
586 | case SNDRV_PCM_TRIGGER_START: | ||
587 | aaci_pcm_playback_start(aacirun); | ||
588 | break; | ||
589 | |||
590 | case SNDRV_PCM_TRIGGER_RESUME: | ||
591 | aaci_pcm_playback_start(aacirun); | ||
592 | break; | ||
593 | |||
594 | case SNDRV_PCM_TRIGGER_STOP: | ||
595 | aaci_pcm_playback_stop(aacirun); | ||
596 | break; | ||
597 | |||
598 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
599 | aaci_pcm_playback_stop(aacirun); | ||
600 | break; | ||
601 | |||
602 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
603 | break; | ||
604 | |||
605 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
606 | break; | ||
607 | |||
608 | default: | ||
609 | ret = -EINVAL; | ||
610 | } | ||
611 | spin_unlock_irqrestore(&aaci->lock, flags); | ||
612 | |||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | static snd_pcm_ops_t aaci_playback_ops = { | ||
617 | .open = aaci_pcm_playback_open, | ||
618 | .close = aaci_pcm_close, | ||
619 | .ioctl = snd_pcm_lib_ioctl, | ||
620 | .hw_params = aaci_pcm_playback_hw_params, | ||
621 | .hw_free = aaci_pcm_hw_free, | ||
622 | .prepare = aaci_pcm_prepare, | ||
623 | .trigger = aaci_pcm_playback_trigger, | ||
624 | .pointer = aaci_pcm_pointer, | ||
625 | .mmap = aaci_pcm_mmap, | ||
626 | }; | ||
627 | |||
628 | |||
629 | |||
630 | /* | ||
631 | * Power Management. | ||
632 | */ | ||
633 | #ifdef CONFIG_PM | ||
634 | static int aaci_do_suspend(snd_card_t *card, unsigned int state) | ||
635 | { | ||
636 | struct aaci *aaci = card->private_data; | ||
637 | if (aaci->card->power_state != SNDRV_CTL_POWER_D3cold) { | ||
638 | snd_pcm_suspend_all(aaci->pcm); | ||
639 | snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D3cold); | ||
640 | } | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int aaci_do_resume(snd_card_t *card, unsigned int state) | ||
645 | { | ||
646 | struct aaci *aaci = card->private_data; | ||
647 | if (aaci->card->power_state != SNDRV_CTL_POWER_D0) { | ||
648 | snd_power_change_state(aaci->card, SNDRV_CTL_POWER_D0); | ||
649 | } | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static int aaci_suspend(struct amba_device *dev, u32 state) | ||
654 | { | ||
655 | snd_card_t *card = amba_get_drvdata(dev); | ||
656 | return card ? aaci_do_suspend(card) : 0; | ||
657 | } | ||
658 | |||
659 | static int aaci_resume(struct amba_device *dev) | ||
660 | { | ||
661 | snd_card_t *card = amba_get_drvdata(dev); | ||
662 | return card ? aaci_do_resume(card) : 0; | ||
663 | } | ||
664 | #else | ||
665 | #define aaci_do_suspend NULL | ||
666 | #define aaci_do_resume NULL | ||
667 | #define aaci_suspend NULL | ||
668 | #define aaci_resume NULL | ||
669 | #endif | ||
670 | |||
671 | |||
672 | static struct ac97_pcm ac97_defs[] __devinitdata = { | ||
673 | [0] = { /* Front PCM */ | ||
674 | .exclusive = 1, | ||
675 | .r = { | ||
676 | [0] = { | ||
677 | .slots = (1 << AC97_SLOT_PCM_LEFT) | | ||
678 | (1 << AC97_SLOT_PCM_RIGHT) | | ||
679 | (1 << AC97_SLOT_PCM_CENTER) | | ||
680 | (1 << AC97_SLOT_PCM_SLEFT) | | ||
681 | (1 << AC97_SLOT_PCM_SRIGHT) | | ||
682 | (1 << AC97_SLOT_LFE), | ||
683 | }, | ||
684 | }, | ||
685 | }, | ||
686 | [1] = { /* PCM in */ | ||
687 | .stream = 1, | ||
688 | .exclusive = 1, | ||
689 | .r = { | ||
690 | [0] = { | ||
691 | .slots = (1 << AC97_SLOT_PCM_LEFT) | | ||
692 | (1 << AC97_SLOT_PCM_RIGHT), | ||
693 | }, | ||
694 | }, | ||
695 | }, | ||
696 | [2] = { /* Mic in */ | ||
697 | .stream = 1, | ||
698 | .exclusive = 1, | ||
699 | .r = { | ||
700 | [0] = { | ||
701 | .slots = (1 << AC97_SLOT_MIC), | ||
702 | }, | ||
703 | }, | ||
704 | } | ||
705 | }; | ||
706 | |||
707 | static ac97_bus_ops_t aaci_bus_ops = { | ||
708 | .write = aaci_ac97_write, | ||
709 | .read = aaci_ac97_read, | ||
710 | }; | ||
711 | |||
712 | static int __devinit aaci_probe_ac97(struct aaci *aaci) | ||
713 | { | ||
714 | ac97_template_t ac97_template; | ||
715 | ac97_bus_t *ac97_bus; | ||
716 | ac97_t *ac97; | ||
717 | int ret; | ||
718 | |||
719 | /* | ||
720 | * Assert AACIRESET for 2us | ||
721 | */ | ||
722 | writel(0, aaci->base + AACI_RESET); | ||
723 | udelay(2); | ||
724 | writel(RESET_NRST, aaci->base + AACI_RESET); | ||
725 | |||
726 | /* | ||
727 | * Give the AC'97 codec more than enough time | ||
728 | * to wake up. (42us = ~2 frames at 48kHz.) | ||
729 | */ | ||
730 | udelay(42); | ||
731 | |||
732 | ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus); | ||
733 | if (ret) | ||
734 | goto out; | ||
735 | |||
736 | ac97_bus->clock = 48000; | ||
737 | aaci->ac97_bus = ac97_bus; | ||
738 | |||
739 | memset(&ac97_template, 0, sizeof(ac97_template_t)); | ||
740 | ac97_template.private_data = aaci; | ||
741 | ac97_template.num = 0; | ||
742 | ac97_template.scaps = AC97_SCAP_SKIP_MODEM; | ||
743 | |||
744 | ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); | ||
745 | if (ret) | ||
746 | goto out; | ||
747 | |||
748 | /* | ||
749 | * Disable AC97 PC Beep input on audio codecs. | ||
750 | */ | ||
751 | if (ac97_is_audio(ac97)) | ||
752 | snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e); | ||
753 | |||
754 | ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs); | ||
755 | if (ret) | ||
756 | goto out; | ||
757 | |||
758 | aaci->playback.pcm = &ac97_bus->pcms[0]; | ||
759 | |||
760 | out: | ||
761 | return ret; | ||
762 | } | ||
763 | |||
764 | static void aaci_free_card(snd_card_t *card) | ||
765 | { | ||
766 | struct aaci *aaci = card->private_data; | ||
767 | if (aaci->base) | ||
768 | iounmap(aaci->base); | ||
769 | } | ||
770 | |||
771 | static struct aaci * __devinit aaci_init_card(struct amba_device *dev) | ||
772 | { | ||
773 | struct aaci *aaci; | ||
774 | snd_card_t *card; | ||
775 | |||
776 | card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, | ||
777 | THIS_MODULE, sizeof(struct aaci)); | ||
778 | if (card == NULL) | ||
779 | return ERR_PTR(-ENOMEM); | ||
780 | |||
781 | card->private_free = aaci_free_card; | ||
782 | snd_card_set_pm_callback(card, aaci_do_suspend, aaci_do_resume, NULL); | ||
783 | |||
784 | strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); | ||
785 | strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname)); | ||
786 | snprintf(card->longname, sizeof(card->longname), | ||
787 | "%s at 0x%08lx, irq %d", | ||
788 | card->shortname, dev->res.start, dev->irq[0]); | ||
789 | |||
790 | aaci = card->private_data; | ||
791 | init_MUTEX(&aaci->ac97_sem); | ||
792 | spin_lock_init(&aaci->lock); | ||
793 | aaci->card = card; | ||
794 | aaci->dev = dev; | ||
795 | |||
796 | /* Set MAINCR to allow slot 1 and 2 data IO */ | ||
797 | aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN | | ||
798 | MAINCR_SL2RXEN | MAINCR_SL2TXEN; | ||
799 | |||
800 | return aaci; | ||
801 | } | ||
802 | |||
803 | static int __devinit aaci_init_pcm(struct aaci *aaci) | ||
804 | { | ||
805 | snd_pcm_t *pcm; | ||
806 | int ret; | ||
807 | |||
808 | ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 0, &pcm); | ||
809 | if (ret == 0) { | ||
810 | aaci->pcm = pcm; | ||
811 | pcm->private_data = aaci; | ||
812 | pcm->info_flags = 0; | ||
813 | |||
814 | strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name)); | ||
815 | |||
816 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); | ||
817 | } | ||
818 | |||
819 | return ret; | ||
820 | } | ||
821 | |||
822 | static unsigned int __devinit aaci_size_fifo(struct aaci *aaci) | ||
823 | { | ||
824 | void *base = aaci->base + AACI_CSCH1; | ||
825 | int i; | ||
826 | |||
827 | writel(TXCR_FEN | TXCR_TSZ16 | TXCR_TXEN, base + AACI_TXCR); | ||
828 | |||
829 | for (i = 0; !(readl(base + AACI_SR) & SR_TXFF) && i < 4096; i++) | ||
830 | writel(0, aaci->base + AACI_DR1); | ||
831 | |||
832 | writel(0, base + AACI_TXCR); | ||
833 | |||
834 | /* | ||
835 | * Re-initialise the AACI after the FIFO depth test, to | ||
836 | * ensure that the FIFOs are empty. Unfortunately, merely | ||
837 | * disabling the channel doesn't clear the FIFO. | ||
838 | */ | ||
839 | writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR); | ||
840 | writel(aaci->maincr, aaci->base + AACI_MAINCR); | ||
841 | |||
842 | /* | ||
843 | * If we hit 4096, we failed. Go back to the specified | ||
844 | * fifo depth. | ||
845 | */ | ||
846 | if (i == 4096) | ||
847 | i = 8; | ||
848 | |||
849 | return i; | ||
850 | } | ||
851 | |||
852 | static int __devinit aaci_probe(struct amba_device *dev, void *id) | ||
853 | { | ||
854 | struct aaci *aaci; | ||
855 | int ret, i; | ||
856 | |||
857 | ret = amba_request_regions(dev, NULL); | ||
858 | if (ret) | ||
859 | return ret; | ||
860 | |||
861 | aaci = aaci_init_card(dev); | ||
862 | if (IS_ERR(aaci)) { | ||
863 | ret = PTR_ERR(aaci); | ||
864 | goto out; | ||
865 | } | ||
866 | |||
867 | aaci->base = ioremap(dev->res.start, SZ_4K); | ||
868 | if (!aaci->base) { | ||
869 | ret = -ENOMEM; | ||
870 | goto out; | ||
871 | } | ||
872 | |||
873 | /* | ||
874 | * Playback uses AACI channel 0 | ||
875 | */ | ||
876 | aaci->playback.base = aaci->base + AACI_CSCH1; | ||
877 | aaci->playback.fifo = aaci->base + AACI_DR1; | ||
878 | |||
879 | for (i = 0; i < 4; i++) { | ||
880 | void *base = aaci->base + i * 0x14; | ||
881 | |||
882 | writel(0, base + AACI_IE); | ||
883 | writel(0, base + AACI_TXCR); | ||
884 | writel(0, base + AACI_RXCR); | ||
885 | } | ||
886 | |||
887 | writel(0x1fff, aaci->base + AACI_INTCLR); | ||
888 | writel(aaci->maincr, aaci->base + AACI_MAINCR); | ||
889 | |||
890 | /* | ||
891 | * Size the FIFOs. | ||
892 | */ | ||
893 | aaci->fifosize = aaci_size_fifo(aaci); | ||
894 | |||
895 | ret = aaci_probe_ac97(aaci); | ||
896 | if (ret) | ||
897 | goto out; | ||
898 | |||
899 | ret = aaci_init_pcm(aaci); | ||
900 | if (ret) | ||
901 | goto out; | ||
902 | |||
903 | ret = snd_card_register(aaci->card); | ||
904 | if (ret == 0) { | ||
905 | dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname, | ||
906 | aaci->fifosize); | ||
907 | amba_set_drvdata(dev, aaci->card); | ||
908 | return ret; | ||
909 | } | ||
910 | |||
911 | out: | ||
912 | if (aaci) | ||
913 | snd_card_free(aaci->card); | ||
914 | amba_release_regions(dev); | ||
915 | return ret; | ||
916 | } | ||
917 | |||
918 | static int __devexit aaci_remove(struct amba_device *dev) | ||
919 | { | ||
920 | snd_card_t *card = amba_get_drvdata(dev); | ||
921 | |||
922 | amba_set_drvdata(dev, NULL); | ||
923 | |||
924 | if (card) { | ||
925 | struct aaci *aaci = card->private_data; | ||
926 | writel(0, aaci->base + AACI_MAINCR); | ||
927 | |||
928 | snd_card_free(card); | ||
929 | amba_release_regions(dev); | ||
930 | } | ||
931 | |||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static struct amba_id aaci_ids[] = { | ||
936 | { | ||
937 | .id = 0x00041041, | ||
938 | .mask = 0x000fffff, | ||
939 | }, | ||
940 | { 0, 0 }, | ||
941 | }; | ||
942 | |||
943 | static struct amba_driver aaci_driver = { | ||
944 | .drv = { | ||
945 | .name = DRIVER_NAME, | ||
946 | }, | ||
947 | .probe = aaci_probe, | ||
948 | .remove = __devexit_p(aaci_remove), | ||
949 | .suspend = aaci_suspend, | ||
950 | .resume = aaci_resume, | ||
951 | .id_table = aaci_ids, | ||
952 | }; | ||
953 | |||
954 | static int __init aaci_init(void) | ||
955 | { | ||
956 | return amba_driver_register(&aaci_driver); | ||
957 | } | ||
958 | |||
959 | static void __exit aaci_exit(void) | ||
960 | { | ||
961 | amba_driver_unregister(&aaci_driver); | ||
962 | } | ||
963 | |||
964 | module_init(aaci_init); | ||
965 | module_exit(aaci_exit); | ||
966 | |||
967 | MODULE_LICENSE("GPL"); | ||
968 | MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver"); | ||