| From 44330ab516c15dda8a1e660eeaf0003f84e43e3f Mon Sep 17 00:00:00 2001 |
| From: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> |
| Date: Tue, 13 May 2014 13:45:15 +0100 |
| Subject: ASoC: wm8962: Update register CLASS_D_CONTROL_1 to be non-volatile |
| |
| From: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> |
| |
| commit 44330ab516c15dda8a1e660eeaf0003f84e43e3f upstream. |
| |
| The register CLASS_D_CONTROL_1 is marked as volatile because it contains |
| a bit, DAC_MUTE, which is also mirrored in the ADC_DAC_CONTROL_1 |
| register. This causes problems for the "Speaker Switch" control, which |
| will report an error if the CODEC is suspended because it relies on a |
| volatile register. |
| |
| To resolve this issue mark CLASS_D_CONTROL_1 as non-volatile and |
| manually keep the register cache in sync by updating both bits when |
| changing the mute status. |
| |
| Reported-by: Shawn Guo <shawn.guo@linaro.org> |
| Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com> |
| Tested-by: Shawn Guo <shawn.guo@linaro.org> |
| Signed-off-by: Mark Brown <broonie@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| sound/soc/codecs/wm8962.c | 15 ++++++++++++--- |
| sound/soc/codecs/wm8962.h | 4 ++++ |
| 2 files changed, 16 insertions(+), 3 deletions(-) |
| |
| --- a/sound/soc/codecs/wm8962.c |
| +++ b/sound/soc/codecs/wm8962.c |
| @@ -153,6 +153,7 @@ static struct reg_default wm8962_reg[] = |
| { 40, 0x0000 }, /* R40 - SPKOUTL volume */ |
| { 41, 0x0000 }, /* R41 - SPKOUTR volume */ |
| |
| + { 49, 0x0010 }, /* R49 - Class D Control 1 */ |
| { 51, 0x0003 }, /* R51 - Class D Control 2 */ |
| |
| { 56, 0x0506 }, /* R56 - Clocking 4 */ |
| @@ -794,7 +795,6 @@ static bool wm8962_volatile_register(str |
| case WM8962_ALC2: |
| case WM8962_THERMAL_SHUTDOWN_STATUS: |
| case WM8962_ADDITIONAL_CONTROL_4: |
| - case WM8962_CLASS_D_CONTROL_1: |
| case WM8962_DC_SERVO_6: |
| case WM8962_INTERRUPT_STATUS_1: |
| case WM8962_INTERRUPT_STATUS_2: |
| @@ -2901,13 +2901,22 @@ static int wm8962_set_fll(struct snd_soc |
| static int wm8962_mute(struct snd_soc_dai *dai, int mute) |
| { |
| struct snd_soc_codec *codec = dai->codec; |
| - int val; |
| + int val, ret; |
| |
| if (mute) |
| - val = WM8962_DAC_MUTE; |
| + val = WM8962_DAC_MUTE | WM8962_DAC_MUTE_ALT; |
| else |
| val = 0; |
| |
| + /** |
| + * The DAC mute bit is mirrored in two registers, update both to keep |
| + * the register cache consistent. |
| + */ |
| + ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1, |
| + WM8962_DAC_MUTE_ALT, val); |
| + if (ret < 0) |
| + return ret; |
| + |
| return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1, |
| WM8962_DAC_MUTE, val); |
| } |
| --- a/sound/soc/codecs/wm8962.h |
| +++ b/sound/soc/codecs/wm8962.h |
| @@ -1954,6 +1954,10 @@ |
| #define WM8962_SPKOUTL_ENA_MASK 0x0040 /* SPKOUTL_ENA */ |
| #define WM8962_SPKOUTL_ENA_SHIFT 6 /* SPKOUTL_ENA */ |
| #define WM8962_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */ |
| +#define WM8962_DAC_MUTE_ALT 0x0010 /* DAC_MUTE */ |
| +#define WM8962_DAC_MUTE_ALT_MASK 0x0010 /* DAC_MUTE */ |
| +#define WM8962_DAC_MUTE_ALT_SHIFT 4 /* DAC_MUTE */ |
| +#define WM8962_DAC_MUTE_ALT_WIDTH 1 /* DAC_MUTE */ |
| #define WM8962_SPKOUTL_PGA_MUTE 0x0002 /* SPKOUTL_PGA_MUTE */ |
| #define WM8962_SPKOUTL_PGA_MUTE_MASK 0x0002 /* SPKOUTL_PGA_MUTE */ |
| #define WM8962_SPKOUTL_PGA_MUTE_SHIFT 1 /* SPKOUTL_PGA_MUTE */ |