aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLawrence Rust <lawrence@softsystem.co.uk>2011-02-06 15:46:12 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-21 19:32:19 -0400
commit6951803c2402d1af0e76df051cc9b117f504550f (patch)
treeb7e64b2226a0873e9e8ba421fc21a69079ff9f35
parent724dcbfa9c24af5afdaa2b7e0449e20066d6555a (diff)
[media] Add proper audio support for Nova-S Plus with wm8775 ADC
This patch adds audio DMA capture and ALSA mixer elements for the line input jack of the Hauppauge Nova-S-plus DVB-S PCI card. The Nova-S-plus has a WM8775 ADC that is currently not detected. This patch enables this chip and exports volume, balance mute and ALC elements for ALSA mixer controls. [mchehab@redhat.com: Changed the patch to only talk with wm8775 if board info says so. Also, added platform_data support, to avoid changing the behaviour for other boards, and fixed CodingStyle] [awalls@md.metrocast.net: Changed patch to make the WM8775_GID defintion bridge driver private and let the bridge driver set the value of v4l2_subdev.grp_id.] -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com> Signed-off-by: Andy Walls <awalls@md.metrocast.net>
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c118
-rw-r--r--drivers/media/video/cx88/cx88-cards.c3
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c8
-rw-r--r--drivers/media/video/cx88/cx88-video.c52
-rw-r--r--drivers/media/video/cx88/cx88.h13
-rw-r--r--drivers/media/video/wm8775.c126
-rw-r--r--include/media/wm8775.h9
7 files changed, 267 insertions, 62 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",
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 8128b936c686..f735262f4767 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -970,7 +970,8 @@ static const struct cx88_board cx88_boards[] = {
970 .radio_type = UNSET, 970 .radio_type = UNSET,
971 .tuner_addr = ADDR_UNSET, 971 .tuner_addr = ADDR_UNSET,
972 .radio_addr = ADDR_UNSET, 972 .radio_addr = ADDR_UNSET,
973 .audio_chip = V4L2_IDENT_WM8775, 973 .audio_chip = V4L2_IDENT_WM8775,
974 .i2sinputcntl = 2,
974 .input = {{ 975 .input = {{
975 .type = CX88_VMUX_DVB, 976 .type = CX88_VMUX_DVB,
976 .vmux = 0, 977 .vmux = 0,
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 08220de3d74d..770ec05b5e9b 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -786,8 +786,12 @@ void cx88_set_tvaudio(struct cx88_core *core)
786 break; 786 break;
787 case WW_I2SADC: 787 case WW_I2SADC:
788 set_audio_start(core, 0x01); 788 set_audio_start(core, 0x01);
789 /* Slave/Philips/Autobaud */ 789 /*
790 cx_write(AUD_I2SINPUTCNTL, 0); 790 * Slave/Philips/Autobaud
791 * NB on Nova-S bit1 NPhilipsSony appears to be inverted:
792 * 0= Sony, 1=Philips
793 */
794 cx_write(AUD_I2SINPUTCNTL, core->board.i2sinputcntl);
791 /* Switch to "I2S ADC mode" */ 795 /* Switch to "I2S ADC mode" */
792 cx_write(AUD_I2SCNTL, 0x1); 796 cx_write(AUD_I2SCNTL, 0x1);
793 set_audio_finish(core, EN_I2SIN_ENABLE); 797 set_audio_finish(core, EN_I2SIN_ENABLE);
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index f814886ccd17..287a41ee1c4f 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -40,6 +40,7 @@
40#include "cx88.h" 40#include "cx88.h"
41#include <media/v4l2-common.h> 41#include <media/v4l2-common.h>
42#include <media/v4l2-ioctl.h> 42#include <media/v4l2-ioctl.h>
43#include <media/wm8775.h>
43 44
44MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); 45MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
45MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); 46MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -989,6 +990,32 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
989 ctl->value = c->v.minimum; 990 ctl->value = c->v.minimum;
990 if (ctl->value > c->v.maximum) 991 if (ctl->value > c->v.maximum)
991 ctl->value = c->v.maximum; 992 ctl->value = c->v.maximum;
993
994 /* Pass changes onto any WM8775 */
995 if (core->board.audio_chip == V4L2_IDENT_WM8775) {
996 struct v4l2_control client_ctl;
997 memset(&client_ctl, 0, sizeof(client_ctl));
998 client_ctl.id = ctl->id;
999
1000 switch (ctl->id) {
1001 case V4L2_CID_AUDIO_MUTE:
1002 client_ctl.value = ctl->value;
1003 break;
1004 case V4L2_CID_AUDIO_VOLUME:
1005 client_ctl.value = (ctl->value) ?
1006 (0x90 + ctl->value) << 8 : 0;
1007 break;
1008 case V4L2_CID_AUDIO_BALANCE:
1009 client_ctl.value = ctl->value << 9;
1010 break;
1011 default:
1012 client_ctl.id = 0;
1013 break;
1014 }
1015 if (client_ctl.id)
1016 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
1017 }
1018
992 mask=c->mask; 1019 mask=c->mask;
993 switch (ctl->id) { 1020 switch (ctl->id) {
994 case V4L2_CID_AUDIO_BALANCE: 1021 case V4L2_CID_AUDIO_BALANCE:
@@ -1526,7 +1553,9 @@ static int radio_queryctrl (struct file *file, void *priv,
1526 if (c->id < V4L2_CID_BASE || 1553 if (c->id < V4L2_CID_BASE ||
1527 c->id >= V4L2_CID_LASTP1) 1554 c->id >= V4L2_CID_LASTP1)
1528 return -EINVAL; 1555 return -EINVAL;
1529 if (c->id == V4L2_CID_AUDIO_MUTE) { 1556 if (c->id == V4L2_CID_AUDIO_MUTE ||
1557 c->id == V4L2_CID_AUDIO_VOLUME ||
1558 c->id == V4L2_CID_AUDIO_BALANCE) {
1530 for (i = 0; i < CX8800_CTLS; i++) { 1559 for (i = 0; i < CX8800_CTLS; i++) {
1531 if (cx8800_ctls[i].v.id == c->id) 1560 if (cx8800_ctls[i].v.id == c->id)
1532 break; 1561 break;
@@ -1856,9 +1885,24 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
1856 1885
1857 /* load and configure helper modules */ 1886 /* load and configure helper modules */
1858 1887
1859 if (core->board.audio_chip == V4L2_IDENT_WM8775) 1888 if (core->board.audio_chip == V4L2_IDENT_WM8775) {
1860 v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, 1889 struct i2c_board_info wm8775_info = {
1861 "wm8775", 0x36 >> 1, NULL); 1890 .type = "wm8775",
1891 .addr = 0x36 >> 1,
1892 .platform_data = &core->wm8775_data,
1893 };
1894 struct v4l2_subdev *sd;
1895
1896 if (core->boardnr == CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1)
1897 core->wm8775_data.is_nova_s = true;
1898 else
1899 core->wm8775_data.is_nova_s = false;
1900
1901 sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap,
1902 &wm8775_info, NULL);
1903 if (sd != NULL)
1904 sd->grp_id = WM8775_GID;
1905 }
1862 1906
1863 if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { 1907 if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
1864 /* This probes for a tda9874 as is used on some 1908 /* This probes for a tda9874 as is used on some
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index c9981e77416a..aaf7d12b77db 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -33,6 +33,7 @@
33#include <media/cx2341x.h> 33#include <media/cx2341x.h>
34#include <media/videobuf-dvb.h> 34#include <media/videobuf-dvb.h>
35#include <media/ir-kbd-i2c.h> 35#include <media/ir-kbd-i2c.h>
36#include <media/wm8775.h>
36 37
37#include "btcx-risc.h" 38#include "btcx-risc.h"
38#include "cx88-reg.h" 39#include "cx88-reg.h"
@@ -273,6 +274,9 @@ struct cx88_board {
273 enum cx88_board_type mpeg; 274 enum cx88_board_type mpeg;
274 unsigned int audio_chip; 275 unsigned int audio_chip;
275 int num_frontends; 276 int num_frontends;
277
278 /* Used for I2S devices */
279 int i2sinputcntl;
276}; 280};
277 281
278struct cx88_subid { 282struct cx88_subid {
@@ -379,6 +383,7 @@ struct cx88_core {
379 383
380 /* I2C remote data */ 384 /* I2C remote data */
381 struct IR_i2c_init_data init_data; 385 struct IR_i2c_init_data init_data;
386 struct wm8775_platform_data wm8775_data;
382 387
383 struct mutex lock; 388 struct mutex lock;
384 /* various v4l controls */ 389 /* various v4l controls */
@@ -398,17 +403,21 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
398 return container_of(v4l2_dev, struct cx88_core, v4l2_dev); 403 return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
399} 404}
400 405
401#define call_all(core, o, f, args...) \ 406#define WM8775_GID (1 << 0)
407
408#define call_hw(core, grpid, o, f, args...) \
402 do { \ 409 do { \
403 if (!core->i2c_rc) { \ 410 if (!core->i2c_rc) { \
404 if (core->gate_ctrl) \ 411 if (core->gate_ctrl) \
405 core->gate_ctrl(core, 1); \ 412 core->gate_ctrl(core, 1); \
406 v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ 413 v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
407 if (core->gate_ctrl) \ 414 if (core->gate_ctrl) \
408 core->gate_ctrl(core, 0); \ 415 core->gate_ctrl(core, 0); \
409 } \ 416 } \
410 } while (0) 417 } while (0)
411 418
419#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
420
412struct cx8800_dev; 421struct cx8800_dev;
413struct cx8802_dev; 422struct cx8802_dev;
414 423
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index fe8ef6419f83..9cedb1e69b58 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -35,6 +35,7 @@
35#include <media/v4l2-device.h> 35#include <media/v4l2-device.h>
36#include <media/v4l2-chip-ident.h> 36#include <media/v4l2-chip-ident.h>
37#include <media/v4l2-ctrls.h> 37#include <media/v4l2-ctrls.h>
38#include <media/wm8775.h>
38 39
39MODULE_DESCRIPTION("wm8775 driver"); 40MODULE_DESCRIPTION("wm8775 driver");
40MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); 41MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
@@ -50,10 +51,16 @@ enum {
50 TOT_REGS 51 TOT_REGS
51}; 52};
52 53
54#define ALC_HOLD 0x85 /* R17: use zero cross detection, ALC hold time 42.6 ms */
55#define ALC_EN 0x100 /* R17: ALC enable */
56
53struct wm8775_state { 57struct wm8775_state {
54 struct v4l2_subdev sd; 58 struct v4l2_subdev sd;
55 struct v4l2_ctrl_handler hdl; 59 struct v4l2_ctrl_handler hdl;
56 struct v4l2_ctrl *mute; 60 struct v4l2_ctrl *mute;
61 struct v4l2_ctrl *vol;
62 struct v4l2_ctrl *bal;
63 struct v4l2_ctrl *loud;
57 u8 input; /* Last selected input (0-0xf) */ 64 u8 input; /* Last selected input (0-0xf) */
58}; 65};
59 66
@@ -85,6 +92,30 @@ static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
85 return -1; 92 return -1;
86} 93}
87 94
95static void wm8775_set_audio(struct v4l2_subdev *sd, int quietly)
96{
97 struct wm8775_state *state = to_state(sd);
98 u8 vol_l, vol_r;
99 int muted = 0 != state->mute->val;
100 u16 volume = (u16)state->vol->val;
101 u16 balance = (u16)state->bal->val;
102
103 /* normalize ( 65535 to 0 -> 255 to 0 (+24dB to -103dB) ) */
104 vol_l = (min(65536 - balance, 32768) * volume) >> 23;
105 vol_r = (min(balance, (u16)32768) * volume) >> 23;
106
107 /* Mute */
108 if (muted || quietly)
109 wm8775_write(sd, R21, 0x0c0 | state->input);
110
111 wm8775_write(sd, R14, vol_l | 0x100); /* 0x100= Left channel ADC zero cross enable */
112 wm8775_write(sd, R15, vol_r | 0x100); /* 0x100= Right channel ADC zero cross enable */
113
114 /* Un-mute */
115 if (!muted)
116 wm8775_write(sd, R21, state->input);
117}
118
88static int wm8775_s_routing(struct v4l2_subdev *sd, 119static int wm8775_s_routing(struct v4l2_subdev *sd,
89 u32 input, u32 output, u32 config) 120 u32 input, u32 output, u32 config)
90{ 121{
@@ -102,25 +133,26 @@ static int wm8775_s_routing(struct v4l2_subdev *sd,
102 state->input = input; 133 state->input = input;
103 if (!v4l2_ctrl_g_ctrl(state->mute)) 134 if (!v4l2_ctrl_g_ctrl(state->mute))
104 return 0; 135 return 0;
105 wm8775_write(sd, R21, 0x0c0); 136 if (!v4l2_ctrl_g_ctrl(state->vol))
106 wm8775_write(sd, R14, 0x1d4); 137 return 0;
107 wm8775_write(sd, R15, 0x1d4); 138 if (!v4l2_ctrl_g_ctrl(state->bal))
108 wm8775_write(sd, R21, 0x100 + state->input); 139 return 0;
140 wm8775_set_audio(sd, 1);
109 return 0; 141 return 0;
110} 142}
111 143
112static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl) 144static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
113{ 145{
114 struct v4l2_subdev *sd = to_sd(ctrl); 146 struct v4l2_subdev *sd = to_sd(ctrl);
115 struct wm8775_state *state = to_state(sd);
116 147
117 switch (ctrl->id) { 148 switch (ctrl->id) {
118 case V4L2_CID_AUDIO_MUTE: 149 case V4L2_CID_AUDIO_MUTE:
119 wm8775_write(sd, R21, 0x0c0); 150 case V4L2_CID_AUDIO_VOLUME:
120 wm8775_write(sd, R14, 0x1d4); 151 case V4L2_CID_AUDIO_BALANCE:
121 wm8775_write(sd, R15, 0x1d4); 152 wm8775_set_audio(sd, 0);
122 if (!ctrl->val) 153 return 0;
123 wm8775_write(sd, R21, 0x100 + state->input); 154 case V4L2_CID_AUDIO_LOUDNESS:
155 wm8775_write(sd, R17, (ctrl->val ? ALC_EN : 0) | ALC_HOLD);
124 return 0; 156 return 0;
125 } 157 }
126 return -EINVAL; 158 return -EINVAL;
@@ -144,16 +176,7 @@ static int wm8775_log_status(struct v4l2_subdev *sd)
144 176
145static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq) 177static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *freq)
146{ 178{
147 struct wm8775_state *state = to_state(sd); 179 wm8775_set_audio(sd, 0);
148
149 /* If I remove this, then it can happen that I have no
150 sound the first time I tune from static to a valid channel.
151 It's difficult to reproduce and is almost certainly related
152 to the zero cross detect circuit. */
153 wm8775_write(sd, R21, 0x0c0);
154 wm8775_write(sd, R14, 0x1d4);
155 wm8775_write(sd, R15, 0x1d4);
156 wm8775_write(sd, R21, 0x100 + state->input);
157 return 0; 180 return 0;
158} 181}
159 182
@@ -203,6 +226,13 @@ static int wm8775_probe(struct i2c_client *client,
203{ 226{
204 struct wm8775_state *state; 227 struct wm8775_state *state;
205 struct v4l2_subdev *sd; 228 struct v4l2_subdev *sd;
229 int err;
230 bool is_nova_s = false;
231
232 if (client->dev.platform_data) {
233 struct wm8775_platform_data *data = client->dev.platform_data;
234 is_nova_s = data->is_nova_s;
235 }
206 236
207 /* Check if the adapter supports the needed features */ 237 /* Check if the adapter supports the needed features */
208 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 238 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -218,13 +248,18 @@ static int wm8775_probe(struct i2c_client *client,
218 v4l2_i2c_subdev_init(sd, client, &wm8775_ops); 248 v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
219 state->input = 2; 249 state->input = 2;
220 250
221 v4l2_ctrl_handler_init(&state->hdl, 1); 251 v4l2_ctrl_handler_init(&state->hdl, 4);
222 state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, 252 state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
223 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); 253 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
254 state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
255 V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/
256 state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
257 V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768);
258 state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
259 V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1);
224 sd->ctrl_handler = &state->hdl; 260 sd->ctrl_handler = &state->hdl;
225 if (state->hdl.error) { 261 err = state->hdl.error;
226 int err = state->hdl.error; 262 if (err) {
227
228 v4l2_ctrl_handler_free(&state->hdl); 263 v4l2_ctrl_handler_free(&state->hdl);
229 kfree(state); 264 kfree(state);
230 return err; 265 return err;
@@ -236,29 +271,44 @@ static int wm8775_probe(struct i2c_client *client,
236 wm8775_write(sd, R23, 0x000); 271 wm8775_write(sd, R23, 0x000);
237 /* Disable zero cross detect timeout */ 272 /* Disable zero cross detect timeout */
238 wm8775_write(sd, R7, 0x000); 273 wm8775_write(sd, R7, 0x000);
239 /* Left justified, 24-bit mode */ 274 /* HPF enable, left justified, 24-bit (Philips) mode */
240 wm8775_write(sd, R11, 0x021); 275 wm8775_write(sd, R11, 0x021);
241 /* Master mode, clock ratio 256fs */ 276 /* Master mode, clock ratio 256fs */
242 wm8775_write(sd, R12, 0x102); 277 wm8775_write(sd, R12, 0x102);
243 /* Powered up */ 278 /* Powered up */
244 wm8775_write(sd, R13, 0x000); 279 wm8775_write(sd, R13, 0x000);
245 /* ADC gain +2.5dB, enable zero cross */ 280
246 wm8775_write(sd, R14, 0x1d4); 281 if (!is_nova_s) {
247 /* ADC gain +2.5dB, enable zero cross */ 282 /* ADC gain +2.5dB, enable zero cross */
248 wm8775_write(sd, R15, 0x1d4); 283 wm8775_write(sd, R14, 0x1d4);
249 /* ALC Stereo, ALC target level -1dB FS max gain +8dB */ 284 /* ADC gain +2.5dB, enable zero cross */
250 wm8775_write(sd, R16, 0x1bf); 285 wm8775_write(sd, R15, 0x1d4);
251 /* Enable gain control, use zero cross detection, 286 /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
252 ALC hold time 42.6 ms */ 287 wm8775_write(sd, R16, 0x1bf);
253 wm8775_write(sd, R17, 0x185); 288 /* Enable gain control, use zero cross detection,
289 ALC hold time 42.6 ms */
290 wm8775_write(sd, R17, 0x185);
291 } else {
292 /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */
293 wm8775_write(sd, R16, 0x1bb);
294 /* Set ALC mode and hold time */
295 wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD);
296 }
254 /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ 297 /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
255 wm8775_write(sd, R18, 0x0a2); 298 wm8775_write(sd, R18, 0x0a2);
256 /* Enable noise gate, threshold -72dBfs */ 299 /* Enable noise gate, threshold -72dBfs */
257 wm8775_write(sd, R19, 0x005); 300 wm8775_write(sd, R19, 0x005);
258 /* Transient window 4ms, lower PGA gain limit -1dB */ 301 if (!is_nova_s) {
259 wm8775_write(sd, R20, 0x07a); 302 /* Transient window 4ms, lower PGA gain limit -1dB */
260 /* LRBOTH = 1, use input 2. */ 303 wm8775_write(sd, R20, 0x07a);
261 wm8775_write(sd, R21, 0x102); 304 /* LRBOTH = 1, use input 2. */
305 wm8775_write(sd, R21, 0x102);
306 } else {
307 /* Transient window 4ms, ALC min gain -5dB */
308 wm8775_write(sd, R20, 0x0fb);
309
310 wm8775_set_audio(sd, 1); /* set volume/mute/mux */
311 }
262 return 0; 312 return 0;
263} 313}
264 314
diff --git a/include/media/wm8775.h b/include/media/wm8775.h
index 60739c5a23ae..d0e801a9935c 100644
--- a/include/media/wm8775.h
+++ b/include/media/wm8775.h
@@ -32,4 +32,13 @@
32#define WM8775_AIN3 4 32#define WM8775_AIN3 4
33#define WM8775_AIN4 8 33#define WM8775_AIN4 8
34 34
35
36struct wm8775_platform_data {
37 /*
38 * FIXME: Instead, we should parametrize the params
39 * that need different settings between ivtv, pvrusb2, and Nova-S
40 */
41 bool is_nova_s;
42};
43
35#endif 44#endif