ASoC: sgtl5000: Fix the cache handling
authorFabio Estevam <fabio.estevam@freescale.com>
Mon, 26 May 2014 13:34:20 +0000 (10:34 -0300)
committerMark Brown <broonie@linaro.org>
Tue, 27 May 2014 11:22:15 +0000 (12:22 +0100)
Since commit e5d80e82e32e (ASoC: sgtl5000: Convert to use regmap directly) a
kernel oops is observed after a suspend/resume sequence.

The kernel oops happens inside sgtl5000_restore_regs() as codec->reg_cache is no
longer a valid pointer.

Add the remaining register entries into sgtl5000_reg_defaults[] and remove
sgtl5000_restore_regs() completely, which allows suspend/resume to work fine and
make the code simpler.

Tested on a im53-qsb board.

Reported-by: Shawn Guo <shawn.guo@freescale.com>
Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Tested-by: Shawn Guo <shawn.guo@freescale.com>
Signed-off-by: Mark Brown <broonie@linaro.org>
sound/soc/codecs/sgtl5000.c

index 75f820c..f2de658 100644 (file)
 
 /* default value of sgtl5000 registers */
 static const struct reg_default sgtl5000_reg_defaults[] = {
+       { SGTL5000_CHIP_DIG_POWER,              0x0000 },
        { SGTL5000_CHIP_CLK_CTRL,               0x0008 },
        { SGTL5000_CHIP_I2S_CTRL,               0x0010 },
        { SGTL5000_CHIP_SSS_CTRL,               0x0010 },
+       { SGTL5000_CHIP_ADCDAC_CTRL,            0x020c },
        { SGTL5000_CHIP_DAC_VOL,                0x3c3c },
        { SGTL5000_CHIP_PAD_STRENGTH,           0x015f },
+       { SGTL5000_CHIP_ANA_ADC_CTRL,           0x0000 },
        { SGTL5000_CHIP_ANA_HP_CTRL,            0x1818 },
        { SGTL5000_CHIP_ANA_CTRL,               0x0111 },
+       { SGTL5000_CHIP_LINREG_CTRL,            0x0000 },
+       { SGTL5000_CHIP_REF_CTRL,               0x0000 },
+       { SGTL5000_CHIP_MIC_CTRL,               0x0000 },
+       { SGTL5000_CHIP_LINE_OUT_CTRL,          0x0000 },
        { SGTL5000_CHIP_LINE_OUT_VOL,           0x0404 },
        { SGTL5000_CHIP_ANA_POWER,              0x7060 },
        { SGTL5000_CHIP_PLL_CTRL,               0x5000 },
+       { SGTL5000_CHIP_CLK_TOP_CTRL,           0x0000 },
+       { SGTL5000_CHIP_ANA_STATUS,             0x0000 },
+       { SGTL5000_CHIP_SHORT_CTRL,             0x0000 },
+       { SGTL5000_CHIP_ANA_TEST2,              0x0000 },
+       { SGTL5000_DAP_CTRL,                    0x0000 },
+       { SGTL5000_DAP_PEQ,                     0x0000 },
        { SGTL5000_DAP_BASS_ENHANCE,            0x0040 },
        { SGTL5000_DAP_BASS_ENHANCE_CTRL,       0x051f },
+       { SGTL5000_DAP_AUDIO_EQ,                0x0000 },
        { SGTL5000_DAP_SURROUND,                0x0040 },
        { SGTL5000_DAP_EQ_BASS_BAND0,           0x002f },
        { SGTL5000_DAP_EQ_BASS_BAND1,           0x002f },
@@ -55,6 +69,7 @@ static const struct reg_default sgtl5000_reg_defaults[] = {
        { SGTL5000_DAP_EQ_BASS_BAND3,           0x002f },
        { SGTL5000_DAP_EQ_BASS_BAND4,           0x002f },
        { SGTL5000_DAP_MAIN_CHAN,               0x8000 },
+       { SGTL5000_DAP_MIX_CHAN,                0x0000 },
        { SGTL5000_DAP_AVC_CTRL,                0x0510 },
        { SGTL5000_DAP_AVC_THRESHOLD,           0x1473 },
        { SGTL5000_DAP_AVC_ATTACK,              0x0028 },
@@ -1068,71 +1083,11 @@ static int sgtl5000_suspend(struct snd_soc_codec *codec)
        return 0;
 }
 
-/*
- * restore all sgtl5000 registers,
- * since a big hole between dap and regular registers,
- * we will restore them respectively.
- */
-static int sgtl5000_restore_regs(struct snd_soc_codec *codec)
-{
-       u16 *cache = codec->reg_cache;
-       u16 reg;
-
-       /* restore regular registers */
-       for (reg = 0; reg <= SGTL5000_CHIP_SHORT_CTRL; reg += 2) {
-
-               /* These regs should restore in particular order */
-               if (reg == SGTL5000_CHIP_ANA_POWER ||
-                       reg == SGTL5000_CHIP_CLK_CTRL ||
-                       reg == SGTL5000_CHIP_LINREG_CTRL ||
-                       reg == SGTL5000_CHIP_LINE_OUT_CTRL ||
-                       reg == SGTL5000_CHIP_REF_CTRL)
-                       continue;
-
-               snd_soc_write(codec, reg, cache[reg]);
-       }
-
-       /* restore dap registers */
-       for (reg = SGTL5000_DAP_REG_OFFSET; reg < SGTL5000_MAX_REG_OFFSET; reg += 2)
-               snd_soc_write(codec, reg, cache[reg]);
-
-       /*
-        * restore these regs according to the power setting sequence in
-        * sgtl5000_set_power_regs() and clock setting sequence in
-        * sgtl5000_set_clock().
-        *
-        * The order of restore is:
-        * 1. SGTL5000_CHIP_CLK_CTRL MCLK_FREQ bits (1:0) should be restore after
-        *    SGTL5000_CHIP_ANA_POWER PLL bits set
-        * 2. SGTL5000_CHIP_LINREG_CTRL should be set before
-        *    SGTL5000_CHIP_ANA_POWER LINREG_D restored
-        * 3. SGTL5000_CHIP_REF_CTRL controls Analog Ground Voltage,
-        *    prefer to resotre it after SGTL5000_CHIP_ANA_POWER restored
-        */
-       snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL,
-                       cache[SGTL5000_CHIP_LINREG_CTRL]);
-
-       snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER,
-                       cache[SGTL5000_CHIP_ANA_POWER]);
-
-       snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL,
-                       cache[SGTL5000_CHIP_CLK_CTRL]);
-
-       snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL,
-                       cache[SGTL5000_CHIP_REF_CTRL]);
-
-       snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
-                       cache[SGTL5000_CHIP_LINE_OUT_CTRL]);
-       return 0;
-}
-
 static int sgtl5000_resume(struct snd_soc_codec *codec)
 {
        /* Bring the codec back up to standby to enable regulators */
        sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
-       /* Restore registers by cached in memory */
-       sgtl5000_restore_regs(codec);
        return 0;
 }
 #else