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: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
This commit is contained in:
parent
ae9d8607fe
commit
4dcc93d0ed
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue