From 971aeb6addbb05a9fb36cea699990e4cdd83bedd Mon Sep 17 00:00:00 2001 From: Yeleswarapu Nagaradhesh Date: Sun, 31 Jul 2016 15:10:55 -0700 Subject: [PATCH 1/4] ASoC: wcd: modify tasha version check macros TASHA_IS_1_1 macro checks only for version number. This macro returns true for tavil codec. So modify tasha macros to check for codec and version. CRs-Fixed: 1066331 Change-Id: I5240e0ee888187a8185974ea288ce2cad62bd776 Signed-off-by: Yeleswarapu Nagaradhesh --- include/linux/mfd/wcd9xxx/core.h | 18 +++++--- sound/soc/codecs/wcd9335.c | 64 ++++++++++++++-------------- sound/soc/codecs/wcd9xxx-common-v2.c | 8 ++-- 3 files changed, 48 insertions(+), 42 deletions(-) diff --git a/include/linux/mfd/wcd9xxx/core.h b/include/linux/mfd/wcd9xxx/core.h index f595275e9d42..c6f6253f477a 100644 --- a/include/linux/mfd/wcd9xxx/core.h +++ b/include/linux/mfd/wcd9xxx/core.h @@ -53,12 +53,18 @@ #define TASHA_VERSION_1_0 0 #define TASHA_VERSION_1_1 1 #define TASHA_VERSION_2_0 2 -#define TASHA_IS_1_0(ver) \ - ((ver == TASHA_VERSION_1_0) ? 1 : 0) -#define TASHA_IS_1_1(ver) \ - ((ver == TASHA_VERSION_1_1) ? 1 : 0) -#define TASHA_IS_2_0(ver) \ - ((ver == TASHA_VERSION_2_0) ? 1 : 0) + +#define TASHA_IS_1_0(wcd) \ + ((wcd->type == WCD9335 || wcd->type == WCD9326) ? \ + ((wcd->version == TASHA_VERSION_1_0) ? 1 : 0) : 0) + +#define TASHA_IS_1_1(wcd) \ + ((wcd->type == WCD9335 || wcd->type == WCD9326) ? \ + ((wcd->version == TASHA_VERSION_1_1) ? 1 : 0) : 0) + +#define TASHA_IS_2_0(wcd) \ + ((wcd->type == WCD9335 || wcd->type == WCD9326) ? \ + ((wcd->version == TASHA_VERSION_2_0) ? 1 : 0) : 0) #define IS_CODEC_TYPE(wcd, wcdtype) \ ((wcd->type == wcdtype) ? true : false) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index b5126351dda0..586165e8f554 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -1114,7 +1114,7 @@ static void tasha_cdc_sido_ccl_enable(struct tasha_priv *tasha, bool ccl_flag) if (!codec) return; - if (!TASHA_IS_2_0(tasha->wcd9xxx->version)) { + if (!TASHA_IS_2_0(tasha->wcd9xxx)) { dev_dbg(codec->dev, "%s: tasha version < 2p0, return\n", __func__); return; @@ -1139,7 +1139,7 @@ static void tasha_cdc_sido_ccl_enable(struct tasha_priv *tasha, bool ccl_flag) static bool tasha_cdc_is_svs_enabled(struct tasha_priv *tasha) { - if (TASHA_IS_2_0(tasha->wcd9xxx->version) && + if (TASHA_IS_2_0(tasha->wcd9xxx) && svs_scaling_enabled) return true; @@ -1269,7 +1269,7 @@ int tasha_enable_efuse_sensing(struct snd_soc_codec *codec) tasha_cdc_mclk_enable(codec, true, false); - if (!TASHA_IS_2_0(priv->wcd9xxx->version)) + if (!TASHA_IS_2_0(priv->wcd9xxx)) snd_soc_update_bits(codec, WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, 0x1E, 0x02); snd_soc_update_bits(codec, WCD9335_CHIP_TIER_CTRL_EFUSE_CTL, @@ -1282,7 +1282,7 @@ int tasha_enable_efuse_sensing(struct snd_soc_codec *codec) if (!(snd_soc_read(codec, WCD9335_CHIP_TIER_CTRL_EFUSE_STATUS) & 0x01)) WARN(1, "%s: Efuse sense is not complete\n", __func__); - if (TASHA_IS_2_0(priv->wcd9xxx->version)) { + if (TASHA_IS_2_0(priv->wcd9xxx)) { if (!(snd_soc_read(codec, WCD9335_CHIP_TIER_CTRL_EFUSE_VAL_OUT0) & 0x40)) snd_soc_update_bits(codec, WCD9335_HPH_R_ATEST, @@ -1502,7 +1502,7 @@ static void tasha_mbhc_hph_l_pull_up_control(struct snd_soc_codec *codec, dev_dbg(codec->dev, "%s: HS pull up current:%d\n", __func__, pull_up_cur); - if (TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (TASHA_IS_2_0(tasha->wcd9xxx)) snd_soc_update_bits(codec, WCD9335_MBHC_PLUG_DETECT_CTL, 0xC0, pull_up_cur << 6); else @@ -1980,7 +1980,7 @@ static void tasha_wcd_mbhc_calc_impedance(struct wcd_mbhc *mbhc, uint32_t *zl, }; s16 *d1 = NULL; - if (!TASHA_IS_2_0(wcd9xxx->version)) { + if (!TASHA_IS_2_0(wcd9xxx)) { dev_dbg(codec->dev, "%s: Z-det is not supported for this codec version\n", __func__); *zl = 0; @@ -2168,13 +2168,13 @@ static void tasha_mbhc_hph_pull_down_ctrl(struct snd_soc_codec *codec, if (enable) { snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x40, 0x40); - if (TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (TASHA_IS_2_0(tasha->wcd9xxx)) snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x10, 0x10); } else { snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x40, 0x00); - if (TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (TASHA_IS_2_0(tasha->wcd9xxx)) snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x10, 0x00); } @@ -3667,7 +3667,7 @@ static int tasha_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_PRE_PMU: tasha->rx_bias_count++; if (tasha->rx_bias_count == 1) { - if (TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (TASHA_IS_2_0(tasha->wcd9xxx)) tasha_codec_init_flyback(codec); snd_soc_update_bits(codec, WCD9335_ANA_RX_SUPPLIES, 0x01, 0x01); @@ -3933,7 +3933,7 @@ static void tasha_codec_hph_post_pa_config(struct tasha_priv *tasha, { u8 scale_val = 0; - if (!TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (!TASHA_IS_2_0(tasha->wcd9xxx)) return; switch (event) { @@ -4418,7 +4418,7 @@ static void tasha_codec_hph_mode_config(struct snd_soc_codec *codec, { struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); - if (!TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (!TASHA_IS_2_0(tasha->wcd9xxx)) return; switch (mode) { @@ -4482,14 +4482,14 @@ static int tasha_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, /* 1000us required as per HW requirement */ usleep_range(1000, 1100); if ((hph_mode == CLS_H_LP) && - (TASHA_IS_1_1(wcd9xxx->version))) { + (TASHA_IS_1_1(wcd9xxx))) { snd_soc_update_bits(codec, WCD9335_HPH_L_DAC_CTL, 0x03, 0x03); } break; case SND_SOC_DAPM_PRE_PMD: if ((hph_mode == CLS_H_LP) && - (TASHA_IS_1_1(wcd9xxx->version))) { + (TASHA_IS_1_1(wcd9xxx))) { snd_soc_update_bits(codec, WCD9335_HPH_L_DAC_CTL, 0x03, 0x00); } @@ -4572,14 +4572,14 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, /* 1000us required as per HW requirement */ usleep_range(1000, 1100); if ((hph_mode == CLS_H_LP) && - (TASHA_IS_1_1(wcd9xxx->version))) { + (TASHA_IS_1_1(wcd9xxx))) { snd_soc_update_bits(codec, WCD9335_HPH_L_DAC_CTL, 0x03, 0x03); } break; case SND_SOC_DAPM_PRE_PMD: if ((hph_mode == CLS_H_LP) && - (TASHA_IS_1_1(wcd9xxx->version))) { + (TASHA_IS_1_1(wcd9xxx))) { snd_soc_update_bits(codec, WCD9335_HPH_L_DAC_CTL, 0x03, 0x00); } @@ -4804,7 +4804,7 @@ static void tasha_codec_hd2_control(struct snd_soc_codec *codec, u16 hd2_scale_reg; u16 hd2_enable_reg = 0; - if (!TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (!TASHA_IS_2_0(tasha->wcd9xxx)) return; if (prim_int_reg == WCD9335_CDC_RX1_RX_PATH_CTL) { @@ -8003,7 +8003,7 @@ static void wcd_vbat_adc_out_config(struct wcd_vbat *vbat, if (!vbat->adc_config) { tasha_cdc_mclk_enable(codec, true, false); - if (TASHA_IS_2_0(wcd9xxx->version)) + if (TASHA_IS_2_0(wcd9xxx)) wcd_vbat_adc_out_config_2_0(vbat, codec); else wcd_vbat_adc_out_config_1_x(vbat, codec); @@ -10948,7 +10948,7 @@ static int tasha_set_channel_map(struct snd_soc_dai *dai, /* Reserve TX12/TX13 for MAD data channel */ dai_data = &tasha->dai[AIF4_MAD_TX]; if (dai_data) { - if (TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (TASHA_IS_2_0(tasha->wcd9xxx)) list_add_tail(&core->tx_chs[TASHA_TX13].list, &dai_data->wcd9xxx_ch_list); else @@ -11899,9 +11899,9 @@ static ssize_t tasha_codec_version_read(struct snd_info_entry *entry, wcd9xxx = tasha->wcd9xxx; if (wcd9xxx->codec_type->id_major == TASHA_MAJOR) { - if (TASHA_IS_1_0(wcd9xxx->version)) + if (TASHA_IS_1_0(wcd9xxx)) len = snprintf(buffer, sizeof(buffer), "WCD9335_1_0\n"); - else if (TASHA_IS_1_1(wcd9xxx->version)) + else if (TASHA_IS_1_1(wcd9xxx)) len = snprintf(buffer, sizeof(buffer), "WCD9335_1_1\n"); else snprintf(buffer, sizeof(buffer), "VER_UNDEFINED\n"); @@ -12243,7 +12243,7 @@ static void tasha_update_reg_reset_values(struct snd_soc_codec *codec) u32 i; struct wcd9xxx *tasha_core = dev_get_drvdata(codec->dev->parent); - if (TASHA_IS_1_1(tasha_core->version)) { + if (TASHA_IS_1_1(tasha_core)) { for (i = 0; i < ARRAY_SIZE(tasha_reg_update_reset_val_1_1); i++) snd_soc_write(codec, @@ -12263,27 +12263,27 @@ static void tasha_codec_init_reg(struct snd_soc_codec *codec) tasha_codec_reg_init_common_val[i].mask, tasha_codec_reg_init_common_val[i].val); - if (TASHA_IS_1_1(wcd9xxx->version) || - TASHA_IS_1_0(wcd9xxx->version)) + if (TASHA_IS_1_1(wcd9xxx) || + TASHA_IS_1_0(wcd9xxx)) for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_1_x_val); i++) snd_soc_update_bits(codec, tasha_codec_reg_init_1_x_val[i].reg, tasha_codec_reg_init_1_x_val[i].mask, tasha_codec_reg_init_1_x_val[i].val); - if (TASHA_IS_1_1(wcd9xxx->version)) { + if (TASHA_IS_1_1(wcd9xxx)) { for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_val_1_1); i++) snd_soc_update_bits(codec, tasha_codec_reg_init_val_1_1[i].reg, tasha_codec_reg_init_val_1_1[i].mask, tasha_codec_reg_init_val_1_1[i].val); - } else if (TASHA_IS_1_0(wcd9xxx->version)) { + } else if (TASHA_IS_1_0(wcd9xxx)) { for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_val_1_0); i++) snd_soc_update_bits(codec, tasha_codec_reg_init_val_1_0[i].reg, tasha_codec_reg_init_val_1_0[i].mask, tasha_codec_reg_init_val_1_0[i].val); - } else if (TASHA_IS_2_0(wcd9xxx->version)) { + } else if (TASHA_IS_2_0(wcd9xxx)) { for (i = 0; i < ARRAY_SIZE(tasha_codec_reg_init_val_2_0); i++) snd_soc_update_bits(codec, tasha_codec_reg_init_val_2_0[i].reg, @@ -12770,7 +12770,7 @@ static int tasha_codec_cpe_fll_enable(struct snd_soc_codec *codec, } } - if (TASHA_IS_1_0(wcd9xxx->version)) { + if (TASHA_IS_1_0(wcd9xxx)) { tasha_cdc_mclk_enable(codec, true, false); clk_sel_reg_val = 0x02; } @@ -12809,7 +12809,7 @@ static int tasha_codec_cpe_fll_enable(struct snd_soc_codec *codec, snd_soc_update_bits(codec, WCD9335_CPE_FLL_USER_CTL_0, 0x01, 0x00); - if (TASHA_IS_1_0(wcd9xxx->version)) + if (TASHA_IS_1_0(wcd9xxx)) tasha_cdc_mclk_enable(codec, false, false); /* @@ -12938,7 +12938,7 @@ static int tasha_cpe_err_irq_control(struct snd_soc_codec *codec, struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); u8 irq_bits; - if (TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (TASHA_IS_2_0(tasha->wcd9xxx)) irq_bits = 0xFF; else irq_bits = 0x3F; @@ -13251,7 +13251,7 @@ static int tasha_codec_probe(struct snd_soc_codec *codec) } /* Initialize MBHC module */ - if (TASHA_IS_2_0(tasha->wcd9xxx->version)) { + if (TASHA_IS_2_0(tasha->wcd9xxx)) { wcd_mbhc_registers[WCD_MBHC_FSM_STATUS].reg = WCD9335_MBHC_FSM_STATUS; wcd_mbhc_registers[WCD_MBHC_FSM_STATUS].mask = 0x01; @@ -13636,7 +13636,7 @@ static int tasha_swrm_clock(void *handle, bool enable) if (enable) { tasha->swr_clk_users++; if (tasha->swr_clk_users == 1) { - if (TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (TASHA_IS_2_0(tasha->wcd9xxx)) regmap_update_bits( tasha->wcd9xxx->regmap, WCD9335_TEST_DEBUG_NPL_DLY_TEST_1, @@ -13653,7 +13653,7 @@ static int tasha_swrm_clock(void *handle, bool enable) WCD9335_CDC_CLK_RST_CTRL_SWR_CONTROL, 0x01, 0x00); __tasha_cdc_mclk_enable(tasha, false); - if (TASHA_IS_2_0(tasha->wcd9xxx->version)) + if (TASHA_IS_2_0(tasha->wcd9xxx)) regmap_update_bits( tasha->wcd9xxx->regmap, WCD9335_TEST_DEBUG_NPL_DLY_TEST_1, diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c index f1b147aafd84..116c4e27c981 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.c +++ b/sound/soc/codecs/wcd9xxx-common-v2.c @@ -386,7 +386,7 @@ static void wcd_clsh_flyback_ctrl(struct snd_soc_codec *codec, (1 << 6), (enable << 6)); /* 100usec delay is needed as per HW requirement */ usleep_range(100, 110); - if (enable && (TASHA_IS_1_1(wcd9xxx->version))) { + if (enable && (TASHA_IS_1_1(wcd9xxx))) { wcd_clsh_set_flyback_mode(codec, CLS_H_HIFI); snd_soc_update_bits(codec, WCD9XXX_FLYBACK_EN, 0x60, 0x40); @@ -427,7 +427,7 @@ static void wcd_clsh_set_gain_path(struct snd_soc_codec *codec, u8 val = 0; struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent); - if (!TASHA_IS_2_0(wcd9xxx->version)) + if (!TASHA_IS_2_0(wcd9xxx)) return; switch (mode) { @@ -484,7 +484,7 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec, }; snd_soc_update_bits(codec, WCD9XXX_A_ANA_HPH, 0x0C, val); - if (TASHA_IS_2_0(wcd9xxx->version)) { + if (TASHA_IS_2_0(wcd9xxx)) { snd_soc_update_bits(codec, WCD9XXX_CLASSH_CTRL_VCL_2, 0x30, (res_val << 4)); if (mode != CLS_H_LP) @@ -515,7 +515,7 @@ static void wcd_clsh_set_flyback_current(struct snd_soc_codec *codec, int mode) { struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent); - if (!TASHA_IS_2_0(wcd9xxx->version)) + if (!TASHA_IS_2_0(wcd9xxx)) return; snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_FLYB_BUFF, 0x0F, 0x0A); From ea965ee6e8494e4244e6c8b0b2c1d53dd8d7e19f Mon Sep 17 00:00:00 2001 From: Yeleswarapu Nagaradhesh Date: Fri, 26 Aug 2016 02:48:15 -0700 Subject: [PATCH 2/4] ASoC: wcd934x: add support for HPH modes Headphones support classH and classAB. Add support for hifi, lowhifi, low power and ultra low power modes for classH. Support hifi and lowhifi power modes for classAB. CRs-Fixed: 1066331 Change-Id: I846f9704a5bf800583682f8dc2ec385a0ec64c61 Signed-off-by: Yeleswarapu Nagaradhesh --- .../linux/mfd/wcd9xxx/wcd9xxx_registers.h | 6 + sound/soc/codecs/wcd934x/wcd934x.c | 190 ++++++++++++++++-- sound/soc/codecs/wcd9xxx-common-v2.c | 108 +++++++++- sound/soc/codecs/wcd9xxx-common-v2.h | 4 +- 4 files changed, 283 insertions(+), 25 deletions(-) diff --git a/include/uapi/linux/mfd/wcd9xxx/wcd9xxx_registers.h b/include/uapi/linux/mfd/wcd9xxx/wcd9xxx_registers.h index a9fe10d8cd6e..7902cfbafad8 100644 --- a/include/uapi/linux/mfd/wcd9xxx/wcd9xxx_registers.h +++ b/include/uapi/linux/mfd/wcd9xxx/wcd9xxx_registers.h @@ -352,4 +352,10 @@ #define WCD9XXX_CDC_RX2_RX_VOL_MIX_CTL (0xB70) #define WCD9XXX_CDC_RX2_RX_PATH_SEC1 (0xB72) +/* Class-H registers for codecs from and above WCD934X */ +#define WCD9XXX_HPH_CNP_WG_CTL (0x06cc) +#define WCD9XXX_FLYBACK_VNEG_CTRL_4 (0x06a8) +#define WCD9XXX_HPH_NEW_INT_PA_MISC2 (0x0738) +#define WCD9XXX_RX_BIAS_HPH_LOWPOWER (0x06bf) +#define WCD9XXX_HPH_PA_CTL1 (0x06d1) #endif diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index 84e5c09494c6..5713014c436f 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -1384,6 +1384,27 @@ static int tavil_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, return 0; } +static void tavil_codec_override(struct snd_soc_codec *codec, int mode, + int event) +{ + if (mode == CLS_AB || mode == CLS_AB_HIFI) { + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (!(snd_soc_read(codec, + WCD934X_CDC_RX2_RX_PATH_CTL) & 0x10) && + (!(snd_soc_read(codec, + WCD934X_CDC_RX1_RX_PATH_CTL) & 0x10))) + snd_soc_update_bits(codec, + WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x02); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, + WCD9XXX_A_ANA_RX_SUPPLIES, 0x02, 0x00); + break; + } + } +} + static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -1396,6 +1417,8 @@ static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL, + 0x06, (0x03 << 1)); set_bit(HPH_PA_DELAY, &tavil->status_mask); break; case SND_SOC_DAPM_POST_PMU: @@ -1410,6 +1433,9 @@ static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, /* Remove mute */ snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CTL, 0x10, 0x00); + /* Enable GM3 boost */ + snd_soc_update_bits(codec, WCD934X_HPH_CNP_WG_CTL, + 0x80, 0x80); /* Enable AutoChop timer at the end of power up */ snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x02); @@ -1427,6 +1453,7 @@ static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD934X_CDC_DSD1_CFG2, 0x04, 0x00); } + tavil_codec_override(codec, tavil->hph_mode, event); break; case SND_SOC_DAPM_PRE_PMD: /* Enable DSD Mute before PA disable */ @@ -1436,6 +1463,9 @@ static int tavil_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, 0x04, 0x04); break; case SND_SOC_DAPM_POST_PMD: + tavil_codec_override(codec, tavil->hph_mode, event); + snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL, + 0x06, 0x0); /* 5ms sleep is required after PA disable */ usleep_range(5000, 5100); break; @@ -1456,6 +1486,8 @@ static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL, + 0x06, (0x03 << 1)); set_bit(HPH_PA_DELAY, &tavil->status_mask); break; case SND_SOC_DAPM_POST_PMU: @@ -1470,6 +1502,12 @@ static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, /* Remove Mute on primary path */ snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CTL, 0x10, 0x00); + /* Enable GM3 boost */ + snd_soc_update_bits(codec, WCD934X_HPH_CNP_WG_CTL, + 0x80, 0x80); + /* Enable AutoChop timer at the end of power up */ + snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x02); /* Remove mix path mute if it is enabled */ if ((snd_soc_read(codec, WCD934X_CDC_RX1_RX_PATH_MIX_CTL)) & 0x10) @@ -1484,6 +1522,7 @@ static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD934X_CDC_DSD0_CFG2, 0x04, 0x00); } + tavil_codec_override(codec, tavil->hph_mode, event); break; case SND_SOC_DAPM_PRE_PMD: /* Enable DSD Mute before PA disable */ @@ -1493,6 +1532,9 @@ static int tavil_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, 0x04, 0x04); break; case SND_SOC_DAPM_POST_PMD: + tavil_codec_override(codec, tavil->hph_mode, event); + snd_soc_update_bits(codec, WCD934X_HPH_REFBUFF_LP_CTL, + 0x06, 0x0); /* 5ms sleep is required after PA disable */ usleep_range(5000, 5100); break; @@ -1602,9 +1644,17 @@ static int tavil_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, __func__, hph_mode); return -EINVAL; } + if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP)) + /* Ripple freq control enable */ + snd_soc_update_bits(codec, + WCD934X_SIDO_NEW_VOUT_D_FREQ2, + 0x01, 0x01); /* Disable AutoChop timer during power up */ snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1, - 0x02, 0x00); + 0x02, 0x00); + /* Set RDAC gain */ + snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x40); if (dsd_conf && (snd_soc_read(codec, WCD934X_CDC_DSD1_PATH_CTL) & 0x01)) @@ -1613,8 +1663,7 @@ static int tavil_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, wcd_clsh_fsm(codec, &tavil->clsh_d, WCD_CLSH_EVENT_PRE_DAC, WCD_CLSH_STATE_HPHR, - ((hph_mode == CLS_H_LOHIFI) ? - CLS_H_HIFI : hph_mode)); + hph_mode); break; case SND_SOC_DAPM_POST_PMD: /* 1000us required as per HW requirement */ @@ -1622,8 +1671,15 @@ static int tavil_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, wcd_clsh_fsm(codec, &tavil->clsh_d, WCD_CLSH_EVENT_POST_PA, WCD_CLSH_STATE_HPHR, - ((hph_mode == CLS_H_LOHIFI) ? - CLS_H_HIFI : hph_mode)); + hph_mode); + if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP)) + /* Ripple freq control disable */ + snd_soc_update_bits(codec, + WCD934X_SIDO_NEW_VOUT_D_FREQ2, + 0x01, 0x0); + /* Re-set RDAC gain */ + snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x0); break; default: break; @@ -1657,6 +1713,17 @@ static int tavil_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, __func__, hph_mode); return -EINVAL; } + if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP)) + /* Ripple freq control enable */ + snd_soc_update_bits(codec, + WCD934X_SIDO_NEW_VOUT_D_FREQ2, + 0x01, 0x01); + /* Disable AutoChop timer during power up */ + snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1, + 0x02, 0x00); + /* Set RDAC gain */ + snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x40); if (dsd_conf && (snd_soc_read(codec, WCD934X_CDC_DSD0_PATH_CTL) & 0x01)) hph_mode = CLS_H_HIFI; @@ -1664,8 +1731,7 @@ static int tavil_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, wcd_clsh_fsm(codec, &tavil->clsh_d, WCD_CLSH_EVENT_PRE_DAC, WCD_CLSH_STATE_HPHL, - ((hph_mode == CLS_H_LOHIFI) ? - CLS_H_HIFI : hph_mode)); + hph_mode); break; case SND_SOC_DAPM_POST_PMD: /* 1000us required as per HW requirement */ @@ -1673,8 +1739,15 @@ static int tavil_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, wcd_clsh_fsm(codec, &tavil->clsh_d, WCD_CLSH_EVENT_POST_PA, WCD_CLSH_STATE_HPHL, - ((hph_mode == CLS_H_LOHIFI) ? - CLS_H_HIFI : hph_mode)); + hph_mode); + if ((hph_mode != CLS_H_LP) && (hph_mode != CLS_H_ULP)) + /* Ripple freq control disable */ + snd_soc_update_bits(codec, + WCD934X_SIDO_NEW_VOUT_D_FREQ2, + 0x01, 0x0); + /* Re-set RDAC gain */ + snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_RDAC_GAIN_CTL, + 0xF0, 0x0); break; default: break; @@ -2207,6 +2280,46 @@ static int tavil_enable_native_supply(struct snd_soc_dapm_widget *w, return 0; } +static void tavil_codec_hphdelay_lutbypass(struct snd_soc_codec *codec, + u16 interp_idx, int event) +{ + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + u8 hph_dly_mask; + u16 hph_lut_bypass_reg = 0; + u16 hph_comp_ctrl7 = 0; + + + switch (interp_idx) { + case INTERP_HPHL: + hph_dly_mask = 1; + hph_lut_bypass_reg = WCD934X_CDC_TOP_HPHL_COMP_LUT; + hph_comp_ctrl7 = WCD934X_CDC_COMPANDER1_CTL7; + break; + case INTERP_HPHR: + hph_dly_mask = 2; + hph_lut_bypass_reg = WCD934X_CDC_TOP_HPHR_COMP_LUT; + hph_comp_ctrl7 = WCD934X_CDC_COMPANDER2_CTL7; + break; + default: + break; + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_update_bits(codec, WCD934X_CDC_CLSH_TEST0, + hph_dly_mask, 0x0); + snd_soc_update_bits(codec, hph_lut_bypass_reg, 0x80, 0x80); + if (tavil->hph_mode == CLS_H_ULP) + snd_soc_update_bits(codec, hph_comp_ctrl7, 0x20, 0x20); + } + + if (hph_lut_bypass_reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_update_bits(codec, WCD934X_CDC_CLSH_TEST0, + hph_dly_mask, hph_dly_mask); + snd_soc_update_bits(codec, hph_lut_bypass_reg, 0x80, 0x00); + snd_soc_update_bits(codec, hph_comp_ctrl7, 0x20, 0x0); + } +} + static void tavil_codec_hd2_control(struct snd_soc_codec *codec, u16 interp_idx, int event) { @@ -2225,14 +2338,12 @@ static void tavil_codec_hd2_control(struct snd_soc_codec *codec, } if (hd2_enable_reg && SND_SOC_DAPM_EVENT_ON(event)) { - snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x10); - snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x01); + snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x14); snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x04); } if (hd2_enable_reg && SND_SOC_DAPM_EVENT_OFF(event)) { snd_soc_update_bits(codec, hd2_enable_reg, 0x04, 0x00); - snd_soc_update_bits(codec, hd2_scale_reg, 0x03, 0x00); snd_soc_update_bits(codec, hd2_scale_reg, 0x3C, 0x00); } } @@ -2267,7 +2378,9 @@ static int tavil_config_compander(struct snd_soc_codec *codec, int interp_n, } if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x00); snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x04); + snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02); snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00); snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x00); snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x00); @@ -2306,6 +2419,8 @@ int tavil_codec_enable_interp_clk(struct snd_soc_codec *codec, /* Clk enable */ snd_soc_update_bits(codec, main_reg, 0x20, 0x20); tavil_codec_hd2_control(codec, interp_idx, event); + tavil_codec_hphdelay_lutbypass(codec, interp_idx, + event); tavil_config_compander(codec, interp_idx, event); } tavil->main_clk_users[interp_idx]++; @@ -2316,6 +2431,8 @@ int tavil_codec_enable_interp_clk(struct snd_soc_codec *codec, if (tavil->main_clk_users[interp_idx] <= 0) { tavil->main_clk_users[interp_idx] = 0; tavil_config_compander(codec, interp_idx, event); + tavil_codec_hphdelay_lutbypass(codec, interp_idx, + event); tavil_codec_hd2_control(codec, interp_idx, event); /* Clk Disable */ snd_soc_update_bits(codec, main_reg, 0x20, 0x00); @@ -3919,6 +4036,47 @@ static int tavil_ear_pa_gain_put(struct snd_kcontrol *kcontrol, return 0; } + +static int tavil_rx_hph_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = tavil->hph_mode; + return 0; +} + +static int tavil_rx_hph_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + u32 mode_val; + + mode_val = ucontrol->value.enumerated.item[0]; + + dev_dbg(codec->dev, "%s: mode: %d\n", __func__, mode_val); + + if (mode_val == 0) { + dev_warn(codec->dev, "%s:Invalid HPH Mode, default to Cls-H LOHiFi\n", + __func__); + mode_val = CLS_H_LOHIFI; + } + tavil->hph_mode = mode_val; + return 0; +} + + +static const char * const rx_hph_mode_mux_text[] = { + "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI", + "CLS_H_ULP", "CLS_AB_HIFI", +}; + +static const struct soc_enum rx_hph_mode_mux_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), + rx_hph_mode_mux_text); + /* Cutoff frequency for high pass filter */ static const char * const cf_text[] = { "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" @@ -4095,6 +4253,9 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = { SOC_ENUM("RX INT8_1 HPF cut off", cf_int8_1_enum), SOC_ENUM("RX INT8_2 HPF cut off", cf_int8_2_enum), + SOC_ENUM_EXT("RX HPH Mode", rx_hph_mode_mux_enum, + tavil_rx_hph_mode_get, tavil_rx_hph_mode_put), + SOC_SINGLE_EXT("IIR0 Enable Band1", IIR0, BAND1, 1, 0, tavil_iir_enable_audio_mixer_get, tavil_iir_enable_audio_mixer_put), @@ -6327,7 +6488,6 @@ static const struct tavil_reg_mask_val tavil_codec_reg_defaults[] = { {WCD934X_BIAS_VBG_FINE_ADJ, 0xFF, 0x75}, {WCD934X_CODEC_CPR_SVS_CX_VDD, 0xFF, 0x7C}, /* value in svs mode */ {WCD934X_CODEC_CPR_SVS2_CX_VDD, 0xFF, 0x58}, /* value in svs2 mode */ - {WCD934X_SIDO_NEW_VOUT_D_FREQ2, 0x01, 0x01}, {WCD934X_CDC_RX0_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX1_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, {WCD934X_CDC_RX2_RX_PATH_DSMDEM_CTL, 0x01, 0x01}, @@ -6831,8 +6991,8 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec) } /* Class-H Init */ wcd_clsh_init(&tavil->clsh_d); - /* Default HPH Mode to Class-H HiFi */ - tavil->hph_mode = CLS_H_HIFI; + /* Default HPH Mode to Class-H Low HiFi */ + tavil->hph_mode = CLS_H_LOHIFI; tavil->fw_data = devm_kzalloc(codec->dev, sizeof(*(tavil->fw_data)), GFP_KERNEL); diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c index 116c4e27c981..63872bbf540c 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.c +++ b/sound/soc/codecs/wcd9xxx-common-v2.c @@ -237,10 +237,16 @@ static const char *mode_to_str(int mode) return "CLS_H_NORMAL"; case CLS_H_HIFI: return "CLS_H_HIFI"; + case CLS_H_LOHIFI: + return "CLS_H_LOHIFI"; case CLS_H_LP: return "CLS_H_LP"; + case CLS_H_ULP: + return "CLS_H_ULP"; case CLS_AB: return "CLS_AB"; + case CLS_AB_HIFI: + return "CLS_AB_HIFI"; default: return "CLS_H_INVALID"; }; @@ -332,7 +338,8 @@ static inline void wcd_clsh_set_int_mode(struct wcd_clsh_cdc_data *clsh_d, static inline void wcd_clsh_set_buck_mode(struct snd_soc_codec *codec, int mode) { - if (mode == CLS_H_HIFI) + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB) snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES, 0x08, 0x08); /* set to HIFI */ else @@ -343,7 +350,8 @@ static inline void wcd_clsh_set_buck_mode(struct snd_soc_codec *codec, static inline void wcd_clsh_set_flyback_mode(struct snd_soc_codec *codec, int mode) { - if (mode == CLS_H_HIFI) + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB) snd_soc_update_bits(codec, WCD9XXX_A_ANA_RX_SUPPLIES, 0x04, 0x04); /* set to HIFI */ else @@ -351,6 +359,55 @@ static inline void wcd_clsh_set_flyback_mode(struct snd_soc_codec *codec, 0x04, 0x00); /* set to Default */ } +static inline void wcd_clsh_gm3_boost_disable(struct snd_soc_codec *codec, + int mode) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent); + + if (!IS_CODEC_TYPE(wcd9xxx, WCD934X)) + return; + + if (mode == CLS_H_HIFI || mode == CLS_H_LOHIFI || + mode == CLS_AB_HIFI || mode == CLS_AB) { + snd_soc_update_bits(codec, WCD9XXX_HPH_CNP_WG_CTL, + 0x80, 0x0); /* disable GM3 Boost */ + snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x80); + } else { + snd_soc_update_bits(codec, WCD9XXX_HPH_CNP_WG_CTL, + 0x80, 0x80); /* set to Default */ + snd_soc_update_bits(codec, WCD9XXX_FLYBACK_VNEG_CTRL_4, + 0xF0, 0x70); + } +} + + +static inline void wcd_clsh_force_iq_ctl(struct snd_soc_codec *codec, + int mode) +{ + struct wcd9xxx *wcd9xxx = dev_get_drvdata(codec->dev->parent); + + if (!IS_CODEC_TYPE(wcd9xxx, WCD934X)) + return; + + if (mode == CLS_H_LOHIFI || mode == CLS_AB) { + snd_soc_update_bits(codec, WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x20); + snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0xC0); + snd_soc_update_bits(codec, WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x02); + } else { + + snd_soc_update_bits(codec, WCD9XXX_HPH_NEW_INT_PA_MISC2, + 0x20, 0x0); + snd_soc_update_bits(codec, WCD9XXX_RX_BIAS_HPH_LOWPOWER, + 0xF0, 0x80); + snd_soc_update_bits(codec, WCD9XXX_HPH_PA_CTL1, + 0x0E, 0x06); + } +} + static void wcd_clsh_buck_ctrl(struct snd_soc_codec *codec, struct wcd_clsh_cdc_data *clsh_d, int mode, @@ -470,11 +527,26 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec, gain = DAC_GAIN_0DB; ipeak = DELTA_I_50MA; break; + case CLS_AB_HIFI: + val = 0x08; + break; case CLS_H_HIFI: val = 0x08; gain = DAC_GAIN_M0P2DB; ipeak = DELTA_I_50MA; break; + case CLS_H_LOHIFI: + val = 0x00; + if ((IS_CODEC_TYPE(wcd9xxx, WCD9335)) || + (IS_CODEC_TYPE(wcd9xxx, WCD9326))) { + val = 0x08; + gain = DAC_GAIN_M0P2DB; + ipeak = DELTA_I_50MA; + } + break; + case CLS_H_ULP: + val = 0x0C; + break; case CLS_H_LP: val = 0x04; ipeak = DELTA_I_30MA; @@ -483,6 +555,14 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_codec *codec, return; }; + /* + * For tavil set mode to Lower_power for + * CLS_H_LOHIFI and CLS_AB + */ + if ((IS_CODEC_TYPE(wcd9xxx, WCD934X)) && + (mode == CLS_H_LOHIFI || mode == CLS_AB)) + val = 0x04; + snd_soc_update_bits(codec, WCD9XXX_A_ANA_HPH, 0x0C, val); if (TASHA_IS_2_0(wcd9xxx)) { snd_soc_update_bits(codec, WCD9XXX_CLASSH_CTRL_VCL_2, @@ -538,7 +618,7 @@ static void wcd_clsh_state_lo(struct snd_soc_codec *codec, dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode), is_enable ? "enable" : "disable"); - if (mode != CLS_AB) { + if (mode != CLS_AB && mode != CLS_AB_HIFI) { dev_err(codec->dev, "%s: LO cannot be in this mode: %d\n", __func__, mode); return; @@ -586,7 +666,8 @@ static void wcd_clsh_state_hph_ear(struct snd_soc_codec *codec, WCD_CLSH_STATE_HPHR); else return; - if (hph_mode != CLS_AB && !is_native_44_1_active(codec)) + if (hph_mode != CLS_AB && hph_mode != CLS_AB_HIFI + && !is_native_44_1_active(codec)) snd_soc_update_bits(codec, WCD9XXX_A_CDC_RX0_RX_PATH_CFG0, 0x40, 0x40); @@ -795,6 +876,7 @@ static void wcd_clsh_state_hph_lo(struct snd_soc_codec *codec, hph_mode); if ((hph_mode == CLS_AB) || + (hph_mode == CLS_AB_HIFI) || (hph_mode == CLS_NONE)) goto end; @@ -843,7 +925,7 @@ static void wcd_clsh_state_hph_st(struct snd_soc_codec *codec, dev_dbg(codec->dev, "%s: mode: %s, %s\n", __func__, mode_to_str(mode), is_enable ? "enable" : "disable"); - if (mode == CLS_AB) + if (mode == CLS_AB || mode == CLS_AB_HIFI) return; if (is_enable) { @@ -881,7 +963,7 @@ static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec, } if (is_enable) { - if (mode != CLS_AB) { + if (mode != CLS_AB && mode != CLS_AB_HIFI) { wcd_enable_clsh_block(codec, clsh_d, true); /* * These K1 values depend on the Headphone Impedance @@ -897,6 +979,8 @@ static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec, } wcd_clsh_set_buck_regulator_mode(codec, mode); wcd_clsh_set_flyback_mode(codec, mode); + wcd_clsh_gm3_boost_disable(codec, mode); + wcd_clsh_force_iq_ctl(codec, mode); wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true); wcd_clsh_set_flyback_current(codec, mode); wcd_clsh_set_buck_mode(codec, mode); @@ -906,7 +990,7 @@ static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec, } else { wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL); - if (mode != CLS_AB) { + if (mode != CLS_AB && mode != CLS_AB_HIFI) { snd_soc_update_bits(codec, WCD9XXX_A_CDC_RX2_RX_PATH_CFG0, 0x40, 0x00); @@ -915,6 +999,8 @@ static void wcd_clsh_state_hph_r(struct snd_soc_codec *codec, /* buck and flyback set to default mode and disable */ wcd_clsh_buck_ctrl(codec, clsh_d, CLS_H_NORMAL, false); wcd_clsh_flyback_ctrl(codec, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_force_iq_ctl(codec, CLS_H_NORMAL); + wcd_clsh_gm3_boost_disable(codec, CLS_H_NORMAL); wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL); wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL); wcd_clsh_set_buck_regulator_mode(codec, CLS_H_NORMAL); @@ -935,7 +1021,7 @@ static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec, } if (is_enable) { - if (mode != CLS_AB) { + if (mode != CLS_AB && mode != CLS_AB_HIFI) { wcd_enable_clsh_block(codec, clsh_d, true); /* * These K1 values depend on the Headphone Impedance @@ -951,6 +1037,8 @@ static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec, } wcd_clsh_set_buck_regulator_mode(codec, mode); wcd_clsh_set_flyback_mode(codec, mode); + wcd_clsh_gm3_boost_disable(codec, mode); + wcd_clsh_force_iq_ctl(codec, mode); wcd_clsh_flyback_ctrl(codec, clsh_d, mode, true); wcd_clsh_set_flyback_current(codec, mode); wcd_clsh_set_buck_mode(codec, mode); @@ -960,7 +1048,7 @@ static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec, } else { wcd_clsh_set_hph_mode(codec, CLS_H_NORMAL); - if (mode != CLS_AB) { + if (mode != CLS_AB && mode != CLS_AB_HIFI) { snd_soc_update_bits(codec, WCD9XXX_A_CDC_RX1_RX_PATH_CFG0, 0x40, 0x00); @@ -969,6 +1057,8 @@ static void wcd_clsh_state_hph_l(struct snd_soc_codec *codec, /* set buck and flyback to Default Mode */ wcd_clsh_buck_ctrl(codec, clsh_d, CLS_H_NORMAL, false); wcd_clsh_flyback_ctrl(codec, clsh_d, CLS_H_NORMAL, false); + wcd_clsh_force_iq_ctl(codec, CLS_H_NORMAL); + wcd_clsh_gm3_boost_disable(codec, CLS_H_NORMAL); wcd_clsh_set_flyback_mode(codec, CLS_H_NORMAL); wcd_clsh_set_buck_mode(codec, CLS_H_NORMAL); wcd_clsh_set_buck_regulator_mode(codec, CLS_H_NORMAL); diff --git a/sound/soc/codecs/wcd9xxx-common-v2.h b/sound/soc/codecs/wcd9xxx-common-v2.h index d3c52e73a7da..ee7e587b3f24 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.h +++ b/sound/soc/codecs/wcd9xxx-common-v2.h @@ -61,8 +61,10 @@ enum { CLS_H_NORMAL = 0, /* Class-H Default */ CLS_H_HIFI, /* Class-H HiFi */ CLS_H_LP, /* Class-H Low Power */ - CLS_AB, /* Class-AB */ + CLS_AB, /* Class-AB Low HIFI*/ CLS_H_LOHIFI, /* LoHIFI */ + CLS_H_ULP, /* Ultra Low power */ + CLS_AB_HIFI, /* Class-AB */ CLS_NONE, /* None of the above modes */ }; From 37e939f466dd6300c12fadb80384bfc2a81c7fae Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Fri, 2 Sep 2016 12:30:05 -0700 Subject: [PATCH 3/4] ASoC: wcd934x: add adaptive ANC support WCD934X codec supports adaptive ANC(Active noise cancellation) on ear and speaker path. Add the required changes to support this feature. Change-Id: I2a069fc208b080c1251f7aa473ae75ad02e883c8 Signed-off-by: Vidyakumar Athota --- sound/soc/codecs/wcd934x/wcd934x-routing.h | 60 ++++ sound/soc/codecs/wcd934x/wcd934x.c | 370 ++++++++++++++++++++- sound/soc/codecs/wcd934x/wcd934x.h | 3 + 3 files changed, 427 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wcd934x/wcd934x-routing.h b/sound/soc/codecs/wcd934x/wcd934x-routing.h index 8b20805de6f9..ac3031ffe615 100644 --- a/sound/soc/codecs/wcd934x/wcd934x-routing.h +++ b/sound/soc/codecs/wcd934x/wcd934x-routing.h @@ -312,6 +312,43 @@ const struct snd_soc_dapm_route tavil_audio_map[] = { {"ADC MUX13", "DMIC", "DMIC MUX13"}, {"ADC MUX13", "AMIC", "AMIC MUX13"}, + {"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX0", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX0", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX1", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX1", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX2", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX2", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX3", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX3", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX4", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX4", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX5", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX5", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX6", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX6", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX7", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX7", "ANC_FB_TUNE2", "ADC MUX13"}, + {"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX10"}, + {"ADC MUX8", "ANC_FB_TUNE1", "ADC MUX11"}, + {"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX12"}, + {"ADC MUX8", "ANC_FB_TUNE2", "ADC MUX13"}, + {"DMIC MUX0", "DMIC0", "DMIC0"}, {"DMIC MUX0", "DMIC1", "DMIC1"}, {"DMIC MUX0", "DMIC2", "DMIC2"}, @@ -860,6 +897,29 @@ const struct snd_soc_dapm_route tavil_audio_map[] = { {"RX INT8 CHAIN", NULL, "RX_BIAS"}, {"SPK2 OUT", NULL, "RX INT8 CHAIN"}, + /* ANC Routing */ + {"ANC0 FB MUX", "ANC_IN_EAR", "RX INT0 MIX2"}, + {"ANC0 FB MUX", "ANC_IN_HPHL", "RX INT1 MIX2"}, + {"ANC0 FB MUX", "ANC_IN_LO1", "RX INT3 MIX2"}, + {"ANC0 FB MUX", "ANC_IN_EAR_SPKR", "RX INT7 MIX2"}, + {"ANC1 FB MUX", "ANC_IN_HPHR", "RX INT2 MIX2"}, + {"ANC1 FB MUX", "ANC_IN_LO2", "RX INT4 MIX2"}, + + {"ANC OUT EAR Enable", "Switch", "ADC MUX10"}, + {"ANC OUT EAR Enable", "Switch", "ADC MUX11"}, + {"RX INT0 MIX2", NULL, "ANC OUT EAR Enable"}, + + {"ANC EAR PA", NULL, "RX INT0 DAC"}, + {"ANC EAR", NULL, "ANC EAR PA"}, + + {"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX10"}, + {"ANC OUT EAR SPKR Enable", "Switch", "ADC MUX11"}, + {"RX INT7 MIX2", NULL, "ANC OUT EAR SPKR Enable"}, + + {"ANC SPKR PA Enable", "Switch", "RX INT7 CHAIN"}, + {"ANC SPK1 PA", NULL, "ANC SPKR PA Enable"}, + {"SPK1 OUT", NULL, "ANC SPK1 PA"}, + /* * SRC0, SRC1 inputs to Sidetone RX Mixer * on RX0, RX1, RX2, RX3, RX4 and RX7 chains diff --git a/sound/soc/codecs/wcd934x/wcd934x.c b/sound/soc/codecs/wcd934x/wcd934x.c index 5713014c436f..a04d3f2add8c 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.c +++ b/sound/soc/codecs/wcd934x/wcd934x.c @@ -66,6 +66,15 @@ #define WCD934X_FORMATS_S16_LE (SNDRV_PCM_FMTBIT_S16_LE) +/* Macros for packing register writes into a U32 */ +#define WCD934X_PACKED_REG_SIZE sizeof(u32) +#define WCD934X_CODEC_UNPACK_ENTRY(packed, reg, mask, val) \ + do { \ + ((reg) = ((packed >> 16) & (0xffff))); \ + ((mask) = ((packed >> 8) & (0xff))); \ + ((val) = ((packed) & (0xff))); \ + } while (0) + #define STRING(name) #name #define WCD_DAPM_ENUM(name, reg, offset, text) \ static SOC_ENUM_SINGLE_DECL(name##_enum, reg, offset, text); \ @@ -378,6 +387,24 @@ static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = { (WCD934X_REGISTER_START_OFFSET + WCD934X_SB_PGD_PORT_RX_BASE), SB_PGD_PORT_RX_ENABLE_N, 0x1, WCD934X_REG_BITS, 0x1 }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + WCD934X_CDC_ANC0_IIR_ADAPT_CTL), + AANC_FF_GAIN_ADAPTIVE, 0x4, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + WCD934X_CDC_ANC0_IIR_ADAPT_CTL), + AANC_FFGAIN_ADAPTIVE_EN, 0x8, WCD934X_REG_BITS, 0 + }, + { + 1, + (WCD934X_REGISTER_START_OFFSET + + WCD934X_CDC_ANC0_FF_A_GAIN_CTL), + AANC_GAIN_CONTROL, 0xFF, WCD934X_REG_BITS, 0 + }, }; static struct afe_param_cdc_reg_cfg_data tavil_audio_reg_cfg = { @@ -385,6 +412,11 @@ static struct afe_param_cdc_reg_cfg_data tavil_audio_reg_cfg = { .reg_data = audio_reg_cfg, }; +static struct afe_param_id_cdc_aanc_version tavil_cdc_aanc_version = { + .cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION, + .aanc_hw_version = AANC_HW_BLOCK_VERSION_2, +}; + static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -451,6 +483,10 @@ struct tavil_priv { s32 micb_ref[TAVIL_MAX_MICBIAS]; s32 pullup_ref[TAVIL_MAX_MICBIAS]; + /* ANC related */ + u32 anc_slot; + bool anc_func; + /* compander */ int comp_enabled[COMPANDER_MAX]; /* class h specific data */ @@ -720,7 +756,7 @@ void *tavil_get_afe_config(struct snd_soc_codec *codec, case AFE_SLIMBUS_SLAVE_PORT_CONFIG: return &tavil_slimbus_slave_port_cfg; case AFE_AANC_VERSION: - return NULL; + return &tavil_cdc_aanc_version; case AFE_CDC_REGISTER_PAGE_CONFIG: return &tavil_cdc_reg_page_cfg; default: @@ -761,6 +797,212 @@ done: mutex_unlock(&tavil->svs_mutex); } +static int tavil_get_anc_slot(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = tavil->anc_slot; + return 0; +} + +static int tavil_put_anc_slot(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + tavil->anc_slot = ucontrol->value.integer.value[0]; + return 0; +} + +static int tavil_get_anc_func(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = (tavil->anc_func == true ? 1 : 0); + return 0; +} + +static int tavil_put_anc_func(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + + mutex_lock(&tavil->codec_mutex); + tavil->anc_func = (!ucontrol->value.integer.value[0] ? false : true); + dev_dbg(codec->dev, "%s: anc_func %x", __func__, tavil->anc_func); + + if (tavil->anc_func == true) { + snd_soc_dapm_enable_pin(dapm, "ANC EAR PA"); + snd_soc_dapm_enable_pin(dapm, "ANC EAR"); + snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA"); + snd_soc_dapm_disable_pin(dapm, "EAR PA"); + snd_soc_dapm_disable_pin(dapm, "EAR"); + } else { + snd_soc_dapm_disable_pin(dapm, "ANC EAR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC EAR"); + snd_soc_dapm_disable_pin(dapm, "ANC SPK1 PA"); + snd_soc_dapm_enable_pin(dapm, "EAR PA"); + snd_soc_dapm_enable_pin(dapm, "EAR"); + } + mutex_unlock(&tavil->codec_mutex); + + snd_soc_dapm_sync(dapm); + return 0; +} + +static int tavil_codec_enable_anc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + const char *filename; + const struct firmware *fw; + int i; + int ret = 0; + int num_anc_slots; + struct wcd9xxx_anc_header *anc_head; + struct firmware_cal *hwdep_cal = NULL; + u32 anc_writes_size = 0; + u32 anc_cal_size = 0; + int anc_size_remaining; + u32 *anc_ptr; + u16 reg; + u8 mask, val; + size_t cal_size; + const void *data; + + if (!tavil->anc_func) + return 0; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + hwdep_cal = wcdcal_get_fw_cal(tavil->fw_data, WCD9XXX_ANC_CAL); + if (hwdep_cal) { + data = hwdep_cal->data; + cal_size = hwdep_cal->size; + dev_dbg(codec->dev, "%s: using hwdep calibration, cal_size %zd", + __func__, cal_size); + } else { + filename = "WCD934X/WCD934X_anc.bin"; + ret = request_firmware(&fw, filename, codec->dev); + if (IS_ERR_VALUE(ret)) { + dev_err(codec->dev, "%s: Failed to acquire ANC data: %d\n", + __func__, ret); + return ret; + } + if (!fw) { + dev_err(codec->dev, "%s: Failed to get anc fw\n", + __func__); + return -ENODEV; + } + data = fw->data; + cal_size = fw->size; + dev_dbg(codec->dev, "%s: using request_firmware calibration\n", + __func__); + } + if (cal_size < sizeof(struct wcd9xxx_anc_header)) { + dev_err(codec->dev, "%s: Invalid cal_size %zd\n", + __func__, cal_size); + ret = -EINVAL; + goto err; + } + /* First number is the number of register writes */ + anc_head = (struct wcd9xxx_anc_header *)(data); + anc_ptr = (u32 *)(data + sizeof(struct wcd9xxx_anc_header)); + anc_size_remaining = cal_size - + sizeof(struct wcd9xxx_anc_header); + num_anc_slots = anc_head->num_anc_slots; + + if (tavil->anc_slot >= num_anc_slots) { + dev_err(codec->dev, "%s: Invalid ANC slot selected\n", + __func__); + ret = -EINVAL; + goto err; + } + for (i = 0; i < num_anc_slots; i++) { + if (anc_size_remaining < WCD934X_PACKED_REG_SIZE) { + dev_err(codec->dev, "%s: Invalid register format\n", + __func__); + ret = -EINVAL; + goto err; + } + anc_writes_size = (u32)(*anc_ptr); + anc_size_remaining -= sizeof(u32); + anc_ptr += 1; + + if ((anc_writes_size * WCD934X_PACKED_REG_SIZE) > + anc_size_remaining) { + dev_err(codec->dev, "%s: Invalid register format\n", + __func__); + ret = -EINVAL; + goto err; + } + + if (tavil->anc_slot == i) + break; + + anc_size_remaining -= (anc_writes_size * + WCD934X_PACKED_REG_SIZE); + anc_ptr += anc_writes_size; + } + if (i == num_anc_slots) { + dev_err(codec->dev, "%s: Selected ANC slot not present\n", + __func__); + ret = -EINVAL; + goto err; + } + + anc_cal_size = anc_writes_size; + for (i = 0; i < anc_writes_size; i++) { + WCD934X_CODEC_UNPACK_ENTRY(anc_ptr[i], reg, mask, val); + snd_soc_write(codec, reg, (val & mask)); + } + + if (!hwdep_cal) + release_firmware(fw); + break; + case SND_SOC_DAPM_POST_PMU: + /* Remove ANC Rx from reset */ + snd_soc_update_bits(codec, WCD934X_CDC_ANC0_CLK_RESET_CTL, + 0x08, 0x00); + snd_soc_update_bits(codec, WCD934X_CDC_ANC1_CLK_RESET_CTL, + 0x08, 0x00); + break; + case SND_SOC_DAPM_POST_PMD: + if (!strcmp(w->name, "ANC EAR PA") || + !strcmp(w->name, "ANC SPK1 PA")) { + snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_1_CTL, + 0x30, 0x00); + msleep(50); + snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_1_CTL, + 0x01, 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_ANC0_CLK_RESET_CTL, + 0x38, 0x38); + snd_soc_update_bits(codec, + WCD934X_CDC_ANC0_CLK_RESET_CTL, + 0x07, 0x00); + snd_soc_update_bits(codec, + WCD934X_CDC_ANC0_CLK_RESET_CTL, + 0x38, 0x00); + } + break; + } + + return 0; +err: + if (!hwdep_cal) + release_firmware(fw); + return ret; +} + static int tavil_vi_feed_mixer_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1353,10 +1595,40 @@ static int tavil_codec_enable_rx_bias(struct snd_soc_dapm_widget *w, return 0; } +static int tavil_codec_enable_spkr_anc(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + int ret = 0; + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); + + if (!tavil->anc_func) + return 0; + + dev_dbg(codec->dev, "%s: w: %s event: %d anc: %d\n", __func__, + w->name, event, tavil->anc_func); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = tavil_codec_enable_anc(w, kcontrol, event); + snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_CFG0, + 0x10, 0x10); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, WCD934X_CDC_RX7_RX_PATH_CFG0, + 0x10, 0x00); + ret = tavil_codec_enable_anc(w, kcontrol, event); + break; + } + return ret; +} + static int tavil_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + int ret = 0; struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); @@ -1377,11 +1649,22 @@ static int tavil_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, WCD934X_CDC_RX0_RX_PATH_MIX_CTL, 0x10, 0x00); break; - default: + case SND_SOC_DAPM_POST_PMD: + /* + * 5ms sleep is required after PA is disabled as per + * HW requirement + */ + usleep_range(5000, 5500); + + if (!(strcmp(w->name, "ANC EAR PA"))) { + ret = tavil_codec_enable_anc(w, kcontrol, event); + snd_soc_update_bits(codec, WCD934X_CDC_RX0_RX_PATH_CFG0, + 0x10, 0x00); + } break; }; - return 0; + return ret; } static void tavil_codec_override(struct snd_soc_codec *codec, int mode, @@ -1592,6 +1875,7 @@ static int tavil_codec_ear_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { + int ret = 0; struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct tavil_priv *tavil = snd_soc_codec_get_drvdata(codec); @@ -1602,10 +1886,17 @@ static int tavil_codec_ear_dac_event(struct snd_soc_dapm_widget *w, /* Disable AutoChop timer during power up */ snd_soc_update_bits(codec, WCD934X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00); + + if (tavil->anc_func) + ret = tavil_codec_enable_anc(w, kcontrol, event); + wcd_clsh_fsm(codec, &tavil->clsh_d, WCD_CLSH_EVENT_PRE_DAC, WCD_CLSH_STATE_EAR, CLS_H_NORMAL); + if (tavil->anc_func) + snd_soc_update_bits(codec, WCD934X_CDC_RX0_RX_PATH_CFG0, + 0x10, 0x10); break; case SND_SOC_DAPM_POST_PMD: wcd_clsh_fsm(codec, &tavil->clsh_d, @@ -1617,7 +1908,7 @@ static int tavil_codec_ear_dac_event(struct snd_soc_dapm_widget *w, break; }; - return 0; + return ret; } static int tavil_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, @@ -4036,7 +4327,6 @@ static int tavil_ear_pa_gain_put(struct snd_kcontrol *kcontrol, return 0; } - static int tavil_rx_hph_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -4067,7 +4357,6 @@ static int tavil_rx_hph_mode_put(struct snd_kcontrol *kcontrol, return 0; } - static const char * const rx_hph_mode_mux_text[] = { "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI", "CLS_H_ULP", "CLS_AB_HIFI", @@ -4077,6 +4366,10 @@ static const struct soc_enum rx_hph_mode_mux_enum = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(rx_hph_mode_mux_text), rx_hph_mode_mux_text); +static const char *const tavil_anc_func_text[] = {"OFF", "ON"}; +static const struct soc_enum tavil_anc_func_enum = + SOC_ENUM_SINGLE_EXT(2, tavil_anc_func_text); + /* Cutoff frequency for high pass filter */ static const char * const cf_text[] = { "CF_NEG_3DB_4HZ", "CF_NEG_3DB_75HZ", "CF_NEG_3DB_150HZ" @@ -4228,6 +4521,11 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = { WCD934X_CDC_SIDETONE_IIR1_IIR_GAIN_B4_CTL, 0, -84, 40, digital_gain), + SOC_SINGLE_EXT("ANC Slot", SND_SOC_NOPM, 0, 100, 0, tavil_get_anc_slot, + tavil_put_anc_slot), + SOC_ENUM_EXT("ANC Function", tavil_anc_func_enum, tavil_get_anc_func, + tavil_put_anc_func), + SOC_ENUM("TX0 HPF cut off", cf_dec0_enum), SOC_ENUM("TX1 HPF cut off", cf_dec1_enum), SOC_ENUM("TX2 HPF cut off", cf_dec2_enum), @@ -4596,6 +4894,15 @@ static const char * const amic4_5_sel_text[] = { "AMIC4", "AMIC5" }; +static const char * const anc0_fb_mux_text[] = { + "ZERO", "ANC_IN_HPHL", "ANC_IN_EAR", "ANC_IN_EAR_SPKR", + "ANC_IN_LO1" +}; + +static const char * const anc1_fb_mux_text[] = { + "ZERO", "ANC_IN_HPHR", "ANC_IN_LO2" +}; + static const char * const rx_echo_mux_text[] = { "ZERO", "RX_MIX0", "RX_MIX1", "RX_MIX2", "RX_MIX3", "RX_MIX4", "RX_MIX5", "RX_MIX6", "RX_MIX7", "RX_MIX8" @@ -5047,6 +5354,18 @@ WCD_DAPM_ENUM(int4_2_native, SND_SOC_NOPM, 0, native_mux_text); WCD_DAPM_ENUM(int7_2_native, SND_SOC_NOPM, 0, native_mux_text); WCD_DAPM_ENUM(int8_2_native, SND_SOC_NOPM, 0, native_mux_text); +WCD_DAPM_ENUM(anc0_fb, WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 0, anc0_fb_mux_text); +WCD_DAPM_ENUM(anc1_fb, WCD934X_CDC_RX_INP_MUX_ANC_CFG0, 3, anc1_fb_mux_text); + +static const struct snd_kcontrol_new anc_ear_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_ear_spkr_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + +static const struct snd_kcontrol_new anc_spkr_pa_switch = + SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); + static const struct snd_kcontrol_new mad_cpe1_switch = SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0); @@ -5417,6 +5736,9 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = { WCD_DAPM_MUX("AMIC4_5 SEL", 0, tx_amic4_5), + WCD_DAPM_MUX("ANC0 FB MUX", 0, anc0_fb), + WCD_DAPM_MUX("ANC1 FB MUX", 0, anc1_fb), + SND_SOC_DAPM_INPUT("AMIC1"), SND_SOC_DAPM_INPUT("AMIC2"), SND_SOC_DAPM_INPUT("AMIC3"), @@ -5648,6 +5970,12 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = { SND_SOC_DAPM_PGA_E("LINEOUT2 PA", WCD934X_ANA_LO_1_2, 6, 0, NULL, 0, tavil_codec_enable_lineout_pa, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC EAR PA", WCD934X_ANA_EAR, 7, 0, NULL, 0, + tavil_codec_enable_ear_pa, SND_SOC_DAPM_POST_PMU | + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PGA_E("ANC SPK1 PA", SND_SOC_NOPM, 0, 0, NULL, 0, + tavil_codec_enable_spkr_anc, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_OUTPUT("EAR"), SND_SOC_DAPM_OUTPUT("HPHL"), @@ -5656,6 +5984,14 @@ static const struct snd_soc_dapm_widget tavil_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("LINEOUT2"), SND_SOC_DAPM_OUTPUT("SPK1 OUT"), SND_SOC_DAPM_OUTPUT("SPK2 OUT"), + SND_SOC_DAPM_OUTPUT("ANC EAR"), + + SND_SOC_DAPM_SWITCH("ANC OUT EAR Enable", SND_SOC_NOPM, 0, 0, + &anc_ear_switch), + SND_SOC_DAPM_SWITCH("ANC OUT EAR SPKR Enable", SND_SOC_NOPM, 0, 0, + &anc_ear_spkr_switch), + SND_SOC_DAPM_SWITCH("ANC SPKR PA Enable", SND_SOC_NOPM, 0, 0, + &anc_spkr_pa_switch), SND_SOC_DAPM_SUPPLY("RX_BIAS", SND_SOC_NOPM, 0, 0, tavil_codec_enable_rx_bias, @@ -6768,6 +7104,7 @@ static int tavil_handle_pdata(struct tavil_priv *tavil, { struct snd_soc_codec *codec = tavil->codec; u8 mad_dmic_ctl_val; + u8 anc_ctl_value; u32 def_dmic_rate, dmic_clk_drv; int vout_ctl_1, vout_ctl_2, vout_ctl_3, vout_ctl_4; int rc = 0; @@ -6873,6 +7210,20 @@ static int tavil_handle_pdata(struct tavil_priv *tavil, snd_soc_update_bits(codec, WCD934X_CPE_SS_DMIC2_CTL, 0x0E, mad_dmic_ctl_val << 1); + if (dmic_clk_drv == WCD934X_DMIC_CLK_DIV_2) + anc_ctl_value = WCD934X_ANC_DMIC_X2_FULL_RATE; + else + anc_ctl_value = WCD934X_ANC_DMIC_X2_HALF_RATE; + + snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_2_CTL, + 0x40, anc_ctl_value << 6); + snd_soc_update_bits(codec, WCD934X_CDC_ANC0_MODE_2_CTL, + 0x20, anc_ctl_value << 5); + snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_2_CTL, + 0x40, anc_ctl_value << 6); + snd_soc_update_bits(codec, WCD934X_CDC_ANC1_MODE_2_CTL, + 0x20, anc_ctl_value << 5); + done: return rc; } @@ -7086,6 +7437,12 @@ static int tavil_soc_codec_probe(struct snd_soc_codec *codec) if (IS_ERR_OR_NULL(tavil->dsd_config)) dev_dbg(tavil->dev, "%s: DSD init failed\n", __func__); + mutex_lock(&tavil->codec_mutex); + snd_soc_dapm_disable_pin(dapm, "ANC EAR PA"); + snd_soc_dapm_disable_pin(dapm, "ANC EAR"); + snd_soc_dapm_enable_pin(dapm, "ANC SPK1 PA"); + mutex_unlock(&tavil->codec_mutex); + snd_soc_dapm_sync(dapm); tavil_wdsp_initialize(codec); @@ -7667,6 +8024,7 @@ static int tavil_probe(struct platform_device *pdev) tavil->swr.plat_data.bulk_write = tavil_swrm_bulk_write; tavil->swr.plat_data.clk = tavil_swrm_clock; tavil->swr.plat_data.handle_irq = tavil_swrm_handle_irq; + tavil->swr.spkr_gain_offset = WCD934X_RX_GAIN_OFFSET_0_DB; /* Register for Clock */ wcd_ext_clk = clk_get(tavil->wcd9xxx->dev, "wcd_clk"); diff --git a/sound/soc/codecs/wcd934x/wcd934x.h b/sound/soc/codecs/wcd934x/wcd934x.h index 9cffa168c298..0b7007e67003 100644 --- a/sound/soc/codecs/wcd934x/wcd934x.h +++ b/sound/soc/codecs/wcd934x/wcd934x.h @@ -32,6 +32,9 @@ #define WCD934X_DMIC_CLK_DIV_16 0x5 #define WCD934X_DMIC_CLK_DRIVE_DEFAULT 0x02 +#define WCD934X_ANC_DMIC_X2_FULL_RATE 1 +#define WCD934X_ANC_DMIC_X2_HALF_RATE 0 + #define TAVIL_MAX_MICBIAS 4 #define TAVIL_NUM_INTERPOLATORS 9 #define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64 From b1c114010839ce7bb57440e20758adcee3860a70 Mon Sep 17 00:00:00 2001 From: Vidyakumar Athota Date: Thu, 15 Sep 2016 13:54:52 -0700 Subject: [PATCH 4/4] drivers: mfd: set IIR and ANC registers as volatile IIR and ANC registers are not cacheable so add them to volatile register list. Change-Id: I99e45021ca90138b73aebe1f13a6af0f42c58227 Signed-off-by: Vidyakumar Athota --- drivers/mfd/wcd934x-regmap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/mfd/wcd934x-regmap.c b/drivers/mfd/wcd934x-regmap.c index b0e3bec683ed..b102264ca8fd 100644 --- a/drivers/mfd/wcd934x-regmap.c +++ b/drivers/mfd/wcd934x-regmap.c @@ -1848,6 +1848,20 @@ static bool wcd934x_is_volatile_register(struct device *dev, unsigned int reg) if (reg_tbl && reg_tbl[reg_offset] == WCD934X_READ) return true; + /* IIR Coeff registers are not cacheable */ + if ((reg >= WCD934X_CDC_SIDETONE_IIR0_IIR_COEF_B1_CTL) && + (reg <= WCD934X_CDC_SIDETONE_IIR1_IIR_COEF_B2_CTL)) + return true; + + if ((reg >= WCD934X_CDC_ANC0_IIR_COEFF_1_CTL) && + (reg <= WCD934X_CDC_ANC0_FB_GAIN_CTL)) + return true; + + if ((reg >= WCD934X_CDC_ANC1_IIR_COEFF_1_CTL) && + (reg <= WCD934X_CDC_ANC1_FB_GAIN_CTL)) + return true; + + /* * Need to mark volatile for registers that are writable but * only few bits are read-only