Skip to content

Commit

Permalink
ALSA: snd-atmel-ac97c: enable interrupts to catch events for error re…
Browse files Browse the repository at this point in the history
…porting

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>
  • Loading branch information
Hans-Christian Egtvedt authored and tiwai committed Apr 6, 2009
1 parent c42eec0 commit df16358
Showing 1 changed file with 76 additions and 1 deletion.
77 changes: 76 additions & 1 deletion sound/atmel/ac97c.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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");
Expand All @@ -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");
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);
Expand All @@ -847,6 +919,8 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)

iounmap(chip->regs);
err_ioremap:
free_irq(irq, chip);
err_request_irq:
snd_card_free(card);
err_snd_card_new:
clk_disable(pclk);
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit df16358

Please sign in to comment.