From ab521cd5c867fb190132397d48f27ab1ddefe082 Mon Sep 17 00:00:00 2001 From: Laxminath Kasam Date: Wed, 21 Oct 2020 17:18:37 +0530 Subject: [PATCH] asoc: lpass-cdc: Add support for unified compander On lpass-cdc 2.5 support unified compander. Update macros to align to this feature. Change-Id: Id444116511db48e8f20948ed7fc4af4fca87b8e4 Signed-off-by: Laxminath Kasam --- asoc/codecs/lpass-cdc/Kbuild | 1 + asoc/codecs/lpass-cdc/lpass-cdc-comp.c | 37 ++++++ asoc/codecs/lpass-cdc/lpass-cdc-comp.h | 23 ++++ asoc/codecs/lpass-cdc/lpass-cdc-rx-macro.c | 126 ++++++++++---------- asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c | 98 ++++++++++++++- 5 files changed, 218 insertions(+), 67 deletions(-) create mode 100644 asoc/codecs/lpass-cdc/lpass-cdc-comp.c create mode 100644 asoc/codecs/lpass-cdc/lpass-cdc-comp.h diff --git a/asoc/codecs/lpass-cdc/Kbuild b/asoc/codecs/lpass-cdc/Kbuild index 561ff25967..0c5b783c93 100644 --- a/asoc/codecs/lpass-cdc/Kbuild +++ b/asoc/codecs/lpass-cdc/Kbuild @@ -80,6 +80,7 @@ COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) # for LPASS_CDC Codec ifdef CONFIG_SND_SOC_LPASS_CDC LPASS_CDC_OBJS += lpass-cdc.o + LPASS_CDC_OBJS += lpass-cdc-comp.o LPASS_CDC_OBJS += lpass-cdc-utils.o LPASS_CDC_OBJS += lpass-cdc-regmap.o LPASS_CDC_OBJS += lpass-cdc-tables.o diff --git a/asoc/codecs/lpass-cdc/lpass-cdc-comp.c b/asoc/codecs/lpass-cdc/lpass-cdc-comp.c new file mode 100644 index 0000000000..fb8750e19e --- /dev/null +++ b/asoc/codecs/lpass-cdc/lpass-cdc-comp.c @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ +#include "lpass-cdc-comp.h" + +int lpass_cdc_load_compander_coeff(struct snd_soc_component *component, + u16 lsb_reg, u16 msb_reg, + struct comp_coeff_val *comp_coeff_table, + u16 arr_size) +{ + int i = 0; + + /* Load Compander Coeff */ + for (i = 0; i < arr_size; i++) { + snd_soc_component_write(component, lsb_reg, + comp_coeff_table[i].lsb); + snd_soc_component_write(component, msb_reg, + comp_coeff_table[i].msb); + } + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_load_compander_coeff); + +int lpass_cdc_update_compander_setting(struct snd_soc_component *component, + u16 start_addr, u8 *reg_val) +{ + u16 i = 0; + + for (i = 0; i < COMP_MAX_SETTING; i++) + snd_soc_component_write(component, + start_addr + i * 4, + reg_val[i]); + + return 0; +} +EXPORT_SYMBOL(lpass_cdc_update_compander_setting); diff --git a/asoc/codecs/lpass-cdc/lpass-cdc-comp.h b/asoc/codecs/lpass-cdc/lpass-cdc-comp.h new file mode 100644 index 0000000000..2aa1c6d1f6 --- /dev/null +++ b/asoc/codecs/lpass-cdc/lpass-cdc-comp.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2020, The Linux Foundation. All rights reserved. + */ +#ifndef LPASS_CDC_COMP_H +#define LPASS_CDC_COMP_H + +#include + +#define COMP_MAX_SETTING 12 + +struct comp_coeff_val { + u8 lsb; + u8 msb; +}; + +int lpass_cdc_load_compander_coeff(struct snd_soc_component *component, + u16 lsb_reg, u16 msb_reg, + struct comp_coeff_val *comp_coeff_table, + u16 arr_size); +int lpass_cdc_update_compander_setting(struct snd_soc_component *component, + u16 start_addr, u8 *reg_val); + +#endif diff --git a/asoc/codecs/lpass-cdc/lpass-cdc-rx-macro.c b/asoc/codecs/lpass-cdc/lpass-cdc-rx-macro.c index cc59dfcf9a..deccb6ab57 100644 --- a/asoc/codecs/lpass-cdc/lpass-cdc-rx-macro.c +++ b/asoc/codecs/lpass-cdc/lpass-cdc-rx-macro.c @@ -18,6 +18,7 @@ #include #include "lpass-cdc.h" +#include "lpass-cdc-comp.h" #include "lpass-cdc-registers.h" #include "lpass-cdc-clk-rsc.h" @@ -102,19 +103,14 @@ static const struct wcd_imped_val imped_index[] = { {13, 9}, }; -struct comp_coeff_val { - u8 lsb; - u8 msb; -}; - enum { HPH_ULP, HPH_LOHIFI, HPH_MODE_MAX, }; -static const struct comp_coeff_val - comp_coeff_table [HPH_MODE_MAX][COMP_MAX_COEFF] = { +static struct comp_coeff_val + comp_coeff_table [HPH_MODE_MAX][COMP_MAX_COEFF] = { { {0x40, 0x00}, {0x4C, 0x00}, @@ -171,6 +167,20 @@ static const struct comp_coeff_val }, }; +enum { + RX_MODE_ULP, + RX_MODE_LOHIFI, + RX_MODE_EAR, + RX_MODE_MAX +}; + +static u8 comp_setting_table[RX_MODE_MAX][COMP_MAX_SETTING] = +{ + {0x00, 0x10, 0x06, 0x12, 0x21, 0x30, 0x3F, 0x48, 0xC4, 0xC, 0xC, 0xB0}, /* ULP */ + {0x00, 0x00, 0x06, 0x12, 0x1E, 0x2A, 0x36, 0x3C, 0xC4, 0x0, 0xC, 0xB0}, /* LOHIFI */ + {0x00, 0x10, 0x06, 0x12, 0x1E, 0x2A, 0x30, 0x30, 0xDC, 0xC, 0xC, 0xB0}, /* EAR -36 max_attn */ +}; + struct lpass_cdc_rx_macro_reg_mask_val { u16 reg; u8 mask; @@ -1774,27 +1784,16 @@ static int lpass_cdc_rx_macro_enable_main_path(struct snd_soc_dapm_widget *w, return 0; } -static int lpass_cdc_rx_macro_config_compander(struct snd_soc_component *component, - struct lpass_cdc_rx_macro_priv *rx_priv, - int interp_n, int event) +static void lpass_cdc_rx_macro_droop_setting(struct snd_soc_component *component, + int interp_n, int event) { - int comp = 0; - u16 comp_ctl0_reg = 0, rx_path_cfg0_reg = 0, rx_path_cfg3_reg = 0; - u16 rx0_path_ctl_reg = 0; u8 pcm_rate = 0, val = 0; - - /* AUX does not have compander */ - if (interp_n == INTERP_AUX) - return 0; - - comp = interp_n; - dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", - __func__, event, comp + 1, rx_priv->comp_enabled[comp]); + u16 rx0_path_ctl_reg = 0, rx_path_cfg3_reg = 0; rx_path_cfg3_reg = LPASS_CDC_RX_RX0_RX_PATH_CFG3 + - (comp * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + (interp_n * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); rx0_path_ctl_reg = LPASS_CDC_RX_RX0_RX_PATH_CTL + - (comp * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); + (interp_n * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); pcm_rate = (snd_soc_component_read(component, rx0_path_ctl_reg) & 0x0F); if (pcm_rate < 0x06) @@ -1812,14 +1811,50 @@ static int lpass_cdc_rx_macro_config_compander(struct snd_soc_component *compone if (SND_SOC_DAPM_EVENT_OFF(event)) snd_soc_component_update_bits(component, rx_path_cfg3_reg, 0x03, 0x03); +} + +static int lpass_cdc_rx_macro_config_compander(struct snd_soc_component *component, + struct lpass_cdc_rx_macro_priv *rx_priv, + int interp_n, int event) +{ + int comp = 0; + u16 comp_ctl0_reg = 0, comp_ctl8_reg = 0, rx_path_cfg0_reg = 0; + u16 comp_coeff_lsb_reg = 0, comp_coeff_msb_reg = 0; + u16 mode = rx_priv->hph_pwr_mode; + + comp = interp_n; if (!rx_priv->comp_enabled[comp]) return 0; + if (rx_priv->is_ear_mode_on && interp_n == INTERP_HPHL) + mode = RX_MODE_EAR; + + if (interp_n == INTERP_HPHL) { + comp_coeff_lsb_reg = LPASS_CDC_RX_TOP_HPHL_COMP_WR_LSB; + comp_coeff_msb_reg = LPASS_CDC_RX_TOP_HPHL_COMP_WR_MSB; + } else if (interp_n == INTERP_HPHR) { + comp_coeff_lsb_reg = LPASS_CDC_RX_TOP_HPHR_COMP_WR_LSB; + comp_coeff_msb_reg = LPASS_CDC_RX_TOP_HPHR_COMP_WR_MSB; + } else { + /* compander coefficients are loaded only for hph path */ + return 0; + } comp_ctl0_reg = LPASS_CDC_RX_COMPANDER0_CTL0 + (comp * LPASS_CDC_RX_MACRO_COMP_OFFSET); + comp_ctl8_reg = LPASS_CDC_RX_COMPANDER0_CTL8 + + (comp * LPASS_CDC_RX_MACRO_COMP_OFFSET); rx_path_cfg0_reg = LPASS_CDC_RX_RX0_RX_PATH_CFG0 + (comp * LPASS_CDC_RX_MACRO_RX_PATH_OFFSET); if (SND_SOC_DAPM_EVENT_ON(event)) { + lpass_cdc_load_compander_coeff(component, + comp_coeff_lsb_reg, comp_coeff_msb_reg, + comp_coeff_table[rx_priv->hph_pwr_mode], + COMP_MAX_COEFF); + + lpass_cdc_update_compander_setting(component, + comp_ctl8_reg, + comp_setting_table[mode]); + /* Enable Compander Clock */ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x01, 0x01); @@ -1845,47 +1880,6 @@ static int lpass_cdc_rx_macro_config_compander(struct snd_soc_component *compone return 0; } -static int lpass_cdc_rx_macro_load_compander_coeff(struct snd_soc_component *component, - struct lpass_cdc_rx_macro_priv *rx_priv, - int interp_n, int event) -{ - int comp = 0; - u16 comp_coeff_lsb_reg = 0, comp_coeff_msb_reg = 0; - int i = 0; - int hph_pwr_mode = HPH_LOHIFI; - - if (!rx_priv->comp_enabled[comp]) - return 0; - - if (interp_n == INTERP_HPHL) { - comp_coeff_lsb_reg = LPASS_CDC_RX_TOP_HPHL_COMP_WR_LSB; - comp_coeff_msb_reg = LPASS_CDC_RX_TOP_HPHL_COMP_WR_MSB; - } else if (interp_n == INTERP_HPHR) { - comp_coeff_lsb_reg = LPASS_CDC_RX_TOP_HPHR_COMP_WR_LSB; - comp_coeff_msb_reg = LPASS_CDC_RX_TOP_HPHR_COMP_WR_MSB; - } else { - /* compander coefficients are loaded only for hph path */ - return 0; - } - - comp = interp_n; - hph_pwr_mode = rx_priv->hph_pwr_mode; - dev_dbg(component->dev, "%s: event %d compander %d, enabled %d\n", - __func__, event, comp + 1, rx_priv->comp_enabled[comp]); - - if (SND_SOC_DAPM_EVENT_ON(event)) { - /* Load Compander Coeff */ - for (i = 0; i < COMP_MAX_COEFF; i++) { - snd_soc_component_write(component, comp_coeff_lsb_reg, - comp_coeff_table[hph_pwr_mode][i].lsb); - snd_soc_component_write(component, comp_coeff_msb_reg, - comp_coeff_table[hph_pwr_mode][i].msb); - } - } - - return 0; -} - static void lpass_cdc_rx_macro_enable_softclip_clk(struct snd_soc_component *component, struct lpass_cdc_rx_macro_priv *rx_priv, bool enable) @@ -2670,8 +2664,6 @@ static int lpass_cdc_rx_macro_enable_interp_clk(struct snd_soc_component *compon 0x01, 0x01); snd_soc_component_update_bits(component, rx_cfg2_reg, 0x03, 0x03); - lpass_cdc_rx_macro_load_compander_coeff(component, rx_priv, - interp_idx, event); lpass_cdc_rx_macro_idle_detect_control(component, rx_priv, interp_idx, event); if (rx_priv->hph_hd2_mode) @@ -2679,6 +2671,8 @@ static int lpass_cdc_rx_macro_enable_interp_clk(struct snd_soc_component *compon component, interp_idx, event); lpass_cdc_rx_macro_hphdelay_lutbypass(component, rx_priv, interp_idx, event); + lpass_cdc_rx_macro_droop_setting(component, + interp_idx, event); lpass_cdc_rx_macro_config_compander(component, rx_priv, interp_idx, event); if (interp_idx == INTERP_AUX) { diff --git a/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c b/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c index 509c2df343..b64a8e8e6e 100644 --- a/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c +++ b/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c @@ -16,6 +16,7 @@ #include #include "lpass-cdc.h" +#include "lpass-cdc-comp.h" #include "lpass-cdc-registers.h" #include "lpass-cdc-wsa-macro.h" #include "lpass-cdc-clk-rsc.h" @@ -107,6 +108,32 @@ enum { INTn_2_INP_SEL_RX3, }; +enum { + WSA_MODE_21DB, + WSA_MODE_19P5DB, + WSA_MODE_18DB, + WSA_MODE_16P5DB, + WSA_MODE_15DB, + WSA_MODE_13P5DB, + WSA_MODE_12DB, + WSA_MODE_10P5DB, + WSA_MODE_9DB, + WSA_MODE_MAX +}; + +static u8 comp_setting_table[WSA_MODE_MAX][COMP_MAX_SETTING] = +{ + {0x00, 0x10, 0x06, 0x18, 0x24, 0x2A, 0x2A, 0x2A, 0x00, 0x2A, 0x2A, 0xB0}, /* WSA_MODE_21DB */ + {0x00, 0x10, 0x06, 0x18, 0x24, 0x2A, 0x2A, 0x2A, 0xFD, 0x2A, 0x2A, 0xB0}, /* WSA_MODE_19PDB -1.5DB*/ + {0x00, 0x10, 0x06, 0x12, 0x1E, 0x24, 0x24, 0x24, 0xFA, 0x24, 0x2A, 0xB0}, /* WSA_MODE_18DB -3DB*/ + {0x00, 0x10, 0x06, 0x0C, 0x18, 0x21, 0x21, 0x21, 0xFA, 0x21, 0x2A, 0xB0}, /* WSA_MODE_16P5DB -3DB*/ + {0x00, 0x10, 0x06, 0x0C, 0x18, 0x21, 0x21, 0x21, 0xFA, 0x21, 0x2A, 0xB0}, /* WSA_MODE_15DB -3DB -->TODO: NEED UPDATE ENTRIES */ + {0x00, 0x10, 0x06, 0x12, 0x1B, 0x1B, 0x1B, 0x1B, 0xFA, 0x1B, 0x2A, 0xB0}, /* WSA_MODE_13P5DB -3DB */ + {0x00, 0x10, 0x06, 0x12, 0x18, 0x18, 0x18, 0x18, 0xFA, 0x18, 0x2A, 0xB0}, /* WSA_MODE_12DB -3DB */ + {0x00, 0x10, 0x06, 0x12, 0x18, 0x18, 0x18, 0x18, 0xFA, 0x18, 0x2A, 0xB0}, /* WSA_MODE_10P5DB -3DB --> NEED Update entries */ + {0x00, 0x10, 0x06, 0x12, 0x18, 0x18, 0x18, 0x18, 0xFA, 0x18, 0x2A, 0xB0}, /* WSA_MODE_9DB -3DB --> NEED Update entries */ +}; + struct interp_sample_rate { int sample_rate; int rate_val; @@ -210,6 +237,7 @@ enum { struct lpass_cdc_wsa_macro_priv { struct device *dev; int comp_enabled[LPASS_CDC_WSA_MACRO_COMP_MAX]; + int comp_mode[LPASS_CDC_WSA_MACRO_COMP_MAX]; int ec_hq[LPASS_CDC_WSA_MACRO_RX1 + 1]; u16 prim_int_users[LPASS_CDC_WSA_MACRO_RX1 + 1]; u16 wsa_mclk_users; @@ -284,6 +312,11 @@ static const char * const lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_text[] = { "OFF", "ON" }; +static const char * const lpass_cdc_wsa_macro_comp_mode_text[] = { + "G_21_DB", "G_19P5_DB", "G_18_DB", "G_16P5_DB", "G_15_DB", + "G_13P5_DB", "G_12_DB", "G_10P5_DB", "G_9_DB" +}; + static const struct snd_kcontrol_new wsa_int0_vbat_mix_switch[] = { SOC_DAPM_SINGLE("WSA RX0 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) }; @@ -298,6 +331,8 @@ static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa_macro_spkr_boost_stage_enum, lpass_cdc_wsa_macro_speaker_boost_stage_text); static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_enum, lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_text); +static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa_macro_comp_mode_enum, + lpass_cdc_wsa_macro_comp_mode_text); /* RX INT0 */ static const struct soc_enum rx0_prim_inp0_chain_enum = @@ -1312,9 +1347,10 @@ static int lpass_cdc_wsa_macro_enable_mix_path(struct snd_soc_dapm_widget *w, static int lpass_cdc_wsa_macro_config_compander(struct snd_soc_component *component, int comp, int event) { - u16 comp_ctl0_reg, rx_path_cfg0_reg; + u16 comp_ctl0_reg, comp_ctl8_reg, rx_path_cfg0_reg; struct device *wsa_dev = NULL; struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u16 mode = 0; if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) return -EINVAL; @@ -1325,12 +1361,18 @@ static int lpass_cdc_wsa_macro_config_compander(struct snd_soc_component *compon if (!wsa_priv->comp_enabled[comp]) return 0; + mode = wsa_priv->comp_mode[comp]; comp_ctl0_reg = LPASS_CDC_WSA_COMPANDER0_CTL0 + (comp * LPASS_CDC_WSA_MACRO_RX_COMP_OFFSET); + comp_ctl8_reg = LPASS_CDC_WSA_COMPANDER0_CTL8 + + (comp * LPASS_CDC_WSA_MACRO_RX_COMP_OFFSET); rx_path_cfg0_reg = LPASS_CDC_WSA_RX0_RX_PATH_CFG0 + (comp * LPASS_CDC_WSA_MACRO_RX_PATH_OFFSET); if (SND_SOC_DAPM_EVENT_ON(event)) { + lpass_cdc_update_compander_setting(component, + comp_ctl8_reg, + comp_setting_table[mode]); /* Enable Compander Clock */ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x01, 0x01); @@ -2134,6 +2176,54 @@ static int lpass_cdc_wsa_macro_ear_spkr_pa_gain_put(struct snd_kcontrol *kcontro return 0; } +static int lpass_cdc_wsa_macro_comp_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u16 idx = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (strnstr(kcontrol->id.name, "RX0", sizeof("WSA_RX0"))) + idx = LPASS_CDC_WSA_MACRO_COMP1; + if (strnstr(kcontrol->id.name, "RX1", sizeof("WSA_RX1"))) + idx = LPASS_CDC_WSA_MACRO_COMP2; + ucontrol->value.integer.value[0] = wsa_priv->comp_mode[idx]; + + dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", + __func__, ucontrol->value.integer.value[0]); + + return 0; +} + +static int lpass_cdc_wsa_macro_comp_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa_dev = NULL; + struct lpass_cdc_wsa_macro_priv *wsa_priv = NULL; + u16 idx = 0; + + if (!lpass_cdc_wsa_macro_get_data(component, &wsa_dev, &wsa_priv, __func__)) + return -EINVAL; + + if (strnstr(kcontrol->id.name, "RX0", sizeof("WSA_RX0"))) + idx = LPASS_CDC_WSA_MACRO_COMP1; + if (strnstr(kcontrol->id.name, "RX1", sizeof("WSA_RX1"))) + idx = LPASS_CDC_WSA_MACRO_COMP2; + wsa_priv->comp_mode[idx] = ucontrol->value.integer.value[0]; + + dev_dbg(component->dev, "%s: comp_mode = %d\n", __func__, + wsa_priv->comp_mode[idx]); + + return 0; +} + static int lpass_cdc_wsa_macro_spkr_left_boost_stage_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -2375,6 +2465,12 @@ static const struct snd_kcontrol_new lpass_cdc_wsa_macro_snd_controls[] = { SOC_ENUM_EXT("GSM mode Enable", lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_enum, lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_func_get, lpass_cdc_wsa_macro_vbat_bcl_gsm_mode_func_put), + SOC_ENUM_EXT("WSA_RX0 comp_mode", lpass_cdc_wsa_macro_comp_mode_enum, + lpass_cdc_wsa_macro_comp_mode_get, + lpass_cdc_wsa_macro_comp_mode_put), + SOC_ENUM_EXT("WSA_RX1 comp_mode", lpass_cdc_wsa_macro_comp_mode_enum, + lpass_cdc_wsa_macro_comp_mode_get, + lpass_cdc_wsa_macro_comp_mode_put), SOC_SINGLE_EXT("WSA_Softclip0 Enable", SND_SOC_NOPM, LPASS_CDC_WSA_MACRO_SOFTCLIP0, 1, 0, lpass_cdc_wsa_macro_soft_clip_enable_get,