diff options
author | Hans-Christian Egtvedt <hans-christian.egtvedt@atmel.com> | 2009-04-02 02:21:14 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-04-05 21:55:33 -0400 |
commit | df163587eab15a24cc34cf8434a5657416f8a203 (patch) | |
tree | 6c9eeebc72fd8bca19cc6c5f8500e3c505e7c871 /sound/atmel/ac97c.c | |
parent | c42eec0f193ed408118e20d85ea8c2e69c529993 (diff) |
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/atmel/ac97c.c')
-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 { | |||
66 | /* Serialize access to opened variable */ | 66 | /* Serialize access to opened variable */ |
67 | spinlock_t lock; | 67 | spinlock_t lock; |
68 | void __iomem *regs; | 68 | void __iomem *regs; |
69 | int irq; | ||
69 | int opened; | 70 | int opened; |
70 | int reset_pin; | 71 | int reset_pin; |
71 | }; | 72 | }; |
@@ -335,8 +336,16 @@ static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream) | |||
335 | return -EINVAL; | 336 | return -EINVAL; |
336 | } | 337 | } |
337 | 338 | ||
339 | /* Enable underrun interrupt on channel A */ | ||
340 | word |= AC97C_CSR_UNRUN; | ||
341 | |||
338 | ac97c_writel(chip, CAMR, word); | 342 | ac97c_writel(chip, CAMR, word); |
339 | 343 | ||
344 | /* Enable channel A event interrupt */ | ||
345 | word = ac97c_readl(chip, IMR); | ||
346 | word |= AC97C_SR_CAEVT; | ||
347 | ac97c_writel(chip, IER, word); | ||
348 | |||
340 | /* set variable rate if needed */ | 349 | /* set variable rate if needed */ |
341 | if (runtime->rate != 48000) { | 350 | if (runtime->rate != 48000) { |
342 | word = ac97c_readl(chip, MR); | 351 | word = ac97c_readl(chip, MR); |
@@ -402,8 +411,16 @@ static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream) | |||
402 | return -EINVAL; | 411 | return -EINVAL; |
403 | } | 412 | } |
404 | 413 | ||
414 | /* Enable overrun interrupt on channel A */ | ||
415 | word |= AC97C_CSR_OVRUN; | ||
416 | |||
405 | ac97c_writel(chip, CAMR, word); | 417 | ac97c_writel(chip, CAMR, word); |
406 | 418 | ||
419 | /* Enable channel A event interrupt */ | ||
420 | word = ac97c_readl(chip, IMR); | ||
421 | word |= AC97C_SR_CAEVT; | ||
422 | ac97c_writel(chip, IER, word); | ||
423 | |||
407 | /* set variable rate if needed */ | 424 | /* set variable rate if needed */ |
408 | if (runtime->rate != 48000) { | 425 | if (runtime->rate != 48000) { |
409 | word = ac97c_readl(chip, MR); | 426 | word = ac97c_readl(chip, MR); |
@@ -554,6 +571,43 @@ static struct snd_pcm_ops atmel_ac97_capture_ops = { | |||
554 | .pointer = atmel_ac97c_capture_pointer, | 571 | .pointer = atmel_ac97c_capture_pointer, |
555 | }; | 572 | }; |
556 | 573 | ||
574 | static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) | ||
575 | { | ||
576 | struct atmel_ac97c *chip = (struct atmel_ac97c *)dev; | ||
577 | irqreturn_t retval = IRQ_NONE; | ||
578 | u32 sr = ac97c_readl(chip, SR); | ||
579 | u32 casr = ac97c_readl(chip, CASR); | ||
580 | u32 cosr = ac97c_readl(chip, COSR); | ||
581 | |||
582 | if (sr & AC97C_SR_CAEVT) { | ||
583 | dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", | ||
584 | casr & AC97C_CSR_OVRUN ? " OVRUN" : "", | ||
585 | casr & AC97C_CSR_RXRDY ? " RXRDY" : "", | ||
586 | casr & AC97C_CSR_UNRUN ? " UNRUN" : "", | ||
587 | casr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", | ||
588 | casr & AC97C_CSR_TXRDY ? " TXRDY" : "", | ||
589 | !casr ? " NONE" : ""); | ||
590 | retval = IRQ_HANDLED; | ||
591 | } | ||
592 | |||
593 | if (sr & AC97C_SR_COEVT) { | ||
594 | dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s\n", | ||
595 | cosr & AC97C_CSR_OVRUN ? " OVRUN" : "", | ||
596 | cosr & AC97C_CSR_RXRDY ? " RXRDY" : "", | ||
597 | cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "", | ||
598 | cosr & AC97C_CSR_TXRDY ? " TXRDY" : "", | ||
599 | !cosr ? " NONE" : ""); | ||
600 | retval = IRQ_HANDLED; | ||
601 | } | ||
602 | |||
603 | if (retval == IRQ_NONE) { | ||
604 | dev_err(&chip->pdev->dev, "spurious interrupt sr 0x%08x " | ||
605 | "casr 0x%08x cosr 0x%08x\n", sr, casr, cosr); | ||
606 | } | ||
607 | |||
608 | return retval; | ||
609 | } | ||
610 | |||
557 | static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) | 611 | static int __devinit atmel_ac97c_pcm_new(struct atmel_ac97c *chip) |
558 | { | 612 | { |
559 | struct snd_pcm *pcm; | 613 | struct snd_pcm *pcm; |
@@ -701,6 +755,7 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) | |||
701 | .read = atmel_ac97c_read, | 755 | .read = atmel_ac97c_read, |
702 | }; | 756 | }; |
703 | int retval; | 757 | int retval; |
758 | int irq; | ||
704 | 759 | ||
705 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 760 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
706 | if (!regs) { | 761 | if (!regs) { |
@@ -714,6 +769,12 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) | |||
714 | return -ENXIO; | 769 | return -ENXIO; |
715 | } | 770 | } |
716 | 771 | ||
772 | irq = platform_get_irq(pdev, 0); | ||
773 | if (irq < 0) { | ||
774 | dev_dbg(&pdev->dev, "could not get irq\n"); | ||
775 | return -ENXIO; | ||
776 | } | ||
777 | |||
717 | pclk = clk_get(&pdev->dev, "pclk"); | 778 | pclk = clk_get(&pdev->dev, "pclk"); |
718 | if (IS_ERR(pclk)) { | 779 | if (IS_ERR(pclk)) { |
719 | dev_dbg(&pdev->dev, "no peripheral clock\n"); | 780 | dev_dbg(&pdev->dev, "no peripheral clock\n"); |
@@ -730,6 +791,13 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) | |||
730 | 791 | ||
731 | chip = get_chip(card); | 792 | chip = get_chip(card); |
732 | 793 | ||
794 | retval = request_irq(irq, atmel_ac97c_interrupt, 0, "AC97C", chip); | ||
795 | if (retval) { | ||
796 | dev_dbg(&pdev->dev, "unable to request irq %d\n", irq); | ||
797 | goto err_request_irq; | ||
798 | } | ||
799 | chip->irq = irq; | ||
800 | |||
733 | spin_lock_init(&chip->lock); | 801 | spin_lock_init(&chip->lock); |
734 | 802 | ||
735 | strcpy(card->driver, "Atmel AC97C"); | 803 | strcpy(card->driver, "Atmel AC97C"); |
@@ -758,6 +826,10 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) | |||
758 | 826 | ||
759 | snd_card_set_dev(card, &pdev->dev); | 827 | snd_card_set_dev(card, &pdev->dev); |
760 | 828 | ||
829 | /* Enable overrun interrupt from codec channel */ | ||
830 | ac97c_writel(chip, COMR, AC97C_CSR_OVRUN); | ||
831 | ac97c_writel(chip, IER, ac97c_readl(chip, IMR) | AC97C_SR_COEVT); | ||
832 | |||
761 | retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus); | 833 | retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus); |
762 | if (retval) { | 834 | if (retval) { |
763 | dev_dbg(&pdev->dev, "could not register on ac97 bus\n"); | 835 | 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) | |||
820 | retval = snd_card_register(card); | 892 | retval = snd_card_register(card); |
821 | if (retval) { | 893 | if (retval) { |
822 | dev_dbg(&pdev->dev, "could not register sound card\n"); | 894 | dev_dbg(&pdev->dev, "could not register sound card\n"); |
823 | goto err_ac97_bus; | 895 | goto err_dma; |
824 | } | 896 | } |
825 | 897 | ||
826 | platform_set_drvdata(pdev, card); | 898 | platform_set_drvdata(pdev, card); |
@@ -847,6 +919,8 @@ err_ac97_bus: | |||
847 | 919 | ||
848 | iounmap(chip->regs); | 920 | iounmap(chip->regs); |
849 | err_ioremap: | 921 | err_ioremap: |
922 | free_irq(irq, chip); | ||
923 | err_request_irq: | ||
850 | snd_card_free(card); | 924 | snd_card_free(card); |
851 | err_snd_card_new: | 925 | err_snd_card_new: |
852 | clk_disable(pclk); | 926 | clk_disable(pclk); |
@@ -898,6 +972,7 @@ static int __devexit atmel_ac97c_remove(struct platform_device *pdev) | |||
898 | clk_disable(chip->pclk); | 972 | clk_disable(chip->pclk); |
899 | clk_put(chip->pclk); | 973 | clk_put(chip->pclk); |
900 | iounmap(chip->regs); | 974 | iounmap(chip->regs); |
975 | free_irq(chip->irq, chip); | ||
901 | 976 | ||
902 | if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) | 977 | if (test_bit(DMA_RX_CHAN_PRESENT, &chip->flags)) |
903 | dma_release_channel(chip->dma.rx_chan); | 978 | dma_release_channel(chip->dma.rx_chan); |