diff options
Diffstat (limited to 'sound/soc/codecs/rt5640.c')
-rw-r--r-- | sound/soc/codecs/rt5640.c | 271 |
1 files changed, 259 insertions, 12 deletions
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index ce9536bce8a6..7844b54aa961 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -33,6 +33,7 @@ #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"); \ @@ -45,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 */ @@ -53,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 */ @@ -74,9 +76,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 */ @@ -167,7 +176,7 @@ 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, @@ -182,12 +191,13 @@ static const u16 rt5640_reg[RT5640_VENDOR_ID2 + 1] = { [RT5640_MP3_PLUS2] = 0x1c17, [RT5640_3D_HP] = 0x8c00, [RT5640_ADJ_HPF] = 0x2a20, - [RT5640_HP_CALIB_AMP_DET] = 0x0400, + [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); @@ -304,6 +314,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; @@ -424,18 +437,45 @@ 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; @@ -451,7 +491,7 @@ int rt5640_headset_detect(struct snd_soc_codec *codec, int jack_insert) 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; @@ -466,9 +506,9 @@ 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(150); + msleep(100); if (snd_soc_read(codec, RT5640_IRQ_CTRL2) & 0x8) jack_type = RT5640_HEADPHO_DET; else @@ -1266,24 +1306,225 @@ static int spk_event(struct snd_soc_dapm_widget *w, 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; + 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) { @@ -2434,10 +2675,11 @@ 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); @@ -2456,6 +2698,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); @@ -2504,7 +2749,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); @@ -2531,6 +2776,8 @@ static int rt5640_probe(struct snd_soc_codec *codec) 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, |