@ -1172,6 +1172,59 @@ static int dspio_write_multiple(struct hda_codec *codec,
return status ;
}
static int dspio_read ( struct hda_codec * codec , unsigned int * data )
{
int status ;
status = dspio_send ( codec , VENDOR_DSPIO_SCP_POST_READ_DATA , 0 ) ;
if ( status = = - EIO )
return status ;
status = dspio_send ( codec , VENDOR_DSPIO_STATUS , 0 ) ;
if ( status = = - EIO | |
status = = VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY )
return - EIO ;
* data = snd_hda_codec_read ( codec , WIDGET_DSP_CTRL , 0 ,
VENDOR_DSPIO_SCP_READ_DATA , 0 ) ;
return 0 ;
}
static int dspio_read_multiple ( struct hda_codec * codec , unsigned int * buffer ,
unsigned int * buf_size , unsigned int size_count )
{
int status = 0 ;
unsigned int size = * buf_size ;
unsigned int count ;
unsigned int skip_count ;
unsigned int dummy ;
if ( ( buffer = = NULL ) )
return - 1 ;
count = 0 ;
while ( count < size & & count < size_count ) {
status = dspio_read ( codec , buffer + + ) ;
if ( status ! = 0 )
break ;
count + + ;
}
skip_count = count ;
if ( status = = 0 ) {
while ( skip_count < size ) {
status = dspio_read ( codec , & dummy ) ;
if ( status ! = 0 )
break ;
skip_count + + ;
}
}
* buf_size = count ;
return status ;
}
/*
* Construct the SCP header using corresponding fields
*/
@ -1231,6 +1284,38 @@ struct scp_msg {
unsigned int data [ SCP_MAX_DATA_WORDS ] ;
} ;
static void dspio_clear_response_queue ( struct hda_codec * codec )
{
unsigned int dummy = 0 ;
int status = - 1 ;
/* clear all from the response queue */
do {
status = dspio_read ( codec , & dummy ) ;
} while ( status = = 0 ) ;
}
static int dspio_get_response_data ( struct hda_codec * codec )
{
struct ca0132_spec * spec = codec - > spec ;
unsigned int data = 0 ;
unsigned int count ;
if ( dspio_read ( codec , & data ) < 0 )
return - EIO ;
if ( ( data & 0x00ffffff ) = = spec - > wait_scp_header ) {
spec - > scp_resp_header = data ;
spec - > scp_resp_count = data > > 27 ;
count = spec - > wait_num_data ;
dspio_read_multiple ( codec , spec - > scp_resp_data ,
& spec - > scp_resp_count , count ) ;
return 0 ;
}
return - EIO ;
}
/*
* Send SCP message to DSP
*/
@ -3743,6 +3828,12 @@ static int ca0132_build_controls(struct hda_codec *codec)
return 0 ;
}
static void ca0132_init_unsol ( struct hda_codec * codec )
{
snd_hda_jack_detect_enable ( codec , UNSOL_TAG_HP , UNSOL_TAG_HP ) ;
snd_hda_jack_detect_enable ( codec , UNSOL_TAG_AMIC1 , UNSOL_TAG_AMIC1 ) ;
}
static void refresh_amp_caps ( struct hda_codec * codec , hda_nid_t nid , int dir )
{
unsigned int caps ;
@ -4152,6 +4243,47 @@ static void ca0132_download_dsp(struct hda_codec *codec)
ca0132_set_dsp_msr ( codec , true ) ;
}
static void ca0132_process_dsp_response ( struct hda_codec * codec )
{
struct ca0132_spec * spec = codec - > spec ;
snd_printdd ( KERN_INFO " ca0132_process_dsp_response \n " ) ;
if ( spec - > wait_scp ) {
if ( dspio_get_response_data ( codec ) > = 0 )
spec - > wait_scp = 0 ;
}
dspio_clear_response_queue ( codec ) ;
}
static void ca0132_unsol_event ( struct hda_codec * codec , unsigned int res )
{
snd_printdd ( KERN_INFO " ca0132_unsol_event: 0x%x \n " , res ) ;
if ( ( ( res > > AC_UNSOL_RES_TAG_SHIFT ) & 0x3f ) = = UNSOL_TAG_DSP ) {
ca0132_process_dsp_response ( codec ) ;
} else {
res = snd_hda_jack_get_action ( codec ,
( res > > AC_UNSOL_RES_TAG_SHIFT ) & 0x3f ) ;
snd_printdd ( KERN_INFO " snd_hda_jack_get_action: 0x%x \n " , res ) ;
switch ( res ) {
case UNSOL_TAG_HP :
ca0132_select_out ( codec ) ;
snd_hda_jack_report_sync ( codec ) ;
break ;
case UNSOL_TAG_AMIC1 :
ca0132_select_mic ( codec ) ;
snd_hda_jack_report_sync ( codec ) ;
break ;
default :
break ;
}
}
}
static int ca0132_init ( struct hda_codec * codec )
{
struct ca0132_spec * spec = codec - > spec ;
@ -4187,9 +4319,13 @@ static int ca0132_init(struct hda_codec *codec)
for ( i = 0 ; i < spec - > num_init_verbs ; i + + )
snd_hda_sequence_write ( codec , spec - > init_verbs [ i ] ) ;
ca0132_init_unsol ( codec ) ;
ca0132_select_out ( codec ) ;
ca0132_select_mic ( codec ) ;
snd_hda_jack_report_sync ( codec ) ;
snd_hda_power_down ( codec ) ;
return 0 ;
@ -4211,11 +4347,13 @@ static struct hda_codec_ops ca0132_patch_ops = {
. build_pcms = ca0132_build_pcms ,
. init = ca0132_init ,
. free = ca0132_free ,
. unsol_event = ca0132_unsol_event ,
} ;
static int patch_ca0132 ( struct hda_codec * codec )
{
struct ca0132_spec * spec ;
int err ;
snd_printdd ( " patch_ca0132 \n " ) ;
@ -4237,6 +4375,10 @@ static int patch_ca0132(struct hda_codec *codec)
ca0132_config ( codec ) ;
err = snd_hda_parse_pin_def_config ( codec , & spec - > autocfg , NULL ) ;
if ( err < 0 )
return err ;
codec - > patch_ops = ca0132_patch_ops ;
return 0 ;