xref: /openbmc/linux/sound/arm/aaci.c (revision 3fd269e7)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2cb5a6ffcSRussell King /*
3cb5a6ffcSRussell King  *  linux/sound/arm/aaci.c - ARM PrimeCell AACI PL041 driver
4cb5a6ffcSRussell King  *
5cb5a6ffcSRussell King  *  Copyright (C) 2003 Deep Blue Solutions Ltd, All Rights Reserved.
6cb5a6ffcSRussell King  *
7cb5a6ffcSRussell King  *  Documentation: ARM DDI 0173B
8cb5a6ffcSRussell King  */
9cb5a6ffcSRussell King #include <linux/module.h>
10cb5a6ffcSRussell King #include <linux/delay.h>
11cb5a6ffcSRussell King #include <linux/init.h>
12cb5a6ffcSRussell King #include <linux/ioport.h>
13cb5a6ffcSRussell King #include <linux/device.h>
14cb5a6ffcSRussell King #include <linux/spinlock.h>
15cb5a6ffcSRussell King #include <linux/interrupt.h>
16cb5a6ffcSRussell King #include <linux/err.h>
17a62c80e5SRussell King #include <linux/amba/bus.h>
1888cdca9cSRussell King #include <linux/io.h>
19cb5a6ffcSRussell King 
20cb5a6ffcSRussell King #include <sound/core.h>
21cb5a6ffcSRussell King #include <sound/initval.h>
22cb5a6ffcSRussell King #include <sound/ac97_codec.h>
23cb5a6ffcSRussell King #include <sound/pcm.h>
24cb5a6ffcSRussell King #include <sound/pcm_params.h>
25cb5a6ffcSRussell King 
26cb5a6ffcSRussell King #include "aaci.h"
27cb5a6ffcSRussell King 
28cb5a6ffcSRussell King #define DRIVER_NAME	"aaci-pl041"
29cb5a6ffcSRussell King 
30250c7a61SRussell King #define FRAME_PERIOD_US	21
31250c7a61SRussell King 
32cb5a6ffcSRussell King /*
33cb5a6ffcSRussell King  * PM support is not complete.  Turn it off.
34cb5a6ffcSRussell King  */
35cb5a6ffcSRussell King #undef CONFIG_PM
36cb5a6ffcSRussell King 
aaci_ac97_select_codec(struct aaci * aaci,struct snd_ac97 * ac97)37ceb9e476STakashi Iwai static void aaci_ac97_select_codec(struct aaci *aaci, struct snd_ac97 *ac97)
38cb5a6ffcSRussell King {
39cb5a6ffcSRussell King 	u32 v, maincr = aaci->maincr | MAINCR_SCRA(ac97->num);
40cb5a6ffcSRussell King 
41cb5a6ffcSRussell King 	/*
42cb5a6ffcSRussell King 	 * Ensure that the slot 1/2 RX registers are empty.
43cb5a6ffcSRussell King 	 */
44cb5a6ffcSRussell King 	v = readl(aaci->base + AACI_SLFR);
45cb5a6ffcSRussell King 	if (v & SLFR_2RXV)
46cb5a6ffcSRussell King 		readl(aaci->base + AACI_SL2RX);
47cb5a6ffcSRussell King 	if (v & SLFR_1RXV)
48cb5a6ffcSRussell King 		readl(aaci->base + AACI_SL1RX);
49cb5a6ffcSRussell King 
507c289385SRussell King 	if (maincr != readl(aaci->base + AACI_MAINCR)) {
51cb5a6ffcSRussell King 		writel(maincr, aaci->base + AACI_MAINCR);
527c289385SRussell King 		readl(aaci->base + AACI_MAINCR);
537c289385SRussell King 		udelay(1);
547c289385SRussell King 	}
55cb5a6ffcSRussell King }
56cb5a6ffcSRussell King 
57cb5a6ffcSRussell King /*
58cb5a6ffcSRussell King  * P29:
59cb5a6ffcSRussell King  *  The recommended use of programming the external codec through slot 1
60cb5a6ffcSRussell King  *  and slot 2 data is to use the channels during setup routines and the
61cb5a6ffcSRussell King  *  slot register at any other time.  The data written into slot 1, slot 2
62cb5a6ffcSRussell King  *  and slot 12 registers is transmitted only when their corresponding
63cb5a6ffcSRussell King  *  SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR
64cb5a6ffcSRussell King  *  register.
65cb5a6ffcSRussell King  */
aaci_ac97_write(struct snd_ac97 * ac97,unsigned short reg,unsigned short val)6614d178a1SKevin Hilman static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
6714d178a1SKevin Hilman 			    unsigned short val)
68cb5a6ffcSRussell King {
69cb5a6ffcSRussell King 	struct aaci *aaci = ac97->private_data;
70250c7a61SRussell King 	int timeout;
71cb5a6ffcSRussell King 	u32 v;
72cb5a6ffcSRussell King 
73cb5a6ffcSRussell King 	if (ac97->num >= 4)
74cb5a6ffcSRussell King 		return;
75cb5a6ffcSRussell King 
7612aa7579SIngo Molnar 	mutex_lock(&aaci->ac97_sem);
77cb5a6ffcSRussell King 
78cb5a6ffcSRussell King 	aaci_ac97_select_codec(aaci, ac97);
79cb5a6ffcSRussell King 
80cb5a6ffcSRussell King 	/*
81cb5a6ffcSRussell King 	 * P54: You must ensure that AACI_SL2TX is always written
82cb5a6ffcSRussell King 	 * to, if required, before data is written to AACI_SL1TX.
83cb5a6ffcSRussell King 	 */
84cb5a6ffcSRussell King 	writel(val << 4, aaci->base + AACI_SL2TX);
85cb5a6ffcSRussell King 	writel(reg << 12, aaci->base + AACI_SL1TX);
86cb5a6ffcSRussell King 
87250c7a61SRussell King 	/* Initially, wait one frame period */
88250c7a61SRussell King 	udelay(FRAME_PERIOD_US);
89250c7a61SRussell King 
90250c7a61SRussell King 	/* And then wait an additional eight frame periods for it to be sent */
91250c7a61SRussell King 	timeout = FRAME_PERIOD_US * 8;
92cb5a6ffcSRussell King 	do {
93250c7a61SRussell King 		udelay(1);
94cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SLFR);
95f6f35bbeSRoel Kluin 	} while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout);
9614d178a1SKevin Hilman 
9769058cd6SRussell King 	if (v & (SLFR_1TXB|SLFR_2TXB))
9814d178a1SKevin Hilman 		dev_err(&aaci->dev->dev,
9914d178a1SKevin Hilman 			"timeout waiting for write to complete\n");
100cb5a6ffcSRussell King 
10112aa7579SIngo Molnar 	mutex_unlock(&aaci->ac97_sem);
102cb5a6ffcSRussell King }
103cb5a6ffcSRussell King 
104cb5a6ffcSRussell King /*
105cb5a6ffcSRussell King  * Read an AC'97 register.
106cb5a6ffcSRussell King  */
aaci_ac97_read(struct snd_ac97 * ac97,unsigned short reg)107ceb9e476STakashi Iwai static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
108cb5a6ffcSRussell King {
109cb5a6ffcSRussell King 	struct aaci *aaci = ac97->private_data;
110250c7a61SRussell King 	int timeout, retries = 10;
111cb5a6ffcSRussell King 	u32 v;
112cb5a6ffcSRussell King 
113cb5a6ffcSRussell King 	if (ac97->num >= 4)
114cb5a6ffcSRussell King 		return ~0;
115cb5a6ffcSRussell King 
11612aa7579SIngo Molnar 	mutex_lock(&aaci->ac97_sem);
117cb5a6ffcSRussell King 
118cb5a6ffcSRussell King 	aaci_ac97_select_codec(aaci, ac97);
119cb5a6ffcSRussell King 
120cb5a6ffcSRussell King 	/*
121cb5a6ffcSRussell King 	 * Write the register address to slot 1.
122cb5a6ffcSRussell King 	 */
123cb5a6ffcSRussell King 	writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX);
124cb5a6ffcSRussell King 
125250c7a61SRussell King 	/* Initially, wait one frame period */
126250c7a61SRussell King 	udelay(FRAME_PERIOD_US);
127250c7a61SRussell King 
128250c7a61SRussell King 	/* And then wait an additional eight frame periods for it to be sent */
129250c7a61SRussell King 	timeout = FRAME_PERIOD_US * 8;
130cb5a6ffcSRussell King 	do {
131250c7a61SRussell King 		udelay(1);
132cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SLFR);
133f6f35bbeSRoel Kluin 	} while ((v & SLFR_1TXB) && --timeout);
13414d178a1SKevin Hilman 
13569058cd6SRussell King 	if (v & SLFR_1TXB) {
13614d178a1SKevin Hilman 		dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n");
13714d178a1SKevin Hilman 		v = ~0;
13814d178a1SKevin Hilman 		goto out;
13914d178a1SKevin Hilman 	}
140cb5a6ffcSRussell King 
141250c7a61SRussell King 	/* Now wait for the response frame */
142250c7a61SRussell King 	udelay(FRAME_PERIOD_US);
143cb5a6ffcSRussell King 
144250c7a61SRussell King 	/* And then wait an additional eight frame periods for data */
145250c7a61SRussell King 	timeout = FRAME_PERIOD_US * 8;
146cb5a6ffcSRussell King 	do {
147250c7a61SRussell King 		udelay(1);
148cb5a6ffcSRussell King 		cond_resched();
149cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
150f6f35bbeSRoel Kluin 	} while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout);
151cb5a6ffcSRussell King 
15269058cd6SRussell King 	if (v != (SLFR_1RXV|SLFR_2RXV)) {
15314d178a1SKevin Hilman 		dev_err(&aaci->dev->dev, "timeout on RX valid\n");
15414d178a1SKevin Hilman 		v = ~0;
15514d178a1SKevin Hilman 		goto out;
15614d178a1SKevin Hilman 	}
15714d178a1SKevin Hilman 
15814d178a1SKevin Hilman 	do {
159cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SL1RX) >> 12;
160cb5a6ffcSRussell King 		if (v == reg) {
161cb5a6ffcSRussell King 			v = readl(aaci->base + AACI_SL2RX) >> 4;
16214d178a1SKevin Hilman 			break;
16314d178a1SKevin Hilman 		} else if (--retries) {
16414d178a1SKevin Hilman 			dev_warn(&aaci->dev->dev,
16514d178a1SKevin Hilman 				 "ac97 read back fail.  retry\n");
16614d178a1SKevin Hilman 			continue;
167cb5a6ffcSRussell King 		} else {
16814d178a1SKevin Hilman 			dev_warn(&aaci->dev->dev,
169cb5a6ffcSRussell King 				"wrong ac97 register read back (%x != %x)\n",
170cb5a6ffcSRussell King 				v, reg);
171cb5a6ffcSRussell King 			v = ~0;
172cb5a6ffcSRussell King 		}
17314d178a1SKevin Hilman 	} while (retries);
17414d178a1SKevin Hilman  out:
17512aa7579SIngo Molnar 	mutex_unlock(&aaci->ac97_sem);
176cb5a6ffcSRussell King 	return v;
177cb5a6ffcSRussell King }
178cb5a6ffcSRussell King 
179d6a89fefSRussell King static inline void
aaci_chan_wait_ready(struct aaci_runtime * aacirun,unsigned long mask)180d6a89fefSRussell King aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask)
181cb5a6ffcSRussell King {
182cb5a6ffcSRussell King 	u32 val;
183cb5a6ffcSRussell King 	int timeout = 5000;
184cb5a6ffcSRussell King 
185cb5a6ffcSRussell King 	do {
186250c7a61SRussell King 		udelay(1);
187cb5a6ffcSRussell King 		val = readl(aacirun->base + AACI_SR);
188d6a89fefSRussell King 	} while (val & mask && timeout--);
189cb5a6ffcSRussell King }
190cb5a6ffcSRussell King 
191cb5a6ffcSRussell King 
192cb5a6ffcSRussell King 
193cb5a6ffcSRussell King /*
194cb5a6ffcSRussell King  * Interrupt support.
195cb5a6ffcSRussell King  */
aaci_fifo_irq(struct aaci * aaci,int channel,u32 mask)19662578cbfSKevin Hilman static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
197cb5a6ffcSRussell King {
19841762b8cSKevin Hilman 	if (mask & ISR_ORINTR) {
19941762b8cSKevin Hilman 		dev_warn(&aaci->dev->dev, "RX overrun on chan %d\n", channel);
20041762b8cSKevin Hilman 		writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR);
20141762b8cSKevin Hilman 	}
20241762b8cSKevin Hilman 
20341762b8cSKevin Hilman 	if (mask & ISR_RXTOINTR) {
20441762b8cSKevin Hilman 		dev_warn(&aaci->dev->dev, "RX timeout on chan %d\n", channel);
20541762b8cSKevin Hilman 		writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR);
20641762b8cSKevin Hilman 	}
20741762b8cSKevin Hilman 
20841762b8cSKevin Hilman 	if (mask & ISR_RXINTR) {
20941762b8cSKevin Hilman 		struct aaci_runtime *aacirun = &aaci->capture;
210ea51d0b1SRussell King 		bool period_elapsed = false;
21141762b8cSKevin Hilman 		void *ptr;
21241762b8cSKevin Hilman 
21341762b8cSKevin Hilman 		if (!aacirun->substream || !aacirun->start) {
214898eb71cSJoe Perches 			dev_warn(&aaci->dev->dev, "RX interrupt???\n");
21541762b8cSKevin Hilman 			writel(0, aacirun->base + AACI_IE);
21641762b8cSKevin Hilman 			return;
21741762b8cSKevin Hilman 		}
21841762b8cSKevin Hilman 
219d6a89fefSRussell King 		spin_lock(&aacirun->lock);
220d6a89fefSRussell King 
221d6a89fefSRussell King 		ptr = aacirun->ptr;
22241762b8cSKevin Hilman 		do {
2235d350cbaSRussell King 			unsigned int len = aacirun->fifo_bytes;
22441762b8cSKevin Hilman 			u32 val;
22541762b8cSKevin Hilman 
22641762b8cSKevin Hilman 			if (aacirun->bytes <= 0) {
22741762b8cSKevin Hilman 				aacirun->bytes += aacirun->period;
228ea51d0b1SRussell King 				period_elapsed = true;
22941762b8cSKevin Hilman 			}
23041762b8cSKevin Hilman 			if (!(aacirun->cr & CR_EN))
23141762b8cSKevin Hilman 				break;
23241762b8cSKevin Hilman 
23341762b8cSKevin Hilman 			val = readl(aacirun->base + AACI_SR);
23441762b8cSKevin Hilman 			if (!(val & SR_RXHF))
23541762b8cSKevin Hilman 				break;
23641762b8cSKevin Hilman 			if (!(val & SR_RXFF))
23741762b8cSKevin Hilman 				len >>= 1;
23841762b8cSKevin Hilman 
23941762b8cSKevin Hilman 			aacirun->bytes -= len;
24041762b8cSKevin Hilman 
24141762b8cSKevin Hilman 			/* reading 16 bytes at a time */
24241762b8cSKevin Hilman 			for( ; len > 0; len -= 16) {
24341762b8cSKevin Hilman 				asm(
24441762b8cSKevin Hilman 					"ldmia	%1, {r0, r1, r2, r3}\n\t"
24541762b8cSKevin Hilman 					"stmia	%0!, {r0, r1, r2, r3}"
24641762b8cSKevin Hilman 					: "+r" (ptr)
24741762b8cSKevin Hilman 					: "r" (aacirun->fifo)
24841762b8cSKevin Hilman 					: "r0", "r1", "r2", "r3", "cc");
24941762b8cSKevin Hilman 
25041762b8cSKevin Hilman 				if (ptr >= aacirun->end)
25141762b8cSKevin Hilman 					ptr = aacirun->start;
25241762b8cSKevin Hilman 			}
25341762b8cSKevin Hilman 		} while(1);
254d6a89fefSRussell King 
25541762b8cSKevin Hilman 		aacirun->ptr = ptr;
256d6a89fefSRussell King 
257d6a89fefSRussell King 		spin_unlock(&aacirun->lock);
258ea51d0b1SRussell King 
259ea51d0b1SRussell King 		if (period_elapsed)
260ea51d0b1SRussell King 			snd_pcm_period_elapsed(aacirun->substream);
26141762b8cSKevin Hilman 	}
26241762b8cSKevin Hilman 
263cb5a6ffcSRussell King 	if (mask & ISR_URINTR) {
26462578cbfSKevin Hilman 		dev_dbg(&aaci->dev->dev, "TX underrun on chan %d\n", channel);
26562578cbfSKevin Hilman 		writel(ICLR_TXUEC1 << channel, aaci->base + AACI_INTCLR);
266cb5a6ffcSRussell King 	}
267cb5a6ffcSRussell King 
268cb5a6ffcSRussell King 	if (mask & ISR_TXINTR) {
269cb5a6ffcSRussell King 		struct aaci_runtime *aacirun = &aaci->playback;
270ea51d0b1SRussell King 		bool period_elapsed = false;
271cb5a6ffcSRussell King 		void *ptr;
272cb5a6ffcSRussell King 
273cb5a6ffcSRussell King 		if (!aacirun->substream || !aacirun->start) {
274898eb71cSJoe Perches 			dev_warn(&aaci->dev->dev, "TX interrupt???\n");
275cb5a6ffcSRussell King 			writel(0, aacirun->base + AACI_IE);
276cb5a6ffcSRussell King 			return;
277cb5a6ffcSRussell King 		}
278cb5a6ffcSRussell King 
279d6a89fefSRussell King 		spin_lock(&aacirun->lock);
280d6a89fefSRussell King 
281cb5a6ffcSRussell King 		ptr = aacirun->ptr;
282cb5a6ffcSRussell King 		do {
2835d350cbaSRussell King 			unsigned int len = aacirun->fifo_bytes;
284cb5a6ffcSRussell King 			u32 val;
285cb5a6ffcSRussell King 
286cb5a6ffcSRussell King 			if (aacirun->bytes <= 0) {
287cb5a6ffcSRussell King 				aacirun->bytes += aacirun->period;
288ea51d0b1SRussell King 				period_elapsed = true;
289cb5a6ffcSRussell King 			}
29041762b8cSKevin Hilman 			if (!(aacirun->cr & CR_EN))
291cb5a6ffcSRussell King 				break;
292cb5a6ffcSRussell King 
293cb5a6ffcSRussell King 			val = readl(aacirun->base + AACI_SR);
294cb5a6ffcSRussell King 			if (!(val & SR_TXHE))
295cb5a6ffcSRussell King 				break;
296cb5a6ffcSRussell King 			if (!(val & SR_TXFE))
297cb5a6ffcSRussell King 				len >>= 1;
298cb5a6ffcSRussell King 
299cb5a6ffcSRussell King 			aacirun->bytes -= len;
300cb5a6ffcSRussell King 
301cb5a6ffcSRussell King 			/* writing 16 bytes at a time */
302cb5a6ffcSRussell King 			for ( ; len > 0; len -= 16) {
303cb5a6ffcSRussell King 				asm(
304cb5a6ffcSRussell King 					"ldmia	%0!, {r0, r1, r2, r3}\n\t"
305cb5a6ffcSRussell King 					"stmia	%1, {r0, r1, r2, r3}"
306cb5a6ffcSRussell King 					: "+r" (ptr)
307cb5a6ffcSRussell King 					: "r" (aacirun->fifo)
308cb5a6ffcSRussell King 					: "r0", "r1", "r2", "r3", "cc");
309cb5a6ffcSRussell King 
310cb5a6ffcSRussell King 				if (ptr >= aacirun->end)
311cb5a6ffcSRussell King 					ptr = aacirun->start;
312cb5a6ffcSRussell King 			}
313cb5a6ffcSRussell King 		} while (1);
314cb5a6ffcSRussell King 
315cb5a6ffcSRussell King 		aacirun->ptr = ptr;
316d6a89fefSRussell King 
317d6a89fefSRussell King 		spin_unlock(&aacirun->lock);
318ea51d0b1SRussell King 
319ea51d0b1SRussell King 		if (period_elapsed)
320ea51d0b1SRussell King 			snd_pcm_period_elapsed(aacirun->substream);
321cb5a6ffcSRussell King 	}
322cb5a6ffcSRussell King }
323cb5a6ffcSRussell King 
aaci_irq(int irq,void * devid)3247d12e780SDavid Howells static irqreturn_t aaci_irq(int irq, void *devid)
325cb5a6ffcSRussell King {
326cb5a6ffcSRussell King 	struct aaci *aaci = devid;
327cb5a6ffcSRussell King 	u32 mask;
328cb5a6ffcSRussell King 	int i;
329cb5a6ffcSRussell King 
330cb5a6ffcSRussell King 	mask = readl(aaci->base + AACI_ALLINTS);
331cb5a6ffcSRussell King 	if (mask) {
332cb5a6ffcSRussell King 		u32 m = mask;
333cb5a6ffcSRussell King 		for (i = 0; i < 4; i++, m >>= 7) {
334cb5a6ffcSRussell King 			if (m & 0x7f) {
33562578cbfSKevin Hilman 				aaci_fifo_irq(aaci, i, m);
336cb5a6ffcSRussell King 			}
337cb5a6ffcSRussell King 		}
338cb5a6ffcSRussell King 	}
339cb5a6ffcSRussell King 
340cb5a6ffcSRussell King 	return mask ? IRQ_HANDLED : IRQ_NONE;
341cb5a6ffcSRussell King }
342cb5a6ffcSRussell King 
343cb5a6ffcSRussell King 
344cb5a6ffcSRussell King 
345cb5a6ffcSRussell King /*
346cb5a6ffcSRussell King  * ALSA support.
347cb5a6ffcSRussell King  */
348db566fb9SBhumika Goyal static const struct snd_pcm_hardware aaci_hw_info = {
349cb5a6ffcSRussell King 	.info			= SNDRV_PCM_INFO_MMAP |
350cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_MMAP_VALID |
351cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_INTERLEAVED |
352cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_BLOCK_TRANSFER |
353cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_RESUME,
354cb5a6ffcSRussell King 
355cb5a6ffcSRussell King 	/*
356cb5a6ffcSRussell King 	 * ALSA doesn't support 18-bit or 20-bit packed into 32-bit
357cb5a6ffcSRussell King 	 * words.  It also doesn't support 12-bit at all.
358cb5a6ffcSRussell King 	 */
359cb5a6ffcSRussell King 	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
360cb5a6ffcSRussell King 
3616ca867c8SRussell King 	/* rates are setup from the AC'97 codec */
362cb5a6ffcSRussell King 	.channels_min		= 2,
363e831d80bSRussell King 	.channels_max		= 2,
364cb5a6ffcSRussell King 	.buffer_bytes_max	= 64 * 1024,
365cb5a6ffcSRussell King 	.period_bytes_min	= 256,
366cb5a6ffcSRussell King 	.period_bytes_max	= PAGE_SIZE,
367cb5a6ffcSRussell King 	.periods_min		= 4,
368cb5a6ffcSRussell King 	.periods_max		= PAGE_SIZE / 16,
369cb5a6ffcSRussell King };
370cb5a6ffcSRussell King 
371e831d80bSRussell King /*
372e831d80bSRussell King  * We can support two and four channel audio.  Unfortunately
373e831d80bSRussell King  * six channel audio requires a non-standard channel ordering:
374e831d80bSRussell King  *   2 -> FL(3), FR(4)
375e831d80bSRussell King  *   4 -> FL(3), FR(4), SL(7), SR(8)
376e831d80bSRussell King  *   6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required)
377e831d80bSRussell King  *        FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual)
378e831d80bSRussell King  * This requires an ALSA configuration file to correct.
379e831d80bSRussell King  */
aaci_rule_channels(struct snd_pcm_hw_params * p,struct snd_pcm_hw_rule * rule)380e831d80bSRussell King static int aaci_rule_channels(struct snd_pcm_hw_params *p,
381e831d80bSRussell King 	struct snd_pcm_hw_rule *rule)
382e831d80bSRussell King {
3837840d8a1STakashi Iwai 	static const unsigned int channel_list[] = { 2, 4, 6 };
384e831d80bSRussell King 	struct aaci *aaci = rule->private;
385e831d80bSRussell King 	unsigned int mask = 1 << 0, slots;
386e831d80bSRussell King 
387e831d80bSRussell King 	/* pcms[0] is the our 5.1 PCM instance. */
388e831d80bSRussell King 	slots = aaci->ac97_bus->pcms[0].r[0].slots;
389e831d80bSRussell King 	if (slots & (1 << AC97_SLOT_PCM_SLEFT)) {
390e831d80bSRussell King 		mask |= 1 << 1;
391e831d80bSRussell King 		if (slots & (1 << AC97_SLOT_LFE))
392e831d80bSRussell King 			mask |= 1 << 2;
393e831d80bSRussell King 	}
394e831d80bSRussell King 
395e831d80bSRussell King 	return snd_interval_list(hw_param_interval(p, rule->var),
396e831d80bSRussell King 				 ARRAY_SIZE(channel_list), channel_list, mask);
397e831d80bSRussell King }
398e831d80bSRussell King 
aaci_pcm_open(struct snd_pcm_substream * substream)399e831d80bSRussell King static int aaci_pcm_open(struct snd_pcm_substream *substream)
400cb5a6ffcSRussell King {
401ceb9e476STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
402e831d80bSRussell King 	struct aaci *aaci = substream->private_data;
403e831d80bSRussell King 	struct aaci_runtime *aacirun;
404b60fb519SRussell King 	int ret = 0;
405cb5a6ffcSRussell King 
406e831d80bSRussell King 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
407e831d80bSRussell King 		aacirun = &aaci->playback;
408e831d80bSRussell King 	} else {
409e831d80bSRussell King 		aacirun = &aaci->capture;
410e831d80bSRussell King 	}
411e831d80bSRussell King 
412cb5a6ffcSRussell King 	aacirun->substream = substream;
413cb5a6ffcSRussell King 	runtime->private_data = aacirun;
414cb5a6ffcSRussell King 	runtime->hw = aaci_hw_info;
4156ca867c8SRussell King 	runtime->hw.rates = aacirun->pcm->rates;
4166ca867c8SRussell King 	snd_pcm_limit_hw_rates(runtime);
417cb5a6ffcSRussell King 
418e831d80bSRussell King 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
419e831d80bSRussell King 		runtime->hw.channels_max = 6;
420e831d80bSRussell King 
421e831d80bSRussell King 		/* Add rule describing channel dependency. */
422e831d80bSRussell King 		ret = snd_pcm_hw_rule_add(substream->runtime, 0,
423e831d80bSRussell King 					  SNDRV_PCM_HW_PARAM_CHANNELS,
424e831d80bSRussell King 					  aaci_rule_channels, aaci,
425e831d80bSRussell King 					  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
426e831d80bSRussell King 		if (ret)
427e831d80bSRussell King 			return ret;
428e831d80bSRussell King 
429e831d80bSRussell King 		if (aacirun->pcm->r[1].slots)
430a08d5658SRussell King 			snd_ac97_pcm_double_rate_rules(runtime);
431e831d80bSRussell King 	}
432a08d5658SRussell King 
433cb5a6ffcSRussell King 	/*
4345d350cbaSRussell King 	 * ALSA wants the byte-size of the FIFOs.  As we only support
4355d350cbaSRussell King 	 * 16-bit samples, this is twice the FIFO depth irrespective
4365d350cbaSRussell King 	 * of whether it's in compact mode or not.
437cb5a6ffcSRussell King 	 */
4385d350cbaSRussell King 	runtime->hw.fifo_size = aaci->fifo_depth * 2;
439cb5a6ffcSRussell King 
440b60fb519SRussell King 	mutex_lock(&aaci->irq_lock);
441b60fb519SRussell King 	if (!aaci->users++) {
442b60fb519SRussell King 		ret = request_irq(aaci->dev->irq[0], aaci_irq,
44388e24c3aSYong Zhang 			   IRQF_SHARED, DRIVER_NAME, aaci);
444b60fb519SRussell King 		if (ret != 0)
445b60fb519SRussell King 			aaci->users--;
446b60fb519SRussell King 	}
447b60fb519SRussell King 	mutex_unlock(&aaci->irq_lock);
448cb5a6ffcSRussell King 
449cb5a6ffcSRussell King 	return ret;
450cb5a6ffcSRussell King }
451cb5a6ffcSRussell King 
452cb5a6ffcSRussell King 
453cb5a6ffcSRussell King /*
454cb5a6ffcSRussell King  * Common ALSA stuff
455cb5a6ffcSRussell King  */
aaci_pcm_close(struct snd_pcm_substream * substream)456ceb9e476STakashi Iwai static int aaci_pcm_close(struct snd_pcm_substream *substream)
457cb5a6ffcSRussell King {
458cb5a6ffcSRussell King 	struct aaci *aaci = substream->private_data;
459cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
460cb5a6ffcSRussell King 
46141762b8cSKevin Hilman 	WARN_ON(aacirun->cr & CR_EN);
462cb5a6ffcSRussell King 
463cb5a6ffcSRussell King 	aacirun->substream = NULL;
464b60fb519SRussell King 
465b60fb519SRussell King 	mutex_lock(&aaci->irq_lock);
466b60fb519SRussell King 	if (!--aaci->users)
467cb5a6ffcSRussell King 		free_irq(aaci->dev->irq[0], aaci);
468b60fb519SRussell King 	mutex_unlock(&aaci->irq_lock);
469cb5a6ffcSRussell King 
470cb5a6ffcSRussell King 	return 0;
471cb5a6ffcSRussell King }
472cb5a6ffcSRussell King 
aaci_pcm_hw_free(struct snd_pcm_substream * substream)473ceb9e476STakashi Iwai static int aaci_pcm_hw_free(struct snd_pcm_substream *substream)
474cb5a6ffcSRussell King {
475cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
476cb5a6ffcSRussell King 
477cb5a6ffcSRussell King 	/*
478cb5a6ffcSRussell King 	 * This must not be called with the device enabled.
479cb5a6ffcSRussell King 	 */
48041762b8cSKevin Hilman 	WARN_ON(aacirun->cr & CR_EN);
481cb5a6ffcSRussell King 
482cb5a6ffcSRussell King 	if (aacirun->pcm_open)
483cb5a6ffcSRussell King 		snd_ac97_pcm_close(aacirun->pcm);
484cb5a6ffcSRussell King 	aacirun->pcm_open = 0;
485cb5a6ffcSRussell King 
486cb5a6ffcSRussell King 	return 0;
487cb5a6ffcSRussell King }
488cb5a6ffcSRussell King 
48958e8a474SRussell King /* Channel to slot mask */
49058e8a474SRussell King static const u32 channels_to_slotmask[] = {
49158e8a474SRussell King 	[2] = CR_SL3 | CR_SL4,
49258e8a474SRussell King 	[4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8,
49358e8a474SRussell King 	[6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9,
49458e8a474SRussell King };
49558e8a474SRussell King 
aaci_pcm_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)496ceb9e476STakashi Iwai static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
497ceb9e476STakashi Iwai 			      struct snd_pcm_hw_params *params)
498cb5a6ffcSRussell King {
49958e8a474SRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
5008ee0c758STakashi Iwai 	struct aaci *aaci = substream->private_data;
50158e8a474SRussell King 	unsigned int channels = params_channels(params);
50258e8a474SRussell King 	unsigned int rate = params_rate(params);
50358e8a474SRussell King 	int dbl = rate > 48000;
504cb5a6ffcSRussell King 	int err;
505cb5a6ffcSRussell King 
506cb5a6ffcSRussell King 	aaci_pcm_hw_free(substream);
5074acd57c3SRussell King 	if (aacirun->pcm_open) {
5084acd57c3SRussell King 		snd_ac97_pcm_close(aacirun->pcm);
5094acd57c3SRussell King 		aacirun->pcm_open = 0;
5104acd57c3SRussell King 	}
511cb5a6ffcSRussell King 
51258e8a474SRussell King 	/* channels is already limited to 2, 4, or 6 by aaci_rule_channels */
51358e8a474SRussell King 	if (dbl && channels != 2)
51458e8a474SRussell King 		return -EINVAL;
51558e8a474SRussell King 
51658e8a474SRussell King 	err = snd_ac97_pcm_open(aacirun->pcm, rate, channels,
517a08d5658SRussell King 				aacirun->pcm->r[dbl].slots);
518cb5a6ffcSRussell King 
5194e30b691SRussell King 	aacirun->pcm_open = err == 0;
520d3aee799SRussell King 	aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16;
52158e8a474SRussell King 	aacirun->cr |= channels_to_slotmask[channels + dbl * 2];
522d3aee799SRussell King 
5235d350cbaSRussell King 	/*
5245d350cbaSRussell King 	 * fifo_bytes is the number of bytes we transfer to/from
5255d350cbaSRussell King 	 * the FIFO, including padding.  So that's x4.  As we're
5265d350cbaSRussell King 	 * in compact mode, the FIFO is half the size.
5275d350cbaSRussell King 	 */
5285d350cbaSRussell King 	aacirun->fifo_bytes = aaci->fifo_depth * 4 / 2;
529cb5a6ffcSRussell King 
530cb5a6ffcSRussell King 	return err;
531cb5a6ffcSRussell King }
532cb5a6ffcSRussell King 
aaci_pcm_prepare(struct snd_pcm_substream * substream)533ceb9e476STakashi Iwai static int aaci_pcm_prepare(struct snd_pcm_substream *substream)
534cb5a6ffcSRussell King {
535ceb9e476STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
536cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = runtime->private_data;
537cb5a6ffcSRussell King 
538c0dea82cSRussell King 	aacirun->period	= snd_pcm_lib_period_bytes(substream);
5394e30b691SRussell King 	aacirun->start	= runtime->dma_area;
54088cdca9cSRussell King 	aacirun->end	= aacirun->start + snd_pcm_lib_buffer_bytes(substream);
541cb5a6ffcSRussell King 	aacirun->ptr	= aacirun->start;
542c0dea82cSRussell King 	aacirun->bytes	= aacirun->period;
543cb5a6ffcSRussell King 
544cb5a6ffcSRussell King 	return 0;
545cb5a6ffcSRussell King }
546cb5a6ffcSRussell King 
aaci_pcm_pointer(struct snd_pcm_substream * substream)547ceb9e476STakashi Iwai static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream)
548cb5a6ffcSRussell King {
549ceb9e476STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
550cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = runtime->private_data;
551cb5a6ffcSRussell King 	ssize_t bytes = aacirun->ptr - aacirun->start;
552cb5a6ffcSRussell King 
553cb5a6ffcSRussell King 	return bytes_to_frames(runtime, bytes);
554cb5a6ffcSRussell King }
555cb5a6ffcSRussell King 
556cb5a6ffcSRussell King 
557cb5a6ffcSRussell King /*
558cb5a6ffcSRussell King  * Playback specific ALSA stuff
559cb5a6ffcSRussell King  */
aaci_pcm_playback_stop(struct aaci_runtime * aacirun)560cb5a6ffcSRussell King static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun)
561cb5a6ffcSRussell King {
562cb5a6ffcSRussell King 	u32 ie;
563cb5a6ffcSRussell King 
564cb5a6ffcSRussell King 	ie = readl(aacirun->base + AACI_IE);
565cb5a6ffcSRussell King 	ie &= ~(IE_URIE|IE_TXIE);
566cb5a6ffcSRussell King 	writel(ie, aacirun->base + AACI_IE);
56741762b8cSKevin Hilman 	aacirun->cr &= ~CR_EN;
568d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_TXB);
569cb5a6ffcSRussell King 	writel(aacirun->cr, aacirun->base + AACI_TXCR);
570cb5a6ffcSRussell King }
571cb5a6ffcSRussell King 
aaci_pcm_playback_start(struct aaci_runtime * aacirun)572cb5a6ffcSRussell King static void aaci_pcm_playback_start(struct aaci_runtime *aacirun)
573cb5a6ffcSRussell King {
574cb5a6ffcSRussell King 	u32 ie;
575cb5a6ffcSRussell King 
576d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_TXB);
57741762b8cSKevin Hilman 	aacirun->cr |= CR_EN;
578cb5a6ffcSRussell King 
579cb5a6ffcSRussell King 	ie = readl(aacirun->base + AACI_IE);
580cb5a6ffcSRussell King 	ie |= IE_URIE | IE_TXIE;
581cb5a6ffcSRussell King 	writel(ie, aacirun->base + AACI_IE);
582cb5a6ffcSRussell King 	writel(aacirun->cr, aacirun->base + AACI_TXCR);
583cb5a6ffcSRussell King }
584cb5a6ffcSRussell King 
aaci_pcm_playback_trigger(struct snd_pcm_substream * substream,int cmd)585ceb9e476STakashi Iwai static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
586cb5a6ffcSRussell King {
587cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
588cb5a6ffcSRussell King 	unsigned long flags;
589cb5a6ffcSRussell King 	int ret = 0;
590cb5a6ffcSRussell King 
591d6a89fefSRussell King 	spin_lock_irqsave(&aacirun->lock, flags);
592d6a89fefSRussell King 
593cb5a6ffcSRussell King 	switch (cmd) {
594cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_START:
595cb5a6ffcSRussell King 		aaci_pcm_playback_start(aacirun);
596cb5a6ffcSRussell King 		break;
597cb5a6ffcSRussell King 
598cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_RESUME:
599cb5a6ffcSRussell King 		aaci_pcm_playback_start(aacirun);
600cb5a6ffcSRussell King 		break;
601cb5a6ffcSRussell King 
602cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_STOP:
603cb5a6ffcSRussell King 		aaci_pcm_playback_stop(aacirun);
604cb5a6ffcSRussell King 		break;
605cb5a6ffcSRussell King 
606cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_SUSPEND:
607cb5a6ffcSRussell King 		aaci_pcm_playback_stop(aacirun);
608cb5a6ffcSRussell King 		break;
609cb5a6ffcSRussell King 
610cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
611cb5a6ffcSRussell King 		break;
612cb5a6ffcSRussell King 
613cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
614cb5a6ffcSRussell King 		break;
615cb5a6ffcSRussell King 
616cb5a6ffcSRussell King 	default:
617cb5a6ffcSRussell King 		ret = -EINVAL;
618cb5a6ffcSRussell King 	}
619d6a89fefSRussell King 
620d6a89fefSRussell King 	spin_unlock_irqrestore(&aacirun->lock, flags);
621cb5a6ffcSRussell King 
622cb5a6ffcSRussell King 	return ret;
623cb5a6ffcSRussell King }
624cb5a6ffcSRussell King 
62528f05480SArvind Yadav static const struct snd_pcm_ops aaci_playback_ops = {
62641762b8cSKevin Hilman 	.open		= aaci_pcm_open,
627cb5a6ffcSRussell King 	.close		= aaci_pcm_close,
62858e8a474SRussell King 	.hw_params	= aaci_pcm_hw_params,
629cb5a6ffcSRussell King 	.hw_free	= aaci_pcm_hw_free,
630cb5a6ffcSRussell King 	.prepare	= aaci_pcm_prepare,
631cb5a6ffcSRussell King 	.trigger	= aaci_pcm_playback_trigger,
632cb5a6ffcSRussell King 	.pointer	= aaci_pcm_pointer,
633cb5a6ffcSRussell King };
634cb5a6ffcSRussell King 
aaci_pcm_capture_stop(struct aaci_runtime * aacirun)63541762b8cSKevin Hilman static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun)
63641762b8cSKevin Hilman {
63741762b8cSKevin Hilman 	u32 ie;
63841762b8cSKevin Hilman 
639d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_RXB);
64041762b8cSKevin Hilman 
64141762b8cSKevin Hilman 	ie = readl(aacirun->base + AACI_IE);
64241762b8cSKevin Hilman 	ie &= ~(IE_ORIE | IE_RXIE);
64341762b8cSKevin Hilman 	writel(ie, aacirun->base+AACI_IE);
64441762b8cSKevin Hilman 
64541762b8cSKevin Hilman 	aacirun->cr &= ~CR_EN;
64641762b8cSKevin Hilman 
64741762b8cSKevin Hilman 	writel(aacirun->cr, aacirun->base + AACI_RXCR);
64841762b8cSKevin Hilman }
64941762b8cSKevin Hilman 
aaci_pcm_capture_start(struct aaci_runtime * aacirun)65041762b8cSKevin Hilman static void aaci_pcm_capture_start(struct aaci_runtime *aacirun)
65141762b8cSKevin Hilman {
65241762b8cSKevin Hilman 	u32 ie;
65341762b8cSKevin Hilman 
654d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_RXB);
65541762b8cSKevin Hilman 
65641762b8cSKevin Hilman #ifdef DEBUG
65741762b8cSKevin Hilman 	/* RX Timeout value: bits 28:17 in RXCR */
65841762b8cSKevin Hilman 	aacirun->cr |= 0xf << 17;
65941762b8cSKevin Hilman #endif
66041762b8cSKevin Hilman 
66141762b8cSKevin Hilman 	aacirun->cr |= CR_EN;
66241762b8cSKevin Hilman 	writel(aacirun->cr, aacirun->base + AACI_RXCR);
66341762b8cSKevin Hilman 
66441762b8cSKevin Hilman 	ie = readl(aacirun->base + AACI_IE);
66541762b8cSKevin Hilman 	ie |= IE_ORIE |IE_RXIE; // overrun and rx interrupt -- half full
66641762b8cSKevin Hilman 	writel(ie, aacirun->base + AACI_IE);
66741762b8cSKevin Hilman }
66841762b8cSKevin Hilman 
aaci_pcm_capture_trigger(struct snd_pcm_substream * substream,int cmd)6698a371840SRussell King static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
6708a371840SRussell King {
67141762b8cSKevin Hilman 	struct aaci_runtime *aacirun = substream->runtime->private_data;
67241762b8cSKevin Hilman 	unsigned long flags;
67341762b8cSKevin Hilman 	int ret = 0;
67441762b8cSKevin Hilman 
675d6a89fefSRussell King 	spin_lock_irqsave(&aacirun->lock, flags);
67641762b8cSKevin Hilman 
67741762b8cSKevin Hilman 	switch (cmd) {
67841762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_START:
67941762b8cSKevin Hilman 		aaci_pcm_capture_start(aacirun);
68041762b8cSKevin Hilman 		break;
68141762b8cSKevin Hilman 
68241762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_RESUME:
68341762b8cSKevin Hilman 		aaci_pcm_capture_start(aacirun);
68441762b8cSKevin Hilman 		break;
68541762b8cSKevin Hilman 
68641762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_STOP:
68741762b8cSKevin Hilman 		aaci_pcm_capture_stop(aacirun);
68841762b8cSKevin Hilman 		break;
68941762b8cSKevin Hilman 
69041762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_SUSPEND:
69141762b8cSKevin Hilman 		aaci_pcm_capture_stop(aacirun);
69241762b8cSKevin Hilman 		break;
69341762b8cSKevin Hilman 
69441762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
69541762b8cSKevin Hilman 		break;
69641762b8cSKevin Hilman 
69741762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
69841762b8cSKevin Hilman 		break;
69941762b8cSKevin Hilman 
70041762b8cSKevin Hilman 	default:
70141762b8cSKevin Hilman 		ret = -EINVAL;
70241762b8cSKevin Hilman 	}
70341762b8cSKevin Hilman 
704d6a89fefSRussell King 	spin_unlock_irqrestore(&aacirun->lock, flags);
70541762b8cSKevin Hilman 
70641762b8cSKevin Hilman 	return ret;
70741762b8cSKevin Hilman }
70841762b8cSKevin Hilman 
aaci_pcm_capture_prepare(struct snd_pcm_substream * substream)7098a371840SRussell King static int aaci_pcm_capture_prepare(struct snd_pcm_substream *substream)
71041762b8cSKevin Hilman {
71141762b8cSKevin Hilman 	struct snd_pcm_runtime *runtime = substream->runtime;
71241762b8cSKevin Hilman 	struct aaci *aaci = substream->private_data;
71341762b8cSKevin Hilman 
71441762b8cSKevin Hilman 	aaci_pcm_prepare(substream);
71541762b8cSKevin Hilman 
71641762b8cSKevin Hilman 	/* allow changing of sample rate */
71741762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_EXTENDED_STATUS, 0x0001); /* VRA */
71841762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
71941762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate);
72041762b8cSKevin Hilman 
72141762b8cSKevin Hilman 	/* Record select: Mic: 0, Aux: 3, Line: 4 */
72241762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_REC_SEL, 0x0404);
72341762b8cSKevin Hilman 
72441762b8cSKevin Hilman 	return 0;
72541762b8cSKevin Hilman }
72641762b8cSKevin Hilman 
72728f05480SArvind Yadav static const struct snd_pcm_ops aaci_capture_ops = {
72841762b8cSKevin Hilman 	.open		= aaci_pcm_open,
72941762b8cSKevin Hilman 	.close		= aaci_pcm_close,
73058e8a474SRussell King 	.hw_params	= aaci_pcm_hw_params,
73141762b8cSKevin Hilman 	.hw_free	= aaci_pcm_hw_free,
73241762b8cSKevin Hilman 	.prepare	= aaci_pcm_capture_prepare,
73341762b8cSKevin Hilman 	.trigger	= aaci_pcm_capture_trigger,
73441762b8cSKevin Hilman 	.pointer	= aaci_pcm_pointer,
73541762b8cSKevin Hilman };
736cb5a6ffcSRussell King 
737cb5a6ffcSRussell King /*
738cb5a6ffcSRussell King  * Power Management.
739cb5a6ffcSRussell King  */
740cb5a6ffcSRussell King #ifdef CONFIG_PM
aaci_do_suspend(struct snd_card * card)741b13a7149SUlf Hansson static int aaci_do_suspend(struct snd_card *card)
742cb5a6ffcSRussell King {
743cb5a6ffcSRussell King 	struct aaci *aaci = card->private_data;
744792a6c51STakashi Iwai 	snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
745cb5a6ffcSRussell King 	return 0;
746cb5a6ffcSRussell King }
747cb5a6ffcSRussell King 
aaci_do_resume(struct snd_card * card)748b13a7149SUlf Hansson static int aaci_do_resume(struct snd_card *card)
749cb5a6ffcSRussell King {
750792a6c51STakashi Iwai 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
751cb5a6ffcSRussell King 	return 0;
752cb5a6ffcSRussell King }
753cb5a6ffcSRussell King 
aaci_suspend(struct device * dev)754b13a7149SUlf Hansson static int aaci_suspend(struct device *dev)
755cb5a6ffcSRussell King {
756b13a7149SUlf Hansson 	struct snd_card *card = dev_get_drvdata(dev);
757cb5a6ffcSRussell King 	return card ? aaci_do_suspend(card) : 0;
758cb5a6ffcSRussell King }
759cb5a6ffcSRussell King 
aaci_resume(struct device * dev)760b13a7149SUlf Hansson static int aaci_resume(struct device *dev)
761cb5a6ffcSRussell King {
762b13a7149SUlf Hansson 	struct snd_card *card = dev_get_drvdata(dev);
763cb5a6ffcSRussell King 	return card ? aaci_do_resume(card) : 0;
764cb5a6ffcSRussell King }
765b13a7149SUlf Hansson 
766b13a7149SUlf Hansson static SIMPLE_DEV_PM_OPS(aaci_dev_pm_ops, aaci_suspend, aaci_resume);
767b13a7149SUlf Hansson #define AACI_DEV_PM_OPS (&aaci_dev_pm_ops)
768cb5a6ffcSRussell King #else
769b13a7149SUlf Hansson #define AACI_DEV_PM_OPS NULL
770cb5a6ffcSRussell King #endif
771cb5a6ffcSRussell King 
772cb5a6ffcSRussell King 
7739b419cd4SArvind Yadav static const struct ac97_pcm ac97_defs[] = {
774cb5a6ffcSRussell King 	[0] = {	/* Front PCM */
775cb5a6ffcSRussell King 		.exclusive = 1,
776cb5a6ffcSRussell King 		.r = {
777cb5a6ffcSRussell King 			[0] = {
778cb5a6ffcSRussell King 				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
779cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_RIGHT) |
780cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_CENTER) |
781cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_SLEFT) |
782cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_SRIGHT) |
783cb5a6ffcSRussell King 					  (1 << AC97_SLOT_LFE),
784cb5a6ffcSRussell King 			},
785a08d5658SRussell King 			[1] = {
786a08d5658SRussell King 				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
787a08d5658SRussell King 					  (1 << AC97_SLOT_PCM_RIGHT) |
788a08d5658SRussell King 					  (1 << AC97_SLOT_PCM_LEFT_0) |
789a08d5658SRussell King 					  (1 << AC97_SLOT_PCM_RIGHT_0),
790a08d5658SRussell King 			},
791cb5a6ffcSRussell King 		},
792cb5a6ffcSRussell King 	},
793cb5a6ffcSRussell King 	[1] = {	/* PCM in */
794cb5a6ffcSRussell King 		.stream = 1,
795cb5a6ffcSRussell King 		.exclusive = 1,
796cb5a6ffcSRussell King 		.r = {
797cb5a6ffcSRussell King 			[0] = {
798cb5a6ffcSRussell King 				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
799cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_RIGHT),
800cb5a6ffcSRussell King 			},
801cb5a6ffcSRussell King 		},
802cb5a6ffcSRussell King 	},
803cb5a6ffcSRussell King 	[2] = {	/* Mic in */
804cb5a6ffcSRussell King 		.stream = 1,
805cb5a6ffcSRussell King 		.exclusive = 1,
806cb5a6ffcSRussell King 		.r = {
807cb5a6ffcSRussell King 			[0] = {
808cb5a6ffcSRussell King 				.slots	= (1 << AC97_SLOT_MIC),
809cb5a6ffcSRussell King 			},
810cb5a6ffcSRussell King 		},
811cb5a6ffcSRussell King 	}
812cb5a6ffcSRussell King };
813cb5a6ffcSRussell King 
81474d2bae3STakashi Iwai static const struct snd_ac97_bus_ops aaci_bus_ops = {
815cb5a6ffcSRussell King 	.write	= aaci_ac97_write,
816cb5a6ffcSRussell King 	.read	= aaci_ac97_read,
817cb5a6ffcSRussell King };
818cb5a6ffcSRussell King 
aaci_probe_ac97(struct aaci * aaci)8196c9dc19cSBill Pemberton static int aaci_probe_ac97(struct aaci *aaci)
820cb5a6ffcSRussell King {
821ceb9e476STakashi Iwai 	struct snd_ac97_template ac97_template;
822ceb9e476STakashi Iwai 	struct snd_ac97_bus *ac97_bus;
823ceb9e476STakashi Iwai 	struct snd_ac97 *ac97;
824cb5a6ffcSRussell King 	int ret;
825cb5a6ffcSRussell King 
826cb5a6ffcSRussell King 	/*
827cb5a6ffcSRussell King 	 * Assert AACIRESET for 2us
828cb5a6ffcSRussell King 	 */
829cb5a6ffcSRussell King 	writel(0, aaci->base + AACI_RESET);
830cb5a6ffcSRussell King 	udelay(2);
831cb5a6ffcSRussell King 	writel(RESET_NRST, aaci->base + AACI_RESET);
832cb5a6ffcSRussell King 
833cb5a6ffcSRussell King 	/*
834cb5a6ffcSRussell King 	 * Give the AC'97 codec more than enough time
835cb5a6ffcSRussell King 	 * to wake up. (42us = ~2 frames at 48kHz.)
836cb5a6ffcSRussell King 	 */
837250c7a61SRussell King 	udelay(FRAME_PERIOD_US * 2);
838cb5a6ffcSRussell King 
839cb5a6ffcSRussell King 	ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus);
840cb5a6ffcSRussell King 	if (ret)
841cb5a6ffcSRussell King 		goto out;
842cb5a6ffcSRussell King 
843cb5a6ffcSRussell King 	ac97_bus->clock = 48000;
844cb5a6ffcSRussell King 	aaci->ac97_bus = ac97_bus;
845cb5a6ffcSRussell King 
846ceb9e476STakashi Iwai 	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
847cb5a6ffcSRussell King 	ac97_template.private_data = aaci;
848cb5a6ffcSRussell King 	ac97_template.num = 0;
849cb5a6ffcSRussell King 	ac97_template.scaps = AC97_SCAP_SKIP_MODEM;
850cb5a6ffcSRussell King 
851cb5a6ffcSRussell King 	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
852cb5a6ffcSRussell King 	if (ret)
853cb5a6ffcSRussell King 		goto out;
85441762b8cSKevin Hilman 	aaci->ac97 = ac97;
855cb5a6ffcSRussell King 
856cb5a6ffcSRussell King 	/*
857cb5a6ffcSRussell King 	 * Disable AC97 PC Beep input on audio codecs.
858cb5a6ffcSRussell King 	 */
859cb5a6ffcSRussell King 	if (ac97_is_audio(ac97))
860cb5a6ffcSRussell King 		snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e);
861cb5a6ffcSRussell King 
862cb5a6ffcSRussell King 	ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs);
863cb5a6ffcSRussell King 	if (ret)
864cb5a6ffcSRussell King 		goto out;
865cb5a6ffcSRussell King 
866cb5a6ffcSRussell King 	aaci->playback.pcm = &ac97_bus->pcms[0];
86741762b8cSKevin Hilman 	aaci->capture.pcm  = &ac97_bus->pcms[1];
868cb5a6ffcSRussell King 
869cb5a6ffcSRussell King  out:
870cb5a6ffcSRussell King 	return ret;
871cb5a6ffcSRussell King }
872cb5a6ffcSRussell King 
aaci_free_card(struct snd_card * card)873ceb9e476STakashi Iwai static void aaci_free_card(struct snd_card *card)
874cb5a6ffcSRussell King {
875cb5a6ffcSRussell King 	struct aaci *aaci = card->private_data;
876ff6defa6SMarkus Elfring 
877cb5a6ffcSRussell King 	iounmap(aaci->base);
878cb5a6ffcSRussell King }
879cb5a6ffcSRussell King 
aaci_init_card(struct amba_device * dev)8806c9dc19cSBill Pemberton static struct aaci *aaci_init_card(struct amba_device *dev)
881cb5a6ffcSRussell King {
882cb5a6ffcSRussell King 	struct aaci *aaci;
883ceb9e476STakashi Iwai 	struct snd_card *card;
884bd7dd77cSTakashi Iwai 	int err;
885cb5a6ffcSRussell King 
8864a875580STakashi Iwai 	err = snd_card_new(&dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
887bd7dd77cSTakashi Iwai 			   THIS_MODULE, sizeof(struct aaci), &card);
888bd7dd77cSTakashi Iwai 	if (err < 0)
889631e8ad4STakashi Iwai 		return NULL;
890cb5a6ffcSRussell King 
891cb5a6ffcSRussell King 	card->private_free = aaci_free_card;
892cb5a6ffcSRussell King 
893cb5a6ffcSRussell King 	strscpy(card->driver, DRIVER_NAME, sizeof(card->driver));
894cb5a6ffcSRussell King 	strscpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
895cb5a6ffcSRussell King 	snprintf(card->longname, sizeof(card->longname),
896f006d8fcSRussell King 		 "%s PL%03x rev%u at 0x%08llx, irq %d",
897f006d8fcSRussell King 		 card->shortname, amba_part(dev), amba_rev(dev),
898f006d8fcSRussell King 		 (unsigned long long)dev->res.start, dev->irq[0]);
899cb5a6ffcSRussell King 
900cb5a6ffcSRussell King 	aaci = card->private_data;
90112aa7579SIngo Molnar 	mutex_init(&aaci->ac97_sem);
902b60fb519SRussell King 	mutex_init(&aaci->irq_lock);
903cb5a6ffcSRussell King 	aaci->card = card;
904cb5a6ffcSRussell King 	aaci->dev = dev;
905cb5a6ffcSRussell King 
906cb5a6ffcSRussell King 	/* Set MAINCR to allow slot 1 and 2 data IO */
907cb5a6ffcSRussell King 	aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN |
908cb5a6ffcSRussell King 		       MAINCR_SL2RXEN | MAINCR_SL2TXEN;
909cb5a6ffcSRussell King 
910cb5a6ffcSRussell King 	return aaci;
911cb5a6ffcSRussell King }
912cb5a6ffcSRussell King 
aaci_init_pcm(struct aaci * aaci)9136c9dc19cSBill Pemberton static int aaci_init_pcm(struct aaci *aaci)
914cb5a6ffcSRussell King {
915ceb9e476STakashi Iwai 	struct snd_pcm *pcm;
916cb5a6ffcSRussell King 	int ret;
917cb5a6ffcSRussell King 
91841762b8cSKevin Hilman 	ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm);
919cb5a6ffcSRussell King 	if (ret == 0) {
920cb5a6ffcSRussell King 		aaci->pcm = pcm;
921cb5a6ffcSRussell King 		pcm->private_data = aaci;
922cb5a6ffcSRussell King 		pcm->info_flags = 0;
923cb5a6ffcSRussell King 
924cb5a6ffcSRussell King 		strscpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
925cb5a6ffcSRussell King 
926cb5a6ffcSRussell King 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops);
92741762b8cSKevin Hilman 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops);
9288ee0c758STakashi Iwai 		snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
929bc70a9d7STakashi Iwai 					       aaci->card->dev,
930bc70a9d7STakashi Iwai 					       0, 64 * 1024);
931cb5a6ffcSRussell King 	}
932cb5a6ffcSRussell King 
933cb5a6ffcSRussell King 	return ret;
934cb5a6ffcSRussell King }
935cb5a6ffcSRussell King 
aaci_size_fifo(struct aaci * aaci)9366c9dc19cSBill Pemberton static unsigned int aaci_size_fifo(struct aaci *aaci)
937cb5a6ffcSRussell King {
93841762b8cSKevin Hilman 	struct aaci_runtime *aacirun = &aaci->playback;
939cb5a6ffcSRussell King 	int i;
940cb5a6ffcSRussell King 
9415d350cbaSRussell King 	/*
9425d350cbaSRussell King 	 * Enable the channel, but don't assign it to any slots, so
9435d350cbaSRussell King 	 * it won't empty onto the AC'97 link.
9445d350cbaSRussell King 	 */
94541762b8cSKevin Hilman 	writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR);
946cb5a6ffcSRussell King 
94741762b8cSKevin Hilman 	for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++)
94841762b8cSKevin Hilman 		writel(0, aacirun->fifo);
949cb5a6ffcSRussell King 
95041762b8cSKevin Hilman 	writel(0, aacirun->base + AACI_TXCR);
951cb5a6ffcSRussell King 
952cb5a6ffcSRussell King 	/*
953cb5a6ffcSRussell King 	 * Re-initialise the AACI after the FIFO depth test, to
954cb5a6ffcSRussell King 	 * ensure that the FIFOs are empty.  Unfortunately, merely
955cb5a6ffcSRussell King 	 * disabling the channel doesn't clear the FIFO.
956cb5a6ffcSRussell King 	 */
957cb5a6ffcSRussell King 	writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR);
9587c289385SRussell King 	readl(aaci->base + AACI_MAINCR);
9597c289385SRussell King 	udelay(1);
960cb5a6ffcSRussell King 	writel(aaci->maincr, aaci->base + AACI_MAINCR);
961cb5a6ffcSRussell King 
962cb5a6ffcSRussell King 	/*
9635d350cbaSRussell King 	 * If we hit 4096 entries, we failed.  Go back to the specified
964cb5a6ffcSRussell King 	 * fifo depth.
965cb5a6ffcSRussell King 	 */
966cb5a6ffcSRussell King 	if (i == 4096)
967cb5a6ffcSRussell King 		i = 8;
968cb5a6ffcSRussell King 
969cb5a6ffcSRussell King 	return i;
970cb5a6ffcSRussell King }
971cb5a6ffcSRussell King 
aaci_probe(struct amba_device * dev,const struct amba_id * id)9726c9dc19cSBill Pemberton static int aaci_probe(struct amba_device *dev,
973aa25afadSRussell King 		      const struct amba_id *id)
974cb5a6ffcSRussell King {
975cb5a6ffcSRussell King 	struct aaci *aaci;
976cb5a6ffcSRussell King 	int ret, i;
977cb5a6ffcSRussell King 
978cb5a6ffcSRussell King 	ret = amba_request_regions(dev, NULL);
979cb5a6ffcSRussell King 	if (ret)
980cb5a6ffcSRussell King 		return ret;
981cb5a6ffcSRussell King 
982cb5a6ffcSRussell King 	aaci = aaci_init_card(dev);
983631e8ad4STakashi Iwai 	if (!aaci) {
984631e8ad4STakashi Iwai 		ret = -ENOMEM;
985cb5a6ffcSRussell King 		goto out;
986cb5a6ffcSRussell King 	}
987cb5a6ffcSRussell King 
988dc890c2dSLinus Walleij 	aaci->base = ioremap(dev->res.start, resource_size(&dev->res));
989cb5a6ffcSRussell King 	if (!aaci->base) {
990cb5a6ffcSRussell King 		ret = -ENOMEM;
991cb5a6ffcSRussell King 		goto out;
992cb5a6ffcSRussell King 	}
993cb5a6ffcSRussell King 
994cb5a6ffcSRussell King 	/*
995cb5a6ffcSRussell King 	 * Playback uses AACI channel 0
996cb5a6ffcSRussell King 	 */
997d6a89fefSRussell King 	spin_lock_init(&aaci->playback.lock);
998cb5a6ffcSRussell King 	aaci->playback.base = aaci->base + AACI_CSCH1;
999cb5a6ffcSRussell King 	aaci->playback.fifo = aaci->base + AACI_DR1;
1000cb5a6ffcSRussell King 
100141762b8cSKevin Hilman 	/*
100241762b8cSKevin Hilman 	 * Capture uses AACI channel 0
100341762b8cSKevin Hilman 	 */
1004d6a89fefSRussell King 	spin_lock_init(&aaci->capture.lock);
100541762b8cSKevin Hilman 	aaci->capture.base = aaci->base + AACI_CSCH1;
100641762b8cSKevin Hilman 	aaci->capture.fifo = aaci->base + AACI_DR1;
100741762b8cSKevin Hilman 
1008cb5a6ffcSRussell King 	for (i = 0; i < 4; i++) {
1009e12ba644Sviro@ZenIV.linux.org.uk 		void __iomem *base = aaci->base + i * 0x14;
1010cb5a6ffcSRussell King 
1011cb5a6ffcSRussell King 		writel(0, base + AACI_IE);
1012cb5a6ffcSRussell King 		writel(0, base + AACI_TXCR);
1013cb5a6ffcSRussell King 		writel(0, base + AACI_RXCR);
1014cb5a6ffcSRussell King 	}
1015cb5a6ffcSRussell King 
1016cb5a6ffcSRussell King 	writel(0x1fff, aaci->base + AACI_INTCLR);
1017cb5a6ffcSRussell King 	writel(aaci->maincr, aaci->base + AACI_MAINCR);
1018b68b58fdSPhilby John 	/*
1019b68b58fdSPhilby John 	 * Fix: ac97 read back fail errors by reading
1020b68b58fdSPhilby John 	 * from any arbitrary aaci register.
1021b68b58fdSPhilby John 	 */
1022b68b58fdSPhilby John 	readl(aaci->base + AACI_CSCH1);
1023cb5a6ffcSRussell King 	ret = aaci_probe_ac97(aaci);
1024cb5a6ffcSRussell King 	if (ret)
1025cb5a6ffcSRussell King 		goto out;
1026cb5a6ffcSRussell King 
1027f27f218cSCatalin Marinas 	/*
1028f27f218cSCatalin Marinas 	 * Size the FIFOs (must be multiple of 16).
10295d350cbaSRussell King 	 * This is the number of entries in the FIFO.
1030f27f218cSCatalin Marinas 	 */
10315d350cbaSRussell King 	aaci->fifo_depth = aaci_size_fifo(aaci);
10325d350cbaSRussell King 	if (aaci->fifo_depth & 15) {
10335d350cbaSRussell King 		printk(KERN_WARNING "AACI: FIFO depth %d not supported\n",
10345d350cbaSRussell King 		       aaci->fifo_depth);
1035f27f218cSCatalin Marinas 		ret = -ENODEV;
1036f27f218cSCatalin Marinas 		goto out;
1037f27f218cSCatalin Marinas 	}
1038f27f218cSCatalin Marinas 
1039cb5a6ffcSRussell King 	ret = aaci_init_pcm(aaci);
1040cb5a6ffcSRussell King 	if (ret)
1041cb5a6ffcSRussell King 		goto out;
1042cb5a6ffcSRussell King 
1043cb5a6ffcSRussell King 	ret = snd_card_register(aaci->card);
1044cb5a6ffcSRussell King 	if (ret == 0) {
10455d350cbaSRussell King 		dev_info(&dev->dev, "%s\n", aaci->card->longname);
10465d350cbaSRussell King 		dev_info(&dev->dev, "FIFO %u entries\n", aaci->fifo_depth);
1047cb5a6ffcSRussell King 		amba_set_drvdata(dev, aaci->card);
1048cb5a6ffcSRussell King 		return ret;
1049cb5a6ffcSRussell King 	}
1050cb5a6ffcSRussell King 
1051cb5a6ffcSRussell King  out:
1052cb5a6ffcSRussell King 	if (aaci)
1053cb5a6ffcSRussell King 		snd_card_free(aaci->card);
1054cb5a6ffcSRussell King 	amba_release_regions(dev);
1055cb5a6ffcSRussell King 	return ret;
1056cb5a6ffcSRussell King }
1057cb5a6ffcSRussell King 
aaci_remove(struct amba_device * dev)1058*3fd269e7SUwe Kleine-König static void aaci_remove(struct amba_device *dev)
1059cb5a6ffcSRussell King {
1060ceb9e476STakashi Iwai 	struct snd_card *card = amba_get_drvdata(dev);
1061cb5a6ffcSRussell King 
1062cb5a6ffcSRussell King 	if (card) {
1063cb5a6ffcSRussell King 		struct aaci *aaci = card->private_data;
1064cb5a6ffcSRussell King 		writel(0, aaci->base + AACI_MAINCR);
1065cb5a6ffcSRussell King 
1066cb5a6ffcSRussell King 		snd_card_free(card);
1067cb5a6ffcSRussell King 		amba_release_regions(dev);
1068cb5a6ffcSRussell King 	}
1069cb5a6ffcSRussell King }
1070cb5a6ffcSRussell King 
1071cb5a6ffcSRussell King static struct amba_id aaci_ids[] = {
1072cb5a6ffcSRussell King 	{
1073cb5a6ffcSRussell King 		.id	= 0x00041041,
1074cb5a6ffcSRussell King 		.mask	= 0x000fffff,
1075cb5a6ffcSRussell King 	},
1076cb5a6ffcSRussell King 	{ 0, 0 },
1077cb5a6ffcSRussell King };
1078cb5a6ffcSRussell King 
10799d5c6273SDave Martin MODULE_DEVICE_TABLE(amba, aaci_ids);
10809d5c6273SDave Martin 
1081cb5a6ffcSRussell King static struct amba_driver aaci_driver = {
1082cb5a6ffcSRussell King 	.drv		= {
1083cb5a6ffcSRussell King 		.name	= DRIVER_NAME,
1084b13a7149SUlf Hansson 		.pm	= AACI_DEV_PM_OPS,
1085cb5a6ffcSRussell King 	},
1086cb5a6ffcSRussell King 	.probe		= aaci_probe,
10876c9dc19cSBill Pemberton 	.remove		= aaci_remove,
1088cb5a6ffcSRussell King 	.id_table	= aaci_ids,
1089cb5a6ffcSRussell King };
1090cb5a6ffcSRussell King 
10919e5ed094Sviresh kumar module_amba_driver(aaci_driver);
1092cb5a6ffcSRussell King 
1093cb5a6ffcSRussell King MODULE_LICENSE("GPL");
1094cb5a6ffcSRussell King MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver");
1095