xref: /openbmc/linux/sound/arm/aaci.c (revision 5d350cba)
1cb5a6ffcSRussell King /*
2cb5a6ffcSRussell King  *  linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver
3cb5a6ffcSRussell King  *
4cb5a6ffcSRussell King  *  Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
5cb5a6ffcSRussell King  *
6cb5a6ffcSRussell King  * This program is free software; you can redistribute it and/or modify
7cb5a6ffcSRussell King  * it under the terms of the GNU General Public License version 2 as
8cb5a6ffcSRussell King  * published by the Free Software Foundation.
9cb5a6ffcSRussell King  *
10cb5a6ffcSRussell King  *  Documentation: ARM DDI 0173B
11cb5a6ffcSRussell King  */
12cb5a6ffcSRussell King #include <linux/module.h>
13cb5a6ffcSRussell King #include <linux/delay.h>
14cb5a6ffcSRussell King #include <linux/init.h>
15cb5a6ffcSRussell King #include <linux/ioport.h>
16cb5a6ffcSRussell King #include <linux/device.h>
17cb5a6ffcSRussell King #include <linux/spinlock.h>
18cb5a6ffcSRussell King #include <linux/interrupt.h>
19cb5a6ffcSRussell King #include <linux/err.h>
20a62c80e5SRussell King #include <linux/amba/bus.h>
2188cdca9cSRussell King #include <linux/io.h>
22cb5a6ffcSRussell King 
23cb5a6ffcSRussell King #include <sound/core.h>
24cb5a6ffcSRussell King #include <sound/initval.h>
25cb5a6ffcSRussell King #include <sound/ac97_codec.h>
26cb5a6ffcSRussell King #include <sound/pcm.h>
27cb5a6ffcSRussell King #include <sound/pcm_params.h>
28cb5a6ffcSRussell King 
29cb5a6ffcSRussell King #include "aaci.h"
30cb5a6ffcSRussell King 
31cb5a6ffcSRussell King #define DRIVER_NAME	"aaci-pl041"
32cb5a6ffcSRussell King 
33250c7a61SRussell King #define FRAME_PERIOD_US	21
34250c7a61SRussell King 
35cb5a6ffcSRussell King /*
36cb5a6ffcSRussell King  * PM support is not complete.  Turn it off.
37cb5a6ffcSRussell King  */
38cb5a6ffcSRussell King #undef CONFIG_PM
39cb5a6ffcSRussell King 
40ceb9e476STakashi Iwai static void aaci_ac97_select_codec(struct aaci *aaci, struct snd_ac97 *ac97)
41cb5a6ffcSRussell King {
42cb5a6ffcSRussell King 	u32 v, maincr = aaci->maincr | MAINCR_SCRA(ac97->num);
43cb5a6ffcSRussell King 
44cb5a6ffcSRussell King 	/*
45cb5a6ffcSRussell King 	 * Ensure that the slot 1/2 RX registers are empty.
46cb5a6ffcSRussell King 	 */
47cb5a6ffcSRussell King 	v = readl(aaci->base + AACI_SLFR);
48cb5a6ffcSRussell King 	if (v & SLFR_2RXV)
49cb5a6ffcSRussell King 		readl(aaci->base + AACI_SL2RX);
50cb5a6ffcSRussell King 	if (v & SLFR_1RXV)
51cb5a6ffcSRussell King 		readl(aaci->base + AACI_SL1RX);
52cb5a6ffcSRussell King 
53cb5a6ffcSRussell King 	writel(maincr, aaci->base + AACI_MAINCR);
54cb5a6ffcSRussell King }
55cb5a6ffcSRussell King 
56cb5a6ffcSRussell King /*
57cb5a6ffcSRussell King  * P29:
58cb5a6ffcSRussell King  *  The recommended use of programming the external codec through slot 1
59cb5a6ffcSRussell King  *  and slot 2 data is to use the channels during setup routines and the
60cb5a6ffcSRussell King  *  slot register at any other time.  The data written into slot 1, slot 2
61cb5a6ffcSRussell King  *  and slot 12 registers is transmitted only when their corresponding
62cb5a6ffcSRussell King  *  SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR
63cb5a6ffcSRussell King  *  register.
64cb5a6ffcSRussell King  */
6514d178a1SKevin Hilman static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
6614d178a1SKevin Hilman 			    unsigned short val)
67cb5a6ffcSRussell King {
68cb5a6ffcSRussell King 	struct aaci *aaci = ac97->private_data;
69250c7a61SRussell King 	int timeout;
70cb5a6ffcSRussell King 	u32 v;
71cb5a6ffcSRussell King 
72cb5a6ffcSRussell King 	if (ac97->num >= 4)
73cb5a6ffcSRussell King 		return;
74cb5a6ffcSRussell King 
7512aa7579SIngo Molnar 	mutex_lock(&aaci->ac97_sem);
76cb5a6ffcSRussell King 
77cb5a6ffcSRussell King 	aaci_ac97_select_codec(aaci, ac97);
78cb5a6ffcSRussell King 
79cb5a6ffcSRussell King 	/*
80cb5a6ffcSRussell King 	 * P54: You must ensure that AACI_SL2TX is always written
81cb5a6ffcSRussell King 	 * to, if required, before data is written to AACI_SL1TX.
82cb5a6ffcSRussell King 	 */
83cb5a6ffcSRussell King 	writel(val << 4, aaci->base + AACI_SL2TX);
84cb5a6ffcSRussell King 	writel(reg << 12, aaci->base + AACI_SL1TX);
85cb5a6ffcSRussell King 
86250c7a61SRussell King 	/* Initially, wait one frame period */
87250c7a61SRussell King 	udelay(FRAME_PERIOD_US);
88250c7a61SRussell King 
89250c7a61SRussell King 	/* And then wait an additional eight frame periods for it to be sent */
90250c7a61SRussell King 	timeout = FRAME_PERIOD_US * 8;
91cb5a6ffcSRussell King 	do {
92250c7a61SRussell King 		udelay(1);
93cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SLFR);
94f6f35bbeSRoel Kluin 	} while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout);
9514d178a1SKevin Hilman 
9669058cd6SRussell King 	if (v & (SLFR_1TXB|SLFR_2TXB))
9714d178a1SKevin Hilman 		dev_err(&aaci->dev->dev,
9814d178a1SKevin Hilman 			"timeout waiting for write to complete\n");
99cb5a6ffcSRussell King 
10012aa7579SIngo Molnar 	mutex_unlock(&aaci->ac97_sem);
101cb5a6ffcSRussell King }
102cb5a6ffcSRussell King 
103cb5a6ffcSRussell King /*
104cb5a6ffcSRussell King  * Read an AC'97 register.
105cb5a6ffcSRussell King  */
106ceb9e476STakashi Iwai static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
107cb5a6ffcSRussell King {
108cb5a6ffcSRussell King 	struct aaci *aaci = ac97->private_data;
109250c7a61SRussell King 	int timeout, retries = 10;
110cb5a6ffcSRussell King 	u32 v;
111cb5a6ffcSRussell King 
112cb5a6ffcSRussell King 	if (ac97->num >= 4)
113cb5a6ffcSRussell King 		return ~0;
114cb5a6ffcSRussell King 
11512aa7579SIngo Molnar 	mutex_lock(&aaci->ac97_sem);
116cb5a6ffcSRussell King 
117cb5a6ffcSRussell King 	aaci_ac97_select_codec(aaci, ac97);
118cb5a6ffcSRussell King 
119cb5a6ffcSRussell King 	/*
120cb5a6ffcSRussell King 	 * Write the register address to slot 1.
121cb5a6ffcSRussell King 	 */
122cb5a6ffcSRussell King 	writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX);
123cb5a6ffcSRussell King 
124250c7a61SRussell King 	/* Initially, wait one frame period */
125250c7a61SRussell King 	udelay(FRAME_PERIOD_US);
126250c7a61SRussell King 
127250c7a61SRussell King 	/* And then wait an additional eight frame periods for it to be sent */
128250c7a61SRussell King 	timeout = FRAME_PERIOD_US * 8;
129cb5a6ffcSRussell King 	do {
130250c7a61SRussell King 		udelay(1);
131cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SLFR);
132f6f35bbeSRoel Kluin 	} while ((v & SLFR_1TXB) && --timeout);
13314d178a1SKevin Hilman 
13469058cd6SRussell King 	if (v & SLFR_1TXB) {
13514d178a1SKevin Hilman 		dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n");
13614d178a1SKevin Hilman 		v = ~0;
13714d178a1SKevin Hilman 		goto out;
13814d178a1SKevin Hilman 	}
139cb5a6ffcSRussell King 
140250c7a61SRussell King 	/* Now wait for the response frame */
141250c7a61SRussell King 	udelay(FRAME_PERIOD_US);
142cb5a6ffcSRussell King 
143250c7a61SRussell King 	/* And then wait an additional eight frame periods for data */
144250c7a61SRussell King 	timeout = FRAME_PERIOD_US * 8;
145cb5a6ffcSRussell King 	do {
146250c7a61SRussell King 		udelay(1);
147cb5a6ffcSRussell King 		cond_resched();
148cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
149f6f35bbeSRoel Kluin 	} while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout);
150cb5a6ffcSRussell King 
15169058cd6SRussell King 	if (v != (SLFR_1RXV|SLFR_2RXV)) {
15214d178a1SKevin Hilman 		dev_err(&aaci->dev->dev, "timeout on RX valid\n");
15314d178a1SKevin Hilman 		v = ~0;
15414d178a1SKevin Hilman 		goto out;
15514d178a1SKevin Hilman 	}
15614d178a1SKevin Hilman 
15714d178a1SKevin Hilman 	do {
158cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SL1RX) >> 12;
159cb5a6ffcSRussell King 		if (v == reg) {
160cb5a6ffcSRussell King 			v = readl(aaci->base + AACI_SL2RX) >> 4;
16114d178a1SKevin Hilman 			break;
16214d178a1SKevin Hilman 		} else if (--retries) {
16314d178a1SKevin Hilman 			dev_warn(&aaci->dev->dev,
16414d178a1SKevin Hilman 				 "ac97 read back fail.  retry\n");
16514d178a1SKevin Hilman 			continue;
166cb5a6ffcSRussell King 		} else {
16714d178a1SKevin Hilman 			dev_warn(&aaci->dev->dev,
168cb5a6ffcSRussell King 				"wrong ac97 register read back (%x != %x)\n",
169cb5a6ffcSRussell King 				v, reg);
170cb5a6ffcSRussell King 			v = ~0;
171cb5a6ffcSRussell King 		}
17214d178a1SKevin Hilman 	} while (retries);
17314d178a1SKevin Hilman  out:
17412aa7579SIngo Molnar 	mutex_unlock(&aaci->ac97_sem);
175cb5a6ffcSRussell King 	return v;
176cb5a6ffcSRussell King }
177cb5a6ffcSRussell King 
178d6a89fefSRussell King static inline void
179d6a89fefSRussell King aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask)
180cb5a6ffcSRussell King {
181cb5a6ffcSRussell King 	u32 val;
182cb5a6ffcSRussell King 	int timeout = 5000;
183cb5a6ffcSRussell King 
184cb5a6ffcSRussell King 	do {
185250c7a61SRussell King 		udelay(1);
186cb5a6ffcSRussell King 		val = readl(aacirun->base + AACI_SR);
187d6a89fefSRussell King 	} while (val & mask && timeout--);
188cb5a6ffcSRussell King }
189cb5a6ffcSRussell King 
190cb5a6ffcSRussell King 
191cb5a6ffcSRussell King 
192cb5a6ffcSRussell King /*
193cb5a6ffcSRussell King  * Interrupt support.
194cb5a6ffcSRussell King  */
19562578cbfSKevin Hilman static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
196cb5a6ffcSRussell King {
19741762b8cSKevin Hilman 	if (mask & ISR_ORINTR) {
19841762b8cSKevin Hilman 		dev_warn(&aaci->dev->dev, "RX overrun on chan %d\n", channel);
19941762b8cSKevin Hilman 		writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR);
20041762b8cSKevin Hilman 	}
20141762b8cSKevin Hilman 
20241762b8cSKevin Hilman 	if (mask & ISR_RXTOINTR) {
20341762b8cSKevin Hilman 		dev_warn(&aaci->dev->dev, "RX timeout on chan %d\n", channel);
20441762b8cSKevin Hilman 		writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR);
20541762b8cSKevin Hilman 	}
20641762b8cSKevin Hilman 
20741762b8cSKevin Hilman 	if (mask & ISR_RXINTR) {
20841762b8cSKevin Hilman 		struct aaci_runtime *aacirun = &aaci->capture;
209ea51d0b1SRussell King 		bool period_elapsed = false;
21041762b8cSKevin Hilman 		void *ptr;
21141762b8cSKevin Hilman 
21241762b8cSKevin Hilman 		if (!aacirun->substream || !aacirun->start) {
213898eb71cSJoe Perches 			dev_warn(&aaci->dev->dev, "RX interrupt???\n");
21441762b8cSKevin Hilman 			writel(0, aacirun->base + AACI_IE);
21541762b8cSKevin Hilman 			return;
21641762b8cSKevin Hilman 		}
21741762b8cSKevin Hilman 
218d6a89fefSRussell King 		spin_lock(&aacirun->lock);
219d6a89fefSRussell King 
220d6a89fefSRussell King 		ptr = aacirun->ptr;
22141762b8cSKevin Hilman 		do {
2225d350cbaSRussell King 			unsigned int len = aacirun->fifo_bytes;
22341762b8cSKevin Hilman 			u32 val;
22441762b8cSKevin Hilman 
22541762b8cSKevin Hilman 			if (aacirun->bytes <= 0) {
22641762b8cSKevin Hilman 				aacirun->bytes += aacirun->period;
227ea51d0b1SRussell King 				period_elapsed = true;
22841762b8cSKevin Hilman 			}
22941762b8cSKevin Hilman 			if (!(aacirun->cr & CR_EN))
23041762b8cSKevin Hilman 				break;
23141762b8cSKevin Hilman 
23241762b8cSKevin Hilman 			val = readl(aacirun->base + AACI_SR);
23341762b8cSKevin Hilman 			if (!(val & SR_RXHF))
23441762b8cSKevin Hilman 				break;
23541762b8cSKevin Hilman 			if (!(val & SR_RXFF))
23641762b8cSKevin Hilman 				len >>= 1;
23741762b8cSKevin Hilman 
23841762b8cSKevin Hilman 			aacirun->bytes -= len;
23941762b8cSKevin Hilman 
24041762b8cSKevin Hilman 			/* reading 16 bytes at a time */
24141762b8cSKevin Hilman 			for( ; len > 0; len -= 16) {
24241762b8cSKevin Hilman 				asm(
24341762b8cSKevin Hilman 					"ldmia	%1, {r0, r1, r2, r3}\n\t"
24441762b8cSKevin Hilman 					"stmia	%0!, {r0, r1, r2, r3}"
24541762b8cSKevin Hilman 					: "+r" (ptr)
24641762b8cSKevin Hilman 					: "r" (aacirun->fifo)
24741762b8cSKevin Hilman 					: "r0", "r1", "r2", "r3", "cc");
24841762b8cSKevin Hilman 
24941762b8cSKevin Hilman 				if (ptr >= aacirun->end)
25041762b8cSKevin Hilman 					ptr = aacirun->start;
25141762b8cSKevin Hilman 			}
25241762b8cSKevin Hilman 		} while(1);
253d6a89fefSRussell King 
25441762b8cSKevin Hilman 		aacirun->ptr = ptr;
255d6a89fefSRussell King 
256d6a89fefSRussell King 		spin_unlock(&aacirun->lock);
257ea51d0b1SRussell King 
258ea51d0b1SRussell King 		if (period_elapsed)
259ea51d0b1SRussell King 			snd_pcm_period_elapsed(aacirun->substream);
26041762b8cSKevin Hilman 	}
26141762b8cSKevin Hilman 
262cb5a6ffcSRussell King 	if (mask & ISR_URINTR) {
26362578cbfSKevin Hilman 		dev_dbg(&aaci->dev->dev, "TX underrun on chan %d\n", channel);
26462578cbfSKevin Hilman 		writel(ICLR_TXUEC1 << channel, aaci->base + AACI_INTCLR);
265cb5a6ffcSRussell King 	}
266cb5a6ffcSRussell King 
267cb5a6ffcSRussell King 	if (mask & ISR_TXINTR) {
268cb5a6ffcSRussell King 		struct aaci_runtime *aacirun = &aaci->playback;
269ea51d0b1SRussell King 		bool period_elapsed = false;
270cb5a6ffcSRussell King 		void *ptr;
271cb5a6ffcSRussell King 
272cb5a6ffcSRussell King 		if (!aacirun->substream || !aacirun->start) {
273898eb71cSJoe Perches 			dev_warn(&aaci->dev->dev, "TX interrupt???\n");
274cb5a6ffcSRussell King 			writel(0, aacirun->base + AACI_IE);
275cb5a6ffcSRussell King 			return;
276cb5a6ffcSRussell King 		}
277cb5a6ffcSRussell King 
278d6a89fefSRussell King 		spin_lock(&aacirun->lock);
279d6a89fefSRussell King 
280cb5a6ffcSRussell King 		ptr = aacirun->ptr;
281cb5a6ffcSRussell King 		do {
2825d350cbaSRussell King 			unsigned int len = aacirun->fifo_bytes;
283cb5a6ffcSRussell King 			u32 val;
284cb5a6ffcSRussell King 
285cb5a6ffcSRussell King 			if (aacirun->bytes <= 0) {
286cb5a6ffcSRussell King 				aacirun->bytes += aacirun->period;
287ea51d0b1SRussell King 				period_elapsed = true;
288cb5a6ffcSRussell King 			}
28941762b8cSKevin Hilman 			if (!(aacirun->cr & CR_EN))
290cb5a6ffcSRussell King 				break;
291cb5a6ffcSRussell King 
292cb5a6ffcSRussell King 			val = readl(aacirun->base + AACI_SR);
293cb5a6ffcSRussell King 			if (!(val & SR_TXHE))
294cb5a6ffcSRussell King 				break;
295cb5a6ffcSRussell King 			if (!(val & SR_TXFE))
296cb5a6ffcSRussell King 				len >>= 1;
297cb5a6ffcSRussell King 
298cb5a6ffcSRussell King 			aacirun->bytes -= len;
299cb5a6ffcSRussell King 
300cb5a6ffcSRussell King 			/* writing 16 bytes at a time */
301cb5a6ffcSRussell King 			for ( ; len > 0; len -= 16) {
302cb5a6ffcSRussell King 				asm(
303cb5a6ffcSRussell King 					"ldmia	%0!, {r0, r1, r2, r3}\n\t"
304cb5a6ffcSRussell King 					"stmia	%1, {r0, r1, r2, r3}"
305cb5a6ffcSRussell King 					: "+r" (ptr)
306cb5a6ffcSRussell King 					: "r" (aacirun->fifo)
307cb5a6ffcSRussell King 					: "r0", "r1", "r2", "r3", "cc");
308cb5a6ffcSRussell King 
309cb5a6ffcSRussell King 				if (ptr >= aacirun->end)
310cb5a6ffcSRussell King 					ptr = aacirun->start;
311cb5a6ffcSRussell King 			}
312cb5a6ffcSRussell King 		} while (1);
313cb5a6ffcSRussell King 
314cb5a6ffcSRussell King 		aacirun->ptr = ptr;
315d6a89fefSRussell King 
316d6a89fefSRussell King 		spin_unlock(&aacirun->lock);
317ea51d0b1SRussell King 
318ea51d0b1SRussell King 		if (period_elapsed)
319ea51d0b1SRussell King 			snd_pcm_period_elapsed(aacirun->substream);
320cb5a6ffcSRussell King 	}
321cb5a6ffcSRussell King }
322cb5a6ffcSRussell King 
3237d12e780SDavid Howells static irqreturn_t aaci_irq(int irq, void *devid)
324cb5a6ffcSRussell King {
325cb5a6ffcSRussell King 	struct aaci *aaci = devid;
326cb5a6ffcSRussell King 	u32 mask;
327cb5a6ffcSRussell King 	int i;
328cb5a6ffcSRussell King 
329cb5a6ffcSRussell King 	mask = readl(aaci->base + AACI_ALLINTS);
330cb5a6ffcSRussell King 	if (mask) {
331cb5a6ffcSRussell King 		u32 m = mask;
332cb5a6ffcSRussell King 		for (i = 0; i < 4; i++, m >>= 7) {
333cb5a6ffcSRussell King 			if (m & 0x7f) {
33462578cbfSKevin Hilman 				aaci_fifo_irq(aaci, i, m);
335cb5a6ffcSRussell King 			}
336cb5a6ffcSRussell King 		}
337cb5a6ffcSRussell King 	}
338cb5a6ffcSRussell King 
339cb5a6ffcSRussell King 	return mask ? IRQ_HANDLED : IRQ_NONE;
340cb5a6ffcSRussell King }
341cb5a6ffcSRussell King 
342cb5a6ffcSRussell King 
343cb5a6ffcSRussell King 
344cb5a6ffcSRussell King /*
345cb5a6ffcSRussell King  * ALSA support.
346cb5a6ffcSRussell King  */
347ceb9e476STakashi Iwai static struct snd_pcm_hardware aaci_hw_info = {
348cb5a6ffcSRussell King 	.info			= SNDRV_PCM_INFO_MMAP |
349cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_MMAP_VALID |
350cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_INTERLEAVED |
351cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_BLOCK_TRANSFER |
352cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_RESUME,
353cb5a6ffcSRussell King 
354cb5a6ffcSRussell King 	/*
355cb5a6ffcSRussell King 	 * ALSA doesn't support 18-bit or 20-bit packed into 32-bit
356cb5a6ffcSRussell King 	 * words.  It also doesn't support 12-bit at all.
357cb5a6ffcSRussell King 	 */
358cb5a6ffcSRussell King 	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
359cb5a6ffcSRussell King 
3606ca867c8SRussell King 	/* rates are setup from the AC'97 codec */
361cb5a6ffcSRussell King 	.channels_min		= 2,
362e831d80bSRussell King 	.channels_max		= 2,
363cb5a6ffcSRussell King 	.buffer_bytes_max	= 64 * 1024,
364cb5a6ffcSRussell King 	.period_bytes_min	= 256,
365cb5a6ffcSRussell King 	.period_bytes_max	= PAGE_SIZE,
366cb5a6ffcSRussell King 	.periods_min		= 4,
367cb5a6ffcSRussell King 	.periods_max		= PAGE_SIZE / 16,
368cb5a6ffcSRussell King };
369cb5a6ffcSRussell King 
370e831d80bSRussell King /*
371e831d80bSRussell King  * We can support two and four channel audio.  Unfortunately
372e831d80bSRussell King  * six channel audio requires a non-standard channel ordering:
373e831d80bSRussell King  *   2 -> FL(3), FR(4)
374e831d80bSRussell King  *   4 -> FL(3), FR(4), SL(7), SR(8)
375e831d80bSRussell King  *   6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required)
376e831d80bSRussell King  *        FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual)
377e831d80bSRussell King  * This requires an ALSA configuration file to correct.
378e831d80bSRussell King  */
379e831d80bSRussell King static int aaci_rule_channels(struct snd_pcm_hw_params *p,
380e831d80bSRussell King 	struct snd_pcm_hw_rule *rule)
381e831d80bSRussell King {
382e831d80bSRussell King 	static unsigned int channel_list[] = { 2, 4, 6 };
383e831d80bSRussell King 	struct aaci *aaci = rule->private;
384e831d80bSRussell King 	unsigned int mask = 1 << 0, slots;
385e831d80bSRussell King 
386e831d80bSRussell King 	/* pcms[0] is the our 5.1 PCM instance. */
387e831d80bSRussell King 	slots = aaci->ac97_bus->pcms[0].r[0].slots;
388e831d80bSRussell King 	if (slots & (1 << AC97_SLOT_PCM_SLEFT)) {
389e831d80bSRussell King 		mask |= 1 << 1;
390e831d80bSRussell King 		if (slots & (1 << AC97_SLOT_LFE))
391e831d80bSRussell King 			mask |= 1 << 2;
392e831d80bSRussell King 	}
393e831d80bSRussell King 
394e831d80bSRussell King 	return snd_interval_list(hw_param_interval(p, rule->var),
395e831d80bSRussell King 				 ARRAY_SIZE(channel_list), channel_list, mask);
396e831d80bSRussell King }
397e831d80bSRussell King 
398e831d80bSRussell King static int aaci_pcm_open(struct snd_pcm_substream *substream)
399cb5a6ffcSRussell King {
400ceb9e476STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
401e831d80bSRussell King 	struct aaci *aaci = substream->private_data;
402e831d80bSRussell King 	struct aaci_runtime *aacirun;
403b60fb519SRussell King 	int ret = 0;
404cb5a6ffcSRussell King 
405e831d80bSRussell King 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
406e831d80bSRussell King 		aacirun = &aaci->playback;
407e831d80bSRussell King 	} else {
408e831d80bSRussell King 		aacirun = &aaci->capture;
409e831d80bSRussell King 	}
410e831d80bSRussell King 
411cb5a6ffcSRussell King 	aacirun->substream = substream;
412cb5a6ffcSRussell King 	runtime->private_data = aacirun;
413cb5a6ffcSRussell King 	runtime->hw = aaci_hw_info;
4146ca867c8SRussell King 	runtime->hw.rates = aacirun->pcm->rates;
4156ca867c8SRussell King 	snd_pcm_limit_hw_rates(runtime);
416cb5a6ffcSRussell King 
417e831d80bSRussell King 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
418e831d80bSRussell King 		runtime->hw.channels_max = 6;
419e831d80bSRussell King 
420e831d80bSRussell King 		/* Add rule describing channel dependency. */
421e831d80bSRussell King 		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
422e831d80bSRussell King 					  SNDRV_PCM_HW_PARAM_CHANNELS,
423e831d80bSRussell King 					  aaci_rule_channels, aaci,
424e831d80bSRussell King 					  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
425e831d80bSRussell King 		if (ret)
426e831d80bSRussell King 			return ret;
427e831d80bSRussell King 
428e831d80bSRussell King 		if (aacirun->pcm->r[1].slots)
429a08d5658SRussell King 			snd_ac97_pcm_double_rate_rules(runtime);
430e831d80bSRussell King 	}
431a08d5658SRussell King 
432cb5a6ffcSRussell King 	/*
4335d350cbaSRussell King 	 * ALSA wants the byte-size of the FIFOs.  As we only support
4345d350cbaSRussell King 	 * 16-bit samples, this is twice the FIFO depth irrespective
4355d350cbaSRussell King 	 * of whether it's in compact mode or not.
436cb5a6ffcSRussell King 	 */
4375d350cbaSRussell King 	runtime->hw.fifo_size = aaci->fifo_depth * 2;
438cb5a6ffcSRussell King 
439b60fb519SRussell King 	mutex_lock(&aaci->irq_lock);
440b60fb519SRussell King 	if (!aaci->users++) {
441b60fb519SRussell King 		ret = request_irq(aaci->dev->irq[0], aaci_irq,
442b60fb519SRussell King 			   IRQF_SHARED | IRQF_DISABLED, DRIVER_NAME, aaci);
443b60fb519SRussell King 		if (ret != 0)
444b60fb519SRussell King 			aaci->users--;
445b60fb519SRussell King 	}
446b60fb519SRussell King 	mutex_unlock(&aaci->irq_lock);
447cb5a6ffcSRussell King 
448cb5a6ffcSRussell King 	return ret;
449cb5a6ffcSRussell King }
450cb5a6ffcSRussell King 
451cb5a6ffcSRussell King 
452cb5a6ffcSRussell King /*
453cb5a6ffcSRussell King  * Common ALSA stuff
454cb5a6ffcSRussell King  */
455ceb9e476STakashi Iwai static int aaci_pcm_close(struct snd_pcm_substream *substream)
456cb5a6ffcSRussell King {
457cb5a6ffcSRussell King 	struct aaci *aaci = substream->private_data;
458cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
459cb5a6ffcSRussell King 
46041762b8cSKevin Hilman 	WARN_ON(aacirun->cr & CR_EN);
461cb5a6ffcSRussell King 
462cb5a6ffcSRussell King 	aacirun->substream = NULL;
463b60fb519SRussell King 
464b60fb519SRussell King 	mutex_lock(&aaci->irq_lock);
465b60fb519SRussell King 	if (!--aaci->users)
466cb5a6ffcSRussell King 		free_irq(aaci->dev->irq[0], aaci);
467b60fb519SRussell King 	mutex_unlock(&aaci->irq_lock);
468cb5a6ffcSRussell King 
469cb5a6ffcSRussell King 	return 0;
470cb5a6ffcSRussell King }
471cb5a6ffcSRussell King 
472ceb9e476STakashi Iwai static int aaci_pcm_hw_free(struct snd_pcm_substream *substream)
473cb5a6ffcSRussell King {
474cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
475cb5a6ffcSRussell King 
476cb5a6ffcSRussell King 	/*
477cb5a6ffcSRussell King 	 * This must not be called with the device enabled.
478cb5a6ffcSRussell King 	 */
47941762b8cSKevin Hilman 	WARN_ON(aacirun->cr & CR_EN);
480cb5a6ffcSRussell King 
481cb5a6ffcSRussell King 	if (aacirun->pcm_open)
482cb5a6ffcSRussell King 		snd_ac97_pcm_close(aacirun->pcm);
483cb5a6ffcSRussell King 	aacirun->pcm_open = 0;
484cb5a6ffcSRussell King 
485cb5a6ffcSRussell King 	/*
486cb5a6ffcSRussell King 	 * Clear out the DMA and any allocated buffers.
487cb5a6ffcSRussell King 	 */
488d6797322STakashi Iwai 	snd_pcm_lib_free_pages(substream);
489cb5a6ffcSRussell King 
490cb5a6ffcSRussell King 	return 0;
491cb5a6ffcSRussell King }
492cb5a6ffcSRussell King 
49358e8a474SRussell King /* Channel to slot mask */
49458e8a474SRussell King static const u32 channels_to_slotmask[] = {
49558e8a474SRussell King 	[2] = CR_SL3 | CR_SL4,
49658e8a474SRussell King 	[4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8,
49758e8a474SRussell King 	[6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9,
49858e8a474SRussell King };
49958e8a474SRussell King 
500ceb9e476STakashi Iwai static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
501ceb9e476STakashi Iwai 			      struct snd_pcm_hw_params *params)
502cb5a6ffcSRussell King {
50358e8a474SRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
50458e8a474SRussell King 	unsigned int channels = params_channels(params);
50558e8a474SRussell King 	unsigned int rate = params_rate(params);
50658e8a474SRussell King 	int dbl = rate > 48000;
507cb5a6ffcSRussell King 	int err;
508cb5a6ffcSRussell King 
509cb5a6ffcSRussell King 	aaci_pcm_hw_free(substream);
5104acd57c3SRussell King 	if (aacirun->pcm_open) {
5114acd57c3SRussell King 		snd_ac97_pcm_close(aacirun->pcm);
5124acd57c3SRussell King 		aacirun->pcm_open = 0;
5134acd57c3SRussell King 	}
514cb5a6ffcSRussell King 
51558e8a474SRussell King 	/* channels is already limited to 2, 4, or 6 by aaci_rule_channels */
51658e8a474SRussell King 	if (dbl && channels != 2)
51758e8a474SRussell King 		return -EINVAL;
51858e8a474SRussell King 
519d6797322STakashi Iwai 	err = snd_pcm_lib_malloc_pages(substream,
520cb5a6ffcSRussell King 				       params_buffer_bytes(params));
5214e30b691SRussell King 	if (err >= 0) {
52258e8a474SRussell King 		struct aaci *aaci = substream->private_data;
523a08d5658SRussell King 
52458e8a474SRussell King 		err = snd_ac97_pcm_open(aacirun->pcm, rate, channels,
525a08d5658SRussell King 					aacirun->pcm->r[dbl].slots);
526cb5a6ffcSRussell King 
5274e30b691SRussell King 		aacirun->pcm_open = err == 0;
528d3aee799SRussell King 		aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16;
52958e8a474SRussell King 		aacirun->cr |= channels_to_slotmask[channels + dbl * 2];
530d3aee799SRussell King 
5315d350cbaSRussell King 		/*
5325d350cbaSRussell King 		 * fifo_bytes is the number of bytes we transfer to/from
5335d350cbaSRussell King 		 * the FIFO, including padding.  So that's x4.  As we're
5345d350cbaSRussell King 		 * in compact mode, the FIFO is half the size.
5355d350cbaSRussell King 		 */
5365d350cbaSRussell King 		aacirun->fifo_bytes = aaci->fifo_depth * 4 / 2;
5374e30b691SRussell King 	}
538cb5a6ffcSRussell King 
539cb5a6ffcSRussell King 	return err;
540cb5a6ffcSRussell King }
541cb5a6ffcSRussell King 
542ceb9e476STakashi Iwai static int aaci_pcm_prepare(struct snd_pcm_substream *substream)
543cb5a6ffcSRussell King {
544ceb9e476STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
545cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = runtime->private_data;
546cb5a6ffcSRussell King 
547c0dea82cSRussell King 	aacirun->period	= snd_pcm_lib_period_bytes(substream);
5484e30b691SRussell King 	aacirun->start	= runtime->dma_area;
54988cdca9cSRussell King 	aacirun->end	= aacirun->start + snd_pcm_lib_buffer_bytes(substream);
550cb5a6ffcSRussell King 	aacirun->ptr	= aacirun->start;
551c0dea82cSRussell King 	aacirun->bytes	= aacirun->period;
552cb5a6ffcSRussell King 
553cb5a6ffcSRussell King 	return 0;
554cb5a6ffcSRussell King }
555cb5a6ffcSRussell King 
556ceb9e476STakashi Iwai static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream)
557cb5a6ffcSRussell King {
558ceb9e476STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
559cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = runtime->private_data;
560cb5a6ffcSRussell King 	ssize_t bytes = aacirun->ptr - aacirun->start;
561cb5a6ffcSRussell King 
562cb5a6ffcSRussell King 	return bytes_to_frames(runtime, bytes);
563cb5a6ffcSRussell King }
564cb5a6ffcSRussell King 
565cb5a6ffcSRussell King 
566cb5a6ffcSRussell King /*
567cb5a6ffcSRussell King  * Playback specific ALSA stuff
568cb5a6ffcSRussell King  */
569cb5a6ffcSRussell King static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun)
570cb5a6ffcSRussell King {
571cb5a6ffcSRussell King 	u32 ie;
572cb5a6ffcSRussell King 
573cb5a6ffcSRussell King 	ie = readl(aacirun->base + AACI_IE);
574cb5a6ffcSRussell King 	ie &= ~(IE_URIE|IE_TXIE);
575cb5a6ffcSRussell King 	writel(ie, aacirun->base + AACI_IE);
57641762b8cSKevin Hilman 	aacirun->cr &= ~CR_EN;
577d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_TXB);
578cb5a6ffcSRussell King 	writel(aacirun->cr, aacirun->base + AACI_TXCR);
579cb5a6ffcSRussell King }
580cb5a6ffcSRussell King 
581cb5a6ffcSRussell King static void aaci_pcm_playback_start(struct aaci_runtime *aacirun)
582cb5a6ffcSRussell King {
583cb5a6ffcSRussell King 	u32 ie;
584cb5a6ffcSRussell King 
585d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_TXB);
58641762b8cSKevin Hilman 	aacirun->cr |= CR_EN;
587cb5a6ffcSRussell King 
588cb5a6ffcSRussell King 	ie = readl(aacirun->base + AACI_IE);
589cb5a6ffcSRussell King 	ie |= IE_URIE | IE_TXIE;
590cb5a6ffcSRussell King 	writel(ie, aacirun->base + AACI_IE);
591cb5a6ffcSRussell King 	writel(aacirun->cr, aacirun->base + AACI_TXCR);
592cb5a6ffcSRussell King }
593cb5a6ffcSRussell King 
594ceb9e476STakashi Iwai static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
595cb5a6ffcSRussell King {
596cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
597cb5a6ffcSRussell King 	unsigned long flags;
598cb5a6ffcSRussell King 	int ret = 0;
599cb5a6ffcSRussell King 
600d6a89fefSRussell King 	spin_lock_irqsave(&aacirun->lock, flags);
601d6a89fefSRussell King 
602cb5a6ffcSRussell King 	switch (cmd) {
603cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_START:
604cb5a6ffcSRussell King 		aaci_pcm_playback_start(aacirun);
605cb5a6ffcSRussell King 		break;
606cb5a6ffcSRussell King 
607cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_RESUME:
608cb5a6ffcSRussell King 		aaci_pcm_playback_start(aacirun);
609cb5a6ffcSRussell King 		break;
610cb5a6ffcSRussell King 
611cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_STOP:
612cb5a6ffcSRussell King 		aaci_pcm_playback_stop(aacirun);
613cb5a6ffcSRussell King 		break;
614cb5a6ffcSRussell King 
615cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_SUSPEND:
616cb5a6ffcSRussell King 		aaci_pcm_playback_stop(aacirun);
617cb5a6ffcSRussell King 		break;
618cb5a6ffcSRussell King 
619cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
620cb5a6ffcSRussell King 		break;
621cb5a6ffcSRussell King 
622cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
623cb5a6ffcSRussell King 		break;
624cb5a6ffcSRussell King 
625cb5a6ffcSRussell King 	default:
626cb5a6ffcSRussell King 		ret = -EINVAL;
627cb5a6ffcSRussell King 	}
628d6a89fefSRussell King 
629d6a89fefSRussell King 	spin_unlock_irqrestore(&aacirun->lock, flags);
630cb5a6ffcSRussell King 
631cb5a6ffcSRussell King 	return ret;
632cb5a6ffcSRussell King }
633cb5a6ffcSRussell King 
634ceb9e476STakashi Iwai static struct snd_pcm_ops aaci_playback_ops = {
63541762b8cSKevin Hilman 	.open		= aaci_pcm_open,
636cb5a6ffcSRussell King 	.close		= aaci_pcm_close,
637cb5a6ffcSRussell King 	.ioctl		= snd_pcm_lib_ioctl,
63858e8a474SRussell King 	.hw_params	= aaci_pcm_hw_params,
639cb5a6ffcSRussell King 	.hw_free	= aaci_pcm_hw_free,
640cb5a6ffcSRussell King 	.prepare	= aaci_pcm_prepare,
641cb5a6ffcSRussell King 	.trigger	= aaci_pcm_playback_trigger,
642cb5a6ffcSRussell King 	.pointer	= aaci_pcm_pointer,
643cb5a6ffcSRussell King };
644cb5a6ffcSRussell King 
64541762b8cSKevin Hilman static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun)
64641762b8cSKevin Hilman {
64741762b8cSKevin Hilman 	u32 ie;
64841762b8cSKevin Hilman 
649d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_RXB);
65041762b8cSKevin Hilman 
65141762b8cSKevin Hilman 	ie = readl(aacirun->base + AACI_IE);
65241762b8cSKevin Hilman 	ie &= ~(IE_ORIE | IE_RXIE);
65341762b8cSKevin Hilman 	writel(ie, aacirun->base+AACI_IE);
65441762b8cSKevin Hilman 
65541762b8cSKevin Hilman 	aacirun->cr &= ~CR_EN;
65641762b8cSKevin Hilman 
65741762b8cSKevin Hilman 	writel(aacirun->cr, aacirun->base + AACI_RXCR);
65841762b8cSKevin Hilman }
65941762b8cSKevin Hilman 
66041762b8cSKevin Hilman static void aaci_pcm_capture_start(struct aaci_runtime *aacirun)
66141762b8cSKevin Hilman {
66241762b8cSKevin Hilman 	u32 ie;
66341762b8cSKevin Hilman 
664d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_RXB);
66541762b8cSKevin Hilman 
66641762b8cSKevin Hilman #ifdef DEBUG
66741762b8cSKevin Hilman 	/* RX Timeout value: bits 28:17 in RXCR */
66841762b8cSKevin Hilman 	aacirun->cr |= 0xf << 17;
66941762b8cSKevin Hilman #endif
67041762b8cSKevin Hilman 
67141762b8cSKevin Hilman 	aacirun->cr |= CR_EN;
67241762b8cSKevin Hilman 	writel(aacirun->cr, aacirun->base + AACI_RXCR);
67341762b8cSKevin Hilman 
67441762b8cSKevin Hilman 	ie = readl(aacirun->base + AACI_IE);
67541762b8cSKevin Hilman 	ie |= IE_ORIE |IE_RXIE; // overrun and rx interrupt -- half full
67641762b8cSKevin Hilman 	writel(ie, aacirun->base + AACI_IE);
67741762b8cSKevin Hilman }
67841762b8cSKevin Hilman 
6798a371840SRussell King static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
6808a371840SRussell King {
68141762b8cSKevin Hilman 	struct aaci_runtime *aacirun = substream->runtime->private_data;
68241762b8cSKevin Hilman 	unsigned long flags;
68341762b8cSKevin Hilman 	int ret = 0;
68441762b8cSKevin Hilman 
685d6a89fefSRussell King 	spin_lock_irqsave(&aacirun->lock, flags);
68641762b8cSKevin Hilman 
68741762b8cSKevin Hilman 	switch (cmd) {
68841762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_START:
68941762b8cSKevin Hilman 		aaci_pcm_capture_start(aacirun);
69041762b8cSKevin Hilman 		break;
69141762b8cSKevin Hilman 
69241762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_RESUME:
69341762b8cSKevin Hilman 		aaci_pcm_capture_start(aacirun);
69441762b8cSKevin Hilman 		break;
69541762b8cSKevin Hilman 
69641762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_STOP:
69741762b8cSKevin Hilman 		aaci_pcm_capture_stop(aacirun);
69841762b8cSKevin Hilman 		break;
69941762b8cSKevin Hilman 
70041762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_SUSPEND:
70141762b8cSKevin Hilman 		aaci_pcm_capture_stop(aacirun);
70241762b8cSKevin Hilman 		break;
70341762b8cSKevin Hilman 
70441762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
70541762b8cSKevin Hilman 		break;
70641762b8cSKevin Hilman 
70741762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
70841762b8cSKevin Hilman 		break;
70941762b8cSKevin Hilman 
71041762b8cSKevin Hilman 	default:
71141762b8cSKevin Hilman 		ret = -EINVAL;
71241762b8cSKevin Hilman 	}
71341762b8cSKevin Hilman 
714d6a89fefSRussell King 	spin_unlock_irqrestore(&aacirun->lock, flags);
71541762b8cSKevin Hilman 
71641762b8cSKevin Hilman 	return ret;
71741762b8cSKevin Hilman }
71841762b8cSKevin Hilman 
7198a371840SRussell King static int aaci_pcm_capture_prepare(struct snd_pcm_substream *substream)
72041762b8cSKevin Hilman {
72141762b8cSKevin Hilman 	struct snd_pcm_runtime *runtime = substream->runtime;
72241762b8cSKevin Hilman 	struct aaci *aaci = substream->private_data;
72341762b8cSKevin Hilman 
72441762b8cSKevin Hilman 	aaci_pcm_prepare(substream);
72541762b8cSKevin Hilman 
72641762b8cSKevin Hilman 	/* allow changing of sample rate */
72741762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_EXTENDED_STATUS, 0x0001); /* VRA */
72841762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
72941762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate);
73041762b8cSKevin Hilman 
73141762b8cSKevin Hilman 	/* Record select: Mic: 0, Aux: 3, Line: 4 */
73241762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_REC_SEL, 0x0404);
73341762b8cSKevin Hilman 
73441762b8cSKevin Hilman 	return 0;
73541762b8cSKevin Hilman }
73641762b8cSKevin Hilman 
7378a371840SRussell King static struct snd_pcm_ops aaci_capture_ops = {
73841762b8cSKevin Hilman 	.open		= aaci_pcm_open,
73941762b8cSKevin Hilman 	.close		= aaci_pcm_close,
74041762b8cSKevin Hilman 	.ioctl		= snd_pcm_lib_ioctl,
74158e8a474SRussell King 	.hw_params	= aaci_pcm_hw_params,
74241762b8cSKevin Hilman 	.hw_free	= aaci_pcm_hw_free,
74341762b8cSKevin Hilman 	.prepare	= aaci_pcm_capture_prepare,
74441762b8cSKevin Hilman 	.trigger	= aaci_pcm_capture_trigger,
74541762b8cSKevin Hilman 	.pointer	= aaci_pcm_pointer,
74641762b8cSKevin Hilman };
747cb5a6ffcSRussell King 
748cb5a6ffcSRussell King /*
749cb5a6ffcSRussell King  * Power Management.
750cb5a6ffcSRussell King  */
751cb5a6ffcSRussell King #ifdef CONFIG_PM
752ceb9e476STakashi Iwai static int aaci_do_suspend(struct snd_card *card, unsigned int state)
753cb5a6ffcSRussell King {
754cb5a6ffcSRussell King 	struct aaci *aaci = card->private_data;
755792a6c51STakashi Iwai 	snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
756cb5a6ffcSRussell King 	snd_pcm_suspend_all(aaci->pcm);
757cb5a6ffcSRussell King 	return 0;
758cb5a6ffcSRussell King }
759cb5a6ffcSRussell King 
760ceb9e476STakashi Iwai static int aaci_do_resume(struct snd_card *card, unsigned int state)
761cb5a6ffcSRussell King {
762792a6c51STakashi Iwai 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
763cb5a6ffcSRussell King 	return 0;
764cb5a6ffcSRussell King }
765cb5a6ffcSRussell King 
766e36d394dSRichard Purdie static int aaci_suspend(struct amba_device *dev, pm_message_t state)
767cb5a6ffcSRussell King {
768ceb9e476STakashi Iwai 	struct snd_card *card = amba_get_drvdata(dev);
769cb5a6ffcSRussell King 	return card ? aaci_do_suspend(card) : 0;
770cb5a6ffcSRussell King }
771cb5a6ffcSRussell King 
772cb5a6ffcSRussell King static int aaci_resume(struct amba_device *dev)
773cb5a6ffcSRussell King {
774ceb9e476STakashi Iwai 	struct snd_card *card = amba_get_drvdata(dev);
775cb5a6ffcSRussell King 	return card ? aaci_do_resume(card) : 0;
776cb5a6ffcSRussell King }
777cb5a6ffcSRussell King #else
778cb5a6ffcSRussell King #define aaci_do_suspend		NULL
779cb5a6ffcSRussell King #define aaci_do_resume		NULL
780cb5a6ffcSRussell King #define aaci_suspend		NULL
781cb5a6ffcSRussell King #define aaci_resume		NULL
782cb5a6ffcSRussell King #endif
783cb5a6ffcSRussell King 
784cb5a6ffcSRussell King 
785cb5a6ffcSRussell King static struct ac97_pcm ac97_defs[] __devinitdata = {
786cb5a6ffcSRussell King 	[0] = {	/* Front PCM */
787cb5a6ffcSRussell King 		.exclusive = 1,
788cb5a6ffcSRussell King 		.r = {
789cb5a6ffcSRussell King 			[0] = {
790cb5a6ffcSRussell King 				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
791cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_RIGHT) |
792cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_CENTER) |
793cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_SLEFT) |
794cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_SRIGHT) |
795cb5a6ffcSRussell King 					  (1 << AC97_SLOT_LFE),
796cb5a6ffcSRussell King 			},
797a08d5658SRussell King 			[1] = {
798a08d5658SRussell King 				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
799a08d5658SRussell King 					  (1 << AC97_SLOT_PCM_RIGHT) |
800a08d5658SRussell King 					  (1 << AC97_SLOT_PCM_LEFT_0) |
801a08d5658SRussell King 					  (1 << AC97_SLOT_PCM_RIGHT_0),
802a08d5658SRussell King 			},
803cb5a6ffcSRussell King 		},
804cb5a6ffcSRussell King 	},
805cb5a6ffcSRussell King 	[1] = {	/* PCM in */
806cb5a6ffcSRussell King 		.stream = 1,
807cb5a6ffcSRussell King 		.exclusive = 1,
808cb5a6ffcSRussell King 		.r = {
809cb5a6ffcSRussell King 			[0] = {
810cb5a6ffcSRussell King 				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
811cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_RIGHT),
812cb5a6ffcSRussell King 			},
813cb5a6ffcSRussell King 		},
814cb5a6ffcSRussell King 	},
815cb5a6ffcSRussell King 	[2] = {	/* Mic in */
816cb5a6ffcSRussell King 		.stream = 1,
817cb5a6ffcSRussell King 		.exclusive = 1,
818cb5a6ffcSRussell King 		.r = {
819cb5a6ffcSRussell King 			[0] = {
820cb5a6ffcSRussell King 				.slots	= (1 << AC97_SLOT_MIC),
821cb5a6ffcSRussell King 			},
822cb5a6ffcSRussell King 		},
823cb5a6ffcSRussell King 	}
824cb5a6ffcSRussell King };
825cb5a6ffcSRussell King 
826ceb9e476STakashi Iwai static struct snd_ac97_bus_ops aaci_bus_ops = {
827cb5a6ffcSRussell King 	.write	= aaci_ac97_write,
828cb5a6ffcSRussell King 	.read	= aaci_ac97_read,
829cb5a6ffcSRussell King };
830cb5a6ffcSRussell King 
831cb5a6ffcSRussell King static int __devinit aaci_probe_ac97(struct aaci *aaci)
832cb5a6ffcSRussell King {
833ceb9e476STakashi Iwai 	struct snd_ac97_template ac97_template;
834ceb9e476STakashi Iwai 	struct snd_ac97_bus *ac97_bus;
835ceb9e476STakashi Iwai 	struct snd_ac97 *ac97;
836cb5a6ffcSRussell King 	int ret;
837cb5a6ffcSRussell King 
838cb5a6ffcSRussell King 	/*
839cb5a6ffcSRussell King 	 * Assert AACIRESET for 2us
840cb5a6ffcSRussell King 	 */
841cb5a6ffcSRussell King 	writel(0, aaci->base + AACI_RESET);
842cb5a6ffcSRussell King 	udelay(2);
843cb5a6ffcSRussell King 	writel(RESET_NRST, aaci->base + AACI_RESET);
844cb5a6ffcSRussell King 
845cb5a6ffcSRussell King 	/*
846cb5a6ffcSRussell King 	 * Give the AC'97 codec more than enough time
847cb5a6ffcSRussell King 	 * to wake up. (42us = ~2 frames at 48kHz.)
848cb5a6ffcSRussell King 	 */
849250c7a61SRussell King 	udelay(FRAME_PERIOD_US * 2);
850cb5a6ffcSRussell King 
851cb5a6ffcSRussell King 	ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus);
852cb5a6ffcSRussell King 	if (ret)
853cb5a6ffcSRussell King 		goto out;
854cb5a6ffcSRussell King 
855cb5a6ffcSRussell King 	ac97_bus->clock = 48000;
856cb5a6ffcSRussell King 	aaci->ac97_bus = ac97_bus;
857cb5a6ffcSRussell King 
858ceb9e476STakashi Iwai 	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
859cb5a6ffcSRussell King 	ac97_template.private_data = aaci;
860cb5a6ffcSRussell King 	ac97_template.num = 0;
861cb5a6ffcSRussell King 	ac97_template.scaps = AC97_SCAP_SKIP_MODEM;
862cb5a6ffcSRussell King 
863cb5a6ffcSRussell King 	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
864cb5a6ffcSRussell King 	if (ret)
865cb5a6ffcSRussell King 		goto out;
86641762b8cSKevin Hilman 	aaci->ac97 = ac97;
867cb5a6ffcSRussell King 
868cb5a6ffcSRussell King 	/*
869cb5a6ffcSRussell King 	 * Disable AC97 PC Beep input on audio codecs.
870cb5a6ffcSRussell King 	 */
871cb5a6ffcSRussell King 	if (ac97_is_audio(ac97))
872cb5a6ffcSRussell King 		snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e);
873cb5a6ffcSRussell King 
874cb5a6ffcSRussell King 	ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs);
875cb5a6ffcSRussell King 	if (ret)
876cb5a6ffcSRussell King 		goto out;
877cb5a6ffcSRussell King 
878cb5a6ffcSRussell King 	aaci->playback.pcm = &ac97_bus->pcms[0];
87941762b8cSKevin Hilman 	aaci->capture.pcm  = &ac97_bus->pcms[1];
880cb5a6ffcSRussell King 
881cb5a6ffcSRussell King  out:
882cb5a6ffcSRussell King 	return ret;
883cb5a6ffcSRussell King }
884cb5a6ffcSRussell King 
885ceb9e476STakashi Iwai static void aaci_free_card(struct snd_card *card)
886cb5a6ffcSRussell King {
887cb5a6ffcSRussell King 	struct aaci *aaci = card->private_data;
888cb5a6ffcSRussell King 	if (aaci->base)
889cb5a6ffcSRussell King 		iounmap(aaci->base);
890cb5a6ffcSRussell King }
891cb5a6ffcSRussell King 
892cb5a6ffcSRussell King static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
893cb5a6ffcSRussell King {
894cb5a6ffcSRussell King 	struct aaci *aaci;
895ceb9e476STakashi Iwai 	struct snd_card *card;
896bd7dd77cSTakashi Iwai 	int err;
897cb5a6ffcSRussell King 
898bd7dd77cSTakashi Iwai 	err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
899bd7dd77cSTakashi Iwai 			      THIS_MODULE, sizeof(struct aaci), &card);
900bd7dd77cSTakashi Iwai 	if (err < 0)
901631e8ad4STakashi Iwai 		return NULL;
902cb5a6ffcSRussell King 
903cb5a6ffcSRussell King 	card->private_free = aaci_free_card;
904cb5a6ffcSRussell King 
905cb5a6ffcSRussell King 	strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
906cb5a6ffcSRussell King 	strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
907cb5a6ffcSRussell King 	snprintf(card->longname, sizeof(card->longname),
908f006d8fcSRussell King 		 "%s PL%03x rev%u at 0x%08llx, irq %d",
909f006d8fcSRussell King 		 card->shortname, amba_part(dev), amba_rev(dev),
910f006d8fcSRussell King 		 (unsigned long long)dev->res.start, dev->irq[0]);
911cb5a6ffcSRussell King 
912cb5a6ffcSRussell King 	aaci = card->private_data;
91312aa7579SIngo Molnar 	mutex_init(&aaci->ac97_sem);
914b60fb519SRussell King 	mutex_init(&aaci->irq_lock);
915cb5a6ffcSRussell King 	aaci->card = card;
916cb5a6ffcSRussell King 	aaci->dev = dev;
917cb5a6ffcSRussell King 
918cb5a6ffcSRussell King 	/* Set MAINCR to allow slot 1 and 2 data IO */
919cb5a6ffcSRussell King 	aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN |
920cb5a6ffcSRussell King 		       MAINCR_SL2RXEN | MAINCR_SL2TXEN;
921cb5a6ffcSRussell King 
922cb5a6ffcSRussell King 	return aaci;
923cb5a6ffcSRussell King }
924cb5a6ffcSRussell King 
925cb5a6ffcSRussell King static int __devinit aaci_init_pcm(struct aaci *aaci)
926cb5a6ffcSRussell King {
927ceb9e476STakashi Iwai 	struct snd_pcm *pcm;
928cb5a6ffcSRussell King 	int ret;
929cb5a6ffcSRussell King 
93041762b8cSKevin Hilman 	ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm);
931cb5a6ffcSRussell King 	if (ret == 0) {
932cb5a6ffcSRussell King 		aaci->pcm = pcm;
933cb5a6ffcSRussell King 		pcm->private_data = aaci;
934cb5a6ffcSRussell King 		pcm->info_flags = 0;
935cb5a6ffcSRussell King 
936cb5a6ffcSRussell King 		strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
937cb5a6ffcSRussell King 
938cb5a6ffcSRussell King 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops);
93941762b8cSKevin Hilman 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops);
940d6797322STakashi Iwai 		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
941d4946431STakashi Iwai 						      NULL, 0, 64 * 1024);
942cb5a6ffcSRussell King 	}
943cb5a6ffcSRussell King 
944cb5a6ffcSRussell King 	return ret;
945cb5a6ffcSRussell King }
946cb5a6ffcSRussell King 
947cb5a6ffcSRussell King static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
948cb5a6ffcSRussell King {
94941762b8cSKevin Hilman 	struct aaci_runtime *aacirun = &aaci->playback;
950cb5a6ffcSRussell King 	int i;
951cb5a6ffcSRussell King 
9525d350cbaSRussell King 	/*
9535d350cbaSRussell King 	 * Enable the channel, but don't assign it to any slots, so
9545d350cbaSRussell King 	 * it won't empty onto the AC'97 link.
9555d350cbaSRussell King 	 */
95641762b8cSKevin Hilman 	writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR);
957cb5a6ffcSRussell King 
95841762b8cSKevin Hilman 	for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++)
95941762b8cSKevin Hilman 		writel(0, aacirun->fifo);
960cb5a6ffcSRussell King 
96141762b8cSKevin Hilman 	writel(0, aacirun->base + AACI_TXCR);
962cb5a6ffcSRussell King 
963cb5a6ffcSRussell King 	/*
964cb5a6ffcSRussell King 	 * Re-initialise the AACI after the FIFO depth test, to
965cb5a6ffcSRussell King 	 * ensure that the FIFOs are empty.  Unfortunately, merely
966cb5a6ffcSRussell King 	 * disabling the channel doesn't clear the FIFO.
967cb5a6ffcSRussell King 	 */
968cb5a6ffcSRussell King 	writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR);
969cb5a6ffcSRussell King 	writel(aaci->maincr, aaci->base + AACI_MAINCR);
970cb5a6ffcSRussell King 
971cb5a6ffcSRussell King 	/*
9725d350cbaSRussell King 	 * If we hit 4096 entries, we failed.  Go back to the specified
973cb5a6ffcSRussell King 	 * fifo depth.
974cb5a6ffcSRussell King 	 */
975cb5a6ffcSRussell King 	if (i == 4096)
976cb5a6ffcSRussell King 		i = 8;
977cb5a6ffcSRussell King 
978cb5a6ffcSRussell King 	return i;
979cb5a6ffcSRussell King }
980cb5a6ffcSRussell King 
98103fbdb15SAlessandro Rubini static int __devinit aaci_probe(struct amba_device *dev, struct amba_id *id)
982cb5a6ffcSRussell King {
983cb5a6ffcSRussell King 	struct aaci *aaci;
984cb5a6ffcSRussell King 	int ret, i;
985cb5a6ffcSRussell King 
986cb5a6ffcSRussell King 	ret = amba_request_regions(dev, NULL);
987cb5a6ffcSRussell King 	if (ret)
988cb5a6ffcSRussell King 		return ret;
989cb5a6ffcSRussell King 
990cb5a6ffcSRussell King 	aaci = aaci_init_card(dev);
991631e8ad4STakashi Iwai 	if (!aaci) {
992631e8ad4STakashi Iwai 		ret = -ENOMEM;
993cb5a6ffcSRussell King 		goto out;
994cb5a6ffcSRussell King 	}
995cb5a6ffcSRussell King 
996dc890c2dSLinus Walleij 	aaci->base = ioremap(dev->res.start, resource_size(&dev->res));
997cb5a6ffcSRussell King 	if (!aaci->base) {
998cb5a6ffcSRussell King 		ret = -ENOMEM;
999cb5a6ffcSRussell King 		goto out;
1000cb5a6ffcSRussell King 	}
1001cb5a6ffcSRussell King 
1002cb5a6ffcSRussell King 	/*
1003cb5a6ffcSRussell King 	 * Playback uses AACI channel 0
1004cb5a6ffcSRussell King 	 */
1005d6a89fefSRussell King 	spin_lock_init(&aaci->playback.lock);
1006cb5a6ffcSRussell King 	aaci->playback.base = aaci->base + AACI_CSCH1;
1007cb5a6ffcSRussell King 	aaci->playback.fifo = aaci->base + AACI_DR1;
1008cb5a6ffcSRussell King 
100941762b8cSKevin Hilman 	/*
101041762b8cSKevin Hilman 	 * Capture uses AACI channel 0
101141762b8cSKevin Hilman 	 */
1012d6a89fefSRussell King 	spin_lock_init(&aaci->capture.lock);
101341762b8cSKevin Hilman 	aaci->capture.base = aaci->base + AACI_CSCH1;
101441762b8cSKevin Hilman 	aaci->capture.fifo = aaci->base + AACI_DR1;
101541762b8cSKevin Hilman 
1016cb5a6ffcSRussell King 	for (i = 0; i < 4; i++) {
1017e12ba644Sviro@ZenIV.linux.org.uk 		void __iomem *base = aaci->base + i * 0x14;
1018cb5a6ffcSRussell King 
1019cb5a6ffcSRussell King 		writel(0, base + AACI_IE);
1020cb5a6ffcSRussell King 		writel(0, base + AACI_TXCR);
1021cb5a6ffcSRussell King 		writel(0, base + AACI_RXCR);
1022cb5a6ffcSRussell King 	}
1023cb5a6ffcSRussell King 
1024cb5a6ffcSRussell King 	writel(0x1fff, aaci->base + AACI_INTCLR);
1025cb5a6ffcSRussell King 	writel(aaci->maincr, aaci->base + AACI_MAINCR);
1026b68b58fdSPhilby John 	/*
1027b68b58fdSPhilby John 	 * Fix: ac97 read back fail errors by reading
1028b68b58fdSPhilby John 	 * from any arbitrary aaci register.
1029b68b58fdSPhilby John 	 */
1030b68b58fdSPhilby John 	readl(aaci->base + AACI_CSCH1);
1031cb5a6ffcSRussell King 	ret = aaci_probe_ac97(aaci);
1032cb5a6ffcSRussell King 	if (ret)
1033cb5a6ffcSRussell King 		goto out;
1034cb5a6ffcSRussell King 
1035f27f218cSCatalin Marinas 	/*
1036f27f218cSCatalin Marinas 	 * Size the FIFOs (must be multiple of 16).
10375d350cbaSRussell King 	 * This is the number of entries in the FIFO.
1038f27f218cSCatalin Marinas 	 */
10395d350cbaSRussell King 	aaci->fifo_depth = aaci_size_fifo(aaci);
10405d350cbaSRussell King 	if (aaci->fifo_depth & 15) {
10415d350cbaSRussell King 		printk(KERN_WARNING "AACI: FIFO depth %d not supported\n",
10425d350cbaSRussell King 		       aaci->fifo_depth);
1043f27f218cSCatalin Marinas 		ret = -ENODEV;
1044f27f218cSCatalin Marinas 		goto out;
1045f27f218cSCatalin Marinas 	}
1046f27f218cSCatalin Marinas 
1047cb5a6ffcSRussell King 	ret = aaci_init_pcm(aaci);
1048cb5a6ffcSRussell King 	if (ret)
1049cb5a6ffcSRussell King 		goto out;
1050cb5a6ffcSRussell King 
1051a76af199STakashi Iwai 	snd_card_set_dev(aaci->card, &dev->dev);
1052a76af199STakashi Iwai 
1053cb5a6ffcSRussell King 	ret = snd_card_register(aaci->card);
1054cb5a6ffcSRussell King 	if (ret == 0) {
10555d350cbaSRussell King 		dev_info(&dev->dev, "%s\n", aaci->card->longname);
10565d350cbaSRussell King 		dev_info(&dev->dev, "FIFO %u entries\n", aaci->fifo_depth);
1057cb5a6ffcSRussell King 		amba_set_drvdata(dev, aaci->card);
1058cb5a6ffcSRussell King 		return ret;
1059cb5a6ffcSRussell King 	}
1060cb5a6ffcSRussell King 
1061cb5a6ffcSRussell King  out:
1062cb5a6ffcSRussell King 	if (aaci)
1063cb5a6ffcSRussell King 		snd_card_free(aaci->card);
1064cb5a6ffcSRussell King 	amba_release_regions(dev);
1065cb5a6ffcSRussell King 	return ret;
1066cb5a6ffcSRussell King }
1067cb5a6ffcSRussell King 
1068cb5a6ffcSRussell King static int __devexit aaci_remove(struct amba_device *dev)
1069cb5a6ffcSRussell King {
1070ceb9e476STakashi Iwai 	struct snd_card *card = amba_get_drvdata(dev);
1071cb5a6ffcSRussell King 
1072cb5a6ffcSRussell King 	amba_set_drvdata(dev, NULL);
1073cb5a6ffcSRussell King 
1074cb5a6ffcSRussell King 	if (card) {
1075cb5a6ffcSRussell King 		struct aaci *aaci = card->private_data;
1076cb5a6ffcSRussell King 		writel(0, aaci->base + AACI_MAINCR);
1077cb5a6ffcSRussell King 
1078cb5a6ffcSRussell King 		snd_card_free(card);
1079cb5a6ffcSRussell King 		amba_release_regions(dev);
1080cb5a6ffcSRussell King 	}
1081cb5a6ffcSRussell King 
1082cb5a6ffcSRussell King 	return 0;
1083cb5a6ffcSRussell King }
1084cb5a6ffcSRussell King 
1085cb5a6ffcSRussell King static struct amba_id aaci_ids[] = {
1086cb5a6ffcSRussell King 	{
1087cb5a6ffcSRussell King 		.id	= 0x00041041,
1088cb5a6ffcSRussell King 		.mask	= 0x000fffff,
1089cb5a6ffcSRussell King 	},
1090cb5a6ffcSRussell King 	{ 0, 0 },
1091cb5a6ffcSRussell King };
1092cb5a6ffcSRussell King 
1093cb5a6ffcSRussell King static struct amba_driver aaci_driver = {
1094cb5a6ffcSRussell King 	.drv		= {
1095cb5a6ffcSRussell King 		.name	= DRIVER_NAME,
1096cb5a6ffcSRussell King 	},
1097cb5a6ffcSRussell King 	.probe		= aaci_probe,
1098cb5a6ffcSRussell King 	.remove		= __devexit_p(aaci_remove),
1099cb5a6ffcSRussell King 	.suspend	= aaci_suspend,
1100cb5a6ffcSRussell King 	.resume		= aaci_resume,
1101cb5a6ffcSRussell King 	.id_table	= aaci_ids,
1102cb5a6ffcSRussell King };
1103cb5a6ffcSRussell King 
1104cb5a6ffcSRussell King static int __init aaci_init(void)
1105cb5a6ffcSRussell King {
1106cb5a6ffcSRussell King 	return amba_driver_register(&aaci_driver);
1107cb5a6ffcSRussell King }
1108cb5a6ffcSRussell King 
1109cb5a6ffcSRussell King static void __exit aaci_exit(void)
1110cb5a6ffcSRussell King {
1111cb5a6ffcSRussell King 	amba_driver_unregister(&aaci_driver);
1112cb5a6ffcSRussell King }
1113cb5a6ffcSRussell King 
1114cb5a6ffcSRussell King module_init(aaci_init);
1115cb5a6ffcSRussell King module_exit(aaci_exit);
1116cb5a6ffcSRussell King 
1117cb5a6ffcSRussell King MODULE_LICENSE("GPL");
1118cb5a6ffcSRussell King MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver");
1119