Merge branch 'topic/atmel' into for-linus
diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c
index 28b3c7f..f2f41c8 100644
--- a/sound/atmel/abdac.c
+++ b/sound/atmel/abdac.c
@@ -165,7 +165,7 @@
 	.buffer_bytes_max	= 64 * 4096,
 	.period_bytes_min	= 4096,
 	.period_bytes_max	= 4096,
-	.periods_min		= 4,
+	.periods_min		= 6,
 	.periods_max		= 64,
 };
 
@@ -502,7 +502,7 @@
 	platform_set_drvdata(pdev, card);
 
 	dev_info(&pdev->dev, "Atmel ABDAC at 0x%p using %s\n",
-			dac->regs, dac->dma.chan->dev->device.bus_id);
+			dac->regs, dev_name(&dac->dma.chan->dev->device));
 
 	return retval;
 
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index dd72e00..0c0f877 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -1,5 +1,5 @@
 /*
- * Driver for the Atmel AC97C controller
+ * Driver for Atmel AC97C
  *
  * Copyright (C) 2005-2009 Atmel Corporation
  *
@@ -10,6 +10,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/bitmap.h>
+#include <linux/device.h>
 #include <linux/dmaengine.h>
 #include <linux/dma-mapping.h>
 #include <linux/init.h>
@@ -65,6 +66,7 @@
 	/* Serialize access to opened variable */
 	spinlock_t			lock;
 	void __iomem			*regs;
+	int				irq;
 	int				opened;
 	int				reset_pin;
 };
@@ -150,10 +152,10 @@
 	.rate_max		= 48000,
 	.channels_min		= 1,
 	.channels_max		= 2,
-	.buffer_bytes_max	= 64 * 4096,
+	.buffer_bytes_max	= 2 * 2 * 64 * 2048,
 	.period_bytes_min	= 4096,
 	.period_bytes_max	= 4096,
-	.periods_min		= 4,
+	.periods_min		= 6,
 	.periods_max		= 64,
 };
 
@@ -297,9 +299,11 @@
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	unsigned long word = 0;
+	unsigned long word = ac97c_readl(chip, OCA);
 	int retval;
 
+	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
+
 	/* assign channels to AC97C channel A */
 	switch (runtime->channels) {
 	case 1:
@@ -312,7 +316,6 @@
 	default:
 		/* TODO: support more than two channels */
 		return -EINVAL;
-		break;
 	}
 	ac97c_writel(chip, OCA, word);
 
@@ -324,13 +327,25 @@
 		word |= AC97C_CMR_CEM_LITTLE;
 		break;
 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
-	default:
 		word &= ~(AC97C_CMR_CEM_LITTLE);
 		break;
+	default:
+		word = ac97c_readl(chip, OCA);
+		word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
+		ac97c_writel(chip, OCA, word);
+		return -EINVAL;
 	}
 
+	/* Enable underrun interrupt on channel A */
+	word |= AC97C_CSR_UNRUN;
+
 	ac97c_writel(chip, CAMR, word);
 
