ASoC: Implement new DC servo readback mode for late WM8994 revisions
Later WM8994 devices implement a new DC servo readback mode with the register used to access the offset moved to register 0x59. Implement support for this and enable it on the appropriate devices. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Liam Girdwood <lrg@ti.com>
This commit is contained in:
@@ -72,6 +72,7 @@
|
|||||||
#define WM8994_DC_SERVO_2 0x55
|
#define WM8994_DC_SERVO_2 0x55
|
||||||
#define WM8994_DC_SERVO_4 0x57
|
#define WM8994_DC_SERVO_4 0x57
|
||||||
#define WM8994_DC_SERVO_READBACK 0x58
|
#define WM8994_DC_SERVO_READBACK 0x58
|
||||||
|
#define WM8994_DC_SERVO_4E 0x59
|
||||||
#define WM8994_ANALOGUE_HP_1 0x60
|
#define WM8994_ANALOGUE_HP_1 0x60
|
||||||
#define WM8958_MIC_DETECT_1 0xD0
|
#define WM8958_MIC_DETECT_1 0xD0
|
||||||
#define WM8958_MIC_DETECT_2 0xD1
|
#define WM8958_MIC_DETECT_2 0xD1
|
||||||
|
@@ -107,6 +107,7 @@ static int wm8994_volatile(struct snd_soc_codec *codec, unsigned int reg)
|
|||||||
case WM8994_LDO_2:
|
case WM8994_LDO_2:
|
||||||
case WM8958_DSP2_EXECCONTROL:
|
case WM8958_DSP2_EXECCONTROL:
|
||||||
case WM8958_MIC_DETECT_3:
|
case WM8958_MIC_DETECT_3:
|
||||||
|
case WM8994_DC_SERVO_4E:
|
||||||
return 1;
|
return 1;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@@ -2978,7 +2979,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
|
|||||||
wm8994->hubs.series_startup = 1;
|
wm8994->hubs.series_startup = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
wm8994->hubs.dcs_readback_mode = 1;
|
wm8994->hubs.dcs_readback_mode = 2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/mfd/wm8994/registers.h>
|
||||||
#include <sound/core.h>
|
#include <sound/core.h>
|
||||||
#include <sound/pcm.h>
|
#include <sound/pcm.h>
|
||||||
#include <sound/pcm_params.h>
|
#include <sound/pcm_params.h>
|
||||||
@@ -116,14 +117,23 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
|
|||||||
{
|
{
|
||||||
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
|
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
|
||||||
s8 offset;
|
s8 offset;
|
||||||
u16 reg, reg_l, reg_r, dcs_cfg;
|
u16 reg, reg_l, reg_r, dcs_cfg, dcs_reg;
|
||||||
|
|
||||||
|
switch (hubs->dcs_readback_mode) {
|
||||||
|
case 2:
|
||||||
|
dcs_reg = WM8994_DC_SERVO_4E;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dcs_reg = WM8993_DC_SERVO_3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* If we're using a digital only path and have a previously
|
/* If we're using a digital only path and have a previously
|
||||||
* callibrated DC servo offset stored then use that. */
|
* callibrated DC servo offset stored then use that. */
|
||||||
if (hubs->class_w && hubs->class_w_dcs) {
|
if (hubs->class_w && hubs->class_w_dcs) {
|
||||||
dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
|
dev_dbg(codec->dev, "Using cached DC servo offset %x\n",
|
||||||
hubs->class_w_dcs);
|
hubs->class_w_dcs);
|
||||||
snd_soc_write(codec, WM8993_DC_SERVO_3, hubs->class_w_dcs);
|
snd_soc_write(codec, dcs_reg, hubs->class_w_dcs);
|
||||||
wait_for_dc_servo(codec,
|
wait_for_dc_servo(codec,
|
||||||
WM8993_DCS_TRIG_DAC_WR_0 |
|
WM8993_DCS_TRIG_DAC_WR_0 |
|
||||||
WM8993_DCS_TRIG_DAC_WR_1);
|
WM8993_DCS_TRIG_DAC_WR_1);
|
||||||
@@ -154,8 +164,9 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
|
|||||||
reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
|
reg_r = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_2)
|
||||||
& WM8993_DCS_INTEG_CHAN_1_MASK;
|
& WM8993_DCS_INTEG_CHAN_1_MASK;
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
case 1:
|
case 1:
|
||||||
reg = snd_soc_read(codec, WM8993_DC_SERVO_3);
|
reg = snd_soc_read(codec, dcs_reg);
|
||||||
reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
|
reg_r = (reg & WM8993_DCS_DAC_WR_VAL_1_MASK)
|
||||||
>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
|
>> WM8993_DCS_DAC_WR_VAL_1_SHIFT;
|
||||||
reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
|
reg_l = reg & WM8993_DCS_DAC_WR_VAL_0_MASK;
|
||||||
@@ -185,7 +196,7 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
|
|||||||
dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
|
dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
|
||||||
|
|
||||||
/* Do it */
|
/* Do it */
|
||||||
snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg);
|
snd_soc_write(codec, dcs_reg, dcs_cfg);
|
||||||
wait_for_dc_servo(codec,
|
wait_for_dc_servo(codec,
|
||||||
WM8993_DCS_TRIG_DAC_WR_0 |
|
WM8993_DCS_TRIG_DAC_WR_0 |
|
||||||
WM8993_DCS_TRIG_DAC_WR_1);
|
WM8993_DCS_TRIG_DAC_WR_1);
|
||||||
|
Reference in New Issue
Block a user