aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlawrence rust <lawrence@softsystem.co.uk>2010-10-18 06:06:02 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-10-22 23:17:52 -0400
commitfcb9757333df37cf4a7feccef7ef6f5300643864 (patch)
treeb04e8567ef7fd1d6a67c291122dbd2476c38bcc8
parentcb0ed22270129b980257fa9c83b152f09ecd9eda (diff)
[media] Nova-S-Plus audio line input
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: Fix CodingStyle issues] Signed-off-by: Lawrence Rust <lawrence@softsystem.co.uk> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c99
-rw-r--r--drivers/media/video/cx88/cx88-cards.c7
-rw-r--r--drivers/media/video/cx88/cx88-video.c27
-rw-r--r--drivers/media/video/cx88/cx88.h6
-rw-r--r--drivers/media/video/wm8775.c104
-rw-r--r--include/media/wm8775.h3
6 files changed, 192 insertions, 54 deletions
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 54b7fcd469a..4aaa47c0eab 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"
@@ -586,26 +587,47 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
586 int left, right, v, b; 587 int left, right, v, b;
587 int changed = 0; 588 int changed = 0;
588 u32 old; 589 u32 old;
590 struct v4l2_control client_ctl;
591
592 /* Pass volume & balance onto any WM8775 */
593 if (value->value.integer.value[0] >= value->value.integer.value[1]) {
594 v = value->value.integer.value[0] << 10;
595 b = value->value.integer.value[0] ?
596 (0x8000 * value->value.integer.value[1]) / value->value.integer.value[0] :
597 0x8000;
598 } else {
599 v = value->value.integer.value[1] << 10;
600 b = value->value.integer.value[1] ?
601 0xffff - (0x8000 * value->value.integer.value[0]) / value->value.integer.value[1] :
602 0x8000;
603 }
604 client_ctl.value = v;
605 client_ctl.id = V4L2_CID_AUDIO_VOLUME;
606 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
607
608 client_ctl.value = b;
609 client_ctl.id = V4L2_CID_AUDIO_BALANCE;
610 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
589 611
590 left = value->value.integer.value[0] & 0x3f; 612 left = value->value.integer.value[0] & 0x3f;
591 right = value->value.integer.value[1] & 0x3f; 613 right = value->value.integer.value[1] & 0x3f;
592 b = right - left; 614 b = right - left;
593 if (b < 0) { 615 if (b < 0) {
594 v = 0x3f - left; 616 v = 0x3f - left;
595 b = (-b) | 0x40; 617 b = (-b) | 0x40;
596 } else { 618 } else {
597 v = 0x3f - right; 619 v = 0x3f - right;
598 } 620 }
599 /* Do we really know this will always be called with IRQs on? */ 621 /* Do we really know this will always be called with IRQs on? */
600 spin_lock_irq(&chip->reg_lock); 622 spin_lock_irq(&chip->reg_lock);
601 old = cx_read(AUD_VOL_CTL); 623 old = cx_read(AUD_VOL_CTL);
602 if (v != (old & 0x3f)) { 624 if (v != (old & 0x3f)) {
603 cx_write(AUD_VOL_CTL, (old & ~0x3f) | v); 625 cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);
604 changed = 1; 626 changed = 1;
605 } 627 }
606 if (cx_read(AUD_BAL_CTL) != b) { 628 if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {
607 cx_write(AUD_BAL_CTL, b); 629 cx_write(AUD_BAL_CTL, b);
608 changed = 1; 630 changed = 1;
609 } 631 }
610 spin_unlock_irq(&chip->reg_lock); 632 spin_unlock_irq(&chip->reg_lock);
611 633
@@ -618,7 +640,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = {
618 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 640 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
619 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | 641 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
620 SNDRV_CTL_ELEM_ACCESS_TLV_READ, 642 SNDRV_CTL_ELEM_ACCESS_TLV_READ,
621 .name = "Playback Volume", 643 .name = "Analog-TV Volume",
622 .info = snd_cx88_volume_info, 644 .info = snd_cx88_volume_info,
623 .get = snd_cx88_volume_get, 645 .get = snd_cx88_volume_get,
624 .put = snd_cx88_volume_put, 646 .put = snd_cx88_volume_put,
@@ -649,7 +671,14 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
649 vol = cx_read(AUD_VOL_CTL); 671 vol = cx_read(AUD_VOL_CTL);
650 if (value->value.integer.value[0] != !(vol & bit)) { 672 if (value->value.integer.value[0] != !(vol & bit)) {
651 vol ^= bit; 673 vol ^= bit;
652 cx_write(AUD_VOL_CTL, vol); 674 cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);
675 /* Pass mute onto any WM8775 */
676 if ((1<<6) == bit) {
677 struct v4l2_control client_ctl;
678 client_ctl.value = 0 != (vol & bit);
679 client_ctl.id = V4L2_CID_AUDIO_MUTE;
680 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
681 }
653 ret = 1; 682 ret = 1;
654 } 683 }
655 spin_unlock_irq(&chip->reg_lock); 684 spin_unlock_irq(&chip->reg_lock);
@@ -658,7 +687,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
658 687
659static const struct snd_kcontrol_new snd_cx88_dac_switch = { 688static const struct snd_kcontrol_new snd_cx88_dac_switch = {
660 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 689 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
661 .name = "Playback Switch", 690 .name = "Audio-Out Switch",
662 .info = snd_ctl_boolean_mono_info, 691 .info = snd_ctl_boolean_mono_info,
663 .get = snd_cx88_switch_get, 692 .get = snd_cx88_switch_get,
664 .put = snd_cx88_switch_put, 693 .put = snd_cx88_switch_put,
@@ -667,13 +696,49 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {
667 696
668static const struct snd_kcontrol_new snd_cx88_source_switch = { 697static const struct snd_kcontrol_new snd_cx88_source_switch = {
669 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 698 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
670 .name = "Capture Switch", 699 .name = "Analog-TV Switch",
671 .info = snd_ctl_boolean_mono_info, 700 .info = snd_ctl_boolean_mono_info,
672 .get = snd_cx88_switch_get, 701 .get = snd_cx88_switch_get,
673 .put = snd_cx88_switch_put, 702 .put = snd_cx88_switch_put,
674 .private_value = (1<<6), 703 .private_value = (1<<6),
675}; 704};
676 705
706static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,
707 struct snd_ctl_elem_value *value)
708{
709 snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
710 struct cx88_core *core = chip->core;
711 struct v4l2_control client_ctl;
712
713 client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
714 call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl);
715 value->value.integer.value[0] = client_ctl.value ? 1 : 0;
716
717 return 0;
718}
719
720static int snd_cx88_alc_put(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 client_ctl.value = 0 != value->value.integer.value[0];
728 client_ctl.id = V4L2_CID_AUDIO_LOUDNESS;
729 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
730
731 return 0;
732}
733
734static struct snd_kcontrol_new snd_cx88_alc_switch = {
735 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
736 .name = "Line-In ALC Switch",
737 .info = snd_ctl_boolean_mono_info,
738 .get = snd_cx88_alc_get,
739 .put = snd_cx88_alc_put,
740};
741
677/**************************************************************************** 742/****************************************************************************
678 Basic Flow for Sound Devices 743 Basic Flow for Sound Devices
679 ****************************************************************************/ 744 ****************************************************************************/
@@ -795,6 +860,7 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
795{ 860{
796 struct snd_card *card; 861 struct snd_card *card;
797 snd_cx88_card_t *chip; 862 snd_cx88_card_t *chip;
863 struct v4l2_subdev *sd;
798 int err; 864 int err;
799 865
800 if (devno >= SNDRV_CARDS) 866 if (devno >= SNDRV_CARDS)
@@ -830,6 +896,15 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,
830 if (err < 0) 896 if (err < 0)
831 goto error; 897 goto error;
832 898
899 /* If there's a wm8775 then add a Line-In ALC switch */
900 list_for_each_entry(sd, &chip->core->v4l2_dev.subdevs, list) {
901 if (WM8775_GID == sd->grp_id) {
902 snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch,
903 chip));
904 break;
905 }
906 }
907
833 strcpy (card->driver, "CX88x"); 908 strcpy (card->driver, "CX88x");
834 sprintf(card->shortname, "Conexant CX%x", pci->device); 909 sprintf(card->shortname, "Conexant CX%x", pci->device);
835 sprintf(card->longname, "%s at %#llx", 910 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 7bfe330a816..b26fcba8600 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -970,15 +970,22 @@ 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 .input = {{ 974 .input = {{
974 .type = CX88_VMUX_DVB, 975 .type = CX88_VMUX_DVB,
975 .vmux = 0, 976 .vmux = 0,
977 /* 2: Line-In */
978 .audioroute = 2,
976 },{ 979 },{
977 .type = CX88_VMUX_COMPOSITE1, 980 .type = CX88_VMUX_COMPOSITE1,
978 .vmux = 1, 981 .vmux = 1,
982 /* 2: Line-In */
983 .audioroute = 2,
979 },{ 984 },{
980 .type = CX88_VMUX_SVIDEO, 985 .type = CX88_VMUX_SVIDEO,
981 .vmux = 2, 986 .vmux = 2,
987 /* 2: Line-In */
988 .audioroute = 2,
982 }}, 989 }},
983 .mpeg = CX88_MPEG_DVB, 990 .mpeg = CX88_MPEG_DVB,
984 }, 991 },
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index e3cff585215..d2f159daa8b 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -41,6 +41,7 @@
41#include "cx88.h" 41#include "cx88.h"
42#include <media/v4l2-common.h> 42#include <media/v4l2-common.h>
43#include <media/v4l2-ioctl.h> 43#include <media/v4l2-ioctl.h>
44#include <media/wm8775.h>
44 45
45MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); 46MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards");
46MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); 47MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -977,6 +978,7 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
977 const struct cx88_ctrl *c = NULL; 978 const struct cx88_ctrl *c = NULL;
978 u32 value,mask; 979 u32 value,mask;
979 int i; 980 int i;
981 struct v4l2_control client_ctl;
980 982
981 for (i = 0; i < CX8800_CTLS; i++) { 983 for (i = 0; i < CX8800_CTLS; i++) {
982 if (cx8800_ctls[i].v.id == ctl->id) { 984 if (cx8800_ctls[i].v.id == ctl->id) {
@@ -990,6 +992,27 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
990 ctl->value = c->v.minimum; 992 ctl->value = c->v.minimum;
991 if (ctl->value > c->v.maximum) 993 if (ctl->value > c->v.maximum)
992 ctl->value = c->v.maximum; 994 ctl->value = c->v.maximum;
995
996 /* Pass changes onto any WM8775 */
997 client_ctl.id = ctl->id;
998 switch (ctl->id) {
999 case V4L2_CID_AUDIO_MUTE:
1000 client_ctl.value = ctl->value;
1001 break;
1002 case V4L2_CID_AUDIO_VOLUME:
1003 client_ctl.value = (ctl->value) ?
1004 (0x90 + ctl->value) << 8 : 0;
1005 break;
1006 case V4L2_CID_AUDIO_BALANCE:
1007 client_ctl.value = ctl->value << 9;
1008 break;
1009 default:
1010 client_ctl.id = 0;
1011 break;
1012 }
1013 if (client_ctl.id)
1014 call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl);
1015
993 mask=c->mask; 1016 mask=c->mask;
994 switch (ctl->id) { 1017 switch (ctl->id) {
995 case V4L2_CID_AUDIO_BALANCE: 1018 case V4L2_CID_AUDIO_BALANCE:
@@ -1536,7 +1559,9 @@ static int radio_queryctrl (struct file *file, void *priv,
1536 if (c->id < V4L2_CID_BASE || 1559 if (c->id < V4L2_CID_BASE ||
1537 c->id >= V4L2_CID_LASTP1) 1560 c->id >= V4L2_CID_LASTP1)
1538 return -EINVAL; 1561 return -EINVAL;
1539 if (c->id == V4L2_CID_AUDIO_MUTE) { 1562 if (c->id == V4L2_CID_AUDIO_MUTE ||
1563 c->id == V4L2_CID_AUDIO_VOLUME ||
1564 c->id == V4L2_CID_AUDIO_BALANCE) {
1540 for (i = 0; i < CX8800_CTLS; i++) { 1565 for (i = 0; i < CX8800_CTLS; i++) {
1541 if (cx8800_ctls[i].v.id == c->id) 1566 if (cx8800_ctls[i].v.id == c->id)
1542 break; 1567 break;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index c9981e77416..e8c732e7ae4 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -398,17 +398,19 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
398 return container_of(v4l2_dev, struct cx88_core, v4l2_dev); 398 return container_of(v4l2_dev, struct cx88_core, v4l2_dev);
399} 399}
400 400
401#define call_all(core, o, f, args...) \ 401#define call_hw(core, grpid, o, f, args...) \
402 do { \ 402 do { \
403 if (!core->i2c_rc) { \ 403 if (!core->i2c_rc) { \
404 if (core->gate_ctrl) \ 404 if (core->gate_ctrl) \
405 core->gate_ctrl(core, 1); \ 405 core->gate_ctrl(core, 1); \
406 v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ 406 v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \
407 if (core->gate_ctrl) \ 407 if (core->gate_ctrl) \
408 core->gate_ctrl(core, 0); \ 408 core->gate_ctrl(core, 0); \
409 } \ 409 } \
410 } while (0) 410 } while (0)
411 411
412#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args)
413
412struct cx8800_dev; 414struct cx8800_dev;
413struct cx8802_dev; 415struct cx8802_dev;
414 416
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index fe8ef6419f8..13552564908 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,7 @@ 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;
206 230
207 /* Check if the adapter supports the needed features */ 231 /* Check if the adapter supports the needed features */
208 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 232 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
@@ -216,15 +240,21 @@ static int wm8775_probe(struct i2c_client *client,
216 return -ENOMEM; 240 return -ENOMEM;
217 sd = &state->sd; 241 sd = &state->sd;
218 v4l2_i2c_subdev_init(sd, client, &wm8775_ops); 242 v4l2_i2c_subdev_init(sd, client, &wm8775_ops);
243 sd->grp_id = WM8775_GID; /* subdev group id */
219 state->input = 2; 244 state->input = 2;
220 245
221 v4l2_ctrl_handler_init(&state->hdl, 1); 246 v4l2_ctrl_handler_init(&state->hdl, 4);
222 state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops, 247 state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
223 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); 248 V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
249 state->vol = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
250 V4L2_CID_AUDIO_VOLUME, 0, 65535, (65535+99)/100, 0xCF00); /* 0dB*/
251 state->bal = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
252 V4L2_CID_AUDIO_BALANCE, 0, 65535, (65535+99)/100, 32768);
253 state->loud = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
254 V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 1);
224 sd->ctrl_handler = &state->hdl; 255 sd->ctrl_handler = &state->hdl;
225 if (state->hdl.error) { 256 err = state->hdl.error;
226 int err = state->hdl.error; 257 if (err) {
227
228 v4l2_ctrl_handler_free(&state->hdl); 258 v4l2_ctrl_handler_free(&state->hdl);
229 kfree(state); 259 kfree(state);
230 return err; 260 return err;
@@ -236,29 +266,25 @@ static int wm8775_probe(struct i2c_client *client,
236 wm8775_write(sd, R23, 0x000); 266 wm8775_write(sd, R23, 0x000);
237 /* Disable zero cross detect timeout */ 267 /* Disable zero cross detect timeout */
238 wm8775_write(sd, R7, 0x000); 268 wm8775_write(sd, R7, 0x000);
239 /* Left justified, 24-bit mode */ 269 /* HPF enable, I2S mode, 24-bit */
240 wm8775_write(sd, R11, 0x021); 270 wm8775_write(sd, R11, 0x022);
241 /* Master mode, clock ratio 256fs */ 271 /* Master mode, clock ratio 256fs */
242 wm8775_write(sd, R12, 0x102); 272 wm8775_write(sd, R12, 0x102);
243 /* Powered up */ 273 /* Powered up */
244 wm8775_write(sd, R13, 0x000); 274 wm8775_write(sd, R13, 0x000);
245 /* ADC gain +2.5dB, enable zero cross */ 275 /* ALC stereo, ALC target level -5dB FS, ALC max gain +8dB */
246 wm8775_write(sd, R14, 0x1d4); 276 wm8775_write(sd, R16, 0x1bb);
247 /* ADC gain +2.5dB, enable zero cross */ 277 /* Set ALC mode and hold time */
248 wm8775_write(sd, R15, 0x1d4); 278 wm8775_write(sd, R17, (state->loud->val ? ALC_EN : 0) | ALC_HOLD);
249 /* ALC Stereo, ALC target level -1dB FS max gain +8dB */
250 wm8775_write(sd, R16, 0x1bf);
251 /* Enable gain control, use zero cross detection,
252 ALC hold time 42.6 ms */
253 wm8775_write(sd, R17, 0x185);
254 /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */ 279 /* ALC gain ramp up delay 34 s, ALC gain ramp down delay 33 ms */
255 wm8775_write(sd, R18, 0x0a2); 280 wm8775_write(sd, R18, 0x0a2);
256 /* Enable noise gate, threshold -72dBfs */ 281 /* Enable noise gate, threshold -72dBfs */
257 wm8775_write(sd, R19, 0x005); 282 wm8775_write(sd, R19, 0x005);
258 /* Transient window 4ms, lower PGA gain limit -1dB */ 283 /* Transient window 4ms, ALC min gain -5dB */
259 wm8775_write(sd, R20, 0x07a); 284 wm8775_write(sd, R20, 0x0fb);
260 /* LRBOTH = 1, use input 2. */ 285
261 wm8775_write(sd, R21, 0x102); 286 wm8775_set_audio(sd, 1); /* set volume/mute/mux */
287
262 return 0; 288 return 0;
263} 289}
264 290
diff --git a/include/media/wm8775.h b/include/media/wm8775.h
index 60739c5a23a..a1c4d417dfa 100644
--- a/include/media/wm8775.h
+++ b/include/media/wm8775.h
@@ -32,4 +32,7 @@
32#define WM8775_AIN3 4 32#define WM8775_AIN3 4
33#define WM8775_AIN4 8 33#define WM8775_AIN4 8
34 34
35/* subdev group ID */
36#define WM8775_GID (1 << 0)
37
35#endif 38#endif