xref: /openbmc/linux/sound/arm/aaci.c (revision aa25afad)
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 
537c289385SRussell King 	if (maincr != readl(aaci->base + AACI_MAINCR)) {
54cb5a6ffcSRussell King 		writel(maincr, aaci->base + AACI_MAINCR);
557c289385SRussell King 		readl(aaci->base + AACI_MAINCR);
567c289385SRussell King 		udelay(1);
577c289385SRussell King 	}
58cb5a6ffcSRussell King }
59cb5a6ffcSRussell King 
60cb5a6ffcSRussell King /*
61cb5a6ffcSRussell King  * P29:
62cb5a6ffcSRussell King  *  The recommended use of programming the external codec through slot 1
63cb5a6ffcSRussell King  *  and slot 2 data is to use the channels during setup routines and the
64cb5a6ffcSRussell King  *  slot register at any other time.  The data written into slot 1, slot 2
65cb5a6ffcSRussell King  *  and slot 12 registers is transmitted only when their corresponding
66cb5a6ffcSRussell King  *  SI1TxEn, SI2TxEn and SI12TxEn bits are set in the AACI_MAINCR
67cb5a6ffcSRussell King  *  register.
68cb5a6ffcSRussell King  */
6914d178a1SKevin Hilman static void aaci_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
7014d178a1SKevin Hilman 			    unsigned short val)
71cb5a6ffcSRussell King {
72cb5a6ffcSRussell King 	struct aaci *aaci = ac97->private_data;
73250c7a61SRussell King 	int timeout;
74cb5a6ffcSRussell King 	u32 v;
75cb5a6ffcSRussell King 
76cb5a6ffcSRussell King 	if (ac97->num >= 4)
77cb5a6ffcSRussell King 		return;
78cb5a6ffcSRussell King 
7912aa7579SIngo Molnar 	mutex_lock(&aaci->ac97_sem);
80cb5a6ffcSRussell King 
81cb5a6ffcSRussell King 	aaci_ac97_select_codec(aaci, ac97);
82cb5a6ffcSRussell King 
83cb5a6ffcSRussell King 	/*
84cb5a6ffcSRussell King 	 * P54: You must ensure that AACI_SL2TX is always written
85cb5a6ffcSRussell King 	 * to, if required, before data is written to AACI_SL1TX.
86cb5a6ffcSRussell King 	 */
87cb5a6ffcSRussell King 	writel(val << 4, aaci->base + AACI_SL2TX);
88cb5a6ffcSRussell King 	writel(reg << 12, aaci->base + AACI_SL1TX);
89cb5a6ffcSRussell King 
90250c7a61SRussell King 	/* Initially, wait one frame period */
91250c7a61SRussell King 	udelay(FRAME_PERIOD_US);
92250c7a61SRussell King 
93250c7a61SRussell King 	/* And then wait an additional eight frame periods for it to be sent */
94250c7a61SRussell King 	timeout = FRAME_PERIOD_US * 8;
95cb5a6ffcSRussell King 	do {
96250c7a61SRussell King 		udelay(1);
97cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SLFR);
98f6f35bbeSRoel Kluin 	} while ((v & (SLFR_1TXB|SLFR_2TXB)) && --timeout);
9914d178a1SKevin Hilman 
10069058cd6SRussell King 	if (v & (SLFR_1TXB|SLFR_2TXB))
10114d178a1SKevin Hilman 		dev_err(&aaci->dev->dev,
10214d178a1SKevin Hilman 			"timeout waiting for write to complete\n");
103cb5a6ffcSRussell King 
10412aa7579SIngo Molnar 	mutex_unlock(&aaci->ac97_sem);
105cb5a6ffcSRussell King }
106cb5a6ffcSRussell King 
107cb5a6ffcSRussell King /*
108cb5a6ffcSRussell King  * Read an AC'97 register.
109cb5a6ffcSRussell King  */
110ceb9e476STakashi Iwai static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
111cb5a6ffcSRussell King {
112cb5a6ffcSRussell King 	struct aaci *aaci = ac97->private_data;
113250c7a61SRussell King 	int timeout, retries = 10;
114cb5a6ffcSRussell King 	u32 v;
115cb5a6ffcSRussell King 
116cb5a6ffcSRussell King 	if (ac97->num >= 4)
117cb5a6ffcSRussell King 		return ~0;
118cb5a6ffcSRussell King 
11912aa7579SIngo Molnar 	mutex_lock(&aaci->ac97_sem);
120cb5a6ffcSRussell King 
121cb5a6ffcSRussell King 	aaci_ac97_select_codec(aaci, ac97);
122cb5a6ffcSRussell King 
123cb5a6ffcSRussell King 	/*
124cb5a6ffcSRussell King 	 * Write the register address to slot 1.
125cb5a6ffcSRussell King 	 */
126cb5a6ffcSRussell King 	writel((reg << 12) | (1 << 19), aaci->base + AACI_SL1TX);
127cb5a6ffcSRussell King 
128250c7a61SRussell King 	/* Initially, wait one frame period */
129250c7a61SRussell King 	udelay(FRAME_PERIOD_US);
130250c7a61SRussell King 
131250c7a61SRussell King 	/* And then wait an additional eight frame periods for it to be sent */
132250c7a61SRussell King 	timeout = FRAME_PERIOD_US * 8;
133cb5a6ffcSRussell King 	do {
134250c7a61SRussell King 		udelay(1);
135cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SLFR);
136f6f35bbeSRoel Kluin 	} while ((v & SLFR_1TXB) && --timeout);
13714d178a1SKevin Hilman 
13869058cd6SRussell King 	if (v & SLFR_1TXB) {
13914d178a1SKevin Hilman 		dev_err(&aaci->dev->dev, "timeout on slot 1 TX busy\n");
14014d178a1SKevin Hilman 		v = ~0;
14114d178a1SKevin Hilman 		goto out;
14214d178a1SKevin Hilman 	}
143cb5a6ffcSRussell King 
144250c7a61SRussell King 	/* Now wait for the response frame */
145250c7a61SRussell King 	udelay(FRAME_PERIOD_US);
146cb5a6ffcSRussell King 
147250c7a61SRussell King 	/* And then wait an additional eight frame periods for data */
148250c7a61SRussell King 	timeout = FRAME_PERIOD_US * 8;
149cb5a6ffcSRussell King 	do {
150250c7a61SRussell King 		udelay(1);
151cb5a6ffcSRussell King 		cond_resched();
152cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SLFR) & (SLFR_1RXV|SLFR_2RXV);
153f6f35bbeSRoel Kluin 	} while ((v != (SLFR_1RXV|SLFR_2RXV)) && --timeout);
154cb5a6ffcSRussell King 
15569058cd6SRussell King 	if (v != (SLFR_1RXV|SLFR_2RXV)) {
15614d178a1SKevin Hilman 		dev_err(&aaci->dev->dev, "timeout on RX valid\n");
15714d178a1SKevin Hilman 		v = ~0;
15814d178a1SKevin Hilman 		goto out;
15914d178a1SKevin Hilman 	}
16014d178a1SKevin Hilman 
16114d178a1SKevin Hilman 	do {
162cb5a6ffcSRussell King 		v = readl(aaci->base + AACI_SL1RX) >> 12;
163cb5a6ffcSRussell King 		if (v == reg) {
164cb5a6ffcSRussell King 			v = readl(aaci->base + AACI_SL2RX) >> 4;
16514d178a1SKevin Hilman 			break;
16614d178a1SKevin Hilman 		} else if (--retries) {
16714d178a1SKevin Hilman 			dev_warn(&aaci->dev->dev,
16814d178a1SKevin Hilman 				 "ac97 read back fail.  retry\n");
16914d178a1SKevin Hilman 			continue;
170cb5a6ffcSRussell King 		} else {
17114d178a1SKevin Hilman 			dev_warn(&aaci->dev->dev,
172cb5a6ffcSRussell King 				"wrong ac97 register read back (%x != %x)\n",
173cb5a6ffcSRussell King 				v, reg);
174cb5a6ffcSRussell King 			v = ~0;
175cb5a6ffcSRussell King 		}
17614d178a1SKevin Hilman 	} while (retries);
17714d178a1SKevin Hilman  out:
17812aa7579SIngo Molnar 	mutex_unlock(&aaci->ac97_sem);
179cb5a6ffcSRussell King 	return v;
180cb5a6ffcSRussell King }
181cb5a6ffcSRussell King 
182d6a89fefSRussell King static inline void
183d6a89fefSRussell King aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask)
184cb5a6ffcSRussell King {
185cb5a6ffcSRussell King 	u32 val;
186cb5a6ffcSRussell King 	int timeout = 5000;
187cb5a6ffcSRussell King 
188cb5a6ffcSRussell King 	do {
189250c7a61SRussell King 		udelay(1);
190cb5a6ffcSRussell King 		val = readl(aacirun->base + AACI_SR);
191d6a89fefSRussell King 	} while (val & mask && timeout--);
192cb5a6ffcSRussell King }
193cb5a6ffcSRussell King 
194cb5a6ffcSRussell King 
195cb5a6ffcSRussell King 
196cb5a6ffcSRussell King /*
197cb5a6ffcSRussell King  * Interrupt support.
198cb5a6ffcSRussell King  */
19962578cbfSKevin Hilman static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask)
200cb5a6ffcSRussell King {
20141762b8cSKevin Hilman 	if (mask & ISR_ORINTR) {
20241762b8cSKevin Hilman 		dev_warn(&aaci->dev->dev, "RX overrun on chan %d\n", channel);
20341762b8cSKevin Hilman 		writel(ICLR_RXOEC1 << channel, aaci->base + AACI_INTCLR);
20441762b8cSKevin Hilman 	}
20541762b8cSKevin Hilman 
20641762b8cSKevin Hilman 	if (mask & ISR_RXTOINTR) {
20741762b8cSKevin Hilman 		dev_warn(&aaci->dev->dev, "RX timeout on chan %d\n", channel);
20841762b8cSKevin Hilman 		writel(ICLR_RXTOFEC1 << channel, aaci->base + AACI_INTCLR);
20941762b8cSKevin Hilman 	}
21041762b8cSKevin Hilman 
21141762b8cSKevin Hilman 	if (mask & ISR_RXINTR) {
21241762b8cSKevin Hilman 		struct aaci_runtime *aacirun = &aaci->capture;
21341762b8cSKevin Hilman 		void *ptr;
21441762b8cSKevin Hilman 
21541762b8cSKevin Hilman 		if (!aacirun->substream || !aacirun->start) {
216898eb71cSJoe Perches 			dev_warn(&aaci->dev->dev, "RX interrupt???\n");
21741762b8cSKevin Hilman 			writel(0, aacirun->base + AACI_IE);
21841762b8cSKevin Hilman 			return;
21941762b8cSKevin Hilman 		}
22041762b8cSKevin Hilman 
221d6a89fefSRussell King 		spin_lock(&aacirun->lock);
222d6a89fefSRussell King 
223d6a89fefSRussell King 		ptr = aacirun->ptr;
22441762b8cSKevin Hilman 		do {
22541762b8cSKevin Hilman 			unsigned int len = aacirun->fifosz;
22641762b8cSKevin Hilman 			u32 val;
22741762b8cSKevin Hilman 
22841762b8cSKevin Hilman 			if (aacirun->bytes <= 0) {
22941762b8cSKevin Hilman 				aacirun->bytes += aacirun->period;
23041762b8cSKevin Hilman 				aacirun->ptr = ptr;
231d6a89fefSRussell King 				spin_unlock(&aacirun->lock);
23241762b8cSKevin Hilman 				snd_pcm_period_elapsed(aacirun->substream);
233d6a89fefSRussell King 				spin_lock(&aacirun->lock);
23441762b8cSKevin Hilman 			}
23541762b8cSKevin Hilman 			if (!(aacirun->cr & CR_EN))
23641762b8cSKevin Hilman 				break;
23741762b8cSKevin Hilman 
23841762b8cSKevin Hilman 			val = readl(aacirun->base + AACI_SR);
23941762b8cSKevin Hilman 			if (!(val & SR_RXHF))
24041762b8cSKevin Hilman 				break;
24141762b8cSKevin Hilman 			if (!(val & SR_RXFF))
24241762b8cSKevin Hilman 				len >>= 1;
24341762b8cSKevin Hilman 
24441762b8cSKevin Hilman 			aacirun->bytes -= len;
24541762b8cSKevin Hilman 
24641762b8cSKevin Hilman 			/* reading 16 bytes at a time */
24741762b8cSKevin Hilman 			for( ; len > 0; len -= 16) {
24841762b8cSKevin Hilman 				asm(
24941762b8cSKevin Hilman 					"ldmia	%1, {r0, r1, r2, r3}\n\t"
25041762b8cSKevin Hilman 					"stmia	%0!, {r0, r1, r2, r3}"
25141762b8cSKevin Hilman 					: "+r" (ptr)
25241762b8cSKevin Hilman 					: "r" (aacirun->fifo)
25341762b8cSKevin Hilman 					: "r0", "r1", "r2", "r3", "cc");
25441762b8cSKevin Hilman 
25541762b8cSKevin Hilman 				if (ptr >= aacirun->end)
25641762b8cSKevin Hilman 					ptr = aacirun->start;
25741762b8cSKevin Hilman 			}
25841762b8cSKevin Hilman 		} while(1);
259d6a89fefSRussell King 
26041762b8cSKevin Hilman 		aacirun->ptr = ptr;
261d6a89fefSRussell King 
262d6a89fefSRussell King 		spin_unlock(&aacirun->lock);
26341762b8cSKevin Hilman 	}
26441762b8cSKevin Hilman 
265cb5a6ffcSRussell King 	if (mask & ISR_URINTR) {
26662578cbfSKevin Hilman 		dev_dbg(&aaci->dev->dev, "TX underrun on chan %d\n", channel);
26762578cbfSKevin Hilman 		writel(ICLR_TXUEC1 << channel, aaci->base + AACI_INTCLR);
268cb5a6ffcSRussell King 	}
269cb5a6ffcSRussell King 
270cb5a6ffcSRussell King 	if (mask & ISR_TXINTR) {
271cb5a6ffcSRussell King 		struct aaci_runtime *aacirun = &aaci->playback;
272cb5a6ffcSRussell King 		void *ptr;
273cb5a6ffcSRussell King 
274cb5a6ffcSRussell King 		if (!aacirun->substream || !aacirun->start) {
275898eb71cSJoe Perches 			dev_warn(&aaci->dev->dev, "TX interrupt???\n");
276cb5a6ffcSRussell King 			writel(0, aacirun->base + AACI_IE);
277cb5a6ffcSRussell King 			return;
278cb5a6ffcSRussell King 		}
279cb5a6ffcSRussell King 
280d6a89fefSRussell King 		spin_lock(&aacirun->lock);
281d6a89fefSRussell King 
282cb5a6ffcSRussell King 		ptr = aacirun->ptr;
283cb5a6ffcSRussell King 		do {
284cb5a6ffcSRussell King 			unsigned int len = aacirun->fifosz;
285cb5a6ffcSRussell King 			u32 val;
286cb5a6ffcSRussell King 
287cb5a6ffcSRussell King 			if (aacirun->bytes <= 0) {
288cb5a6ffcSRussell King 				aacirun->bytes += aacirun->period;
289cb5a6ffcSRussell King 				aacirun->ptr = ptr;
290d6a89fefSRussell King 				spin_unlock(&aacirun->lock);
291cb5a6ffcSRussell King 				snd_pcm_period_elapsed(aacirun->substream);
292d6a89fefSRussell King 				spin_lock(&aacirun->lock);
293cb5a6ffcSRussell King 			}
29441762b8cSKevin Hilman 			if (!(aacirun->cr & CR_EN))
295cb5a6ffcSRussell King 				break;
296cb5a6ffcSRussell King 
297cb5a6ffcSRussell King 			val = readl(aacirun->base + AACI_SR);
298cb5a6ffcSRussell King 			if (!(val & SR_TXHE))
299cb5a6ffcSRussell King 				break;
300cb5a6ffcSRussell King 			if (!(val & SR_TXFE))
301cb5a6ffcSRussell King 				len >>= 1;
302cb5a6ffcSRussell King 
303cb5a6ffcSRussell King 			aacirun->bytes -= len;
304cb5a6ffcSRussell King 
305cb5a6ffcSRussell King 			/* writing 16 bytes at a time */
306cb5a6ffcSRussell King 			for ( ; len > 0; len -= 16) {
307cb5a6ffcSRussell King 				asm(
308cb5a6ffcSRussell King 					"ldmia	%0!, {r0, r1, r2, r3}\n\t"
309cb5a6ffcSRussell King 					"stmia	%1, {r0, r1, r2, r3}"
310cb5a6ffcSRussell King 					: "+r" (ptr)
311cb5a6ffcSRussell King 					: "r" (aacirun->fifo)
312cb5a6ffcSRussell King 					: "r0", "r1", "r2", "r3", "cc");
313cb5a6ffcSRussell King 
314cb5a6ffcSRussell King 				if (ptr >= aacirun->end)
315cb5a6ffcSRussell King 					ptr = aacirun->start;
316cb5a6ffcSRussell King 			}
317cb5a6ffcSRussell King 		} while (1);
318cb5a6ffcSRussell King 
319cb5a6ffcSRussell King 		aacirun->ptr = ptr;
320d6a89fefSRussell King 
321d6a89fefSRussell King 		spin_unlock(&aacirun->lock);
322cb5a6ffcSRussell King 	}
323cb5a6ffcSRussell King }
324cb5a6ffcSRussell King 
3257d12e780SDavid Howells static irqreturn_t aaci_irq(int irq, void *devid)
326cb5a6ffcSRussell King {
327cb5a6ffcSRussell King 	struct aaci *aaci = devid;
328cb5a6ffcSRussell King 	u32 mask;
329cb5a6ffcSRussell King 	int i;
330cb5a6ffcSRussell King 
331cb5a6ffcSRussell King 	mask = readl(aaci->base + AACI_ALLINTS);
332cb5a6ffcSRussell King 	if (mask) {
333cb5a6ffcSRussell King 		u32 m = mask;
334cb5a6ffcSRussell King 		for (i = 0; i < 4; i++, m >>= 7) {
335cb5a6ffcSRussell King 			if (m & 0x7f) {
33662578cbfSKevin Hilman 				aaci_fifo_irq(aaci, i, m);
337cb5a6ffcSRussell King 			}
338cb5a6ffcSRussell King 		}
339cb5a6ffcSRussell King 	}
340cb5a6ffcSRussell King 
341cb5a6ffcSRussell King 	return mask ? IRQ_HANDLED : IRQ_NONE;
342cb5a6ffcSRussell King }
343cb5a6ffcSRussell King 
344cb5a6ffcSRussell King 
345cb5a6ffcSRussell King 
346cb5a6ffcSRussell King /*
347cb5a6ffcSRussell King  * ALSA support.
348cb5a6ffcSRussell King  */
349ceb9e476STakashi Iwai static struct snd_pcm_hardware aaci_hw_info = {
350cb5a6ffcSRussell King 	.info			= SNDRV_PCM_INFO_MMAP |
351cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_MMAP_VALID |
352cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_INTERLEAVED |
353cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_BLOCK_TRANSFER |
354cb5a6ffcSRussell King 				  SNDRV_PCM_INFO_RESUME,
355cb5a6ffcSRussell King 
356cb5a6ffcSRussell King 	/*
357cb5a6ffcSRussell King 	 * ALSA doesn't support 18-bit or 20-bit packed into 32-bit
358cb5a6ffcSRussell King 	 * words.  It also doesn't support 12-bit at all.
359cb5a6ffcSRussell King 	 */
360cb5a6ffcSRussell King 	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
361cb5a6ffcSRussell King 
3626ca867c8SRussell King 	/* rates are setup from the AC'97 codec */
363cb5a6ffcSRussell King 	.channels_min		= 2,
364cb5a6ffcSRussell King 	.channels_max		= 6,
365cb5a6ffcSRussell King 	.buffer_bytes_max	= 64 * 1024,
366cb5a6ffcSRussell King 	.period_bytes_min	= 256,
367cb5a6ffcSRussell King 	.period_bytes_max	= PAGE_SIZE,
368cb5a6ffcSRussell King 	.periods_min		= 4,
369cb5a6ffcSRussell King 	.periods_max		= PAGE_SIZE / 16,
370cb5a6ffcSRussell King };
371cb5a6ffcSRussell King 
37241762b8cSKevin Hilman static int __aaci_pcm_open(struct aaci *aaci,
37341762b8cSKevin Hilman 			   struct snd_pcm_substream *substream,
374cb5a6ffcSRussell King 			   struct aaci_runtime *aacirun)
375cb5a6ffcSRussell King {
376ceb9e476STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
377cb5a6ffcSRussell King 	int ret;
378cb5a6ffcSRussell King 
379cb5a6ffcSRussell King 	aacirun->substream = substream;
380cb5a6ffcSRussell King 	runtime->private_data = aacirun;
381cb5a6ffcSRussell King 	runtime->hw = aaci_hw_info;
3826ca867c8SRussell King 	runtime->hw.rates = aacirun->pcm->rates;
3836ca867c8SRussell King 	snd_pcm_limit_hw_rates(runtime);
384cb5a6ffcSRussell King 
385a08d5658SRussell King 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
386a08d5658SRussell King 	    aacirun->pcm->r[1].slots)
387a08d5658SRussell King 		snd_ac97_pcm_double_rate_rules(runtime);
388a08d5658SRussell King 
389cb5a6ffcSRussell King 	/*
390cb5a6ffcSRussell King 	 * FIXME: ALSA specifies fifo_size in bytes.  If we're in normal
391cb5a6ffcSRussell King 	 * mode, each 32-bit word contains one sample.  If we're in
392cb5a6ffcSRussell King 	 * compact mode, each 32-bit word contains two samples, effectively
393cb5a6ffcSRussell King 	 * halving the FIFO size.  However, we don't know for sure which
394cb5a6ffcSRussell King 	 * we'll be using at this point.  We set this to the lower limit.
395cb5a6ffcSRussell King 	 */
396cb5a6ffcSRussell King 	runtime->hw.fifo_size = aaci->fifosize * 2;
397cb5a6ffcSRussell King 
39865ca68b3SThomas Gleixner 	ret = request_irq(aaci->dev->irq[0], aaci_irq, IRQF_SHARED|IRQF_DISABLED,
399cb5a6ffcSRussell King 			  DRIVER_NAME, aaci);
400cb5a6ffcSRussell King 	if (ret)
401cb5a6ffcSRussell King 		goto out;
402cb5a6ffcSRussell King 
403cb5a6ffcSRussell King 	return 0;
404cb5a6ffcSRussell King 
405cb5a6ffcSRussell King  out:
406cb5a6ffcSRussell King 	return ret;
407cb5a6ffcSRussell King }
408cb5a6ffcSRussell King 
409cb5a6ffcSRussell King 
410cb5a6ffcSRussell King /*
411cb5a6ffcSRussell King  * Common ALSA stuff
412cb5a6ffcSRussell King  */
413ceb9e476STakashi Iwai static int aaci_pcm_close(struct snd_pcm_substream *substream)
414cb5a6ffcSRussell King {
415cb5a6ffcSRussell King 	struct aaci *aaci = substream->private_data;
416cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
417cb5a6ffcSRussell King 
41841762b8cSKevin Hilman 	WARN_ON(aacirun->cr & CR_EN);
419cb5a6ffcSRussell King 
420cb5a6ffcSRussell King 	aacirun->substream = NULL;
421cb5a6ffcSRussell King 	free_irq(aaci->dev->irq[0], aaci);
422cb5a6ffcSRussell King 
423cb5a6ffcSRussell King 	return 0;
424cb5a6ffcSRussell King }
425cb5a6ffcSRussell King 
426ceb9e476STakashi Iwai static int aaci_pcm_hw_free(struct snd_pcm_substream *substream)
427cb5a6ffcSRussell King {
428cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
429cb5a6ffcSRussell King 
430cb5a6ffcSRussell King 	/*
431cb5a6ffcSRussell King 	 * This must not be called with the device enabled.
432cb5a6ffcSRussell King 	 */
43341762b8cSKevin Hilman 	WARN_ON(aacirun->cr & CR_EN);
434cb5a6ffcSRussell King 
435cb5a6ffcSRussell King 	if (aacirun->pcm_open)
436cb5a6ffcSRussell King 		snd_ac97_pcm_close(aacirun->pcm);
437cb5a6ffcSRussell King 	aacirun->pcm_open = 0;
438cb5a6ffcSRussell King 
439cb5a6ffcSRussell King 	/*
440cb5a6ffcSRussell King 	 * Clear out the DMA and any allocated buffers.
441cb5a6ffcSRussell King 	 */
442d6797322STakashi Iwai 	snd_pcm_lib_free_pages(substream);
443cb5a6ffcSRussell King 
444cb5a6ffcSRussell King 	return 0;
445cb5a6ffcSRussell King }
446cb5a6ffcSRussell King 
447ceb9e476STakashi Iwai static int aaci_pcm_hw_params(struct snd_pcm_substream *substream,
448cb5a6ffcSRussell King 			      struct aaci_runtime *aacirun,
449ceb9e476STakashi Iwai 			      struct snd_pcm_hw_params *params)
450cb5a6ffcSRussell King {
451cb5a6ffcSRussell King 	int err;
452903b0eb3SPeter Huewe 	struct aaci *aaci = substream->private_data;
453cb5a6ffcSRussell King 
454cb5a6ffcSRussell King 	aaci_pcm_hw_free(substream);
4554acd57c3SRussell King 	if (aacirun->pcm_open) {
4564acd57c3SRussell King 		snd_ac97_pcm_close(aacirun->pcm);
4574acd57c3SRussell King 		aacirun->pcm_open = 0;
4584acd57c3SRussell King 	}
459cb5a6ffcSRussell King 
460d6797322STakashi Iwai 	err = snd_pcm_lib_malloc_pages(substream,
461cb5a6ffcSRussell King 				       params_buffer_bytes(params));
4624e30b691SRussell King 	if (err >= 0) {
463a08d5658SRussell King 		unsigned int rate = params_rate(params);
464a08d5658SRussell King 		int dbl = rate > 48000;
465a08d5658SRussell King 
466a08d5658SRussell King 		err = snd_ac97_pcm_open(aacirun->pcm, rate,
467cb5a6ffcSRussell King 					params_channels(params),
468a08d5658SRussell King 					aacirun->pcm->r[dbl].slots);
469cb5a6ffcSRussell King 
4704e30b691SRussell King 		aacirun->pcm_open = err == 0;
471d3aee799SRussell King 		aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16;
472d3aee799SRussell King 		aacirun->fifosz = aaci->fifosize * 4;
473d3aee799SRussell King 
474d3aee799SRussell King 		if (aacirun->cr & CR_COMPACT)
475d3aee799SRussell King 			aacirun->fifosz >>= 1;
4764e30b691SRussell King 	}
477cb5a6ffcSRussell King 
478cb5a6ffcSRussell King 	return err;
479cb5a6ffcSRussell King }
480cb5a6ffcSRussell King 
481ceb9e476STakashi Iwai static int aaci_pcm_prepare(struct snd_pcm_substream *substream)
482cb5a6ffcSRussell King {
483ceb9e476STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
484cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = runtime->private_data;
485cb5a6ffcSRussell King 
4864e30b691SRussell King 	aacirun->start	= runtime->dma_area;
48788cdca9cSRussell King 	aacirun->end	= aacirun->start + snd_pcm_lib_buffer_bytes(substream);
488cb5a6ffcSRussell King 	aacirun->ptr	= aacirun->start;
489cb5a6ffcSRussell King 	aacirun->period	=
490cb5a6ffcSRussell King 	aacirun->bytes	= frames_to_bytes(runtime, runtime->period_size);
491cb5a6ffcSRussell King 
492cb5a6ffcSRussell King 	return 0;
493cb5a6ffcSRussell King }
494cb5a6ffcSRussell King 
495ceb9e476STakashi Iwai static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream)
496cb5a6ffcSRussell King {
497ceb9e476STakashi Iwai 	struct snd_pcm_runtime *runtime = substream->runtime;
498cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = runtime->private_data;
499cb5a6ffcSRussell King 	ssize_t bytes = aacirun->ptr - aacirun->start;
500cb5a6ffcSRussell King 
501cb5a6ffcSRussell King 	return bytes_to_frames(runtime, bytes);
502cb5a6ffcSRussell King }
503cb5a6ffcSRussell King 
504cb5a6ffcSRussell King 
505cb5a6ffcSRussell King /*
506cb5a6ffcSRussell King  * Playback specific ALSA stuff
507cb5a6ffcSRussell King  */
508cb5a6ffcSRussell King static const u32 channels_to_txmask[] = {
50941762b8cSKevin Hilman 	[2] = CR_SL3 | CR_SL4,
51041762b8cSKevin Hilman 	[4] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8,
51141762b8cSKevin Hilman 	[6] = CR_SL3 | CR_SL4 | CR_SL7 | CR_SL8 | CR_SL6 | CR_SL9,
512cb5a6ffcSRussell King };
513cb5a6ffcSRussell King 
514cb5a6ffcSRussell King /*
515cb5a6ffcSRussell King  * We can support two and four channel audio.  Unfortunately
516cb5a6ffcSRussell King  * six channel audio requires a non-standard channel ordering:
517cb5a6ffcSRussell King  *   2 -> FL(3), FR(4)
518cb5a6ffcSRussell King  *   4 -> FL(3), FR(4), SL(7), SR(8)
519cb5a6ffcSRussell King  *   6 -> FL(3), FR(4), SL(7), SR(8), C(6), LFE(9) (required)
520cb5a6ffcSRussell King  *        FL(3), FR(4), C(6), SL(7), SR(8), LFE(9) (actual)
521cb5a6ffcSRussell King  * This requires an ALSA configuration file to correct.
522cb5a6ffcSRussell King  */
523cb5a6ffcSRussell King static unsigned int channel_list[] = { 2, 4, 6 };
524cb5a6ffcSRussell King 
525cb5a6ffcSRussell King static int
526ceb9e476STakashi Iwai aaci_rule_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule)
527cb5a6ffcSRussell King {
528cb5a6ffcSRussell King 	struct aaci *aaci = rule->private;
529cb5a6ffcSRussell King 	unsigned int chan_mask = 1 << 0, slots;
530cb5a6ffcSRussell King 
531cb5a6ffcSRussell King 	/*
532cb5a6ffcSRussell King 	 * pcms[0] is the our 5.1 PCM instance.
533cb5a6ffcSRussell King 	 */
534cb5a6ffcSRussell King 	slots = aaci->ac97_bus->pcms[0].r[0].slots;
535cb5a6ffcSRussell King 	if (slots & (1 << AC97_SLOT_PCM_SLEFT)) {
536cb5a6ffcSRussell King 		chan_mask |= 1 << 1;
537cb5a6ffcSRussell King 		if (slots & (1 << AC97_SLOT_LFE))
538cb5a6ffcSRussell King 			chan_mask |= 1 << 2;
539cb5a6ffcSRussell King 	}
540cb5a6ffcSRussell King 
541cb5a6ffcSRussell King 	return snd_interval_list(hw_param_interval(p, rule->var),
542cb5a6ffcSRussell King 				 ARRAY_SIZE(channel_list), channel_list,
543cb5a6ffcSRussell King 				 chan_mask);
544cb5a6ffcSRussell King }
545cb5a6ffcSRussell King 
54641762b8cSKevin Hilman static int aaci_pcm_open(struct snd_pcm_substream *substream)
547cb5a6ffcSRussell King {
548cb5a6ffcSRussell King 	struct aaci *aaci = substream->private_data;
549cb5a6ffcSRussell King 	int ret;
550cb5a6ffcSRussell King 
551cb5a6ffcSRussell King 	/*
552cb5a6ffcSRussell King 	 * Add rule describing channel dependency.
553cb5a6ffcSRussell King 	 */
554cb5a6ffcSRussell King 	ret = snd_pcm_hw_rule_add(substream->runtime, 0,
555cb5a6ffcSRussell King 				  SNDRV_PCM_HW_PARAM_CHANNELS,
556cb5a6ffcSRussell King 				  aaci_rule_channels, aaci,
557cb5a6ffcSRussell King 				  SNDRV_PCM_HW_PARAM_CHANNELS, -1);
558cb5a6ffcSRussell King 	if (ret)
559cb5a6ffcSRussell King 		return ret;
560cb5a6ffcSRussell King 
56141762b8cSKevin Hilman 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
56241762b8cSKevin Hilman 		ret = __aaci_pcm_open(aaci, substream, &aaci->playback);
56341762b8cSKevin Hilman 	} else {
56441762b8cSKevin Hilman 		ret = __aaci_pcm_open(aaci, substream, &aaci->capture);
56541762b8cSKevin Hilman 	}
56641762b8cSKevin Hilman 	return ret;
567cb5a6ffcSRussell King }
568cb5a6ffcSRussell King 
569ceb9e476STakashi Iwai static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream,
570ceb9e476STakashi Iwai 				       struct snd_pcm_hw_params *params)
571cb5a6ffcSRussell King {
572cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
573cb5a6ffcSRussell King 	unsigned int channels = params_channels(params);
574cb5a6ffcSRussell King 	int ret;
575cb5a6ffcSRussell King 
576cb5a6ffcSRussell King 	WARN_ON(channels >= ARRAY_SIZE(channels_to_txmask) ||
577cb5a6ffcSRussell King 		!channels_to_txmask[channels]);
578cb5a6ffcSRussell King 
579cb5a6ffcSRussell King 	ret = aaci_pcm_hw_params(substream, aacirun, params);
580cb5a6ffcSRussell King 
581cb5a6ffcSRussell King 	/*
582cb5a6ffcSRussell King 	 * Enable FIFO, compact mode, 16 bits per sample.
583cb5a6ffcSRussell King 	 * FIXME: double rate slots?
584cb5a6ffcSRussell King 	 */
585d3aee799SRussell King 	if (ret >= 0)
586cb5a6ffcSRussell King 		aacirun->cr |= channels_to_txmask[channels];
587cb5a6ffcSRussell King 
588cb5a6ffcSRussell King 	return ret;
589cb5a6ffcSRussell King }
590cb5a6ffcSRussell King 
591cb5a6ffcSRussell King static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun)
592cb5a6ffcSRussell King {
593cb5a6ffcSRussell King 	u32 ie;
594cb5a6ffcSRussell King 
595cb5a6ffcSRussell King 	ie = readl(aacirun->base + AACI_IE);
596cb5a6ffcSRussell King 	ie &= ~(IE_URIE|IE_TXIE);
597cb5a6ffcSRussell King 	writel(ie, aacirun->base + AACI_IE);
59841762b8cSKevin Hilman 	aacirun->cr &= ~CR_EN;
599d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_TXB);
600cb5a6ffcSRussell King 	writel(aacirun->cr, aacirun->base + AACI_TXCR);
601cb5a6ffcSRussell King }
602cb5a6ffcSRussell King 
603cb5a6ffcSRussell King static void aaci_pcm_playback_start(struct aaci_runtime *aacirun)
604cb5a6ffcSRussell King {
605cb5a6ffcSRussell King 	u32 ie;
606cb5a6ffcSRussell King 
607d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_TXB);
60841762b8cSKevin Hilman 	aacirun->cr |= CR_EN;
609cb5a6ffcSRussell King 
610cb5a6ffcSRussell King 	ie = readl(aacirun->base + AACI_IE);
611cb5a6ffcSRussell King 	ie |= IE_URIE | IE_TXIE;
612cb5a6ffcSRussell King 	writel(ie, aacirun->base + AACI_IE);
613cb5a6ffcSRussell King 	writel(aacirun->cr, aacirun->base + AACI_TXCR);
614cb5a6ffcSRussell King }
615cb5a6ffcSRussell King 
616ceb9e476STakashi Iwai static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
617cb5a6ffcSRussell King {
618cb5a6ffcSRussell King 	struct aaci_runtime *aacirun = substream->runtime->private_data;
619cb5a6ffcSRussell King 	unsigned long flags;
620cb5a6ffcSRussell King 	int ret = 0;
621cb5a6ffcSRussell King 
622d6a89fefSRussell King 	spin_lock_irqsave(&aacirun->lock, flags);
623d6a89fefSRussell King 
624cb5a6ffcSRussell King 	switch (cmd) {
625cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_START:
626cb5a6ffcSRussell King 		aaci_pcm_playback_start(aacirun);
627cb5a6ffcSRussell King 		break;
628cb5a6ffcSRussell King 
629cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_RESUME:
630cb5a6ffcSRussell King 		aaci_pcm_playback_start(aacirun);
631cb5a6ffcSRussell King 		break;
632cb5a6ffcSRussell King 
633cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_STOP:
634cb5a6ffcSRussell King 		aaci_pcm_playback_stop(aacirun);
635cb5a6ffcSRussell King 		break;
636cb5a6ffcSRussell King 
637cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_SUSPEND:
638cb5a6ffcSRussell King 		aaci_pcm_playback_stop(aacirun);
639cb5a6ffcSRussell King 		break;
640cb5a6ffcSRussell King 
641cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
642cb5a6ffcSRussell King 		break;
643cb5a6ffcSRussell King 
644cb5a6ffcSRussell King 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
645cb5a6ffcSRussell King 		break;
646cb5a6ffcSRussell King 
647cb5a6ffcSRussell King 	default:
648cb5a6ffcSRussell King 		ret = -EINVAL;
649cb5a6ffcSRussell King 	}
650d6a89fefSRussell King 
651d6a89fefSRussell King 	spin_unlock_irqrestore(&aacirun->lock, flags);
652cb5a6ffcSRussell King 
653cb5a6ffcSRussell King 	return ret;
654cb5a6ffcSRussell King }
655cb5a6ffcSRussell King 
656ceb9e476STakashi Iwai static struct snd_pcm_ops aaci_playback_ops = {
65741762b8cSKevin Hilman 	.open		= aaci_pcm_open,
658cb5a6ffcSRussell King 	.close		= aaci_pcm_close,
659cb5a6ffcSRussell King 	.ioctl		= snd_pcm_lib_ioctl,
660cb5a6ffcSRussell King 	.hw_params	= aaci_pcm_playback_hw_params,
661cb5a6ffcSRussell King 	.hw_free	= aaci_pcm_hw_free,
662cb5a6ffcSRussell King 	.prepare	= aaci_pcm_prepare,
663cb5a6ffcSRussell King 	.trigger	= aaci_pcm_playback_trigger,
664cb5a6ffcSRussell King 	.pointer	= aaci_pcm_pointer,
665cb5a6ffcSRussell King };
666cb5a6ffcSRussell King 
6678a371840SRussell King static int aaci_pcm_capture_hw_params(struct snd_pcm_substream *substream,
6688a371840SRussell King 				      struct snd_pcm_hw_params *params)
66941762b8cSKevin Hilman {
67041762b8cSKevin Hilman 	struct aaci_runtime *aacirun = substream->runtime->private_data;
67141762b8cSKevin Hilman 	int ret;
672cb5a6ffcSRussell King 
67341762b8cSKevin Hilman 	ret = aaci_pcm_hw_params(substream, aacirun, params);
674d3aee799SRussell King 	if (ret >= 0)
67541762b8cSKevin Hilman 		/* Line in record: slot 3 and 4 */
67641762b8cSKevin Hilman 		aacirun->cr |= CR_SL3 | CR_SL4;
67741762b8cSKevin Hilman 
67841762b8cSKevin Hilman 	return ret;
67941762b8cSKevin Hilman }
68041762b8cSKevin Hilman 
68141762b8cSKevin Hilman static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun)
68241762b8cSKevin Hilman {
68341762b8cSKevin Hilman 	u32 ie;
68441762b8cSKevin Hilman 
685d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_RXB);
68641762b8cSKevin Hilman 
68741762b8cSKevin Hilman 	ie = readl(aacirun->base + AACI_IE);
68841762b8cSKevin Hilman 	ie &= ~(IE_ORIE | IE_RXIE);
68941762b8cSKevin Hilman 	writel(ie, aacirun->base+AACI_IE);
69041762b8cSKevin Hilman 
69141762b8cSKevin Hilman 	aacirun->cr &= ~CR_EN;
69241762b8cSKevin Hilman 
69341762b8cSKevin Hilman 	writel(aacirun->cr, aacirun->base + AACI_RXCR);
69441762b8cSKevin Hilman }
69541762b8cSKevin Hilman 
69641762b8cSKevin Hilman static void aaci_pcm_capture_start(struct aaci_runtime *aacirun)
69741762b8cSKevin Hilman {
69841762b8cSKevin Hilman 	u32 ie;
69941762b8cSKevin Hilman 
700d6a89fefSRussell King 	aaci_chan_wait_ready(aacirun, SR_RXB);
70141762b8cSKevin Hilman 
70241762b8cSKevin Hilman #ifdef DEBUG
70341762b8cSKevin Hilman 	/* RX Timeout value: bits 28:17 in RXCR */
70441762b8cSKevin Hilman 	aacirun->cr |= 0xf << 17;
70541762b8cSKevin Hilman #endif
70641762b8cSKevin Hilman 
70741762b8cSKevin Hilman 	aacirun->cr |= CR_EN;
70841762b8cSKevin Hilman 	writel(aacirun->cr, aacirun->base + AACI_RXCR);
70941762b8cSKevin Hilman 
71041762b8cSKevin Hilman 	ie = readl(aacirun->base + AACI_IE);
71141762b8cSKevin Hilman 	ie |= IE_ORIE |IE_RXIE; // overrun and rx interrupt -- half full
71241762b8cSKevin Hilman 	writel(ie, aacirun->base + AACI_IE);
71341762b8cSKevin Hilman }
71441762b8cSKevin Hilman 
7158a371840SRussell King static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
7168a371840SRussell King {
71741762b8cSKevin Hilman 	struct aaci_runtime *aacirun = substream->runtime->private_data;
71841762b8cSKevin Hilman 	unsigned long flags;
71941762b8cSKevin Hilman 	int ret = 0;
72041762b8cSKevin Hilman 
721d6a89fefSRussell King 	spin_lock_irqsave(&aacirun->lock, flags);
72241762b8cSKevin Hilman 
72341762b8cSKevin Hilman 	switch (cmd) {
72441762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_START:
72541762b8cSKevin Hilman 		aaci_pcm_capture_start(aacirun);
72641762b8cSKevin Hilman 		break;
72741762b8cSKevin Hilman 
72841762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_RESUME:
72941762b8cSKevin Hilman 		aaci_pcm_capture_start(aacirun);
73041762b8cSKevin Hilman 		break;
73141762b8cSKevin Hilman 
73241762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_STOP:
73341762b8cSKevin Hilman 		aaci_pcm_capture_stop(aacirun);
73441762b8cSKevin Hilman 		break;
73541762b8cSKevin Hilman 
73641762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_SUSPEND:
73741762b8cSKevin Hilman 		aaci_pcm_capture_stop(aacirun);
73841762b8cSKevin Hilman 		break;
73941762b8cSKevin Hilman 
74041762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
74141762b8cSKevin Hilman 		break;
74241762b8cSKevin Hilman 
74341762b8cSKevin Hilman 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
74441762b8cSKevin Hilman 		break;
74541762b8cSKevin Hilman 
74641762b8cSKevin Hilman 	default:
74741762b8cSKevin Hilman 		ret = -EINVAL;
74841762b8cSKevin Hilman 	}
74941762b8cSKevin Hilman 
750d6a89fefSRussell King 	spin_unlock_irqrestore(&aacirun->lock, flags);
75141762b8cSKevin Hilman 
75241762b8cSKevin Hilman 	return ret;
75341762b8cSKevin Hilman }
75441762b8cSKevin Hilman 
7558a371840SRussell King static int aaci_pcm_capture_prepare(struct snd_pcm_substream *substream)
75641762b8cSKevin Hilman {
75741762b8cSKevin Hilman 	struct snd_pcm_runtime *runtime = substream->runtime;
75841762b8cSKevin Hilman 	struct aaci *aaci = substream->private_data;
75941762b8cSKevin Hilman 
76041762b8cSKevin Hilman 	aaci_pcm_prepare(substream);
76141762b8cSKevin Hilman 
76241762b8cSKevin Hilman 	/* allow changing of sample rate */
76341762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_EXTENDED_STATUS, 0x0001); /* VRA */
76441762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
76541762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_PCM_MIC_ADC_RATE, runtime->rate);
76641762b8cSKevin Hilman 
76741762b8cSKevin Hilman 	/* Record select: Mic: 0, Aux: 3, Line: 4 */
76841762b8cSKevin Hilman 	aaci_ac97_write(aaci->ac97, AC97_REC_SEL, 0x0404);
76941762b8cSKevin Hilman 
77041762b8cSKevin Hilman 	return 0;
77141762b8cSKevin Hilman }
77241762b8cSKevin Hilman 
7738a371840SRussell King static struct snd_pcm_ops aaci_capture_ops = {
77441762b8cSKevin Hilman 	.open		= aaci_pcm_open,
77541762b8cSKevin Hilman 	.close		= aaci_pcm_close,
77641762b8cSKevin Hilman 	.ioctl		= snd_pcm_lib_ioctl,
77741762b8cSKevin Hilman 	.hw_params	= aaci_pcm_capture_hw_params,
77841762b8cSKevin Hilman 	.hw_free	= aaci_pcm_hw_free,
77941762b8cSKevin Hilman 	.prepare	= aaci_pcm_capture_prepare,
78041762b8cSKevin Hilman 	.trigger	= aaci_pcm_capture_trigger,
78141762b8cSKevin Hilman 	.pointer	= aaci_pcm_pointer,
78241762b8cSKevin Hilman };
783cb5a6ffcSRussell King 
784cb5a6ffcSRussell King /*
785cb5a6ffcSRussell King  * Power Management.
786cb5a6ffcSRussell King  */
787cb5a6ffcSRussell King #ifdef CONFIG_PM
788ceb9e476STakashi Iwai static int aaci_do_suspend(struct snd_card *card, unsigned int state)
789cb5a6ffcSRussell King {
790cb5a6ffcSRussell King 	struct aaci *aaci = card->private_data;
791792a6c51STakashi Iwai 	snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
792cb5a6ffcSRussell King 	snd_pcm_suspend_all(aaci->pcm);
793cb5a6ffcSRussell King 	return 0;
794cb5a6ffcSRussell King }
795cb5a6ffcSRussell King 
796ceb9e476STakashi Iwai static int aaci_do_resume(struct snd_card *card, unsigned int state)
797cb5a6ffcSRussell King {
798792a6c51STakashi Iwai 	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
799cb5a6ffcSRussell King 	return 0;
800cb5a6ffcSRussell King }
801cb5a6ffcSRussell King 
802e36d394dSRichard Purdie static int aaci_suspend(struct amba_device *dev, pm_message_t state)
803cb5a6ffcSRussell King {
804ceb9e476STakashi Iwai 	struct snd_card *card = amba_get_drvdata(dev);
805cb5a6ffcSRussell King 	return card ? aaci_do_suspend(card) : 0;
806cb5a6ffcSRussell King }
807cb5a6ffcSRussell King 
808cb5a6ffcSRussell King static int aaci_resume(struct amba_device *dev)
809cb5a6ffcSRussell King {
810ceb9e476STakashi Iwai 	struct snd_card *card = amba_get_drvdata(dev);
811cb5a6ffcSRussell King 	return card ? aaci_do_resume(card) : 0;
812cb5a6ffcSRussell King }
813cb5a6ffcSRussell King #else
814cb5a6ffcSRussell King #define aaci_do_suspend		NULL
815cb5a6ffcSRussell King #define aaci_do_resume		NULL
816cb5a6ffcSRussell King #define aaci_suspend		NULL
817cb5a6ffcSRussell King #define aaci_resume		NULL
818cb5a6ffcSRussell King #endif
819cb5a6ffcSRussell King 
820cb5a6ffcSRussell King 
821cb5a6ffcSRussell King static struct ac97_pcm ac97_defs[] __devinitdata = {
822cb5a6ffcSRussell King 	[0] = {	/* Front PCM */
823cb5a6ffcSRussell King 		.exclusive = 1,
824cb5a6ffcSRussell King 		.r = {
825cb5a6ffcSRussell King 			[0] = {
826cb5a6ffcSRussell King 				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
827cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_RIGHT) |
828cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_CENTER) |
829cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_SLEFT) |
830cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_SRIGHT) |
831cb5a6ffcSRussell King 					  (1 << AC97_SLOT_LFE),
832cb5a6ffcSRussell King 			},
833a08d5658SRussell King 			[1] = {
834a08d5658SRussell King 				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
835a08d5658SRussell King 					  (1 << AC97_SLOT_PCM_RIGHT) |
836a08d5658SRussell King 					  (1 << AC97_SLOT_PCM_LEFT_0) |
837a08d5658SRussell King 					  (1 << AC97_SLOT_PCM_RIGHT_0),
838a08d5658SRussell King 			},
839cb5a6ffcSRussell King 		},
840cb5a6ffcSRussell King 	},
841cb5a6ffcSRussell King 	[1] = {	/* PCM in */
842cb5a6ffcSRussell King 		.stream = 1,
843cb5a6ffcSRussell King 		.exclusive = 1,
844cb5a6ffcSRussell King 		.r = {
845cb5a6ffcSRussell King 			[0] = {
846cb5a6ffcSRussell King 				.slots	= (1 << AC97_SLOT_PCM_LEFT) |
847cb5a6ffcSRussell King 					  (1 << AC97_SLOT_PCM_RIGHT),
848cb5a6ffcSRussell King 			},
849cb5a6ffcSRussell King 		},
850cb5a6ffcSRussell King 	},
851cb5a6ffcSRussell King 	[2] = {	/* Mic in */
852cb5a6ffcSRussell King 		.stream = 1,
853cb5a6ffcSRussell King 		.exclusive = 1,
854cb5a6ffcSRussell King 		.r = {
855cb5a6ffcSRussell King 			[0] = {
856cb5a6ffcSRussell King 				.slots	= (1 << AC97_SLOT_MIC),
857cb5a6ffcSRussell King 			},
858cb5a6ffcSRussell King 		},
859cb5a6ffcSRussell King 	}
860cb5a6ffcSRussell King };
861cb5a6ffcSRussell King 
862ceb9e476STakashi Iwai static struct snd_ac97_bus_ops aaci_bus_ops = {
863cb5a6ffcSRussell King 	.write	= aaci_ac97_write,
864cb5a6ffcSRussell King 	.read	= aaci_ac97_read,
865cb5a6ffcSRussell King };
866cb5a6ffcSRussell King 
867cb5a6ffcSRussell King static int __devinit aaci_probe_ac97(struct aaci *aaci)
868cb5a6ffcSRussell King {
869ceb9e476STakashi Iwai 	struct snd_ac97_template ac97_template;
870ceb9e476STakashi Iwai 	struct snd_ac97_bus *ac97_bus;
871ceb9e476STakashi Iwai 	struct snd_ac97 *ac97;
872cb5a6ffcSRussell King 	int ret;
873cb5a6ffcSRussell King 
874cb5a6ffcSRussell King 	/*
875cb5a6ffcSRussell King 	 * Assert AACIRESET for 2us
876cb5a6ffcSRussell King 	 */
877cb5a6ffcSRussell King 	writel(0, aaci->base + AACI_RESET);
878cb5a6ffcSRussell King 	udelay(2);
879cb5a6ffcSRussell King 	writel(RESET_NRST, aaci->base + AACI_RESET);
880cb5a6ffcSRussell King 
881cb5a6ffcSRussell King 	/*
882cb5a6ffcSRussell King 	 * Give the AC'97 codec more than enough time
883cb5a6ffcSRussell King 	 * to wake up. (42us = ~2 frames at 48kHz.)
884cb5a6ffcSRussell King 	 */
885250c7a61SRussell King 	udelay(FRAME_PERIOD_US * 2);
886cb5a6ffcSRussell King 
887cb5a6ffcSRussell King 	ret = snd_ac97_bus(aaci->card, 0, &aaci_bus_ops, aaci, &ac97_bus);
888cb5a6ffcSRussell King 	if (ret)
889cb5a6ffcSRussell King 		goto out;
890cb5a6ffcSRussell King 
891cb5a6ffcSRussell King 	ac97_bus->clock = 48000;
892cb5a6ffcSRussell King 	aaci->ac97_bus = ac97_bus;
893cb5a6ffcSRussell King 
894ceb9e476STakashi Iwai 	memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
895cb5a6ffcSRussell King 	ac97_template.private_data = aaci;
896cb5a6ffcSRussell King 	ac97_template.num = 0;
897cb5a6ffcSRussell King 	ac97_template.scaps = AC97_SCAP_SKIP_MODEM;
898cb5a6ffcSRussell King 
899cb5a6ffcSRussell King 	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
900cb5a6ffcSRussell King 	if (ret)
901cb5a6ffcSRussell King 		goto out;
90241762b8cSKevin Hilman 	aaci->ac97 = ac97;
903cb5a6ffcSRussell King 
904cb5a6ffcSRussell King 	/*
905cb5a6ffcSRussell King 	 * Disable AC97 PC Beep input on audio codecs.
906cb5a6ffcSRussell King 	 */
907cb5a6ffcSRussell King 	if (ac97_is_audio(ac97))
908cb5a6ffcSRussell King 		snd_ac97_write_cache(ac97, AC97_PC_BEEP, 0x801e);
909cb5a6ffcSRussell King 
910cb5a6ffcSRussell King 	ret = snd_ac97_pcm_assign(ac97_bus, ARRAY_SIZE(ac97_defs), ac97_defs);
911cb5a6ffcSRussell King 	if (ret)
912cb5a6ffcSRussell King 		goto out;
913cb5a6ffcSRussell King 
914cb5a6ffcSRussell King 	aaci->playback.pcm = &ac97_bus->pcms[0];
91541762b8cSKevin Hilman 	aaci->capture.pcm  = &ac97_bus->pcms[1];
916cb5a6ffcSRussell King 
917cb5a6ffcSRussell King  out:
918cb5a6ffcSRussell King 	return ret;
919cb5a6ffcSRussell King }
920cb5a6ffcSRussell King 
921ceb9e476STakashi Iwai static void aaci_free_card(struct snd_card *card)
922cb5a6ffcSRussell King {
923cb5a6ffcSRussell King 	struct aaci *aaci = card->private_data;
924cb5a6ffcSRussell King 	if (aaci->base)
925cb5a6ffcSRussell King 		iounmap(aaci->base);
926cb5a6ffcSRussell King }
927cb5a6ffcSRussell King 
928cb5a6ffcSRussell King static struct aaci * __devinit aaci_init_card(struct amba_device *dev)
929cb5a6ffcSRussell King {
930cb5a6ffcSRussell King 	struct aaci *aaci;
931ceb9e476STakashi Iwai 	struct snd_card *card;
932bd7dd77cSTakashi Iwai 	int err;
933cb5a6ffcSRussell King 
934bd7dd77cSTakashi Iwai 	err = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
935bd7dd77cSTakashi Iwai 			      THIS_MODULE, sizeof(struct aaci), &card);
936bd7dd77cSTakashi Iwai 	if (err < 0)
937631e8ad4STakashi Iwai 		return NULL;
938cb5a6ffcSRussell King 
939cb5a6ffcSRussell King 	card->private_free = aaci_free_card;
940cb5a6ffcSRussell King 
941cb5a6ffcSRussell King 	strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver));
942cb5a6ffcSRussell King 	strlcpy(card->shortname, "ARM AC'97 Interface", sizeof(card->shortname));
943cb5a6ffcSRussell King 	snprintf(card->longname, sizeof(card->longname),
944aa0a2ddcSGreg Kroah-Hartman 		 "%s at 0x%016llx, irq %d",
945aa0a2ddcSGreg Kroah-Hartman 		 card->shortname, (unsigned long long)dev->res.start,
946aa0a2ddcSGreg Kroah-Hartman 		 dev->irq[0]);
947cb5a6ffcSRussell King 
948cb5a6ffcSRussell King 	aaci = card->private_data;
94912aa7579SIngo Molnar 	mutex_init(&aaci->ac97_sem);
950cb5a6ffcSRussell King 	aaci->card = card;
951cb5a6ffcSRussell King 	aaci->dev = dev;
952cb5a6ffcSRussell King 
953cb5a6ffcSRussell King 	/* Set MAINCR to allow slot 1 and 2 data IO */
954cb5a6ffcSRussell King 	aaci->maincr = MAINCR_IE | MAINCR_SL1RXEN | MAINCR_SL1TXEN |
955cb5a6ffcSRussell King 		       MAINCR_SL2RXEN | MAINCR_SL2TXEN;
956cb5a6ffcSRussell King 
957cb5a6ffcSRussell King 	return aaci;
958cb5a6ffcSRussell King }
959cb5a6ffcSRussell King 
960cb5a6ffcSRussell King static int __devinit aaci_init_pcm(struct aaci *aaci)
961cb5a6ffcSRussell King {
962ceb9e476STakashi Iwai 	struct snd_pcm *pcm;
963cb5a6ffcSRussell King 	int ret;
964cb5a6ffcSRussell King 
96541762b8cSKevin Hilman 	ret = snd_pcm_new(aaci->card, "AACI AC'97", 0, 1, 1, &pcm);
966cb5a6ffcSRussell King 	if (ret == 0) {
967cb5a6ffcSRussell King 		aaci->pcm = pcm;
968cb5a6ffcSRussell King 		pcm->private_data = aaci;
969cb5a6ffcSRussell King 		pcm->info_flags = 0;
970cb5a6ffcSRussell King 
971cb5a6ffcSRussell King 		strlcpy(pcm->name, DRIVER_NAME, sizeof(pcm->name));
972cb5a6ffcSRussell King 
973cb5a6ffcSRussell King 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops);
97441762b8cSKevin Hilman 		snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops);
975d6797322STakashi Iwai 		snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
976d4946431STakashi Iwai 						      NULL, 0, 64 * 1024);
977cb5a6ffcSRussell King 	}
978cb5a6ffcSRussell King 
979cb5a6ffcSRussell King 	return ret;
980cb5a6ffcSRussell King }
981cb5a6ffcSRussell King 
982cb5a6ffcSRussell King static unsigned int __devinit aaci_size_fifo(struct aaci *aaci)
983cb5a6ffcSRussell King {
98441762b8cSKevin Hilman 	struct aaci_runtime *aacirun = &aaci->playback;
985cb5a6ffcSRussell King 	int i;
986cb5a6ffcSRussell King 
98741762b8cSKevin Hilman 	writel(CR_FEN | CR_SZ16 | CR_EN, aacirun->base + AACI_TXCR);
988cb5a6ffcSRussell King 
98941762b8cSKevin Hilman 	for (i = 0; !(readl(aacirun->base + AACI_SR) & SR_TXFF) && i < 4096; i++)
99041762b8cSKevin Hilman 		writel(0, aacirun->fifo);
991cb5a6ffcSRussell King 
99241762b8cSKevin Hilman 	writel(0, aacirun->base + AACI_TXCR);
993cb5a6ffcSRussell King 
994cb5a6ffcSRussell King 	/*
995cb5a6ffcSRussell King 	 * Re-initialise the AACI after the FIFO depth test, to
996cb5a6ffcSRussell King 	 * ensure that the FIFOs are empty.  Unfortunately, merely
997cb5a6ffcSRussell King 	 * disabling the channel doesn't clear the FIFO.
998cb5a6ffcSRussell King 	 */
999cb5a6ffcSRussell King 	writel(aaci->maincr & ~MAINCR_IE, aaci->base + AACI_MAINCR);
10007c289385SRussell King 	readl(aaci->base + AACI_MAINCR);
10017c289385SRussell King 	udelay(1);
1002cb5a6ffcSRussell King 	writel(aaci->maincr, aaci->base + AACI_MAINCR);
1003cb5a6ffcSRussell King 
1004cb5a6ffcSRussell King 	/*
1005cb5a6ffcSRussell King 	 * If we hit 4096, we failed.  Go back to the specified
1006cb5a6ffcSRussell King 	 * fifo depth.
1007cb5a6ffcSRussell King 	 */
1008cb5a6ffcSRussell King 	if (i == 4096)
1009cb5a6ffcSRussell King 		i = 8;
1010cb5a6ffcSRussell King 
1011cb5a6ffcSRussell King 	return i;
1012cb5a6ffcSRussell King }
1013cb5a6ffcSRussell King 
1014aa25afadSRussell King static int __devinit aaci_probe(struct amba_device *dev,
1015aa25afadSRussell King 	const struct amba_id *id)
1016cb5a6ffcSRussell King {
1017cb5a6ffcSRussell King 	struct aaci *aaci;
1018cb5a6ffcSRussell King 	int ret, i;
1019cb5a6ffcSRussell King 
1020cb5a6ffcSRussell King 	ret = amba_request_regions(dev, NULL);
1021cb5a6ffcSRussell King 	if (ret)
1022cb5a6ffcSRussell King 		return ret;
1023cb5a6ffcSRussell King 
1024cb5a6ffcSRussell King 	aaci = aaci_init_card(dev);
1025631e8ad4STakashi Iwai 	if (!aaci) {
1026631e8ad4STakashi Iwai 		ret = -ENOMEM;
1027cb5a6ffcSRussell King 		goto out;
1028cb5a6ffcSRussell King 	}
1029cb5a6ffcSRussell King 
1030dc890c2dSLinus Walleij 	aaci->base = ioremap(dev->res.start, resource_size(&dev->res));
1031cb5a6ffcSRussell King 	if (!aaci->base) {
1032cb5a6ffcSRussell King 		ret = -ENOMEM;
1033cb5a6ffcSRussell King 		goto out;
1034cb5a6ffcSRussell King 	}
1035cb5a6ffcSRussell King 
1036cb5a6ffcSRussell King 	/*
1037cb5a6ffcSRussell King 	 * Playback uses AACI channel 0
1038cb5a6ffcSRussell King 	 */
1039d6a89fefSRussell King 	spin_lock_init(&aaci->playback.lock);
1040cb5a6ffcSRussell King 	aaci->playback.base = aaci->base + AACI_CSCH1;
1041cb5a6ffcSRussell King 	aaci->playback.fifo = aaci->base + AACI_DR1;
1042cb5a6ffcSRussell King 
104341762b8cSKevin Hilman 	/*
104441762b8cSKevin Hilman 	 * Capture uses AACI channel 0
104541762b8cSKevin Hilman 	 */
1046d6a89fefSRussell King 	spin_lock_init(&aaci->capture.lock);
104741762b8cSKevin Hilman 	aaci->capture.base = aaci->base + AACI_CSCH1;
104841762b8cSKevin Hilman 	aaci->capture.fifo = aaci->base + AACI_DR1;
104941762b8cSKevin Hilman 
1050cb5a6ffcSRussell King 	for (i = 0; i < 4; i++) {
1051e12ba644Sviro@ZenIV.linux.org.uk 		void __iomem *base = aaci->base + i * 0x14;
1052cb5a6ffcSRussell King 
1053cb5a6ffcSRussell King 		writel(0, base + AACI_IE);
1054cb5a6ffcSRussell King 		writel(0, base + AACI_TXCR);
1055cb5a6ffcSRussell King 		writel(0, base + AACI_RXCR);
1056cb5a6ffcSRussell King 	}
1057cb5a6ffcSRussell King 
1058cb5a6ffcSRussell King 	writel(0x1fff, aaci->base + AACI_INTCLR);
1059cb5a6ffcSRussell King 	writel(aaci->maincr, aaci->base + AACI_MAINCR);
1060b68b58fdSPhilby John 	/*
1061b68b58fdSPhilby John 	 * Fix: ac97 read back fail errors by reading
1062b68b58fdSPhilby John 	 * from any arbitrary aaci register.
1063b68b58fdSPhilby John 	 */
1064b68b58fdSPhilby John 	readl(aaci->base + AACI_CSCH1);
1065cb5a6ffcSRussell King 	ret = aaci_probe_ac97(aaci);
1066cb5a6ffcSRussell King 	if (ret)
1067cb5a6ffcSRussell King 		goto out;
1068cb5a6ffcSRussell King 
1069f27f218cSCatalin Marinas 	/*
1070f27f218cSCatalin Marinas 	 * Size the FIFOs (must be multiple of 16).
1071f27f218cSCatalin Marinas 	 */
1072f27f218cSCatalin Marinas 	aaci->fifosize = aaci_size_fifo(aaci);
1073f27f218cSCatalin Marinas 	if (aaci->fifosize & 15) {
1074f27f218cSCatalin Marinas 		printk(KERN_WARNING "AACI: fifosize = %d not supported\n",
1075f27f218cSCatalin Marinas 		       aaci->fifosize);
1076f27f218cSCatalin Marinas 		ret = -ENODEV;
1077f27f218cSCatalin Marinas 		goto out;
1078f27f218cSCatalin Marinas 	}
1079f27f218cSCatalin Marinas 
1080cb5a6ffcSRussell King 	ret = aaci_init_pcm(aaci);
1081cb5a6ffcSRussell King 	if (ret)
1082cb5a6ffcSRussell King 		goto out;
1083cb5a6ffcSRussell King 
1084a76af199STakashi Iwai 	snd_card_set_dev(aaci->card, &dev->dev);
1085a76af199STakashi Iwai 
1086cb5a6ffcSRussell King 	ret = snd_card_register(aaci->card);
1087cb5a6ffcSRussell King 	if (ret == 0) {
1088cb5a6ffcSRussell King 		dev_info(&dev->dev, "%s, fifo %d\n", aaci->card->longname,
1089cb5a6ffcSRussell King 			 aaci->fifosize);
1090cb5a6ffcSRussell King 		amba_set_drvdata(dev, aaci->card);
1091cb5a6ffcSRussell King 		return ret;
1092cb5a6ffcSRussell King 	}
1093cb5a6ffcSRussell King 
1094cb5a6ffcSRussell King  out:
1095cb5a6ffcSRussell King 	if (aaci)
1096cb5a6ffcSRussell King 		snd_card_free(aaci->card);
1097cb5a6ffcSRussell King 	amba_release_regions(dev);
1098cb5a6ffcSRussell King 	return ret;
1099cb5a6ffcSRussell King }
1100cb5a6ffcSRussell King 
1101cb5a6ffcSRussell King static int __devexit aaci_remove(struct amba_device *dev)
1102cb5a6ffcSRussell King {
1103ceb9e476STakashi Iwai 	struct snd_card *card = amba_get_drvdata(dev);
1104cb5a6ffcSRussell King 
1105cb5a6ffcSRussell King 	amba_set_drvdata(dev, NULL);
1106cb5a6ffcSRussell King 
1107cb5a6ffcSRussell King 	if (card) {
1108cb5a6ffcSRussell King 		struct aaci *aaci = card->private_data;
1109cb5a6ffcSRussell King 		writel(0, aaci->base + AACI_MAINCR);
1110cb5a6ffcSRussell King 
1111cb5a6ffcSRussell King 		snd_card_free(card);
1112cb5a6ffcSRussell King 		amba_release_regions(dev);
1113cb5a6ffcSRussell King 	}
1114cb5a6ffcSRussell King 
1115cb5a6ffcSRussell King 	return 0;
1116cb5a6ffcSRussell King }
1117cb5a6ffcSRussell King 
1118cb5a6ffcSRussell King static struct amba_id aaci_ids[] = {
1119cb5a6ffcSRussell King 	{
1120cb5a6ffcSRussell King 		.id	= 0x00041041,
1121cb5a6ffcSRussell King 		.mask	= 0x000fffff,
1122cb5a6ffcSRussell King 	},
1123cb5a6ffcSRussell King 	{ 0, 0 },
1124cb5a6ffcSRussell King };
1125cb5a6ffcSRussell King 
1126cb5a6ffcSRussell King static struct amba_driver aaci_driver = {
1127cb5a6ffcSRussell King 	.drv		= {
1128cb5a6ffcSRussell King 		.name	= DRIVER_NAME,
1129cb5a6ffcSRussell King 	},
1130cb5a6ffcSRussell King 	.probe		= aaci_probe,
1131cb5a6ffcSRussell King 	.remove		= __devexit_p(aaci_remove),
1132cb5a6ffcSRussell King 	.suspend	= aaci_suspend,
1133cb5a6ffcSRussell King 	.resume		= aaci_resume,
1134cb5a6ffcSRussell King 	.id_table	= aaci_ids,
1135cb5a6ffcSRussell King };
1136cb5a6ffcSRussell King 
1137cb5a6ffcSRussell King static int __init aaci_init(void)
1138cb5a6ffcSRussell King {
1139cb5a6ffcSRussell King 	return amba_driver_register(&aaci_driver);
1140cb5a6ffcSRussell King }
1141cb5a6ffcSRussell King 
1142cb5a6ffcSRussell King static void __exit aaci_exit(void)
1143cb5a6ffcSRussell King {
1144cb5a6ffcSRussell King 	amba_driver_unregister(&aaci_driver);
1145cb5a6ffcSRussell King }
1146cb5a6ffcSRussell King 
1147cb5a6ffcSRussell King module_init(aaci_init);
1148cb5a6ffcSRussell King module_exit(aaci_exit);
1149cb5a6ffcSRussell King 
1150cb5a6ffcSRussell King MODULE_LICENSE("GPL");
1151cb5a6ffcSRussell King MODULE_DESCRIPTION("ARM PrimeCell PL041 Advanced Audio CODEC Interface driver");
1152