Commit 4dcc93d0 authored by Mark Brown's avatar Mark Brown

ASoC: Don't use DCS_DATAPATH_BUSY for WM hubs devices

The DCS_DATAPATH_BUSY bit used to monitor the completion of DC servo
operations has been deprecated and with some more recente revisions
may perform incorrectly, especially when only analogue bypass paths
are in use. Switch to using readback from the DC servo command
register instead, which is supported for all devices. Without this
unacceptably long timeouts may be observed in some circumstances.
Signed-off-by: default avatarMark Brown <broonie@opensource.wolfsonmicro.com>
Acked-by: default avatarLiam Girdwood <lrg@slimlogic.co.uk>
parent ae9d8607
......@@ -62,21 +62,27 @@ static const char *speaker_mode_text[] = {
static const struct soc_enum speaker_mode =
SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text);
static void wait_for_dc_servo(struct snd_soc_codec *codec)
static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
{
unsigned int reg;
int count = 0;
unsigned int val;
val = op | WM8993_DCS_ENA_CHAN_0 | WM8993_DCS_ENA_CHAN_1;
/* Trigger the command */
snd_soc_write(codec, WM8993_DC_SERVO_0, val);
dev_dbg(codec->dev, "Waiting for DC servo...\n");
do {
count++;
msleep(1);
reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_0);
reg = snd_soc_read(codec, WM8993_DC_SERVO_0);
dev_dbg(codec->dev, "DC servo: %x\n", reg);
} while (reg & WM8993_DCS_DATAPATH_BUSY && count < 400);
} while (reg & op && count < 400);
if (reg & WM8993_DCS_DATAPATH_BUSY)
if (reg & op)
dev_err(codec->dev, "Timed out waiting for DC Servo\n");
}
......@@ -92,18 +98,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8993_DC_SERVO_1,
WM8993_DCS_SERIES_NO_01_MASK,
32 << WM8993_DCS_SERIES_NO_01_SHIFT);
/* Enable the DC servo. Write all bits to avoid triggering startup
* or write calibration.
*/
snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
0xFFFF,
WM8993_DCS_ENA_CHAN_0 |
WM8993_DCS_ENA_CHAN_1 |
WM8993_DCS_TRIG_SERIES_1 |
WM8993_DCS_TRIG_SERIES_0);
wait_for_dc_servo(codec);
wait_for_dc_servo(codec,
WM8993_DCS_TRIG_SERIES_0 | WM8993_DCS_TRIG_SERIES_1);
/* Apply correction to DC servo result */
if (hubs->dcs_codes) {
......@@ -145,13 +141,9 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
/* Do it */
snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg);
snd_soc_update_bits(codec, WM8993_DC_SERVO_0,
WM8993_DCS_TRIG_DAC_WR_0 |
WM8993_DCS_TRIG_DAC_WR_1,
WM8993_DCS_TRIG_DAC_WR_0 |
WM8993_DCS_TRIG_DAC_WR_1);
wait_for_dc_servo(codec);
wait_for_dc_servo(codec,
WM8993_DCS_TRIG_DAC_WR_0 |
WM8993_DCS_TRIG_DAC_WR_1);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment