asoc: alc5640: Mic noise gate
[linux-2.6.git] / sound / soc / codecs / rt5640.c
index 2abfac1..509e4c1 100644 (file)
 #include <sound/tlv.h>
 
 #include "rt5640.h"
-#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642)
+#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
 #include "rt5640-dsp.h"
 #endif
 
 #define RT5640_DEMO 1
 #define RT5640_REG_RW 1
 #define RT5640_DET_EXT_MIC 0
+#define RT5639_RESET_ID 0x0008
+#define USE_ONEBIT_DEPOP 1 /* for one bit depop */
+
+#define CHECK_I2C_SHUTDOWN(r, c) { if (r && r->shutdown_complete) { \
+dev_err(c->dev, "error: i2c state is 'shutdown'\n"); \
+mutex_unlock(&r->lock); return -ENODEV; } }
 
 #ifdef RT5640_DEMO
 struct rt5640_init_reg {
@@ -40,7 +46,7 @@ struct rt5640_init_reg {
 };
 
 static struct rt5640_init_reg init_list[] = {
-       {RT5640_DUMMY1          , 0x3701},/*fa[12:13] = 1'b;fa[8~10]=1;fa[0]=1*/
+       {RT5640_GEN_CTRL1       , 0x3701},/*fa[12:13] = 1'b; fa[8~10]=1; fa[0]=1 */
        {RT5640_DEPOP_M1        , 0x0019},/* 8e[4:3] = 11'b; 8e[0] = 1'b */
        {RT5640_DEPOP_M2        , 0x3100},/* 8f[13] = 1'b */
        {RT5640_ADDA_CLK1       , 0x1114},/* 73[2] = 1'b  */
@@ -48,6 +54,7 @@ static struct rt5640_init_reg init_list[] = {
        {RT5640_PRIV_INDEX      , 0x003d},/* PR3d[12] = 1'b */
        {RT5640_PRIV_DATA       , 0x3600},
        {RT5640_CLS_D_OUT       , 0xa000},/* 8d[11] = 0'b */
+       {RT5640_CLS_D_OVCD      , 0x0328},//8c[8] = 1'b
        {RT5640_PRIV_INDEX      , 0x001c},/* PR1c = 0D21'h */
        {RT5640_PRIV_DATA       , 0x0D21},
        {RT5640_PRIV_INDEX      , 0x001b},/* PR1B = 0D21'h */
@@ -62,6 +69,8 @@ static struct rt5640_init_reg init_list[] = {
        {RT5640_PRIV_DATA       , 0xe0e0},
        {RT5640_PRIV_INDEX      , 0x0023},/* PR23 = 1804'h */
        {RT5640_PRIV_DATA       , 0x1804},
+       {RT5640_PRIV_INDEX      , 0x006e},/* PR6E = 1804'h */
+       {RT5640_PRIV_DATA       , 0x3219},
        /*playback*/
        {RT5640_STO_DAC_MIXER   , 0x1414},/*Dig inf 1 -> Sto DAC mixer -> DACL*/
        {RT5640_OUT_L3_MIXER    , 0x01fe},/*DACL1 -> OUTMIXL*/
@@ -69,9 +78,16 @@ static struct rt5640_init_reg init_list[] = {
        {RT5640_HP_VOL          , 0x8888},/* OUTMIX -> HPVOL */
        {RT5640_HPO_MIXER       , 0xc000},/* HPVOL -> HPOLMIX */
 /*     {RT5640_HPO_MIXER       , 0xa000},// DAC1 -> HPOLMIX   */
+       {RT5640_CHARGE_PUMP     , 0x0f00},
+       {RT5640_PRIV_INDEX      , 0x0090},
+       {RT5640_PRIV_DATA       , 0x2000},
+       {RT5640_PRIV_INDEX      , 0x0091},
+       {RT5640_PRIV_DATA       , 0x1000},
+       {RT5640_HP_CALIB_AMP_DET, 0x0420},
        {RT5640_SPK_L_MIXER     , 0x0036},/* DACL1 -> SPKMIXL */
        {RT5640_SPK_R_MIXER     , 0x0036},/* DACR1 -> SPKMIXR */
        {RT5640_SPK_VOL         , 0x8888},/* SPKMIX -> SPKVOL */
+       {RT5640_SPO_CLSD_RATIO  , 0x0001},
        {RT5640_SPO_L_MIXER     , 0xe800},/* SPKVOLL -> SPOLMIX */
        {RT5640_SPO_R_MIXER     , 0x2800},/* SPKVOLR -> SPORMIX */
 /*     {RT5640_SPO_L_MIXER     , 0xb800},//DAC -> SPOLMIX */
@@ -106,6 +122,18 @@ static int rt5640_reg_init(struct snd_soc_codec *codec)
 }
 #endif
 
+static int rt5640_index_sync(struct snd_soc_codec *codec)
+{
+       int i;
+
+       for (i = 0; i < RT5640_INIT_REG_LEN; i++)
+               if (RT5640_PRIV_INDEX == init_list[i].reg ||
+                       RT5640_PRIV_DATA == init_list[i].reg)
+                       snd_soc_write(codec, init_list[i].reg,
+                                       init_list[i].val);
+       return 0;
+}
+
 static const u16 rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
        [RT5640_RESET] = 0x000c,
        [RT5640_SPK_VOL] = 0xc8c8,
@@ -150,11 +178,12 @@ static const u16 rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
        [RT5640_DEPOP_M1] = 0x0004,
        [RT5640_DEPOP_M2] = 0x1100,
        [RT5640_DEPOP_M3] = 0x0646,
-       [RT5640_CHARGE_PUMP] = 0x0c00,
+       [RT5640_CHARGE_PUMP] = 0x0d00,
        [RT5640_MICBIAS] = 0x3000,
        [RT5640_EQ_CTRL1] = 0x2080,
-       [RT5640_DRC_AGC_1] = 0x2206,
+       [RT5640_DRC_AGC_1] = 0xe206,
        [RT5640_DRC_AGC_2] = 0x1f00,
+       [RT5640_DRC_AGC_3] = 0x0040,
        [RT5640_ANC_CTRL1] = 0x034b,
        [RT5640_ANC_CTRL2] = 0x0066,
        [RT5640_ANC_CTRL3] = 0x000b,
@@ -164,13 +193,14 @@ static const u16 rt5640_reg[RT5640_VENDOR_ID2 + 1] = {
        [RT5640_MP3_PLUS1] = 0x0680,
        [RT5640_MP3_PLUS2] = 0x1c17,
        [RT5640_3D_HP] = 0x8c00,
-       [RT5640_ADJ_HPF] = 0x2a20,
-       [RT5640_HP_CALIB_AMP_DET] = 0x0400,
+       [RT5640_ADJ_HPF] = 0xaa20,
+       [RT5640_HP_CALIB_AMP_DET] = 0x0420,
        [RT5640_SV_ZCD1] = 0x0809,
        [RT5640_VENDOR_ID1] = 0x10ec,
        [RT5640_VENDOR_ID2] = 0x6231,
 };
 
+
 static int rt5640_reset(struct snd_soc_codec *codec)
 {
        return snd_soc_write(codec, RT5640_RESET, 0);
@@ -287,6 +317,9 @@ static int rt5640_volatile_register(
        case RT5640_DSP_CTRL3:
        case RT5640_PGM_REG_ARR1:
        case RT5640_PGM_REG_ARR3:
+       case RT5640_VENDOR_ID:
+       case RT5640_VENDOR_ID1:
+       case RT5640_VENDOR_ID2:
                return 1;
        default:
                return 0;
@@ -407,28 +440,61 @@ static int rt5640_readable_register(
        case RT5640_HP_CALIB2:
        case RT5640_SV_ZCD1:
        case RT5640_SV_ZCD2:
-       case RT5640_DUMMY1:
-       case RT5640_DUMMY2:
-       case RT5640_DUMMY3:
+       case RT5640_GEN_CTRL1:
+       case RT5640_GEN_CTRL2:
+       case RT5640_GEN_CTRL3:
        case RT5640_VENDOR_ID:
        case RT5640_VENDOR_ID1:
        case RT5640_VENDOR_ID2:
+       case RT5640_DUMMY_PR3F:
                return 1;
        default:
                return 0;
        }
 }
 
+void DC_Calibrate(struct snd_soc_codec *codec)
+{
+       unsigned int sclk_src;
+
+       sclk_src = snd_soc_read(codec, RT5640_GLB_CLK) &
+               RT5640_SCLK_SRC_MASK;
+
+       snd_soc_update_bits(codec, RT5640_PWR_ANLG2,
+               RT5640_PWR_MB1, RT5640_PWR_MB1);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M2,
+               RT5640_DEPOP_MASK, RT5640_DEPOP_MAN);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+               RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
+               RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU);
+
+       snd_soc_update_bits(codec, RT5640_GLB_CLK,
+               RT5640_SCLK_SRC_MASK, 0x2 << RT5640_SCLK_SRC_SFT);
+
+       rt5640_index_write(codec, RT5640_HP_DCC_INT1, 0x9f00);
+       snd_soc_update_bits(codec, RT5640_PWR_ANLG2,
+               RT5640_PWR_MB1, 0);
+       snd_soc_update_bits(codec, RT5640_GLB_CLK,
+               RT5640_SCLK_SRC_MASK, sclk_src);
+}
+
+
 int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert)
 {
        int jack_type;
        int sclk_src;
+       int reg63, reg64;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
        if (jack_insert) {
+               reg63 = snd_soc_read(codec, RT5640_PWR_ANLG1);
+               reg64 = snd_soc_read(codec, RT5640_PWR_ANLG2);
                if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
                        snd_soc_write(codec, RT5640_PWR_ANLG1, 0x2004);
                        snd_soc_write(codec, RT5640_MICBIAS, 0x3830);
-                       snd_soc_write(codec, RT5640_DUMMY1 , 0x3701);
+                       snd_soc_write(codec, RT5640_GEN_CTRL1 , 0x3701);
                }
                sclk_src = snd_soc_read(codec, RT5640_GLB_CLK) &
                        RT5640_SCLK_SRC_MASK;
@@ -443,7 +509,7 @@ int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert)
                        RT5640_PWR_CLK25M_MASK | RT5640_PWR_MB_MASK,
                        RT5640_MIC1_OVCD_EN | RT5640_MIC1_OVTH_600UA |
                        RT5640_PWR_MB_PU | RT5640_PWR_CLK25M_PU);
-               snd_soc_update_bits(codec, RT5640_DUMMY1,
+               snd_soc_update_bits(codec, RT5640_GEN_CTRL1,
                        0x1, 0x1);
                msleep(100);
                if (snd_soc_read(codec, RT5640_IRQ_CTRL2) & 0x8)
@@ -454,6 +520,8 @@ int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert)
                        RT5640_MB1_OC_CLR, 0);
                snd_soc_update_bits(codec, RT5640_GLB_CLK,
                        RT5640_SCLK_SRC_MASK, sclk_src);
