2006-11-14 14:13:39 +03:00
/*
* HD audio interface patch for Conexant HDA audio codec
*
* Copyright ( c ) 2006 Pototskiy Akex < alex . pototskiy @ gmail . com >
* Takashi Iwai < tiwai @ suse . de >
* Tobin Davis < tdavis @ dsl - only . net >
*
* This driver is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This driver is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/pci.h>
# include <sound/core.h>
# include "hda_codec.h"
# include "hda_local.h"
# define CXT_PIN_DIR_IN 0x00
# define CXT_PIN_DIR_OUT 0x01
# define CXT_PIN_DIR_INOUT 0x02
# define CXT_PIN_DIR_IN_NOMICBIAS 0x03
# define CXT_PIN_DIR_INOUT_NOMICBIAS 0x04
# define CONEXANT_HP_EVENT 0x37
# define CONEXANT_MIC_EVENT 0x38
struct conexant_spec {
struct snd_kcontrol_new * mixers [ 5 ] ;
int num_mixers ;
const struct hda_verb * init_verbs [ 5 ] ; /* initialization verbs
* don ' t forget NULL
* termination !
*/
unsigned int num_init_verbs ;
/* playback */
struct hda_multi_out multiout ; /* playback set-up
* max_channels , dacs must be set
* dig_out_nid and hp_nid are optional
*/
unsigned int cur_eapd ;
2007-02-13 14:45:44 +03:00
unsigned int hp_present ;
2006-11-14 14:13:39 +03:00
unsigned int need_dac_fix ;
/* capture */
unsigned int num_adc_nids ;
hda_nid_t * adc_nids ;
hda_nid_t dig_in_nid ; /* digital-in NID; optional */
/* capture source */
const struct hda_input_mux * input_mux ;
hda_nid_t * capsrc_nids ;
unsigned int cur_mux [ 3 ] ;
/* channel model */
const struct hda_channel_mode * channel_mode ;
int num_channel_mode ;
/* PCM information */
struct hda_pcm pcm_rec [ 2 ] ; /* used in build_pcms() */
struct mutex amp_mutex ; /* PCM volume/mute control mutex */
unsigned int spdif_route ;
/* dynamic controls, init_verbs and input_mux */
struct auto_pin_cfg autocfg ;
unsigned int num_kctl_alloc , num_kctl_used ;
struct snd_kcontrol_new * kctl_alloc ;
struct hda_input_mux private_imux ;
2007-10-22 19:20:10 +04:00
hda_nid_t private_dac_nids [ AUTO_CFG_MAX_OUTS ] ;
2006-11-14 14:13:39 +03:00
} ;
static int conexant_playback_pcm_open ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
struct snd_pcm_substream * substream )
{
struct conexant_spec * spec = codec - > spec ;
return snd_hda_multi_out_analog_open ( codec , & spec - > multiout , substream ) ;
}
static int conexant_playback_pcm_prepare ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
unsigned int stream_tag ,
unsigned int format ,
struct snd_pcm_substream * substream )
{
struct conexant_spec * spec = codec - > spec ;
return snd_hda_multi_out_analog_prepare ( codec , & spec - > multiout ,
stream_tag ,
format , substream ) ;
}
static int conexant_playback_pcm_cleanup ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
struct snd_pcm_substream * substream )
{
struct conexant_spec * spec = codec - > spec ;
return snd_hda_multi_out_analog_cleanup ( codec , & spec - > multiout ) ;
}
/*
* Digital out
*/
static int conexant_dig_playback_pcm_open ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
struct snd_pcm_substream * substream )
{
struct conexant_spec * spec = codec - > spec ;
return snd_hda_multi_out_dig_open ( codec , & spec - > multiout ) ;
}
static int conexant_dig_playback_pcm_close ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
struct snd_pcm_substream * substream )
{
struct conexant_spec * spec = codec - > spec ;
return snd_hda_multi_out_dig_close ( codec , & spec - > multiout ) ;
}
2007-04-05 16:51:48 +04:00
static int conexant_dig_playback_pcm_prepare ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
unsigned int stream_tag ,
unsigned int format ,
struct snd_pcm_substream * substream )
{
struct conexant_spec * spec = codec - > spec ;
return snd_hda_multi_out_dig_prepare ( codec , & spec - > multiout ,
stream_tag ,
format , substream ) ;
}
2006-11-14 14:13:39 +03:00
/*
* Analog capture
*/
static int conexant_capture_pcm_prepare ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
unsigned int stream_tag ,
unsigned int format ,
struct snd_pcm_substream * substream )
{
struct conexant_spec * spec = codec - > spec ;
snd_hda_codec_setup_stream ( codec , spec - > adc_nids [ substream - > number ] ,
stream_tag , 0 , format ) ;
return 0 ;
}
static int conexant_capture_pcm_cleanup ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
struct snd_pcm_substream * substream )
{
struct conexant_spec * spec = codec - > spec ;
snd_hda_codec_setup_stream ( codec , spec - > adc_nids [ substream - > number ] ,
0 , 0 , 0 ) ;
return 0 ;
}
static struct hda_pcm_stream conexant_pcm_analog_playback = {
. substreams = 1 ,
. channels_min = 2 ,
. channels_max = 2 ,
. nid = 0 , /* fill later */
. ops = {
. open = conexant_playback_pcm_open ,
. prepare = conexant_playback_pcm_prepare ,
. cleanup = conexant_playback_pcm_cleanup
} ,
} ;
static struct hda_pcm_stream conexant_pcm_analog_capture = {
. substreams = 1 ,
. channels_min = 2 ,
. channels_max = 2 ,
. nid = 0 , /* fill later */
. ops = {
. prepare = conexant_capture_pcm_prepare ,
. cleanup = conexant_capture_pcm_cleanup
} ,
} ;
static struct hda_pcm_stream conexant_pcm_digital_playback = {
. substreams = 1 ,
. channels_min = 2 ,
. channels_max = 2 ,
. nid = 0 , /* fill later */
. ops = {
. open = conexant_dig_playback_pcm_open ,
2007-04-05 16:51:48 +04:00
. close = conexant_dig_playback_pcm_close ,
. prepare = conexant_dig_playback_pcm_prepare
2006-11-14 14:13:39 +03:00
} ,
} ;
static struct hda_pcm_stream conexant_pcm_digital_capture = {
. substreams = 1 ,
. channels_min = 2 ,
. channels_max = 2 ,
/* NID is set in alc_build_pcms */
} ;
static int conexant_build_pcms ( struct hda_codec * codec )
{
struct conexant_spec * spec = codec - > spec ;
struct hda_pcm * info = spec - > pcm_rec ;
codec - > num_pcms = 1 ;
codec - > pcm_info = info ;
info - > name = " CONEXANT Analog " ;
info - > stream [ SNDRV_PCM_STREAM_PLAYBACK ] = conexant_pcm_analog_playback ;
info - > stream [ SNDRV_PCM_STREAM_PLAYBACK ] . channels_max =
spec - > multiout . max_channels ;
info - > stream [ SNDRV_PCM_STREAM_PLAYBACK ] . nid =
spec - > multiout . dac_nids [ 0 ] ;
info - > stream [ SNDRV_PCM_STREAM_CAPTURE ] = conexant_pcm_analog_capture ;
info - > stream [ SNDRV_PCM_STREAM_CAPTURE ] . substreams = spec - > num_adc_nids ;
info - > stream [ SNDRV_PCM_STREAM_CAPTURE ] . nid = spec - > adc_nids [ 0 ] ;
if ( spec - > multiout . dig_out_nid ) {
info + + ;
codec - > num_pcms + + ;
info - > name = " Conexant Digital " ;
info - > stream [ SNDRV_PCM_STREAM_PLAYBACK ] =
conexant_pcm_digital_playback ;
info - > stream [ SNDRV_PCM_STREAM_PLAYBACK ] . nid =
spec - > multiout . dig_out_nid ;
if ( spec - > dig_in_nid ) {
info - > stream [ SNDRV_PCM_STREAM_CAPTURE ] =
conexant_pcm_digital_capture ;
info - > stream [ SNDRV_PCM_STREAM_CAPTURE ] . nid =
spec - > dig_in_nid ;
}
}
return 0 ;
}
static int conexant_mux_enum_info ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
return snd_hda_input_mux_info ( spec - > input_mux , uinfo ) ;
}
static int conexant_mux_enum_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
unsigned int adc_idx = snd_ctl_get_ioffidx ( kcontrol , & ucontrol - > id ) ;
ucontrol - > value . enumerated . item [ 0 ] = spec - > cur_mux [ adc_idx ] ;
return 0 ;
}
static int conexant_mux_enum_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
unsigned int adc_idx = snd_ctl_get_ioffidx ( kcontrol , & ucontrol - > id ) ;
return snd_hda_input_mux_put ( codec , spec - > input_mux , ucontrol ,
spec - > capsrc_nids [ adc_idx ] ,
& spec - > cur_mux [ adc_idx ] ) ;
}
static int conexant_init ( struct hda_codec * codec )
{
struct conexant_spec * spec = codec - > spec ;
int i ;
for ( i = 0 ; i < spec - > num_init_verbs ; i + + )
snd_hda_sequence_write ( codec , spec - > init_verbs [ i ] ) ;
return 0 ;
}
static void conexant_free ( struct hda_codec * codec )
{
struct conexant_spec * spec = codec - > spec ;
unsigned int i ;
if ( spec - > kctl_alloc ) {
for ( i = 0 ; i < spec - > num_kctl_used ; i + + )
kfree ( spec - > kctl_alloc [ i ] . name ) ;
kfree ( spec - > kctl_alloc ) ;
}
kfree ( codec - > spec ) ;
}
static int conexant_build_controls ( struct hda_codec * codec )
{
struct conexant_spec * spec = codec - > spec ;
unsigned int i ;
int err ;
for ( i = 0 ; i < spec - > num_mixers ; i + + ) {
err = snd_hda_add_new_ctls ( codec , spec - > mixers [ i ] ) ;
if ( err < 0 )
return err ;
}
if ( spec - > multiout . dig_out_nid ) {
err = snd_hda_create_spdif_out_ctls ( codec ,
spec - > multiout . dig_out_nid ) ;
if ( err < 0 )
return err ;
}
if ( spec - > dig_in_nid ) {
err = snd_hda_create_spdif_in_ctls ( codec , spec - > dig_in_nid ) ;
if ( err < 0 )
return err ;
}
return 0 ;
}
static struct hda_codec_ops conexant_patch_ops = {
. build_controls = conexant_build_controls ,
. build_pcms = conexant_build_pcms ,
. init = conexant_init ,
. free = conexant_free ,
} ;
/*
* EAPD control
* the private value = nid | ( invert < < 8 )
*/
2007-07-23 17:42:26 +04:00
# define cxt_eapd_info snd_ctl_boolean_mono_info
2006-11-14 14:13:39 +03:00
2007-02-13 14:45:44 +03:00
static int cxt_eapd_get ( struct snd_kcontrol * kcontrol ,
2006-11-14 14:13:39 +03:00
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
int invert = ( kcontrol - > private_value > > 8 ) & 1 ;
if ( invert )
ucontrol - > value . integer . value [ 0 ] = ! spec - > cur_eapd ;
else
ucontrol - > value . integer . value [ 0 ] = spec - > cur_eapd ;
return 0 ;
2007-02-13 14:45:44 +03:00
2006-11-14 14:13:39 +03:00
}
2007-02-13 14:45:44 +03:00
static int cxt_eapd_put ( struct snd_kcontrol * kcontrol ,
2006-11-14 14:13:39 +03:00
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
int invert = ( kcontrol - > private_value > > 8 ) & 1 ;
hda_nid_t nid = kcontrol - > private_value & 0xff ;
unsigned int eapd ;
2007-02-13 14:45:44 +03:00
2007-11-15 17:54:38 +03:00
eapd = ! ! ucontrol - > value . integer . value [ 0 ] ;
2006-11-14 14:13:39 +03:00
if ( invert )
eapd = ! eapd ;
2007-08-10 19:09:26 +04:00
if ( eapd = = spec - > cur_eapd )
2006-11-14 14:13:39 +03:00
return 0 ;
2007-02-13 14:45:44 +03:00
2006-11-14 14:13:39 +03:00
spec - > cur_eapd = eapd ;
2007-08-10 19:09:26 +04:00
snd_hda_codec_write_cache ( codec , nid ,
0 , AC_VERB_SET_EAPD_BTLENABLE ,
eapd ? 0x02 : 0x00 ) ;
2006-11-14 14:13:39 +03:00
return 1 ;
}
2006-11-28 13:33:10 +03:00
/* controls for test mode */
# ifdef CONFIG_SND_DEBUG
2007-02-13 14:45:44 +03:00
# define CXT_EAPD_SWITCH(xname, nid, mask) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , . index = 0 , \
. info = cxt_eapd_info , \
. get = cxt_eapd_get , \
. put = cxt_eapd_put , \
. private_value = nid | ( mask < < 16 ) }
2006-11-14 14:13:39 +03:00
static int conexant_ch_mode_info ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
return snd_hda_ch_mode_info ( codec , uinfo , spec - > channel_mode ,
spec - > num_channel_mode ) ;
}
static int conexant_ch_mode_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
return snd_hda_ch_mode_get ( codec , ucontrol , spec - > channel_mode ,
spec - > num_channel_mode ,
spec - > multiout . max_channels ) ;
}
static int conexant_ch_mode_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
int err = snd_hda_ch_mode_put ( codec , ucontrol , spec - > channel_mode ,
spec - > num_channel_mode ,
& spec - > multiout . max_channels ) ;
if ( err > = 0 & & spec - > need_dac_fix )
spec - > multiout . num_dacs = spec - > multiout . max_channels / 2 ;
return err ;
}
# define CXT_PIN_MODE(xname, nid, dir) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , . name = xname , . index = 0 , \
. info = conexant_ch_mode_info , \
. get = conexant_ch_mode_get , \
. put = conexant_ch_mode_put , \
. private_value = nid | ( dir < < 16 ) }
2006-11-28 13:33:10 +03:00
# endif /* CONFIG_SND_DEBUG */
2006-11-14 14:13:39 +03:00
/* Conexant 5045 specific */
static hda_nid_t cxt5045_dac_nids [ 1 ] = { 0x19 } ;
static hda_nid_t cxt5045_adc_nids [ 1 ] = { 0x1a } ;
static hda_nid_t cxt5045_capsrc_nids [ 1 ] = { 0x1a } ;
# define CXT5045_SPDIF_OUT 0x13
2006-11-20 19:42:09 +03:00
static struct hda_channel_mode cxt5045_modes [ 1 ] = {
{ 2 , NULL } ,
} ;
2006-11-14 14:13:39 +03:00
static struct hda_input_mux cxt5045_capture_source = {
. num_items = 2 ,
. items = {
2007-02-13 14:45:44 +03:00
{ " IntMic " , 0x1 } ,
[ALSA] hda-codec - Fix capture source for Cx5045 codec
For codec conexant 5045, I found that the name of 'Capture Source Items'
is different from the name of mixer.
The mixer is:
HDA_CODEC_VOLUME('Ext Mic Playback Volume', 0x17, 0x2, HDA_INPUT),
HDA_CODEC_MUTE('Ext Mic Playback Switch', 0x17, 0x2, HDA_INPUT),
But the capture source item is :
static struct hda_input_mux cxt5045_capture_source = {
.num_items = 2,
.items = {
{ 'IntMic', 0x1 },
{ 'LineIn', 0x2 },
}
};
I think that it's better to change the name of capture_source to avoid
misunderstanding.
Signed-off-by: Jiang zhe <zhe.jiang@intel.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
2008-01-17 13:19:26 +03:00
{ " ExtMic " , 0x2 } ,
2006-11-14 14:13:39 +03:00
}
} ;
2008-01-17 13:18:41 +03:00
static struct hda_input_mux cxt5045_capture_source_benq = {
. num_items = 3 ,
. items = {
{ " IntMic " , 0x1 } ,
{ " ExtMic " , 0x2 } ,
{ " LineIn " , 0x3 } ,
}
} ;
2006-11-14 14:13:39 +03:00
/* turn on/off EAPD (+ mute HP) as a master switch */
static int cxt5045_hp_master_sw_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
2007-02-13 14:45:44 +03:00
unsigned int bits ;
2006-11-14 14:13:39 +03:00
2007-02-13 14:45:44 +03:00
if ( ! cxt_eapd_put ( kcontrol , ucontrol ) )
2006-11-14 14:13:39 +03:00
return 0 ;
2007-02-13 14:45:44 +03:00
/* toggle internal speakers mute depending of presence of
* the headphone jack
*/
2007-08-10 19:11:07 +04:00
bits = ( ! spec - > hp_present & & spec - > cur_eapd ) ? 0 : HDA_AMP_MUTE ;
snd_hda_codec_amp_stereo ( codec , 0x10 , HDA_OUTPUT , 0 ,
HDA_AMP_MUTE , bits ) ;
2007-03-12 13:39:01 +03:00
2007-08-10 19:11:07 +04:00
bits = spec - > cur_eapd ? 0 : HDA_AMP_MUTE ;
snd_hda_codec_amp_stereo ( codec , 0x11 , HDA_OUTPUT , 0 ,
HDA_AMP_MUTE , bits ) ;
2006-11-14 14:13:39 +03:00
return 1 ;
}
/* bind volumes of both NID 0x10 and 0x11 */
2007-08-10 19:12:15 +04:00
static struct hda_bind_ctls cxt5045_hp_bind_master_vol = {
. ops = & snd_hda_bind_vol ,
. values = {
HDA_COMPOSE_AMP_VAL ( 0x10 , 3 , 0 , HDA_OUTPUT ) ,
HDA_COMPOSE_AMP_VAL ( 0x11 , 3 , 0 , HDA_OUTPUT ) ,
0
} ,
} ;
2006-11-14 14:13:39 +03:00
2007-03-12 13:39:01 +03:00
/* toggle input of built-in and mic jack appropriately */
static void cxt5045_hp_automic ( struct hda_codec * codec )
{
static struct hda_verb mic_jack_on [ ] = {
{ 0x14 , AC_VERB_SET_AMP_GAIN_MUTE , 0xb080 } ,
{ 0x12 , AC_VERB_SET_AMP_GAIN_MUTE , 0xb000 } ,
{ }
} ;
static struct hda_verb mic_jack_off [ ] = {
{ 0x12 , AC_VERB_SET_AMP_GAIN_MUTE , 0xb080 } ,
{ 0x14 , AC_VERB_SET_AMP_GAIN_MUTE , 0xb000 } ,
{ }
} ;
unsigned int present ;
present = snd_hda_codec_read ( codec , 0x12 , 0 ,
AC_VERB_GET_PIN_SENSE , 0 ) & 0x80000000 ;
if ( present )
snd_hda_sequence_write ( codec , mic_jack_on ) ;
else
snd_hda_sequence_write ( codec , mic_jack_off ) ;
}
2006-11-14 14:13:39 +03:00
/* mute internal speaker if HP is plugged */
static void cxt5045_hp_automute ( struct hda_codec * codec )
{
2007-02-13 14:45:44 +03:00
struct conexant_spec * spec = codec - > spec ;
2007-02-26 18:07:42 +03:00
unsigned int bits ;
2006-11-14 14:13:39 +03:00
2007-02-13 14:45:44 +03:00
spec - > hp_present = snd_hda_codec_read ( codec , 0x11 , 0 ,
2006-11-14 14:13:39 +03:00
AC_VERB_GET_PIN_SENSE , 0 ) & 0x80000000 ;
2007-02-26 18:07:42 +03:00
2007-08-10 19:11:07 +04:00
bits = ( spec - > hp_present | | ! spec - > cur_eapd ) ? HDA_AMP_MUTE : 0 ;
snd_hda_codec_amp_stereo ( codec , 0x10 , HDA_OUTPUT , 0 ,
HDA_AMP_MUTE , bits ) ;
2006-11-14 14:13:39 +03:00
}
/* unsolicited event for HP jack sensing */
static void cxt5045_hp_unsol_event ( struct hda_codec * codec ,
unsigned int res )
{
res > > = 26 ;
switch ( res ) {
case CONEXANT_HP_EVENT :
cxt5045_hp_automute ( codec ) ;
break ;
2007-03-12 13:39:01 +03:00
case CONEXANT_MIC_EVENT :
cxt5045_hp_automic ( codec ) ;
break ;
2006-11-14 14:13:39 +03:00
}
}
static struct snd_kcontrol_new cxt5045_mixers [ ] = {
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Capture Source " ,
. info = conexant_mux_enum_info ,
. get = conexant_mux_enum_get ,
. put = conexant_mux_enum_put
} ,
2007-10-19 10:06:21 +04:00
HDA_CODEC_VOLUME ( " Int Mic Capture Volume " , 0x1a , 0x01 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Int Mic Capture Switch " , 0x1a , 0x01 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Ext Mic Capture Volume " , 0x1a , 0x02 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Ext Mic Capture Switch " , 0x1a , 0x02 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " PCM Playback Volume " , 0x17 , 0x0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " PCM Playback Switch " , 0x17 , 0x0 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Int Mic Playback Volume " , 0x17 , 0x1 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Int Mic Playback Switch " , 0x17 , 0x1 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Ext Mic Playback Volume " , 0x17 , 0x2 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Ext Mic Playback Switch " , 0x17 , 0x2 , HDA_INPUT ) ,
2007-08-10 19:12:15 +04:00
HDA_BIND_VOL ( " Master Playback Volume " , & cxt5045_hp_bind_master_vol ) ,
2006-11-14 14:13:39 +03:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Master Playback Switch " ,
2007-02-13 14:45:44 +03:00
. info = cxt_eapd_info ,
. get = cxt_eapd_get ,
2006-11-14 14:13:39 +03:00
. put = cxt5045_hp_master_sw_put ,
2007-02-13 14:45:44 +03:00
. private_value = 0x10 ,
2006-11-14 14:13:39 +03:00
} ,
{ }
} ;
2008-01-17 13:18:41 +03:00
static struct snd_kcontrol_new cxt5045_benq_mixers [ ] = {
HDA_CODEC_VOLUME ( " Line In Capture Volume " , 0x1a , 0x03 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Line In Capture Switch " , 0x1a , 0x03 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Line In Playback Volume " , 0x17 , 0x3 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Line In Playback Switch " , 0x17 , 0x3 , HDA_INPUT ) ,
{ }
} ;
2006-11-14 14:13:39 +03:00
static struct hda_verb cxt5045_init_verbs [ ] = {
/* Line in, Mic */
{ 0x12 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN } ,
2007-03-12 13:39:01 +03:00
{ 0x14 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN | AC_PINCTL_VREF_80 } ,
2006-11-14 14:13:39 +03:00
/* HP, Amp */
2007-10-19 10:06:21 +04:00
{ 0x10 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_OUT } ,
{ 0x10 , AC_VERB_SET_CONNECT_SEL , 0x1 } ,
{ 0x11 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_HP } ,
{ 0x11 , AC_VERB_SET_CONNECT_SEL , 0x1 } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 1 ) } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 2 ) } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 3 ) } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 4 ) } ,
2007-02-13 14:45:44 +03:00
/* Record selector: Int mic */
2007-03-12 13:39:01 +03:00
{ 0x1a , AC_VERB_SET_CONNECT_SEL , 0x1 } ,
2007-02-13 14:45:44 +03:00
{ 0x1a , AC_VERB_SET_AMP_GAIN_MUTE ,
2006-11-14 14:13:39 +03:00
AC_AMP_SET_INPUT | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | 0x17 } ,
/* SPDIF route: PCM */
{ 0x13 , AC_VERB_SET_CONNECT_SEL , 0x0 } ,
/* EAPD */
2007-02-13 14:45:44 +03:00
{ 0x10 , AC_VERB_SET_EAPD_BTLENABLE , 0x2 } , /* default on */
2006-11-14 14:13:39 +03:00
{ } /* end */
} ;
2008-01-17 13:18:41 +03:00
static struct hda_verb cxt5045_benq_init_verbs [ ] = {
/* Int Mic, Mic */
{ 0x12 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN | AC_PINCTL_VREF_80 } ,
{ 0x14 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN | AC_PINCTL_VREF_80 } ,
/* Line In,HP, Amp */
{ 0x10 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_OUT } ,
{ 0x10 , AC_VERB_SET_CONNECT_SEL , 0x1 } ,
{ 0x11 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN } ,
{ 0x11 , AC_VERB_SET_CONNECT_SEL , 0x1 } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 1 ) } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 2 ) } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 3 ) } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 4 ) } ,
/* Record selector: Int mic */
{ 0x1a , AC_VERB_SET_CONNECT_SEL , 0x1 } ,
{ 0x1a , AC_VERB_SET_AMP_GAIN_MUTE ,
AC_AMP_SET_INPUT | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | 0x17 } ,
/* SPDIF route: PCM */
{ 0x13 , AC_VERB_SET_CONNECT_SEL , 0x0 } ,
/* EAPD */
{ 0x10 , AC_VERB_SET_EAPD_BTLENABLE , 0x2 } , /* default on */
{ } /* end */
} ;
2007-03-12 13:39:01 +03:00
static struct hda_verb cxt5045_hp_sense_init_verbs [ ] = {
/* pin sensing on HP jack */
{ 0x11 , AC_VERB_SET_UNSOLICITED_ENABLE , AC_USRSP_EN | CONEXANT_HP_EVENT } ,
2007-03-28 17:11:53 +04:00
{ } /* end */
2007-03-12 13:39:01 +03:00
} ;
static struct hda_verb cxt5045_mic_sense_init_verbs [ ] = {
/* pin sensing on HP jack */
{ 0x12 , AC_VERB_SET_UNSOLICITED_ENABLE , AC_USRSP_EN | CONEXANT_MIC_EVENT } ,
2007-03-28 17:11:53 +04:00
{ } /* end */
2007-03-12 13:39:01 +03:00
} ;
2006-11-14 14:13:39 +03:00
# ifdef CONFIG_SND_DEBUG
/* Test configuration for debugging, modelled after the ALC260 test
* configuration .
*/
static struct hda_input_mux cxt5045_test_capture_source = {
. num_items = 5 ,
. items = {
{ " MIXER " , 0x0 } ,
{ " MIC1 pin " , 0x1 } ,
{ " LINE1 pin " , 0x2 } ,
{ " HP-OUT pin " , 0x3 } ,
{ " CD pin " , 0x4 } ,
} ,
} ;
static struct snd_kcontrol_new cxt5045_test_mixer [ ] = {
/* Output controls */
HDA_CODEC_VOLUME ( " Speaker Playback Volume " , 0x10 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Speaker Playback Switch " , 0x10 , 0x0 , HDA_OUTPUT ) ,
2007-03-12 13:39:01 +03:00
HDA_CODEC_VOLUME ( " Node 11 Playback Volume " , 0x11 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Node 11 Playback Switch " , 0x11 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_VOLUME ( " Node 12 Playback Volume " , 0x12 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Node 12 Playback Switch " , 0x12 , 0x0 , HDA_OUTPUT ) ,
2006-11-14 14:13:39 +03:00
/* Modes for retasking pin widgets */
CXT_PIN_MODE ( " HP-OUT pin mode " , 0x11 , CXT_PIN_DIR_INOUT ) ,
CXT_PIN_MODE ( " LINE1 pin mode " , 0x12 , CXT_PIN_DIR_INOUT ) ,
2007-02-13 14:45:44 +03:00
/* EAPD Switch Control */
CXT_EAPD_SWITCH ( " External Amplifier " , 0x10 , 0x0 ) ,
2006-11-14 14:13:39 +03:00
/* Loopback mixer controls */
2007-03-12 13:39:01 +03:00
HDA_CODEC_VOLUME ( " Mixer-1 Volume " , 0x17 , 0x0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Mixer-1 Switch " , 0x17 , 0x0 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Mixer-2 Volume " , 0x17 , 0x1 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Mixer-2 Switch " , 0x17 , 0x1 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Mixer-3 Volume " , 0x17 , 0x2 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Mixer-3 Switch " , 0x17 , 0x2 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Mixer-4 Volume " , 0x17 , 0x3 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Mixer-4 Switch " , 0x17 , 0x3 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Mixer-5 Volume " , 0x17 , 0x4 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Mixer-5 Switch " , 0x17 , 0x4 , HDA_INPUT ) ,
2006-11-14 14:13:39 +03:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Input Source " ,
. info = conexant_mux_enum_info ,
. get = conexant_mux_enum_get ,
. put = conexant_mux_enum_put ,
} ,
2007-05-17 11:40:47 +04:00
/* Audio input controls */
HDA_CODEC_VOLUME ( " Input-1 Volume " , 0x1a , 0x0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-1 Switch " , 0x1a , 0x0 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Input-2 Volume " , 0x1a , 0x1 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-2 Switch " , 0x1a , 0x1 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Input-3 Volume " , 0x1a , 0x2 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-3 Switch " , 0x1a , 0x2 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Input-4 Volume " , 0x1a , 0x3 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-4 Switch " , 0x1a , 0x3 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Input-5 Volume " , 0x1a , 0x4 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-5 Switch " , 0x1a , 0x4 , HDA_INPUT ) ,
2006-11-14 14:13:39 +03:00
{ } /* end */
} ;
static struct hda_verb cxt5045_test_init_verbs [ ] = {
2007-03-12 13:39:01 +03:00
/* Set connections */
{ 0x10 , AC_VERB_SET_CONNECT_SEL , 0x0 } ,
{ 0x11 , AC_VERB_SET_CONNECT_SEL , 0x0 } ,
{ 0x12 , AC_VERB_SET_CONNECT_SEL , 0x0 } ,
2006-11-14 14:13:39 +03:00
/* Enable retasking pins as output, initially without power amp */
{ 0x12 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_OUT } ,
2007-03-12 13:39:01 +03:00
{ 0x11 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_OUT } ,
2006-11-14 14:13:39 +03:00
/* Disable digital (SPDIF) pins initially, but users can enable
* them via a mixer switch . In the case of SPDIF - out , this initverb
* payload also sets the generation to 0 , output to be in " consumer "
* PCM format , copyright asserted , no pre - emphasis and no validity
* control .
*/
{ 0x13 , AC_VERB_SET_DIGI_CONVERT_1 , 0 } ,
/* Start with output sum widgets muted and their output gains at min */
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 1 ) } ,
/* Unmute retasking pin widget output buffers since the default
* state appears to be output . As the pin mode is changed by the
* user the pin mode control will take care of enabling the pin ' s
* input / output buffers as needed .
*/
{ 0x12 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_UNMUTE } ,
{ 0x11 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_UNMUTE } ,
/* Mute capture amp left and right */
{ 0x1a , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } ,
/* Set ADC connection select to match default mixer setting (mic1
* pin )
*/
{ 0x1a , AC_VERB_SET_CONNECT_SEL , 0x00 } ,
2007-03-12 13:39:01 +03:00
{ 0x17 , AC_VERB_SET_CONNECT_SEL , 0x00 } ,
2006-11-14 14:13:39 +03:00
/* Mute all inputs to mixer widget (even unconnected ones) */
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } , /* Mixer pin */
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 1 ) } , /* Mic1 pin */
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 2 ) } , /* Line pin */
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 3 ) } , /* HP pin */
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 4 ) } , /* CD pin */
{ }
} ;
# endif
/* initialize jack-sensing, too */
static int cxt5045_init ( struct hda_codec * codec )
{
conexant_init ( codec ) ;
cxt5045_hp_automute ( codec ) ;
return 0 ;
}
enum {
2008-01-22 17:15:59 +03:00
CXT5045_LAPTOP_HPSENSE ,
CXT5045_LAPTOP_MICSENSE ,
CXT5045_LAPTOP_HPMICSENSE ,
2008-01-17 13:18:41 +03:00
CXT5045_BENQ ,
2006-11-14 14:13:39 +03:00
# ifdef CONFIG_SND_DEBUG
CXT5045_TEST ,
# endif
2006-11-24 19:07:44 +03:00
CXT5045_MODELS
2006-11-14 14:13:39 +03:00
} ;
2006-11-24 19:07:44 +03:00
static const char * cxt5045_models [ CXT5045_MODELS ] = {
2008-01-22 17:15:59 +03:00
[ CXT5045_LAPTOP_HPSENSE ] = " laptop-hpsense " ,
[ CXT5045_LAPTOP_MICSENSE ] = " laptop-micsense " ,
[ CXT5045_LAPTOP_HPMICSENSE ] = " laptop-hpmicsense " ,
[ CXT5045_BENQ ] = " benq " ,
2006-11-14 14:13:39 +03:00
# ifdef CONFIG_SND_DEBUG
2006-11-24 19:07:44 +03:00
[ CXT5045_TEST ] = " test " ,
2006-11-14 14:13:39 +03:00
# endif
2006-11-24 19:07:44 +03:00
} ;
static struct snd_pci_quirk cxt5045_cfg_tbl [ ] = {
2008-01-22 17:15:59 +03:00
SND_PCI_QUIRK ( 0x103c , 0x30a5 , " HP " , CXT5045_LAPTOP_HPSENSE ) ,
SND_PCI_QUIRK ( 0x103c , 0x30b2 , " HP DV Series " , CXT5045_LAPTOP_HPSENSE ) ,
SND_PCI_QUIRK ( 0x103c , 0x30b5 , " HP DV2120 " , CXT5045_LAPTOP_HPSENSE ) ,
SND_PCI_QUIRK ( 0x103c , 0x30b7 , " HP DV6000Z " , CXT5045_LAPTOP_HPSENSE ) ,
SND_PCI_QUIRK ( 0x103c , 0x30bb , " HP DV8000 " , CXT5045_LAPTOP_HPSENSE ) ,
SND_PCI_QUIRK ( 0x103c , 0x30cd , " HP DV Series " , CXT5045_LAPTOP_HPSENSE ) ,
SND_PCI_QUIRK ( 0x103c , 0x30d5 , " HP 530 " , CXT5045_LAPTOP_HPSENSE ) ,
SND_PCI_QUIRK ( 0x103c , 0x30d9 , " HP Spartan " , CXT5045_LAPTOP_HPSENSE ) ,
2008-01-17 13:18:41 +03:00
SND_PCI_QUIRK ( 0x152d , 0x0753 , " Benq R55E " , CXT5045_BENQ ) ,
2008-01-22 17:15:59 +03:00
SND_PCI_QUIRK ( 0x1734 , 0x10ad , " Fujitsu Si1520 " , CXT5045_LAPTOP_MICSENSE ) ,
SND_PCI_QUIRK ( 0x1734 , 0x10cb , " Fujitsu Si3515 " , CXT5045_LAPTOP_HPMICSENSE ) ,
SND_PCI_QUIRK ( 0x1734 , 0x110e , " Fujitsu V5505 " , CXT5045_LAPTOP_HPSENSE ) ,
SND_PCI_QUIRK ( 0x1509 , 0x1e40 , " FIC " , CXT5045_LAPTOP_HPMICSENSE ) ,
SND_PCI_QUIRK ( 0x1509 , 0x2f05 , " FIC " , CXT5045_LAPTOP_HPMICSENSE ) ,
SND_PCI_QUIRK ( 0x1509 , 0x2f06 , " FIC " , CXT5045_LAPTOP_HPMICSENSE ) ,
SND_PCI_QUIRK ( 0x1631 , 0xc106 , " Packard Bell " , CXT5045_LAPTOP_HPMICSENSE ) ,
SND_PCI_QUIRK ( 0x1631 , 0xc107 , " Packard Bell " , CXT5045_LAPTOP_HPMICSENSE ) ,
SND_PCI_QUIRK ( 0x8086 , 0x2111 , " Conexant Reference board " , CXT5045_LAPTOP_HPSENSE ) ,
2006-11-14 14:13:39 +03:00
{ }
} ;
static int patch_cxt5045 ( struct hda_codec * codec )
{
struct conexant_spec * spec ;
int board_config ;
spec = kzalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
if ( ! spec )
return - ENOMEM ;
mutex_init ( & spec - > amp_mutex ) ;
codec - > spec = spec ;
spec - > multiout . max_channels = 2 ;
spec - > multiout . num_dacs = ARRAY_SIZE ( cxt5045_dac_nids ) ;
spec - > multiout . dac_nids = cxt5045_dac_nids ;
spec - > multiout . dig_out_nid = CXT5045_SPDIF_OUT ;
spec - > num_adc_nids = 1 ;
spec - > adc_nids = cxt5045_adc_nids ;
spec - > capsrc_nids = cxt5045_capsrc_nids ;
spec - > input_mux = & cxt5045_capture_source ;
spec - > num_mixers = 1 ;
spec - > mixers [ 0 ] = cxt5045_mixers ;
spec - > num_init_verbs = 1 ;
spec - > init_verbs [ 0 ] = cxt5045_init_verbs ;
spec - > spdif_route = 0 ;
2006-11-20 19:42:09 +03:00
spec - > num_channel_mode = ARRAY_SIZE ( cxt5045_modes ) ,
spec - > channel_mode = cxt5045_modes ,
2006-11-14 14:13:39 +03:00
codec - > patch_ops = conexant_patch_ops ;
2006-11-24 19:07:44 +03:00
board_config = snd_hda_check_board_config ( codec , CXT5045_MODELS ,
cxt5045_models ,
cxt5045_cfg_tbl ) ;
2006-11-14 14:13:39 +03:00
switch ( board_config ) {
2008-01-22 17:15:59 +03:00
case CXT5045_LAPTOP_HPSENSE :
2007-03-12 13:39:01 +03:00
codec - > patch_ops . unsol_event = cxt5045_hp_unsol_event ;
spec - > input_mux = & cxt5045_capture_source ;
spec - > num_init_verbs = 2 ;
spec - > init_verbs [ 1 ] = cxt5045_hp_sense_init_verbs ;
spec - > mixers [ 0 ] = cxt5045_mixers ;
codec - > patch_ops . init = cxt5045_init ;
break ;
2008-01-22 17:15:59 +03:00
case CXT5045_LAPTOP_MICSENSE :
2006-11-14 14:13:39 +03:00
spec - > input_mux = & cxt5045_capture_source ;
spec - > num_init_verbs = 2 ;
2007-03-12 13:39:01 +03:00
spec - > init_verbs [ 1 ] = cxt5045_mic_sense_init_verbs ;
2006-11-14 14:13:39 +03:00
spec - > mixers [ 0 ] = cxt5045_mixers ;
codec - > patch_ops . init = cxt5045_init ;
break ;
2008-01-22 17:15:59 +03:00
default :
case CXT5045_LAPTOP_HPMICSENSE :
codec - > patch_ops . unsol_event = cxt5045_hp_unsol_event ;
spec - > input_mux = & cxt5045_capture_source ;
spec - > num_init_verbs = 3 ;
spec - > init_verbs [ 1 ] = cxt5045_hp_sense_init_verbs ;
spec - > init_verbs [ 2 ] = cxt5045_mic_sense_init_verbs ;
spec - > mixers [ 0 ] = cxt5045_mixers ;
codec - > patch_ops . init = cxt5045_init ;
break ;
2008-01-17 13:18:41 +03:00
case CXT5045_BENQ :
codec - > patch_ops . unsol_event = cxt5045_hp_unsol_event ;
spec - > input_mux = & cxt5045_capture_source_benq ;
spec - > num_init_verbs = 1 ;
spec - > init_verbs [ 0 ] = cxt5045_benq_init_verbs ;
spec - > mixers [ 0 ] = cxt5045_mixers ;
spec - > mixers [ 1 ] = cxt5045_benq_mixers ;
spec - > num_mixers = 2 ;
codec - > patch_ops . init = cxt5045_init ;
break ;
2006-11-14 14:13:39 +03:00
# ifdef CONFIG_SND_DEBUG
case CXT5045_TEST :
spec - > input_mux = & cxt5045_test_capture_source ;
spec - > mixers [ 0 ] = cxt5045_test_mixer ;
spec - > init_verbs [ 0 ] = cxt5045_test_init_verbs ;
2008-01-22 17:15:59 +03:00
break ;
2006-11-14 14:13:39 +03:00
# endif
}
2007-12-17 16:32:49 +03:00
/*
* Fix max PCM level to 0 dB
* ( originall it has 0x2b steps with 0 dB offset 0x14 )
*/
snd_hda_override_amp_caps ( codec , 0x17 , HDA_INPUT ,
( 0x14 < < AC_AMPCAP_OFFSET_SHIFT ) |
( 0x14 < < AC_AMPCAP_NUM_STEPS_SHIFT ) |
( 0x05 < < AC_AMPCAP_STEP_SIZE_SHIFT ) |
( 1 < < AC_AMPCAP_MUTE_SHIFT ) ) ;
2006-11-14 14:13:39 +03:00
return 0 ;
}
/* Conexant 5047 specific */
2007-02-13 14:45:44 +03:00
# define CXT5047_SPDIF_OUT 0x11
2006-11-14 14:13:39 +03:00
2007-02-13 14:45:44 +03:00
static hda_nid_t cxt5047_dac_nids [ 2 ] = { 0x10 , 0x1c } ;
2006-11-14 14:13:39 +03:00
static hda_nid_t cxt5047_adc_nids [ 1 ] = { 0x12 } ;
static hda_nid_t cxt5047_capsrc_nids [ 1 ] = { 0x1a } ;
2006-11-20 19:42:09 +03:00
static struct hda_channel_mode cxt5047_modes [ 1 ] = {
{ 2 , NULL } ,
} ;
2006-11-14 14:13:39 +03:00
static struct hda_input_mux cxt5047_capture_source = {
2007-03-12 13:39:01 +03:00
. num_items = 1 ,
2006-11-14 14:13:39 +03:00
. items = {
2007-03-12 13:39:01 +03:00
{ " Mic " , 0x2 } ,
2006-11-14 14:13:39 +03:00
}
} ;
static struct hda_input_mux cxt5047_hp_capture_source = {
. num_items = 1 ,
. items = {
2007-02-13 14:45:44 +03:00
{ " ExtMic " , 0x2 } ,
}
} ;
static struct hda_input_mux cxt5047_toshiba_capture_source = {
. num_items = 2 ,
. items = {
{ " ExtMic " , 0x2 } ,
{ " Line-In " , 0x1 } ,
2006-11-14 14:13:39 +03:00
}
} ;
/* turn on/off EAPD (+ mute HP) as a master switch */
static int cxt5047_hp_master_sw_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct conexant_spec * spec = codec - > spec ;
2007-02-13 14:45:44 +03:00
unsigned int bits ;
2006-11-14 14:13:39 +03:00
2007-02-13 14:45:44 +03:00
if ( ! cxt_eapd_put ( kcontrol , ucontrol ) )
2006-11-14 14:13:39 +03:00
return 0 ;
2007-02-13 14:45:44 +03:00
/* toggle internal speakers mute depending of presence of
* the headphone jack
*/
2007-08-10 19:11:07 +04:00
bits = ( ! spec - > hp_present & & spec - > cur_eapd ) ? 0 : HDA_AMP_MUTE ;
snd_hda_codec_amp_stereo ( codec , 0x1d , HDA_OUTPUT , 0 ,
HDA_AMP_MUTE , bits ) ;
bits = spec - > cur_eapd ? 0 : HDA_AMP_MUTE ;
snd_hda_codec_amp_stereo ( codec , 0x13 , HDA_OUTPUT , 0 ,
HDA_AMP_MUTE , bits ) ;
2006-11-14 14:13:39 +03:00
return 1 ;
}
2007-02-13 14:45:44 +03:00
/* bind volumes of both NID 0x13 (Headphones) and 0x1d (Speakers) */
2007-08-10 19:12:15 +04:00
static struct hda_bind_ctls cxt5047_bind_master_vol = {
. ops = & snd_hda_bind_vol ,
. values = {
HDA_COMPOSE_AMP_VAL ( 0x13 , 3 , 0 , HDA_OUTPUT ) ,
HDA_COMPOSE_AMP_VAL ( 0x1d , 3 , 0 , HDA_OUTPUT ) ,
0
} ,
} ;
2006-11-14 14:13:39 +03:00
/* mute internal speaker if HP is plugged */
static void cxt5047_hp_automute ( struct hda_codec * codec )
{
2007-02-13 14:45:44 +03:00
struct conexant_spec * spec = codec - > spec ;
2007-02-26 18:07:42 +03:00
unsigned int bits ;
2006-11-14 14:13:39 +03:00
2007-02-13 14:45:44 +03:00
spec - > hp_present = snd_hda_codec_read ( codec , 0x13 , 0 ,
2006-11-14 14:13:39 +03:00
AC_VERB_GET_PIN_SENSE , 0 ) & 0x80000000 ;
2007-02-26 18:07:42 +03:00
2007-08-10 19:11:07 +04:00
bits = ( spec - > hp_present | | ! spec - > cur_eapd ) ? HDA_AMP_MUTE : 0 ;
snd_hda_codec_amp_stereo ( codec , 0x1d , HDA_OUTPUT , 0 ,
HDA_AMP_MUTE , bits ) ;
2007-02-13 14:45:44 +03:00
/* Mute/Unmute PCM 2 for good measure - some systems need this */
2007-08-10 19:11:07 +04:00
snd_hda_codec_amp_stereo ( codec , 0x1c , HDA_OUTPUT , 0 ,
HDA_AMP_MUTE , bits ) ;
2006-11-14 14:13:39 +03:00
}
2007-05-17 11:40:47 +04:00
/* mute internal speaker if HP is plugged */
static void cxt5047_hp2_automute ( struct hda_codec * codec )
{
struct conexant_spec * spec = codec - > spec ;
unsigned int bits ;
spec - > hp_present = snd_hda_codec_read ( codec , 0x13 , 0 ,
AC_VERB_GET_PIN_SENSE , 0 ) & 0x80000000 ;
2007-08-10 19:11:07 +04:00
bits = spec - > hp_present ? HDA_AMP_MUTE : 0 ;
snd_hda_codec_amp_stereo ( codec , 0x1d , HDA_OUTPUT , 0 ,
HDA_AMP_MUTE , bits ) ;
2007-05-17 11:40:47 +04:00
/* Mute/Unmute PCM 2 for good measure - some systems need this */
2007-08-10 19:11:07 +04:00
snd_hda_codec_amp_stereo ( codec , 0x1c , HDA_OUTPUT , 0 ,
HDA_AMP_MUTE , bits ) ;
2007-05-17 11:40:47 +04:00
}
2006-11-14 14:13:39 +03:00
/* toggle input of built-in and mic jack appropriately */
static void cxt5047_hp_automic ( struct hda_codec * codec )
{
static struct hda_verb mic_jack_on [ ] = {
2008-01-22 17:18:08 +03:00
{ 0x15 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_MUTE } ,
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_UNMUTE } ,
2006-11-14 14:13:39 +03:00
{ }
} ;
static struct hda_verb mic_jack_off [ ] = {
2008-01-22 17:18:08 +03:00
{ 0x17 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_MUTE } ,
{ 0x15 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_UNMUTE } ,
2006-11-14 14:13:39 +03:00
{ }
} ;
unsigned int present ;
2007-03-12 13:39:01 +03:00
present = snd_hda_codec_read ( codec , 0x15 , 0 ,
2006-11-14 14:13:39 +03:00
AC_VERB_GET_PIN_SENSE , 0 ) & 0x80000000 ;
if ( present )
snd_hda_sequence_write ( codec , mic_jack_on ) ;
else
snd_hda_sequence_write ( codec , mic_jack_off ) ;
}
/* unsolicited event for HP jack sensing */
static void cxt5047_hp_unsol_event ( struct hda_codec * codec ,
unsigned int res )
{
2008-01-22 17:18:08 +03:00
switch ( res > > 26 ) {
2006-11-14 14:13:39 +03:00
case CONEXANT_HP_EVENT :
cxt5047_hp_automute ( codec ) ;
break ;
case CONEXANT_MIC_EVENT :
cxt5047_hp_automic ( codec ) ;
break ;
}
}
2007-05-17 11:40:47 +04:00
/* unsolicited event for HP jack sensing - non-EAPD systems */
static void cxt5047_hp2_unsol_event ( struct hda_codec * codec ,
unsigned int res )
{
res > > = 26 ;
switch ( res ) {
case CONEXANT_HP_EVENT :
cxt5047_hp2_automute ( codec ) ;
break ;
case CONEXANT_MIC_EVENT :
cxt5047_hp_automic ( codec ) ;
break ;
}
}
2006-11-14 14:13:39 +03:00
static struct snd_kcontrol_new cxt5047_mixers [ ] = {
HDA_CODEC_VOLUME ( " Mic Bypass Capture Volume " , 0x19 , 0x02 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Mic Bypass Capture Switch " , 0x19 , 0x02 , HDA_INPUT ) ,
2007-03-12 13:39:01 +03:00
HDA_CODEC_VOLUME ( " Mic Gain Volume " , 0x1a , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Mic Gain Switch " , 0x1a , 0x0 , HDA_OUTPUT ) ,
2006-11-14 14:13:39 +03:00
HDA_CODEC_VOLUME ( " Capture Volume " , 0x12 , 0x03 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Capture Switch " , 0x12 , 0x03 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " PCM Volume " , 0x10 , 0x00 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " PCM Switch " , 0x10 , 0x00 , HDA_OUTPUT ) ,
2007-02-13 14:45:44 +03:00
HDA_CODEC_VOLUME ( " PCM-2 Volume " , 0x1c , 0x00 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " PCM-2 Switch " , 0x1c , 0x00 , HDA_OUTPUT ) ,
2007-04-24 19:56:55 +04:00
HDA_CODEC_VOLUME ( " Speaker Playback Volume " , 0x1d , 0x00 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Speaker Playback Switch " , 0x1d , 0x00 , HDA_OUTPUT ) ,
HDA_CODEC_VOLUME ( " Headphone Playback Volume " , 0x13 , 0x00 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Headphone Playback Switch " , 0x13 , 0x00 , HDA_OUTPUT ) ,
2007-02-13 14:45:44 +03:00
{ }
} ;
static struct snd_kcontrol_new cxt5047_toshiba_mixers [ ] = {
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Capture Source " ,
. info = conexant_mux_enum_info ,
. get = conexant_mux_enum_get ,
. put = conexant_mux_enum_put
} ,
HDA_CODEC_VOLUME ( " Mic Bypass Capture Volume " , 0x19 , 0x02 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Mic Bypass Capture Switch " , 0x19 , 0x02 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Capture Volume " , 0x12 , 0x03 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Capture Switch " , 0x12 , 0x03 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " PCM Volume " , 0x10 , 0x00 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " PCM Switch " , 0x10 , 0x00 , HDA_OUTPUT ) ,
2007-08-10 19:12:15 +04:00
HDA_BIND_VOL ( " Master Playback Volume " , & cxt5047_bind_master_vol ) ,
2007-02-13 14:45:44 +03:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Master Playback Switch " ,
. info = cxt_eapd_info ,
. get = cxt_eapd_get ,
2006-11-14 14:13:39 +03:00
. put = cxt5047_hp_master_sw_put ,
. private_value = 0x13 ,
} ,
{ }
} ;
static struct snd_kcontrol_new cxt5047_hp_mixers [ ] = {
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Capture Source " ,
. info = conexant_mux_enum_info ,
. get = conexant_mux_enum_get ,
. put = conexant_mux_enum_put
} ,
HDA_CODEC_VOLUME ( " Mic Bypass Capture Volume " , 0x19 , 0x02 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Mic Bypass Capture Switch " , 0x19 , 0x02 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Capture Volume " , 0x12 , 0x03 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Capture Switch " , 0x12 , 0x03 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " PCM Volume " , 0x10 , 0x00 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " PCM Switch " , 0x10 , 0x00 , HDA_OUTPUT ) ,
HDA_CODEC_VOLUME ( " Master Playback Volume " , 0x13 , 0x00 , HDA_OUTPUT ) ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Master Playback Switch " ,
2007-02-13 14:45:44 +03:00
. info = cxt_eapd_info ,
. get = cxt_eapd_get ,
2006-11-14 14:13:39 +03:00
. put = cxt5047_hp_master_sw_put ,
. private_value = 0x13 ,
} ,
{ } /* end */
} ;
static struct hda_verb cxt5047_init_verbs [ ] = {
/* Line in, Mic, Built-in Mic */
{ 0x14 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN } ,
{ 0x15 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN | AC_PINCTL_VREF_50 } ,
{ 0x17 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN | AC_PINCTL_VREF_50 } ,
2007-03-12 13:39:01 +03:00
/* HP, Speaker */
2007-04-24 19:56:55 +04:00
{ 0x13 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_HP } ,
{ 0x13 , AC_VERB_SET_CONNECT_SEL , 0x1 } ,
2007-02-13 14:45:44 +03:00
{ 0x1d , AC_VERB_SET_CONNECT_SEL , 0x0 } ,
2007-03-12 13:39:01 +03:00
/* Record selector: Mic */
2006-11-14 14:13:39 +03:00
{ 0x12 , AC_VERB_SET_CONNECT_SEL , 0x03 } ,
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE ,
AC_AMP_SET_INPUT | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | 0x17 } ,
2007-03-12 13:39:01 +03:00
{ 0x1A , AC_VERB_SET_CONNECT_SEL , 0x02 } ,
{ 0x1A , AC_VERB_SET_AMP_GAIN_MUTE ,
AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | 0x00 } ,
{ 0x1A , AC_VERB_SET_AMP_GAIN_MUTE ,
AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | 0x03 } ,
2006-11-14 14:13:39 +03:00
/* SPDIF route: PCM */
{ 0x18 , AC_VERB_SET_CONNECT_SEL , 0x0 } ,
2007-02-13 14:45:44 +03:00
/* Enable unsolicited events */
{ 0x13 , AC_VERB_SET_UNSOLICITED_ENABLE , AC_USRSP_EN | CONEXANT_HP_EVENT } ,
{ 0x15 , AC_VERB_SET_UNSOLICITED_ENABLE , AC_USRSP_EN | CONEXANT_MIC_EVENT } ,
2006-11-14 14:13:39 +03:00
{ } /* end */
} ;
/* configuration for Toshiba Laptops */
static struct hda_verb cxt5047_toshiba_init_verbs [ ] = {
{ 0x13 , AC_VERB_SET_EAPD_BTLENABLE , 0x0 } , /* default on */
/* pin sensing on HP and Mic jacks */
{ 0x13 , AC_VERB_SET_UNSOLICITED_ENABLE , AC_USRSP_EN | CONEXANT_HP_EVENT } ,
{ 0x15 , AC_VERB_SET_UNSOLICITED_ENABLE , AC_USRSP_EN | CONEXANT_MIC_EVENT } ,
2007-02-13 14:45:44 +03:00
/* Speaker routing */
{ 0x1d , AC_VERB_SET_CONNECT_SEL , 0x1 } ,
2006-11-14 14:13:39 +03:00
{ }
} ;
/* configuration for HP Laptops */
static struct hda_verb cxt5047_hp_init_verbs [ ] = {
2007-02-13 14:45:44 +03:00
/* pin sensing on HP jack */
2006-11-14 14:13:39 +03:00
{ 0x13 , AC_VERB_SET_UNSOLICITED_ENABLE , AC_USRSP_EN | CONEXANT_HP_EVENT } ,
2007-02-13 14:45:44 +03:00
/* Record selector: Ext Mic */
{ 0x12 , AC_VERB_SET_CONNECT_SEL , 0x03 } ,
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE ,
AC_AMP_SET_INPUT | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | 0x17 } ,
/* Speaker routing */
{ 0x1d , AC_VERB_SET_CONNECT_SEL , 0x1 } ,
2006-11-14 14:13:39 +03:00
{ }
} ;
/* Test configuration for debugging, modelled after the ALC260 test
* configuration .
*/
# ifdef CONFIG_SND_DEBUG
static struct hda_input_mux cxt5047_test_capture_source = {
2007-02-13 14:45:44 +03:00
. num_items = 4 ,
2006-11-14 14:13:39 +03:00
. items = {
2007-02-13 14:45:44 +03:00
{ " LINE1 pin " , 0x0 } ,
{ " MIC1 pin " , 0x1 } ,
{ " MIC2 pin " , 0x2 } ,
{ " CD pin " , 0x3 } ,
2006-11-14 14:13:39 +03:00
} ,
} ;
static struct snd_kcontrol_new cxt5047_test_mixer [ ] = {
/* Output only controls */
2007-02-13 14:45:44 +03:00
HDA_CODEC_VOLUME ( " OutAmp-1 Volume " , 0x10 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " OutAmp-1 Switch " , 0x10 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_VOLUME ( " OutAmp-2 Volume " , 0x1c , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " OutAmp-2 Switch " , 0x1c , 0x0 , HDA_OUTPUT ) ,
2006-11-14 14:13:39 +03:00
HDA_CODEC_VOLUME ( " Speaker Playback Volume " , 0x1d , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Speaker Playback Switch " , 0x1d , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_VOLUME ( " HeadPhone Playback Volume " , 0x13 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " HeadPhone Playback Switch " , 0x13 , 0x0 , HDA_OUTPUT ) ,
2007-02-13 14:45:44 +03:00
HDA_CODEC_VOLUME ( " Line1-Out Playback Volume " , 0x14 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Line1-Out Playback Switch " , 0x14 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_VOLUME ( " Line2-Out Playback Volume " , 0x15 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Line2-Out Playback Switch " , 0x15 , 0x0 , HDA_OUTPUT ) ,
2006-11-14 14:13:39 +03:00
/* Modes for retasking pin widgets */
CXT_PIN_MODE ( " LINE1 pin mode " , 0x14 , CXT_PIN_DIR_INOUT ) ,
CXT_PIN_MODE ( " MIC1 pin mode " , 0x15 , CXT_PIN_DIR_INOUT ) ,
2007-02-13 14:45:44 +03:00
/* EAPD Switch Control */
CXT_EAPD_SWITCH ( " External Amplifier " , 0x13 , 0x0 ) ,
2006-11-14 14:13:39 +03:00
2007-02-13 14:45:44 +03:00
/* Loopback mixer controls */
HDA_CODEC_VOLUME ( " MIC1 Playback Volume " , 0x12 , 0x01 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " MIC1 Playback Switch " , 0x12 , 0x01 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " MIC2 Playback Volume " , 0x12 , 0x02 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " MIC2 Playback Switch " , 0x12 , 0x02 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " LINE Playback Volume " , 0x12 , 0x0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " LINE Playback Switch " , 0x12 , 0x0 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " CD Playback Volume " , 0x12 , 0x04 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " CD Playback Switch " , 0x12 , 0x04 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Capture-1 Volume " , 0x19 , 0x0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Capture-1 Switch " , 0x19 , 0x0 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Capture-2 Volume " , 0x19 , 0x1 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Capture-2 Switch " , 0x19 , 0x1 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Capture-3 Volume " , 0x19 , 0x2 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Capture-3 Switch " , 0x19 , 0x2 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Capture-4 Volume " , 0x19 , 0x3 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Capture-4 Switch " , 0x19 , 0x3 , HDA_INPUT ) ,
2006-11-14 14:13:39 +03:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Input Source " ,
. info = conexant_mux_enum_info ,
. get = conexant_mux_enum_get ,
. put = conexant_mux_enum_put ,
} ,
2008-01-22 17:18:08 +03:00
HDA_CODEC_VOLUME ( " Input-1 Volume " , 0x1a , 0x0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-1 Switch " , 0x1a , 0x0 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Input-2 Volume " , 0x1a , 0x1 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-2 Switch " , 0x1a , 0x1 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Input-3 Volume " , 0x1a , 0x2 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-3 Switch " , 0x1a , 0x2 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Input-4 Volume " , 0x1a , 0x3 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-4 Switch " , 0x1a , 0x3 , HDA_INPUT ) ,
HDA_CODEC_VOLUME ( " Input-5 Volume " , 0x1a , 0x4 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Input-5 Switch " , 0x1a , 0x4 , HDA_INPUT ) ,
2006-11-14 14:13:39 +03:00
{ } /* end */
} ;
static struct hda_verb cxt5047_test_init_verbs [ ] = {
/* Enable retasking pins as output, initially without power amp */
{ 0x15 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_OUT } ,
{ 0x14 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_OUT } ,
{ 0x13 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_OUT } ,
/* Disable digital (SPDIF) pins initially, but users can enable
* them via a mixer switch . In the case of SPDIF - out , this initverb
* payload also sets the generation to 0 , output to be in " consumer "
* PCM format , copyright asserted , no pre - emphasis and no validity
* control .
*/
{ 0x18 , AC_VERB_SET_DIGI_CONVERT_1 , 0 } ,
/* Ensure mic1, mic2, line1 pin widgets take input from the
* OUT1 sum bus when acting as an output .
*/
{ 0x1a , AC_VERB_SET_CONNECT_SEL , 0 } ,
{ 0x1b , AC_VERB_SET_CONNECT_SEL , 0 } ,
/* Start with output sum widgets muted and their output gains at min */
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } ,
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 1 ) } ,
/* Unmute retasking pin widget output buffers since the default
* state appears to be output . As the pin mode is changed by the
* user the pin mode control will take care of enabling the pin ' s
* input / output buffers as needed .
*/
{ 0x15 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_UNMUTE } ,
{ 0x14 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_UNMUTE } ,
{ 0x13 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_UNMUTE } ,
/* Mute capture amp left and right */
{ 0x12 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } ,
/* Set ADC connection select to match default mixer setting (mic1
* pin )
*/
{ 0x12 , AC_VERB_SET_CONNECT_SEL , 0x00 } ,
/* Mute all inputs to mixer widget (even unconnected ones) */
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } , /* mic1 pin */
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 1 ) } , /* mic2 pin */
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 2 ) } , /* line1 pin */
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 3 ) } , /* line2 pin */
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 4 ) } , /* CD pin */
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 5 ) } , /* Beep-gen pin */
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 6 ) } , /* Line-out pin */
{ 0x19 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 7 ) } , /* HP-pin pin */
{ }
} ;
# endif
/* initialize jack-sensing, too */
static int cxt5047_hp_init ( struct hda_codec * codec )
{
conexant_init ( codec ) ;
cxt5047_hp_automute ( codec ) ;
return 0 ;
}
enum {
2006-11-24 19:07:44 +03:00
CXT5047_LAPTOP , /* Laptops w/o EAPD support */
CXT5047_LAPTOP_HP , /* Some HP laptops */
CXT5047_LAPTOP_EAPD , /* Laptops with EAPD support */
2006-11-14 14:13:39 +03:00
# ifdef CONFIG_SND_DEBUG
CXT5047_TEST ,
# endif
2006-11-24 19:07:44 +03:00
CXT5047_MODELS
2006-11-14 14:13:39 +03:00
} ;
2006-11-24 19:07:44 +03:00
static const char * cxt5047_models [ CXT5047_MODELS ] = {
[ CXT5047_LAPTOP ] = " laptop " ,
[ CXT5047_LAPTOP_HP ] = " laptop-hp " ,
[ CXT5047_LAPTOP_EAPD ] = " laptop-eapd " ,
2006-11-14 14:13:39 +03:00
# ifdef CONFIG_SND_DEBUG
2006-11-24 19:07:44 +03:00
[ CXT5047_TEST ] = " test " ,
2006-11-14 14:13:39 +03:00
# endif
2006-11-24 19:07:44 +03:00
} ;
static struct snd_pci_quirk cxt5047_cfg_tbl [ ] = {
SND_PCI_QUIRK ( 0x103c , 0x30a0 , " HP DV1000 " , CXT5047_LAPTOP ) ,
2007-12-17 19:14:18 +03:00
SND_PCI_QUIRK ( 0x103c , 0x30a5 , " HP DV5200T/DV8000T " , CXT5047_LAPTOP_HP ) ,
2006-11-24 19:07:44 +03:00
SND_PCI_QUIRK ( 0x103c , 0x30b2 , " HP DV2000T/DV3000T " , CXT5047_LAPTOP ) ,
2007-02-13 14:45:44 +03:00
SND_PCI_QUIRK ( 0x103c , 0x30b5 , " HP DV2000Z " , CXT5047_LAPTOP ) ,
2006-11-24 19:07:44 +03:00
SND_PCI_QUIRK ( 0x1179 , 0xff31 , " Toshiba P100 " , CXT5047_LAPTOP_EAPD ) ,
2006-11-14 14:13:39 +03:00
{ }
} ;
static int patch_cxt5047 ( struct hda_codec * codec )
{
struct conexant_spec * spec ;
int board_config ;
spec = kzalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
if ( ! spec )
return - ENOMEM ;
mutex_init ( & spec - > amp_mutex ) ;
codec - > spec = spec ;
spec - > multiout . max_channels = 2 ;
spec - > multiout . num_dacs = ARRAY_SIZE ( cxt5047_dac_nids ) ;
spec - > multiout . dac_nids = cxt5047_dac_nids ;
spec - > multiout . dig_out_nid = CXT5047_SPDIF_OUT ;
spec - > num_adc_nids = 1 ;
spec - > adc_nids = cxt5047_adc_nids ;
spec - > capsrc_nids = cxt5047_capsrc_nids ;
spec - > input_mux = & cxt5047_capture_source ;
spec - > num_mixers = 1 ;
spec - > mixers [ 0 ] = cxt5047_mixers ;
spec - > num_init_verbs = 1 ;
spec - > init_verbs [ 0 ] = cxt5047_init_verbs ;
spec - > spdif_route = 0 ;
2006-11-20 19:42:09 +03:00
spec - > num_channel_mode = ARRAY_SIZE ( cxt5047_modes ) ,
spec - > channel_mode = cxt5047_modes ,
2006-11-14 14:13:39 +03:00
codec - > patch_ops = conexant_patch_ops ;
2006-11-24 19:07:44 +03:00
board_config = snd_hda_check_board_config ( codec , CXT5047_MODELS ,
cxt5047_models ,
cxt5047_cfg_tbl ) ;
2006-11-14 14:13:39 +03:00
switch ( board_config ) {
case CXT5047_LAPTOP :
2007-05-17 11:40:47 +04:00
codec - > patch_ops . unsol_event = cxt5047_hp2_unsol_event ;
2006-11-14 14:13:39 +03:00
break ;
case CXT5047_LAPTOP_HP :
spec - > input_mux = & cxt5047_hp_capture_source ;
spec - > num_init_verbs = 2 ;
spec - > init_verbs [ 1 ] = cxt5047_hp_init_verbs ;
spec - > mixers [ 0 ] = cxt5047_hp_mixers ;
2007-05-17 11:40:47 +04:00
codec - > patch_ops . unsol_event = cxt5047_hp_unsol_event ;
2006-11-14 14:13:39 +03:00
codec - > patch_ops . init = cxt5047_hp_init ;
break ;
case CXT5047_LAPTOP_EAPD :
2007-02-13 14:45:44 +03:00
spec - > input_mux = & cxt5047_toshiba_capture_source ;
2006-11-14 14:13:39 +03:00
spec - > num_init_verbs = 2 ;
spec - > init_verbs [ 1 ] = cxt5047_toshiba_init_verbs ;
2007-02-13 14:45:44 +03:00
spec - > mixers [ 0 ] = cxt5047_toshiba_mixers ;
2007-05-17 11:40:47 +04:00
codec - > patch_ops . unsol_event = cxt5047_hp_unsol_event ;
2006-11-14 14:13:39 +03:00
break ;
# ifdef CONFIG_SND_DEBUG
case CXT5047_TEST :
spec - > input_mux = & cxt5047_test_capture_source ;
spec - > mixers [ 0 ] = cxt5047_test_mixer ;
spec - > init_verbs [ 0 ] = cxt5047_test_init_verbs ;
2007-05-17 11:40:47 +04:00
codec - > patch_ops . unsol_event = cxt5047_hp_unsol_event ;
2006-11-14 14:13:39 +03:00
# endif
}
return 0 ;
}
struct hda_codec_preset snd_hda_preset_conexant [ ] = {
2007-02-13 14:45:44 +03:00
{ . id = 0x14f15045 , . name = " CX20549 (Venice) " ,
. patch = patch_cxt5045 } ,
{ . id = 0x14f15047 , . name = " CX20551 (Waikiki) " ,
. patch = patch_cxt5047 } ,
2006-11-14 14:13:39 +03:00
{ } /* terminator */
} ;