@@ -320,32 +320,6 @@ enum {
#define DL_GAIN_N_40DB_REG (DL_GAIN_N_40DB << 7 | DL_GAIN_N_40DB)
#define DL_GAIN_REG_MASK 0x0f9f
-static void lo_store_gain(struct mt6358_priv *priv)
-{
- unsigned int reg;
- unsigned int gain_l, gain_r;
-
- regmap_read(priv->regmap, MT6358_ZCD_CON1, ®);
- gain_l = (reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK;
- gain_r = (reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK;
-
- priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] = gain_l;
- priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] = gain_r;
-}
-
-static void hp_store_gain(struct mt6358_priv *priv)
-{
- unsigned int reg;
- unsigned int gain_l, gain_r;
-
- regmap_read(priv->regmap, MT6358_ZCD_CON2, ®);
- gain_l = (reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
- gain_r = (reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
-
- priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] = gain_l;
- priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] = gain_r;
-}
-
static void hp_zcd_disable(struct mt6358_priv *priv)
{
regmap_write(priv->regmap, MT6358_ZCD_CON0, 0x0000);
@@ -439,20 +413,62 @@ static void headset_volume_ramp(struct mt6358_priv *priv, int from, int to)
}
}
+static int mt6358_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component =
+ snd_soc_kcontrol_component(kcontrol);
+ struct mt6358_priv *priv = snd_soc_component_get_drvdata(component);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg;
+ int ret;
+
+ ret = snd_soc_put_volsw(kcontrol, ucontrol);
+ if (ret < 0)
+ return ret;
+
+ switch (mc->reg) {
+ case MT6358_ZCD_CON2:
+ regmap_read(priv->regmap, MT6358_ZCD_CON2, ®);
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] =
+ (reg >> RG_AUDHPLGAIN_SFT) & RG_AUDHPLGAIN_MASK;
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_HPOUTR] =
+ (reg >> RG_AUDHPRGAIN_SFT) & RG_AUDHPRGAIN_MASK;
+ break;
+ case MT6358_ZCD_CON1:
+ regmap_read(priv->regmap, MT6358_ZCD_CON1, ®);
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTL] =
+ (reg >> RG_AUDLOLGAIN_SFT) & RG_AUDLOLGAIN_MASK;
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_LINEOUTR] =
+ (reg >> RG_AUDLORGAIN_SFT) & RG_AUDLORGAIN_MASK;
+ break;
+ case MT6358_ZCD_CON3:
+ regmap_read(priv->regmap, MT6358_ZCD_CON3, ®);
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTL] =
+ (reg >> RG_AUDHSGAIN_SFT) & RG_AUDHSGAIN_MASK;
+ priv->ana_gain[AUDIO_ANALOG_VOLUME_HSOUTR] =
+ (reg >> RG_AUDHSGAIN_SFT) & RG_AUDHSGAIN_MASK;
+ break;
+ }
+
+ return ret;
+}
+
static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0);
static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 600, 0);
static const struct snd_kcontrol_new mt6358_snd_controls[] = {
/* dl pga gain */
- SOC_DOUBLE_TLV("Headphone Volume",
- MT6358_ZCD_CON2, 0, 7, 0x12, 1,
- playback_tlv),
- SOC_DOUBLE_TLV("Lineout Volume",
- MT6358_ZCD_CON1, 0, 7, 0x12, 1,
- playback_tlv),
- SOC_SINGLE_TLV("Handset Volume",
- MT6358_ZCD_CON3, 0, 0x12, 1,
- playback_tlv),
+ SOC_DOUBLE_EXT_TLV("Headphone Volume",
+ MT6358_ZCD_CON2, 0, 7, 0x12, 1,
+ snd_soc_get_volsw, mt6358_put_volsw, playback_tlv),
+ SOC_DOUBLE_EXT_TLV("Lineout Volume",
+ MT6358_ZCD_CON1, 0, 7, 0x12, 1,
+ snd_soc_get_volsw, mt6358_put_volsw, playback_tlv),
+ SOC_SINGLE_EXT_TLV("Handset Volume",
+ MT6358_ZCD_CON3, 0, 0x12, 1,
+ snd_soc_get_volsw, mt6358_put_volsw, playback_tlv),
/* ul pga gain */
SOC_DOUBLE_R_TLV("PGA Volume",
MT6358_AUDENC_ANA_CON0, MT6358_AUDENC_ANA_CON1,
@@ -831,8 +847,6 @@ static int mtk_hp_enable(struct mt6358_priv *priv)
/* Reduce ESD resistance of AU_REFN */
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000);
- /* save target gain to restore after hardware open complete */
- hp_store_gain(priv);
/* Set HPR/HPL gain as minimum (~ -40dB) */
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_40DB_REG);
@@ -1042,8 +1056,6 @@ static int mtk_hp_spk_enable(struct mt6358_priv *priv)
/* Reduce ESD resistance of AU_REFN */
regmap_write(priv->regmap, MT6358_AUDDEC_ANA_CON2, 0x4000);
- /* save target gain to restore after hardware open complete */
- hp_store_gain(priv);
/* Set HPR/HPL gain to -10dB */
regmap_write(priv->regmap, MT6358_ZCD_CON2, DL_GAIN_N_10DB_REG);
@@ -1103,7 +1115,6 @@ static int mtk_hp_spk_enable(struct mt6358_priv *priv)
hp_main_output_ramp(priv, true);
/* Set LO gain as minimum (~ -40dB) */
- lo_store_gain(priv);
regmap_write(priv->regmap, MT6358_ZCD_CON1, DL_GAIN_N_40DB_REG);
/* apply volume setting */
headset_volume_ramp(priv,
Output volume settings from mixer controls would be lost. Imagine that "Headphone Volume" has set to -10dB via amixer: - in mtk_hp_enable() - hp_store_gain() saves the volume setting -10dB from regmap_read() to ana_gain[AUDIO_ANALOG_VOLUME_HPOUTL] - headset_volume_ramp() ramps up from -10dB to -10dB - in mtk_hp_disable() - headset_volume_ramp() ramps down from -10dB to -40dB Next time in mtk_hp_enable(), hp_store_gain() would save -40dB but not -10dB. As a result, headset_volume_ramp() would ramp from -10dB to -40dB (which is mute). Signed-off-by: Tzung-Bi Shih <tzungbi@google.com> --- sound/soc/codecs/mt6358.c | 91 ++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 40 deletions(-)