+               snd_soc_write(codec, RT5640_PWR_ANLG1, reg63);
+               snd_soc_write(codec, RT5640_PWR_ANLG2, reg64);
        } else {
                snd_soc_update_bits(codec, RT5640_MICBIAS,
                        RT5640_MIC1_OVCD_MASK,
@@ -462,6 +530,7 @@ int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert)
                jack_type = RT5640_NO_JACK;
        }
 
+       mutex_unlock(&rt5640->lock);
        return jack_type;
 }
 EXPORT_SYMBOL(rt5640_headset_detect);
@@ -500,9 +569,13 @@ static int rt5640_dmic_put(struct snd_kcontrol *kcontrol,
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
-       if (rt5640->dmic_en == ucontrol->value.integer.value[0])
+       if (rt5640->dmic_en == ucontrol->value.integer.value[0]) {
+               mutex_unlock(&rt5640->lock);
                return 0;
+       }
 
        rt5640->dmic_en = ucontrol->value.integer.value[0];
        switch (rt5640->dmic_en) {
@@ -547,9 +620,11 @@ static int rt5640_dmic_put(struct snd_kcontrol *kcontrol,
                break;
 
        default:
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
 
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
@@ -619,8 +694,13 @@ static int rt5640_regctl_get(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
+
        ucontrol->value.integer.value[0] = regctl_addr;
        ucontrol->value.integer.value[1] = snd_soc_read(codec, regctl_addr);
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
@@ -628,10 +708,15 @@ static int rt5640_regctl_put(struct snd_kcontrol *kcontrol,
                        struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
+
        regctl_addr = ucontrol->value.integer.value[0];
        if (ucontrol->value.integer.value[1] <= REGVAL_MAX)
                snd_soc_write(codec, regctl_addr,
                ucontrol->value.integer.value[1]);
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 #endif
@@ -646,13 +731,18 @@ static int rt5640_vol_rescale_get(struct snd_kcontrol *kcontrol,
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int val = snd_soc_read(codec, mc->reg);
+       unsigned int val;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
+       val = snd_soc_read(codec, mc->reg);
 
        ucontrol->value.integer.value[0] = VOL_RESCALE_MAX_VOL -
                ((val & RT5640_L_VOL_MASK) >> mc->shift);
        ucontrol->value.integer.value[1] = VOL_RESCALE_MAX_VOL -
                (val & RT5640_R_VOL_MASK);
 
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
@@ -663,11 +753,17 @@ static int rt5640_vol_rescale_put(struct snd_kcontrol *kcontrol,
                (struct soc_mixer_control *)kcontrol->private_value;
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
        unsigned int val, val2;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       int ret;
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
        val = VOL_RESCALE_MAX_VOL - ucontrol->value.integer.value[0];
        val2 = VOL_RESCALE_MAX_VOL - ucontrol->value.integer.value[1];
-       return snd_soc_update_bits_locked(codec, mc->reg, RT5640_L_VOL_MASK |
+       ret = snd_soc_update_bits_locked(codec, mc->reg, RT5640_L_VOL_MASK |
                        RT5640_R_VOL_MASK, val << mc->shift | val2);
+       mutex_unlock(&rt5640->lock);
+       return ret;
 }
 
 
@@ -761,6 +857,8 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        struct snd_soc_codec *codec = w->codec;
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        int div[] = {2, 3, 4, 6, 12}, idx = -EINVAL, i, rate, red, bound, temp;
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
        rate = rt5640->lrck[rt5640->aif_pu] << 8;
        red = 3000000 * 12;
@@ -779,6 +877,7 @@ static int set_dmic_clk(struct snd_soc_dapm_widget *w,
        else
                snd_soc_update_bits(codec, RT5640_DMIC, RT5640_DMIC_CLK_MASK,
                                        idx << RT5640_DMIC_CLK_SFT);
+       mutex_unlock(&rt5640->lock);
        return idx;
 }
 
@@ -786,9 +885,13 @@ static int check_sysclk1_source(struct snd_soc_dapm_widget *source,
                         struct snd_soc_dapm_widget *sink)
 {
        unsigned int val;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(source->codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, source->codec)
 
        val = snd_soc_read(source->codec, RT5640_GLB_CLK);
        val &= RT5640_SCLK_SRC_MASK;
+       mutex_unlock(&rt5640->lock);
        if (val == RT5640_SCLK_SRC_PLL1 || val == RT5640_SCLK_SRC_PLL1T)
                return 1;
        else
@@ -1179,8 +1282,9 @@ static int spk_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_codec *codec = w->codec;
-       static unsigned int spkl_out_enable;
-       static unsigned int spkr_out_enable;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
@@ -1198,29 +1302,289 @@ static int spk_event(struct snd_soc_dapm_widget *w,
                break;
 
        default:
+               mutex_unlock(&rt5640->lock);
                return 0;
        }
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
+#if USE_ONEBIT_DEPOP
+void hp_amp_power(struct snd_soc_codec *codec, int on)
+{
+       static int hp_amp_power_count;
+//     printk("one bit hp_amp_power on=%d hp_amp_power_count=%d\n",on,hp_amp_power_count);
+
+       if (on) {
+               if (hp_amp_power_count <= 0) {
+                       /* depop parameters */
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M2,
+                               RT5640_DEPOP_MASK, RT5640_DEPOP_MAN);
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+                               RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
+                               RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU);
+                       /* headphone amp power on */
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2, 0);
+                       msleep(5);
+                       snd_soc_update_bits(codec, RT5640_PWR_VOL,
+                               RT5640_PWR_HV_L | RT5640_PWR_HV_R,
+                               RT5640_PWR_HV_L | RT5640_PWR_HV_R);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_HP_L | RT5640_PWR_HP_R | RT5640_PWR_HA,
+                               RT5640_PWR_HP_L | RT5640_PWR_HP_R | RT5640_PWR_HA);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2 ,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2 );
+               }
+               hp_amp_power_count++;
+       } else {
+               hp_amp_power_count--;
+               if (hp_amp_power_count <= 0) {
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+                               RT5640_HP_CB_MASK, RT5640_HP_CB_PD);
+                       msleep(30);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_HP_L | RT5640_PWR_HP_R | RT5640_PWR_HA,
+                               0);
+                       snd_soc_write(codec, RT5640_DEPOP_M2, 0x3100);
+               }
+       }
+}
+
+static void rt5640_pmu_depop(struct snd_soc_codec *codec)
+{
+       hp_amp_power(codec, 1);
+       /* headphone unmute sequence */
+       snd_soc_update_bits(codec, RT5640_DEPOP_M2,
+               RT5640_DEPOP_MASK | RT5640_DIG_DP_MASK,
+               RT5640_DEPOP_AUTO | RT5640_DIG_DP_EN);
+       snd_soc_update_bits(codec, RT5640_CHARGE_PUMP,
+               RT5640_PM_HP_MASK, RT5640_PM_HP_HV);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M3,
+               RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK,
+               (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) |
+               (RT5640_CP_FQ_24_KHZ << RT5640_CP_FQ2_SFT) |
+               (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT));
+       rt5640_index_write(codec, RT5640_MAMP_INT_REG2, 0x1c00);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+               RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CO_MASK,
+               RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CO_EN);
+       msleep(5);
+       snd_soc_update_bits(codec, RT5640_HP_VOL,
+               RT5640_L_MUTE | RT5640_R_MUTE, 0);
+       msleep(65);
+       //snd_soc_update_bits(codec, RT5640_HP_CALIB_AMP_DET,
+       //      RT5640_HPD_PS_MASK, RT5640_HPD_PS_EN);
+}
+
+static void rt5640_pmd_depop(struct snd_soc_codec *codec)
+{
+       snd_soc_update_bits(codec, RT5640_DEPOP_M3,
+               RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK,
+               (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ1_SFT) |
+               (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+               (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ3_SFT));
+       rt5640_index_write(codec, RT5640_MAMP_INT_REG2, 0x7c00);
+       //snd_soc_update_bits(codec, RT5640_HP_CALIB_AMP_DET,
+       //      RT5640_HPD_PS_MASK, RT5640_HPD_PS_DIS);
+       snd_soc_update_bits(codec, RT5640_HP_VOL,
+               RT5640_L_MUTE | RT5640_R_MUTE,
+               RT5640_L_MUTE | RT5640_R_MUTE);
+       msleep(50);
+       hp_amp_power(codec, 0);
+}
+
+#else //seq
+void hp_amp_power(struct snd_soc_codec *codec, int on)
+{
+       static int hp_amp_power_count;
+//     printk("hp_amp_power on=%d hp_amp_power_count=%d\n",on,hp_amp_power_count);
+
+       if (on) {
+               if (hp_amp_power_count <= 0) {
+                       /* depop parameters */
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M2,
+                               RT5640_DEPOP_MASK, RT5640_DEPOP_MAN);
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+                               RT5640_HP_CP_MASK | RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
+                               RT5640_HP_CP_PU | RT5640_HP_SG_DIS | RT5640_HP_CB_PU);
+                       /* headphone amp power on */
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2 , 0);
+                       snd_soc_update_bits(codec, RT5640_PWR_VOL,
+                               RT5640_PWR_HV_L | RT5640_PWR_HV_R,
+                               RT5640_PWR_HV_L | RT5640_PWR_HV_R);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_HP_L | RT5640_PWR_HP_R | RT5640_PWR_HA | RT5640_PWR_LM,
+                               RT5640_PWR_HP_L | RT5640_PWR_HP_R | RT5640_PWR_HA | RT5640_PWR_LM);
+                       msleep(50);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2,
+                               RT5640_PWR_FV1 | RT5640_PWR_FV2);
+                       snd_soc_update_bits(codec, RT5640_CHARGE_PUMP,
+                               RT5640_PM_HP_MASK, RT5640_PM_HP_HV);
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+                               RT5640_HP_CO_MASK | RT5640_HP_SG_MASK,
+                               RT5640_HP_CO_EN | RT5640_HP_SG_EN);
+               }
+               hp_amp_power_count++;
+       } else {
+               hp_amp_power_count--;
+               if (hp_amp_power_count <= 0) {
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+                               RT5640_HP_SG_MASK | RT5640_HP_L_SMT_MASK |
+                               RT5640_HP_R_SMT_MASK, RT5640_HP_SG_DIS |
+                               RT5640_HP_L_SMT_DIS | RT5640_HP_R_SMT_DIS);
+                       /* headphone amp power down */
+                       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+                               RT5640_SMT_TRIG_MASK | RT5640_HP_CD_PD_MASK |
+                               RT5640_HP_CO_MASK | RT5640_HP_CP_MASK |
+                               RT5640_HP_SG_MASK | RT5640_HP_CB_MASK,
+                               RT5640_SMT_TRIG_DIS | RT5640_HP_CD_PD_EN |
+                               RT5640_HP_CO_DIS | RT5640_HP_CP_PD |
+                               RT5640_HP_SG_EN | RT5640_HP_CB_PD);
+                       snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
+                               RT5640_PWR_HP_L | RT5640_PWR_HP_R | RT5640_PWR_HA | RT5640_PWR_LM,
+                               0);
+               }
+       }
+}
+
+static void rt5640_pmu_depop(struct snd_soc_codec *codec)
+{
+       hp_amp_power(codec, 1);
+       /* headphone unmute sequence */
+       snd_soc_update_bits(codec, RT5640_DEPOP_M3,
+               RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK,
+               (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ1_SFT) |
+               (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+               (RT5640_CP_FQ_192_KHZ << RT5640_CP_FQ3_SFT));
+       rt5640_index_write(codec, RT5640_MAMP_INT_REG2, 0xfc00);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+               RT5640_SMT_TRIG_MASK, RT5640_SMT_TRIG_EN);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+               RT5640_RSTN_MASK, RT5640_RSTN_EN);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+               RT5640_RSTN_MASK | RT5640_HP_L_SMT_MASK | RT5640_HP_R_SMT_MASK,
+               RT5640_RSTN_DIS | RT5640_HP_L_SMT_EN | RT5640_HP_R_SMT_EN);
+       snd_soc_update_bits(codec, RT5640_HP_VOL,
+               RT5640_L_MUTE | RT5640_R_MUTE, 0);
+       msleep(100);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+               RT5640_HP_SG_MASK | RT5640_HP_L_SMT_MASK |
+               RT5640_HP_R_SMT_MASK, RT5640_HP_SG_DIS |
+               RT5640_HP_L_SMT_DIS | RT5640_HP_R_SMT_DIS);
+       msleep(20);
+}
+
+static void rt5640_pmd_depop(struct snd_soc_codec *codec)
+{
+       /* headphone mute sequence */
+       snd_soc_update_bits(codec, RT5640_DEPOP_M3,
+               RT5640_CP_FQ1_MASK | RT5640_CP_FQ2_MASK | RT5640_CP_FQ3_MASK,
+               (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ1_SFT) |
+               (RT5640_CP_FQ_12_KHZ << RT5640_CP_FQ2_SFT) |
+               (RT5640_CP_FQ_96_KHZ << RT5640_CP_FQ3_SFT));
+       rt5640_index_write(codec, RT5640_MAMP_INT_REG2, 0xfc00);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+               RT5640_HP_SG_MASK, RT5640_HP_SG_EN);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+               RT5640_RSTP_MASK, RT5640_RSTP_EN);
+       snd_soc_update_bits(codec, RT5640_DEPOP_M1,
+               RT5640_RSTP_MASK | RT5640_HP_L_SMT_MASK |
+               RT5640_HP_R_SMT_MASK, RT5640_RSTP_DIS |
+               RT5640_HP_L_SMT_EN | RT5640_HP_R_SMT_EN);
+       msleep(90);
+       snd_soc_update_bits(codec, RT5640_HP_VOL,
+               RT5640_L_MUTE | RT5640_R_MUTE, RT5640_L_MUTE | RT5640_R_MUTE);
+       msleep(30);
+
+       hp_amp_power(codec, 0);
+}
+#endif
+
 static int hp_event(struct snd_soc_dapm_widget *w,
        struct snd_kcontrol *kcontrol, int event)
 {
        struct snd_soc_codec *codec = w->codec;
-       static unsigned int hp_out_enable;
 
        switch (event) {
        case SND_SOC_DAPM_POST_PMU:
                pr_info("hp_event --SND_SOC_DAPM_POST_PMU\n");
+               rt5640_pmu_depop(codec);
                break;
 
        case SND_SOC_DAPM_PRE_PMD:
-               pr_info("hp_event --SND_SOC_DAPM_POST_PMD\n");
+               pr_info("hp_event --SND_SOC_DAPM_PRE_PMD\n");
+               rt5640_pmd_depop(codec);
                break;
 
        default:
                return 0;
        }
+
+       return 0;
+}
+
+
+static int rt5640_set_dmic1_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       unsigned int val, mask;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
+                       RT5640_GP2_PIN_MASK | RT5640_GP3_PIN_MASK,
+                       RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP3_PIN_DMIC1_SDA);
+               snd_soc_update_bits(codec, RT5640_DMIC,
+                       RT5640_DMIC_1L_LH_MASK | RT5640_DMIC_1R_LH_MASK |
+                       RT5640_DMIC_1_DP_MASK,
+                       RT5640_DMIC_1L_LH_FALLING | RT5640_DMIC_1R_LH_RISING |
+                       RT5640_DMIC_1_DP_IN1P);
+               snd_soc_update_bits(codec, RT5640_DMIC,
+                       RT5640_DMIC_1_EN_MASK, RT5640_DMIC_1_EN);
+       default:
+               mutex_unlock(&rt5640->lock);
+               return 0;
+       }
+
+       mutex_unlock(&rt5640->lock);
+       return 0;
+}
+
+static int rt5640_set_dmic2_event(struct snd_soc_dapm_widget *w,
+       struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_codec *codec = w->codec;
+       unsigned int val, mask;
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_update_bits(codec, RT5640_GPIO_CTRL1,
+                       RT5640_GP2_PIN_MASK | RT5640_GP4_PIN_MASK,
+                       RT5640_GP2_PIN_DMIC1_SCL | RT5640_GP4_PIN_DMIC2_SDA);
+               snd_soc_update_bits(codec, RT5640_DMIC,
+                       RT5640_DMIC_2L_LH_MASK | RT5640_DMIC_2R_LH_MASK |
+                       RT5640_DMIC_2_DP_MASK,
+                       RT5640_DMIC_2L_LH_FALLING | RT5640_DMIC_2R_LH_RISING |
+                       RT5640_DMIC_2_DP_IN1N);
+               snd_soc_update_bits(codec, RT5640_DMIC,
+                       RT5640_DMIC_2_EN_MASK, RT5640_DMIC_2_EN);
+       default:
+               mutex_unlock(&rt5640->lock);
+               return 0;
+       }
+
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
@@ -1245,10 +1609,19 @@ static const struct snd_soc_dapm_widget rt5640_dapm_widgets[] = {
        SND_SOC_DAPM_INPUT("IN1N"),
        SND_SOC_DAPM_INPUT("IN2P"),
        SND_SOC_DAPM_INPUT("IN2N"),
+#if 0
        SND_SOC_DAPM_INPUT("DMIC L1"),
        SND_SOC_DAPM_INPUT("DMIC R1"),
        SND_SOC_DAPM_INPUT("DMIC L2"),
        SND_SOC_DAPM_INPUT("DMIC R2"),
+#else
+       SND_SOC_DAPM_PGA_E("DMIC L1", SND_SOC_NOPM, 0, 0, NULL, 0,
+               rt5640_set_dmic1_event, SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_PGA("DMIC R1", SND_SOC_NOPM, 0, 0, NULL, 0),
+       SND_SOC_DAPM_PGA_E("DMIC L2", SND_SOC_NOPM, 0, 0, NULL, 0,
+               rt5640_set_dmic2_event, SND_SOC_DAPM_PRE_PMU),
+       SND_SOC_DAPM_PGA("DMIC R2", SND_SOC_NOPM, 0, 0, NULL, 0),
+#endif
        SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0,
                set_dmic_clk, SND_SOC_DAPM_PRE_PMU),
        /* Boost */
@@ -1820,9 +2193,8 @@ static int get_sdp_info(struct snd_soc_codec *codec, int dai_id)
                        ret |= RT5640_U_IF3;
                break;
 
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
-                       CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
-
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+       defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
        case RT5640_AIF3:
                if (val == RT5640_IF_312 || val == RT5640_IF_321)
                        ret |= RT5640_U_IF1;
@@ -1865,16 +2237,20 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        unsigned int val_len = 0, val_clk, mask_clk, dai_sel;
        int pre_div, bclk_ms, frame_size;
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
        rt5640->lrck[dai->id] = params_rate(params);
        pre_div = get_clk_info(rt5640->sysclk, rt5640->lrck[dai->id]);
        if (pre_div < 0) {
                dev_err(codec->dev, "Unsupported clock setting\n");
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
        frame_size = snd_soc_params_to_frame_size(params);
        if (frame_size < 0) {
                dev_err(codec->dev, "Unsupported frame size: %d\n", frame_size);
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
        bclk_ms = frame_size > 32 ? 1 : 0;
@@ -1898,12 +2274,14 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
                val_len |= RT5640_I2S_DL_8;
                break;
        default:
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
 
        dai_sel = get_sdp_info(codec, dai->id);
        if (dai_sel < 0) {
                dev_err(codec->dev, "Failed to get sdp info: %d\n", dai_sel);
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
        if (dai_sel & RT5640_U_IF1) {
@@ -1922,8 +2300,8 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
                        RT5640_I2S_DL_MASK, val_len);
                snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
        }
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
-                       CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+       defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
        if (dai_sel & RT5640_U_IF3) {
                mask_clk = RT5640_I2S_BCLK_MS3_MASK | RT5640_I2S_PD3_MASK;
                val_clk = bclk_ms << RT5640_I2S_BCLK_MS3_SFT |
@@ -1933,6 +2311,7 @@ static int rt5640_hw_params(struct snd_pcm_substream *substream,
                snd_soc_update_bits(codec, RT5640_ADDA_CLK1, mask_clk, val_clk);
        }
 #endif
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
@@ -1952,6 +2331,8 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
        struct snd_soc_codec *codec = dai->codec;
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        unsigned int reg_val = 0, dai_sel;
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
@@ -1962,6 +2343,7 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                rt5640->master[dai->id] = 0;
                break;
        default:
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
 
@@ -1972,6 +2354,7 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                reg_val |= RT5640_I2S_BP_INV;
                break;
        default:
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
 
@@ -1988,12 +2371,14 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                reg_val  |= RT5640_I2S_DF_PCM_B;
                break;
        default:
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
 
        dai_sel = get_sdp_info(codec, dai->id);
        if (dai_sel < 0) {
                dev_err(codec->dev, "Failed to get sdp info: %d\n", dai_sel);
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
        if (dai_sel & RT5640_U_IF1) {
@@ -2006,14 +2391,15 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
                        RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
                        RT5640_I2S_DF_MASK, reg_val);
        }
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
-                       CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+       defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
        if (dai_sel & RT5640_U_IF3) {
                snd_soc_update_bits(codec, RT5640_I2S3_SDP,
                        RT5640_I2S_MS_MASK | RT5640_I2S_BP_MASK |
                        RT5640_I2S_DF_MASK, reg_val);
        }
 #endif
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
@@ -2023,9 +2409,13 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
        struct snd_soc_codec *codec = dai->codec;
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        unsigned int reg_val = 0;
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
-       if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src)
+       if (freq == rt5640->sysclk && clk_id == rt5640->sysclk_src) {
+               mutex_unlock(&rt5640->lock);
                return 0;
+       }
 
        switch (clk_id) {
        case RT5640_SCLK_S_MCLK:
@@ -2042,6 +2432,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
                break;
        default:
                dev_err(codec->dev, "Invalid clock id (%d)\n", clk_id);
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
        snd_soc_update_bits(codec, RT5640_GLB_CLK,
@@ -2050,6 +2441,7 @@ static int rt5640_set_dai_sysclk(struct snd_soc_dai *dai,
        rt5640->sysclk_src = clk_id;
 
        dev_dbg(dai->dev, "Sysclk is %dHz and clock id is %d\n", freq, clk_id);
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
@@ -2113,10 +2505,14 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        struct rt5640_pll_code pll_code;
        int ret, dai_sel;
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
        if (source == rt5640->pll_src && freq_in == rt5640->pll_in &&
-           freq_out == rt5640->pll_out)
+           freq_out == rt5640->pll_out) {
+               mutex_unlock(&rt5640->lock);
                return 0;
+               }
 
        if (!freq_in || !freq_out) {
                dev_dbg(codec->dev, "PLL disabled\n");
@@ -2125,6 +2521,7 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
                rt5640->pll_out = 0;
                snd_soc_update_bits(codec, RT5640_GLB_CLK,
                        RT5640_SCLK_SRC_MASK, RT5640_SCLK_SRC_MCLK);
+               mutex_unlock(&rt5640->lock);
                return 0;
        }
 
@@ -2135,10 +2532,8 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
                break;
        case RT5640_PLL1_S_BCLK1:
        case RT5640_PLL1_S_BCLK2:
-
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
-                       CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
-
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+       defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
        case RT5640_PLL1_S_BCLK3:
 
 #endif
@@ -2146,6 +2541,7 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
                if (dai_sel < 0) {
                        dev_err(codec->dev,
                                "Failed to get sdp info: %d\n", dai_sel);
+                       mutex_unlock(&rt5640->lock);
                        return -EINVAL;
                }
                if (dai_sel & RT5640_U_IF1) {
@@ -2163,12 +2559,14 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
                break;
        default:
                dev_err(codec->dev, "Unknown PLL source %d\n", source);
+               mutex_unlock(&rt5640->lock);
                return -EINVAL;
        }
 
        ret = rt5640_pll_calc(freq_in, freq_out, &pll_code);
        if (ret < 0) {
                dev_err(codec->dev, "Unsupport input clock %d\n", freq_in);
+               mutex_unlock(&rt5640->lock);
                return ret;
        }
 
@@ -2185,6 +2583,7 @@ static int rt5640_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source,
        rt5640->pll_out = freq_out;
        rt5640->pll_src = source;
 
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
@@ -2206,6 +2605,8 @@ static ssize_t rt5640_index_show(struct device *dev,
        struct snd_soc_codec *codec = rt5640->codec;
        unsigned int val;
        int cnt = 0, i;
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
        cnt += sprintf(buf, "RT5640 index register\n");
        for (i = 0; i < 0xb4; i++) {
@@ -2220,6 +2621,7 @@ static ssize_t rt5640_index_show(struct device *dev,
        if (cnt >= PAGE_SIZE)
                cnt = PAGE_SIZE - 1;
 
+       mutex_unlock(&rt5640->lock);
        return cnt;
 }
 static DEVICE_ATTR(index_reg, 0444, rt5640_index_show, NULL);
@@ -2227,6 +2629,10 @@ static DEVICE_ATTR(index_reg, 0444, rt5640_index_show, NULL);
 static int rt5640_set_bias_level(struct snd_soc_codec *codec,
                        enum snd_soc_bias_level level)
 {
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
+
        switch (level) {
        case SND_SOC_BIAS_ON:
 #ifdef RT5640_DEMO
@@ -2272,12 +2678,15 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
                                RT5640_PWR_BG | RT5640_PWR_VREF2,
                                RT5640_PWR_VREF1 | RT5640_PWR_MB |
                                RT5640_PWR_BG | RT5640_PWR_VREF2);
-                       msleep(10);
+                       msleep(5);
                        snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
                                RT5640_PWR_FV1 | RT5640_PWR_FV2,
                                RT5640_PWR_FV1 | RT5640_PWR_FV2);
+                       snd_soc_write(codec, RT5640_GEN_CTRL1, 0x3701);
                        codec->cache_only = false;
+                       codec->cache_sync = 1;
                        snd_soc_cache_sync(codec);
+                       rt5640_index_sync(codec);
                }
                break;
 
@@ -2292,6 +2701,9 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
                snd_soc_update_bits(codec, RT5640_MONO_OUT,
                        RT5640_L_MUTE, RT5640_L_MUTE);
 #endif
+               snd_soc_write(codec, RT5640_DEPOP_M1, 0x0004);
+               snd_soc_write(codec, RT5640_DEPOP_M2, 0x1100);
+               snd_soc_write(codec, RT5640_GEN_CTRL1, 0x3700);
                snd_soc_write(codec, RT5640_PWR_DIG1, 0x0000);
                snd_soc_write(codec, RT5640_PWR_DIG2, 0x0000);
                snd_soc_write(codec, RT5640_PWR_VOL, 0x0000);
@@ -2305,6 +2717,7 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec,
        }
        codec->dapm.bias_level = level;
 
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
@@ -2313,19 +2726,23 @@ static int rt5640_probe(struct snd_soc_codec *codec)
        struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
        int ret;
        u16 val;
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
 
        codec->dapm.idle_bias_off = 1;
 
        ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
+               mutex_unlock(&rt5640->lock);
                return ret;
        }
 
        val = snd_soc_read(codec, RT5640_RESET);
-       if (val != rt5640_reg[RT5640_RESET]) {
+       if ((val != rt5640_reg[RT5640_RESET]) && (val != RT5639_RESET_ID)) {
                dev_err(codec->dev,
-                       "Device with ID register %x is not a rt5640\n", val);
+                       "Device with ID register %x is not rt5640/39\n", val);
+               mutex_unlock(&rt5640->lock);
                return -ENODEV;
        }
 
@@ -2335,7 +2752,7 @@ static int rt5640_probe(struct snd_soc_codec *codec)
                RT5640_PWR_BG | RT5640_PWR_VREF2,
                RT5640_PWR_VREF1 | RT5640_PWR_MB |
                RT5640_PWR_BG | RT5640_PWR_VREF2);
-       msleep(100);
+       msleep(10);
        snd_soc_update_bits(codec, RT5640_PWR_ANLG1,
                RT5640_PWR_FV1 | RT5640_PWR_FV2,
                RT5640_PWR_FV1 | RT5640_PWR_FV2);
@@ -2358,11 +2775,12 @@ static int rt5640_probe(struct snd_soc_codec *codec)
        rt5640_reg_init(codec);
 #endif
 
-
-#if (CONFIG_SND_SOC_RT5642_MODULE | CONFIG_SND_SOC_RT5642)
+#if defined(CONFIG_SND_SOC_RT5642_MODULE) || defined(CONFIG_SND_SOC_RT5642)
        rt5640_register_dsp(codec);
 #endif
 
+       DC_Calibrate(codec);
+
        codec->dapm.bias_level = SND_SOC_BIAS_STANDBY;
 
        snd_soc_add_codec_controls(codec, rt5640_snd_controls,
@@ -2373,23 +2791,31 @@ static int rt5640_probe(struct snd_soc_codec *codec)
        if (ret != 0) {
                dev_err(codec->dev,
                        "Failed to create index_reg sysfs files: %d\n", ret);
+               mutex_unlock(&rt5640->lock);
                return ret;
        }
 
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 
 static int rt5640_remove(struct snd_soc_codec *codec)
 {
+       struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec);
+
        rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
+       mutex_lock(&rt5640->lock);
+       CHECK_I2C_SHUTDOWN(rt5640, codec)
        rt5640_reset(codec);
        snd_soc_write(codec, RT5640_PWR_ANLG1, 0);
 
+       mutex_unlock(&rt5640->lock);
        return 0;
 }
 #ifdef CONFIG_PM
 static int rt5640_suspend(struct snd_soc_codec *codec, pm_message_t state)
 {
+       rt5640_reset(codec);
        rt5640_set_bias_level(codec, SND_SOC_BIAS_OFF);
        snd_soc_write(codec, RT5640_PWR_ANLG1, 0);
 
@@ -2398,6 +2824,14 @@ static int rt5640_suspend(struct snd_soc_codec *codec, pm_message_t state)
 
 static int rt5640_resume(struct snd_soc_codec *codec)
 {
+       int ret = 0 ;
+
+       codec->cache_sync = 1;
+       ret = snd_soc_cache_sync(codec);
+       if (ret) {
+               dev_err(codec->dev,"Failed to sync cache: %d\n", ret);
+               return ret;
+       }
        rt5640_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
        return 0;
@@ -2458,8 +2892,8 @@ struct snd_soc_dai_driver rt5640_dai[] = {
                },
                .ops = &rt5640_aif_dai_ops,
        },
-#if (CONFIG_SND_SOC_RT5643_MODULE | CONFIG_SND_SOC_RT5643 | \
-                       CONFIG_SND_SOC_RT5646_MODULE | CONFIG_SND_SOC_RT5646)
+#if defined(CONFIG_SND_SOC_RT5643_MODULE) || defined(CONFIG_SND_SOC_RT5643) || \
+       defined(CONFIG_SND_SOC_RT5646_MODULE) || defined(CONFIG_SND_SOC_RT5646)
        {
                .name = "rt5640-aif3",
                .id = RT5640_AIF3,
@@ -2517,6 +2951,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c,
                return -ENOMEM;
 
        i2c_set_clientdata(i2c, rt5640);
+       mutex_init(&rt5640->lock);
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640,
                        rt5640_dai, ARRAY_SIZE(rt5640_dai));
@@ -2533,6 +2968,19 @@ static __devexit int rt5640_i2c_remove(struct i2c_client *i2c)
        return 0;
 }
 
+static void rt5640_i2c_shutdown(struct i2c_client *i2c)
+{
+       struct rt5640_priv *rt5640 = i2c_get_clientdata(i2c);
+
+       mutex_lock(&rt5640->lock);
+
+       if (i2c->irq)
+               disable_irq(i2c->irq);
+       rt5640->shutdown_complete = 1;
+
+       mutex_unlock(&rt5640->lock);
+}
+
 struct i2c_driver rt5640_i2c_driver = {
        .driver = {
                .name = "rt5640",
@@ -2541,6 +2989,7 @@ struct i2c_driver rt5640_i2c_driver = {
        .probe = rt5640_i2c_probe,
        .remove   = __devexit_p(rt5640_i2c_remove),
        .id_table = rt5640_i2c_id,
+       .shutdown = rt5640_i2c_shutdown,
 };
 
 static int __init rt5640_modinit(void)