Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df163587 authored by Hans-Christian Egtvedt's avatar Hans-Christian Egtvedt Committed by Takashi Iwai
Browse files

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: default avatarHans-Christian Egtvedt <hans-christian.egtvedt@atmel.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent c42eec0f
Loading
Loading
Loading
Loading
+76 −1
Original line number Original line Diff line number Diff line
@@ -66,6 +66,7 @@ struct atmel_ac97c {
	/* Serialize access to opened variable */
	/* Serialize access to opened variable */
	spinlock_t			lock;
	spinlock_t			lock;
	void __iomem			*regs;
	void __iomem			*regs;
	int				irq;
	int				opened;
	int				opened;
	int				reset_pin;
	int				reset_pin;
};
};
@@ -335,8 +336,16 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
		return -EINVAL;
		return -EINVAL;
	}
	}


	/* Enable underrun interrupt on channel A */
	word |= AC97C_CSR_UNRUN;

	ac97c_writel(chip, CAMR, word);
	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 */
	/* set variable rate if needed */
	if (runtime->rate != 48000) {
	if (runtime->rate != 48000) {
		word = ac97c_readl(chip, MR);
		word = ac97c_readl(chip, MR);
@@ -402,8 +411,16 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
		return -EINVAL;
		return -EINVAL;
	}
	}


	/* Enable overrun interrupt on channel A */
	word |= AC97C_CSR_OVRUN;

	ac97c_writel(chip, CAMR, word);
	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 */
	/* set variable rate if needed */
	if (runtime->rate != 48000) {
	if (runtime->rate != 48000) {
		word = ac97c_readl(chip, MR);
		word = ac97c_readl(chip, MR);
@@ -554,6 +571,43 @@ static struct snd_pcm_ops atmel_ac97_capture_ops = {
	.pointer	= atmel_ac97c_capture_pointer,
	.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)
static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
{
{
	struct snd_pcm		*pcm;
	struct snd_pcm		*pcm;
@@ -701,6 +755,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
		.read	= atmel_ac97c_read,
		.read	= atmel_ac97c_read,
	};
	};
	int				retval;
	int				retval;
	int				irq;


	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!regs) {
	if (!regs) {
@@ -714,6 +769,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)
		return -ENXIO;
		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");
	pclk = clk_get(&pdev->dev, "pclk");
	if (IS_ERR(pclk)) {
	if (IS_ERR(pclk)) {
		dev_dbg(&pdev->dev, "no peripheral clock\n");
		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);
	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);
	spin_lock_init(&chip->lock);


	strcpy(card->driver, "Atmel AC97C");
	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);
	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);
	retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
	if (retval) {
	if (retval) {
		dev_dbg(&pdev->dev, "could not register on ac97 bus\n");
		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);
	retval = snd_card_register(card);
	if (retval) {
	if (retval) {
		dev_dbg(&pdev->dev, "could not register sound card\n");
		dev_dbg(&pdev->dev, "could not register sound card\n");
		goto err_ac97_bus;
		goto err_dma;
	}
	}


	platform_set_drvdata(pdev, card);
	platform_set_drvdata(pdev, card);
@@ -847,6 +919,8 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev)


	iounmap(chip->regs);
	iounmap(chip->regs);
err_ioremap:
err_ioremap:
	free_irq(irq, chip);
err_request_irq:
	snd_card_free(card);
	snd_card_free(card);
err_snd_card_new:
err_snd_card_new:
	clk_disable(pclk);
	clk_disable(pclk);
@@ -898,6 +972,7 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev)
	clk_disable(chip->pclk);
	clk_disable(chip->pclk);
	clk_put(chip->pclk);
	clk_put(chip->pclk);
	iounmap(chip->regs);
	iounmap(chip->regs);
	free_irq(chip->irq, chip);


	if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
	if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags))
		dma_release_channel(chip->dma.rx_chan);
		dma_release_channel(chip->dma.rx_chan);