// SPDX-License-Identifier: GPL-2.0 /* * MT6357 ALSA SoC audio codec driver * * Copyright (c) 2024 Baylibre * Author: Nicolas Belin */ #include #include #include #include #include #include "mt6357.h" static void set_playback_gpio(struct mt6357_priv *priv, bool enable) { regmap_write(priv->regmap, MT6357_GPIO_MODE2_CLR, MT6357_GPIO_MODE2_CLEAR_ALL); if (enable) { /* set gpio mosi mode */ regmap_write(priv->regmap, MT6357_GPIO_MODE2_SET, MT6357_GPIO8_MODE_SET_AUD_CLK_MOSI | MT6357_GPIO9_MODE_SET_AUD_DAT_MOSI0 | MT6357_GPIO10_MODE_SET_AUD_DAT_MOSI1 | MT6357_GPIO11_MODE_SET_AUD_SYNC_MOSI); } else { /* pad_aud_*_mosi are GPIO mode after clear and set them to dir input * reason: * pad_aud_dat_mosi*, because the pin is used as boot strap */ regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0, MT6357_GPIO8_DIR_MASK | MT6357_GPIO9_DIR_MASK | MT6357_GPIO10_DIR_MASK | MT6357_GPIO11_DIR_MASK, MT6357_GPIO8_DIR_INPUT | MT6357_GPIO9_DIR_INPUT | MT6357_GPIO10_DIR_INPUT | MT6357_GPIO11_DIR_INPUT); } } static void set_capture_gpio(struct mt6357_priv *priv, bool enable) { regmap_write(priv->regmap, MT6357_GPIO_MODE3_CLR, MT6357_GPIO_MODE3_CLEAR_ALL); if (enable) { /* set gpio miso mode */ regmap_write(priv->regmap, MT6357_GPIO_MODE3_SET, MT6357_GPIO12_MODE_SET_AUD_CLK_MISO | MT6357_GPIO13_MODE_SET_AUD_DAT_MISO0 | MT6357_GPIO14_MODE_SET_AUD_DAT_MISO1 | MT6357_GPIO15_MODE_SET_AUD_SYNC_MISO); } else { /* pad_aud_*_mosi are GPIO mode after clear and set them to dir input * reason: * pad_aud_clk_miso, because when playback only the miso_clk * will also have 26m, so will have power leak * pad_aud_dat_miso*, because the pin is used as boot strap */ regmap_update_bits(priv->regmap, MT6357_GPIO_DIR0, MT6357_GPIO12_DIR_MASK | MT6357_GPIO13_DIR_MASK | MT6357_GPIO14_DIR_MASK | MT6357_GPIO15_DIR_MASK, MT6357_GPIO12_DIR_INPUT | MT6357_GPIO13_DIR_INPUT | MT6357_GPIO14_DIR_INPUT | MT6357_GPIO15_DIR_INPUT); } } static void hp_main_output_ramp(struct mt6357_priv *priv, bool up) { int i, stage; /* Enable/Reduce HPL/R main output stage step by step */ for (i = 0; i <= MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX; i++) { stage = up ? i : MT6357_HPLOUT_STG_CTRL_VAUDP15_MAX - i; regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPLOUT_STG_CTRL_VAUDP15_MASK, stage << MT6357_HPLOUT_STG_CTRL_VAUDP15_SFT); regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPROUT_STG_CTRL_VAUDP15_MASK, stage << MT6357_HPROUT_STG_CTRL_VAUDP15_SFT); usleep_range(600, 700); } } static void hp_aux_feedback_loop_gain_ramp(struct mt6357_priv *priv, bool up) { int i, stage; /* Reduce HP aux feedback loop gain step by step */ for (i = 0; i <= MT6357_HP_AUX_LOOP_GAIN_MAX; i++) { stage = up ? i : MT6357_HP_AUX_LOOP_GAIN_MAX - i; regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_HP_AUX_LOOP_GAIN_MASK, stage << MT6357_HP_AUX_LOOP_GAIN_SFT); usleep_range(600, 700); } } static void hp_pull_down(struct mt6357_priv *priv, bool enable) { if (enable) regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2, MT6357_HPP_SHORT_2VCM_VAUDP15_MASK, MT6357_HPP_SHORT_2VCM_VAUDP15_ENABLE); else regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2, MT6357_HPP_SHORT_2VCM_VAUDP15_MASK, MT6357_HPP_SHORT_2VCM_VAUDP15_DISABLE); } static bool is_valid_hp_pga_idx(int reg_idx) { return (reg_idx >= DL_GAIN_8DB && reg_idx <= DL_GAIN_N_12DB) || reg_idx == DL_GAIN_N_40DB; } static void volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto, unsigned int reg_addr) { int lcount, rcount, sleep = 0; if (!is_valid_hp_pga_idx(lfrom) || !is_valid_hp_pga_idx(lto)) pr_debug("%s(), invalid left volume index, from %d, to %d\n", __func__, lfrom, lto); if (!is_valid_hp_pga_idx(rfrom) || !is_valid_hp_pga_idx(rto)) pr_debug("%s(), invalid right volume index, from %d, to %d\n", __func__, rfrom, rto); if (lto > lfrom) lcount = 1; else lcount = -1; if (rto > rfrom) rcount = 1; else rcount = -1; while ((lto != lfrom) || (rto != rfrom)) { if (lto != lfrom) { lfrom += lcount; if (is_valid_hp_pga_idx(lfrom)) { regmap_update_bits(priv->regmap, reg_addr, MT6357_DL_GAIN_REG_LEFT_MASK, lfrom << MT6357_DL_GAIN_REG_LEFT_SHIFT); sleep = 1; } } if (rto != rfrom) { rfrom += rcount; if (is_valid_hp_pga_idx(rfrom)) { regmap_update_bits(priv->regmap, reg_addr, MT6357_DL_GAIN_REG_RIGHT_MASK, rfrom << MT6357_DL_GAIN_REG_RIGHT_SHIFT); sleep = 1; } } if (sleep) usleep_range(200, 300); } } static void lo_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto) { volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON1); } static void hp_volume_ramp(struct mt6357_priv *priv, int lfrom, int lto, int rfrom, int rto) { volume_ramp(priv, lfrom, lto, rfrom, rto, MT6357_ZCD_CON2); } static void hs_volume_ramp(struct mt6357_priv *priv, int from, int to) { volume_ramp(priv, from, to, 0, 0, MT6357_ZCD_CON3); } /* Volume and channel swap controls */ static const DECLARE_TLV_DB_SCALE(playback_tlv, -1000, 100, 0); static const DECLARE_TLV_DB_SCALE(capture_tlv, 0, 600, 0); static const DECLARE_TLV_DB_SCALE(hp_degain_tlv, -1200, 1200, 0); static const struct snd_kcontrol_new mt6357_controls[] = { /* dl pga gain */ SOC_DOUBLE_TLV("Headphone Volume", MT6357_ZCD_CON2, MT6357_AUD_HPL_GAIN_SFT, MT6357_AUD_HPR_GAIN_SFT, MT6357_AUD_HP_GAIN_MAX, 1, playback_tlv), SOC_SINGLE_TLV("Headphone Vin Volume", MT6357_AUDDEC_ANA_CON7, MT6357_HP_IVBUF_DEGAIN_SFT, MT6357_HP_IVBUF_DEGAIN_MAX, 1, hp_degain_tlv), SOC_DOUBLE_TLV("Lineout Volume", MT6357_ZCD_CON1, MT6357_AUD_LOL_GAIN_SFT, MT6357_AUD_LOR_GAIN_SFT, MT6357_AUD_LO_GAIN_MAX, 1, playback_tlv), SOC_SINGLE_TLV("Handset Volume", MT6357_ZCD_CON3, MT6357_AUD_HS_GAIN_SFT, MT6357_AUD_HS_GAIN_MAX, 1, playback_tlv), /* ul pga gain */ SOC_DOUBLE_R_TLV("Mic Volume", MT6357_AUDENC_ANA_CON0, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPLGAIN_SFT, MT6357_AUDPREAMPLGAIN_MAX, 0, capture_tlv), }; /* Uplink controls */ enum { MIC_TYPE_MUX_IDLE, MIC_TYPE_MUX_ACC, MIC_TYPE_MUX_DMIC, MIC_TYPE_MUX_DCC, MIC_TYPE_MUX_DCC_ECM_DIFF, MIC_TYPE_MUX_DCC_ECM_SINGLE, MIC_TYPE_MUX_LPBK, MIC_TYPE_MUX_SGEN, }; #define IS_DCC_BASE(type) ((type) == MIC_TYPE_MUX_DCC || \ (type) == MIC_TYPE_MUX_DCC_ECM_DIFF || \ (type) == MIC_TYPE_MUX_DCC_ECM_SINGLE) static const char * const mic_type_mux_map[] = { "Idle", "ACC", "DMIC", "DCC", "DCC_ECM_DIFF", "DCC_ECM_SINGLE", "Loopback", "Sine Generator", }; static SOC_ENUM_SINGLE_DECL(mic_type_mux_map_enum, SND_SOC_NOPM, 0, mic_type_mux_map); static const struct snd_kcontrol_new mic_type_mux_control = SOC_DAPM_ENUM("Mic Type Select", mic_type_mux_map_enum); static const char * const pga_mux_map[] = { "None", "AIN0", "AIN1", "AIN2" }; static SOC_ENUM_SINGLE_DECL(pga_left_mux_map_enum, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLINPUTSEL_SFT, pga_mux_map); static const struct snd_kcontrol_new pga_left_mux_control = SOC_DAPM_ENUM("PGA L Select", pga_left_mux_map_enum); static SOC_ENUM_SINGLE_DECL(pga_right_mux_map_enum, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRINPUTSEL_SFT, pga_mux_map); static const struct snd_kcontrol_new pga_right_mux_control = SOC_DAPM_ENUM("PGA R Select", pga_right_mux_map_enum); /* Downlink controls */ static const char * const hslo_mux_map[] = { "Open", "DACR", "Playback", "Test mode" }; static SOC_ENUM_SINGLE_DECL(lo_mux_map_enum, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOL_MUX_INPUT_VAUDP15_SFT, hslo_mux_map); static const struct snd_kcontrol_new lo_mux_control = SOC_DAPM_ENUM("Line out source", lo_mux_map_enum); static SOC_ENUM_SINGLE_DECL(hs_mux_map_enum, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HS_MUX_INPUT_VAUDP15_SFT, hslo_mux_map); static const struct snd_kcontrol_new hs_mux_control = SOC_DAPM_ENUM("Handset source", hs_mux_map_enum); static const char * const hplr_mux_map[] = { "Open", "Line Out", "DAC", "Handset" }; static SOC_ENUM_SINGLE_DECL(hpr_mux_map_enum, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_HPR_MUX_INPUT_VAUDP15_SFT, hplr_mux_map); static const struct snd_kcontrol_new hpr_mux_control = SOC_DAPM_ENUM("Headphone Right source", hpr_mux_map_enum); static SOC_ENUM_SINGLE_DECL(hpl_mux_map_enum, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_HPL_MUX_INPUT_VAUDP15_SFT, hplr_mux_map); static const struct snd_kcontrol_new hpl_mux_control = SOC_DAPM_ENUM("Headphone Left source", hpl_mux_map_enum); static const char * const dac_mux_map[] = { "Normal Path", "Sine Generator" }; static SOC_ENUM_SINGLE_DECL(dac_mux_map_enum, MT6357_AFE_TOP_CON0, MT6357_DL_SINE_ON_SFT, dac_mux_map); static const struct snd_kcontrol_new dac_mux_control = SOC_DAPM_ENUM("DAC Select", dac_mux_map_enum); static int mt6357_set_dmic(struct mt6357_priv *priv, bool enable) { if (enable) { /* DMIC enable */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7, MT6357_AUDDIGMICBIAS_MASK | MT6357_AUDDIGMICEN_MASK, MT6357_AUDDIGMICBIAS_DEFAULT_VALUE | MT6357_AUDDIGMICEN_ENABLE); /* enable aud_pad TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE); /* UL dmic setting: dual mode */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H, MT6357_C_TWO_DIGITAL_MIC_CTL_MASK, MT6357_C_TWO_DIGITAL_MIC_ENABLE); /* UL turn on SDM 3 level mode */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SDM_3_LEVEL_CTL_MASK, MT6357_UL_SDM_3_LEVEL_SELECT); /* UL turn on */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_ENABLE); /* Wait to avoid any pop noises */ msleep(100); } else { /* UL turn off */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_DISABLE); /* UL turn on SDM 3 level mode */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SDM_3_LEVEL_CTL_MASK, MT6357_UL_SDM_3_LEVEL_DESELECT); /* disable aud_pad TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE); /* UL dmic setting: dual mode */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_H, MT6357_C_TWO_DIGITAL_MIC_CTL_MASK, MT6357_C_TWO_DIGITAL_MIC_DISABLE); /* DMIC disable */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON7, MT6357_AUDDIGMICBIAS_MASK | MT6357_AUDDIGMICEN_MASK, MT6357_AUDDIGMICBIAS_OFF | MT6357_AUDDIGMICEN_DISABLE); } return 0; } static int mt6357_set_amic(struct mt6357_priv *priv, bool enable, unsigned int mic_type) { if (enable) { if (IS_DCC_BASE(mic_type)) { regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, MT6357_DCCLK_DIV_MASK, MT6357_DCCLK_DIV_RUN_VALUE); regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, MT6357_DCCLK_PDN_MASK, MT6357_DCCLK_OUTPUT); regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, MT6357_DCCLK_GEN_ON_MASK, MT6357_DCCLK_GEN_ON); regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG1, MT6357_DCCLK_RESYNC_BYPASS_MASK, MT6357_DCCLK_RESYNC_BYPASS); /* mic bias 0: set the correct DC couple*/ switch (mic_type) { case MIC_TYPE_MUX_DCC_ECM_DIFF: regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, MT6357_AUD_MICBIAS0_DC_MASK, MT6357_AUD_MICBIAS0_DC_ENABLE_ALL); break; case MIC_TYPE_MUX_DCC_ECM_SINGLE: regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, MT6357_AUD_MICBIAS0_DC_MASK, MT6357_AUD_MICBIAS0_DC_ENABLE_P1); break; default: regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, MT6357_AUD_MICBIAS0_DC_MASK, MT6357_AUD_MICBIAS0_DC_DISABLE_ALL); break; } /* mic bias 1: set the correct DC couple */ if (mic_type == MIC_TYPE_MUX_DCC_ECM_SINGLE) regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9, MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK, MT6357_AUD_MICBIAS1_DCSW1P_ENABLE); /* Audio L/R preamplifier DCC precharge */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLDCPRECHARGE_MASK, MT6357_AUDPREAMPLDCPRECHARGE_ENABLE); regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRDCPRECHARGE_MASK, MT6357_AUDPREAMPRDCPRECHARGE_ENABLE); /* L preamplifier DCCEN */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLDCCEN_MASK, MT6357_AUDPREAMPLDCCEN_DC); /* R preamplifier DCCEN */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRDCCEN_MASK, MT6357_AUDPREAMPRDCCEN_DC); } else { /* Audio L preamplifier DCC precharge disable */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLDCPRECHARGE_MASK, MT6357_AUDPREAMPLDCPRECHARGE_DISABLE); /* L preamplifier ACC */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLDCCEN_MASK, MT6357_AUDPREAMPLDCCEN_AC); /* Audio R preamplifier DCC precharge disable */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRDCPRECHARGE_MASK, MT6357_AUDPREAMPRDCPRECHARGE_DISABLE); /* R preamplifier ACC */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRDCCEN_MASK, MT6357_AUDPREAMPRDCCEN_AC); } } else { /* disable any Mic Bias 0 DC couple */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, MT6357_AUD_MICBIAS0_DC_MASK, MT6357_AUD_MICBIAS0_DC_DISABLE_ALL); /* disable any Mic Bias 1 DC couple */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9, MT6357_AUD_MICBIAS1_DCSW1P_EN_MASK, MT6357_AUD_MICBIAS1_DCSW1P_DISABLE); if (IS_DCC_BASE(mic_type)) { regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, MT6357_DCCLK_GEN_ON_MASK, MT6357_DCCLK_GEN_OFF); regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, MT6357_DCCLK_PDN_MASK, MT6357_DCCLK_PDN); regmap_update_bits(priv->regmap, MT6357_AFE_DCCLK_CFG0, MT6357_DCCLK_DIV_MASK, MT6357_DCCLK_DIV_STOP_VALUE); } } return 0; } static int mt6357_set_loopback(struct mt6357_priv *priv, bool enable) { if (enable) { /* enable aud_pad TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE); /* enable aud_pad lpk TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_LPBK_MASK, MT6357_AUD_PAD_TX_FIFO_LPBK_ENABLE); /* Set UL Part: enable new lpbk 2 */ regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0, MT6357_ADDA_MTKAIF_LPBK_CTL_MASK, MT6357_ADDA_MTKAIF_LPBK_ENABLE); /* UL turn on */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_ENABLE); } else { /* UL turn off */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_DISABLE); /* disable new lpbk 2 */ regmap_update_bits(priv->regmap, MT6357_AFE_ADDA_MTKAIF_CFG0, MT6357_ADDA_MTKAIF_LPBK_CTL_MASK, MT6357_ADDA_MTKAIF_LPBK_DISABLE); /* disable aud_pad lpbk TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_LPBK_MASK, MT6357_AUD_PAD_TX_FIFO_LPBK_DISABLE); /* disable aud_pad TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE); } return 0; } static int mt6357_set_ul_sine_gen(struct mt6357_priv *priv, bool enable) { if (enable) { /* enable aud_pad TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE); /* UL turn on */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_ENABLE); } else { /* UL turn off */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_DISABLE); /* disable aud_pad TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE); } return 0; } static int mt_aif_out_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); switch (event) { case SND_SOC_DAPM_PRE_PMU: set_capture_gpio(priv, true); break; case SND_SOC_DAPM_POST_PMD: set_capture_gpio(priv, false); break; default: break; } return 0; } static int mt_adc_supply_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); switch (event) { case SND_SOC_DAPM_PRE_PMU: /* Enable audio ADC CLKGEN */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11, MT6357_RSTB_ENCODER_VA28_MASK, MT6357_RSTB_ENCODER_VA28_ENABLE); /* Enable LCLDO_ENC 2P8V */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, MT6357_LCLDO_ENC_EN_VA28_MASK, MT6357_LCLDO_ENC_EN_VA28_ENABLE); /* LCLDO_ENC remote sense */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, MT6357_VA28REFGEN_EN_VA28_MASK | MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK, MT6357_VA28REFGEN_EN_VA28_ENABLE | MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_ENABLE); break; case SND_SOC_DAPM_POST_PMD: /* LCLDO_ENC remote sense off */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, MT6357_VA28REFGEN_EN_VA28_MASK | MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_MASK, MT6357_VA28REFGEN_EN_VA28_DISABLE | MT6357_LCLDO_ENC_REMOTE_SENSE_VA28_DISABLE); /* disable LCLDO_ENC 2P8V */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, MT6357_LCLDO_ENC_EN_VA28_MASK, MT6357_LCLDO_ENC_EN_VA28_DISABLE); /* disable audio ADC CLKGEN */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11, MT6357_RSTB_ENCODER_VA28_MASK, MT6357_RSTB_ENCODER_VA28_DISABLE); break; default: break; } return 0; } static int mt_mic_type_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); unsigned int mic_type = dapm_kcontrol_get_value(w->kcontrols[0]); switch (event) { case SND_SOC_DAPM_PRE_PMU: switch (mic_type) { case MIC_TYPE_MUX_DMIC: mt6357_set_dmic(priv, true); break; case MIC_TYPE_MUX_LPBK: mt6357_set_loopback(priv, true); break; case MIC_TYPE_MUX_SGEN: mt6357_set_ul_sine_gen(priv, true); break; default: mt6357_set_amic(priv, true, mic_type); break; } break; case SND_SOC_DAPM_POST_PMD: switch (mic_type) { case MIC_TYPE_MUX_DMIC: mt6357_set_dmic(priv, false); break; case MIC_TYPE_MUX_LPBK: mt6357_set_loopback(priv, false); break; case MIC_TYPE_MUX_SGEN: mt6357_set_ul_sine_gen(priv, false); break; default: mt6357_set_amic(priv, false, mic_type); break; } break; default: break; } return 0; } static int mt_pga_left_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); switch (event) { case SND_SOC_DAPM_POST_PMU: /* L preamplifier enable */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLON_MASK, MT6357_AUDPREAMPLON_ENABLE); /* L ADC input sel : L PGA. Enable audio L ADC */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDADCLINPUTSEL_MASK, MT6357_AUDADCLINPUTSEL_PREAMPLIFIER); regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDADCLPWRUP_MASK, MT6357_AUDADCLPWRUP); /* Audio L preamplifier DCC precharge off */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLDCPRECHARGE_MASK, MT6357_AUDPREAMPLDCPRECHARGE_DISABLE); break; case SND_SOC_DAPM_PRE_PMD: /* Audio L ADC input sel : off, disable audio L ADC */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDADCLPWRUP_MASK, MT6357_AUDADCLPWRDOWN); regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDADCLINPUTSEL_MASK, MT6357_AUDADCLINPUTSEL_IDLE); /* L preamplifier ACC */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLDCCEN_MASK, MT6357_AUDPREAMPLDCCEN_AC); /* L preamplifier disable */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLON_MASK, MT6357_AUDPREAMPLON_DISABLE); /* disable Audio L preamplifier DCC precharge */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLDCPRECHARGE_MASK, MT6357_AUDPREAMPLDCPRECHARGE_DISABLE); break; default: break; } return 0; } static int mt_pga_right_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); switch (event) { case SND_SOC_DAPM_POST_PMU: /* R preamplifier enable */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRON_MASK, MT6357_AUDPREAMPRON_ENABLE); /* R ADC input sel : R PGA. Enable audio R ADC */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDADCRINPUTSEL_MASK, MT6357_AUDADCRINPUTSEL_PREAMPLIFIER); regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDADCRPWRUP_MASK, MT6357_AUDADCRPWRUP); /* Audio R preamplifier DCC precharge off */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRDCPRECHARGE_MASK, MT6357_AUDPREAMPRDCPRECHARGE_DISABLE); break; case SND_SOC_DAPM_PRE_PMD: /* Audio R ADC input sel : off, disable audio R ADC */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDADCRPWRUP_MASK, MT6357_AUDADCRPWRDOWN); regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDADCRINPUTSEL_MASK, MT6357_AUDADCRINPUTSEL_IDLE); /* R preamplifier ACC */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRDCCEN_MASK, MT6357_AUDPREAMPRDCCEN_AC); /* R preamplifier disable */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRON_MASK, MT6357_AUDPREAMPRON_DISABLE); /* disable Audio R preamplifier DCC precharge */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRDCPRECHARGE_MASK, MT6357_AUDPREAMPRDCPRECHARGE_DISABLE); break; default: break; } return 0; } static int adc_enable_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); int lgain, rgain; switch (event) { case SND_SOC_DAPM_PRE_PMU: regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON0, &lgain); regmap_read(priv->regmap, MT6357_AUDENC_ANA_CON1, &rgain); /* L PGA 0 dB gain */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLGAIN_MASK, UL_GAIN_0DB << MT6357_AUDPREAMPLGAIN_SFT); /* R PGA 0 dB gain */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRGAIN_MASK, UL_GAIN_0DB << MT6357_AUDPREAMPRGAIN_SFT); /* enable aud_pad TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_ENABLE); /* UL turn on */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_ENABLE); /* Wait to avoid any pop noises */ msleep(100); /* set the mic gains to the stored values */ regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON0, MT6357_AUDPREAMPLGAIN_MASK, lgain); regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON1, MT6357_AUDPREAMPRGAIN_MASK, rgain); break; case SND_SOC_DAPM_POST_PMD: /* UL turn off */ regmap_update_bits(priv->regmap, MT6357_AFE_UL_SRC_CON0_L, MT6357_UL_SRC_ON_TMP_CTL_MASK, MT6357_UL_SRC_DISABLE); /* disable aud_pad TX fifos */ regmap_update_bits(priv->regmap, MT6357_AFE_AUD_PAD_TOP, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_MASK, MT6357_AUD_PAD_TX_FIFO_NORMAL_PATH_DISABLE); break; default: break; } return 0; } static void configure_downlinks(struct mt6357_priv *priv, bool enable) { if (enable) { regmap_update_bits(priv->regmap, MT6357_AUDDEC_ELR_0, MT6357_AUD_HP_TRIM_EN_VAUDP15_MASK, MT6357_AUD_HP_TRIM_EN_VAUDP15_ENABLE); /* Disable headphone short-circuit protection */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_HPR_SC_VAUDP15_MASK | MT6357_AUD_HPL_SC_VAUDP15_MASK, MT6357_AUD_HPR_SC_VAUDP15_DISABLE | MT6357_AUD_HPL_SC_VAUDP15_DISABLE); /* Disable handset short-circuit protection */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HS_SC_VAUDP15_MASK, MT6357_AUD_HS_SC_VAUDP15_DISABLE); /* Disable lineout short-circuit protection */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOL_SC_VAUDP15_MASK, MT6357_AUD_LOL_SC_VAUDP15_DISABLE); /* Reduce ESD resistance of AU_REFN */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2, MT6357_AUD_REFN_DERES_VAUDP15_MASK, MT6357_AUD_REFN_DERES_VAUDP15_ENABLE); /* Turn on DA_600K_NCP_VA18 */ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON1, MT6357_DIVCKS_ON); /* Set NCP clock as 604kHz // 26MHz/43 = 604KHz */ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON2, 0x002c); /* Toggle DIVCKS_CHG */ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON0, MT6357_DIVCKS_CHG); /* Set NCP soft start mode as default mode: 150us */ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON4, MT6357_DIVCKS_PWD_NCP_ST_150US); /* Enable NCP */ regmap_write(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3, MT6357_DIVCKS_PWD_NCP_ENABLE); usleep_range(250, 270); /* Enable cap-less LDOs (1.5V) */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, MT6357_VA33REFGEN_EN_VA18_MASK | MT6357_LCLDO_REMOTE_SENSE_VA18_MASK | MT6357_LCLDO_EN_VA18_MASK | MT6357_HCLDO_REMOTE_SENSE_VA18_MASK | MT6357_HCLDO_EN_VA18_MASK, MT6357_VA33REFGEN_EN_VA18_ENABLE | MT6357_LCLDO_REMOTE_SENSE_VA18_ENABLE | MT6357_LCLDO_EN_VA18_ENABLE | MT6357_HCLDO_REMOTE_SENSE_VA18_ENABLE | MT6357_HCLDO_EN_VA18_ENABLE); /* Enable NV regulator (-1.2V) */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13, MT6357_NVREG_EN_VAUDP15_MASK, MT6357_NVREG_EN_VAUDP15_ENABLE); usleep_range(100, 120); /* Enable IBIST */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10, MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK, MT6357_AUD_IBIAS_PWRDN_VAUDP15_ENABLE); /* Enable AUD_CLK */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11, MT6357_RSTB_DECODER_VA28_MASK, MT6357_RSTB_DECODER_VA28_ENABLE); /* Enable low-noise mode of DAC */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_DAC_LOW_NOISE_MODE_MASK, MT6357_DAC_LOW_NOISE_MODE_ENABLE); usleep_range(100, 120); } else { /* Disable low-noise mode of DAC */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_DAC_LOW_NOISE_MODE_MASK, MT6357_DAC_LOW_NOISE_MODE_DISABLE); /* Disable AUD_CLK */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON11, MT6357_RSTB_DECODER_VA28_MASK, MT6357_RSTB_DECODER_VA28_DISABLE); /* Enable linout short-circuit protection */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOL_SC_VAUDP15_MASK, MT6357_AUD_LOL_SC_VAUDP15_ENABLE); /* Enable handset short-circuit protection */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HS_SC_VAUDP15_MASK, MT6357_AUD_HS_SC_VAUDP15_ENABLE); /* Enable headphone short-circuit protection */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_HPR_SC_VAUDP15_MASK | MT6357_AUD_HPL_SC_VAUDP15_MASK, MT6357_AUD_HPR_SC_VAUDP15_ENABLE | MT6357_AUD_HPL_SC_VAUDP15_ENABLE); /* Disable IBIST */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON10, MT6357_AUD_IBIAS_PWRDN_VAUDP15_MASK, MT6357_AUD_IBIAS_PWRDN_VAUDP15_DISABLE); /* Disable NV regulator (-1.2V) */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON13, MT6357_NVREG_EN_VAUDP15_MASK, MT6357_NVREG_EN_VAUDP15_DISABLE); /* Disable cap-less LDOs (1.5V) */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON12, MT6357_VA33REFGEN_EN_VA18_MASK | MT6357_LCLDO_REMOTE_SENSE_VA18_MASK | MT6357_LCLDO_EN_VA18_MASK | MT6357_HCLDO_REMOTE_SENSE_VA18_MASK | MT6357_HCLDO_EN_VA18_MASK, MT6357_VA33REFGEN_EN_VA18_DISABLE | MT6357_LCLDO_REMOTE_SENSE_VA18_DISABLE | MT6357_LCLDO_EN_VA18_DISABLE | MT6357_HCLDO_REMOTE_SENSE_VA18_DISABLE | MT6357_HCLDO_EN_VA18_DISABLE); /* Disable NCP */ regmap_update_bits(priv->regmap, MT6357_AUDNCP_CLKDIV_CON3, MT6357_DIVCKS_PWD_NCP_MASK, MT6357_DIVCKS_PWD_NCP_DISABLE); } } static int mt_audio_in_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); switch (event) { case SND_SOC_DAPM_PRE_PMU: set_playback_gpio(priv, true); /* Pull-down HPL/R to AVSS28_AUD */ if (priv->pull_down_needed) hp_pull_down(priv, true); /* Disable HP main CMFB Switch */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_HPRL_MAIN_CMFB_LOOP_MASK, MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE); /* Audio system digital clock power down release */ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, MT6357_CCI_AUDIO_FIFO_DISABLE | MT6357_CCI_ACD_MODE_NORMAL_PATH | MT6357_CCI_AFIFO_CLK_PWDB_ON | MT6357_CCI_ACD_FUNC_RSTB_RESET); /* sdm audio fifo clock power on */ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0, MT6357_CCI_AUD_ANACK_INVERT | (4 << MT6357_CCI_AUDIO_FIFO_WPTR_SFT) | MT6357_CCI_SCRAMBLER_CG_ENABLE | MT6357_CCI_RAND_ENABLE | MT6357_CCI_SPLT_SCRMB_CLK_ON | MT6357_CCI_SPLT_SCRMB_ON | MT6357_CCI_ZERO_PADDING_DISABLE | MT6357_CCI_SCRAMBLER_ENABLE); /* scrambler clock on enable */ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, MT6357_CCI_AUDIO_FIFO_DISABLE | MT6357_CCI_ACD_MODE_TEST_PATH | MT6357_CCI_AFIFO_CLK_PWDB_ON | MT6357_CCI_ACD_FUNC_RSTB_RELEASE); /* sdm power on */ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, MT6357_CCI_AUDIO_FIFO_ENABLE | MT6357_CCI_ACD_MODE_TEST_PATH | MT6357_CCI_AFIFO_CLK_PWDB_ON | MT6357_CCI_ACD_FUNC_RSTB_RELEASE); configure_downlinks(priv, true); break; case SND_SOC_DAPM_POST_PMD: configure_downlinks(priv, false); /* DL scrambler disabling sequence */ regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON2, MT6357_CCI_AUDIO_FIFO_DISABLE | MT6357_CCI_ACD_MODE_TEST_PATH | MT6357_CCI_AFIFO_CLK_PWDB_DOWN | MT6357_CCI_ACD_FUNC_RSTB_RESET); regmap_write(priv->regmap, MT6357_AFUNC_AUD_CON0, MT6357_CCI_AUD_ANACK_INVERT | (4 << MT6357_CCI_AUDIO_FIFO_WPTR_SFT) | MT6357_CCI_SCRAMBLER_CG_ENABLE | MT6357_CCI_RAND_ENABLE | MT6357_CCI_SPLT_SCRMB_CLK_ON | MT6357_CCI_SPLT_SCRMB_ON | MT6357_CCI_ZERO_PADDING_DISABLE | MT6357_CCI_SCRAMBLER_DISABLE); set_playback_gpio(priv, false); /* disable Pull-down HPL/R to AVSS28_AUD */ if (priv->pull_down_needed) hp_pull_down(priv, false); break; default: break; } return 0; } static int mt_delay_250_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { switch (event) { case SND_SOC_DAPM_POST_PMU: usleep_range(250, 270); break; case SND_SOC_DAPM_PRE_PMD: usleep_range(250, 270); break; default: break; } return 0; } static int lo_mux_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); int lgain, rgain; /* Get current gain value */ regmap_read(priv->regmap, MT6357_ZCD_CON1, &lgain); rgain = (lgain & MT6357_AUD_LOR_GAIN_MASK) >> MT6357_AUD_LOR_GAIN_SFT; lgain = lgain & MT6357_AUD_LOL_GAIN_MASK; switch (event) { case SND_SOC_DAPM_POST_PMU: /* Set -40dB before enable HS to avoid POP noise */ regmap_update_bits(priv->regmap, MT6357_ZCD_CON1, MT6357_AUD_LOL_GAIN_MASK | MT6357_AUD_LOR_GAIN_MASK, MT6357_DL_GAIN_N_40DB_REG); /* Set LO STB enhance circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK, MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_ENABLE); /* Enable LO driver bias circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK, MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_ENABLE); /* Enable LO driver core circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOL_PWRUP_VAUDP15_MASK, MT6357_AUD_LOL_PWRUP_VAUDP15_ENABLE); /* Set LOL gain to normal gain step by step */ lo_volume_ramp(priv, DL_GAIN_N_40DB, lgain, DL_GAIN_N_40DB, rgain); break; case SND_SOC_DAPM_PRE_PMD: /* decrease LOL gain to minimum gain step by step */ lo_volume_ramp(priv, lgain, DL_GAIN_N_40DB, rgain, DL_GAIN_N_40DB); /* Disable LO driver core circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOL_PWRUP_VAUDP15_MASK, MT6357_AUD_LOL_PWRUP_VAUDP15_DISABLE); /* Disable LO driver bias circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_MASK, MT6357_AUD_LOL_PWRUP_BIAS_VAUDP15_DISABLE); /* Clear LO STB enhance circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_MASK, MT6357_AUD_LOLOUT_STB_ENH_VAUDP15_DISABLE); /* Save the gain value into the register*/ regmap_update_bits(priv->regmap, MT6357_ZCD_CON1, MT6357_AUD_LOL_GAIN_MASK | MT6357_AUD_LOR_GAIN_MASK, lgain << MT6357_AUD_LOL_GAIN_SFT | rgain << MT6357_AUD_LOR_GAIN_SFT); break; default: break; } return 0; } static int hs_mux_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); int gain; /* HS register has only one gain slot */ /* Get current gain value */ regmap_read(priv->regmap, MT6357_ZCD_CON3, &gain); switch (event) { case SND_SOC_DAPM_POST_PMU: /* Set -40dB before enable HS to avoid POP noise */ regmap_update_bits(priv->regmap, MT6357_ZCD_CON3, MT6357_AUD_HS_GAIN_MASK, DL_GAIN_N_40DB); /* Set HS STB enhance circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK, MT6357_AUD_HSOUT_STB_ENH_VAUDP15_ENABLE); /* Enable HS driver bias circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK, MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE); /* Enable HS driver core circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HS_PWRUP_VAUDP15_MASK, MT6357_AUD_HS_PWRUP_VAUDP15_ENABLE); /* Set HS gain to normal gain step by step */ hs_volume_ramp(priv, DL_GAIN_N_40DB, gain); break; case SND_SOC_DAPM_PRE_PMD: /* decrease HS gain to minimum gain step by step */ hs_volume_ramp(priv, gain, DL_GAIN_N_40DB); /* Disable HS driver core circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HS_PWRUP_VAUDP15_MASK, MT6357_AUD_HS_PWRUP_VAUDP15_DISABLE); /* Disable HS driver bias circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_MASK, MT6357_AUD_HS_PWRUP_BIAS_VAUDP15_ENABLE); /* Clear HS STB enhance circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HSOUT_STB_ENH_VAUDP15_MASK, MT6357_AUD_HSOUT_STB_ENH_VAUDP15_DISABLE); /* Save the gain value into the register*/ regmap_update_bits(priv->regmap, MT6357_ZCD_CON3, MT6357_AUD_HS_GAIN_MASK, gain); break; default: break; } return 0; } static int hp_main_mux_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); int lgain, rgain; /* Get current gain value */ regmap_read(priv->regmap, MT6357_ZCD_CON2, &lgain); rgain = (lgain & MT6357_AUD_HPR_GAIN_MASK) >> MT6357_AUD_HPR_GAIN_SFT; lgain = lgain & MT6357_AUD_HPL_GAIN_MASK; switch (event) { case SND_SOC_DAPM_POST_PMU: priv->hp_channel_number++; if (priv->hp_channel_number > 1) break; /* Set -40dB before enable HS to avoid POP noise */ regmap_update_bits(priv->regmap, MT6357_ZCD_CON2, MT6357_AUD_HPL_GAIN_MASK | MT6357_AUD_HPR_GAIN_MASK, MT6357_DL_GAIN_N_40DB_REG); /* Set HPP/N STB enhance circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON2, MT6357_HPROUT_STB_ENH_VAUDP15_MASK | MT6357_HPLOUT_STB_ENH_VAUDP15_MASK, MT6357_HPROUT_STB_ENH_VAUDP15_N470_P250 | MT6357_HPLOUT_STB_ENH_VAUDP15_N470_P250); /* Enable HP aux output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK | MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK, MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE | MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE); /* Enable HP aux feedback loop */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPR_AUX_FBRSW_VAUDP15_MASK | MT6357_HPL_AUX_FBRSW_VAUDP15_MASK, MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE | MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE); /* Enable HP aux CMFB loop */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_HP_CMFB_RST_MASK | MT6357_HPL_AUX_CMFB_LOOP_MASK | MT6357_HPR_AUX_CMFB_LOOP_MASK, MT6357_HP_CMFB_RST_NORMAL | MT6357_HPL_AUX_CMFB_LOOP_ENABLE | MT6357_HPR_AUX_CMFB_LOOP_ENABLE); /* Enable HP driver bias circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_HPR_BIAS_VAUDP15_MASK | MT6357_AUD_HPL_BIAS_VAUDP15_MASK, MT6357_AUD_HPR_BIAS_VAUDP15_ENABLE | MT6357_AUD_HPL_BIAS_VAUDP15_ENABLE); /* Enable HP driver core circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_HPR_PWRUP_VAUDP15_MASK | MT6357_AUD_HPL_PWRUP_VAUDP15_MASK, MT6357_AUD_HPR_PWRUP_VAUDP15_ENABLE | MT6357_AUD_HPL_PWRUP_VAUDP15_ENABLE); /* Short HP main output to HP aux output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK | MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK, MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE | MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE); /* Enable HP main CMFB loop */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_HPRL_MAIN_CMFB_LOOP_MASK, MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE); /* Disable HP aux CMFB loop */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_HPR_AUX_CMFB_LOOP_MASK | MT6357_HPL_AUX_CMFB_LOOP_MASK, MT6357_HPR_AUX_CMFB_LOOP_DISABLE | MT6357_HPL_AUX_CMFB_LOOP_DISABLE); /* Enable HP main output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPROUT_PWRUP_VAUDP15_MASK | MT6357_HPLOUT_PWRUP_VAUDP15_MASK, MT6357_HPROUT_PWRUP_VAUDP15_ENABLE | MT6357_HPLOUT_PWRUP_VAUDP15_ENABLE); /* Enable HPR/L main output stage step by step */ hp_main_output_ramp(priv, true); usleep_range(1000, 1200); /* Reduce HP aux feedback loop gain */ hp_aux_feedback_loop_gain_ramp(priv, true); /* Disable HP aux feedback loop */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPR_AUX_FBRSW_VAUDP15_MASK | MT6357_HPL_AUX_FBRSW_VAUDP15_MASK, MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE | MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE); /* apply volume setting */ hp_volume_ramp(priv, DL_GAIN_N_40DB, lgain, DL_GAIN_N_40DB, rgain); /* Disable HP aux output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK | MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK, MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE | MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE); /* Unshort HP main output to HP aux output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK | MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK, MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE | MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE); usleep_range(100, 120); break; case SND_SOC_DAPM_PRE_PMD: priv->hp_channel_number--; if (priv->hp_channel_number > 0) break; /* Short HP main output to HP aux output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK | MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK, MT6357_HPR_SHORT2HPR_AUX_VAUDP15_ENABLE | MT6357_HPL_SHORT2HPR_AUX_VAUDP15_ENABLE); /* Enable HP aux output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK | MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK, MT6357_HPROUT_AUX_PWRUP_VAUDP15_ENABLE | MT6357_HPLOUT_AUX_PWRUP_VAUDP15_ENABLE); /* decrease HPL/R gain to normal gain step by step */ hp_volume_ramp(priv, lgain, DL_GAIN_N_40DB, rgain, DL_GAIN_N_40DB); /* Enable HP aux feedback loop */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPR_AUX_FBRSW_VAUDP15_MASK | MT6357_HPL_AUX_FBRSW_VAUDP15_MASK, MT6357_HPR_AUX_FBRSW_VAUDP15_ENABLE | MT6357_HPL_AUX_FBRSW_VAUDP15_ENABLE); /* Reduce HP aux feedback loop gain */ hp_aux_feedback_loop_gain_ramp(priv, false); /* decrease HPR/L main output stage step by step */ hp_main_output_ramp(priv, false); /* Disable HP main output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPROUT_PWRUP_VAUDP15_MASK | MT6357_HPLOUT_PWRUP_VAUDP15_MASK, MT6357_HPROUT_PWRUP_VAUDP15_DISABLE | MT6357_HPLOUT_PWRUP_VAUDP15_DISABLE); /* Enable HP aux CMFB loop */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_HP_CMFB_RST_MASK | MT6357_HPL_AUX_CMFB_LOOP_MASK | MT6357_HPR_AUX_CMFB_LOOP_MASK, MT6357_HP_CMFB_RST_RESET | MT6357_HPL_AUX_CMFB_LOOP_ENABLE | MT6357_HPR_AUX_CMFB_LOOP_ENABLE); /* Disable HP main CMFB loop */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_HPRL_MAIN_CMFB_LOOP_MASK, MT6357_HPRL_MAIN_CMFB_LOOP_DISABLE); /* Unshort HP main output to HP aux output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPR_SHORT2HPR_AUX_VAUDP15_MASK | MT6357_HPL_SHORT2HPR_AUX_VAUDP15_MASK, MT6357_HPR_SHORT2HPR_AUX_VAUDP15_DISABLE | MT6357_HPL_SHORT2HPR_AUX_VAUDP15_DISABLE); /* Disable HP driver core circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_HPR_PWRUP_VAUDP15_MASK | MT6357_AUD_HPL_PWRUP_VAUDP15_MASK, MT6357_AUD_HPR_PWRUP_VAUDP15_DISABLE | MT6357_AUD_HPL_PWRUP_VAUDP15_DISABLE); /* Disable HP driver bias circuits */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_HPR_BIAS_VAUDP15_MASK | MT6357_AUD_HPL_BIAS_VAUDP15_MASK, MT6357_AUD_HPR_BIAS_VAUDP15_DISABLE | MT6357_AUD_HPL_BIAS_VAUDP15_DISABLE); /* Disable HP aux CMFB loop, * Enable HP main CMFB for HP off state */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON6, MT6357_HPRL_MAIN_CMFB_LOOP_MASK | MT6357_HPR_AUX_CMFB_LOOP_MASK | MT6357_HPL_AUX_CMFB_LOOP_MASK, MT6357_HPRL_MAIN_CMFB_LOOP_ENABLE | MT6357_HPR_AUX_CMFB_LOOP_DISABLE | MT6357_HPL_AUX_CMFB_LOOP_DISABLE); /* Disable HP aux feedback loop */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPR_AUX_FBRSW_VAUDP15_MASK | MT6357_HPL_AUX_FBRSW_VAUDP15_MASK, MT6357_HPR_AUX_FBRSW_VAUDP15_DISABLE | MT6357_HPL_AUX_FBRSW_VAUDP15_DISABLE); /* Disable HP aux output stage */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON1, MT6357_HPROUT_AUX_PWRUP_VAUDP15_MASK | MT6357_HPLOUT_AUX_PWRUP_VAUDP15_MASK, MT6357_HPROUT_AUX_PWRUP_VAUDP15_DISABLE | MT6357_HPLOUT_AUX_PWRUP_VAUDP15_DISABLE); /* Save the gain value into the register*/ regmap_update_bits(priv->regmap, MT6357_ZCD_CON2, MT6357_AUD_HPL_GAIN_MASK | MT6357_AUD_HPR_GAIN_MASK, lgain << MT6357_AUD_HPL_GAIN_SFT | rgain << MT6357_AUD_HPR_GAIN_SFT); break; default: break; } return 0; } static int right_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); switch (event) { case SND_SOC_DAPM_PRE_PMU: /* Enable Audio DAC and control audio bias gen */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_DACR_PWRUP_VA28_MASK | MT6357_AUD_DACR_PWRUP_VAUDP15_MASK, MT6357_AUD_DACR_PWRUP_VA28_ENABLE | MT6357_AUD_DACR_PWRUP_VAUDP15_ENABLE); break; case SND_SOC_DAPM_POST_PMU: /* disable Pull-down HPL/R to AVSS28_AUD */ if (priv->pull_down_needed) hp_pull_down(priv, false); break; case SND_SOC_DAPM_PRE_PMD: /* Pull-down HPL/R to AVSS28_AUD */ if (priv->pull_down_needed) hp_pull_down(priv, true); /* Disable Audio DAC and control audio bias gen */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_DACR_PWRUP_VA28_MASK | MT6357_AUD_DACR_PWRUP_VAUDP15_MASK, MT6357_AUD_DACR_PWRUP_VA28_DISABLE | MT6357_AUD_DACR_PWRUP_VAUDP15_DISABLE); break; default: break; } return 0; } static int left_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); struct mt6357_priv *priv = snd_soc_component_get_drvdata(cmpnt); switch (event) { case SND_SOC_DAPM_PRE_PMU: /* Enable Audio DAC and control audio bias gen */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_DACL_PWRUP_VA28_MASK | MT6357_AUD_DACL_PWRUP_VAUDP15_MASK, MT6357_AUD_DACL_PWRUP_VA28_ENABLE | MT6357_AUD_DACL_PWRUP_VAUDP15_ENABLE); break; case SND_SOC_DAPM_POST_PMU: /* disable Pull-down HPL/R to AVSS28_AUD */ if (priv->pull_down_needed) hp_pull_down(priv, false); break; case SND_SOC_DAPM_PRE_PMD: /* Pull-down HPL/R to AVSS28_AUD */ if (priv->pull_down_needed) hp_pull_down(priv, true); /* Disable Audio DAC and control audio bias gen */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_DACL_PWRUP_VA28_MASK | MT6357_AUD_DACL_PWRUP_VAUDP15_MASK, MT6357_AUD_DACL_PWRUP_VA28_DISABLE | MT6357_AUD_DACL_PWRUP_VAUDP15_DISABLE); break; default: break; } return 0; } /* Supply widgets subsequence */ enum { /* common */ SUPPLY_SEQ_CLK_BUF, SUPPLY_SEQ_AUD_GLB, SUPPLY_SEQ_CLKSQ, SUPPLY_SEQ_VOW_AUD_LPW, SUPPLY_SEQ_AUD_VOW, SUPPLY_SEQ_VOW_CLK, SUPPLY_SEQ_VOW_LDO, SUPPLY_SEQ_TOP_CK, SUPPLY_SEQ_TOP_CK_LAST, SUPPLY_SEQ_AUD_TOP, SUPPLY_SEQ_AUD_TOP_LAST, SUPPLY_SEQ_AFE, /* capture */ SUPPLY_SEQ_ADC_SUPPLY, }; /* DAPM Widgets */ static const struct snd_soc_dapm_widget mt6357_dapm_widgets[] = { /* Analog Clocks */ SND_SOC_DAPM_SUPPLY_S("CLK_BUF", SUPPLY_SEQ_CLK_BUF, MT6357_DCXO_CW14, MT6357_XO_AUDIO_EN_M_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AUDGLB", SUPPLY_SEQ_AUD_GLB, MT6357_AUDDEC_ANA_CON11, MT6357_AUDGLB_PWRDN_VA28_SFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("CLKSQ Audio", SUPPLY_SEQ_CLKSQ, MT6357_AUDENC_ANA_CON6, MT6357_CLKSQ_EN_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AUDNCP_CK", SUPPLY_SEQ_TOP_CK, MT6357_AUD_TOP_CKPDN_CON0, MT6357_AUDNCP_CK_PDN_SFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("ZCD13M_CK", SUPPLY_SEQ_TOP_CK, MT6357_AUD_TOP_CKPDN_CON0, MT6357_ZCD13M_CK_PDN_SFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AUD_CK", SUPPLY_SEQ_TOP_CK_LAST, MT6357_AUD_TOP_CKPDN_CON0, MT6357_AUD_CK_PDN_SFT, 1, mt_delay_250_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SUPPLY_S("AUDIF_CK", SUPPLY_SEQ_TOP_CK, MT6357_AUD_TOP_CKPDN_CON0, MT6357_AUDIF_CK_PDN_SFT, 1, NULL, 0), /* Digital Clocks */ SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_AFE_CTL", SUPPLY_SEQ_AUD_TOP_LAST, MT6357_AUDIO_TOP_CON0, MT6357_PDN_AFE_CTL_SFT, 1, mt_delay_250_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_DAC_CTL", SUPPLY_SEQ_AUD_TOP, MT6357_AUDIO_TOP_CON0, MT6357_PDN_DAC_CTL_SFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_ADC_CTL", SUPPLY_SEQ_AUD_TOP, MT6357_AUDIO_TOP_CON0, MT6357_PDN_ADC_CTL_SFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_I2S_DL", SUPPLY_SEQ_AUD_TOP, MT6357_AUDIO_TOP_CON0, MT6357_PDN_I2S_DL_CTL_SFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PWR_CLK", SUPPLY_SEQ_AUD_TOP, MT6357_AUDIO_TOP_CON0, MT6357_PWR_CLK_DIS_CTL_SFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_AFE_TESTMODEL", SUPPLY_SEQ_AUD_TOP, MT6357_AUDIO_TOP_CON0, MT6357_PDN_AFE_TESTMODEL_CTL_SFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_PDN_RESERVED", SUPPLY_SEQ_AUD_TOP, MT6357_AUDIO_TOP_CON0, MT6357_PDN_RESERVED_SFT, 1, NULL, 0), SND_SOC_DAPM_SUPPLY_S("AUDIO_TOP_LPBK", SUPPLY_SEQ_AUD_TOP, MT6357_AUDIO_TOP_CON0, MT6357_PDN_LPBK_CTL_SFT, 1, NULL, 0), /* General */ SND_SOC_DAPM_SUPPLY_S("AFE_ON", SUPPLY_SEQ_AFE, MT6357_AFE_UL_DL_CON0, MT6357_AFE_ON_SFT, 0, NULL, 0), /* Uplinks */ SND_SOC_DAPM_AIF_OUT_E("AIF1TX", "MT6357 Capture", 0, SND_SOC_NOPM, 0, 0, mt_aif_out_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY_S("ADC Supply", SUPPLY_SEQ_ADC_SUPPLY, SND_SOC_NOPM, 0, 0, mt_adc_supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, adc_enable_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MUX_E("PGA L Mux", SND_SOC_NOPM, 0, 0, &pga_left_mux_control, mt_pga_left_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_MUX_E("PGA R Mux", SND_SOC_NOPM, 0, 0, &pga_right_mux_control, mt_pga_right_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_PGA("PGA L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("PGA R", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MUX_E("Mic Type Mux", SND_SOC_NOPM, 0, 0, &mic_type_mux_control, mt_mic_type_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("MICBIAS0", MT6357_AUDENC_ANA_CON8, MT6357_AUD_MICBIAS0_PWD_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("MICBIAS1", MT6357_AUDENC_ANA_CON9, MT6357_AUD_MICBIAS1_PWD_SFT, 0, NULL, 0), /* UL inputs */ SND_SOC_DAPM_INPUT("AIN0"), SND_SOC_DAPM_INPUT("AIN1"), SND_SOC_DAPM_INPUT("AIN2"), SND_SOC_DAPM_INPUT("LPBK"), SND_SOC_DAPM_INPUT("SGEN UL"), /* Downlinks */ SND_SOC_DAPM_AIF_IN_E("AIF_RX", "MT6357 Playback", 0, SND_SOC_NOPM, 0, 0, mt_audio_in_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_INPUT("SGEN DL"), SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, &dac_mux_control), SND_SOC_DAPM_DAC_E("DACR", NULL, SND_SOC_NOPM, 0, 0, right_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_DAC_E("DACL", NULL, SND_SOC_NOPM, 0, 0, left_dac_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_SUPPLY("DL Digital Supply", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DL Analog Supply", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("DL SRC", MT6357_AFE_DL_SRC2_CON0_L, MT6357_DL_2_SRC_ON_TMP_CTL_PRE_SFT, 0, NULL, 0), SND_SOC_DAPM_MUX_E("Line Out Source", SND_SOC_NOPM, 0, 0, &lo_mux_control, lo_mux_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_MUX_E("Handset Source", SND_SOC_NOPM, 0, 0, &hs_mux_control, hs_mux_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_MUX_E("Headphone Right Source", SND_SOC_NOPM, 0, 0, &hpr_mux_control, hp_main_mux_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), SND_SOC_DAPM_MUX_E("Headphone Left Source", SND_SOC_NOPM, 0, 0, &hpl_mux_control, hp_main_mux_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), /* DL outputs */ SND_SOC_DAPM_OUTPUT("Headphones"), SND_SOC_DAPM_OUTPUT("Hansdet"), SND_SOC_DAPM_OUTPUT("Line out"), /* Sine generator */ SND_SOC_DAPM_SUPPLY("SGEN UL Enable", MT6357_AFE_TOP_CON0, MT6357_UL_SINE_ON_SFT, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("SGEN Enable", MT6357_AFE_SGEN_CFG0, MT6357_SGEN_DAC_EN_CTL_SFT, 0, mt_audio_in_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_SUPPLY("SGEN MUTE", MT6357_AFE_SGEN_CFG0, MT6357_SGEN_MUTE_SW_CTL_SFT, 1, NULL, 0) }; static const struct snd_soc_dapm_route mt6357_dapm_routes[] = { /* Capture */ {"AIF1TX", NULL, "Mic Type Mux"}, {"AIF1TX", NULL, "CLK_BUF"}, {"AIF1TX", NULL, "AUDGLB"}, {"AIF1TX", NULL, "CLKSQ Audio"}, {"AIF1TX", NULL, "AUD_CK"}, {"AIF1TX", NULL, "AUDIF_CK"}, {"AIF1TX", NULL, "AUDIO_TOP_AFE_CTL"}, {"AIF1TX", NULL, "AUDIO_TOP_ADC_CTL"}, {"AIF1TX", NULL, "AUDIO_TOP_PWR_CLK"}, {"AIF1TX", NULL, "AUDIO_TOP_PDN_RESERVED"}, {"AIF1TX", NULL, "AUDIO_TOP_I2S_DL"}, {"AIF1TX", NULL, "AFE_ON"}, {"Mic Type Mux", "ACC", "ADC"}, {"Mic Type Mux", "DCC", "ADC"}, {"Mic Type Mux", "DCC_ECM_DIFF", "ADC"}, {"Mic Type Mux", "DCC_ECM_SINGLE", "ADC"}, {"Mic Type Mux", "DMIC", "AIN0"}, {"Mic Type Mux", "DMIC", "AIN2"}, {"Mic Type Mux", "Loopback", "LPBK"}, {"Mic Type Mux", "Sine Generator", "SGEN UL"}, {"SGEN UL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"}, {"SGEN UL", NULL, "SGEN UL Enable"}, {"SGEN UL", NULL, "SGEN MUTE"}, {"SGEN UL", NULL, "SGEN Enable"}, {"ADC", NULL, "PGA L Mux"}, {"ADC", NULL, "PGA R Mux"}, {"ADC", NULL, "ADC Supply"}, {"PGA L Mux", "AIN0", "AIN0"}, {"PGA L Mux", "AIN1", "AIN1"}, {"PGA L Mux", "AIN2", "AIN2"}, {"PGA R Mux", "AIN0", "AIN0"}, {"PGA R Mux", "AIN1", "AIN1"}, {"PGA R Mux", "AIN2", "AIN2"}, {"AIN0", NULL, "MICBIAS0"}, {"AIN1", NULL, "MICBIAS1"}, {"AIN2", NULL, "MICBIAS0"}, {"LPBK", NULL, "AUDIO_TOP_LPBK"}, /* Playback */ {"DAC Mux", "Normal Path", "AIF_RX"}, {"DAC Mux", "Sine Generator", "SGEN DL"}, {"AIF_RX", NULL, "DL SRC"}, {"SGEN DL", NULL, "DL SRC"}, {"SGEN DL", NULL, "SGEN MUTE"}, {"SGEN DL", NULL, "SGEN Enable"}, {"SGEN DL", NULL, "DL Digital Supply"}, {"SGEN DL", NULL, "AUDIO_TOP_PDN_AFE_TESTMODEL"}, {"DACL", NULL, "DAC Mux"}, {"DACR", NULL, "DAC Mux"}, {"DL Analog Supply", NULL, "CLK_BUF"}, {"DL Analog Supply", NULL, "AUDGLB"}, {"DL Analog Supply", NULL, "CLKSQ Audio"}, {"DL Analog Supply", NULL, "AUDNCP_CK"}, {"DL Analog Supply", NULL, "ZCD13M_CK"}, {"DL Analog Supply", NULL, "AUD_CK"}, {"DL Analog Supply", NULL, "AUDIF_CK"}, {"DL Digital Supply", NULL, "AUDIO_TOP_AFE_CTL"}, {"DL Digital Supply", NULL, "AUDIO_TOP_DAC_CTL"}, {"DL Digital Supply", NULL, "AUDIO_TOP_PWR_CLK"}, {"DL Digital Supply", NULL, "AFE_ON"}, {"DACR", NULL, "DL Digital Supply"}, {"DACR", NULL, "DL Analog Supply"}, {"DACL", NULL, "DL Digital Supply"}, {"DACL", NULL, "DL Analog Supply"}, {"Line Out Source", "DACR", "DACR"}, {"Line Out Source", "Playback", "DACL"}, {"Line Out Source", "Test mode", "DACL"}, {"Handset Source", "DACR", "DACR"}, {"Handset Source", "Playback", "DACL"}, {"Handset Source", "Test mode", "DACL"}, {"Headphone Right Source", "DAC", "DACR"}, {"Headphone Right Source", "Line Out", "Line Out Source"}, {"Headphone Right Source", "Handset", "Handset Source"}, {"Headphone Left Source", "DAC", "DACL"}, {"Headphone Left Source", "Line Out", "Line Out Source"}, {"Headphone Left Source", "Handset", "Handset Source"}, {"Line out", NULL, "Line Out Source"}, {"Hansdet", NULL, "Handset Source"}, {"Headphones", NULL, "Headphone Right Source"}, {"Headphones", NULL, "Headphone Left Source"}, }; static struct snd_soc_dai_driver mtk_6357_dai_codecs[] = { { .name = "mt6357-snd-codec-aif1", .playback = { .stream_name = "MT6357 Playback", .channels_min = 1, .channels_max = 2, .rates = SNDRV_PCM_RATE_8000_192000, .formats = MT6357_SND_SOC_ADV_MT_FMTS, }, .capture = { .stream_name = "MT6357 Capture", .channels_min = 1, .channels_max = 2, .rates = MT6357_SOC_HIGH_USE_RATE, .formats = MT6357_SND_SOC_ADV_MT_FMTS, }, }, }; static int mt6357_codec_probe(struct snd_soc_component *codec) { struct mt6357_priv *priv = snd_soc_component_get_drvdata(codec); snd_soc_component_init_regmap(codec, priv->regmap); /* Enable audio part */ regmap_update_bits(priv->regmap, MT6357_DCXO_CW14, MT6357_XO_AUDIO_EN_M_MASK, MT6357_XO_AUDIO_EN_M_ENABLE); /* Disable HeadphoneL/HeadphoneR short circuit protection */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON0, MT6357_AUD_HPR_SC_VAUDP15_MASK | MT6357_AUD_HPL_SC_VAUDP15_MASK, MT6357_AUD_HPR_SC_VAUDP15_DISABLE | MT6357_AUD_HPL_SC_VAUDP15_DISABLE); /* Disable voice short circuit protection */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON3, MT6357_AUD_HS_SC_VAUDP15_MASK, MT6357_AUD_HS_SC_VAUDP15_DISABLE); /* disable LO buffer left short circuit protection */ regmap_update_bits(priv->regmap, MT6357_AUDDEC_ANA_CON4, MT6357_AUD_LOL_SC_VAUDP15_MASK, MT6357_AUD_LOL_SC_VAUDP15_DISABLE); /* set gpio */ set_playback_gpio(priv, false); set_capture_gpio(priv, false); /* Disable audio part */ regmap_update_bits(priv->regmap, MT6357_DCXO_CW14, MT6357_XO_AUDIO_EN_M_MASK, MT6357_XO_AUDIO_EN_M_DISABLE); return 0; } static const struct snd_soc_component_driver mt6357_soc_component_driver = { .probe = mt6357_codec_probe, .read = snd_soc_component_read, .write = snd_soc_component_write, .controls = mt6357_controls, .num_controls = ARRAY_SIZE(mt6357_controls), .dapm_widgets = mt6357_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(mt6357_dapm_widgets), .dapm_routes = mt6357_dapm_routes, .num_dapm_routes = ARRAY_SIZE(mt6357_dapm_routes), }; static const u32 micbias_values[] = { 1700000, 1800000, 1900000, 2000000, 2100000, 2500000, 2600000, 2700000 }; static u32 mt6357_get_micbias_idx(struct device_node *np, const char *micbias) { int err; u32 idx, val; err = of_property_read_u32(np, micbias, &val); if (err) return 0; for (idx = 0; idx < ARRAY_SIZE(micbias_values); idx++) { if (val == micbias_values[idx]) return idx; } return 0; } static int mt6357_parse_dt(struct mt6357_priv *priv) { u32 micbias_voltage_index = 0; struct device_node *np = priv->dev->parent->of_node; if (!np) return -EINVAL; priv->pull_down_needed = false; if (of_property_read_bool(np, "mediatek,hp-pull-down")) priv->pull_down_needed = true; micbias_voltage_index = mt6357_get_micbias_idx(np, "mediatek,micbias0-microvolt"); regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON8, MT6357_AUD_MICBIAS0_VREF_MASK, micbias_voltage_index << MT6357_AUD_MICBIAS0_VREF_SFT); micbias_voltage_index = mt6357_get_micbias_idx(np, "mediatek,micbias1-microvolt"); regmap_update_bits(priv->regmap, MT6357_AUDENC_ANA_CON9, MT6357_AUD_MICBIAS1_VREF_MASK, micbias_voltage_index << MT6357_AUD_MICBIAS1_VREF_SFT); return 0; } static int mt6357_platform_driver_probe(struct platform_device *pdev) { struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); struct mt6357_priv *priv; int ret; ret = devm_regulator_get_enable(&pdev->dev, "vaud28"); if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to enable vaud28 regulator\n"); priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; dev_set_drvdata(&pdev->dev, priv); priv->dev = &pdev->dev; priv->regmap = mt6397->regmap; if (IS_ERR(priv->regmap)) return PTR_ERR(priv->regmap); ret = mt6357_parse_dt(priv); if (ret) return dev_err_probe(&pdev->dev, ret, "Failed to parse dts\n"); pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64); if (!pdev->dev.dma_mask) pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; return devm_snd_soc_register_component(&pdev->dev, &mt6357_soc_component_driver, mtk_6357_dai_codecs, ARRAY_SIZE(mtk_6357_dai_codecs)); } static const struct platform_device_id mt6357_platform_ids[] = { {"mt6357-sound", 0}, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(platform, mt6357_platform_ids); static struct platform_driver mt6357_platform_driver = { .driver = { .name = "mt6357-sound", .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .probe = mt6357_platform_driver_probe, .id_table = mt6357_platform_ids, }; module_platform_driver(mt6357_platform_driver) MODULE_DESCRIPTION("MT6357 ALSA SoC codec driver"); MODULE_AUTHOR("Nicolas Belin "); MODULE_LICENSE("GPL");