diff options
author | Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com> | 2009-04-02 10:21:14 +0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-04-06 05:55:33 +0400 |
commit | df163587eab15a24cc34cf8434a5657416f8a203 (patch) | |
tree | 6c9eeebc72fd8bca19cc6c5f8500e3c505e7c871 /sound | |
parent | c42eec0f193ed408118e20d85ea8c2e69c529993 (diff) | |
download | linux-df163587eab15a24cc34cf8434a5657416f8a203.tar.xz |
ALSA: snd-atmel-ac97c: enable interrupts to catch events for error reporting
This patch will enable interrupts from AC97C and report about error
conditions that occurs.
On channel A both overrun and underrun will be enabled depending if
playback and/or capture are enabled. On the control channel the overrun
interrupt is enabled.
Signed-off-by: Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/atmel/ac97c.c | 77 |
1 files changed, 76 insertions, 1 deletions
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index c9bc3458fa2d..e8484cb9ac62 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -66,6 +66,7 @@ struct atmel_ac97c { /* Serialize access to opened variable */ spinlock_t lock; void __iomem *regs; + int irq; int opened; int reset_pin; }; @@ -335,8 +336,16 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) 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); @@ -402,8 +411,16 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) 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); @@ -554,6 +571,43 @@ static struct snd_pcm_ops atmel_ac97_capture_ops = { .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; @@ -701,6 +755,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) .read = atmel_ac97c_read, }; int retval; + int irq; regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { @@ -714,6 +769,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) 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"); @@ -730,6 +791,13 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) 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"); @@ -758,6 +826,10 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) snd_card_set_dev(card, &pdev->dev); + /* 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"); @@ -820,7 +892,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) 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); @@ -847,6 +919,8 @@ err_ac97_bus: iounmap(chip->regs); err_ioremap: + free_irq(irq, chip); +err_request_irq: snd_card_free(card); err_snd_card_new: clk_disable(pclk); @@ -898,6 +972,7 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) 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); |