aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx88/cx88-alsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx88/cx88-alsa.c')
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c118
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
581static 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 */
581static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, 611static 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
659static const struct snd_kcontrol_new snd_cx88_dac_switch = { 702static 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
668static const struct snd_kcontrol_new snd_cx88_source_switch = { 711static 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
720static 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
735static 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
750static 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)
724static int devno; 805static int devno;
725static int __devinit snd_cx88_create(struct snd_card *card, 806static 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",