diff options
author | johnnyhsu@realtek.com <johnnyhsu@realtek.com> | 2011-09-07 11:16:35 +0800 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-09-21 15:52:23 +0100 |
commit | d80852223ecabd1ab433a9c71436d81b697ef1fc (patch) | |
tree | 445a116437cdc9bf40f2b9847336b713e336a772 /sound/soc/codecs/rt5631.c | |
parent | 49acf73bd03a22d1a0e866b244a4003c222aabee (diff) |
ASoC: Add driver for rt5631
Signed-off-by: Johnny Hsu <johnnyhsu@realtek.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/codecs/rt5631.c')
-rw-r--r-- | sound/soc/codecs/rt5631.c | 1789 |
1 files changed, 1789 insertions, 0 deletions
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c new file mode 100644 index 00000000000..110b3d852d0 --- /dev/null +++ b/sound/soc/codecs/rt5631.c @@ -0,0 +1,1789 @@ +/* + * rt5631.c -- RT5631 ALSA Soc Audio driver + * + * Copyright 2011 Realtek Microelectronics + * + * Author: flove <flove@realtek.com> + * + * Based on WM8753.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pm.h> +#include <linux/i2c.h> +#include <linux/platform_device.h> +#include <linux/spi/spi.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include <sound/soc-dapm.h> +#include <sound/initval.h> +#include <sound/tlv.h> + +#include "rt5631.h" + +struct rt5631_priv { + struct snd_soc_codec *codec; + int codec_version; + int master; + int sysclk; + int rx_rate; + int bclk_rate; + int dmic_used_flag; +}; + +static const u16 rt5631_reg[RT5631_VENDOR_ID2 + 1] = { + [RT5631_SPK_OUT_VOL] = 0x8888, + [RT5631_HP_OUT_VOL] = 0x8080, + [RT5631_MONO_AXO_1_2_VOL] = 0xa080, + [RT5631_AUX_IN_VOL] = 0x0808, + [RT5631_ADC_REC_MIXER] = 0xf0f0, + [RT5631_VDAC_DIG_VOL] = 0x0010, + [RT5631_OUTMIXER_L_CTRL] = 0xffc0, + [RT5631_OUTMIXER_R_CTRL] = 0xffc0, + [RT5631_AXO1MIXER_CTRL] = 0x88c0, + [RT5631_AXO2MIXER_CTRL] = 0x88c0, + [RT5631_DIG_MIC_CTRL] = 0x3000, + [RT5631_MONO_INPUT_VOL] = 0x8808, + [RT5631_SPK_MIXER_CTRL] = 0xf8f8, + [RT5631_SPK_MONO_OUT_CTRL] = 0xfc00, + [RT5631_SPK_MONO_HP_OUT_CTRL] = 0x4440, + [RT5631_SDP_CTRL] = 0x8000, + [RT5631_MONO_SDP_CTRL] = 0x8000, + [RT5631_STEREO_AD_DA_CLK_CTRL] = 0x2010, + [RT5631_GEN_PUR_CTRL_REG] = 0x0e00, + [RT5631_INT_ST_IRQ_CTRL_2] = 0x071a, + [RT5631_MISC_CTRL] = 0x2040, + [RT5631_DEPOP_FUN_CTRL_2] = 0x8000, + [RT5631_SOFT_VOL_CTRL] = 0x07e0, + [RT5631_ALC_CTRL_1] = 0x0206, + [RT5631_ALC_CTRL_3] = 0x2000, + [RT5631_PSEUDO_SPATL_CTRL] = 0x0553, +}; + +/** + * rt5631_write_index - write index register of 2nd layer + */ +static void rt5631_write_index(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + snd_soc_write(codec, RT5631_INDEX_ADD, reg); + snd_soc_write(codec, RT5631_INDEX_DATA, value); +} + +/** + * rt5631_read_index - read index register of 2nd layer + */ +static unsigned int rt5631_read_index(struct snd_soc_codec *codec, + unsigned int reg) +{ + unsigned int value; + + snd_soc_write(codec, RT5631_INDEX_ADD, reg); + value = snd_soc_read(codec, RT5631_INDEX_DATA); + + return value; +} + +static int rt5631_reset(struct snd_soc_codec *codec) +{ + return snd_soc_write(codec, RT5631_RESET, 0); +} + +static int rt5631_volatile_register(struct snd_soc_codec *codec, + unsigned int reg) +{ + switch (reg) { + case RT5631_RESET: + case RT5631_INT_ST_IRQ_CTRL_2: + case RT5631_INDEX_ADD: + case RT5631_INDEX_DATA: + case RT5631_EQ_CTRL: + return 1; + default: + return 0; + } +} + +static int rt5631_readable_register(struct snd_soc_codec *codec, + unsigned int reg) +{ + switch (reg) { + case RT5631_RESET: + case RT5631_SPK_OUT_VOL: + case RT5631_HP_OUT_VOL: + case RT5631_MONO_AXO_1_2_VOL: + case RT5631_AUX_IN_VOL: + case RT5631_STEREO_DAC_VOL_1: + case RT5631_MIC_CTRL_1: + case RT5631_STEREO_DAC_VOL_2: + case RT5631_ADC_CTRL_1: + case RT5631_ADC_REC_MIXER: + case RT5631_ADC_CTRL_2: + case RT5631_VDAC_DIG_VOL: + case RT5631_OUTMIXER_L_CTRL: + case RT5631_OUTMIXER_R_CTRL: + case RT5631_AXO1MIXER_CTRL: + case RT5631_AXO2MIXER_CTRL: + case RT5631_MIC_CTRL_2: + case RT5631_DIG_MIC_CTRL: + case RT5631_MONO_INPUT_VOL: + case RT5631_SPK_MIXER_CTRL: + case RT5631_SPK_MONO_OUT_CTRL: + case RT5631_SPK_MONO_HP_OUT_CTRL: + case RT5631_SDP_CTRL: + case RT5631_MONO_SDP_CTRL: + case RT5631_STEREO_AD_DA_CLK_CTRL: + case RT5631_PWR_MANAG_ADD1: + case RT5631_PWR_MANAG_ADD2: + case RT5631_PWR_MANAG_ADD3: + case RT5631_PWR_MANAG_ADD4: + case RT5631_GEN_PUR_CTRL_REG: + case RT5631_GLOBAL_CLK_CTRL: + case RT5631_PLL_CTRL: + case RT5631_INT_ST_IRQ_CTRL_1: + case RT5631_INT_ST_IRQ_CTRL_2: + case RT5631_GPIO_CTRL: + case RT5631_MISC_CTRL: + case RT5631_DEPOP_FUN_CTRL_1: + case RT5631_DEPOP_FUN_CTRL_2: + case RT5631_JACK_DET_CTRL: + case RT5631_SOFT_VOL_CTRL: + case RT5631_ALC_CTRL_1: + case RT5631_ALC_CTRL_2: + case RT5631_ALC_CTRL_3: + case RT5631_PSEUDO_SPATL_CTRL: + case RT5631_INDEX_ADD: + case RT5631_INDEX_DATA: + case RT5631_EQ_CTRL: + case RT5631_VENDOR_ID: + case RT5631_VENDOR_ID1: + case RT5631_VENDOR_ID2: + return 1; + default: + return 0; + } +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); +static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -95625, 375, 0); +static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); +/* {0, +20, +24, +30, +35, +40, +44, +50, +52}dB */ +static unsigned int mic_bst_tlv[] = { + TLV_DB_RANGE_HEAD(6), + 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), + 1, 1, TLV_DB_SCALE_ITEM(2000, 0, 0), + 2, 2, TLV_DB_SCALE_ITEM(2400, 0, 0), + 3, 5, TLV_DB_SCALE_ITEM(3000, 500, 0), + 6, 6, TLV_DB_SCALE_ITEM(4400, 0, 0), + 7, 7, TLV_DB_SCALE_ITEM(5000, 0, 0), + 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), +}; + +static int rt5631_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = rt5631->dmic_used_flag; + + return 0; +} + +static int rt5631_dmic_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); + struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); + + rt5631->dmic_used_flag = ucontrol->value.integer.value[0]; + return 0; +} + +/* MIC Input Type */ +static const char *rt5631_input_mode[] = { + "Single ended", "Differential"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1, + RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode); + +static const SOC_ENUM_SINGLE_DECL( + rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1, + RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode); + +/* MONO Input Type */ +static const SOC_ENUM_SINGLE_DECL( + rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL, + RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode); + +/* SPK Ratio Gain Control */ +static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x", + "1.56x", "1.68x", "1.99x", "2.34x"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG, + RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio); + +static const struct snd_kcontrol_new rt5631_snd_controls[] = { + /* MIC */ + SOC_ENUM("MIC1 Mode Control", rt5631_mic1_mode_enum), + SOC_SINGLE_TLV("MIC1 Boost", RT5631_MIC_CTRL_2, + RT5631_MIC1_BOOST_SHIFT, 8, 0, mic_bst_tlv), + SOC_ENUM("MIC2 Mode Control", rt5631_mic2_mode_enum), + SOC_SINGLE_TLV("MIC2 Boost", RT5631_MIC_CTRL_2, + RT5631_MIC2_BOOST_SHIFT, 8, 0, mic_bst_tlv), + /* MONO IN */ + SOC_ENUM("MONOIN Mode Control", rt5631_monoin_mode_enum), + SOC_DOUBLE_TLV("MONOIN_RX Capture Volume", RT5631_MONO_INPUT_VOL, + RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT, + RT5631_VOL_MASK, 1, in_vol_tlv), + /* AXI */ + SOC_DOUBLE_TLV("AXI Capture Volume", RT5631_AUX_IN_VOL, + RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT, + RT5631_VOL_MASK, 1, in_vol_tlv), + /* DAC */ + SOC_DOUBLE_TLV("PCM Playback Volume", RT5631_STEREO_DAC_VOL_2, + RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT, + RT5631_DAC_VOL_MASK, 1, dac_vol_tlv), + SOC_DOUBLE("PCM Playback Switch", RT5631_STEREO_DAC_VOL_1, + RT5631_L_MUTE_SHIFT, RT5631_R_MUTE_SHIFT, 1, 1), + /* AXO */ + SOC_SINGLE("AXO1 Playback Switch", RT5631_MONO_AXO_1_2_VOL, + RT5631_L_MUTE_SHIFT, 1, 1), + SOC_SINGLE("AXO2 Playback Switch", RT5631_MONO_AXO_1_2_VOL, + RT5631_R_VOL_SHIFT, 1, 1), + /* OUTVOL */ + SOC_DOUBLE("OUTVOL Channel Switch", RT5631_SPK_OUT_VOL, + RT5631_L_EN_SHIFT, RT5631_R_EN_SHIFT, 1, 0), + + /* SPK */ + SOC_DOUBLE("Speaker Playback Switch", RT5631_SPK_OUT_VOL, + RT5631_L_MUTE_SHIFT, RT5631_R_MUTE_SHIFT, 1, 1), + SOC_DOUBLE_TLV("Speaker Playback Volume", RT5631_SPK_OUT_VOL, + RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT, 39, 1, out_vol_tlv), + /* MONO OUT */ + SOC_SINGLE("MONO Playback Switch", RT5631_MONO_AXO_1_2_VOL, + RT5631_MUTE_MONO_SHIFT, 1, 1), + /* HP */ + SOC_DOUBLE("HP Playback Switch", RT5631_HP_OUT_VOL, + RT5631_L_MUTE_SHIFT, RT5631_R_MUTE_SHIFT, 1, 1), + SOC_DOUBLE_TLV("HP Playback Volume", RT5631_HP_OUT_VOL, + RT5631_L_VOL_SHIFT, RT5631_R_VOL_SHIFT, + RT5631_VOL_MASK, 1, out_vol_tlv), + /* DMIC */ + SOC_SINGLE_EXT("DMIC Switch", 0, 0, 1, 0, + rt5631_dmic_get, rt5631_dmic_put), + SOC_DOUBLE("DMIC Capture Switch", RT5631_DIG_MIC_CTRL, + RT5631_DMIC_L_CH_MUTE_SHIFT, + RT5631_DMIC_R_CH_MUTE_SHIFT, 1, 1), + + /* SPK Ratio Gain Control */ + SOC_ENUM("SPK Ratio Control", rt5631_spk_ratio_enum), +}; + +static int check_sysclk1_source(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg; + + reg = snd_soc_read(source->codec, RT5631_GLOBAL_CLK_CTRL); + return reg & RT5631_SYSCLK_SOUR_SEL_PLL; +} + +static int check_dmic_used(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(source->codec); + return rt5631->dmic_used_flag; +} + +static int check_dacl_to_outmixl(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg; + + reg = snd_soc_read(source->codec, RT5631_OUTMIXER_L_CTRL); + return !(reg & RT5631_M_DAC_L_TO_OUTMIXER_L); +} + +static int check_dacr_to_outmixr(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg; + + reg = snd_soc_read(source->codec, RT5631_OUTMIXER_R_CTRL); + return !(reg & RT5631_M_DAC_R_TO_OUTMIXER_R); +} + +static int check_dacl_to_spkmixl(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg; + + reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL); + return !(reg & RT5631_M_DAC_L_TO_SPKMIXER_L); +} + +static int check_dacr_to_spkmixr(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg; + + reg = snd_soc_read(source->codec, RT5631_SPK_MIXER_CTRL); + return !(reg & RT5631_M_DAC_R_TO_SPKMIXER_R); +} + +static int check_vdac_to_outmix(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg, ret = 1; + + reg = snd_soc_read(source->codec, RT5631_OUTMIXER_L_CTRL); + if (reg & RT5631_M_VDAC_TO_OUTMIXER_L) { + reg = snd_soc_read(source->codec, RT5631_OUTMIXER_R_CTRL); + if (reg & RT5631_M_VDAC_TO_OUTMIXER_R) + ret = 0; + } + return ret; +} + +static int check_adcl_select(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg; + + reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER); + return !(reg & RT5631_M_MIC1_TO_RECMIXER_L); +} + +static int check_adcr_select(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + unsigned int reg; + + reg = snd_soc_read(source->codec, RT5631_ADC_REC_MIXER); + return !(reg & RT5631_M_MIC2_TO_RECMIXER_R); +} + +/** + * onebit_depop_power_stage - auto depop in power stage. + * @enable: power on/off + * + * When power on/off headphone, the depop sequence is done by hardware. + */ +static void onebit_depop_power_stage(struct snd_soc_codec *codec, int enable) +{ + unsigned int soft_vol, hp_zc; + + /* enable one-bit depop function */ + snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2, + RT5631_EN_ONE_BIT_DEPOP, 0); + + /* keep soft volume and zero crossing setting */ + soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL); + snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0); + hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2); + snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff); + if (enable) { + /* config one-bit depop parameter */ + rt5631_write_index(codec, RT5631_TEST_MODE_CTRL, 0x84c0); + rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x309f); + rt5631_write_index(codec, RT5631_CP_INTL_REG2, 0x6530); + /* power on capless block */ + snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_2, + RT5631_EN_CAP_FREE_DEPOP); + } else { + /* power off capless block */ + snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_2, 0); + msleep(100); + } + + /* recover soft volume and zero crossing setting */ + snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol); + snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc); +} + +/** + * onebit_depop_mute_stage - auto depop in mute stage. + * @enable: mute/unmute + * + * When mute/unmute headphone, the depop sequence is done by hardware. + */ +static void onebit_depop_mute_stage(struct snd_soc_codec *codec, int enable) +{ + unsigned int soft_vol, hp_zc; + + /* enable one-bit depop function */ + snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2, + RT5631_EN_ONE_BIT_DEPOP, 0); + + /* keep soft volume and zero crossing setting */ + soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL); + snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0); + hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2); + snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff); + if (enable) { + schedule_timeout_uninterruptible(msecs_to_jiffies(10)); + /* config one-bit depop parameter */ + rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x307f); + snd_soc_update_bits(codec, RT5631_HP_OUT_VOL, + RT5631_L_MUTE | RT5631_R_MUTE, 0); + msleep(300); + } else { + snd_soc_update_bits(codec, RT5631_HP_OUT_VOL, + RT5631_L_MUTE | RT5631_R_MUTE, + RT5631_L_MUTE | RT5631_R_MUTE); + msleep(100); + } + + /* recover soft volume and zero crossing setting */ + snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol); + snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc); +} + +/** + * onebit_depop_power_stage - step by step depop sequence in power stage. + * @enable: power on/off + * + * When power on/off headphone, the depop sequence is done in step by step. + */ +static void depop_seq_power_stage(struct snd_soc_codec *codec, int enable) +{ + unsigned int soft_vol, hp_zc; + + /* depop control by register */ + snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2, + RT5631_EN_ONE_BIT_DEPOP, RT5631_EN_ONE_BIT_DEPOP); + + /* keep soft volume and zero crossing setting */ + soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL); + snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0); + hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2); + snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff); + if (enable) { + /* config depop sequence parameter */ + rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x303e); + + /* power on headphone and charge pump */ + snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3, + RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP | + RT5631_PWR_HP_R_AMP, + RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP | + RT5631_PWR_HP_R_AMP); + + /* power on soft generator and depop mode2 */ + snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1, + RT5631_POW_ON_SOFT_GEN | RT5631_EN_DEPOP2_FOR_HP); + msleep(100); + + /* stop depop mode */ + snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3, + RT5631_PWR_HP_DEPOP_DIS, RT5631_PWR_HP_DEPOP_DIS); + } else { + /* config depop sequence parameter */ + rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x303F); + snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1, + RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP | + RT5631_PD_HPAMP_L_ST_UP | RT5631_PD_HPAMP_R_ST_UP); + msleep(75); + snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1, + RT5631_POW_ON_SOFT_GEN | RT5631_PD_HPAMP_L_ST_UP | + RT5631_PD_HPAMP_R_ST_UP); + + /* start depop mode */ + snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3, + RT5631_PWR_HP_DEPOP_DIS, 0); + + /* config depop sequence parameter */ + snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1, + RT5631_POW_ON_SOFT_GEN | RT5631_EN_DEPOP2_FOR_HP | + RT5631_PD_HPAMP_L_ST_UP | RT5631_PD_HPAMP_R_ST_UP); + msleep(80); + snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1, + RT5631_POW_ON_SOFT_GEN); + + /* power down headphone and charge pump */ + snd_soc_update_bits(codec, RT5631_PWR_MANAG_ADD3, + RT5631_PWR_CHARGE_PUMP | RT5631_PWR_HP_L_AMP | + RT5631_PWR_HP_R_AMP, 0); + } + + /* recover soft volume and zero crossing setting */ + snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol); + snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc); +} + +/** + * depop_seq_mute_stage - step by step depop sequence in mute stage. + * @enable: mute/unmute + * + * When mute/unmute headphone, the depop sequence is done in step by step. + */ +static void depop_seq_mute_stage(struct snd_soc_codec *codec, int enable) +{ + unsigned int soft_vol, hp_zc; + + /* depop control by register */ + snd_soc_update_bits(codec, RT5631_DEPOP_FUN_CTRL_2, + RT5631_EN_ONE_BIT_DEPOP, RT5631_EN_ONE_BIT_DEPOP); + + /* keep soft volume and zero crossing setting */ + soft_vol = snd_soc_read(codec, RT5631_SOFT_VOL_CTRL); + snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, 0); + hp_zc = snd_soc_read(codec, RT5631_INT_ST_IRQ_CTRL_2); + snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc & 0xf7ff); + if (enable) { + schedule_timeout_uninterruptible(msecs_to_jiffies(10)); + + /* config depop sequence parameter */ + rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x302f); + snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1, + RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP | + RT5631_EN_HP_R_M_UN_MUTE_DEPOP | + RT5631_EN_HP_L_M_UN_MUTE_DEPOP); + + snd_soc_update_bits(codec, RT5631_HP_OUT_VOL, + RT5631_L_MUTE | RT5631_R_MUTE, 0); + msleep(160); + } else { + /* config depop sequence parameter */ + rt5631_write_index(codec, RT5631_SPK_INTL_CTRL, 0x302f); + snd_soc_write(codec, RT5631_DEPOP_FUN_CTRL_1, + RT5631_POW_ON_SOFT_GEN | RT5631_EN_MUTE_UNMUTE_DEPOP | + RT5631_EN_HP_R_M_UN_MUTE_DEPOP | + RT5631_EN_HP_L_M_UN_MUTE_DEPOP); + + snd_soc_update_bits(codec, RT5631_HP_OUT_VOL, + RT5631_L_MUTE | RT5631_R_MUTE, + RT5631_L_MUTE | RT5631_R_MUTE); + msleep(150); + } + + /* recover soft volume and zero crossing setting */ + snd_soc_write(codec, RT5631_SOFT_VOL_CTRL, soft_vol); + snd_soc_write(codec, RT5631_INT_ST_IRQ_CTRL_2, hp_zc); +} + +static int hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMD: + if (rt5631->codec_version) { + onebit_depop_mute_stage(codec, 0); + onebit_depop_power_stage(codec, 0); + } else { + depop_seq_mute_stage(codec, 0); + depop_seq_power_stage(codec, 0); + } + break; + + case SND_SOC_DAPM_POST_PMU: + if (rt5631->codec_version) { + onebit_depop_power_stage(codec, 1); + onebit_depop_mute_stage(codec, 1); + } else { + depop_seq_power_stage(codec, 1); + depop_seq_mute_stage(codec, 1); + } + break; + + default: + break; + } + + return 0; +} + +static int set_dmic_params(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = w->codec; + struct rt5631_priv *rt5631 = snd_soc_codec_get_drvdata(codec); + + switch (rt5631->rx_rate) { + case 44100: + case 48000: + snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL, + RT5631_DMIC_CLK_CTRL_MASK, + RT5631_DMIC_CLK_CTRL_TO_32FS); + break; + + case 32000: + case 22050: + snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL, + RT5631_DMIC_CLK_CTRL_MASK, + RT5631_DMIC_CLK_CTRL_TO_64FS); + break; + + case 16000: + case 11025: + case 8000: + snd_soc_update_bits(codec, RT5631_DIG_MIC_CTRL, + RT5631_DMIC_CLK_CTRL_MASK, + RT5631_DMIC_CLK_CTRL_TO_128FS); + break; + + default: + return -EINVAL; + } + + return 0; +} + +static const struct snd_kcontrol_new rt5631_recmixl_mixer_controls[] = { + SOC_DAPM_SINGLE("OUTMIXL Capture Switch", RT5631_ADC_REC_MIXER, + RT5631_M_OUTMIXL_RECMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("MIC1_BST1 Capture Switch", RT5631_ADC_REC_MIXER, + RT5631_M_MIC1_RECMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("AXILVOL Capture Switch", RT5631_ADC_REC_MIXER, + RT5631_M_AXIL_RECMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER, + RT5631_M_MONO_IN_RECMIXL_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5631_recmixr_mixer_controls[] = { + SOC_DAPM_SINGLE("MONOIN_RX Capture Switch", RT5631_ADC_REC_MIXER, + RT5631_M_MONO_IN_RECMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("AXIRVOL Capture Switch", RT5631_ADC_REC_MIXER, + RT5631_M_AXIR_RECMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("MIC2_BST2 Capture Switch", RT5631_ADC_REC_MIXER, + RT5631_M_MIC2_RECMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("OUTMIXR Capture Switch", RT5631_ADC_REC_MIXER, + RT5631_M_OUTMIXR_RECMIXR_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5631_spkmixl_mixer_controls[] = { + SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_SPK_MIXER_CTRL, + RT5631_M_RECMIXL_SPKMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("MIC1_P Playback Switch", RT5631_SPK_MIXER_CTRL, + RT5631_M_MIC1P_SPKMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_SPK_MIXER_CTRL, + RT5631_M_DACL_SPKMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("OUTMIXL Playback Switch", RT5631_SPK_MIXER_CTRL, + RT5631_M_OUTMIXL_SPKMIXL_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5631_spkmixr_mixer_controls[] = { + SOC_DAPM_SINGLE("OUTMIXR Playback Switch", RT5631_SPK_MIXER_CTRL, + RT5631_M_OUTMIXR_SPKMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_SPK_MIXER_CTRL, + RT5631_M_DACR_SPKMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("MIC2_P Playback Switch", RT5631_SPK_MIXER_CTRL, + RT5631_M_MIC2P_SPKMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_SPK_MIXER_CTRL, + RT5631_M_RECMIXR_SPKMIXR_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5631_outmixl_mixer_controls[] = { + SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_L_CTRL, + RT5631_M_RECMIXL_OUTMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_L_CTRL, + RT5631_M_RECMIXR_OUTMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("DACL Playback Switch", RT5631_OUTMIXER_L_CTRL, + RT5631_M_DACL_OUTMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_L_CTRL, + RT5631_M_MIC1_OUTMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_L_CTRL, + RT5631_M_MIC2_OUTMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("MONOIN_RXP Playback Switch", RT5631_OUTMIXER_L_CTRL, + RT5631_M_MONO_INP_OUTMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_L_CTRL, + RT5631_M_AXIL_OUTMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_L_CTRL, + RT5631_M_AXIR_OUTMIXL_BIT, 1, 1), + SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_L_CTRL, + RT5631_M_VDAC_OUTMIXL_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5631_outmixr_mixer_controls[] = { + SOC_DAPM_SINGLE("VDAC Playback Switch", RT5631_OUTMIXER_R_CTRL, + RT5631_M_VDAC_OUTMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("AXIRVOL Playback Switch", RT5631_OUTMIXER_R_CTRL, + RT5631_M_AXIR_OUTMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("AXILVOL Playback Switch", RT5631_OUTMIXER_R_CTRL, + RT5631_M_AXIL_OUTMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("MONOIN_RXN Playback Switch", RT5631_OUTMIXER_R_CTRL, + RT5631_M_MONO_INN_OUTMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_OUTMIXER_R_CTRL, + RT5631_M_MIC2_OUTMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_OUTMIXER_R_CTRL, + RT5631_M_MIC1_OUTMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("DACR Playback Switch", RT5631_OUTMIXER_R_CTRL, + RT5631_M_DACR_OUTMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("RECMIXR Playback Switch", RT5631_OUTMIXER_R_CTRL, + RT5631_M_RECMIXR_OUTMIXR_BIT, 1, 1), + SOC_DAPM_SINGLE("RECMIXL Playback Switch", RT5631_OUTMIXER_R_CTRL, + RT5631_M_RECMIXL_OUTMIXR_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5631_AXO1MIX_mixer_controls[] = { + SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO1MIXER_CTRL, + RT5631_M_MIC1_AXO1MIX_BIT , 1, 1), + SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO1MIXER_CTRL, + RT5631_M_MIC2_AXO1MIX_BIT, 1, 1), + SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO1MIXER_CTRL, + RT5631_M_OUTMIXL_AXO1MIX_BIT , 1 , 1), + SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO1MIXER_CTRL, + RT5631_M_OUTMIXR_AXO1MIX_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5631_AXO2MIX_mixer_controls[] = { + SOC_DAPM_SINGLE("MIC1_BST1 Playback Switch", RT5631_AXO2MIXER_CTRL, + RT5631_M_MIC1_AXO2MIX_BIT, 1, 1), + SOC_DAPM_SINGLE("MIC2_BST2 Playback Switch", RT5631_AXO2MIXER_CTRL, + RT5631_M_MIC2_AXO2MIX_BIT, 1, 1), + SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_AXO2MIXER_CTRL, + RT5631_M_OUTMIXL_AXO2MIX_BIT, 1, 1), + SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_AXO2MIXER_CTRL, + RT5631_M_OUTMIXR_AXO2MIX_BIT, 1 , 1), +}; + +static const struct snd_kcontrol_new rt5631_spolmix_mixer_controls[] = { + SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL, + RT5631_M_SPKVOLL_SPOLMIX_BIT, 1, 1), + SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL, + RT5631_M_SPKVOLR_SPOLMIX_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5631_spormix_mixer_controls[] = { + SOC_DAPM_SINGLE("SPKVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL, + RT5631_M_SPKVOLL_SPORMIX_BIT, 1, 1), + SOC_DAPM_SINGLE("SPKVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL, + RT5631_M_SPKVOLR_SPORMIX_BIT, 1, 1), +}; + +static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = { + SOC_DAPM_SINGLE("OUTVOLL Playback Switch", RT5631_SPK_MONO_OUT_CTRL, + RT5631_M_OUTVOLL_MONOMIX_BIT, 1, 1), + SOC_DAPM_SINGLE("OUTVOLR Playback Switch", RT5631_SPK_MONO_OUT_CTRL, + RT5631_M_OUTVOLR_MONOMIX_BIT, 1, 1), +}; + +/* Left SPK Volume Input */ +static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL, + RT5631_L_EN_SHIFT, rt5631_spkvoll_sel); + +static const struct snd_kcontrol_new rt5631_spkvoll_mux_control = + SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum); + +/* Left HP Volume Input */ +static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_hpvoll_enum, RT5631_HP_OUT_VOL, + RT5631_L_EN_SHIFT, rt5631_hpvoll_sel); + +static const struct snd_kcontrol_new rt5631_hpvoll_mux_control = + SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum); + +/* Left Out Volume Input */ +static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL, + RT5631_L_EN_SHIFT, rt5631_outvoll_sel); + +static const struct snd_kcontrol_new rt5631_outvoll_mux_control = + SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum); + +/* Right Out Volume Input */ +static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL, + RT5631_R_EN_SHIFT, rt5631_outvolr_sel); + +static const struct snd_kcontrol_new rt5631_outvolr_mux_control = + SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum); + +/* Right HP Volume Input */ +static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_hpvolr_enum, RT5631_HP_OUT_VOL, + RT5631_R_EN_SHIFT, rt5631_hpvolr_sel); + +static const struct snd_kcontrol_new rt5631_hpvolr_mux_control = + SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum); + +/* Right SPK Volume Input */ +static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL, + RT5631_R_EN_SHIFT, rt5631_spkvolr_sel); + +static const struct snd_kcontrol_new rt5631_spkvolr_mux_control = + SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum); + +/* SPO Left Channel Input */ +static const char *rt5631_spol_src_sel[] = { + "SPOLMIX", "MONOIN_RX", "VDAC", "DACL"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel); + +static const struct snd_kcontrol_new rt5631_spol_mux_control = + SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum); + +/* SPO Right Channel Input */ +static const char *rt5631_spor_src_sel[] = { + "SPORMIX", "MONOIN_RX", "VDAC", "DACR"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel); + +static const struct snd_kcontrol_new rt5631_spor_mux_control = + SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum); + +/* MONO Input */ +static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel); + +static const struct snd_kcontrol_new rt5631_mono_mux_control = + SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum); + +/* Left HPO Input */ +static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel); + +static const struct snd_kcontrol_new rt5631_hpl_mux_control = + SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum); + +/* Right HPO Input */ +static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"}; + +static const SOC_ENUM_SINGLE_DECL( + rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, + RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel); + +static const struct snd_kcontrol_new rt5631_hpr_mux_control = + SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum); + +static const struct snd_soc_dapm_widget rt5631_dapm_widgets[] = { + /* Vmid */ + SND_SOC_DAPM_VMID("Vmid"), + /* PLL1 */ + SND_SOC_DAPM_SUPPLY("PLL1", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_PLL1_BIT, 0, NULL, 0), + + /* Input Side */ + /* Input Lines */ + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("MIC2"), + SND_SOC_DAPM_INPUT("AXIL"), + SND_SOC_DAPM_INPUT("AXIR"), + SND_SOC_DAPM_INPUT("MONOIN_RXN"), + SND_SOC_DAPM_INPUT("MONOIN_RXP"), + SND_SOC_DAPM_INPUT("DMIC"), + + /* MICBIAS */ + SND_SOC_DAPM_MICBIAS("MIC Bias1", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_MICBIAS1_VOL_BIT, 0), + SND_SOC_DAPM_MICBIAS("MIC Bias2", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_MICBIAS2_VOL_BIT, 0), + + /* Boost */ + SND_SOC_DAPM_PGA("MIC1 Boost", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_MIC1_BOOT_GAIN_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("MIC2 Boost", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_MIC2_BOOT_GAIN_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("MONOIN_RXP Boost", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_MONO_IN_P_VOL_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("MONOIN_RXN Boost", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_MONO_IN_N_VOL_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("AXIL Boost", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_AXIL_IN_VOL_BIT, 0, NULL, 0), + SND_SOC_DAPM_PGA("AXIR Boost", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_AXIR_IN_VOL_BIT, 0, NULL, 0), + + /* MONO In */ + SND_SOC_DAPM_MIXER("MONO_IN", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIXL Mixer", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_RECMIXER_L_BIT, 0, + &rt5631_recmixl_mixer_controls[0], + ARRAY_SIZE(rt5631_recmixl_mixer_controls)), + SND_SOC_DAPM_MIXER("RECMIXR Mixer", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_RECMIXER_R_BIT, 0, + &rt5631_recmixr_mixer_controls[0], + ARRAY_SIZE(rt5631_recmixr_mixer_controls)), + /* Because of record duplication for L/R channel, + * L/R ADCs need power up at the same time */ + SND_SOC_DAPM_MIXER("ADC Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), + + /* DMIC */ + SND_SOC_DAPM_SUPPLY("DMIC Supply", RT5631_DIG_MIC_CTRL, + RT5631_DMIC_ENA_SHIFT, 0, + set_dmic_params, SND_SOC_DAPM_PRE_PMU), + /* ADC Data Srouce */ + SND_SOC_DAPM_SUPPLY("Left ADC Select", RT5631_INT_ST_IRQ_CTRL_2, + RT5631_ADC_DATA_SEL_MIC1_SHIFT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Right ADC Select", RT5631_INT_ST_IRQ_CTRL_2, + RT5631_ADC_DATA_SEL_MIC2_SHIFT, 0, NULL, 0), + + /* ADCs */ + SND_SOC_DAPM_ADC("Left ADC", "HIFI Capture", + RT5631_PWR_MANAG_ADD1, RT5631_PWR_ADC_L_CLK_BIT, 0), + SND_SOC_DAPM_ADC("Right ADC", "HIFI Capture", + RT5631_PWR_MANAG_ADD1, RT5631_PWR_ADC_R_CLK_BIT, 0), + + /* DAC and ADC supply power */ + SND_SOC_DAPM_SUPPLY("I2S", RT5631_PWR_MANAG_ADD1, + RT5631_PWR_MAIN_I2S_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("DAC REF", RT5631_PWR_MANAG_ADD1, + RT5631_PWR_DAC_REF_BIT, 0, NULL, 0), + + /* Output Side */ + /* DACs */ + SND_SOC_DAPM_DAC("Left DAC", "HIFI Playback", + RT5631_PWR_MANAG_ADD1, RT5631_PWR_DAC_L_CLK_BIT, 0), + SND_SOC_DAPM_DAC("Right DAC", "HIFI Playback", + RT5631_PWR_MANAG_ADD1, RT5631_PWR_DAC_R_CLK_BIT, 0), + SND_SOC_DAPM_DAC("Voice DAC", "Voice DAC Mono Playback", + SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_PGA("Voice DAC Boost", SND_SOC_NOPM, 0, 0, NULL, 0), + /* DAC supply power */ + SND_SOC_DAPM_SUPPLY("Left DAC To Mixer", RT5631_PWR_MANAG_ADD1, + RT5631_PWR_DAC_L_TO_MIXER_BIT, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("Right DAC To Mixer", RT5631_PWR_MANAG_ADD1, + RT5631_PWR_DAC_R_TO_MIXER_BIT, 0, NULL, 0), + + /* Left SPK Mixer */ + SND_SOC_DAPM_MIXER("SPKMIXL Mixer", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_SPKMIXER_L_BIT, 0, + &rt5631_spkmixl_mixer_controls[0], + ARRAY_SIZE(rt5631_spkmixl_mixer_controls)), + /* Left Out Mixer */ + SND_SOC_DAPM_MIXER("OUTMIXL Mixer", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_OUTMIXER_L_BIT, 0, + &rt5631_outmixl_mixer_controls[0], + ARRAY_SIZE(rt5631_outmixl_mixer_controls)), + /* Right Out Mixer */ + SND_SOC_DAPM_MIXER("OUTMIXR Mixer", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_OUTMIXER_R_BIT, 0, + &rt5631_outmixr_mixer_controls[0], + ARRAY_SIZE(rt5631_outmixr_mixer_controls)), + /* Right SPK Mixer */ + SND_SOC_DAPM_MIXER("SPKMIXR Mixer", RT5631_PWR_MANAG_ADD2, + RT5631_PWR_SPKMIXER_R_BIT, 0, + &rt5631_spkmixr_mixer_controls[0], + ARRAY_SIZE(rt5631_spkmixr_mixer_controls)), + + /* Volume Mux */ + SND_SOC_DAPM_MUX("Left SPKVOL Mux", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_SPK_L_VOL_BIT, 0, + &rt5631_spkvoll_mux_control), + SND_SOC_DAPM_MUX("Left HPVOL Mux", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_HP_L_OUT_VOL_BIT, 0, + &rt5631_hpvoll_mux_control), + SND_SOC_DAPM_MUX("Left OUTVOL Mux", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_LOUT_VOL_BIT, 0, + &rt5631_outvoll_mux_control), + SND_SOC_DAPM_MUX("Right OUTVOL Mux", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_ROUT_VOL_BIT, 0, + &rt5631_outvolr_mux_control), + SND_SOC_DAPM_MUX("Right HPVOL Mux", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_HP_R_OUT_VOL_BIT, 0, + &rt5631_hpvolr_mux_control), + SND_SOC_DAPM_MUX("Right SPKVOL Mux", RT5631_PWR_MANAG_ADD4, + RT5631_PWR_SPK_R_VOL_BIT, 0, + &rt5631_spkvolr_mux_control), + + /* DAC To HP */ + SND_SOC_DAPM_PGA_S("Left DAC_HP", 0, SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_PGA_S("Right DAC_HP", 0, SND_SOC_NOPM, 0, 0, NULL, 0), + + /* HP Depop */ + SND_SOC_DAPM_PGA_S("HP Depop", 1, SND_SOC_NOPM, 0, 0, + hp_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + + /* AXO1 Mixer */ + SND_SOC_DAPM_MIXER("AXO1MIX Mixer", RT5631_PWR_MANAG_ADD3, + RT5631_PWR_AXO1MIXER_BIT, 0, + &rt5631_AXO1MIX_mixer_controls[0], + ARRAY_SIZE(rt5631_AXO1MIX_mixer_controls)), + /* SP |