summaryrefslogtreecommitdiff
path: root/sound/soc/codecs/wm_hubs.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2010-10-27 13:48:36 -0700
committerMark Brown <broonie@opensource.wolfsonmicro.com>2010-10-28 11:34:03 -0700
commitfec6dd833e733b5d9588a1f1e4d81118b79b5774 (patch)
treefd321d8252fa61dd6df15166c41e262f4c8955ae /sound/soc/codecs/wm_hubs.c
parentd906401114861585c990ff0290c002b5d22fc71a (diff)
ASoC: Store DC offset correction for wm_hubs devices in class W mode
Providing the analogue configuration of the output path remains the same the DC offset corrected by the DC servo will remain identical so we can skip the callibration, reducing the startup time for the headphone output. Implement this for the wm_hubs devices as has been done for several other CODECs. Don't do this if we have any analogue paths enabled since offsets may be being introduced by the analogue paths which could vary outside the control of the driver. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
Diffstat (limited to 'sound/soc/codecs/wm_hubs.c')
-rw-r--r--sound/soc/codecs/wm_hubs.c69
1 files changed, 46 insertions, 23 deletions
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c
index 2cb81538cd91..31c2a5724d85 100644
--- a/sound/soc/codecs/wm_hubs.c
+++ b/sound/soc/codecs/wm_hubs.c
@@ -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)