Nova-S-Plus audio line input
PATCH v3 1/1 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.
This revision provides compatibility with the current 2.6.37 staging codebase.
Signed-off-by Lawrence Rust <[email protected]>
--- drivers/media/video/cx88/cx88-alsa.c | 98 +++++++++++++++++++++++++++---- drivers/media/video/cx88/cx88-cards.c | 7 ++ drivers/media/video/cx88/cx88-video.c | 27 ++++++++- drivers/media/video/cx88/cx88.h | 6 +- drivers/media/video/wm8775.c | 105 +++++++++++++++++++++------------ include/media/wm8775.h | 3 + 6 files changed, 192 insertions(+), 54 deletions(-)
drivers/media/video/cx88/cx88-alsa.c +86 -12
@@ -40,6 +40,7 @@#include <sound/control.h> #include <sound/initval.h> #include <sound/tlv.h> +#include <media/wm8775.h> #include "cx88.h" #include "cx88-reg.h"
@@ -586,26 +587,47 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,int left, right, v, b;int changed =0 ;u32 old; +struct v4l2_control client_ctl; + +/* Pass volume & balance onto any WM8775 */ +if ( value->value.integer.value[0 ] >= value->value.integer.value[1 ]) { + v = value->value.integer.value[0 ] <<10 ; + b = value->value.integer.value[0 ] ? + (0x8000 * value->value.integer.value[1 ]) / value->value.integer.value[0 ] : +0x8000 ; + }else { + v = value->value.integer.value[1 ] <<10 ; + b = value->value.integer.value[1 ] ? +0xffff - (0x8000 * value->value.integer.value[0 ]) / value->value.integer.value[1 ] : +0x8000 ; + } + client_ctl.value = v; + client_ctl.id =V4L2_CID_AUDIO_VOLUME ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + + client_ctl.value = b; + client_ctl.id =V4L2_CID_AUDIO_BALANCE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); left = value->value.integer.value[0 ] &0x3f ; right = value->value.integer.value[1 ] &0x3f ; b = right - left;if (b <0 ) { - v =0x3f - left; - b = (-b) |0x40 ; + v =0x3f - left; + b = (-b) |0x40 ; }else { - v =0x3f - right; + v =0x3f - right; }/* Do we really know this will always be called with IRQs on? */ spin_lock_irq (&chip->reg_lock); old =cx_read (AUD_VOL_CTL );if (v != (old &0x3f )) { -cx_write (AUD_VOL_CTL , (old & ~0x3f ) | v); - changed =1 ; +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , (old & ~0x3f ) | v); + changed =1 ; } -if (cx_read (AUD_BAL_CTL ) != b) { -cx_write (AUD_BAL_CTL , b); - changed =1 ; +if ((cx_read (AUD_BAL_CTL ) &0x7f ) != b) { +cx_write (AUD_BAL_CTL , b); + changed =1 ; }spin_unlock_irq (&chip->reg_lock);
@@ -618,7 +640,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access =SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .name = "Playback Volume", + .name = "Analog-TV Volume", .info = snd_cx88_volume_info, .get = snd_cx88_volume_get, .put = snd_cx88_volume_put,
@@ -649,7 +671,14 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, vol =cx_read (AUD_VOL_CTL );if (value->value.integer.value[0 ] != !(vol & bit)) { vol ^= bit; -cx_write (AUD_VOL_CTL , vol); +cx_swrite (SHADOW_AUD_VOL_CTL ,AUD_VOL_CTL , vol); +/* Pass mute onto any WM8775 */ +if ( (1 <<6 ) == bit) { +struct v4l2_control client_ctl; + client_ctl.value =0 != (vol & bit); + client_ctl.id =V4L2_CID_AUDIO_MUTE ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + } ret =1 ; }spin_unlock_irq (&chip->reg_lock);
@@ -658,7 +687,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,static const struct snd_kcontrol_new snd_cx88_dac_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Playback Switch" , + .name ="Audio-Out Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put,
@@ -667,13 +696,49 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = {static const struct snd_kcontrol_new snd_cx88_source_switch = { .iface =SNDRV_CTL_ELEM_IFACE_MIXER , - .name ="Capture Switch" , + .name ="Analog-TV Switch" , .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, .private_value = (1 <<6 ), }; +static int snd_cx88_alc_get (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, g_ctrl, &client_ctl); + value->value.integer.value[0 ] = client_ctl.value ?1 :0 ; + +return 0 ; +} + +static int snd_cx88_alc_put (struct snd_kcontrol *kcontrol, +struct snd_ctl_elem_value *value) +{ +snd_cx88_card_t *chip =snd_kcontrol_chip (kcontrol); +struct cx88_core *core = chip->core; +struct v4l2_control client_ctl; + + client_ctl.value =0 != value->value.integer.value[0 ]; + client_ctl.id =V4L2_CID_AUDIO_LOUDNESS ; +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + +return 0 ; +} + +static struct snd_kcontrol_new snd_cx88_alc_switch = { + .iface =SNDRV_CTL_ELEM_IFACE_MIXER , + .name ="Line-In ALC Switch" , + .info = snd_ctl_boolean_mono_info, + .get = snd_cx88_alc_get, + .put = snd_cx88_alc_put, +}; +/**************************************************************************** Basic Flow for Sound Devices ****************************************************************************/
@@ -830,6 +895,15 @@ static int __devinit cx88_audio_initdev(struct pci_dev *pci,if (err <0 ) goto error; +/* If there's a wm8775 then add a Line-In ALC switch */ + {struct v4l2_subdev *sd; +list_for_each_entry (sd, &chip->core->v4l2_dev.subdevs, list) { +if (WM8775_GID == sd->grp_id) { +snd_ctl_add (card,snd_ctl_new1 (&snd_cx88_alc_switch, chip)); +break ; + } + }} +strcpy (card->driver,"CX88x" );sprintf (card->shortname,"Conexant CX%x" , pci->device); sprintf(card->longname, "%s at %#llx",
drivers/media/video/cx88/cx88-cards.c +7 -0
@@ -970,15 +970,22 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, + .audio_chip = V4L2_IDENT_WM8775, .input = {{ .type = CX88_VMUX_DVB, .vmux = 0, + /* 2: Line-In */ + .audioroute = 2, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, + /* 2: Line-In */ + .audioroute = 2, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, + /* 2: Line-In */ + .audioroute = 2, }}, .mpeg = CX88_MPEG_DVB, },
drivers/media/video/cx88/cx88-video.c +26 -1
@@ -41,6 +41,7 @@#include "cx88.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/wm8775.h> MODULE_DESCRIPTION ("v4l2 driver module for cx2388x based TV cards" );MODULE_AUTHOR ("Gerd Knorr <[email protected]> [SuSE Labs]" );
@@ -978,6 +979,7 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)const struct cx88_ctrl *c =NULL ;u32 value,mask;int i; +struct v4l2_control client_ctl;for (i =0 ; i <CX8800_CTLS ; i++) {if (cx8800_ctls[i].v.id == ctl->id) {
@@ -991,6 +993,27 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) ctl->value = c->v.minimum;if (ctl->value > c->v.maximum) ctl->value = c->v.maximum; + +/* Pass changes onto any WM8775 */ + client_ctl.id = ctl->id; +switch (ctl->id) { +case V4L2_CID_AUDIO_MUTE : + client_ctl.value = ctl->value; +break ; +case V4L2_CID_AUDIO_VOLUME : + client_ctl.value = (ctl->value) ? + (0x90 + ctl->value) <<8 :0 ; +break ; +case V4L2_CID_AUDIO_BALANCE : + client_ctl.value = ctl->value <<9 ; +break ; +default : + client_ctl.id =0 ; +break ; + } +if (client_ctl.id) +call_hw (core,WM8775_GID , core, s_ctrl, &client_ctl); + mask=c->mask;switch (ctl->id) {case V4L2_CID_AUDIO_BALANCE :
@@ -1537,7 +1560,9 @@ static int radio_queryctrl (struct file *file, void *priv,if (c->id <V4L2_CID_BASE || c->id >=V4L2_CID_LASTP1 )return -EINVAL ; -if (c->id ==V4L2_CID_AUDIO_MUTE ) { +if (c->id ==V4L2_CID_AUDIO_MUTE || + c->id ==V4L2_CID_AUDIO_VOLUME || + c->id ==V4L2_CID_AUDIO_BALANCE ) {for (i =0 ; i <CX8800_CTLS ; i++) {if (cx8800_ctls[i].v.id == c->id)break ;
drivers/media/video/cx88/cx88.h +4 -2
@@ -398,17 +398,19 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define call_all(core, o, f, args...) \ +#define call_hw(core, grpid, o, f, args...) \ do { \ if (!core->i2c_rc) { \ if (core->gate_ctrl) \ core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, 0, o, f, ##args); \ + v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ if (core->gate_ctrl) \ core->gate_ctrl(core, 0); \ } \ } while (0) +#define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) +struct cx8800_dev ;struct cx8802_dev ;
drivers/media/video/wm8775.c +66 -39
182 lines not on this page · raw message
include/media/wm8775.h +3 -0
@@ -32,4 +32,7 @@#define WM8775_AIN3 4#define WM8775_AIN4 8 +/* subdev group ID */ +#define WM8775_GID (1 << 0) +#endif
Signature · 1 line
1.7.0.4