diff options
Diffstat (limited to 'drivers/media/video/cx88/cx88-alsa.c')
-rw-r--r-- | drivers/media/video/cx88/cx88-alsa.c | 118 |
1 files changed, 103 insertions, 15 deletions
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 54b7fcd469a8..a2d688ebed90 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <sound/control.h> | 40 | #include <sound/control.h> |
41 | #include <sound/initval.h> | 41 | #include <sound/initval.h> |
42 | #include <sound/tlv.h> | 42 | #include <sound/tlv.h> |
43 | #include <media/wm8775.h> | ||
43 | 44 | ||
44 | #include "cx88.h" | 45 | #include "cx88.h" |
45 | #include "cx88-reg.h" | 46 | #include "cx88-reg.h" |
@@ -577,6 +578,35 @@ static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol, | |||
577 | return 0; | 578 | return 0; |
578 | } | 579 | } |
579 | 580 | ||
581 | static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, | ||
582 | struct snd_ctl_elem_value *value) | ||
583 | { | ||
584 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); | ||
585 | struct cx88_core *core = chip->core; | ||
586 | struct v4l2_control client_ctl; | ||
587 | int left = value->value.integer.value[0]; | ||
588 | int right = value->value.integer.value[1]; | ||
589 | int v, b; | ||
590 | |||
591 | memset(&client_ctl, 0, sizeof(client_ctl)); | ||
592 | |||
593 | /* Pass volume & balance onto any WM8775 */ | ||
594 | if (left >= right) { | ||
595 | v = left << 10; | ||
596 | b = left ? (0x8000 * right) / left : 0x8000; | ||
597 | } else { | ||
598 | v = right << 10; | ||
599 | b = right ? 0xffff - (0x8000 * left) / right : 0x8000; | ||
600 | } | ||
601 | client_ctl.value = v; | ||
602 | client_ctl.id = V4L2_CID_AUDIO_VOLUME; | ||
603 | call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); | ||
604 | |||
605 | client_ctl.value = b; | ||
606 | client_ctl.id = V4L2_CID_AUDIO_BALANCE; | ||
607 | call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); | ||
608 | } | ||
609 | |||
580 | /* OK - TODO: test it */ | 610 | /* OK - TODO: test it */ |
581 | static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, | 611 | static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, |
582 | struct snd_ctl_elem_value *value) | 612 | struct snd_ctl_elem_value *value) |
@@ -587,25 +617,28 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, | |||
587 | int changed = 0; | 617 | int changed = 0; |
588 | u32 old; | 618 | u32 old; |
589 | 619 | ||
620 | if (core->board.audio_chip == V4L2_IDENT_WM8775) | ||
621 | snd_cx88_wm8775_volume_put(kcontrol, value); | ||
622 | |||
590 | left = value->value.integer.value[0] & 0x3f; | 623 | left = value->value.integer.value[0] & 0x3f; |
591 | right = value->value.integer.value[1] & 0x3f; | 624 | right = value->value.integer.value[1] & 0x3f; |
592 | b = right - left; | 625 | b = right - left; |
593 | if (b < 0) { | 626 | if (b < 0) { |
594 | v = 0x3f - left; | 627 | v = 0x3f - left; |
595 | b = (-b) | 0x40; | 628 | b = (-b) | 0x40; |
596 | } else { | 629 | } else { |
597 | v = 0x3f - right; | 630 | v = 0x3f - right; |
598 | } | 631 | } |
599 | /* Do we really know this will always be called with IRQs on? */ | 632 | /* Do we really know this will always be called with IRQs on? */ |
600 | spin_lock_irq(&chip->reg_lock); | 633 | spin_lock_irq(&chip->reg_lock); |
601 | old = cx_read(AUD_VOL_CTL); | 634 | old = cx_read(AUD_VOL_CTL); |
602 | if (v != (old & 0x3f)) { | 635 | if (v != (old & 0x3f)) { |
603 | cx_write(AUD_VOL_CTL, (old & ~0x3f) | v); | 636 | cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v); |
604 | changed = 1; | 637 | changed = 1; |
605 | } | 638 | } |
606 | if (cx_read(AUD_BAL_CTL) != b) { | 639 | if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) { |
607 | cx_write(AUD_BAL_CTL, b); | 640 | cx_write(AUD_BAL_CTL, b); |
608 | changed = 1; | 641 | changed = 1; |
609 | } | 642 | } |
610 | spin_unlock_irq(&chip->reg_lock); | 643 | spin_unlock_irq(&chip->reg_lock); |
611 | 644 | ||
@@ -618,7 +651,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = { | |||
618 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 651 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
619 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 652 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
620 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 653 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, |
621 | .name = "Playback Volume", | 654 | .name = "Analog-TV Volume", |
622 | .info = snd_cx88_volume_info, | 655 | .info = snd_cx88_volume_info, |
623 | .get = snd_cx88_volume_get, | 656 | .get = snd_cx88_volume_get, |
624 | .put = snd_cx88_volume_put, | 657 | .put = snd_cx88_volume_put, |
@@ -649,7 +682,17 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, | |||
649 | vol = cx_read(AUD_VOL_CTL); | 682 | vol = cx_read(AUD_VOL_CTL); |
650 | if (value->value.integer.value[0] != !(vol & bit)) { | 683 | if (value->value.integer.value[0] != !(vol & bit)) { |
651 | vol ^= bit; | 684 | vol ^= bit; |
652 | cx_write(AUD_VOL_CTL, vol); | 685 | cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol); |
686 | /* Pass mute onto any WM8775 */ | ||
687 | if ((core->board.audio_chip == V4L2_IDENT_WM8775) && | ||
688 | ((1<<6) == bit)) { | ||
689 | struct v4l2_control client_ctl; | ||
690 | |||
691 | memset(&client_ctl, 0, sizeof(client_ctl)); | ||
692 | client_ctl.value = 0 != (vol & bit); | ||
693 | client_ctl.id = V4L2_CID_AUDIO_MUTE; | ||
694 | call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); | ||
695 | } | ||
653 | ret = 1; | 696 | ret = 1; |
654 | } | 697 | } |
655 | spin_unlock_irq(&chip->reg_lock); | 698 | spin_unlock_irq(&chip->reg_lock); |
@@ -658,7 +701,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, | |||
658 | 701 | ||
659 | static const struct snd_kcontrol_new snd_cx88_dac_switch = { | 702 | static const struct snd_kcontrol_new snd_cx88_dac_switch = { |
660 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 703 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
661 | .name = "Playback Switch", | 704 | .name = "Audio-Out Switch", |
662 | .info = snd_ctl_boolean_mono_info, | 705 | .info = snd_ctl_boolean_mono_info, |
663 | .get = snd_cx88_switch_get, | 706 | .get = snd_cx88_switch_get, |
664 | .put = snd_cx88_switch_put, | 707 | .put = snd_cx88_switch_put, |
@@ -667,13 +710,51 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = { | |||
667 | 710 | ||
668 | static const struct snd_kcontrol_new snd_cx88_source_switch = { | 711 | static const struct snd_kcontrol_new snd_cx88_source_switch = { |
669 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 712 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
670 | .name = "Capture Switch", | 713 | .name = "Analog-TV Switch", |
671 | .info = snd_ctl_boolean_mono_info, | 714 | .info = snd_ctl_boolean_mono_info, |
672 | .get = snd_cx88_switch_get, | 715 | .get = snd_cx88_switch_get, |
673 | .put = snd_cx88_switch_put, | 716 | .put = snd_cx88_switch_put, |
674 | .private_value = (1<<6), | 717 | .private_value = (1<<6), |
675 | }; | 718 | }; |
676 | 719 | ||
720 | static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol, | ||
721 | struct snd_ctl_elem_value *value) | ||
722 | { | ||
723 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); | ||
724 | struct cx88_core *core = chip->core; | ||
725 | struct v4l2_control client_ctl; | ||
726 | |||
727 | memset(&client_ctl, 0, sizeof(client_ctl)); | ||
728 | client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; | ||
729 | call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl); | ||
730 | value->value.integer.value[0] = client_ctl.value ? 1 : 0; | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol, | ||
736 | struct snd_ctl_elem_value *value) | ||
737 | { | ||
738 | snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); | ||
739 | struct cx88_core *core = chip->core; | ||
740 | struct v4l2_control client_ctl; | ||
741 | |||
742 | memset(&client_ctl, 0, sizeof(client_ctl)); | ||
743 | client_ctl.value = 0 != value->value.integer.value[0]; | ||
744 | client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; | ||
745 | call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | static struct snd_kcontrol_new snd_cx88_alc_switch = { | ||
751 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
752 | .name = "Line-In ALC Switch", | ||
753 | .info = snd_ctl_boolean_mono_info, | ||
754 | .get = snd_cx88_alc_get, | ||
755 | .put = snd_cx88_alc_put, | ||
756 | }; | ||
757 | |||
677 | /**************************************************************************** | 758 | /**************************************************************************** |
678 | Basic Flow for Sound Devices | 759 | Basic Flow for Sound Devices |
679 | ****************************************************************************/ | 760 | ****************************************************************************/ |
@@ -724,7 +805,8 @@ static void snd_cx88_dev_free(struct snd_card * card) | |||
724 | static int devno; | 805 | static int devno; |
725 | static int __devinit snd_cx88_create(struct snd_card *card, | 806 | static int __devinit snd_cx88_create(struct snd_card *card, |
726 | struct pci_dev *pci, | 807 | struct pci_dev *pci, |
727 | snd_cx88_card_t **rchip) | 808 | snd_cx88_card_t **rchip, |
809 | struct cx88_core **core_ptr) | ||
728 | { | 810 | { |
729 | snd_cx88_card_t *chip; | 811 | snd_cx88_card_t *chip; |
730 | struct cx88_core *core; | 812 | struct cx88_core *core; |
@@ -750,7 +832,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, | |||
750 | if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) { | 832 | if (!pci_dma_supported(pci,DMA_BIT_MASK(32))) { |
751 | dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); | 833 | dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); |
752 | err = -EIO; | 834 | err = -EIO; |
753 | cx88_core_put(core,pci); | 835 | cx88_core_put(core, pci); |
754 | return err; | 836 | return err; |
755 | } | 837 | } |
756 | 838 | ||
@@ -786,6 +868,7 @@ static int __devinit snd_cx88_create(struct snd_card *card, | |||
786 | snd_card_set_dev(card, &pci->dev); | 868 | snd_card_set_dev(card, &pci->dev); |
787 | 869 | ||
788 | *rchip = chip; | 870 | *rchip = chip; |
871 | *core_ptr = core; | ||
789 | 872 | ||
790 | return 0; | 873 | return 0; |
791 | } | 874 | } |
@@ -795,6 +878,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, | |||
795 | { | 878 | { |
796 | struct snd_card *card; | 879 | struct snd_card *card; |
797 | snd_cx88_card_t *chip; | 880 | snd_cx88_card_t *chip; |
881 | struct cx88_core *core; | ||
798 | int err; | 882 | int err; |
799 | 883 | ||
800 | if (devno >= SNDRV_CARDS) | 884 | if (devno >= SNDRV_CARDS) |
@@ -812,7 +896,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, | |||
812 | 896 | ||
813 | card->private_free = snd_cx88_dev_free; | 897 | card->private_free = snd_cx88_dev_free; |
814 | 898 | ||
815 | err = snd_cx88_create(card, pci, &chip); | 899 | err = snd_cx88_create(card, pci, &chip, &core); |
816 | if (err < 0) | 900 | if (err < 0) |
817 | goto error; | 901 | goto error; |
818 | 902 | ||
@@ -830,6 +914,10 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci, | |||
830 | if (err < 0) | 914 | if (err < 0) |
831 | goto error; | 915 | goto error; |
832 | 916 | ||
917 | /* If there's a wm8775 then add a Line-In ALC switch */ | ||
918 | if (core->board.audio_chip == V4L2_IDENT_WM8775) | ||
919 | snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip)); | ||
920 | |||
833 | strcpy (card->driver, "CX88x"); | 921 | strcpy (card->driver, "CX88x"); |
834 | sprintf(card->shortname, "Conexant CX%x", pci->device); | 922 | sprintf(card->shortname, "Conexant CX%x", pci->device); |
835 | sprintf(card->longname, "%s at %#llx", | 923 | sprintf(card->longname, "%s at %#llx", |