@ -94,6 +94,18 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
struct wm_hubs_data * hubs = snd_soc_codec_get_drvdata ( codec ) ;
u16 reg , reg_l , reg_r , dcs_cfg ;
/* If we're using a digital only path and have a previously
* callibrated DC servo offset stored then use that . */
if ( hubs - > class_w & & hubs - > class_w_dcs ) {
dev_dbg ( codec - > dev , " Using cached DC servo offset %x \n " ,
hubs - > class_w_dcs ) ;
snd_soc_write ( codec , WM8993_DC_SERVO_3 , hubs - > class_w_dcs ) ;
wait_for_dc_servo ( codec ,
WM8993_DCS_TRIG_DAC_WR_0 |
WM8993_DCS_TRIG_DAC_WR_1 ) ;
return ;
}
/* Set for 32 series updates */
snd_soc_update_bits ( codec , WM8993_DC_SERVO_1 ,
WM8993_DCS_SERIES_NO_01_MASK ,
@ -101,34 +113,34 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
wait_for_dc_servo ( codec ,
WM8993_DCS_TRIG_SERIES_0 | WM8993_DCS_TRIG_SERIES_1 ) ;
/* Different chips in the family support different readback
* methods .
*/
switch ( hubs - > dcs_readback_mode ) {
case 0 :
reg_l = snd_soc_read ( codec , WM8993_DC_SERVO_READBACK_1 )
& WM8993_DCS_INTEG_CHAN_0_MASK ; ;
reg_r = snd_soc_read ( codec , WM8993_DC_SERVO_READBACK_2 )
& WM8993_DCS_INTEG_CHAN_1_MASK ;
break ;
case 1 :
reg = snd_soc_read ( codec , WM8993_DC_SERVO_3 ) ;
reg_l = ( reg & WM8993_DCS_DAC_WR_VAL_1_MASK )
> > WM8993_DCS_DAC_WR_VAL_1_SHIFT ;
reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK ;
break ;
default :
WARN ( 1 , " Unknown DCS readback method " ) ;
break ;
}
dev_dbg ( codec - > dev , " DCS input: %x %x \n " , reg_l , reg_r ) ;
/* Apply correction to DC servo result */
if ( hubs - > dcs_codes ) {
dev_dbg ( codec - > dev , " Applying %d code DC servo correction \n " ,
hubs - > dcs_codes ) ;
/* Different chips in the family support different
* readback methods .
*/
switch ( hubs - > dcs_readback_mode ) {
case 0 :
reg_l = snd_soc_read ( codec , WM8993_DC_SERVO_READBACK_1 )
& WM8993_DCS_INTEG_CHAN_0_MASK ; ;
reg_r = snd_soc_read ( codec , WM8993_DC_SERVO_READBACK_2 )
& WM8993_DCS_INTEG_CHAN_1_MASK ;
break ;
case 1 :
reg = snd_soc_read ( codec , WM8993_DC_SERVO_3 ) ;
reg_l = ( reg & WM8993_DCS_DAC_WR_VAL_1_MASK )
> > WM8993_DCS_DAC_WR_VAL_1_SHIFT ;
reg_r = reg & WM8993_DCS_DAC_WR_VAL_0_MASK ;
break ;
default :
WARN ( 1 , " Unknown DCS readback method " ) ;
break ;
}
dev_dbg ( codec - > dev , " DCS input: %x %x \n " , reg_l , reg_r ) ;
/* HPOUT1L */
if ( reg_l + hubs - > dcs_codes > 0 & &
reg_l + hubs - > dcs_codes < 0xff )
@ -148,7 +160,15 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
wait_for_dc_servo ( codec ,
WM8993_DCS_TRIG_DAC_WR_0 |
WM8993_DCS_TRIG_DAC_WR_1 ) ;
} else {
dcs_cfg = reg_l < < WM8993_DCS_DAC_WR_VAL_1_SHIFT ;
dcs_cfg | = reg_r ;
}
/* Save the callibrated offset if we're in class W mode and
* therefore don ' t have any analogue signal mixed in . */
if ( hubs - > class_w )
hubs - > class_w_dcs = dcs_cfg ;
}
/*
@ -163,6 +183,9 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
ret = snd_soc_put_volsw_2r ( kcontrol , ucontrol ) ;
/* Updating the analogue gains invalidates the DC servo cache */
hubs - > class_w_dcs = 0 ;
/* If we're applying an offset correction then updating the
* callibration would be likely to introduce further offsets . */
if ( hubs - > dcs_codes )