Loading sound/soc/codecs/msm8x16-wcd.c +211 −7 Original line number Diff line number Diff line Loading @@ -2066,6 +2066,51 @@ static int msm8x16_wcd_pa_gain_put(struct snd_kcontrol *kcontrol, return 0; } static int msm8x16_wcd_hph_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); if (msm8x16_wcd->hph_mode == NORMAL_MODE) { ucontrol->value.integer.value[0] = 0; } else if (msm8x16_wcd->hph_mode == HD2_MODE) { ucontrol->value.integer.value[0] = 1; } else { dev_err(codec->dev, "%s: ERROR: Default HPH Mode= %d\n", __func__, msm8x16_wcd->hph_mode); } dev_dbg(codec->dev, "%s: msm8x16_wcd->hph_mode = %d\n", __func__, msm8x16_wcd->hph_mode); return 0; } static int msm8x16_wcd_hph_mode_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", __func__, ucontrol->value.integer.value[0]); switch (ucontrol->value.integer.value[0]) { case 0: msm8x16_wcd->hph_mode = NORMAL_MODE; break; case 1: if (get_codec_version(msm8x16_wcd) >= DIANGU) msm8x16_wcd->hph_mode = HD2_MODE; break; default: msm8x16_wcd->hph_mode = NORMAL_MODE; break; } dev_dbg(codec->dev, "%s: msm8x16_wcd->hph_mode_set = %d\n", __func__, msm8x16_wcd->hph_mode); return 0; } static int msm8x16_wcd_boost_option_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) Loading Loading @@ -2362,6 +2407,56 @@ static int msm8x16_wcd_put_iir_band_audio_mixer( return 0; } static int msm8x16_wcd_compander_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); int comp_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->reg; int rx_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->shift; dev_dbg(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n", __func__, comp_idx, rx_idx, msm8x16_wcd->comp_enabled[rx_idx]); ucontrol->value.integer.value[0] = msm8x16_wcd->comp_enabled[rx_idx]; dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", __func__, ucontrol->value.integer.value[0]); return 0; } static int msm8x16_wcd_compander_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); int comp_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->reg; int rx_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->shift; int value = ucontrol->value.integer.value[0]; dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", __func__, ucontrol->value.integer.value[0]); if (get_codec_version(msm8x16_wcd) >= DIANGU) { if (!value) msm8x16_wcd->comp_enabled[rx_idx] = 0; else msm8x16_wcd->comp_enabled[rx_idx] = comp_idx; } dev_dbg(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n", __func__, comp_idx, rx_idx, msm8x16_wcd->comp_enabled[rx_idx]); return 0; } static const char * const msm8x16_wcd_loopback_mode_ctrl_text[] = { "DISABLE", "ENABLE"}; static const struct soc_enum msm8x16_wcd_loopback_mode_ctl_enum[] = { Loading Loading @@ -2398,6 +2493,13 @@ static const struct soc_enum msm8x16_wcd_ext_spk_boost_ctl_enum[] = { SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ext_spk_boost_ctrl_text), }; static const char * const msm8x16_wcd_hph_mode_ctrl_text[] = { "NORMAL", "HD2"}; static const struct soc_enum msm8x16_wcd_hph_mode_ctl_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm8x16_wcd_hph_mode_ctrl_text), msm8x16_wcd_hph_mode_ctrl_text), }; /*cut of frequency for high pass filter*/ static const char * const cf_text[] = { "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz" Loading @@ -2420,6 +2522,9 @@ static const struct soc_enum cf_rxmix3_enum = static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = { SOC_ENUM_EXT("RX HPH Mode", msm8x16_wcd_hph_mode_ctl_enum[0], msm8x16_wcd_hph_mode_get, msm8x16_wcd_hph_mode_set), SOC_ENUM_EXT("Boost Option", msm8x16_wcd_boost_option_ctl_enum[0], msm8x16_wcd_boost_option_get, msm8x16_wcd_boost_option_set), Loading Loading @@ -2556,6 +2661,11 @@ static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = { msm8x16_wcd_get_iir_band_audio_mixer, msm8x16_wcd_put_iir_band_audio_mixer), SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM8X16_WCD_RX1, 1, 0, msm8x16_wcd_compander_get, msm8x16_wcd_compander_set), SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM8X16_WCD_RX2, 1, 0, msm8x16_wcd_compander_get, msm8x16_wcd_compander_set), }; static int tombak_hph_impedance_get(struct snd_kcontrol *kcontrol, Loading Loading @@ -3707,6 +3817,59 @@ static int msm89xx_wcd_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w, return 0; } static int msm8x16_wcd_codec_config_compander(struct snd_soc_codec *codec, int interp_n, int event) { struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: event %d shift %d, enabled %d\n", __func__, event, interp_n, msm8x16_wcd->comp_enabled[interp_n]); /* compander is not enabled */ if (!msm8x16_wcd->comp_enabled[interp_n]) return 0; switch (msm8x16_wcd->comp_enabled[interp_n]) { case COMPANDER_1: if (SND_SOC_DAPM_EVENT_ON(event)) { /* Enable Compander Clock */ snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0x0F, 0x09); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL, 0x01, 0x01); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B1_CTL, 1 << interp_n, 1 << interp_n); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B3_CTL, 0xFF, 0x01); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0xF0, 0x50); /* add sleep for compander to settle */ usleep_range(1000, 1100); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B3_CTL, 0xFF, 0x28); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0xF0, 0xB0); } else if (SND_SOC_DAPM_EVENT_OFF(event)) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0x0F, 0x05); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B1_CTL, 1 << interp_n, 0); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL, 0x01, 0x00); } break; default: dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__, msm8x16_wcd->comp_enabled[interp_n]); break; }; return 0; } static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) Loading @@ -3718,6 +3881,7 @@ static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: msm8x16_wcd_codec_config_compander(codec, w->shift, event); /* apply the digital gain after the interpolator is enabled*/ if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg)) snd_soc_write(codec, Loading @@ -3727,6 +3891,7 @@ static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w, ); break; case SND_SOC_DAPM_POST_PMD: msm8x16_wcd_codec_config_compander(codec, w->shift, event); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL, 1 << w->shift, 1 << w->shift); Loading Loading @@ -3933,6 +4098,14 @@ static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x08, 0x00); if (HD2_MODE == msm8x16_wcd->hph_mode) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x1C, 0x14); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B4_CTL, 0x18, 0x10); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x80, 0x80); } snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02); snd_soc_update_bits(codec, Loading @@ -3955,6 +4128,14 @@ static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w, MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00); if (HD2_MODE == msm8x16_wcd->hph_mode) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x1C, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B4_CTL, 0x18, 0xFF); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x80, 0x00); } break; } return 0; Loading @@ -3979,8 +4160,6 @@ static int msm8x16_wcd_lo_dac_event(struct snd_soc_dapm_widget *w, MSM8X16_WCD_A_ANALOG_RX_LO_DAC_CTL, 0x08, 0x08); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_LO_DAC_CTL, 0x40, 0x40); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC, 0xff, 0x98); break; case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(codec, Loading @@ -3989,8 +4168,6 @@ static int msm8x16_wcd_lo_dac_event(struct snd_soc_dapm_widget *w, MSM8X16_WCD_A_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_LO_EN_CTL, 0x40, 0x40); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC, 0xff, 0x98); break; case SND_SOC_DAPM_POST_PMD: usleep_range(20000, 20100); Loading @@ -4017,11 +4194,20 @@ static int msm8x16_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); switch (event) { case SND_SOC_DAPM_PRE_PMU: if (HD2_MODE == msm8x16_wcd->hph_mode) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x1C, 0x14); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B4_CTL, 0x18, 0x10); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x80, 0x80); } snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02); snd_soc_update_bits(codec, Loading @@ -4038,6 +4224,14 @@ static int msm8x16_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w, MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00); if (HD2_MODE == msm8x16_wcd->hph_mode) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x1C, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B4_CTL, 0x18, 0xFF); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x80, 0x00); } break; } return 0; Loading Loading @@ -4816,15 +5010,15 @@ static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = { SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER_E("RX1 MIX2", MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL, MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, MSM8X16_WCD_RX1, 0, NULL, 0, msm8x16_wcd_codec_enable_interpolator, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER_E("RX2 MIX2", MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL, MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, MSM8X16_WCD_RX2, 0, NULL, 0, msm8x16_wcd_codec_enable_interpolator, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER_E("RX3 MIX1", MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL, MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, MSM8X16_WCD_RX3, 0, NULL, 0, msm8x16_wcd_codec_enable_interpolator, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), Loading Loading @@ -5185,6 +5379,7 @@ static int msm8x16_wcd_device_down(struct snd_soc_codec *codec) struct msm8916_asoc_mach_data *pdata = NULL; struct msm8x16_wcd_priv *msm8x16_wcd_priv = snd_soc_codec_get_drvdata(codec); int i; pdata = snd_soc_card_get_drvdata(codec->component.card); dev_dbg(codec->dev, "%s: device down!\n", __func__); Loading Loading @@ -5231,6 +5426,10 @@ static int msm8x16_wcd_device_down(struct snd_soc_codec *codec) } } msm8x16_wcd_boost_off(codec); msm8x16_wcd_priv->hph_mode = NORMAL_MODE; for (i = 0; i < MSM8X16_WCD_RX_MAX; i++) msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE; /* 40ms to allow boost to discharge */ msleep(40); /* Disable PA to avoid pop during codec bring up */ Loading Loading @@ -5507,6 +5706,11 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen. */ msm8x16_wcd_priv->boost_option = BOOST_SWITCH; msm8x16_wcd_priv->hph_mode = NORMAL_MODE; for (i = 0; i < MSM8X16_WCD_RX_MAX; i++) msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE; msm8x16_wcd_dt_parse_boost_info(codec); msm8x16_wcd_set_boost_v(codec); Loading sound/soc/codecs/msm8x16-wcd.h +16 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,18 @@ enum codec_versions { UNSUPPORTED, }; /* Support different hph modes */ enum { NORMAL_MODE = 0, HD2_MODE, }; /* Codec supports 1 compander */ enum { COMPANDER_NONE = 0, COMPANDER_1, /* HPHL/R */ COMPANDER_MAX, }; enum wcd_curr_ref { I_h4_UA = 0, Loading Loading @@ -287,6 +299,10 @@ struct msm8x16_wcd_priv { bool clock_active; bool config_mode_active; u16 boost_option; /* mode to select hd2 */ u32 hph_mode; /* compander used for each rx chain */ u32 comp_enabled[MSM8X16_WCD_RX_MAX]; bool spk_boost_set; bool ear_pa_boost_set; bool ext_spk_boost_set; Loading sound/soc/codecs/msm8x16_wcd_registers.h +21 −1 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -350,6 +350,8 @@ #define MSM8X16_WCD_A_CDC_CLK_SD_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_CLK_WSA_VI_B1_CTL (0x230) #define MSM8X16_WCD_A_CDC_CLK_WSA_VI_B1_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL (0x234) #define MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_RX1_B1_CTL (0x240) #define MSM8X16_WCD_A_CDC_RX1_B1_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_RX2_B1_CTL (0x260) Loading Loading @@ -402,6 +404,24 @@ #define MSM8X16_WCD_A_CDC_TOP_GAIN_UPDATE__POR (0x00) #define MSM8X16_WCD_A_CDC_TOP_CTL (0x2A4) #define MSM8X16_WCD_A_CDC_TOP_CTL__POR (0x01) #define MSM8X16_WCD_A_CDC_COMP0_B1_CTL (0x2B0) #define MSM8X16_WCD_A_CDC_COMP0_B1_CTL__POR (0x30) #define MSM8X16_WCD_A_CDC_COMP0_B2_CTL (0x2B4) #define MSM8X16_WCD_A_CDC_COMP0_B2_CTL__POR (0xB5) #define MSM8X16_WCD_A_CDC_COMP0_B3_CTL (0x2B8) #define MSM8X16_WCD_A_CDC_COMP0_B3_CTL__POR (0x28) #define MSM8X16_WCD_A_CDC_COMP0_B4_CTL (0x2BC) #define MSM8X16_WCD_A_CDC_COMP0_B4_CTL__POR (0x37) #define MSM8X16_WCD_A_CDC_COMP0_B5_CTL (0x2C0) #define MSM8X16_WCD_A_CDC_COMP0_B5_CTL__POR (0x7F) #define MSM8X16_WCD_A_CDC_COMP0_B6_CTL (0x2C4) #define MSM8X16_WCD_A_CDC_COMP0_B6_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_COMP0_SHUT_DOWN_STATUS (0x2C8) #define MSM8X16_WCD_A_CDC_COMP0_SHUT_DOWN_STATUS__POR (0x03) #define MSM8X16_WCD_A_CDC_COMP0_FS_CFG (0x2CC) #define MSM8X16_WCD_A_CDC_COMP0_FS_CFG__POR (0x03) #define MSM8X16_WCD_A_CDC_COMP0_DELAY_BUF_CTL (0x2D0) #define MSM8X16_WCD_A_CDC_COMP0_DELAY_BUF_CTL__POR (0x02) #define MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL (0x2E0) #define MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_DEBUG_DESER2_CTL (0x2E4) Loading Loading
sound/soc/codecs/msm8x16-wcd.c +211 −7 Original line number Diff line number Diff line Loading @@ -2066,6 +2066,51 @@ static int msm8x16_wcd_pa_gain_put(struct snd_kcontrol *kcontrol, return 0; } static int msm8x16_wcd_hph_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); if (msm8x16_wcd->hph_mode == NORMAL_MODE) { ucontrol->value.integer.value[0] = 0; } else if (msm8x16_wcd->hph_mode == HD2_MODE) { ucontrol->value.integer.value[0] = 1; } else { dev_err(codec->dev, "%s: ERROR: Default HPH Mode= %d\n", __func__, msm8x16_wcd->hph_mode); } dev_dbg(codec->dev, "%s: msm8x16_wcd->hph_mode = %d\n", __func__, msm8x16_wcd->hph_mode); return 0; } static int msm8x16_wcd_hph_mode_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", __func__, ucontrol->value.integer.value[0]); switch (ucontrol->value.integer.value[0]) { case 0: msm8x16_wcd->hph_mode = NORMAL_MODE; break; case 1: if (get_codec_version(msm8x16_wcd) >= DIANGU) msm8x16_wcd->hph_mode = HD2_MODE; break; default: msm8x16_wcd->hph_mode = NORMAL_MODE; break; } dev_dbg(codec->dev, "%s: msm8x16_wcd->hph_mode_set = %d\n", __func__, msm8x16_wcd->hph_mode); return 0; } static int msm8x16_wcd_boost_option_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) Loading Loading @@ -2362,6 +2407,56 @@ static int msm8x16_wcd_put_iir_band_audio_mixer( return 0; } static int msm8x16_wcd_compander_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); int comp_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->reg; int rx_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->shift; dev_dbg(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n", __func__, comp_idx, rx_idx, msm8x16_wcd->comp_enabled[rx_idx]); ucontrol->value.integer.value[0] = msm8x16_wcd->comp_enabled[rx_idx]; dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", __func__, ucontrol->value.integer.value[0]); return 0; } static int msm8x16_wcd_compander_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); int comp_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->reg; int rx_idx = ((struct soc_multi_mixer_control *) kcontrol->private_value)->shift; int value = ucontrol->value.integer.value[0]; dev_dbg(codec->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", __func__, ucontrol->value.integer.value[0]); if (get_codec_version(msm8x16_wcd) >= DIANGU) { if (!value) msm8x16_wcd->comp_enabled[rx_idx] = 0; else msm8x16_wcd->comp_enabled[rx_idx] = comp_idx; } dev_dbg(codec->dev, "%s: msm8x16_wcd->comp[%d]_enabled[%d] = %d\n", __func__, comp_idx, rx_idx, msm8x16_wcd->comp_enabled[rx_idx]); return 0; } static const char * const msm8x16_wcd_loopback_mode_ctrl_text[] = { "DISABLE", "ENABLE"}; static const struct soc_enum msm8x16_wcd_loopback_mode_ctl_enum[] = { Loading Loading @@ -2398,6 +2493,13 @@ static const struct soc_enum msm8x16_wcd_ext_spk_boost_ctl_enum[] = { SOC_ENUM_SINGLE_EXT(2, msm8x16_wcd_ext_spk_boost_ctrl_text), }; static const char * const msm8x16_wcd_hph_mode_ctrl_text[] = { "NORMAL", "HD2"}; static const struct soc_enum msm8x16_wcd_hph_mode_ctl_enum[] = { SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(msm8x16_wcd_hph_mode_ctrl_text), msm8x16_wcd_hph_mode_ctrl_text), }; /*cut of frequency for high pass filter*/ static const char * const cf_text[] = { "MIN_3DB_4Hz", "MIN_3DB_75Hz", "MIN_3DB_150Hz" Loading @@ -2420,6 +2522,9 @@ static const struct soc_enum cf_rxmix3_enum = static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = { SOC_ENUM_EXT("RX HPH Mode", msm8x16_wcd_hph_mode_ctl_enum[0], msm8x16_wcd_hph_mode_get, msm8x16_wcd_hph_mode_set), SOC_ENUM_EXT("Boost Option", msm8x16_wcd_boost_option_ctl_enum[0], msm8x16_wcd_boost_option_get, msm8x16_wcd_boost_option_set), Loading Loading @@ -2556,6 +2661,11 @@ static const struct snd_kcontrol_new msm8x16_wcd_snd_controls[] = { msm8x16_wcd_get_iir_band_audio_mixer, msm8x16_wcd_put_iir_band_audio_mixer), SOC_SINGLE_EXT("COMP0 RX1", COMPANDER_1, MSM8X16_WCD_RX1, 1, 0, msm8x16_wcd_compander_get, msm8x16_wcd_compander_set), SOC_SINGLE_EXT("COMP0 RX2", COMPANDER_1, MSM8X16_WCD_RX2, 1, 0, msm8x16_wcd_compander_get, msm8x16_wcd_compander_set), }; static int tombak_hph_impedance_get(struct snd_kcontrol *kcontrol, Loading Loading @@ -3707,6 +3817,59 @@ static int msm89xx_wcd_codec_enable_vdd_spkr(struct snd_soc_dapm_widget *w, return 0; } static int msm8x16_wcd_codec_config_compander(struct snd_soc_codec *codec, int interp_n, int event) { struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s: event %d shift %d, enabled %d\n", __func__, event, interp_n, msm8x16_wcd->comp_enabled[interp_n]); /* compander is not enabled */ if (!msm8x16_wcd->comp_enabled[interp_n]) return 0; switch (msm8x16_wcd->comp_enabled[interp_n]) { case COMPANDER_1: if (SND_SOC_DAPM_EVENT_ON(event)) { /* Enable Compander Clock */ snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0x0F, 0x09); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL, 0x01, 0x01); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B1_CTL, 1 << interp_n, 1 << interp_n); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B3_CTL, 0xFF, 0x01); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0xF0, 0x50); /* add sleep for compander to settle */ usleep_range(1000, 1100); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B3_CTL, 0xFF, 0x28); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0xF0, 0xB0); } else if (SND_SOC_DAPM_EVENT_OFF(event)) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B2_CTL, 0x0F, 0x05); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_COMP0_B1_CTL, 1 << interp_n, 0); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL, 0x01, 0x00); } break; default: dev_dbg(codec->dev, "%s: Invalid compander %d\n", __func__, msm8x16_wcd->comp_enabled[interp_n]); break; }; return 0; } static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) Loading @@ -3718,6 +3881,7 @@ static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: msm8x16_wcd_codec_config_compander(codec, w->shift, event); /* apply the digital gain after the interpolator is enabled*/ if ((w->shift) < ARRAY_SIZE(rx_digital_gain_reg)) snd_soc_write(codec, Loading @@ -3727,6 +3891,7 @@ static int msm8x16_wcd_codec_enable_interpolator(struct snd_soc_dapm_widget *w, ); break; case SND_SOC_DAPM_POST_PMD: msm8x16_wcd_codec_config_compander(codec, w->shift, event); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_CLK_RX_RESET_CTL, 1 << w->shift, 1 << w->shift); Loading Loading @@ -3933,6 +4098,14 @@ static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_CNP_EN, 0x08, 0x00); if (HD2_MODE == msm8x16_wcd->hph_mode) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x1C, 0x14); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B4_CTL, 0x18, 0x10); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x80, 0x80); } snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_L_PA_DAC_CTL, 0x02, 0x02); snd_soc_update_bits(codec, Loading @@ -3955,6 +4128,14 @@ static int msm8x16_wcd_hphl_dac_event(struct snd_soc_dapm_widget *w, MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x02, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x01, 0x00); if (HD2_MODE == msm8x16_wcd->hph_mode) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x1C, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B4_CTL, 0x18, 0xFF); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX1_B3_CTL, 0x80, 0x00); } break; } return 0; Loading @@ -3979,8 +4160,6 @@ static int msm8x16_wcd_lo_dac_event(struct snd_soc_dapm_widget *w, MSM8X16_WCD_A_ANALOG_RX_LO_DAC_CTL, 0x08, 0x08); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_LO_DAC_CTL, 0x40, 0x40); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC, 0xff, 0x98); break; case SND_SOC_DAPM_POST_PMU: snd_soc_update_bits(codec, Loading @@ -3989,8 +4168,6 @@ static int msm8x16_wcd_lo_dac_event(struct snd_soc_dapm_widget *w, MSM8X16_WCD_A_ANALOG_RX_LO_DAC_CTL, 0x08, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_LO_EN_CTL, 0x40, 0x40); snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_COM_BIAS_DAC, 0xff, 0x98); break; case SND_SOC_DAPM_POST_PMD: usleep_range(20000, 20100); Loading @@ -4017,11 +4194,20 @@ static int msm8x16_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; struct msm8x16_wcd_priv *msm8x16_wcd = snd_soc_codec_get_drvdata(codec); dev_dbg(codec->dev, "%s %s %d\n", __func__, w->name, event); switch (event) { case SND_SOC_DAPM_PRE_PMU: if (HD2_MODE == msm8x16_wcd->hph_mode) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x1C, 0x14); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B4_CTL, 0x18, 0x10); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x80, 0x80); } snd_soc_update_bits(codec, MSM8X16_WCD_A_ANALOG_RX_HPH_R_PA_DAC_CTL, 0x02, 0x02); snd_soc_update_bits(codec, Loading @@ -4038,6 +4224,14 @@ static int msm8x16_wcd_hphr_dac_event(struct snd_soc_dapm_widget *w, MSM8X16_WCD_A_DIGITAL_CDC_ANA_CLK_CTL, 0x01, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_DIGITAL_CDC_DIG_CLK_CTL, 0x02, 0x00); if (HD2_MODE == msm8x16_wcd->hph_mode) { snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x1C, 0x00); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B4_CTL, 0x18, 0xFF); snd_soc_update_bits(codec, MSM8X16_WCD_A_CDC_RX2_B3_CTL, 0x80, 0x00); } break; } return 0; Loading Loading @@ -4816,15 +5010,15 @@ static const struct snd_soc_dapm_widget msm8x16_wcd_dapm_widgets[] = { SND_SOC_DAPM_MIXER("RX2 MIX1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_MIXER_E("RX1 MIX2", MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 0, 0, NULL, MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, MSM8X16_WCD_RX1, 0, NULL, 0, msm8x16_wcd_codec_enable_interpolator, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER_E("RX2 MIX2", MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 1, 0, NULL, MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, MSM8X16_WCD_RX2, 0, NULL, 0, msm8x16_wcd_codec_enable_interpolator, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_MIXER_E("RX3 MIX1", MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, 2, 0, NULL, MSM8X16_WCD_A_CDC_CLK_RX_B1_CTL, MSM8X16_WCD_RX3, 0, NULL, 0, msm8x16_wcd_codec_enable_interpolator, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), Loading Loading @@ -5185,6 +5379,7 @@ static int msm8x16_wcd_device_down(struct snd_soc_codec *codec) struct msm8916_asoc_mach_data *pdata = NULL; struct msm8x16_wcd_priv *msm8x16_wcd_priv = snd_soc_codec_get_drvdata(codec); int i; pdata = snd_soc_card_get_drvdata(codec->component.card); dev_dbg(codec->dev, "%s: device down!\n", __func__); Loading Loading @@ -5231,6 +5426,10 @@ static int msm8x16_wcd_device_down(struct snd_soc_codec *codec) } } msm8x16_wcd_boost_off(codec); msm8x16_wcd_priv->hph_mode = NORMAL_MODE; for (i = 0; i < MSM8X16_WCD_RX_MAX; i++) msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE; /* 40ms to allow boost to discharge */ msleep(40); /* Disable PA to avoid pop during codec bring up */ Loading Loading @@ -5507,6 +5706,11 @@ static int msm8x16_wcd_codec_probe(struct snd_soc_codec *codec) * it to BOOST_ALWAYS or BOOST_BYPASS based on solution chosen. */ msm8x16_wcd_priv->boost_option = BOOST_SWITCH; msm8x16_wcd_priv->hph_mode = NORMAL_MODE; for (i = 0; i < MSM8X16_WCD_RX_MAX; i++) msm8x16_wcd_priv->comp_enabled[i] = COMPANDER_NONE; msm8x16_wcd_dt_parse_boost_info(codec); msm8x16_wcd_set_boost_v(codec); Loading
sound/soc/codecs/msm8x16-wcd.h +16 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,18 @@ enum codec_versions { UNSUPPORTED, }; /* Support different hph modes */ enum { NORMAL_MODE = 0, HD2_MODE, }; /* Codec supports 1 compander */ enum { COMPANDER_NONE = 0, COMPANDER_1, /* HPHL/R */ COMPANDER_MAX, }; enum wcd_curr_ref { I_h4_UA = 0, Loading Loading @@ -287,6 +299,10 @@ struct msm8x16_wcd_priv { bool clock_active; bool config_mode_active; u16 boost_option; /* mode to select hd2 */ u32 hph_mode; /* compander used for each rx chain */ u32 comp_enabled[MSM8X16_WCD_RX_MAX]; bool spk_boost_set; bool ear_pa_boost_set; bool ext_spk_boost_set; Loading
sound/soc/codecs/msm8x16_wcd_registers.h +21 −1 Original line number Diff line number Diff line /* Copyright (c) 2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -350,6 +350,8 @@ #define MSM8X16_WCD_A_CDC_CLK_SD_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_CLK_WSA_VI_B1_CTL (0x230) #define MSM8X16_WCD_A_CDC_CLK_WSA_VI_B1_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL (0x234) #define MSM8X16_WCD_A_CDC_CLK_RX_B2_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_RX1_B1_CTL (0x240) #define MSM8X16_WCD_A_CDC_RX1_B1_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_RX2_B1_CTL (0x260) Loading Loading @@ -402,6 +404,24 @@ #define MSM8X16_WCD_A_CDC_TOP_GAIN_UPDATE__POR (0x00) #define MSM8X16_WCD_A_CDC_TOP_CTL (0x2A4) #define MSM8X16_WCD_A_CDC_TOP_CTL__POR (0x01) #define MSM8X16_WCD_A_CDC_COMP0_B1_CTL (0x2B0) #define MSM8X16_WCD_A_CDC_COMP0_B1_CTL__POR (0x30) #define MSM8X16_WCD_A_CDC_COMP0_B2_CTL (0x2B4) #define MSM8X16_WCD_A_CDC_COMP0_B2_CTL__POR (0xB5) #define MSM8X16_WCD_A_CDC_COMP0_B3_CTL (0x2B8) #define MSM8X16_WCD_A_CDC_COMP0_B3_CTL__POR (0x28) #define MSM8X16_WCD_A_CDC_COMP0_B4_CTL (0x2BC) #define MSM8X16_WCD_A_CDC_COMP0_B4_CTL__POR (0x37) #define MSM8X16_WCD_A_CDC_COMP0_B5_CTL (0x2C0) #define MSM8X16_WCD_A_CDC_COMP0_B5_CTL__POR (0x7F) #define MSM8X16_WCD_A_CDC_COMP0_B6_CTL (0x2C4) #define MSM8X16_WCD_A_CDC_COMP0_B6_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_COMP0_SHUT_DOWN_STATUS (0x2C8) #define MSM8X16_WCD_A_CDC_COMP0_SHUT_DOWN_STATUS__POR (0x03) #define MSM8X16_WCD_A_CDC_COMP0_FS_CFG (0x2CC) #define MSM8X16_WCD_A_CDC_COMP0_FS_CFG__POR (0x03) #define MSM8X16_WCD_A_CDC_COMP0_DELAY_BUF_CTL (0x2D0) #define MSM8X16_WCD_A_CDC_COMP0_DELAY_BUF_CTL__POR (0x02) #define MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL (0x2E0) #define MSM8X16_WCD_A_CDC_DEBUG_DESER1_CTL__POR (0x00) #define MSM8X16_WCD_A_CDC_DEBUG_DESER2_CTL (0x2E4) Loading