aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-10-21 12:08:42 -0700
committerArve Hjønnevåg <arve@android.com>2011-11-17 17:51:26 -0800
commitc54363c80b2b84a92bb1954017c2177df1343d06 (patch)
tree834c5c5cd007503890de85ecf8d6fd0bb1c8fa04
parentf285e2c3263b94563bde469328e7915929d62b73 (diff)
downloadkernel_samsung_crespo-c54363c80b2b84a92bb1954017c2177df1343d06.zip
kernel_samsung_crespo-c54363c80b2b84a92bb1954017c2177df1343d06.tar.gz
kernel_samsung_crespo-c54363c80b2b84a92bb1954017c2177df1343d06.tar.bz2
ASoC: Save and restore DC servo state when unchanged
We only need to recalibrate the DC servo configuration when the analogue configuration is changed, which in this system means whenver the analogue volume is changed or whenever the path is changed. Use this to save the ~160ms taken by the recalibration by saving the value per-path We still need to recalibrate after volume changes and the first time a given path is used but these should be much less frequent events than headphone enable. Change-Id: I706fe161f5cc0709e58d7702b28796ed85c51384 Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
-rw-r--r--sound/soc/codecs/wm8994_herring.c75
-rwxr-xr-xsound/soc/codecs/wm8994_samsung.c7
-rwxr-xr-xsound/soc/codecs/wm8994_samsung.h7
3 files changed, 64 insertions, 25 deletions
diff --git a/sound/soc/codecs/wm8994_herring.c b/sound/soc/codecs/wm8994_herring.c
index e9ee4c4..f8c3d9a 100644
--- a/sound/soc/codecs/wm8994_herring.c
+++ b/sound/soc/codecs/wm8994_herring.c
@@ -1404,18 +1404,25 @@ void wm8994_set_playback_headset(struct snd_soc_codec *codec)
WM8994_MIXOUTL_ENA | WM8994_MIXOUTR_ENA);
wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, 0x0030);
- wait_for_dc_servo(codec,
- WM8994_DCS_TRIG_SERIES_0 | WM8994_DCS_TRIG_SERIES_1);
+ if (!wm8994->dc_servo[DCS_MEDIA]) {
+ wait_for_dc_servo(codec,
+ WM8994_DCS_TRIG_SERIES_0 |
+ WM8994_DCS_TRIG_SERIES_1);
+
+ testreturn1 = wm8994_read(codec, WM8994_DC_SERVO_4);
- testreturn1 = wm8994_read(codec, WM8994_DC_SERVO_4);
+ testlow = (signed char)(testreturn1 & 0xff);
+ testhigh = (signed char)((testreturn1>>8) & 0xff);
- testlow = (signed char)(testreturn1 & 0xff);
- testhigh = (signed char)((testreturn1>>8) & 0xff);
+ testlow1 = ((signed short)(testlow-5)) & 0x00ff;
+ testhigh1 = (((signed short)(testhigh-5)<<8) & 0xff00);
+ testreturn2 = testlow1|testhigh1;
+ } else {
+ testreturn2 = wm8994->dc_servo[DCS_MEDIA];
+ }
- testlow1 = ((signed short)(testlow-5)) & 0x00ff;
- testhigh1 = (((signed short)(testhigh-5)<<8) & 0xff00);
- testreturn2 = testlow1|testhigh1;
wm8994_write(codec, WM8994_DC_SERVO_4, testreturn2);
+ wm8994->dc_servo[DCS_MEDIA] = testreturn2;
wait_for_dc_servo(codec,
WM8994_DCS_TRIG_DAC_WR_0 | WM8994_DCS_TRIG_DAC_WR_1);
@@ -1691,17 +1698,27 @@ void wm8994_set_playback_speaker_headset(struct snd_soc_codec *codec)
wm8994_write(codec, WM8994_POWER_MANAGEMENT_3, val);
/* DC Servo */
- wait_for_dc_servo(codec,
- WM8994_DCS_TRIG_SERIES_0 | WM8994_DCS_TRIG_SERIES_1);
-
- nreadservo4val = wm8994_read(codec, WM8994_DC_SERVO_4);
- nservo4low = (signed char)(nreadservo4val & 0xff);
- nservo4high = (signed char)((nreadservo4val>>8) & 0xff);
+ if (!wm8994->dc_servo[DCS_SPK_HP]) {
+ wait_for_dc_servo(codec,
+ WM8994_DCS_TRIG_SERIES_0 |
+ WM8994_DCS_TRIG_SERIES_1);
+
+ nreadservo4val = wm8994_read(codec, WM8994_DC_SERVO_4);
+ nservo4low = (signed char)(nreadservo4val & 0xff);
+ nservo4high = (signed char)((nreadservo4val>>8) & 0xff);
+
+ ncompensationresultlow = ((signed short)nservo4low - 5)
+ & 0x00ff;
+ ncompensationresulthigh = ((signed short)(nservo4high - 5)<<8)
+ & 0xff00;
+ ncompensationresult = ncompensationresultlow |
+ ncompensationresulthigh;
+ } else {
+ ncompensationresult = wm8994->dc_servo[DCS_SPK_HP];
+ }
- ncompensationresultlow = ((signed short)nservo4low - 5) & 0x00ff;
- ncompensationresulthigh = ((signed short)(nservo4high - 5)<<8) & 0xff00;
- ncompensationresult = ncompensationresultlow|ncompensationresulthigh;
wm8994_write(codec, WM8994_DC_SERVO_4, ncompensationresult);
+ wm8994->dc_servo[DCS_SPK_HP] = ncompensationresult;
wait_for_dc_servo(codec,
WM8994_DCS_TRIG_DAC_WR_1 | WM8994_DCS_TRIG_DAC_WR_0 |
@@ -2088,22 +2105,30 @@ void wm8994_set_voicecall_headset(struct snd_soc_codec *codec)
wm8994_write(codec, WM8994_AIF2_CLOCKING_1, 0x0019);
- wait_for_dc_servo(codec,
- WM8994_DCS_TRIG_SERIES_0 | WM8994_DCS_TRIG_SERIES_1);
+ if (!wm8994->dc_servo[DCS_VOICE]) {
+ wait_for_dc_servo(codec,
+ WM8994_DCS_TRIG_SERIES_0 |
+ WM8994_DCS_TRIG_SERIES_1);
+
+ testreturn1 = wm8994_read(codec, WM8994_DC_SERVO_4);
- testreturn1 = wm8994_read(codec, WM8994_DC_SERVO_4);
+ testlow = (signed char)(testreturn1 & 0xff);
+ testhigh = (signed char)((testreturn1>>8) & 0xff);
- testlow = (signed char)(testreturn1 & 0xff);
- testhigh = (signed char)((testreturn1>>8) & 0xff);
+ testlow1 = ((signed short)testlow - 5) & 0x00ff;
+ testhigh1 = (((signed short)(testhigh - 5)<<8) & 0xff00);
+ testreturn2 = testlow1|testhigh1;
+ } else {
+ testreturn2 = wm8994->dc_servo[DCS_VOICE];
+ }
- testlow1 = ((signed short)testlow - 5) & 0x00ff;
- testhigh1 = (((signed short)(testhigh - 5)<<8) & 0xff00);
- testreturn2 = testlow1|testhigh1;
wm8994_write(codec, WM8994_DC_SERVO_4, testreturn2);
wait_for_dc_servo(codec,
WM8994_DCS_TRIG_DAC_WR_0 | WM8994_DCS_TRIG_DAC_WR_1);
+ wm8994->dc_servo[DCS_VOICE] = testreturn2;
+
wm8994_write(codec, WM8994_ANALOGUE_HP_1, 0x00EE);
wm8994_set_codec_gain(codec, VOICECALL_MODE, VOICECALL_HP);
diff --git a/sound/soc/codecs/wm8994_samsung.c b/sound/soc/codecs/wm8994_samsung.c
index adfb009..e48348d 100755
--- a/sound/soc/codecs/wm8994_samsung.c
+++ b/sound/soc/codecs/wm8994_samsung.c
@@ -228,6 +228,7 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int reg = mc->reg;
+ struct wm8994_priv *wm8994 = codec->drvdata;
DEBUG_LOG("");
@@ -235,6 +236,12 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol,
if (ret < 0)
return ret;
+ /* Volume changes in the headphone path mean we need to
+ * recallibrate DC servo */
+ if (strcmp(kcontrol->id.name, "Playback Spkr Volume") == 0 ||
+ strcmp(kcontrol->id.name, "Playback Volume") == 0)
+ memset(wm8994->dc_servo, 0, sizeof(wm8994->dc_servo));
+
val = wm8994_read(codec, reg);
return wm8994_write(codec, reg, val | 0x0100);
diff --git a/sound/soc/codecs/wm8994_samsung.h b/sound/soc/codecs/wm8994_samsung.h
index fa0c4a8..5a0f1cb 100755
--- a/sound/soc/codecs/wm8994_samsung.h
+++ b/sound/soc/codecs/wm8994_samsung.h
@@ -98,6 +98,12 @@ struct wm8994_setup_data {
unsigned short i2c_address;
};
+enum wm8994_dc_servo_slots {
+ DCS_MEDIA = 0,
+ DCS_VOICE = 1,
+ DCS_SPK_HP = 2,
+};
+
struct wm8994_priv {
struct snd_soc_codec codec;
int master;
@@ -121,6 +127,7 @@ struct wm8994_priv {
struct wm8994_platform_data *pdata;
struct clk *codec_clk;
int gain_code;
+ u16 dc_servo[3];
};
struct gain_info_t {