diff options
Diffstat (limited to 'sound/soc/codecs/mt6358.c')
-rw-r--r-- | sound/soc/codecs/mt6358.c | 131 |
1 files changed, 83 insertions, 48 deletions
diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index d4c4fee6d3d9..50b3fc5457ea 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -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); @@ -405,10 +379,9 @@ static bool is_valid_hp_pga_idx(int reg_idx) reg_idx == DL_GAIN_N_40DB; } -static void headset_volume_ramp(struct mt6358_priv *priv, - int from, int to) +static void headset_volume_ramp(struct mt6358_priv *priv, int from, int to) { - int offset = 0, count = 1, reg_idx; + int offset = 0, count = 0, reg_idx; if (!is_valid_hp_pga_idx(from) || !is_valid_hp_pga_idx(to)) dev_warn(priv->dev, "%s(), volume index is not valid, from %d, to %d\n", @@ -422,7 +395,7 @@ static void headset_volume_ramp(struct mt6358_priv *priv, else offset = from - to; - while (offset > 0) { + while (offset >= 0) { if (to > from) reg_idx = from + count; else @@ -440,25 +413,76 @@ static void headset_volume_ramp(struct mt6358_priv *priv, } } +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; + case MT6358_AUDENC_ANA_CON0: + case MT6358_AUDENC_ANA_CON1: + regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON0, ®); + priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1] = + (reg >> RG_AUDPREAMPLGAIN_SFT) & RG_AUDPREAMPLGAIN_MASK; + regmap_read(priv->regmap, MT6358_AUDENC_ANA_CON1, ®); + priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2] = + (reg >> RG_AUDPREAMPRGAIN_SFT) & RG_AUDPREAMPRGAIN_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, - 8, 4, 0, - pga_tlv), + SOC_DOUBLE_R_EXT_TLV("PGA Volume", + MT6358_AUDENC_ANA_CON0, MT6358_AUDENC_ANA_CON1, + 8, 4, 0, + snd_soc_get_volsw, mt6358_put_volsw, pga_tlv), }; /* MUX */ @@ -832,8 +856,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); @@ -1043,8 +1065,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); @@ -1104,7 +1124,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, @@ -1740,6 +1759,21 @@ static void mt6358_dmic_disable(struct mt6358_priv *priv) regmap_write(priv->regmap, MT6358_AUDENC_ANA_CON9, 0x0000); } +static void mt6358_restore_pga(struct mt6358_priv *priv) +{ + unsigned int gain_l, gain_r; + + gain_l = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP1]; + gain_r = priv->ana_gain[AUDIO_ANALOG_VOLUME_MICAMP2]; + + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON0, + RG_AUDPREAMPLGAIN_MASK_SFT, + gain_l << RG_AUDPREAMPLGAIN_SFT); + regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON1, + RG_AUDPREAMPRGAIN_MASK_SFT, + gain_r << RG_AUDPREAMPRGAIN_SFT); +} + static int mt_mic_type_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -1764,6 +1798,7 @@ static int mt_mic_type_event(struct snd_soc_dapm_widget *w, mt6358_amic_enable(priv); break; } + mt6358_restore_pga(priv); break; case SND_SOC_DAPM_POST_PMD: |