From 97cc2dc6d099ccbbd4f727d25916cd3481307647 Mon Sep 17 00:00:00 2001 From: Phani Kumar Uppalapati Date: Tue, 18 Aug 2015 20:20:44 -0700 Subject: [PATCH] ASoC: wcd9335: Add support for various headphone modes WCD9335 codec version 2.0 supports multiple headphone modes namely LOHIFI, LOWPWR for audio playback. Add support to configure codec registers for these modes in version 2.0. Change-Id: I62eb409868795ea3913f6e967429b76f45cde2f9 Signed-off-by: Phani Kumar Uppalapati --- sound/soc/codecs/wcd9335.c | 102 +++++++++++++++++++++++++-- sound/soc/codecs/wcd9xxx-common-v2.c | 6 ++ sound/soc/codecs/wcd9xxx-common-v2.h | 2 + 3 files changed, 103 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/wcd9335.c b/sound/soc/codecs/wcd9335.c index 70adf933659e..a43424117e79 100644 --- a/sound/soc/codecs/wcd9335.c +++ b/sound/soc/codecs/wcd9335.c @@ -3311,6 +3311,75 @@ static int tasha_codec_enable_ear_pa(struct snd_soc_dapm_widget *w, return ret; } +static void tasha_codec_hph_lohifi_config(struct snd_soc_codec *codec, + struct tasha_priv *tasha, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x02); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08); + snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_PA, 0x0F, 0x06); + snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, + 0xF0, 0x40); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_write(codec, WCD9335_RX_BIAS_HPH_RDACBUFF_CNP2, 0x8A); + snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_PA, 0x0F, 0x0A); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x06); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00); + } +} + +static void tasha_codec_hph_lp_config(struct snd_soc_codec *codec, + struct tasha_priv *tasha, + int event) +{ + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x0C); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x08); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x04, 0x04); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x20, 0x20); + snd_soc_update_bits(codec, WCD9335_HPH_RDAC_LDO_CTL, 0x07, + 0x01); + snd_soc_update_bits(codec, WCD9335_HPH_RDAC_LDO_CTL, 0x70, + 0x10); + snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_RDAC_LDO, + 0x0F, 0x01); + snd_soc_update_bits(codec, WCD9335_RX_BIAS_HPH_RDAC_LDO, + 0xF0, 0x10); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_update_bits(codec, WCD9335_HPH_R_EN, 0xC0, 0x80); + snd_soc_update_bits(codec, WCD9335_HPH_L_EN, 0xC0, 0x80); + snd_soc_write(codec, WCD9335_RX_BIAS_HPH_RDAC_LDO, 0x88); + snd_soc_write(codec, WCD9335_HPH_RDAC_LDO_CTL, 0x33); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x20, 0x00); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x04, 0x00); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL2, 0x08, 0x00); + snd_soc_update_bits(codec, WCD9335_HPH_PA_CTL1, 0x0E, 0x06); + } +} + +static void tasha_codec_hph_mode_config(struct snd_soc_codec *codec, + int event, int mode) +{ + struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec); + + if (!TASHA_IS_2_0(tasha->wcd9xxx->version)) + return; + + switch (mode) { + case CLS_H_LP: + tasha_codec_hph_lp_config(codec, tasha, event); + break; + case CLS_H_LOHIFI: + tasha_codec_hph_lohifi_config(codec, tasha, event); + break; + } +} + static int tasha_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -3333,7 +3402,7 @@ static int tasha_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, /* Read DEM INP Select */ dem_inp = snd_soc_read(codec, WCD9335_CDC_RX2_RX_PATH_SEC0) & 0x03; - if (((hph_mode == CLS_H_HIFI) || + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { dev_err(codec->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", __func__, hph_mode); @@ -3342,7 +3411,11 @@ static int tasha_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, wcd_clsh_fsm(codec, &tasha->clsh_d, WCD_CLSH_EVENT_PRE_DAC, WCD_CLSH_STATE_HPHR, - hph_mode); + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + tasha_codec_hph_mode_config(codec, event, hph_mode); + if (tasha->anc_func) snd_soc_update_bits(codec, WCD9335_CDC_RX2_RX_PATH_CFG0, 0x10, 0x10); @@ -3367,10 +3440,16 @@ static int tasha_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMD: /* 1000us required as per HW requirement */ usleep_range(1000, 1100); + + if (!(wcd_clsh_get_clsh_state(&tasha->clsh_d) & + WCD_CLSH_STATE_HPHL)) + tasha_codec_hph_mode_config(codec, event, hph_mode); + wcd_clsh_fsm(codec, &tasha->clsh_d, WCD_CLSH_EVENT_POST_PA, WCD_CLSH_STATE_HPHR, - hph_mode); + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); break; }; @@ -3399,7 +3478,7 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, /* Read DEM INP Select */ dem_inp = snd_soc_read(codec, WCD9335_CDC_RX1_RX_PATH_SEC0) & 0x03; - if (((hph_mode == CLS_H_HIFI) || + if (((hph_mode == CLS_H_HIFI) || (hph_mode == CLS_H_LOHIFI) || (hph_mode == CLS_H_LP)) && (dem_inp != 0x01)) { dev_err(codec->dev, "%s: DEM Input not set correctly, hph_mode: %d\n", __func__, hph_mode); @@ -3408,7 +3487,11 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, wcd_clsh_fsm(codec, &tasha->clsh_d, WCD_CLSH_EVENT_PRE_DAC, WCD_CLSH_STATE_HPHL, - hph_mode); + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); + + tasha_codec_hph_mode_config(codec, event, hph_mode); + if (tasha->anc_func) snd_soc_update_bits(codec, WCD9335_CDC_RX1_RX_PATH_CFG0, 0x10, 0x10); @@ -3433,10 +3516,15 @@ static int tasha_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, case SND_SOC_DAPM_POST_PMD: /* 1000us required as per HW requirement */ usleep_range(1000, 1100); + + if (!(wcd_clsh_get_clsh_state(&tasha->clsh_d) & + WCD_CLSH_STATE_HPHR)) + tasha_codec_hph_mode_config(codec, event, hph_mode); wcd_clsh_fsm(codec, &tasha->clsh_d, WCD_CLSH_EVENT_POST_PA, WCD_CLSH_STATE_HPHL, - hph_mode); + ((hph_mode == CLS_H_LOHIFI) ? + CLS_H_HIFI : hph_mode)); break; }; @@ -6448,7 +6536,7 @@ static int tasha_codec_vbat_enable_event(struct snd_soc_dapm_widget *w, } static const char * const rx_hph_mode_mux_text[] = { - "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB" + "CLS_H_INVALID", "CLS_H_HIFI", "CLS_H_LP", "CLS_AB", "CLS_H_LOHIFI" }; static const struct soc_enum rx_hph_mode_mux_enum = diff --git a/sound/soc/codecs/wcd9xxx-common-v2.c b/sound/soc/codecs/wcd9xxx-common-v2.c index a7f54071eb62..54f96cfa26f0 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.c +++ b/sound/soc/codecs/wcd9xxx-common-v2.c @@ -847,6 +847,12 @@ void wcd_clsh_fsm(struct snd_soc_codec *codec, }; } +int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh) +{ + return clsh->state; +} +EXPORT_SYMBOL(wcd_clsh_get_clsh_state); + void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh) { int i; diff --git a/sound/soc/codecs/wcd9xxx-common-v2.h b/sound/soc/codecs/wcd9xxx-common-v2.h index 63a27233a06d..2ad91189d3cb 100644 --- a/sound/soc/codecs/wcd9xxx-common-v2.h +++ b/sound/soc/codecs/wcd9xxx-common-v2.h @@ -62,6 +62,7 @@ enum { CLS_H_HIFI, /* Class-H HiFi */ CLS_H_LP, /* Class-H Low Power */ CLS_AB, /* Class-AB */ + CLS_H_LOHIFI, /* LoHIFI */ CLS_NONE, /* None of the above modes */ }; @@ -141,6 +142,7 @@ extern void wcd_clsh_fsm(struct snd_soc_codec *codec, int int_mode); extern void wcd_clsh_init(struct wcd_clsh_cdc_data *clsh); +extern int wcd_clsh_get_clsh_state(struct wcd_clsh_cdc_data *clsh); enum { RESERVED = 0,