Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: wm8962: Update register CLASS_D_CONTROL_1 to be non-volatile

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>
Cc: stable@vger.kernel.org

authored by

Charles Keepax and committed by
Mark Brown
44330ab5 c9eaa447

+16 -3
+12 -3
sound/soc/codecs/wm8962.c
··· 154 154 { 40, 0x0000 }, /* R40 - SPKOUTL volume */ 155 155 { 41, 0x0000 }, /* R41 - SPKOUTR volume */ 156 156 157 + { 49, 0x0010 }, /* R49 - Class D Control 1 */ 157 158 { 51, 0x0003 }, /* R51 - Class D Control 2 */ 158 159 159 160 { 56, 0x0506 }, /* R56 - Clocking 4 */ ··· 796 795 case WM8962_ALC2: 797 796 case WM8962_THERMAL_SHUTDOWN_STATUS: 798 797 case WM8962_ADDITIONAL_CONTROL_4: 799 - case WM8962_CLASS_D_CONTROL_1: 800 798 case WM8962_DC_SERVO_6: 801 799 case WM8962_INTERRUPT_STATUS_1: 802 800 case WM8962_INTERRUPT_STATUS_2: ··· 2929 2929 static int wm8962_mute(struct snd_soc_dai *dai, int mute) 2930 2930 { 2931 2931 struct snd_soc_codec *codec = dai->codec; 2932 - int val; 2932 + int val, ret; 2933 2933 2934 2934 if (mute) 2935 - val = WM8962_DAC_MUTE; 2935 + val = WM8962_DAC_MUTE | WM8962_DAC_MUTE_ALT; 2936 2936 else 2937 2937 val = 0; 2938 + 2939 + /** 2940 + * The DAC mute bit is mirrored in two registers, update both to keep 2941 + * the register cache consistent. 2942 + */ 2943 + ret = snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_1, 2944 + WM8962_DAC_MUTE_ALT, val); 2945 + if (ret < 0) 2946 + return ret; 2938 2947 2939 2948 return snd_soc_update_bits(codec, WM8962_ADC_DAC_CONTROL_1, 2940 2949 WM8962_DAC_MUTE, val);
+4
sound/soc/codecs/wm8962.h
··· 1954 1954 #define WM8962_SPKOUTL_ENA_MASK 0x0040 /* SPKOUTL_ENA */ 1955 1955 #define WM8962_SPKOUTL_ENA_SHIFT 6 /* SPKOUTL_ENA */ 1956 1956 #define WM8962_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */ 1957 + #define WM8962_DAC_MUTE_ALT 0x0010 /* DAC_MUTE */ 1958 + #define WM8962_DAC_MUTE_ALT_MASK 0x0010 /* DAC_MUTE */ 1959 + #define WM8962_DAC_MUTE_ALT_SHIFT 4 /* DAC_MUTE */ 1960 + #define WM8962_DAC_MUTE_ALT_WIDTH 1 /* DAC_MUTE */ 1957 1961 #define WM8962_SPKOUTL_PGA_MUTE 0x0002 /* SPKOUTL_PGA_MUTE */ 1958 1962 #define WM8962_SPKOUTL_PGA_MUTE_MASK 0x0002 /* SPKOUTL_PGA_MUTE */ 1959 1963 #define WM8962_SPKOUTL_PGA_MUTE_SHIFT 1 /* SPKOUTL_PGA_MUTE */