diff options
-rw-r--r-- | sound/mips/au1x00.c | 239 |
1 files changed, 141 insertions, 98 deletions
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c index 224f54be15a6..526e59f43832 100644 --- a/sound/mips/au1x00.c +++ b/sound/mips/au1x00.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/ioport.h> | 37 | #include <linux/ioport.h> |
38 | #include <linux/interrupt.h> | 38 | #include <linux/interrupt.h> |
39 | #include <linux/init.h> | 39 | #include <linux/init.h> |
40 | #include <linux/platform_device.h> | ||
40 | #include <linux/slab.h> | 41 | #include <linux/slab.h> |
41 | #include <linux/module.h> | 42 | #include <linux/module.h> |
42 | #include <sound/core.h> | 43 | #include <sound/core.h> |
@@ -98,6 +99,7 @@ struct snd_au1000 { | |||
98 | 99 | ||
99 | struct snd_pcm *pcm; | 100 | struct snd_pcm *pcm; |
100 | struct audio_stream *stream[2]; /* playback & capture */ | 101 | struct audio_stream *stream[2]; /* playback & capture */ |
102 | int dmaid[2]; /* tx(0)/rx(1) DMA ids */ | ||
101 | }; | 103 | }; |
102 | 104 | ||
103 | /*--------------------------- Local Functions --------------------------------*/ | 105 | /*--------------------------- Local Functions --------------------------------*/ |
@@ -465,15 +467,17 @@ snd_au1000_pcm_new(struct snd_au1000 *au1000) | |||
465 | spin_lock_init(&au1000->stream[CAPTURE]->dma_lock); | 467 | spin_lock_init(&au1000->stream[CAPTURE]->dma_lock); |
466 | 468 | ||
467 | flags = claim_dma_lock(); | 469 | flags = claim_dma_lock(); |
468 | if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX, | 470 | au1000->stream[PLAYBACK]->dma = request_au1000_dma(au1000->dmaid[0], |
469 | "AC97 TX", au1000_dma_interrupt, 0, | 471 | "AC97 TX", au1000_dma_interrupt, 0, |
470 | au1000->stream[PLAYBACK])) < 0) { | 472 | au1000->stream[PLAYBACK]); |
473 | if (au1000->stream[PLAYBACK]->dma < 0) { | ||
471 | release_dma_lock(flags); | 474 | release_dma_lock(flags); |
472 | return -EBUSY; | 475 | return -EBUSY; |
473 | } | 476 | } |
474 | if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX, | 477 | au1000->stream[CAPTURE]->dma = request_au1000_dma(au1000->dmaid[1], |
475 | "AC97 RX", au1000_dma_interrupt, 0, | 478 | "AC97 RX", au1000_dma_interrupt, 0, |
476 | au1000->stream[CAPTURE])) < 0){ | 479 | au1000->stream[CAPTURE]); |
480 | if (au1000->stream[CAPTURE]->dma < 0){ | ||
477 | release_dma_lock(flags); | 481 | release_dma_lock(flags); |
478 | return -EBUSY; | 482 | return -EBUSY; |
479 | } | 483 | } |
@@ -552,69 +556,12 @@ get the interrupt driven case to work efficiently */ | |||
552 | spin_unlock(&au1000->ac97_lock); | 556 | spin_unlock(&au1000->ac97_lock); |
553 | } | 557 | } |
554 | 558 | ||
555 | static int | ||
556 | snd_au1000_ac97_new(struct snd_au1000 *au1000) | ||
557 | { | ||
558 | int err; | ||
559 | struct snd_ac97_bus *pbus; | ||
560 | struct snd_ac97_template ac97; | ||
561 | static struct snd_ac97_bus_ops ops = { | ||
562 | .write = snd_au1000_ac97_write, | ||
563 | .read = snd_au1000_ac97_read, | ||
564 | }; | ||
565 | |||
566 | if ((au1000->ac97_res_port = request_mem_region(CPHYSADDR(AC97C_CONFIG), | ||
567 | 0x100000, "Au1x00 AC97")) == NULL) { | ||
568 | snd_printk(KERN_ERR "ALSA AC97: can't grap AC97 port\n"); | ||
569 | return -EBUSY; | ||
570 | } | ||
571 | au1000->ac97_ioport = (struct au1000_ac97_reg *) | ||
572 | KSEG1ADDR(au1000->ac97_res_port->start); | ||
573 | |||
574 | spin_lock_init(&au1000->ac97_lock); | ||
575 | |||
576 | /* configure pins for AC'97 | ||
577 | TODO: move to board_setup.c */ | ||
578 | au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC); | ||
579 | |||
580 | /* Initialise Au1000's AC'97 Control Block */ | ||
581 | au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE; | ||
582 | udelay(10); | ||
583 | au1000->ac97_ioport->cntrl = AC97C_CE; | ||
584 | udelay(10); | ||
585 | |||
586 | /* Initialise External CODEC -- cold reset */ | ||
587 | au1000->ac97_ioport->config = AC97C_RESET; | ||
588 | udelay(10); | ||
589 | au1000->ac97_ioport->config = 0x0; | ||
590 | mdelay(5); | ||
591 | |||
592 | /* Initialise AC97 middle-layer */ | ||
593 | if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0) | ||
594 | return err; | ||
595 | |||
596 | memset(&ac97, 0, sizeof(ac97)); | ||
597 | ac97.private_data = au1000; | ||
598 | if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0) | ||
599 | return err; | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | /*------------------------------ Setup / Destroy ----------------------------*/ | 559 | /*------------------------------ Setup / Destroy ----------------------------*/ |
605 | 560 | ||
606 | void | 561 | static void snd_au1000_free(struct snd_card *card) |
607 | snd_au1000_free(struct snd_card *card) | ||
608 | { | 562 | { |
609 | struct snd_au1000 *au1000 = card->private_data; | 563 | struct snd_au1000 *au1000 = card->private_data; |
610 | 564 | ||
611 | if (au1000->ac97_res_port) { | ||
612 | /* put internal AC97 block into reset */ | ||
613 | au1000->ac97_ioport->cntrl = AC97C_RS; | ||
614 | au1000->ac97_ioport = NULL; | ||
615 | release_and_free_resource(au1000->ac97_res_port); | ||
616 | } | ||
617 | |||
618 | if (au1000->stream[PLAYBACK]) { | 565 | if (au1000->stream[PLAYBACK]) { |
619 | if (au1000->stream[PLAYBACK]->dma >= 0) | 566 | if (au1000->stream[PLAYBACK]->dma >= 0) |
620 | free_au1000_dma(au1000->stream[PLAYBACK]->dma); | 567 | free_au1000_dma(au1000->stream[PLAYBACK]->dma); |
@@ -626,71 +573,167 @@ snd_au1000_free(struct snd_card *card) | |||
626 | free_au1000_dma(au1000->stream[CAPTURE]->dma); | 573 | free_au1000_dma(au1000->stream[CAPTURE]->dma); |
627 | kfree(au1000->stream[CAPTURE]); | 574 | kfree(au1000->stream[CAPTURE]); |
628 | } | 575 | } |
629 | } | ||
630 | 576 | ||
577 | if (au1000->ac97_res_port) { | ||
578 | /* put internal AC97 block into reset */ | ||
579 | if (au1000->ac97_ioport) { | ||
580 | au1000->ac97_ioport->cntrl = AC97C_RS; | ||
581 | iounmap(au1000->ac97_ioport); | ||
582 | au1000->ac97_ioport = NULL; | ||
583 | } | ||
584 | release_and_free_resource(au1000->ac97_res_port); | ||
585 | au1000->ac97_res_port = NULL; | ||
586 | } | ||
587 | } | ||
631 | 588 | ||
632 | static struct snd_card *au1000_card; | 589 | static struct snd_ac97_bus_ops ops = { |
590 | .write = snd_au1000_ac97_write, | ||
591 | .read = snd_au1000_ac97_read, | ||
592 | }; | ||
633 | 593 | ||
634 | static int __init | 594 | static int au1000_ac97_probe(struct platform_device *pdev) |
635 | au1000_init(void) | ||
636 | { | 595 | { |
637 | int err; | 596 | int err; |
597 | void __iomem *io; | ||
598 | struct resource *r; | ||
638 | struct snd_card *card; | 599 | struct snd_card *card; |
639 | struct snd_au1000 *au1000; | 600 | struct snd_au1000 *au1000; |
601 | struct snd_ac97_bus *pbus; | ||
602 | struct snd_ac97_template ac97; | ||
640 | 603 | ||
641 | err = snd_card_create(-1, "AC97", THIS_MODULE, | 604 | err = snd_card_create(-1, "AC97", THIS_MODULE, |
642 | sizeof(struct snd_au1000), &card); | 605 | sizeof(struct snd_au1000), &card); |
643 | if (err < 0) | 606 | if (err < 0) |
644 | return err; | 607 | return err; |
645 | 608 | ||
646 | card->private_free = snd_au1000_free; | ||
647 | au1000 = card->private_data; | 609 | au1000 = card->private_data; |
648 | au1000->card = card; | 610 | au1000->card = card; |
611 | spin_lock_init(&au1000->ac97_lock); | ||
649 | 612 | ||
650 | au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL); | 613 | /* from here on let ALSA call the special freeing function */ |
651 | au1000->stream[CAPTURE ] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL); | 614 | card->private_free = snd_au1000_free; |
652 | /* so that snd_au1000_free will work as intended */ | ||
653 | au1000->ac97_res_port = NULL; | ||
654 | if (au1000->stream[PLAYBACK]) | ||
655 | au1000->stream[PLAYBACK]->dma = -1; | ||
656 | if (au1000->stream[CAPTURE ]) | ||
657 | au1000->stream[CAPTURE ]->dma = -1; | ||
658 | |||
659 | if (au1000->stream[PLAYBACK] == NULL || | ||
660 | au1000->stream[CAPTURE ] == NULL) { | ||
661 | snd_card_free(card); | ||
662 | return -ENOMEM; | ||
663 | } | ||
664 | 615 | ||
665 | if ((err = snd_au1000_ac97_new(au1000)) < 0 ) { | 616 | /* TX DMA ID */ |
666 | snd_card_free(card); | 617 | r = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
667 | return err; | 618 | if (!r) { |
619 | err = -ENODEV; | ||
620 | snd_printk(KERN_INFO "no TX DMA platform resource!\n"); | ||
621 | goto out; | ||
668 | } | 622 | } |
669 | 623 | au1000->dmaid[0] = r->start; | |
670 | if ((err = snd_au1000_pcm_new(au1000)) < 0) { | 624 | |
671 | snd_card_free(card); | 625 | /* RX DMA ID */ |
672 | return err; | 626 | r = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
627 | if (!r) { | ||
628 | err = -ENODEV; | ||
629 | snd_printk(KERN_INFO "no RX DMA platform resource!\n"); | ||
630 | goto out; | ||
631 | } | ||
632 | au1000->dmaid[1] = r->start; | ||
633 | |||
634 | au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), | ||
635 | GFP_KERNEL); | ||
636 | if (!au1000->stream[PLAYBACK]) | ||
637 | goto out; | ||
638 | au1000->stream[PLAYBACK]->dma = -1; | ||
639 | |||
640 | au1000->stream[CAPTURE] = kmalloc(sizeof(struct audio_stream), | ||
641 | GFP_KERNEL); | ||
642 | if (!au1000->stream[CAPTURE]) | ||
643 | goto out; | ||
644 | au1000->stream[CAPTURE]->dma = -1; | ||
645 | |||
646 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
647 | if (!r) | ||
648 | goto out; | ||
649 | |||
650 | err = -EBUSY; | ||
651 | au1000->ac97_res_port = request_mem_region(r->start, | ||
652 | r->end - r->start + 1, pdev->name); | ||
653 | if (!au1000->ac97_res_port) { | ||
654 | snd_printk(KERN_ERR "ALSA AC97: can't grab AC97 port\n"); | ||
655 | goto out; | ||
673 | } | 656 | } |
674 | 657 | ||
658 | io = ioremap(r->start, r->end - r->start + 1); | ||
659 | if (!io) | ||
660 | goto out; | ||
661 | |||
662 | au1000->ac97_ioport = (struct au1000_ac97_reg *)io; | ||
663 | |||
664 | /* configure pins for AC'97 | ||
665 | TODO: move to board_setup.c */ | ||
666 | au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC); | ||
667 | |||
668 | /* Initialise Au1000's AC'97 Control Block */ | ||
669 | au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE; | ||
670 | udelay(10); | ||
671 | au1000->ac97_ioport->cntrl = AC97C_CE; | ||
672 | udelay(10); | ||
673 | |||
674 | /* Initialise External CODEC -- cold reset */ | ||
675 | au1000->ac97_ioport->config = AC97C_RESET; | ||
676 | udelay(10); | ||
677 | au1000->ac97_ioport->config = 0x0; | ||
678 | mdelay(5); | ||
679 | |||
680 | /* Initialise AC97 middle-layer */ | ||
681 | err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus); | ||
682 | if (err < 0) | ||
683 | goto out; | ||
684 | |||
685 | memset(&ac97, 0, sizeof(ac97)); | ||
686 | ac97.private_data = au1000; | ||
687 | err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97); | ||
688 | if (err < 0) | ||
689 | goto out; | ||
690 | |||
691 | err = snd_au1000_pcm_new(au1000); | ||
692 | if (err < 0) | ||
693 | goto out; | ||
694 | |||
675 | strcpy(card->driver, "Au1000-AC97"); | 695 | strcpy(card->driver, "Au1000-AC97"); |
676 | strcpy(card->shortname, "AMD Au1000-AC97"); | 696 | strcpy(card->shortname, "AMD Au1000-AC97"); |
677 | sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver"); | 697 | sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver"); |
678 | 698 | ||
679 | if ((err = snd_card_register(card)) < 0) { | 699 | err = snd_card_register(card); |
680 | snd_card_free(card); | 700 | if (err < 0) |
681 | return err; | 701 | goto out; |
682 | } | ||
683 | 702 | ||
684 | printk(KERN_INFO "ALSA AC97: Driver Initialized\n"); | 703 | printk(KERN_INFO "ALSA AC97: Driver Initialized\n"); |
685 | au1000_card = card; | 704 | |
705 | platform_set_drvdata(pdev, card); | ||
706 | |||
686 | return 0; | 707 | return 0; |
708 | |||
709 | out: | ||
710 | snd_card_free(card); | ||
711 | return err; | ||
712 | } | ||
713 | |||
714 | static int au1000_ac97_remove(struct platform_device *pdev) | ||
715 | { | ||
716 | return snd_card_free(platform_get_drvdata(pdev)); | ||
687 | } | 717 | } |
688 | 718 | ||
689 | static void __exit au1000_exit(void) | 719 | struct platform_driver au1000_ac97c_driver = { |
720 | .driver = { | ||
721 | .name = "au1000-ac97c", | ||
722 | .owner = THIS_MODULE, | ||
723 | }, | ||
724 | .probe = au1000_ac97_probe, | ||
725 | .remove = au1000_ac97_remove, | ||
726 | }; | ||
727 | |||
728 | static int __init au1000_ac97_load(void) | ||
690 | { | 729 | { |
691 | snd_card_free(au1000_card); | 730 | return platform_driver_register(&au1000_ac97c_driver); |
692 | } | 731 | } |
693 | 732 | ||
694 | module_init(au1000_init); | 733 | static void __exit au1000_ac97_unload(void) |
695 | module_exit(au1000_exit); | 734 | { |
735 | platform_driver_unregister(&au1000_ac97c_driver); | ||
736 | } | ||
696 | 737 | ||
738 | module_init(au1000_ac97_load); | ||
739 | module_exit(au1000_ac97_unload); | ||