+	/* Enable channel A event interrupt */
+	word = ac97c_readl(chip, IMR);
+	word |= AC97C_SR_CAEVT;
+	ac97c_writel(chip, IER, word);
+
 	/* set variable rate if needed */
 	if (runtime->rate != 48000) {
 		word = ac97c_readl(chip, MR);
@@ -359,9 +374,11 @@
 {
 	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
 	struct snd_pcm_runtime *runtime = substream->runtime;
-	unsigned long word = 0;
+	unsigned long word = ac97c_readl(chip, ICA);
 	int retval;
 
+	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
+
 	/* assign channels to AC97C channel A */
 	switch (runtime->channels) {
 	case 1:
@@ -374,7 +391,6 @@
 	default:
 		/* TODO: support more than two channels */
 		return -EINVAL;
-		break;
 	}
 	ac97c_writel(chip, ICA, word);
 
@@ -386,13 +402,25 @@
 		word |= AC97C_CMR_CEM_LITTLE;
 		break;
 	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
-	default:
 		word &= ~(AC97C_CMR_CEM_LITTLE);
 		break;
+	default:
+		word = ac97c_readl(chip, ICA);
+		word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
+		ac97c_writel(chip, ICA, word);
+		return -EINVAL;
 	}
 
+	/* Enable overrun interrupt on channel A */
+	word |= AC97C_CSR_OVRUN;
+
 	ac97c_writel(chip, CAMR, word);
 
+	/* Enable channel A event interrupt */
+	word = ac97c_readl(chip, IMR);
+	word |= AC97C_SR_CAEVT;
+	ac97c_writel(chip, IER, word);
+
 	/* set variable rate if needed */
 	if (runtime->rate != 48000) {
 		word = ac97c_readl(chip, MR);
@@ -543,6 +571,43 @@
 	.pointer	= atmel_ac97c_capture_pointer,
 };
 
+static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
+{
+	struct atmel_ac97c	*chip  = (struct atmel_ac97c *)dev;
+	irqreturn_t		retval = IRQ_NONE;
+	u32			sr     = ac97c_readl(chip, SR);
+	u32			casr   = ac97c_readl(chip, CASR);
+	u32			cosr   = ac97c_readl(chip, COSR);
+
+	if (sr & AC97C_SR_CAEVT) {
+		dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n",
+				casr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
+				casr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
+				casr & AC97C_CSR_UNRUN   ? " UNRUN"   : "",
+				casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
+				casr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
+				!casr                    ? " NONE"    : "");
+		retval = IRQ_HANDLED;
+	}
+
+	if (sr & AC97C_SR_COEVT) {
+		dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n",
+				cosr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
+				cosr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
+				cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
+				cosr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
+				!cosr                    ? " NONE"    : "");
+		retval = IRQ_HANDLED;
+	}
+
+	if (retval == IRQ_NONE) {
+		dev_err(&chip->pdev->dev, "spurious interrupt sr 0x%08x "
+				"casr 0x%08x cosr 0x%08x\n", sr, casr, cosr);
+	}
+
+	return retval;
+}
+
 static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
 {
 	struct snd_pcm		*pcm;
@@ -665,17 +730,17 @@
 
 static void atmel_ac97c_reset(struct atmel_ac97c *chip)
 {
-	ac97c_writel(chip, MR, AC97C_MR_WRST);
+	ac97c_writel(chip, MR,   0);
+	ac97c_writel(chip, MR,   AC97C_MR_ENA);
+	ac97c_writel(chip, CAMR, 0);
+	ac97c_writel(chip, COMR, 0);
 
 	if (gpio_is_valid(chip->reset_pin)) {
 		gpio_set_value(chip->reset_pin, 0);
 		/* AC97 v2.2 specifications says minimum 1 us. */
-		udelay(10);
+		udelay(2);
 		gpio_set_value(chip->reset_pin, 1);
 	}
-
-	udelay(1);
-	ac97c_writel(chip, MR, AC97C_MR_ENA);
 }
 
 static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
@@ -690,6 +755,7 @@
 		.read	= atmel_ac97c_read,
 	};
 	int				retval;
+	int				irq;
 
 	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!regs) {
@@ -703,6 +769,12 @@
 		return -ENXIO;
 	}
 
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_dbg(&pdev->dev, "could not get irq\n");
+		return -ENXIO;
+	}
+
 	pclk = clk_get(&pdev->dev, "pclk");
 	if (IS_ERR(pclk)) {
 		dev_dbg(&pdev->dev, "no peripheral clock\n");
@@ -719,6 +791,13 @@
 
 	chip = get_chip(card);
 
+	retval = request_irq(irq, atmel_ac97c_interrupt, 0, "AC97C", chip);
+	if (retval) {
+		dev_dbg(&pdev->dev, "unable to request irq %d\n", irq);
+		goto err_request_irq;
+	}
+	chip->irq = irq;
+
 	spin_lock_init(&chip->lock);
 
 	strcpy(card->driver, "Atmel AC97C");
@@ -747,14 +826,18 @@
 
 	snd_card_set_dev(card, &pdev->dev);
 
+	atmel_ac97c_reset(chip);
+
+	/* Enable overrun interrupt from codec channel */
+	ac97c_writel(chip, COMR, AC97C_CSR_OVRUN);
+	ac97c_writel(chip, IER, ac97c_readl(chip, IMR) | AC97C_SR_COEVT);
+
 	retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
 	if (retval) {
 		dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
 		goto err_ac97_bus;
 	}
 
-	atmel_ac97c_reset(chip);
-
 	retval = atmel_ac97c_mixer_new(chip);
 	if (retval) {
 		dev_dbg(&pdev->dev, "could not register ac97 mixer\n");
@@ -773,7 +856,7 @@
 		chip->dma.rx_chan = dma_request_channel(mask, filter, dws);
 
 		dev_info(&chip->pdev->dev, "using %s for DMA RX\n",
-					chip->dma.rx_chan->dev->device.bus_id);
+				dev_name(&chip->dma.rx_chan->dev->device));
 		set_bit(DMA_RX_CHAN_PRESENT, &chip->flags);
 	}
 
