2005-04-13 14:45:30 +02:00
/*
* Universal Interface for Intel High Definition Audio Codec
*
* HD audio interface patch for SigmaTel STAC92xx
*
* Copyright ( c ) 2005 Embedded Alley Solutions , Inc .
2005-11-29 15:00:51 +01:00
* Matt Porter < mporter @ embeddedalley . com >
2005-04-13 14:45:30 +02:00
*
* Based on patch_cmedia . c and patch_realtek . c
* Copyright ( c ) 2004 Takashi Iwai < tiwai @ suse . de >
*
* 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 <sound/driver.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/slab.h>
# include <linux/pci.h>
# include <sound/core.h>
2005-06-27 14:59:41 +02:00
# include <sound/asoundef.h>
2005-04-13 14:45:30 +02:00
# include "hda_codec.h"
# include "hda_local.h"
2005-07-04 17:51:39 +02:00
# define NUM_CONTROL_ALLOC 32
# define STAC_HP_EVENT 0x37
2006-11-24 17:07:44 +01:00
enum {
STAC_REF ,
STAC_9200_MODELS
} ;
enum {
STAC_9205_REF ,
STAC_9205_MODELS
} ;
2007-01-08 11:04:17 +01:00
enum {
STAC_925x_REF ,
STAC_M2_2 ,
STAC_MA6 ,
STAC_925x_MODELS
} ;
2006-11-24 17:07:44 +01:00
enum {
STAC_D945_REF ,
STAC_D945GTP3 ,
STAC_D945GTP5 ,
STAC_MACMINI ,
2007-02-16 13:27:18 +01:00
STAC_MACBOOK ,
STAC_MACBOOK_PRO ,
2006-11-24 17:07:44 +01:00
STAC_922X_MODELS
} ;
enum {
STAC_D965_REF ,
STAC_D965_3ST ,
STAC_D965_5ST ,
STAC_927X_MODELS
} ;
2005-11-29 15:00:51 +01:00
2005-04-13 14:45:30 +02:00
struct sigmatel_spec {
2005-11-17 14:57:47 +01:00
struct snd_kcontrol_new * mixers [ 4 ] ;
2005-06-27 14:59:41 +02:00
unsigned int num_mixers ;
2005-11-29 15:00:51 +01:00
int board_config ;
2005-06-27 14:59:41 +02:00
unsigned int surr_switch : 1 ;
2005-11-29 15:00:51 +01:00
unsigned int line_switch : 1 ;
unsigned int mic_switch : 1 ;
2006-01-23 15:27:49 +01:00
unsigned int alt_switch : 1 ;
2006-03-21 11:24:42 +01:00
unsigned int hp_detect : 1 ;
2006-05-10 15:09:17 +02:00
unsigned int gpio_mute : 1 ;
2005-06-27 14:59:41 +02:00
2005-04-13 14:45:30 +02:00
/* playback */
struct hda_multi_out multiout ;
2006-01-23 15:27:49 +01:00
hda_nid_t dac_nids [ 5 ] ;
2005-04-13 14:45:30 +02:00
/* capture */
hda_nid_t * adc_nids ;
unsigned int num_adcs ;
2005-06-14 10:19:34 +02:00
hda_nid_t * mux_nids ;
unsigned int num_muxes ;
2006-10-26 17:12:59 +02:00
hda_nid_t * dmic_nids ;
unsigned int num_dmics ;
hda_nid_t dmux_nid ;
2005-06-14 10:19:34 +02:00
hda_nid_t dig_in_nid ;
2005-04-13 14:45:30 +02:00
/* pin widgets */
hda_nid_t * pin_nids ;
unsigned int num_pins ;
unsigned int * pin_configs ;
2006-08-23 18:31:34 +02:00
unsigned int * bios_pin_configs ;
2005-04-13 14:45:30 +02:00
/* codec specific stuff */
struct hda_verb * init ;
2005-11-17 14:57:47 +01:00
struct snd_kcontrol_new * mixer ;
2005-04-13 14:45:30 +02:00
/* capture source */
2006-10-26 17:12:59 +02:00
struct hda_input_mux * dinput_mux ;
unsigned int cur_dmux ;
2005-06-27 14:59:41 +02:00
struct hda_input_mux * input_mux ;
2006-01-23 15:27:49 +01:00
unsigned int cur_mux [ 3 ] ;
2005-04-13 14:45:30 +02:00
2005-11-29 15:00:51 +01:00
/* i/o switches */
unsigned int io_switch [ 2 ] ;
2005-04-13 14:45:30 +02:00
2005-06-27 14:59:41 +02:00
struct hda_pcm pcm_rec [ 2 ] ; /* PCM information */
/* dynamic controls and input_mux */
struct auto_pin_cfg autocfg ;
unsigned int num_kctl_alloc , num_kctl_used ;
2005-11-17 14:57:47 +01:00
struct snd_kcontrol_new * kctl_alloc ;
2006-10-26 17:12:59 +02:00
struct hda_input_mux private_dimux ;
2005-06-27 14:59:41 +02:00
struct hda_input_mux private_imux ;
2005-04-13 14:45:30 +02:00
} ;
static hda_nid_t stac9200_adc_nids [ 1 ] = {
0x03 ,
} ;
static hda_nid_t stac9200_mux_nids [ 1 ] = {
0x0c ,
} ;
static hda_nid_t stac9200_dac_nids [ 1 ] = {
0x02 ,
} ;
2007-01-08 11:04:17 +01:00
static hda_nid_t stac925x_adc_nids [ 1 ] = {
0x03 ,
} ;
static hda_nid_t stac925x_mux_nids [ 1 ] = {
0x0f ,
} ;
static hda_nid_t stac925x_dac_nids [ 1 ] = {
0x02 ,
} ;
2005-04-13 14:45:30 +02:00
static hda_nid_t stac922x_adc_nids [ 2 ] = {
0x06 , 0x07 ,
} ;
static hda_nid_t stac922x_mux_nids [ 2 ] = {
0x12 , 0x13 ,
} ;
2006-01-23 15:27:49 +01:00
static hda_nid_t stac927x_adc_nids [ 3 ] = {
0x07 , 0x08 , 0x09
} ;
static hda_nid_t stac927x_mux_nids [ 3 ] = {
0x15 , 0x16 , 0x17
} ;
2006-07-31 12:49:34 +02:00
static hda_nid_t stac9205_adc_nids [ 2 ] = {
0x12 , 0x13
} ;
static hda_nid_t stac9205_mux_nids [ 2 ] = {
0x19 , 0x1a
} ;
2006-10-26 17:12:59 +02:00
static hda_nid_t stac9205_dmic_nids [ 3 ] = {
0x17 , 0x18 , 0
} ;
2005-06-27 14:59:41 +02:00
static hda_nid_t stac9200_pin_nids [ 8 ] = {
2006-09-01 21:03:12 +02:00
0x08 , 0x09 , 0x0d , 0x0e ,
0x0f , 0x10 , 0x11 , 0x12 ,
2005-04-13 14:45:30 +02:00
} ;
2007-01-08 11:04:17 +01:00
static hda_nid_t stac925x_pin_nids [ 8 ] = {
0x07 , 0x08 , 0x0a , 0x0b ,
0x0c , 0x0d , 0x10 , 0x11 ,
} ;
2005-04-13 14:45:30 +02:00
static hda_nid_t stac922x_pin_nids [ 10 ] = {
0x0a , 0x0b , 0x0c , 0x0d , 0x0e ,
0x0f , 0x10 , 0x11 , 0x15 , 0x1b ,
} ;
2006-01-23 15:27:49 +01:00
static hda_nid_t stac927x_pin_nids [ 14 ] = {
0x0a , 0x0b , 0x0c , 0x0d , 0x0e ,
0x0f , 0x10 , 0x11 , 0x12 , 0x13 ,
0x14 , 0x21 , 0x22 , 0x23 ,
} ;
2006-07-31 12:49:34 +02:00
static hda_nid_t stac9205_pin_nids [ 12 ] = {
0x0a , 0x0b , 0x0c , 0x0d , 0x0e ,
0x0f , 0x14 , 0x16 , 0x17 , 0x18 ,
0x21 , 0x22 ,
} ;
2006-10-26 17:12:59 +02:00
static int stac92xx_dmux_enum_info ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_info * uinfo )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct sigmatel_spec * spec = codec - > spec ;
return snd_hda_input_mux_info ( spec - > dinput_mux , uinfo ) ;
}
static int stac92xx_dmux_enum_get ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct sigmatel_spec * spec = codec - > spec ;
ucontrol - > value . enumerated . item [ 0 ] = spec - > cur_dmux ;
return 0 ;
}
static int stac92xx_dmux_enum_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct sigmatel_spec * spec = codec - > spec ;
return snd_hda_input_mux_put ( codec , spec - > dinput_mux , ucontrol ,
spec - > dmux_nid , & spec - > cur_dmux ) ;
}
2005-11-17 14:57:47 +01:00
static int stac92xx_mux_enum_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
2005-04-13 14:45:30 +02:00
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct sigmatel_spec * spec = codec - > spec ;
2005-06-27 14:59:41 +02:00
return snd_hda_input_mux_info ( spec - > input_mux , uinfo ) ;
2005-04-13 14:45:30 +02:00
}
2005-11-17 14:57:47 +01:00
static int stac92xx_mux_enum_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-13 14:45:30 +02:00
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct sigmatel_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 ;
}
2005-11-17 14:57:47 +01:00
static int stac92xx_mux_enum_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
2005-04-13 14:45:30 +02:00
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct sigmatel_spec * spec = codec - > spec ;
unsigned int adc_idx = snd_ctl_get_ioffidx ( kcontrol , & ucontrol - > id ) ;
2005-06-27 14:59:41 +02:00
return snd_hda_input_mux_put ( codec , spec - > input_mux , ucontrol ,
2005-04-13 14:45:30 +02:00
spec - > mux_nids [ adc_idx ] , & spec - > cur_mux [ adc_idx ] ) ;
}
2005-06-27 14:59:41 +02:00
static struct hda_verb stac9200_core_init [ ] = {
2005-04-13 14:45:30 +02:00
/* set dac0mux for dac converter */
2005-06-27 14:59:41 +02:00
{ 0x07 , AC_VERB_SET_CONNECT_SEL , 0x00 } ,
2005-04-13 14:45:30 +02:00
{ }
} ;
2007-01-08 11:04:17 +01:00
static struct hda_verb stac925x_core_init [ ] = {
/* set dac0mux for dac converter */
{ 0x06 , AC_VERB_SET_CONNECT_SEL , 0x00 } ,
{ }
} ;
2005-06-27 14:59:41 +02:00
static struct hda_verb stac922x_core_init [ ] = {
2005-04-13 14:45:30 +02:00
/* set master volume and direct control */
2005-06-27 14:59:41 +02:00
{ 0x16 , AC_VERB_SET_VOLUME_KNOB_CONTROL , 0xff } ,
2005-04-13 14:45:30 +02:00
{ }
} ;
2006-09-01 21:03:12 +02:00
static struct hda_verb d965_core_init [ ] = {
2006-06-28 15:52:16 +02:00
/* set master volume and direct control */
2006-09-01 21:03:12 +02:00
{ 0x24 , AC_VERB_SET_VOLUME_KNOB_CONTROL , 0xff } ,
2006-06-28 15:52:16 +02:00
/* unmute node 0x1b */
{ 0x1b , AC_VERB_SET_AMP_GAIN_MUTE , 0xb000 } ,
/* select node 0x03 as DAC */
{ 0x0b , AC_VERB_SET_CONNECT_SEL , 0x01 } ,
{ }
} ;
2006-01-23 15:27:49 +01:00
static struct hda_verb stac927x_core_init [ ] = {
/* set master volume and direct control */
{ 0x24 , AC_VERB_SET_VOLUME_KNOB_CONTROL , 0xff } ,
{ }
} ;
2006-07-31 12:49:34 +02:00
static struct hda_verb stac9205_core_init [ ] = {
/* set master volume and direct control */
{ 0x24 , AC_VERB_SET_VOLUME_KNOB_CONTROL , 0xff } ,
{ }
} ;
2005-11-17 14:57:47 +01:00
static struct snd_kcontrol_new stac9200_mixer [ ] = {
2005-04-13 14:45:30 +02:00
HDA_CODEC_VOLUME ( " Master Playback Volume " , 0xb , 0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Master Playback Switch " , 0xb , 0 , HDA_OUTPUT ) ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Input Source " ,
. count = 1 ,
. info = stac92xx_mux_enum_info ,
. get = stac92xx_mux_enum_get ,
. put = stac92xx_mux_enum_put ,
} ,
HDA_CODEC_VOLUME ( " Capture Volume " , 0x0a , 0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Capture Switch " , 0x0a , 0 , HDA_OUTPUT ) ,
2005-06-27 14:59:41 +02:00
HDA_CODEC_VOLUME ( " Capture Mux Volume " , 0x0c , 0 , HDA_OUTPUT ) ,
2005-04-13 14:45:30 +02:00
{ } /* end */
} ;
2007-01-08 11:04:17 +01:00
static struct snd_kcontrol_new stac925x_mixer [ ] = {
HDA_CODEC_VOLUME ( " Master Playback Volume " , 0xe , 0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Master Playback Switch " , 0xe , 0 , HDA_OUTPUT ) ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Input Source " ,
. count = 1 ,
. info = stac92xx_mux_enum_info ,
. get = stac92xx_mux_enum_get ,
. put = stac92xx_mux_enum_put ,
} ,
HDA_CODEC_VOLUME ( " Capture Volume " , 0x09 , 0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Capture Switch " , 0x09 , 0 , HDA_OUTPUT ) ,
HDA_CODEC_VOLUME ( " Capture Mux Volume " , 0x0f , 0 , HDA_OUTPUT ) ,
{ } /* end */
} ;
2005-06-27 14:59:41 +02:00
/* This needs to be generated dynamically based on sequence */
2005-11-17 14:57:47 +01:00
static struct snd_kcontrol_new stac922x_mixer [ ] = {
2005-04-13 14:45:30 +02:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Input Source " ,
. count = 1 ,
. info = stac92xx_mux_enum_info ,
. get = stac92xx_mux_enum_get ,
. put = stac92xx_mux_enum_put ,
} ,
HDA_CODEC_VOLUME ( " Capture Volume " , 0x17 , 0x0 , HDA_INPUT ) ,
2006-01-13 18:46:21 +01:00
HDA_CODEC_MUTE ( " Capture Switch " , 0x17 , 0x0 , HDA_INPUT ) ,
2005-04-13 14:45:30 +02:00
HDA_CODEC_VOLUME ( " Mux Capture Volume " , 0x12 , 0x0 , HDA_OUTPUT ) ,
{ } /* end */
} ;
2006-06-28 15:52:16 +02:00
/* This needs to be generated dynamically based on sequence */
static struct snd_kcontrol_new stac9227_mixer [ ] = {
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Input Source " ,
. count = 1 ,
. info = stac92xx_mux_enum_info ,
. get = stac92xx_mux_enum_get ,
. put = stac92xx_mux_enum_put ,
} ,
HDA_CODEC_VOLUME ( " Capture Volume " , 0x15 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_MUTE ( " Capture Switch " , 0x1b , 0x0 , HDA_OUTPUT ) ,
{ } /* end */
} ;
2006-11-23 19:27:12 +01:00
static struct snd_kcontrol_new stac927x_mixer [ ] = {
2006-01-23 15:27:49 +01:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Input Source " ,
. count = 1 ,
. info = stac92xx_mux_enum_info ,
. get = stac92xx_mux_enum_get ,
. put = stac92xx_mux_enum_put ,
} ,
HDA_CODEC_VOLUME ( " InMux Capture Volume " , 0x15 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_VOLUME ( " InVol Capture Volume " , 0x18 , 0x0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " ADCMux Capture Switch " , 0x1b , 0x0 , HDA_OUTPUT ) ,
{ } /* end */
} ;
2006-11-23 19:27:12 +01:00
static struct snd_kcontrol_new stac9205_mixer [ ] = {
2006-10-26 17:12:59 +02:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Digital Input Source " ,
. count = 1 ,
. info = stac92xx_dmux_enum_info ,
. get = stac92xx_dmux_enum_get ,
. put = stac92xx_dmux_enum_put ,
} ,
2006-07-31 12:49:34 +02:00
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Input Source " ,
. count = 1 ,
. info = stac92xx_mux_enum_info ,
. get = stac92xx_mux_enum_get ,
. put = stac92xx_mux_enum_put ,
} ,
HDA_CODEC_VOLUME ( " InMux Capture Volume " , 0x19 , 0x0 , HDA_OUTPUT ) ,
HDA_CODEC_VOLUME ( " InVol Capture Volume " , 0x1b , 0x0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " ADCMux Capture Switch " , 0x1d , 0x0 , HDA_OUTPUT ) ,
{ } /* end */
} ;
2005-04-13 14:45:30 +02:00
static int stac92xx_build_controls ( struct hda_codec * codec )
{
struct sigmatel_spec * spec = codec - > spec ;
int err ;
2005-06-27 14:59:41 +02:00
int i ;
2005-04-13 14:45:30 +02:00
err = snd_hda_add_new_ctls ( codec , spec - > mixer ) ;
if ( err < 0 )
return err ;
2005-06-27 14:59:41 +02:00
for ( i = 0 ; i < spec - > num_mixers ; i + + ) {
err = snd_hda_add_new_ctls ( codec , spec - > mixers [ i ] ) ;
if ( err < 0 )
return err ;
}
2005-06-14 10:19:34 +02:00
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 ;
2005-04-13 14:45:30 +02:00
}
2005-11-29 15:00:51 +01:00
static unsigned int ref9200_pin_configs [ 8 ] = {
2005-06-14 10:19:34 +02:00
0x01c47010 , 0x01447010 , 0x0221401f , 0x01114010 ,
2005-04-13 14:45:30 +02:00
0x02a19020 , 0x01a19021 , 0x90100140 , 0x01813122 ,
} ;
2006-11-24 17:07:44 +01:00
static unsigned int * stac9200_brd_tbl [ STAC_9200_MODELS ] = {
[ STAC_REF ] = ref9200_pin_configs ,
2005-11-29 15:00:51 +01:00
} ;
2006-11-24 17:07:44 +01:00
static const char * stac9200_models [ STAC_9200_MODELS ] = {
[ STAC_REF ] = " ref " ,
} ;
static struct snd_pci_quirk stac9200_cfg_tbl [ ] = {
/* SigmaTel reference board */
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2668 ,
" DFI LanParty " , STAC_REF ) ,
2006-11-06 11:20:38 +01:00
/* Dell laptops have BIOS problem */
2006-11-24 17:07:44 +01:00
SND_PCI_QUIRK ( PCI_VENDOR_ID_DELL , 0x01b5 ,
" Dell Inspiron 630m " , STAC_REF ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_DELL , 0x01c2 ,
" Dell Latitude D620 " , STAC_REF ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_DELL , 0x01cb ,
" Dell Latitude 120L " , STAC_REF ) ,
2007-01-30 17:30:55 +01:00
SND_PCI_QUIRK ( PCI_VENDOR_ID_DELL , 0x01cc ,
" Dell Latitude D820 " , STAC_REF ) ,
2007-02-13 12:46:16 +01:00
SND_PCI_QUIRK ( PCI_VENDOR_ID_DELL , 0x01cd ,
" Dell Inspiron E1705/9400 " , STAC_REF ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_DELL , 0x01ce ,
" Dell XPS M1710 " , STAC_REF ) ,
2007-02-14 00:59:17 +01:00
SND_PCI_QUIRK ( PCI_VENDOR_ID_DELL , 0x01cf ,
" Dell Precision M90 " , STAC_REF ) ,
2005-11-29 15:00:51 +01:00
{ } /* terminator */
} ;
2007-01-08 11:04:17 +01:00
static unsigned int ref925x_pin_configs [ 8 ] = {
0x40c003f0 , 0x424503f2 , 0x01813022 , 0x02a19021 ,
0x90a70320 , 0x02214210 , 0x400003f1 , 0x9033032e ,
} ;
static unsigned int stac925x_MA6_pin_configs [ 8 ] = {
0x40c003f0 , 0x424503f2 , 0x01813022 , 0x02a19021 ,
0x90a70320 , 0x90100211 , 0x400003f1 , 0x9033032e ,
} ;
static unsigned int stac925xM2_2_pin_configs [ 8 ] = {
0x40c003f3 , 0x424503f2 , 0x041800f4 , 0x02a19020 ,
0x50a103F0 , 0x90100210 , 0x400003f1 , 0x9033032e ,
} ;
static unsigned int * stac925x_brd_tbl [ STAC_925x_MODELS ] = {
[ STAC_REF ] = ref925x_pin_configs ,
[ STAC_M2_2 ] = stac925xM2_2_pin_configs ,
[ STAC_MA6 ] = stac925x_MA6_pin_configs ,
} ;
static const char * stac925x_models [ STAC_925x_MODELS ] = {
[ STAC_REF ] = " ref " ,
[ STAC_M2_2 ] = " m2-2 " ,
[ STAC_MA6 ] = " m6 " ,
} ;
static struct snd_pci_quirk stac925x_cfg_tbl [ ] = {
/* SigmaTel reference board */
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2668 , " DFI LanParty " , STAC_REF ) ,
SND_PCI_QUIRK ( 0x107b , 0x0316 , " Gateway M255 " , STAC_REF ) ,
SND_PCI_QUIRK ( 0x107b , 0x0366 , " Gateway MP6954 " , STAC_REF ) ,
SND_PCI_QUIRK ( 0x107b , 0x0461 , " Gateway NX560XL " , STAC_MA6 ) ,
SND_PCI_QUIRK ( 0x1002 , 0x437b , " Gateway MX6453 " , STAC_M2_2 ) ,
{ } /* terminator */
} ;
2005-11-29 15:00:51 +01:00
static unsigned int ref922x_pin_configs [ 10 ] = {
0x01014010 , 0x01016011 , 0x01012012 , 0x0221401f ,
0x01813122 , 0x01011014 , 0x01441030 , 0x01c41030 ,
2005-04-13 14:45:30 +02:00
0x40000100 , 0x40000100 ,
} ;
2005-11-29 15:00:51 +01:00
static unsigned int d945gtp3_pin_configs [ 10 ] = {
2006-01-25 19:20:50 +01:00
0x0221401f , 0x01a19022 , 0x01813021 , 0x01014010 ,
2005-11-29 15:00:51 +01:00
0x40000100 , 0x40000100 , 0x40000100 , 0x40000100 ,
0x02a19120 , 0x40000100 ,
} ;
static unsigned int d945gtp5_pin_configs [ 10 ] = {
2006-01-25 19:20:50 +01:00
0x0221401f , 0x01011012 , 0x01813024 , 0x01014010 ,
0x01a19021 , 0x01016011 , 0x01452130 , 0x40000100 ,
2005-11-29 15:00:51 +01:00
0x02a19320 , 0x40000100 ,
} ;
2007-02-16 13:27:18 +01:00
static unsigned int macbook_pin_configs [ 10 ] = {
0x0321e230 , 0x03a1e020 , 0x400000fd , 0x9017e110 ,
0x400000fe , 0x0381e021 , 0x1345e240 , 0x13c5e22e ,
0x400000fc , 0x400000fb ,
} ;
static unsigned int macbook_pro_pin_configs [ 10 ] = {
0x0221401f , 0x90a70120 , 0x01813024 , 0x01014010 ,
0x400000fd , 0x01016011 , 0x1345e240 , 0x13c5e22e ,
0x400000fc , 0x400000fb ,
} ;
2006-06-28 15:52:16 +02:00
static unsigned int * stac922x_brd_tbl [ STAC_922X_MODELS ] = {
2006-11-24 17:07:44 +01:00
[ STAC_D945_REF ] = ref922x_pin_configs ,
2006-06-28 15:52:16 +02:00
[ STAC_D945GTP3 ] = d945gtp3_pin_configs ,
[ STAC_D945GTP5 ] = d945gtp5_pin_configs ,
2006-07-10 22:21:43 -07:00
[ STAC_MACMINI ] = d945gtp5_pin_configs ,
2007-02-16 13:27:18 +01:00
[ STAC_MACBOOK ] = macbook_pin_configs ,
[ STAC_MACBOOK_PRO ] = macbook_pro_pin_configs ,
2005-11-29 15:00:51 +01:00
} ;
2006-11-24 17:07:44 +01:00
static const char * stac922x_models [ STAC_922X_MODELS ] = {
[ STAC_D945_REF ] = " ref " ,
[ STAC_D945GTP5 ] = " 5stack " ,
[ STAC_D945GTP3 ] = " 3stack " ,
[ STAC_MACMINI ] = " macmini " ,
2007-02-16 13:27:18 +01:00
[ STAC_MACBOOK ] = " macbook " ,
[ STAC_MACBOOK_PRO ] = " macbook-pro " ,
2006-11-24 17:07:44 +01:00
} ;
static struct snd_pci_quirk stac922x_cfg_tbl [ ] = {
/* SigmaTel reference board */
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2668 ,
" DFI LanParty " , STAC_D945_REF ) ,
/* Intel 945G based systems */
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0101 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0202 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0606 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0601 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0111 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x1115 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x1116 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x1117 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x1118 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x1119 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x8826 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x5049 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x5055 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x5048 ,
" Intel D945G " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0110 ,
" Intel D945G " , STAC_D945GTP3 ) ,
/* Intel D945G 5-stack systems */
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0404 ,
" Intel D945G " , STAC_D945GTP5 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0303 ,
" Intel D945G " , STAC_D945GTP5 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0013 ,
" Intel D945G " , STAC_D945GTP5 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0417 ,
" Intel D945G " , STAC_D945GTP5 ) ,
/* Intel 945P based systems */
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0b0b ,
" Intel D945P " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0112 ,
" Intel D945P " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0d0d ,
" Intel D945P " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0909 ,
" Intel D945P " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0505 ,
" Intel D945P " , STAC_D945GTP3 ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x0707 ,
" Intel D945P " , STAC_D945GTP5 ) ,
/* other systems */
/* Apple Mac Mini (early 2006) */
SND_PCI_QUIRK ( 0x8384 , 0x7680 ,
" Mac Mini " , STAC_MACMINI ) ,
2005-11-29 15:00:51 +01:00
{ } /* terminator */
} ;
2006-01-23 15:27:49 +01:00
static unsigned int ref927x_pin_configs [ 14 ] = {
2006-09-01 21:03:12 +02:00
0x02214020 , 0x02a19080 , 0x0181304e , 0x01014010 ,
0x01a19040 , 0x01011012 , 0x01016011 , 0x0101201f ,
0x183301f0 , 0x18a001f0 , 0x18a001f0 , 0x01442070 ,
0x01c42190 , 0x40000100 ,
2006-01-23 15:27:49 +01:00
} ;
2006-09-01 21:03:12 +02:00
static unsigned int d965_3st_pin_configs [ 14 ] = {
2006-08-22 19:44:45 +02:00
0x0221401f , 0x02a19120 , 0x40000100 , 0x01014011 ,
0x01a19021 , 0x01813024 , 0x40000100 , 0x40000100 ,
0x40000100 , 0x40000100 , 0x40000100 , 0x40000100 ,
0x40000100 , 0x40000100
} ;
2006-09-01 21:03:12 +02:00
static unsigned int d965_5st_pin_configs [ 14 ] = {
0x02214020 , 0x02a19080 , 0x0181304e , 0x01014010 ,
0x01a19040 , 0x01011012 , 0x01016011 , 0x40000100 ,
0x40000100 , 0x40000100 , 0x40000100 , 0x01442070 ,
0x40000100 , 0x40000100
} ;
static unsigned int * stac927x_brd_tbl [ STAC_927X_MODELS ] = {
2006-11-24 17:07:44 +01:00
[ STAC_D965_REF ] = ref927x_pin_configs ,
2006-09-01 21:03:12 +02:00
[ STAC_D965_3ST ] = d965_3st_pin_configs ,
[ STAC_D965_5ST ] = d965_5st_pin_configs ,
2006-01-23 15:27:49 +01:00
} ;
2006-11-24 17:07:44 +01:00
static const char * stac927x_models [ STAC_927X_MODELS ] = {
[ STAC_D965_REF ] = " ref " ,
[ STAC_D965_3ST ] = " 3stack " ,
[ STAC_D965_5ST ] = " 5stack " ,
} ;
static struct snd_pci_quirk stac927x_cfg_tbl [ ] = {
/* SigmaTel reference board */
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2668 ,
" DFI LanParty " , STAC_D965_REF ) ,
2006-08-22 19:44:45 +02:00
/* Intel 946 based systems */
2006-11-24 17:07:44 +01:00
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x3d01 , " Intel D946 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0xa301 , " Intel D946 " , STAC_D965_3ST ) ,
2006-09-01 21:03:12 +02:00
/* 965 based 3 stack systems */
2006-11-24 17:07:44 +01:00
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2116 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2115 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2114 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2113 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2112 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2111 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2110 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2009 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2008 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2007 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2006 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2005 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2004 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2003 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2002 , " Intel D965 " , STAC_D965_3ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2001 , " Intel D965 " , STAC_D965_3ST ) ,
2006-09-01 21:03:12 +02:00
/* 965 based 5 stack systems */
2006-11-24 17:07:44 +01:00
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2301 , " Intel D965 " , STAC_D965_5ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2302 , " Intel D965 " , STAC_D965_5ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2303 , " Intel D965 " , STAC_D965_5ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2304 , " Intel D965 " , STAC_D965_5ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2305 , " Intel D965 " , STAC_D965_5ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2501 , " Intel D965 " , STAC_D965_5ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2502 , " Intel D965 " , STAC_D965_5ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2503 , " Intel D965 " , STAC_D965_5ST ) ,
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2504 , " Intel D965 " , STAC_D965_5ST ) ,
2006-01-23 15:27:49 +01:00
{ } /* terminator */
} ;
2006-07-31 12:49:34 +02:00
static unsigned int ref9205_pin_configs [ 12 ] = {
0x40000100 , 0x40000100 , 0x01016011 , 0x01014010 ,
2006-10-26 17:12:59 +02:00
0x01813122 , 0x01a19021 , 0x40000100 , 0x40000100 ,
0x90a000f0 , 0x90a000f0 , 0x01441030 , 0x01c41030
2006-07-31 12:49:34 +02:00
} ;
2006-11-24 17:07:44 +01:00
static unsigned int * stac9205_brd_tbl [ STAC_9205_MODELS ] = {
2006-07-31 12:49:34 +02:00
ref9205_pin_configs ,
} ;
2006-11-24 17:07:44 +01:00
static const char * stac9205_models [ STAC_9205_MODELS ] = {
[ STAC_9205_REF ] = " ref " ,
} ;
static struct snd_pci_quirk stac9205_cfg_tbl [ ] = {
/* SigmaTel reference board */
SND_PCI_QUIRK ( PCI_VENDOR_ID_INTEL , 0x2668 ,
" DFI LanParty " , STAC_9205_REF ) ,
2006-07-31 12:49:34 +02:00
{ } /* terminator */
} ;
2006-08-23 18:31:34 +02:00
static int stac92xx_save_bios_config_regs ( struct hda_codec * codec )
{
int i ;
struct sigmatel_spec * spec = codec - > spec ;
if ( ! spec - > bios_pin_configs ) {
spec - > bios_pin_configs = kcalloc ( spec - > num_pins ,
sizeof ( * spec - > bios_pin_configs ) , GFP_KERNEL ) ;
if ( ! spec - > bios_pin_configs )
return - ENOMEM ;
}
for ( i = 0 ; i < spec - > num_pins ; i + + ) {
hda_nid_t nid = spec - > pin_nids [ i ] ;
unsigned int pin_cfg ;
pin_cfg = snd_hda_codec_read ( codec , nid , 0 ,
AC_VERB_GET_CONFIG_DEFAULT , 0x00 ) ;
snd_printdd ( KERN_INFO " hda_codec: pin nid %2.2x bios pin config %8.8x \n " ,
nid , pin_cfg ) ;
spec - > bios_pin_configs [ i ] = pin_cfg ;
}
return 0 ;
}
2005-04-13 14:45:30 +02:00
static void stac92xx_set_config_regs ( struct hda_codec * codec )
{
int i ;
struct sigmatel_spec * spec = codec - > spec ;
unsigned int pin_cfg ;
2006-08-23 18:31:34 +02:00
if ( ! spec - > pin_nids | | ! spec - > pin_configs )
return ;
for ( i = 0 ; i < spec - > num_pins ; i + + ) {
2005-04-13 14:45:30 +02:00
snd_hda_codec_write ( codec , spec - > pin_nids [ i ] , 0 ,
AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 ,
spec - > pin_configs [ i ] & 0x000000ff ) ;
snd_hda_codec_write ( codec , spec - > pin_nids [ i ] , 0 ,
AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 ,
( spec - > pin_configs [ i ] & 0x0000ff00 ) > > 8 ) ;
snd_hda_codec_write ( codec , spec - > pin_nids [ i ] , 0 ,
AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 ,
( spec - > pin_configs [ i ] & 0x00ff0000 ) > > 16 ) ;
snd_hda_codec_write ( codec , spec - > pin_nids [ i ] , 0 ,
AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 ,
spec - > pin_configs [ i ] > > 24 ) ;
pin_cfg = snd_hda_codec_read ( codec , spec - > pin_nids [ i ] , 0 ,
AC_VERB_GET_CONFIG_DEFAULT ,
0x00 ) ;
2005-11-29 15:00:51 +01:00
snd_printdd ( KERN_INFO " hda_codec: pin nid %2.2x pin config %8.8x \n " , spec - > pin_nids [ i ] , pin_cfg ) ;
2005-04-13 14:45:30 +02:00
}
}
2005-06-14 10:19:34 +02:00
/*
2005-06-27 14:59:41 +02:00
* Analog playback callbacks
2005-06-14 10:19:34 +02:00
*/
2005-06-27 14:59:41 +02:00
static int stac92xx_playback_pcm_open ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
2005-11-17 14:57:47 +01:00
struct snd_pcm_substream * substream )
2005-04-13 14:45:30 +02:00
{
2005-06-14 10:19:34 +02:00
struct sigmatel_spec * spec = codec - > spec ;
2005-06-27 14:59:41 +02:00
return snd_hda_multi_out_analog_open ( codec , & spec - > multiout , substream ) ;
2005-04-13 14:45:30 +02:00
}
static int stac92xx_playback_pcm_prepare ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
unsigned int stream_tag ,
unsigned int format ,
2005-11-17 14:57:47 +01:00
struct snd_pcm_substream * substream )
2005-04-13 14:45:30 +02:00
{
struct sigmatel_spec * spec = codec - > spec ;
2005-11-29 15:00:51 +01:00
return snd_hda_multi_out_analog_prepare ( codec , & spec - > multiout , stream_tag , format , substream ) ;
2005-04-13 14:45:30 +02:00
}
static int stac92xx_playback_pcm_cleanup ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
2005-11-17 14:57:47 +01:00
struct snd_pcm_substream * substream )
2005-04-13 14:45:30 +02:00
{
struct sigmatel_spec * spec = codec - > spec ;
return snd_hda_multi_out_analog_cleanup ( codec , & spec - > multiout ) ;
}
2005-06-14 10:19:34 +02:00
/*
* Digital playback callbacks
*/
static int stac92xx_dig_playback_pcm_open ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
2005-11-17 14:57:47 +01:00
struct snd_pcm_substream * substream )
2005-06-14 10:19:34 +02:00
{
struct sigmatel_spec * spec = codec - > spec ;
return snd_hda_multi_out_dig_open ( codec , & spec - > multiout ) ;
}
static int stac92xx_dig_playback_pcm_close ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
2005-11-17 14:57:47 +01:00
struct snd_pcm_substream * substream )
2005-06-14 10:19:34 +02:00
{
struct sigmatel_spec * spec = codec - > spec ;
return snd_hda_multi_out_dig_close ( codec , & spec - > multiout ) ;
}
2005-04-13 14:45:30 +02:00
/*
* Analog capture callbacks
*/
static int stac92xx_capture_pcm_prepare ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
unsigned int stream_tag ,
unsigned int format ,
2005-11-17 14:57:47 +01:00
struct snd_pcm_substream * substream )
2005-04-13 14:45:30 +02:00
{
struct sigmatel_spec * spec = codec - > spec ;
snd_hda_codec_setup_stream ( codec , spec - > adc_nids [ substream - > number ] ,
stream_tag , 0 , format ) ;
return 0 ;
}
static int stac92xx_capture_pcm_cleanup ( struct hda_pcm_stream * hinfo ,
struct hda_codec * codec ,
2005-11-17 14:57:47 +01:00
struct snd_pcm_substream * substream )
2005-04-13 14:45:30 +02:00
{
struct sigmatel_spec * spec = codec - > spec ;
snd_hda_codec_setup_stream ( codec , spec - > adc_nids [ substream - > number ] , 0 , 0 , 0 ) ;
return 0 ;
}
2005-06-14 10:19:34 +02:00
static struct hda_pcm_stream stac92xx_pcm_digital_playback = {
. substreams = 1 ,
. channels_min = 2 ,
. channels_max = 2 ,
/* NID is set in stac92xx_build_pcms */
. ops = {
. open = stac92xx_dig_playback_pcm_open ,
. close = stac92xx_dig_playback_pcm_close
} ,
} ;
static struct hda_pcm_stream stac92xx_pcm_digital_capture = {
. substreams = 1 ,
. channels_min = 2 ,
. channels_max = 2 ,
/* NID is set in stac92xx_build_pcms */
} ;
2005-04-13 14:45:30 +02:00
static struct hda_pcm_stream stac92xx_pcm_analog_playback = {
. substreams = 1 ,
. channels_min = 2 ,
2005-06-27 14:59:41 +02:00
. channels_max = 8 ,
2005-04-13 14:45:30 +02:00
. nid = 0x02 , /* NID to query formats and rates */
. ops = {
. open = stac92xx_playback_pcm_open ,
. prepare = stac92xx_playback_pcm_prepare ,
. cleanup = stac92xx_playback_pcm_cleanup
} ,
} ;
2006-01-23 15:27:49 +01:00
static struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = {
. substreams = 1 ,
. channels_min = 2 ,
. channels_max = 2 ,
. nid = 0x06 , /* NID to query formats and rates */
. ops = {
. open = stac92xx_playback_pcm_open ,
. prepare = stac92xx_playback_pcm_prepare ,
. cleanup = stac92xx_playback_pcm_cleanup
} ,
} ;
2005-04-13 14:45:30 +02:00
static struct hda_pcm_stream stac92xx_pcm_analog_capture = {
. substreams = 2 ,
. channels_min = 2 ,
. channels_max = 2 ,
2006-01-23 15:27:49 +01:00
/* NID is set in stac92xx_build_pcms */
2005-04-13 14:45:30 +02:00
. ops = {
. prepare = stac92xx_capture_pcm_prepare ,
. cleanup = stac92xx_capture_pcm_cleanup
} ,
} ;
static int stac92xx_build_pcms ( struct hda_codec * codec )
{
struct sigmatel_spec * spec = codec - > spec ;
struct hda_pcm * info = spec - > pcm_rec ;
codec - > num_pcms = 1 ;
codec - > pcm_info = info ;
2005-06-27 14:59:41 +02:00
info - > name = " STAC92xx Analog " ;
2005-04-13 14:45:30 +02:00
info - > stream [ SNDRV_PCM_STREAM_PLAYBACK ] = stac92xx_pcm_analog_playback ;
info - > stream [ SNDRV_PCM_STREAM_CAPTURE ] = stac92xx_pcm_analog_capture ;
2006-01-23 15:27:49 +01:00
info - > stream [ SNDRV_PCM_STREAM_CAPTURE ] . nid = spec - > adc_nids [ 0 ] ;
if ( spec - > alt_switch ) {
codec - > num_pcms + + ;
info + + ;
info - > name = " STAC92xx Analog Alt " ;
info - > stream [ SNDRV_PCM_STREAM_PLAYBACK ] = stac92xx_pcm_analog_alt_playback ;
}
2005-04-13 14:45:30 +02:00
2005-06-14 10:19:34 +02:00
if ( spec - > multiout . dig_out_nid | | spec - > dig_in_nid ) {
codec - > num_pcms + + ;
info + + ;
info - > name = " STAC92xx Digital " ;
if ( spec - > multiout . dig_out_nid ) {
info - > stream [ SNDRV_PCM_STREAM_PLAYBACK ] = stac92xx_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 ] = stac92xx_pcm_digital_capture ;
info - > stream [ SNDRV_PCM_STREAM_CAPTURE ] . nid = spec - > dig_in_nid ;
}
}
2005-04-13 14:45:30 +02:00
return 0 ;
}
2006-03-23 17:06:28 +01:00
static unsigned int stac92xx_get_vref ( struct hda_codec * codec , hda_nid_t nid )
{
unsigned int pincap = snd_hda_param_read ( codec , nid ,
AC_PAR_PIN_CAP ) ;
pincap = ( pincap & AC_PINCAP_VREF ) > > AC_PINCAP_VREF_SHIFT ;
if ( pincap & AC_PINCAP_VREF_100 )
return AC_PINCTL_VREF_100 ;
if ( pincap & AC_PINCAP_VREF_80 )
return AC_PINCTL_VREF_80 ;
if ( pincap & AC_PINCAP_VREF_50 )
return AC_PINCTL_VREF_50 ;
if ( pincap & AC_PINCAP_VREF_GRD )
return AC_PINCTL_VREF_GRD ;
return 0 ;
}
2005-11-29 15:00:51 +01:00
static void stac92xx_auto_set_pinctl ( struct hda_codec * codec , hda_nid_t nid , int pin_type )
{
snd_hda_codec_write ( codec , nid , 0 , AC_VERB_SET_PIN_WIDGET_CONTROL , pin_type ) ;
}
static int stac92xx_io_switch_info ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_info * uinfo )
{
uinfo - > type = SNDRV_CTL_ELEM_TYPE_BOOLEAN ;
uinfo - > count = 1 ;
uinfo - > value . integer . min = 0 ;
uinfo - > value . integer . max = 1 ;
return 0 ;
}
static int stac92xx_io_switch_get ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct sigmatel_spec * spec = codec - > spec ;
int io_idx = kcontrol - > private_value & 0xff ;
ucontrol - > value . integer . value [ 0 ] = spec - > io_switch [ io_idx ] ;
return 0 ;
}
static int stac92xx_io_switch_put ( struct snd_kcontrol * kcontrol , struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
struct sigmatel_spec * spec = codec - > spec ;
hda_nid_t nid = kcontrol - > private_value > > 8 ;
int io_idx = kcontrol - > private_value & 0xff ;
unsigned short val = ucontrol - > value . integer . value [ 0 ] ;
spec - > io_switch [ io_idx ] = val ;
if ( val )
stac92xx_auto_set_pinctl ( codec , nid , AC_PINCTL_OUT_EN ) ;
2006-03-23 17:06:28 +01:00
else {
unsigned int pinctl = AC_PINCTL_IN_EN ;
if ( io_idx ) /* set VREF for mic */
pinctl | = stac92xx_get_vref ( codec , nid ) ;
stac92xx_auto_set_pinctl ( codec , nid , pinctl ) ;
}
2005-11-29 15:00:51 +01:00
return 1 ;
}
# define STAC_CODEC_IO_SWITCH(xname, xpval) \
{ . iface = SNDRV_CTL_ELEM_IFACE_MIXER , \
. name = xname , \
. index = 0 , \
. info = stac92xx_io_switch_info , \
. get = stac92xx_io_switch_get , \
. put = stac92xx_io_switch_put , \
. private_value = xpval , \
}
2005-06-27 14:59:41 +02:00
enum {
STAC_CTL_WIDGET_VOL ,
STAC_CTL_WIDGET_MUTE ,
2005-11-29 15:00:51 +01:00
STAC_CTL_WIDGET_IO_SWITCH ,
2005-06-27 14:59:41 +02:00
} ;
2005-11-17 14:57:47 +01:00
static struct snd_kcontrol_new stac92xx_control_templates [ ] = {
2005-06-27 14:59:41 +02:00
HDA_CODEC_VOLUME ( NULL , 0 , 0 , 0 ) ,
HDA_CODEC_MUTE ( NULL , 0 , 0 , 0 ) ,
2005-11-29 15:00:51 +01:00
STAC_CODEC_IO_SWITCH ( NULL , 0 ) ,
2005-06-27 14:59:41 +02:00
} ;
/* add dynamic controls */
static int stac92xx_add_control ( struct sigmatel_spec * spec , int type , const char * name , unsigned long val )
{
2005-11-17 14:57:47 +01:00
struct snd_kcontrol_new * knew ;
2005-06-27 14:59:41 +02:00
if ( spec - > num_kctl_used > = spec - > num_kctl_alloc ) {
int num = spec - > num_kctl_alloc + NUM_CONTROL_ALLOC ;
knew = kcalloc ( num + 1 , sizeof ( * knew ) , GFP_KERNEL ) ; /* array + terminator */
if ( ! knew )
return - ENOMEM ;
if ( spec - > kctl_alloc ) {
memcpy ( knew , spec - > kctl_alloc , sizeof ( * knew ) * spec - > num_kctl_alloc ) ;
kfree ( spec - > kctl_alloc ) ;
}
spec - > kctl_alloc = knew ;
spec - > num_kctl_alloc = num ;
}
knew = & spec - > kctl_alloc [ spec - > num_kctl_used ] ;
* knew = stac92xx_control_templates [ type ] ;
2005-06-30 10:54:33 +02:00
knew - > name = kstrdup ( name , GFP_KERNEL ) ;
2005-06-27 14:59:41 +02:00
if ( ! knew - > name )
return - ENOMEM ;
knew - > private_value = val ;
spec - > num_kctl_used + + ;
return 0 ;
}
2005-11-29 15:00:51 +01:00
/* flag inputs as additional dynamic lineouts */
static int stac92xx_add_dyn_out_pins ( struct hda_codec * codec , struct auto_pin_cfg * cfg )
{
struct sigmatel_spec * spec = codec - > spec ;
switch ( cfg - > line_outs ) {
case 3 :
/* add line-in as side */
if ( cfg - > input_pins [ AUTO_PIN_LINE ] ) {
cfg - > line_out_pins [ 3 ] = cfg - > input_pins [ AUTO_PIN_LINE ] ;
spec - > line_switch = 1 ;
cfg - > line_outs + + ;
}
break ;
case 2 :
/* add line-in as clfe and mic as side */
if ( cfg - > input_pins [ AUTO_PIN_LINE ] ) {
cfg - > line_out_pins [ 2 ] = cfg - > input_pins [ AUTO_PIN_LINE ] ;
spec - > line_switch = 1 ;
cfg - > line_outs + + ;
}
if ( cfg - > input_pins [ AUTO_PIN_MIC ] ) {
cfg - > line_out_pins [ 3 ] = cfg - > input_pins [ AUTO_PIN_MIC ] ;
spec - > mic_switch = 1 ;
cfg - > line_outs + + ;
}
break ;
case 1 :
/* add line-in as surr and mic as clfe */
if ( cfg - > input_pins [ AUTO_PIN_LINE ] ) {
cfg - > line_out_pins [ 1 ] = cfg - > input_pins [ AUTO_PIN_LINE ] ;
spec - > line_switch = 1 ;
cfg - > line_outs + + ;
}
if ( cfg - > input_pins [ AUTO_PIN_MIC ] ) {
cfg - > line_out_pins [ 2 ] = cfg - > input_pins [ AUTO_PIN_MIC ] ;
spec - > mic_switch = 1 ;
cfg - > line_outs + + ;
}
break ;
}
return 0 ;
}
2006-01-23 15:27:49 +01:00
/*
* XXX The line_out pin widget connection list may not be set to the
* desired DAC nid . This is the case on 927 x where ports A and B can
* be routed to several DACs .
*
* This requires an analysis of the line - out / hp pin configuration
* to provide a best fit for pin / DAC configurations that are routable .
* For now , 927 x DAC4 is not supported and 927 x DAC1 output to ports
* A and B is not supported .
*/
2005-06-27 14:59:41 +02:00
/* fill in the dac_nids table from the parsed pin configuration */
2006-06-28 15:52:16 +02:00
static int stac92xx_auto_fill_dac_nids ( struct hda_codec * codec ,
const struct auto_pin_cfg * cfg )
2005-06-27 14:59:41 +02:00
{
struct sigmatel_spec * spec = codec - > spec ;
hda_nid_t nid ;
int i ;
/* check the pins hardwired to audio widget */
for ( i = 0 ; i < cfg - > line_outs ; i + + ) {
nid = cfg - > line_out_pins [ i ] ;
spec - > multiout . dac_nids [ i ] = snd_hda_codec_read ( codec , nid , 0 ,
AC_VERB_GET_CONNECT_LIST , 0 ) & 0xff ;
}
2006-03-21 11:24:42 +01:00
spec - > multiout . num_dacs = cfg - > line_outs ;
2005-06-27 14:59:41 +02:00
return 0 ;
}
2006-09-20 17:10:27 +02:00
/* create volume control/switch for the given prefx type */
static int create_controls ( struct sigmatel_spec * spec , const char * pfx , hda_nid_t nid , int chs )
{
char name [ 32 ] ;
int err ;
sprintf ( name , " %s Playback Volume " , pfx ) ;
err = stac92xx_add_control ( spec , STAC_CTL_WIDGET_VOL , name ,
HDA_COMPOSE_AMP_VAL ( nid , chs , 0 , HDA_OUTPUT ) ) ;
if ( err < 0 )
return err ;
sprintf ( name , " %s Playback Switch " , pfx ) ;
err = stac92xx_add_control ( spec , STAC_CTL_WIDGET_MUTE , name ,
HDA_COMPOSE_AMP_VAL ( nid , chs , 0 , HDA_OUTPUT ) ) ;
if ( err < 0 )
return err ;
return 0 ;
}
2005-06-27 14:59:41 +02:00
/* add playback controls from the parsed DAC table */
2006-06-28 15:52:16 +02:00
static int stac92xx_auto_create_multi_out_ctls ( struct sigmatel_spec * spec ,
const struct auto_pin_cfg * cfg )
2005-06-27 14:59:41 +02:00
{
2006-06-28 15:52:16 +02:00
static const char * chname [ 4 ] = {
" Front " , " Surround " , NULL /*CLFE*/ , " Side "
} ;
2005-06-27 14:59:41 +02:00
hda_nid_t nid ;
int i , err ;
for ( i = 0 ; i < cfg - > line_outs ; i + + ) {
2005-11-29 15:00:51 +01:00
if ( ! spec - > multiout . dac_nids [ i ] )
2005-06-27 14:59:41 +02:00
continue ;
nid = spec - > multiout . dac_nids [ i ] ;
if ( i = = 2 ) {
/* Center/LFE */
2006-09-20 17:10:27 +02:00
err = create_controls ( spec , " Center " , nid , 1 ) ;
if ( err < 0 )
2005-06-27 14:59:41 +02:00
return err ;
2006-09-20 17:10:27 +02:00
err = create_controls ( spec , " LFE " , nid , 2 ) ;
if ( err < 0 )
2005-06-27 14:59:41 +02:00
return err ;
} else {
2006-09-20 17:10:27 +02:00
err = create_controls ( spec , chname [ i ] , nid , 3 ) ;
if ( err < 0 )
2005-06-27 14:59:41 +02:00
return err ;
}
}
2005-11-29 15:00:51 +01:00
if ( spec - > line_switch )
if ( ( err = stac92xx_add_control ( spec , STAC_CTL_WIDGET_IO_SWITCH , " Line In as Output Switch " , cfg - > input_pins [ AUTO_PIN_LINE ] < < 8 ) ) < 0 )
return err ;
if ( spec - > mic_switch )
if ( ( err = stac92xx_add_control ( spec , STAC_CTL_WIDGET_IO_SWITCH , " Mic as Output Switch " , ( cfg - > input_pins [ AUTO_PIN_MIC ] < < 8 ) | 1 ) ) < 0 )
return err ;
2005-06-27 14:59:41 +02:00
return 0 ;
}
2006-09-20 17:10:27 +02:00
static int check_in_dac_nids ( struct sigmatel_spec * spec , hda_nid_t nid )
2005-06-27 14:59:41 +02:00
{
2006-09-20 17:10:27 +02:00
int i ;
2005-06-27 14:59:41 +02:00
2006-09-20 17:10:27 +02:00
for ( i = 0 ; i < spec - > multiout . num_dacs ; i + + ) {
if ( spec - > multiout . dac_nids [ i ] = = nid )
return 1 ;
}
if ( spec - > multiout . hp_nid = = nid )
return 1 ;
return 0 ;
}
2005-06-27 14:59:41 +02:00
2006-09-20 17:10:27 +02:00
static int add_spec_dacs ( struct sigmatel_spec * spec , hda_nid_t nid )
{
if ( ! spec - > multiout . hp_nid )
spec - > multiout . hp_nid = nid ;
else if ( spec - > multiout . num_dacs > 4 ) {
printk ( KERN_WARNING " stac92xx: No space for DAC 0x%x \n " , nid ) ;
return 1 ;
} else {
spec - > multiout . dac_nids [ spec - > multiout . num_dacs ] = nid ;
spec - > multiout . num_dacs + + ;
}
return 0 ;
}
2005-07-04 17:51:39 +02:00
2006-09-20 17:10:27 +02:00
/* add playback controls for Speaker and HP outputs */
static int stac92xx_auto_create_hp_ctls ( struct hda_codec * codec ,
struct auto_pin_cfg * cfg )
{
struct sigmatel_spec * spec = codec - > spec ;
hda_nid_t nid ;
int i , old_num_dacs , err ;
old_num_dacs = spec - > multiout . num_dacs ;
for ( i = 0 ; i < cfg - > hp_outs ; i + + ) {
unsigned int wid_caps = get_wcaps ( codec , cfg - > hp_pins [ i ] ) ;
if ( wid_caps & AC_WCAP_UNSOL_CAP )
spec - > hp_detect = 1 ;
nid = snd_hda_codec_read ( codec , cfg - > hp_pins [ i ] , 0 ,
AC_VERB_GET_CONNECT_LIST , 0 ) & 0xff ;
if ( check_in_dac_nids ( spec , nid ) )
nid = 0 ;
if ( ! nid )
2005-06-27 14:59:41 +02:00
continue ;
2006-09-20 17:10:27 +02:00
add_spec_dacs ( spec , nid ) ;
}
for ( i = 0 ; i < cfg - > speaker_outs ; i + + ) {
nid = snd_hda_codec_read ( codec , cfg - > speaker_pins [ 0 ] , 0 ,
AC_VERB_GET_CONNECT_LIST , 0 ) & 0xff ;
if ( check_in_dac_nids ( spec , nid ) )
nid = 0 ;
if ( check_in_dac_nids ( spec , nid ) )
nid = 0 ;
if ( ! nid )
continue ;
add_spec_dacs ( spec , nid ) ;
2005-06-27 14:59:41 +02:00
}
2006-09-20 17:10:27 +02:00
for ( i = old_num_dacs ; i < spec - > multiout . num_dacs ; i + + ) {
static const char * pfxs [ ] = {
" Speaker " , " External Speaker " , " Speaker2 " ,
} ;
err = create_controls ( spec , pfxs [ i - old_num_dacs ] ,
spec - > multiout . dac_nids [ i ] , 3 ) ;
if ( err < 0 )
return err ;
}
if ( spec - > multiout . hp_nid ) {
const char * pfx ;
if ( old_num_dacs = = spec - > multiout . num_dacs )
pfx = " Master " ;
else
pfx = " Headphone " ;
err = create_controls ( spec , pfx , spec - > multiout . hp_nid , 3 ) ;
if ( err < 0 )
return err ;
}
2005-06-27 14:59:41 +02:00
return 0 ;
}
2006-10-26 17:12:59 +02:00
/* labels for dmic mux inputs */
2006-11-20 12:03:44 +01:00
static const char * stac92xx_dmic_labels [ 5 ] = {
2006-10-26 17:12:59 +02:00
" Analog Inputs " , " Digital Mic 1 " , " Digital Mic 2 " ,
" Digital Mic 3 " , " Digital Mic 4 "
} ;
/* create playback/capture controls for input pins on dmic capable codecs */
static int stac92xx_auto_create_dmic_input_ctls ( struct hda_codec * codec ,
const struct auto_pin_cfg * cfg )
{
struct sigmatel_spec * spec = codec - > spec ;
struct hda_input_mux * dimux = & spec - > private_dimux ;
hda_nid_t con_lst [ HDA_MAX_NUM_INPUTS ] ;
int i , j ;
dimux - > items [ dimux - > num_items ] . label = stac92xx_dmic_labels [ 0 ] ;
dimux - > items [ dimux - > num_items ] . index = 0 ;
dimux - > num_items + + ;
for ( i = 0 ; i < spec - > num_dmics ; i + + ) {
int index ;
int num_cons ;
unsigned int def_conf ;
def_conf = snd_hda_codec_read ( codec ,
spec - > dmic_nids [ i ] ,
0 ,
AC_VERB_GET_CONFIG_DEFAULT ,
0 ) ;
if ( get_defcfg_connect ( def_conf ) = = AC_JACK_PORT_NONE )
continue ;
num_cons = snd_hda_get_connections ( codec ,
spec - > dmux_nid ,
con_lst ,
HDA_MAX_NUM_INPUTS ) ;
for ( j = 0 ; j < num_cons ; j + + )
if ( con_lst [ j ] = = spec - > dmic_nids [ i ] ) {
index = j ;
goto found ;
}
continue ;
found :
dimux - > items [ dimux - > num_items ] . label =
stac92xx_dmic_labels [ dimux - > num_items ] ;
dimux - > items [ dimux - > num_items ] . index = index ;
dimux - > num_items + + ;
}
return 0 ;
}
2005-06-27 14:59:41 +02:00
/* create playback/capture controls for input pins */
static int stac92xx_auto_create_analog_input_ctls ( struct hda_codec * codec , const struct auto_pin_cfg * cfg )
{
struct sigmatel_spec * spec = codec - > spec ;
struct hda_input_mux * imux = & spec - > private_imux ;
hda_nid_t con_lst [ HDA_MAX_NUM_INPUTS ] ;
int i , j , k ;
for ( i = 0 ; i < AUTO_PIN_LAST ; i + + ) {
2006-09-21 11:56:18 +02:00
int index ;
if ( ! cfg - > input_pins [ i ] )
continue ;
index = - 1 ;
for ( j = 0 ; j < spec - > num_muxes ; j + + ) {
int num_cons ;
num_cons = snd_hda_get_connections ( codec ,
spec - > mux_nids [ j ] ,
con_lst ,
HDA_MAX_NUM_INPUTS ) ;
for ( k = 0 ; k < num_cons ; k + + )
if ( con_lst [ k ] = = cfg - > input_pins [ i ] ) {
index = k ;
goto found ;
}
2005-06-27 14:59:41 +02:00
}
2006-09-21 11:56:18 +02:00
continue ;
found :
imux - > items [ imux - > num_items ] . label = auto_pin_cfg_labels [ i ] ;
imux - > items [ imux - > num_items ] . index = index ;
imux - > num_items + + ;
2005-06-27 14:59:41 +02:00
}
2006-05-10 15:09:17 +02:00
if ( imux - > num_items = = 1 ) {
/*
* Set the current input for the muxes .
* The STAC9221 has two input muxes with identical source
* NID lists . Hopefully this won ' t get confused .
*/
for ( i = 0 ; i < spec - > num_muxes ; i + + ) {
snd_hda_codec_write ( codec , spec - > mux_nids [ i ] , 0 ,
AC_VERB_SET_CONNECT_SEL ,
imux - > items [ 0 ] . index ) ;
}
}
2005-06-27 14:59:41 +02:00
return 0 ;
}
static void stac92xx_auto_init_multi_out ( struct hda_codec * codec )
{
struct sigmatel_spec * spec = codec - > spec ;
int i ;
for ( i = 0 ; i < spec - > autocfg . line_outs ; i + + ) {
hda_nid_t nid = spec - > autocfg . line_out_pins [ i ] ;
stac92xx_auto_set_pinctl ( codec , nid , AC_PINCTL_OUT_EN ) ;
}
}
static void stac92xx_auto_init_hp_out ( struct hda_codec * codec )
{
struct sigmatel_spec * spec = codec - > spec ;
2006-09-20 17:10:27 +02:00
int i ;
2005-06-27 14:59:41 +02:00
2006-09-20 17:10:27 +02:00
for ( i = 0 ; i < spec - > autocfg . hp_outs ; i + + ) {
hda_nid_t pin ;
pin = spec - > autocfg . hp_pins [ i ] ;
if ( pin ) /* connect to front */
stac92xx_auto_set_pinctl ( codec , pin , AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN ) ;
}
for ( i = 0 ; i < spec - > autocfg . speaker_outs ; i + + ) {
hda_nid_t pin ;
pin = spec - > autocfg . speaker_pins [ i ] ;
if ( pin ) /* connect to front */
stac92xx_auto_set_pinctl ( codec , pin , AC_PINCTL_OUT_EN ) ;
}
2005-06-27 14:59:41 +02:00
}
2006-01-23 15:27:49 +01:00
static int stac92xx_parse_auto_config ( struct hda_codec * codec , hda_nid_t dig_out , hda_nid_t dig_in )
2005-06-27 14:59:41 +02:00
{
struct sigmatel_spec * spec = codec - > spec ;
int err ;
2006-10-26 17:12:59 +02:00
if ( ( err = snd_hda_parse_pin_def_config ( codec ,
& spec - > autocfg ,
spec - > dmic_nids ) ) < 0 )
2005-06-27 14:59:41 +02:00
return err ;
2006-03-21 11:24:42 +01:00
if ( ! spec - > autocfg . line_outs )
2006-01-25 19:20:50 +01:00
return 0 ; /* can't find valid pin config */
2006-06-28 15:52:16 +02:00
2005-11-29 15:00:51 +01:00
if ( ( err = stac92xx_add_dyn_out_pins ( codec , & spec - > autocfg ) ) < 0 )
return err ;
2006-06-28 15:52:16 +02:00
if ( spec - > multiout . num_dacs = = 0 )
if ( ( err = stac92xx_auto_fill_dac_nids ( codec , & spec - > autocfg ) ) < 0 )
return err ;
2005-06-27 14:59:41 +02:00
if ( ( err = stac92xx_auto_create_multi_out_ctls ( spec , & spec - > autocfg ) ) < 0 | |
( err = stac92xx_auto_create_hp_ctls ( codec , & spec - > autocfg ) ) < 0 | |
( err = stac92xx_auto_create_analog_input_ctls ( codec , & spec - > autocfg ) ) < 0 )
return err ;
2006-10-26 17:12:59 +02:00
if ( spec - > num_dmics > 0 )
if ( ( err = stac92xx_auto_create_dmic_input_ctls ( codec ,
& spec - > autocfg ) ) < 0 )
return err ;
2005-06-27 14:59:41 +02:00
spec - > multiout . max_channels = spec - > multiout . num_dacs * 2 ;
2005-11-29 15:00:51 +01:00
if ( spec - > multiout . max_channels > 2 )
2005-06-27 14:59:41 +02:00
spec - > surr_switch = 1 ;
2006-03-21 11:24:42 +01:00
if ( spec - > autocfg . dig_out_pin )
2006-01-23 15:27:49 +01:00
spec - > multiout . dig_out_nid = dig_out ;
2006-03-21 11:24:42 +01:00
if ( spec - > autocfg . dig_in_pin )
2006-01-23 15:27:49 +01:00
spec - > dig_in_nid = dig_in ;
2005-06-27 14:59:41 +02:00
if ( spec - > kctl_alloc )
spec - > mixers [ spec - > num_mixers + + ] = spec - > kctl_alloc ;
spec - > input_mux = & spec - > private_imux ;
2006-10-26 17:12:59 +02:00
spec - > dinput_mux = & spec - > private_dimux ;
2005-06-27 14:59:41 +02:00
return 1 ;
}
2006-03-21 11:24:42 +01:00
/* add playback controls for HP output */
static int stac9200_auto_create_hp_ctls ( struct hda_codec * codec ,
struct auto_pin_cfg * cfg )
{
struct sigmatel_spec * spec = codec - > spec ;
2006-09-20 17:10:27 +02:00
hda_nid_t pin = cfg - > hp_pins [ 0 ] ;
2006-03-21 11:24:42 +01:00
unsigned int wid_caps ;
if ( ! pin )
return 0 ;
wid_caps = get_wcaps ( codec , pin ) ;
2006-03-27 12:51:52 +02:00
if ( wid_caps & AC_WCAP_UNSOL_CAP )
2006-03-21 11:24:42 +01:00
spec - > hp_detect = 1 ;
return 0 ;
}
2006-09-06 13:58:25 +02:00
/* add playback controls for LFE output */
static int stac9200_auto_create_lfe_ctls ( struct hda_codec * codec ,
struct auto_pin_cfg * cfg )
{
struct sigmatel_spec * spec = codec - > spec ;
int err ;
hda_nid_t lfe_pin = 0x0 ;
int i ;
/*
* search speaker outs and line outs for a mono speaker pin
* with an amp . If one is found , add LFE controls
* for it .
*/
for ( i = 0 ; i < spec - > autocfg . speaker_outs & & lfe_pin = = 0x0 ; i + + ) {
hda_nid_t pin = spec - > autocfg . speaker_pins [ i ] ;
unsigned long wcaps = get_wcaps ( codec , pin ) ;
wcaps & = ( AC_WCAP_STEREO | AC_WCAP_OUT_AMP ) ;
if ( wcaps = = AC_WCAP_OUT_AMP )
/* found a mono speaker with an amp, must be lfe */
lfe_pin = pin ;
}
/* if speaker_outs is 0, then speakers may be in line_outs */
if ( lfe_pin = = 0 & & spec - > autocfg . speaker_outs = = 0 ) {
for ( i = 0 ; i < spec - > autocfg . line_outs & & lfe_pin = = 0x0 ; i + + ) {
hda_nid_t pin = spec - > autocfg . line_out_pins [ i ] ;
unsigned long cfg ;
cfg = snd_hda_codec_read ( codec , pin , 0 ,
AC_VERB_GET_CONFIG_DEFAULT ,
0x00 ) ;
if ( get_defcfg_device ( cfg ) = = AC_JACK_SPEAKER ) {
unsigned long wcaps = get_wcaps ( codec , pin ) ;
wcaps & = ( AC_WCAP_STEREO | AC_WCAP_OUT_AMP ) ;
if ( wcaps = = AC_WCAP_OUT_AMP )
/* found a mono speaker with an amp,
must be lfe */
lfe_pin = pin ;
}
}
}
if ( lfe_pin ) {
2006-09-20 17:10:27 +02:00
err = create_controls ( spec , " LFE " , lfe_pin , 1 ) ;
2006-09-06 13:58:25 +02:00
if ( err < 0 )
return err ;
}
return 0 ;
}
2005-06-27 14:59:41 +02:00
static int stac9200_parse_auto_config ( struct hda_codec * codec )
{
struct sigmatel_spec * spec = codec - > spec ;
int err ;
2005-12-05 19:42:22 +01:00
if ( ( err = snd_hda_parse_pin_def_config ( codec , & spec - > autocfg , NULL ) ) < 0 )
2005-06-27 14:59:41 +02:00
return err ;
if ( ( err = stac92xx_auto_create_analog_input_ctls ( codec , & spec - > autocfg ) ) < 0 )
return err ;
2006-03-21 11:24:42 +01:00
if ( ( err = stac9200_auto_create_hp_ctls ( codec , & spec - > autocfg ) ) < 0 )
return err ;
2006-09-06 13:58:25 +02:00
if ( ( err = stac9200_auto_create_lfe_ctls ( codec , & spec - > autocfg ) ) < 0 )
return err ;
2006-03-21 11:24:42 +01:00
if ( spec - > autocfg . dig_out_pin )
2005-06-27 14:59:41 +02:00
spec - > multiout . dig_out_nid = 0x05 ;
2006-03-21 11:24:42 +01:00
if ( spec - > autocfg . dig_in_pin )
2005-06-27 14:59:41 +02:00
spec - > dig_in_nid = 0x04 ;
if ( spec - > kctl_alloc )
spec - > mixers [ spec - > num_mixers + + ] = spec - > kctl_alloc ;
spec - > input_mux = & spec - > private_imux ;
2006-10-26 17:12:59 +02:00
spec - > dinput_mux = & spec - > private_dimux ;
2005-06-27 14:59:41 +02:00
return 1 ;
}
2006-05-10 15:09:17 +02:00
/*
* Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
* funky external mute control using GPIO pins .
*/
static void stac922x_gpio_mute ( struct hda_codec * codec , int pin , int muted )
{
unsigned int gpiostate , gpiomask , gpiodir ;
gpiostate = snd_hda_codec_read ( codec , codec - > afg , 0 ,
AC_VERB_GET_GPIO_DATA , 0 ) ;
if ( ! muted )
gpiostate | = ( 1 < < pin ) ;
else
gpiostate & = ~ ( 1 < < pin ) ;
gpiomask = snd_hda_codec_read ( codec , codec - > afg , 0 ,
AC_VERB_GET_GPIO_MASK , 0 ) ;
gpiomask | = ( 1 < < pin ) ;
gpiodir = snd_hda_codec_read ( codec , codec - > afg , 0 ,
AC_VERB_GET_GPIO_DIRECTION , 0 ) ;
gpiodir | = ( 1 < < pin ) ;
/* AppleHDA seems to do this -- WTF is this verb?? */
snd_hda_codec_write ( codec , codec - > afg , 0 , 0x7e7 , 0 ) ;
snd_hda_codec_write ( codec , codec - > afg , 0 ,
AC_VERB_SET_GPIO_MASK , gpiomask ) ;
snd_hda_codec_write ( codec , codec - > afg , 0 ,
AC_VERB_SET_GPIO_DIRECTION , gpiodir ) ;
msleep ( 1 ) ;
snd_hda_codec_write ( codec , codec - > afg , 0 ,
AC_VERB_SET_GPIO_DATA , gpiostate ) ;
}
2006-09-21 11:56:18 +02:00
static void enable_pin_detect ( struct hda_codec * codec , hda_nid_t nid ,
unsigned int event )
{
if ( get_wcaps ( codec , nid ) & AC_WCAP_UNSOL_CAP )
snd_hda_codec_write ( codec , nid , 0 ,
AC_VERB_SET_UNSOLICITED_ENABLE ,
( AC_USRSP_EN | event ) ) ;
}
2005-06-27 14:59:41 +02:00
static int stac92xx_init ( struct hda_codec * codec )
{
struct sigmatel_spec * spec = codec - > spec ;
2006-03-21 11:24:42 +01:00
struct auto_pin_cfg * cfg = & spec - > autocfg ;
int i ;
2005-06-27 14:59:41 +02:00
snd_hda_sequence_write ( codec , spec - > init ) ;
2006-03-21 11:24:42 +01:00
/* set up pins */
if ( spec - > hp_detect ) {
2006-03-27 12:51:52 +02:00
/* Enable unsolicited responses on the HP widget */
2006-09-20 17:10:27 +02:00
for ( i = 0 ; i < cfg - > hp_outs ; i + + )
2006-09-21 11:56:18 +02:00
enable_pin_detect ( codec , cfg - > hp_pins [ i ] ,
STAC_HP_EVENT ) ;
2007-03-13 10:40:23 +01:00
/* force to enable the first line-out; the others are set up
* in unsol_event
*/
stac92xx_auto_set_pinctl ( codec , spec - > autocfg . line_out_pins [ 0 ] ,
AC_PINCTL_OUT_EN ) ;
2006-09-21 14:28:21 +02:00
stac92xx_auto_init_hp_out ( codec ) ;
2006-03-21 11:24:42 +01:00
/* fake event to set up pins */
codec - > patch_ops . unsol_event ( codec , STAC_HP_EVENT < < 26 ) ;
} else {
stac92xx_auto_init_multi_out ( codec ) ;
stac92xx_auto_init_hp_out ( codec ) ;
}
for ( i = 0 ; i < AUTO_PIN_LAST ; i + + ) {
2006-03-23 17:06:28 +01:00
hda_nid_t nid = cfg - > input_pins [ i ] ;
if ( nid ) {
unsigned int pinctl = AC_PINCTL_IN_EN ;
if ( i = = AUTO_PIN_MIC | | i = = AUTO_PIN_FRONT_MIC )
pinctl | = stac92xx_get_vref ( codec , nid ) ;
stac92xx_auto_set_pinctl ( codec , nid , pinctl ) ;
}
2006-03-21 11:24:42 +01:00
}
2006-10-26 17:12:59 +02:00
if ( spec - > num_dmics > 0 )
for ( i = 0 ; i < spec - > num_dmics ; i + + )
stac92xx_auto_set_pinctl ( codec , spec - > dmic_nids [ i ] ,
AC_PINCTL_IN_EN ) ;
2006-03-21 11:24:42 +01:00
if ( cfg - > dig_out_pin )
stac92xx_auto_set_pinctl ( codec , cfg - > dig_out_pin ,
AC_PINCTL_OUT_EN ) ;
if ( cfg - > dig_in_pin )
stac92xx_auto_set_pinctl ( codec , cfg - > dig_in_pin ,
AC_PINCTL_IN_EN ) ;
2006-05-10 15:09:17 +02:00
if ( spec - > gpio_mute ) {
stac922x_gpio_mute ( codec , 0 , 0 ) ;
stac922x_gpio_mute ( codec , 1 , 0 ) ;
}
2005-06-27 14:59:41 +02:00
return 0 ;
}
2005-04-13 14:45:30 +02:00
static void stac92xx_free ( struct hda_codec * codec )
{
2005-06-27 14:59:41 +02:00
struct sigmatel_spec * spec = codec - > spec ;
int i ;
if ( ! spec )
return ;
if ( spec - > kctl_alloc ) {
for ( i = 0 ; i < spec - > num_kctl_used ; i + + )
kfree ( spec - > kctl_alloc [ i ] . name ) ;
kfree ( spec - > kctl_alloc ) ;
}
2006-08-23 18:31:34 +02:00
if ( spec - > bios_pin_configs )
kfree ( spec - > bios_pin_configs ) ;
2005-06-27 14:59:41 +02:00
kfree ( spec ) ;
2005-04-13 14:45:30 +02:00
}
2005-07-04 17:51:39 +02:00
static void stac92xx_set_pinctl ( struct hda_codec * codec , hda_nid_t nid ,
unsigned int flag )
{
unsigned int pin_ctl = snd_hda_codec_read ( codec , nid ,
0 , AC_VERB_GET_PIN_WIDGET_CONTROL , 0x00 ) ;
2006-09-21 11:56:18 +02:00
if ( flag = = AC_PINCTL_OUT_EN & & ( pin_ctl & AC_PINCTL_IN_EN ) )
return ;
2005-07-04 17:51:39 +02:00
snd_hda_codec_write ( codec , nid , 0 ,
AC_VERB_SET_PIN_WIDGET_CONTROL ,
pin_ctl | flag ) ;
}
static void stac92xx_reset_pinctl ( struct hda_codec * codec , hda_nid_t nid ,
unsigned int flag )
{
unsigned int pin_ctl = snd_hda_codec_read ( codec , nid ,
0 , AC_VERB_GET_PIN_WIDGET_CONTROL , 0x00 ) ;
snd_hda_codec_write ( codec , nid , 0 ,
AC_VERB_SET_PIN_WIDGET_CONTROL ,
pin_ctl & ~ flag ) ;
}
2006-09-21 11:56:18 +02:00
static int get_pin_presence ( struct hda_codec * codec , hda_nid_t nid )
{
if ( ! nid )
return 0 ;
if ( snd_hda_codec_read ( codec , nid , 0 , AC_VERB_GET_PIN_SENSE , 0x00 )
& ( 1 < < 31 ) )
return 1 ;
return 0 ;
}
static void stac92xx_hp_detect ( struct hda_codec * codec , unsigned int res )
2005-07-04 17:51:39 +02:00
{
struct sigmatel_spec * spec = codec - > spec ;
struct auto_pin_cfg * cfg = & spec - > autocfg ;
int i , presence ;
2006-09-20 17:10:27 +02:00
presence = 0 ;
for ( i = 0 ; i < cfg - > hp_outs ; i + + ) {
2006-09-21 11:56:18 +02:00
presence = get_pin_presence ( codec , cfg - > hp_pins [ i ] ) ;
if ( presence )
break ;
2006-09-20 17:10:27 +02:00
}
2005-07-04 17:51:39 +02:00
if ( presence ) {
/* disable lineouts, enable hp */
for ( i = 0 ; i < cfg - > line_outs ; i + + )
stac92xx_reset_pinctl ( codec , cfg - > line_out_pins [ i ] ,
AC_PINCTL_OUT_EN ) ;
2006-09-20 17:10:27 +02:00
for ( i = 0 ; i < cfg - > speaker_outs ; i + + )
stac92xx_reset_pinctl ( codec , cfg - > speaker_pins [ i ] ,
AC_PINCTL_OUT_EN ) ;
2005-07-04 17:51:39 +02:00
} else {
/* enable lineouts, disable hp */
for ( i = 0 ; i < cfg - > line_outs ; i + + )
stac92xx_set_pinctl ( codec , cfg - > line_out_pins [ i ] ,
AC_PINCTL_OUT_EN ) ;
2006-09-20 17:10:27 +02:00
for ( i = 0 ; i < cfg - > speaker_outs ; i + + )
stac92xx_set_pinctl ( codec , cfg - > speaker_pins [ i ] ,
AC_PINCTL_OUT_EN ) ;
2005-07-04 17:51:39 +02:00
}
}
2006-09-21 11:56:18 +02:00
static void stac92xx_unsol_event ( struct hda_codec * codec , unsigned int res )
{
switch ( res > > 26 ) {
case STAC_HP_EVENT :
stac92xx_hp_detect ( codec , res ) ;
break ;
}
}
2005-06-27 15:06:52 +02:00
# ifdef CONFIG_PM
static int stac92xx_resume ( struct hda_codec * codec )
{
struct sigmatel_spec * spec = codec - > spec ;
int i ;
stac92xx_init ( codec ) ;
2006-08-23 18:31:34 +02:00
stac92xx_set_config_regs ( codec ) ;
2005-06-27 15:06:52 +02:00
for ( i = 0 ; i < spec - > num_mixers ; i + + )
snd_hda_resume_ctls ( codec , spec - > mixers [ i ] ) ;
if ( spec - > multiout . dig_out_nid )
snd_hda_resume_spdif_out ( codec ) ;
if ( spec - > dig_in_nid )
snd_hda_resume_spdif_in ( codec ) ;
return 0 ;
}
# endif
2005-04-13 14:45:30 +02:00
static struct hda_codec_ops stac92xx_patch_ops = {
. build_controls = stac92xx_build_controls ,
. build_pcms = stac92xx_build_pcms ,
. init = stac92xx_init ,
. free = stac92xx_free ,
2005-07-04 17:51:39 +02:00
. unsol_event = stac92xx_unsol_event ,
2005-06-27 15:06:52 +02:00
# ifdef CONFIG_PM
. resume = stac92xx_resume ,
# endif
2005-04-13 14:45:30 +02:00
} ;
static int patch_stac9200 ( struct hda_codec * codec )
{
struct sigmatel_spec * spec ;
2005-06-27 14:59:41 +02:00
int err ;
2005-04-13 14:45:30 +02:00
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 14:21:46 +02:00
spec = kzalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
2005-04-13 14:45:30 +02:00
if ( spec = = NULL )
return - ENOMEM ;
codec - > spec = spec ;
2006-08-23 18:31:34 +02:00
spec - > num_pins = 8 ;
spec - > pin_nids = stac9200_pin_nids ;
2006-11-24 17:07:44 +01:00
spec - > board_config = snd_hda_check_board_config ( codec , STAC_9200_MODELS ,
stac9200_models ,
stac9200_cfg_tbl ) ;
2006-08-23 18:31:34 +02:00
if ( spec - > board_config < 0 ) {
snd_printdd ( KERN_INFO " hda_codec: Unknown model for STAC9200, using BIOS defaults \n " ) ;
err = stac92xx_save_bios_config_regs ( codec ) ;
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
spec - > pin_configs = spec - > bios_pin_configs ;
} else {
2005-11-29 15:00:51 +01:00
spec - > pin_configs = stac9200_brd_tbl [ spec - > board_config ] ;
stac92xx_set_config_regs ( codec ) ;
}
2005-04-13 14:45:30 +02:00
spec - > multiout . max_channels = 2 ;
spec - > multiout . num_dacs = 1 ;
spec - > multiout . dac_nids = stac9200_dac_nids ;
spec - > adc_nids = stac9200_adc_nids ;
spec - > mux_nids = stac9200_mux_nids ;
2005-06-14 10:19:34 +02:00
spec - > num_muxes = 1 ;
2006-10-26 17:12:59 +02:00
spec - > num_dmics = 0 ;
2005-06-27 14:59:41 +02:00
spec - > init = stac9200_core_init ;
2005-04-13 14:45:30 +02:00
spec - > mixer = stac9200_mixer ;
2005-06-27 14:59:41 +02:00
err = stac9200_parse_auto_config ( codec ) ;
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
2005-04-13 14:45:30 +02:00
codec - > patch_ops = stac92xx_patch_ops ;
return 0 ;
}
2007-01-08 11:04:17 +01:00
static int patch_stac925x ( struct hda_codec * codec )
{
struct sigmatel_spec * spec ;
int err ;
spec = kzalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
if ( spec = = NULL )
return - ENOMEM ;
codec - > spec = spec ;
spec - > num_pins = 8 ;
spec - > pin_nids = stac925x_pin_nids ;
spec - > board_config = snd_hda_check_board_config ( codec , STAC_925x_MODELS ,
stac925x_models ,
stac925x_cfg_tbl ) ;
2007-02-08 17:50:10 +01:00
again :
2007-01-08 11:04:17 +01:00
if ( spec - > board_config < 0 ) {
snd_printdd ( KERN_INFO " hda_codec: Unknown model for STAC925x, using BIOS defaults \n " ) ;
err = stac92xx_save_bios_config_regs ( codec ) ;
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
spec - > pin_configs = spec - > bios_pin_configs ;
} else if ( stac925x_brd_tbl [ spec - > board_config ] ! = NULL ) {
spec - > pin_configs = stac925x_brd_tbl [ spec - > board_config ] ;
stac92xx_set_config_regs ( codec ) ;
}
spec - > multiout . max_channels = 2 ;
spec - > multiout . num_dacs = 1 ;
spec - > multiout . dac_nids = stac925x_dac_nids ;
spec - > adc_nids = stac925x_adc_nids ;
spec - > mux_nids = stac925x_mux_nids ;
spec - > num_muxes = 1 ;
spec - > num_dmics = 0 ;
spec - > init = stac925x_core_init ;
spec - > mixer = stac925x_mixer ;
err = stac92xx_parse_auto_config ( codec , 0x8 , 0x7 ) ;
2007-02-08 17:50:10 +01:00
if ( ! err ) {
if ( spec - > board_config < 0 ) {
printk ( KERN_WARNING " hda_codec: No auto-config is "
" available, default to model=ref \n " ) ;
spec - > board_config = STAC_925x_REF ;
goto again ;
}
err = - EINVAL ;
}
2007-01-08 11:04:17 +01:00
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
codec - > patch_ops = stac92xx_patch_ops ;
return 0 ;
}
2005-04-13 14:45:30 +02:00
static int patch_stac922x ( struct hda_codec * codec )
{
struct sigmatel_spec * spec ;
2005-06-27 14:59:41 +02:00
int err ;
2005-04-13 14:45:30 +02:00
[ALSA] Replace with kzalloc() - pci stuff
AD1889 driver,ATIIXP driver,ATIIXP-modem driver,AZT3328 driver
BT87x driver,CMIPCI driver,CS4281 driver,ENS1370/1+ driver
ES1938 driver,ES1968 driver,FM801 driver,Intel8x0 driver
Intel8x0-modem driver,Maestro3 driver,SonicVibes driver,VIA82xx driver
VIA82xx-modem driver,AC97 Codec,AK4531 codec,au88x0 driver
CA0106 driver,CS46xx driver,EMU10K1/EMU10K2 driver,HDA Codec driver
HDA generic driver,HDA Intel driver,ICE1712 driver,ICE1724 driver
KORG1212 driver,MIXART driver,NM256 driver,Trident driver,YMFPCI driver
Replace kcalloc(1,..) with kzalloc().
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2005-09-09 14:21:46 +02:00
spec = kzalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
2005-04-13 14:45:30 +02:00
if ( spec = = NULL )
return - ENOMEM ;
codec - > spec = spec ;
2006-08-23 18:31:34 +02:00
spec - > num_pins = 10 ;
spec - > pin_nids = stac922x_pin_nids ;
2006-11-24 17:07:44 +01:00
spec - > board_config = snd_hda_check_board_config ( codec , STAC_922X_MODELS ,
stac922x_models ,
stac922x_cfg_tbl ) ;
2007-02-16 13:27:18 +01:00
if ( spec - > board_config = = STAC_MACMINI ) {
spec - > gpio_mute = 1 ;
/* Intel Macs have all same PCI SSID, so we need to check
* codec SSID to distinguish the exact models
*/
switch ( codec - > subsystem_id ) {
case 0x106b1e00 :
spec - > board_config = STAC_MACBOOK_PRO ;
break ;
}
}
2007-02-08 17:50:10 +01:00
again :
2006-08-23 18:31:34 +02:00
if ( spec - > board_config < 0 ) {
snd_printdd ( KERN_INFO " hda_codec: Unknown model for STAC922x, "
" using BIOS defaults \n " ) ;
err = stac92xx_save_bios_config_regs ( codec ) ;
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
spec - > pin_configs = spec - > bios_pin_configs ;
} else if ( stac922x_brd_tbl [ spec - > board_config ] ! = NULL ) {
2005-11-29 15:00:51 +01:00
spec - > pin_configs = stac922x_brd_tbl [ spec - > board_config ] ;
stac92xx_set_config_regs ( codec ) ;
}
2005-04-13 14:45:30 +02:00
2005-06-27 14:59:41 +02:00
spec - > adc_nids = stac922x_adc_nids ;
spec - > mux_nids = stac922x_mux_nids ;
spec - > num_muxes = 2 ;
2006-10-26 17:12:59 +02:00
spec - > num_dmics = 0 ;
2005-06-27 14:59:41 +02:00
spec - > init = stac922x_core_init ;
2005-04-13 14:45:30 +02:00
spec - > mixer = stac922x_mixer ;
2005-06-27 14:59:41 +02:00
spec - > multiout . dac_nids = spec - > dac_nids ;
2006-06-28 15:52:16 +02:00
2006-01-23 15:27:49 +01:00
err = stac92xx_parse_auto_config ( codec , 0x08 , 0x09 ) ;
2007-02-08 17:50:10 +01:00
if ( ! err ) {
if ( spec - > board_config < 0 ) {
printk ( KERN_WARNING " hda_codec: No auto-config is "
" available, default to model=ref \n " ) ;
spec - > board_config = STAC_D945_REF ;
goto again ;
}
err = - EINVAL ;
}
2006-01-23 15:27:49 +01:00
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
codec - > patch_ops = stac92xx_patch_ops ;
return 0 ;
}
static int patch_stac927x ( struct hda_codec * codec )
{
struct sigmatel_spec * spec ;
int err ;
spec = kzalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
if ( spec = = NULL )
return - ENOMEM ;
codec - > spec = spec ;
2006-08-23 18:31:34 +02:00
spec - > num_pins = 14 ;
spec - > pin_nids = stac927x_pin_nids ;
2006-11-24 17:07:44 +01:00
spec - > board_config = snd_hda_check_board_config ( codec , STAC_927X_MODELS ,
stac927x_models ,
stac927x_cfg_tbl ) ;
2007-02-08 17:50:10 +01:00
again :
2006-08-23 18:31:34 +02:00
if ( spec - > board_config < 0 ) {
2006-01-23 15:27:49 +01:00
snd_printdd ( KERN_INFO " hda_codec: Unknown model for STAC927x, using BIOS defaults \n " ) ;
2006-08-23 18:31:34 +02:00
err = stac92xx_save_bios_config_regs ( codec ) ;
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
spec - > pin_configs = spec - > bios_pin_configs ;
} else if ( stac927x_brd_tbl [ spec - > board_config ] ! = NULL ) {
2006-01-23 15:27:49 +01:00
spec - > pin_configs = stac927x_brd_tbl [ spec - > board_config ] ;
stac92xx_set_config_regs ( codec ) ;
}
2006-08-22 19:44:45 +02:00
switch ( spec - > board_config ) {
2006-09-01 21:03:12 +02:00
case STAC_D965_3ST :
2006-08-22 19:44:45 +02:00
spec - > adc_nids = stac927x_adc_nids ;
spec - > mux_nids = stac927x_mux_nids ;
spec - > num_muxes = 3 ;
2006-10-26 17:12:59 +02:00
spec - > num_dmics = 0 ;
2006-09-01 21:03:12 +02:00
spec - > init = d965_core_init ;
2006-08-22 19:44:45 +02:00
spec - > mixer = stac9227_mixer ;
break ;
2006-09-01 21:03:12 +02:00
case STAC_D965_5ST :
spec - > adc_nids = stac927x_adc_nids ;
spec - > mux_nids = stac927x_mux_nids ;
spec - > num_muxes = 3 ;
2006-10-26 17:12:59 +02:00
spec - > num_dmics = 0 ;
2006-09-01 21:03:12 +02:00
spec - > init = d965_core_init ;
2006-08-22 19:44:45 +02:00
spec - > mixer = stac9227_mixer ;
break ;
default :
spec - > adc_nids = stac927x_adc_nids ;
spec - > mux_nids = stac927x_mux_nids ;
spec - > num_muxes = 3 ;
2006-10-26 17:12:59 +02:00
spec - > num_dmics = 0 ;
2006-08-22 19:44:45 +02:00
spec - > init = stac927x_core_init ;
spec - > mixer = stac927x_mixer ;
}
2006-01-23 15:27:49 +01:00
spec - > multiout . dac_nids = spec - > dac_nids ;
err = stac92xx_parse_auto_config ( codec , 0x1e , 0x20 ) ;
2007-02-08 17:50:10 +01:00
if ( ! err ) {
if ( spec - > board_config < 0 ) {
printk ( KERN_WARNING " hda_codec: No auto-config is "
" available, default to model=ref \n " ) ;
spec - > board_config = STAC_D965_REF ;
goto again ;
}
err = - EINVAL ;
}
2005-06-27 14:59:41 +02:00
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
2005-04-13 14:45:30 +02:00
codec - > patch_ops = stac92xx_patch_ops ;
return 0 ;
}
2006-07-31 12:49:34 +02:00
static int patch_stac9205 ( struct hda_codec * codec )
{
struct sigmatel_spec * spec ;
int err ;
spec = kzalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
if ( spec = = NULL )
return - ENOMEM ;
codec - > spec = spec ;
2006-08-23 18:31:34 +02:00
spec - > num_pins = 14 ;
spec - > pin_nids = stac9205_pin_nids ;
2006-11-24 17:07:44 +01:00
spec - > board_config = snd_hda_check_board_config ( codec , STAC_9205_MODELS ,
stac9205_models ,
stac9205_cfg_tbl ) ;
2007-02-08 17:50:10 +01:00
again :
2006-08-23 18:31:34 +02:00
if ( spec - > board_config < 0 ) {
snd_printdd ( KERN_INFO " hda_codec: Unknown model for STAC9205, using BIOS defaults \n " ) ;
err = stac92xx_save_bios_config_regs ( codec ) ;
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
spec - > pin_configs = spec - > bios_pin_configs ;
} else {
2006-07-31 12:49:34 +02:00
spec - > pin_configs = stac9205_brd_tbl [ spec - > board_config ] ;
stac92xx_set_config_regs ( codec ) ;
}
spec - > adc_nids = stac9205_adc_nids ;
spec - > mux_nids = stac9205_mux_nids ;
2006-10-26 17:12:59 +02:00
spec - > num_muxes = 2 ;
spec - > dmic_nids = stac9205_dmic_nids ;
spec - > num_dmics = 2 ;
spec - > dmux_nid = 0x1d ;
2006-07-31 12:49:34 +02:00
spec - > init = stac9205_core_init ;
spec - > mixer = stac9205_mixer ;
spec - > multiout . dac_nids = spec - > dac_nids ;
2006-12-18 13:17:28 +01:00
/* Configure GPIO0 as EAPD output */
snd_hda_codec_write ( codec , codec - > afg , 0 ,
AC_VERB_SET_GPIO_DIRECTION , 0x00000001 ) ;
/* Configure GPIO0 as CMOS */
snd_hda_codec_write ( codec , codec - > afg , 0 , 0x7e7 , 0x00000000 ) ;
/* Assert GPIO0 high */
snd_hda_codec_write ( codec , codec - > afg , 0 ,
AC_VERB_SET_GPIO_DATA , 0x00000001 ) ;
/* Enable GPIO0 */
snd_hda_codec_write ( codec , codec - > afg , 0 ,
AC_VERB_SET_GPIO_MASK , 0x00000001 ) ;
2006-07-31 12:49:34 +02:00
err = stac92xx_parse_auto_config ( codec , 0x1f , 0x20 ) ;
2007-02-08 17:50:10 +01:00
if ( ! err ) {
if ( spec - > board_config < 0 ) {
printk ( KERN_WARNING " hda_codec: No auto-config is "
" available, default to model=ref \n " ) ;
spec - > board_config = STAC_9205_REF ;
goto again ;
}
err = - EINVAL ;
}
2006-07-31 12:49:34 +02:00
if ( err < 0 ) {
stac92xx_free ( codec ) ;
return err ;
}
codec - > patch_ops = stac92xx_patch_ops ;
return 0 ;
}
2006-03-16 16:04:58 +01:00
/*
2006-08-22 17:15:47 +02:00
* STAC9872 hack
2006-03-16 16:04:58 +01:00
*/
2006-08-16 19:35:12 +02:00
/* static config for Sony VAIO FE550G and Sony VAIO AR */
2006-03-16 16:04:58 +01:00
static hda_nid_t vaio_dacs [ ] = { 0x2 } ;
# define VAIO_HP_DAC 0x5
static hda_nid_t vaio_adcs [ ] = { 0x8 /*,0x6*/ } ;
static hda_nid_t vaio_mux_nids [ ] = { 0x15 } ;
static struct hda_input_mux vaio_mux = {
. num_items = 2 ,
. items = {
2006-04-25 13:05:43 +02:00
/* { "HP", 0x0 }, */
{ " Line " , 0x1 } ,
2006-03-16 16:04:58 +01:00
{ " Mic " , 0x2 } ,
{ " PCM " , 0x3 } ,
}
} ;
static struct hda_verb vaio_init [ ] = {
{ 0x0a , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_HP } , /* HP <- 0x2 */
{ 0x0f , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_OUT } , /* Speaker <- 0x5 */
{ 0x0d , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_VREF80 } , /* Mic? (<- 0x2) */
{ 0x0e , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN } , /* CD */
{ 0x14 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_VREF80 } , /* Mic? */
{ 0x15 , AC_VERB_SET_CONNECT_SEL , 0x2 } , /* mic-sel: 0a,0d,14,02 */
{ 0x02 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_MUTE } , /* HP */
{ 0x05 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_MUTE } , /* Speaker */
{ 0x09 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } , /* capture sw/vol -> 0x8 */
{ 0x07 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_UNMUTE ( 0 ) } , /* CD-in -> 0x6 */
{ 0x15 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_UNMUTE } , /* Mic-in -> 0x9 */
{ }
} ;
2006-08-22 17:15:47 +02:00
static struct hda_verb vaio_ar_init [ ] = {
{ 0x0a , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_HP } , /* HP <- 0x2 */
{ 0x0f , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_OUT } , /* Speaker <- 0x5 */
{ 0x0d , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_VREF80 } , /* Mic? (<- 0x2) */
{ 0x0e , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_IN } , /* CD */
/* {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },*/ /* Optical Out */
{ 0x14 , AC_VERB_SET_PIN_WIDGET_CONTROL , PIN_VREF80 } , /* Mic? */
{ 0x15 , AC_VERB_SET_CONNECT_SEL , 0x2 } , /* mic-sel: 0a,0d,14,02 */
{ 0x02 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_MUTE } , /* HP */
{ 0x05 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_MUTE } , /* Speaker */
/* {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},*/ /* Optical Out */
{ 0x09 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_MUTE ( 0 ) } , /* capture sw/vol -> 0x8 */
{ 0x07 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_IN_UNMUTE ( 0 ) } , /* CD-in -> 0x6 */
{ 0x15 , AC_VERB_SET_AMP_GAIN_MUTE , AMP_OUT_UNMUTE } , /* Mic-in -> 0x9 */
{ }
} ;
2006-03-16 16:04:58 +01:00
/* bind volumes of both NID 0x02 and 0x05 */
static int vaio_master_vol_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
long * valp = ucontrol - > value . integer . value ;
int change ;
change = snd_hda_codec_amp_update ( codec , 0x02 , 0 , HDA_OUTPUT , 0 ,
0x7f , valp [ 0 ] & 0x7f ) ;
change | = snd_hda_codec_amp_update ( codec , 0x02 , 1 , HDA_OUTPUT , 0 ,
0x7f , valp [ 1 ] & 0x7f ) ;
snd_hda_codec_amp_update ( codec , 0x05 , 0 , HDA_OUTPUT , 0 ,
0x7f , valp [ 0 ] & 0x7f ) ;
snd_hda_codec_amp_update ( codec , 0x05 , 1 , HDA_OUTPUT , 0 ,
0x7f , valp [ 1 ] & 0x7f ) ;
return change ;
}
/* bind volumes of both NID 0x02 and 0x05 */
static int vaio_master_sw_put ( struct snd_kcontrol * kcontrol ,
struct snd_ctl_elem_value * ucontrol )
{
struct hda_codec * codec = snd_kcontrol_chip ( kcontrol ) ;
long * valp = ucontrol - > value . integer . value ;
int change ;
change = snd_hda_codec_amp_update ( codec , 0x02 , 0 , HDA_OUTPUT , 0 ,
2006-05-03 11:59:03 +02:00
0x80 , ( valp [ 0 ] ? 0 : 0x80 ) ) ;
2006-03-16 16:04:58 +01:00
change | = snd_hda_codec_amp_update ( codec , 0x02 , 1 , HDA_OUTPUT , 0 ,
2006-05-03 11:59:03 +02:00
0x80 , ( valp [ 1 ] ? 0 : 0x80 ) ) ;
2006-03-16 16:04:58 +01:00
snd_hda_codec_amp_update ( codec , 0x05 , 0 , HDA_OUTPUT , 0 ,
2006-05-03 11:59:03 +02:00
0x80 , ( valp [ 0 ] ? 0 : 0x80 ) ) ;
2006-03-16 16:04:58 +01:00
snd_hda_codec_amp_update ( codec , 0x05 , 1 , HDA_OUTPUT , 0 ,
2006-05-03 11:59:03 +02:00
0x80 , ( valp [ 1 ] ? 0 : 0x80 ) ) ;
2006-03-16 16:04:58 +01:00
return change ;
}
static struct snd_kcontrol_new vaio_mixer [ ] = {
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Master Playback Volume " ,
. info = snd_hda_mixer_amp_volume_info ,
. get = snd_hda_mixer_amp_volume_get ,
. put = vaio_master_vol_put ,
2006-08-17 18:21:36 +02:00
. tlv = { . c = snd_hda_mixer_amp_tlv } ,
2006-03-16 16:04:58 +01:00
. private_value = HDA_COMPOSE_AMP_VAL ( 0x02 , 3 , 0 , HDA_OUTPUT ) ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Master Playback Switch " ,
. info = snd_hda_mixer_amp_switch_info ,
. get = snd_hda_mixer_amp_switch_get ,
. put = vaio_master_sw_put ,
. private_value = HDA_COMPOSE_AMP_VAL ( 0x02 , 3 , 0 , HDA_OUTPUT ) ,
} ,
/* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
HDA_CODEC_VOLUME ( " Capture Volume " , 0x09 , 0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Capture Switch " , 0x09 , 0 , HDA_INPUT ) ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Capture Source " ,
. count = 1 ,
. info = stac92xx_mux_enum_info ,
. get = stac92xx_mux_enum_get ,
. put = stac92xx_mux_enum_put ,
} ,
{ }
} ;
2006-08-22 17:15:47 +02:00
static struct snd_kcontrol_new vaio_ar_mixer [ ] = {
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Master Playback Volume " ,
. info = snd_hda_mixer_amp_volume_info ,
. get = snd_hda_mixer_amp_volume_get ,
. put = vaio_master_vol_put ,
. private_value = HDA_COMPOSE_AMP_VAL ( 0x02 , 3 , 0 , HDA_OUTPUT ) ,
} ,
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Master Playback Switch " ,
. info = snd_hda_mixer_amp_switch_info ,
. get = snd_hda_mixer_amp_switch_get ,
. put = vaio_master_sw_put ,
. private_value = HDA_COMPOSE_AMP_VAL ( 0x02 , 3 , 0 , HDA_OUTPUT ) ,
} ,
/* HDA_CODEC_VOLUME("CD Capture Volume", 0x07, 0, HDA_INPUT), */
HDA_CODEC_VOLUME ( " Capture Volume " , 0x09 , 0 , HDA_INPUT ) ,
HDA_CODEC_MUTE ( " Capture Switch " , 0x09 , 0 , HDA_INPUT ) ,
/*HDA_CODEC_MUTE("Optical Out Switch", 0x10, 0, HDA_OUTPUT),
HDA_CODEC_VOLUME ( " Optical Out Volume " , 0x10 , 0 , HDA_OUTPUT ) , */
{
. iface = SNDRV_CTL_ELEM_IFACE_MIXER ,
. name = " Capture Source " ,
. count = 1 ,
. info = stac92xx_mux_enum_info ,
. get = stac92xx_mux_enum_get ,
. put = stac92xx_mux_enum_put ,
} ,
{ }
} ;
static struct hda_codec_ops stac9872_patch_ops = {
2006-03-16 16:04:58 +01:00
. build_controls = stac92xx_build_controls ,
. build_pcms = stac92xx_build_pcms ,
. init = stac92xx_init ,
. free = stac92xx_free ,
# ifdef CONFIG_PM
. resume = stac92xx_resume ,
# endif
} ;
2006-08-22 17:15:47 +02:00
enum { /* FE and SZ series. id=0x83847661 and subsys=0x104D0700 or 104D1000. */
CXD9872RD_VAIO ,
/* Unknown. id=0x83847662 and subsys=0x104D1200 or 104D1000. */
STAC9872AK_VAIO ,
/* Unknown. id=0x83847661 and subsys=0x104D1200. */
STAC9872K_VAIO ,
/* AR Series. id=0x83847664 and subsys=104D1300 */
2006-11-24 17:07:44 +01:00
CXD9872AKD_VAIO ,
STAC_9872_MODELS ,
} ;
static const char * stac9872_models [ STAC_9872_MODELS ] = {
[ CXD9872RD_VAIO ] = " vaio " ,
[ CXD9872AKD_VAIO ] = " vaio-ar " ,
} ;
static struct snd_pci_quirk stac9872_cfg_tbl [ ] = {
SND_PCI_QUIRK ( 0x104d , 0x81e6 , " Sony VAIO F/S " , CXD9872RD_VAIO ) ,
SND_PCI_QUIRK ( 0x104d , 0x81ef , " Sony VAIO F/S " , CXD9872RD_VAIO ) ,
SND_PCI_QUIRK ( 0x104d , 0x81fd , " Sony VAIO AR " , CXD9872AKD_VAIO ) ,
2006-03-16 16:04:58 +01:00
{ }
} ;
2006-08-22 17:15:47 +02:00
static int patch_stac9872 ( struct hda_codec * codec )
2006-03-16 16:04:58 +01:00
{
struct sigmatel_spec * spec ;
int board_config ;
2006-11-24 17:07:44 +01:00
board_config = snd_hda_check_board_config ( codec , STAC_9872_MODELS ,
stac9872_models ,
stac9872_cfg_tbl ) ;
2006-03-16 16:04:58 +01:00
if ( board_config < 0 )
/* unknown config, let generic-parser do its job... */
return snd_hda_parse_generic_codec ( codec ) ;
spec = kzalloc ( sizeof ( * spec ) , GFP_KERNEL ) ;
if ( spec = = NULL )
return - ENOMEM ;
codec - > spec = spec ;
switch ( board_config ) {
2006-08-22 17:15:47 +02:00
case CXD9872RD_VAIO :
case STAC9872AK_VAIO :
case STAC9872K_VAIO :
2006-03-16 16:04:58 +01:00
spec - > mixer = vaio_mixer ;
spec - > init = vaio_init ;
spec - > multiout . max_channels = 2 ;
spec - > multiout . num_dacs = ARRAY_SIZE ( vaio_dacs ) ;
spec - > multiout . dac_nids = vaio_dacs ;
spec - > multiout . hp_nid = VAIO_HP_DAC ;
spec - > num_adcs = ARRAY_SIZE ( vaio_adcs ) ;
spec - > adc_nids = vaio_adcs ;
spec - > input_mux = & vaio_mux ;
spec - > mux_nids = vaio_mux_nids ;
break ;
2006-08-22 17:15:47 +02:00
case CXD9872AKD_VAIO :
spec - > mixer = vaio_ar_mixer ;
spec - > init = vaio_ar_init ;
spec - > multiout . max_channels = 2 ;
spec - > multiout . num_dacs = ARRAY_SIZE ( vaio_dacs ) ;
spec - > multiout . dac_nids = vaio_dacs ;
spec - > multiout . hp_nid = VAIO_HP_DAC ;
spec - > num_adcs = ARRAY_SIZE ( vaio_adcs ) ;
spec - > adc_nids = vaio_adcs ;
spec - > input_mux = & vaio_mux ;
spec - > mux_nids = vaio_mux_nids ;
break ;
2006-03-16 16:04:58 +01:00
}
2006-08-22 17:15:47 +02:00
codec - > patch_ops = stac9872_patch_ops ;
2006-03-16 16:04:58 +01:00
return 0 ;
}
2005-04-13 14:45:30 +02:00
/*
* patch entries
*/
struct hda_codec_preset snd_hda_preset_sigmatel [ ] = {
{ . id = 0x83847690 , . name = " STAC9200 " , . patch = patch_stac9200 } ,
{ . id = 0x83847882 , . name = " STAC9220 A1 " , . patch = patch_stac922x } ,
{ . id = 0x83847680 , . name = " STAC9221 A1 " , . patch = patch_stac922x } ,
{ . id = 0x83847880 , . name = " STAC9220 A2 " , . patch = patch_stac922x } ,
{ . id = 0x83847681 , . name = " STAC9220D/9223D A2 " , . patch = patch_stac922x } ,
{ . id = 0x83847682 , . name = " STAC9221 A2 " , . patch = patch_stac922x } ,
{ . id = 0x83847683 , . name = " STAC9221D A2 " , . patch = patch_stac922x } ,
2006-07-06 18:49:10 +02:00
{ . id = 0x83847618 , . name = " STAC9227 " , . patch = patch_stac927x } ,
{ . id = 0x83847619 , . name = " STAC9227 " , . patch = patch_stac927x } ,
{ . id = 0x83847616 , . name = " STAC9228 " , . patch = patch_stac927x } ,
{ . id = 0x83847617 , . name = " STAC9228 " , . patch = patch_stac927x } ,
{ . id = 0x83847614 , . name = " STAC9229 " , . patch = patch_stac927x } ,
{ . id = 0x83847615 , . name = " STAC9229 " , . patch = patch_stac927x } ,
2006-01-23 15:27:49 +01:00
{ . id = 0x83847620 , . name = " STAC9274 " , . patch = patch_stac927x } ,
{ . id = 0x83847621 , . name = " STAC9274D " , . patch = patch_stac927x } ,
{ . id = 0x83847622 , . name = " STAC9273X " , . patch = patch_stac927x } ,
{ . id = 0x83847623 , . name = " STAC9273D " , . patch = patch_stac927x } ,
{ . id = 0x83847624 , . name = " STAC9272X " , . patch = patch_stac927x } ,
{ . id = 0x83847625 , . name = " STAC9272D " , . patch = patch_stac927x } ,
{ . id = 0x83847626 , . name = " STAC9271X " , . patch = patch_stac927x } ,
{ . id = 0x83847627 , . name = " STAC9271D " , . patch = patch_stac927x } ,
{ . id = 0x83847628 , . name = " STAC9274X5NH " , . patch = patch_stac927x } ,
{ . id = 0x83847629 , . name = " STAC9274D5NH " , . patch = patch_stac927x } ,
2007-01-08 11:04:17 +01:00
{ . id = 0x83847632 , . name = " STAC9202 " , . patch = patch_stac925x } ,
{ . id = 0x83847633 , . name = " STAC9202D " , . patch = patch_stac925x } ,
{ . id = 0x83847634 , . name = " STAC9250 " , . patch = patch_stac925x } ,
{ . id = 0x83847635 , . name = " STAC9250D " , . patch = patch_stac925x } ,
{ . id = 0x83847636 , . name = " STAC9251 " , . patch = patch_stac925x } ,
{ . id = 0x83847637 , . name = " STAC9250D " , . patch = patch_stac925x } ,
2006-08-22 17:15:47 +02:00
/* The following does not take into account .id=0x83847661 when subsys =
* 104 D0C00 which is STAC9225s . Because of this , some SZ Notebooks are
* currently not fully supported .
*/
{ . id = 0x83847661 , . name = " CXD9872RD/K " , . patch = patch_stac9872 } ,
{ . id = 0x83847662 , . name = " STAC9872AK " , . patch = patch_stac9872 } ,
{ . id = 0x83847664 , . name = " CXD9872AKD " , . patch = patch_stac9872 } ,
2006-07-31 12:49:34 +02:00
{ . id = 0x838476a0 , . name = " STAC9205 " , . patch = patch_stac9205 } ,
{ . id = 0x838476a1 , . name = " STAC9205D " , . patch = patch_stac9205 } ,
{ . id = 0x838476a2 , . name = " STAC9204 " , . patch = patch_stac9205 } ,
{ . id = 0x838476a3 , . name = " STAC9204D " , . patch = patch_stac9205 } ,
{ . id = 0x838476a4 , . name = " STAC9255 " , . patch = patch_stac9205 } ,
{ . id = 0x838476a5 , . name = " STAC9255D " , . patch = patch_stac9205 } ,
{ . id = 0x838476a6 , . name = " STAC9254 " , . patch = patch_stac9205 } ,
{ . id = 0x838476a7 , . name = " STAC9254D " , . patch = patch_stac9205 } ,
2005-04-13 14:45:30 +02:00
{ } /* terminator */
} ;