@@ -789,7 +872,7 @@
 		chip->dma.tx_chan = dma_request_channel(mask, filter, dws);
 
 		dev_info(&chip->pdev->dev, "using %s for DMA TX\n",
-					chip->dma.tx_chan->dev->device.bus_id);
+				dev_name(&chip->dma.tx_chan->dev->device));
 		set_bit(DMA_TX_CHAN_PRESENT, &chip->flags);
 	}
 
@@ -809,7 +892,7 @@
 	retval = snd_card_register(card);
 	if (retval) {
 		dev_dbg(&pdev->dev, "could not register sound card\n");
-		goto err_ac97_bus;
+		goto err_dma;
 	}
 
 	platform_set_drvdata(pdev, card);
@@ -836,6 +919,8 @@
 
 	iounmap(chip->regs);
 err_ioremap:
+	free_irq(irq, chip);
+err_request_irq:
 	snd_card_free(card);
 err_snd_card_new:
 	clk_disable(pclk);
@@ -884,9 +969,14 @@
 	if (gpio_is_valid(chip->reset_pin))
 		gpio_free(chip->reset_pin);
 
+	ac97c_writel(chip, CAMR, 0);
+	ac97c_writel(chip, COMR, 0);
+	ac97c_writel(chip, MR,   0);
+
 	clk_disable(chip->pclk);
 	clk_put(chip->pclk);
 	iounmap(chip->regs);
+	free_irq(chip->irq, chip);
 
 	if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
 		dma_release_channel(chip->dma.rx_chan);
diff --git a/sound/atmel/ac97c.h b/sound/atmel/ac97c.h
index c17bd58..ecbba50 100644
--- a/sound/atmel/ac97c.h
+++ b/sound/atmel/ac97c.h
@@ -1,5 +1,5 @@
 /*
- * Register definitions for the Atmel AC97C controller
+ * Register definitions for Atmel AC97C
  *
  * Copyright (C) 2005-2009 Atmel Corporation
  *
@@ -17,10 +17,6 @@
 #define AC97C_CATHR		0x24
 #define AC97C_CASR		0x28
 #define AC97C_CAMR		0x2c
-#define AC97C_CBRHR		0x30
-#define AC97C_CBTHR		0x34
-#define AC97C_CBSR		0x38
-#define AC97C_CBMR		0x3c
 #define AC97C_CORHR		0x40
 #define AC97C_COTHR		0x44
 #define AC97C_COSR		0x48
@@ -46,8 +42,10 @@
 #define AC97C_MR_VRA		(1 << 2)
 
 #define AC97C_CSR_TXRDY		(1 << 0)
+#define AC97C_CSR_TXEMPTY	(1 << 1)
 #define AC97C_CSR_UNRUN		(1 << 2)
 #define AC97C_CSR_RXRDY		(1 << 4)
+#define AC97C_CSR_OVRUN		(1 << 5)
 #define AC97C_CSR_ENDTX		(1 << 10)
 #define AC97C_CSR_ENDRX		(1 << 14)
 
@@ -61,11 +59,15 @@
 #define AC97C_CMR_DMAEN		(1 << 22)
 
 #define AC97C_SR_CAEVT		(1 << 3)
+#define AC97C_SR_COEVT		(1 << 2)
+#define AC97C_SR_WKUP		(1 << 1)
+#define AC97C_SR_SOF		(1 << 0)
 
+#define AC97C_CH_MASK(slot)						\
+	(0x7 << (3 * (AC97_SLOT_##slot - 3)))
 #define AC97C_CH_ASSIGN(slot, channel)					\
 	(AC97C_CHANNEL_##channel << (3 * (AC97_SLOT_##slot - 3)))
 #define AC97C_CHANNEL_NONE	0x0
 #define AC97C_CHANNEL_A		0x1
-#define AC97C_CHANNEL_B		0x2
 
 #endif /* __SOUND_ATMEL_AC97C_H */