diff --git a/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c b/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c index adab1fd4b5..683e9ee473 100644 --- a/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c +++ b/asoc/codecs/lpass-cdc/lpass-cdc-wsa-macro.c @@ -1700,14 +1700,14 @@ static void lpass_cdc_macro_idle_detect_control(struct snd_soc_component *compon if (reg && SND_SOC_DAPM_EVENT_ON(event)) { snd_soc_component_update_bits(component, reg, mask, val); - dev_dbg(component->dev, "%s: Idle detect clks ON \n", __func__); + dev_dbg(component->dev, "%s: Idle detect clks ON\n", __func__); } if (reg && SND_SOC_DAPM_EVENT_OFF(event)) { snd_soc_component_update_bits(component, reg, mask, 0x00); snd_soc_component_write(component, LPASS_CDC_WSA_IDLE_DETECT_CFG3, 0x0); - dev_dbg(component->dev, "%s: Idle detect clks OFF \n", __func__); + dev_dbg(component->dev, "%s: Idle detect clks OFF\n", __func__); } } @@ -1786,7 +1786,7 @@ static int lpass_cdc_wsa_macro_enable_interpolator(struct snd_soc_dapm_widget *w break; case SND_SOC_DAPM_POST_PMD: snd_soc_component_update_bits(component, - LPASS_CDC_WSA_RX0_RX_PATH_CFG1, 0x08, 0x08); + LPASS_CDC_WSA_RX0_RX_PATH_CFG1, 0x08, 0x08); lpass_cdc_wsa_macro_config_compander(component, w->shift, event); lpass_cdc_macro_idle_detect_control(component, wsa_priv, w->shift, event); @@ -3752,7 +3752,7 @@ static int lpass_cdc_wsa_macro_probe(struct platform_device *pdev) __func__, "qcom,noise-gate-mode"); wsa_priv->noise_gate_mode = IDLE_DETECT; } else { - if (IDLE_DETECT <= noise_gate_mode && noise_gate_mode <= NG3) + if (noise_gate_mode >= IDLE_DETECT && noise_gate_mode <= NG3) wsa_priv->noise_gate_mode = noise_gate_mode; else wsa_priv->noise_gate_mode = IDLE_DETECT; diff --git a/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.c b/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.c index 811ae2769d..d1afd78815 100644 --- a/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.c +++ b/asoc/codecs/lpass-cdc/lpass-cdc-wsa2-macro.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,9 @@ enum { LPASS_CDC_WSA2_MACRO_RX_MIX1, LPASS_CDC_WSA2_MACRO_RX4, LPASS_CDC_WSA2_MACRO_RX5, + LPASS_CDC_WSA2_MACRO_RX6, + LPASS_CDC_WSA2_MACRO_RX7, + LPASS_CDC_WSA2_MACRO_RX8, LPASS_CDC_WSA2_MACRO_RX_MAX, }; @@ -106,6 +110,9 @@ enum { INTn_1_INP_SEL_RX3, INTn_1_INP_SEL_RX4, INTn_1_INP_SEL_RX5, + INTn_1_INP_SEL_RX6, + INTn_1_INP_SEL_RX7, + INTn_1_INP_SEL_RX8, INTn_1_INP_SEL_DEC0, INTn_1_INP_SEL_DEC1, }; @@ -118,23 +125,19 @@ enum { INTn_2_INP_SEL_RX3, INTn_2_INP_SEL_RX4, INTn_2_INP_SEL_RX5, + INTn_2_INP_SEL_RX6, + INTn_2_INP_SEL_RX7, + INTn_2_INP_SEL_RX8, }; enum { - WSA2_MODE_21DB, - WSA2_MODE_19P5DB, - WSA2_MODE_18DB, - WSA2_MODE_16P5DB, - WSA2_MODE_15DB, - WSA2_MODE_13P5DB, - WSA2_MODE_12DB, - WSA2_MODE_10P5DB, - WSA2_MODE_9DB, - WSA2_MODE_MAX + IDLE_DETECT, + NG1, + NG2, + NG3, }; -static struct lpass_cdc_comp_setting comp_setting_table[WSA2_MODE_MAX] = -{ +static struct lpass_cdc_comp_setting comp_setting_table[G_MAX_DB] = { {42, 0, 42}, {39, 0, 42}, {36, 0, 42}, @@ -189,6 +192,8 @@ static int lpass_cdc_wsa2_macro_get_channel_map(struct snd_soc_dai *dai, unsigned int *tx_num, unsigned int *tx_slot, unsigned int *rx_num, unsigned int *rx_slot); static int lpass_cdc_wsa2_macro_mute_stream(struct snd_soc_dai *dai, int mute, int stream); + +#define LPASS_CDC_WSA2_MACRO_VTH_TO_REG(vth) ((vth) == 0 ? 255 : (vth)) /* Hold instance to soundwire platform device */ struct lpass_cdc_wsa2_macro_swr_ctrl_data { struct platform_device *wsa2_swr_pdev; @@ -229,6 +234,7 @@ enum { LPASS_CDC_WSA2_MACRO_MAX_DAIS, }; + #define LPASS_CDC_WSA2_MACRO_CHILD_DEVICES_MAX 3 /* @@ -252,6 +258,9 @@ enum { * @active_ch_cnt: channel count of all AIF DAIs * @rx_port_value: mixer ctl value of WSA2 RX MUXes * @wsa2_io_base: Base address of WSA2 macro addr space + * @wsa2_sys_gain System gain value, see wsa2 driver + * @wsa2_bat_cfg Battery Configuration value, see wsa2 driver + * @wsa2_rload Resistor load value for WSA2 Speaker, see wsa2 driver */ struct lpass_cdc_wsa2_macro_priv { struct device *dev; @@ -273,14 +282,17 @@ struct lpass_cdc_wsa2_macro_priv { struct snd_soc_component *component; int rx_0_count; int rx_1_count; - int wsa_spkrrecv; unsigned long active_ch_mask[LPASS_CDC_WSA2_MACRO_MAX_DAIS]; unsigned long active_ch_cnt[LPASS_CDC_WSA2_MACRO_MAX_DAIS]; + u16 bit_width[LPASS_CDC_WSA2_MACRO_MAX_DAIS]; int rx_port_value[LPASS_CDC_WSA2_MACRO_RX_MAX]; char __iomem *wsa2_io_base; struct platform_device *pdev_child_devices [LPASS_CDC_WSA2_MACRO_CHILD_DEVICES_MAX]; int child_count; + int wsa2_spkrrecv; + int spkr_gain_offset; + int spkr_mode; int is_softclip_on[LPASS_CDC_WSA2_MACRO_SOFTCLIP_MAX]; int softclip_clk_users[LPASS_CDC_WSA2_MACRO_SOFTCLIP_MAX]; char __iomem *mclk_mode_muxsel; @@ -293,17 +305,24 @@ struct lpass_cdc_wsa2_macro_priv { uint32_t thermal_cur_state; uint32_t thermal_max_state; struct work_struct lpass_cdc_wsa2_macro_cooling_work; + bool pbr_enable; + u32 wsa2_sys_gain[2 * (LPASS_CDC_WSA2_MACRO_RX1 + 1)]; + u32 wsa2_bat_cfg[LPASS_CDC_WSA2_MACRO_RX1 + 1]; + u32 wsa2_rload[LPASS_CDC_WSA2_MACRO_RX1 + 1]; + u8 idle_detect_en; + int noise_gate_mode; }; static struct snd_soc_dai_driver lpass_cdc_wsa2_macro_dai[]; static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0); static const char *const rx_text[] = { - "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "DEC0", "DEC1" + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", + "RX5", "RX6", "RX7", "RX8", "DEC0", "DEC1" }; static const char *const rx_mix_text[] = { - "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", + "ZERO", "RX0", "RX1", "RX_MIX0", "RX_MIX1", "RX4", "RX5", "RX6", "RX7", "RX8" }; static const char *const rx_mix_ec_text[] = { @@ -322,10 +341,6 @@ static const char * const lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_text[] = { "OFF", "ON" }; -static const char *const lpass_cdc_wsa2_macro_ear_spkrrecv_text[] = { - "OFF", "ON" -}; - static const char * const lpass_cdc_wsa2_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" @@ -339,8 +354,7 @@ static const struct snd_kcontrol_new wsa2_int1_vbat_mix_switch[] = { SOC_DAPM_SINGLE("WSA2 RX1 VBAT Enable", SND_SOC_NOPM, 0, 1, 0) }; -static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa2_macro_ear_spkrrecv_enum, - lpass_cdc_wsa2_macro_ear_spkrrecv_text); + static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_enum, lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_text); static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa2_macro_comp_mode_enum, @@ -349,19 +363,19 @@ static SOC_ENUM_SINGLE_EXT_DECL(lpass_cdc_wsa2_macro_comp_mode_enum, /* RX INT0 */ static const struct soc_enum rx0_prim_inp0_chain_enum = SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG0, - 0, 9, rx_text); + 0, 12, rx_text); static const struct soc_enum rx0_prim_inp1_chain_enum = SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG0, - 3, 9, rx_text); + 3, 12, rx_text); static const struct soc_enum rx0_prim_inp2_chain_enum = SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG1, - 3, 9, rx_text); + 3, 12, rx_text); static const struct soc_enum rx0_mix_chain_enum = SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT0_CFG1, - 0, 7, rx_mix_text); + 0, 10, rx_mix_text); static const struct soc_enum rx0_sidetone_mix_enum = SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, 2, rx_sidetone_mix_text); @@ -384,19 +398,19 @@ static const struct snd_kcontrol_new rx0_sidetone_mix_mux = /* RX INT1 */ static const struct soc_enum rx1_prim_inp0_chain_enum = SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG0, - 0, 9, rx_text); + 0, 12, rx_text); static const struct soc_enum rx1_prim_inp1_chain_enum = SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG0, - 3, 9, rx_text); + 3, 12, rx_text); static const struct soc_enum rx1_prim_inp2_chain_enum = SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG1, - 3, 9, rx_text); + 3, 12, rx_text); static const struct soc_enum rx1_mix_chain_enum = SOC_ENUM_SINGLE(LPASS_CDC_WSA2_RX_INP_MUX_RX_INT1_CFG1, - 0, 7, rx_mix_text); + 0, 10, rx_mix_text); static const struct snd_kcontrol_new rx1_prim_inp0_mux = SOC_DAPM_ENUM("WSA2_RX1 INP0 Mux", rx1_prim_inp0_chain_enum); @@ -730,10 +744,37 @@ static int lpass_cdc_wsa2_macro_hw_params(struct snd_pcm_substream *substream, __func__, params_rate(params)); return ret; } + switch (params_width(params)) { + case 16: + wsa2_priv->bit_width[dai->id] = 16; + break; + case 24: + wsa2_priv->bit_width[dai->id] = 24; + break; + case 32: + wsa2_priv->bit_width[dai->id] = 32; + break; + default: + dev_err_ratelimited(component->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + } break; case SNDRV_PCM_STREAM_CAPTURE: if (dai->id == LPASS_CDC_WSA2_MACRO_AIF_VI) wsa2_priv->pcm_rate_vi = params_rate(params); + switch (params_width(params)) { + case 16: + wsa2_priv->bit_width[dai->id] = 16; + break; + case 24: + wsa2_priv->bit_width[dai->id] = 24; + break; + default: + dev_err_ratelimited(component->dev, "%s: Invalid format 0x%x\n", + __func__, params_width(params)); + return -EINVAL; + } default: break; } @@ -1019,16 +1060,16 @@ static int lpass_cdc_wsa2_macro_enable_vi_feedback(struct snd_soc_dapm_widget *w return -EINVAL; switch (wsa2_priv->pcm_rate_vi) { - case 48000: - val = 0x04; - break; - case 24000: - val = 0x02; - break; - case 8000: - default: - val = 0x00; - break; + case 48000: + val = 0x04; + break; + case 24000: + val = 0x02; + break; + case 8000: + default: + val = 0x00; + break; } switch (event) { @@ -1256,7 +1297,9 @@ static int lpass_cdc_wsa2_macro_config_compander(struct snd_soc_component *compo u16 comp_ctl0_reg, comp_ctl8_reg, rx_path_cfg0_reg; struct device *wsa2_dev = NULL; struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + struct lpass_cdc_comp_setting *comp_settings = NULL; u16 mode = 0; + int sys_gain, bat_cfg, sys_gain_int, upper_gain, lower_gain; if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) return -EINVAL; @@ -1274,11 +1317,49 @@ static int lpass_cdc_wsa2_macro_config_compander(struct snd_soc_component *compo (comp * LPASS_CDC_WSA2_MACRO_RX_COMP_OFFSET); rx_path_cfg0_reg = LPASS_CDC_WSA2_RX0_RX_PATH_CFG0 + (comp * LPASS_CDC_WSA2_MACRO_RX_PATH_OFFSET); + comp_settings = &comp_setting_table[mode]; + + /* If System has battery configuration */ + if (wsa2_priv->wsa2_bat_cfg[comp]) { + sys_gain = wsa2_priv->wsa2_sys_gain[comp * 2 + wsa2_priv->wsa2_spkrrecv]; + bat_cfg = wsa2_priv->wsa2_bat_cfg[comp]; + /* Convert enum to value and + * multiply all values by 10 to avoid float + */ + sys_gain_int = -15 * sys_gain + 210; + switch (bat_cfg) { + case CONFIG_1S: + case EXT_1S: + if (sys_gain > G_13P5_DB) { + upper_gain = sys_gain_int + 60; + lower_gain = 0; + } else { + upper_gain = 210; + lower_gain = 0; + } + break; + case CONFIG_3S: + case EXT_3S: + upper_gain = sys_gain_int; + lower_gain = 75; + case EXT_ABOVE_3S: + upper_gain = sys_gain_int; + lower_gain = 120; + break; + default: + upper_gain = sys_gain_int; + lower_gain = 0; + break; + } + /* Truncate after calculation */ + comp_settings->lower_gain_int = (lower_gain * 2) / 10; + comp_settings->upper_gain_int = (upper_gain * 2) / 10; + } if (SND_SOC_DAPM_EVENT_ON(event)) { lpass_cdc_update_compander_setting(component, comp_ctl8_reg, - &comp_setting_table[mode]); + comp_settings); /* Enable Compander Clock */ snd_soc_component_update_bits(component, comp_ctl0_reg, 0x01, 0x01); @@ -1386,6 +1467,63 @@ static int lpass_cdc_wsa2_macro_config_softclip(struct snd_soc_component *compon return 0; } +static int lpass_cdc_was_macro_config_pbr(struct snd_soc_component *component, + int path, int event) +{ + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + u16 reg1 = 0, reg2 = 0, reg3 = 0; + int softclip_path = 0; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + if (path == LPASS_CDC_WSA2_MACRO_COMP1) { + reg1 = LPASS_CDC_WSA2_COMPANDER0_CTL0; + reg2 = LPASS_CDC_WSA2_RX0_RX_PATH_CFG3; + reg3 = LPASS_CDC_WSA2_RX0_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA2_MACRO_SOFTCLIP0; + } else if (path == LPASS_CDC_WSA2_MACRO_COMP2) { + reg1 = LPASS_CDC_WSA2_COMPANDER1_CTL0; + reg2 = LPASS_CDC_WSA2_RX1_RX_PATH_CFG3; + reg3 = LPASS_CDC_WSA2_RX1_RX_PATH_CFG1; + softclip_path = LPASS_CDC_WSA2_MACRO_SOFTCLIP1; + } + if (!wsa2_priv->pbr_enable || wsa2_priv->wsa2_bat_cfg[path] >= EXT_1S || + wsa2_priv->wsa2_sys_gain[path * 2] > G_12_DB || + wsa2_priv->wsa2_spkrrecv || !reg1 || !reg2 || !reg3) + return 0; + + if (SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, + reg1, 0x08, 0x08); + snd_soc_component_update_bits(component, + reg2, 0x40, 0x40); + snd_soc_component_update_bits(component, + reg3, 0x80, 0x80); + lpass_cdc_wsa2_macro_enable_softclip_clk(component, wsa2_priv, + softclip_path, true); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_PBR_PATH_CTL, + 0x01, 0x01); + } + + if (SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_PBR_PATH_CTL, + 0x01, 0x00); + lpass_cdc_wsa2_macro_enable_softclip_clk(component, wsa2_priv, + softclip_path, false); + snd_soc_component_update_bits(component, + reg1, 0x08, 0x00); + snd_soc_component_update_bits(component, + reg2, 0x40, 0x00); + snd_soc_component_update_bits(component, + reg3, 0x80, 0x00); + } + return 0; +} + static bool lpass_cdc_wsa2_macro_adie_lb(struct snd_soc_component *component, int interp_idx) { @@ -1524,6 +1662,57 @@ static int lpass_cdc_wsa2_macro_enable_prim_interpolator( return 0; } +static void lpass_cdc_macro_idle_detect_control(struct snd_soc_component *component, + struct lpass_cdc_wsa2_macro_priv *wsa2_priv, + int interp, int event) +{ + int reg = 0, mask = 0, val = 0, source_reg = 0; + u16 mode = 0; + + dev_dbg(component->dev, "%s: Idle_detect_en value: %d\n", __func__, + wsa2_priv->idle_detect_en); + + if (!wsa2_priv->idle_detect_en) + return; + + if (interp == LPASS_CDC_WSA2_MACRO_COMP1) { + source_reg = LPASS_CDC_WSA2_RX0_RX_PATH_CFG3; + reg = LPASS_CDC_WSA2_IDLE_DETECT_PATH_CTL; + mask = 0x01; + val = 0x01; + } + if (interp == LPASS_CDC_WSA2_MACRO_COMP2) { + source_reg = LPASS_CDC_WSA2_RX1_RX_PATH_CFG3; + reg = LPASS_CDC_WSA2_IDLE_DETECT_PATH_CTL; + mask = 0x02; + val = 0x02; + } + + mode = wsa2_priv->comp_mode[interp]; + + if ((wsa2_priv->noise_gate_mode == NG2 && mode >= G_13P5_DB) || + wsa2_priv->noise_gate_mode == IDLE_DETECT || !wsa2_priv->pbr_enable || + wsa2_priv->wsa2_spkrrecv) { + snd_soc_component_update_bits(component, source_reg, 0x80, 0x00); + dev_dbg(component->dev, "%s: Idle detect source: Legacy\n", __func__); + } else { + snd_soc_component_update_bits(component, source_reg, 0x80, 0x80); + dev_dbg(component->dev, "%s: Idle detect source: PRE-LA\n", __func__); + } + + if (reg && SND_SOC_DAPM_EVENT_ON(event)) { + snd_soc_component_update_bits(component, reg, mask, val); + dev_dbg(component->dev, "%s: Idle detect clks ON\n", __func__); + } + + if (reg && SND_SOC_DAPM_EVENT_OFF(event)) { + snd_soc_component_update_bits(component, reg, mask, 0x00); + snd_soc_component_write(component, + LPASS_CDC_WSA2_IDLE_DETECT_CFG3, 0x0); + dev_dbg(component->dev, "%s: Idle detect clks OFF\n", __func__); + } +} + static int lpass_cdc_wsa2_macro_enable_interpolator(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -1588,8 +1777,11 @@ static int lpass_cdc_wsa2_macro_enable_interpolator(struct snd_soc_dapm_widget * } lpass_cdc_wsa2_macro_config_compander(component, w->shift, event); + lpass_cdc_macro_idle_detect_control(component, wsa2_priv, + w->shift, event); lpass_cdc_wsa2_macro_config_softclip(component, w->shift, event); - if(wsa2_priv->wsa_spkrrecv) + lpass_cdc_was_macro_config_pbr(component, w->shift, event); + if (wsa2_priv->wsa2_spkrrecv) snd_soc_component_update_bits(component, LPASS_CDC_WSA2_RX0_RX_PATH_CFG1, 0x08, 0x00); @@ -1598,7 +1790,10 @@ static int lpass_cdc_wsa2_macro_enable_interpolator(struct snd_soc_dapm_widget * snd_soc_component_update_bits(component, LPASS_CDC_WSA2_RX0_RX_PATH_CFG1, 0x08, 0x08); lpass_cdc_wsa2_macro_config_compander(component, w->shift, event); + lpass_cdc_macro_idle_detect_control(component, wsa2_priv, + w->shift, event); lpass_cdc_wsa2_macro_config_softclip(component, w->shift, event); + lpass_cdc_was_macro_config_pbr(component, w->shift, event); lpass_cdc_wsa2_macro_enable_prim_interpolator(component, reg, event); break; } @@ -1733,24 +1928,24 @@ static int lpass_cdc_wsa2_macro_enable_vbat(struct snd_soc_dapm_widget *w, snd_soc_component_update_bits(component, LPASS_CDC_WSA2_VBAT_BCL_VBAT_BCL_GAIN_UPD9, 0xFF, 0x00); - /* Enable CB decode block clock */ - snd_soc_component_update_bits(component, - LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x01); - /* Enable BCL path */ - snd_soc_component_update_bits(component, - LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x01); - /* Request for BCL data */ - snd_soc_component_update_bits(component, - LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x01); + /* Enable CB decode block clock */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x01); + /* Enable BCL path */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x01); + /* Request for BCL data */ + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x01); break; case SND_SOC_DAPM_POST_PMD: - snd_soc_component_update_bits(component, - LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x00); - snd_soc_component_update_bits(component, - LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x00); - snd_soc_component_update_bits(component, - LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL3, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL2, 0x01, 0x00); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_CB_DECODE_CB_DECODE_CTL1, 0x01, 0x00); snd_soc_component_update_bits(component, vbat_path_cfg, 0x80, 0x00); snd_soc_component_update_bits(component, @@ -2056,7 +2251,7 @@ static int lpass_cdc_wsa2_macro_ear_spkrrecv_get(struct snd_kcontrol *kcontrol, if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) return -EINVAL; - ucontrol->value.integer.value[0] = wsa2_priv->wsa_spkrrecv; + ucontrol->value.integer.value[0] = wsa2_priv->wsa2_spkrrecv; dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n", __func__, ucontrol->value.integer.value[0]); @@ -2065,21 +2260,54 @@ static int lpass_cdc_wsa2_macro_ear_spkrrecv_get(struct snd_kcontrol *kcontrol, } static int lpass_cdc_wsa2_macro_ear_spkrrecv_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = - snd_soc_kcontrol_component(kcontrol); - struct device *wsa2_dev = NULL; - struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; - if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) - return -EINVAL; - wsa2_priv->wsa_spkrrecv = ucontrol->value.integer.value[0]; + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; - dev_dbg(component->dev, "%s:spkrrecv status = %d\n", - __func__, wsa2_priv->wsa_spkrrecv); + wsa2_priv->wsa2_spkrrecv = ucontrol->value.integer.value[0]; - return 0; + dev_dbg(component->dev, "%s:spkrrecv status = %d\n", + __func__, wsa2_priv->wsa2_spkrrecv); + + return 0; +} + +static int lpass_cdc_wsa2_macro_idle_detect_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + struct device *wsa2_dev = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa2_priv->idle_detect_en; + + return 0; +} + +static int lpass_cdc_wsa2_macro_idle_detect_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + struct device *wsa2_dev = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv->idle_detect_en = ucontrol->value.integer.value[0]; + + return 0; } static int lpass_cdc_wsa2_macro_comp_mode_get(struct snd_kcontrol *kcontrol, @@ -2292,10 +2520,41 @@ static int lpass_cdc_wsa2_macro_soft_clip_enable_put(struct snd_kcontrol *kcontr return 0; } +static int lpass_cdc_wsa2_macro_pbr_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + ucontrol->value.integer.value[0] = wsa2_priv->pbr_enable; + return 0; +} + +static int lpass_cdc_wsa2_macro_pbr_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct snd_soc_component *component = + snd_soc_kcontrol_component(kcontrol); + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return -EINVAL; + + wsa2_priv->pbr_enable = ucontrol->value.integer.value[0]; + return 0; + +} + + static const struct snd_kcontrol_new lpass_cdc_wsa2_macro_snd_controls[] = { - SOC_ENUM_EXT("WSA2 SPKRRECV", lpass_cdc_wsa2_macro_ear_spkrrecv_enum, - lpass_cdc_wsa2_macro_ear_spkrrecv_get, - lpass_cdc_wsa2_macro_ear_spkrrecv_put), SOC_ENUM_EXT("WSA2_GSM mode Enable", lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_enum, lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_func_get, lpass_cdc_wsa2_macro_vbat_bcl_gsm_mode_func_put), @@ -2305,6 +2564,12 @@ static const struct snd_kcontrol_new lpass_cdc_wsa2_macro_snd_controls[] = { SOC_ENUM_EXT("WSA2_RX1 comp_mode", lpass_cdc_wsa2_macro_comp_mode_enum, lpass_cdc_wsa2_macro_comp_mode_get, lpass_cdc_wsa2_macro_comp_mode_put), + SOC_SINGLE_EXT("WSA2 SPKRRECV", SND_SOC_NOPM, 0, 1, 0, + lpass_cdc_wsa2_macro_ear_spkrrecv_get, + lpass_cdc_wsa2_macro_ear_spkrrecv_put), + SOC_SINGLE_EXT("WSA2 Idle Detect", SND_SOC_NOPM, 0, 1, + 0, lpass_cdc_wsa2_macro_idle_detect_get, + lpass_cdc_wsa2_macro_idle_detect_put), SOC_SINGLE_EXT("WSA2_Softclip0 Enable", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_SOFTCLIP0, 1, 0, lpass_cdc_wsa2_macro_soft_clip_enable_get, @@ -2339,6 +2604,9 @@ static const struct snd_kcontrol_new lpass_cdc_wsa2_macro_snd_controls[] = { 1, 0, lpass_cdc_wsa2_macro_get_ec_hq, lpass_cdc_wsa2_macro_set_ec_hq), SOC_SINGLE_EXT("WSA2_RX1 EC_HQ Switch", SND_SOC_NOPM, LPASS_CDC_WSA2_MACRO_RX1, 1, 0, lpass_cdc_wsa2_macro_get_ec_hq, lpass_cdc_wsa2_macro_set_ec_hq), + SOC_SINGLE_EXT("WSA2 PBR Enable", SND_SOC_NOPM, 0, 1, + 0, lpass_cdc_wsa2_macro_pbr_enable_get, + lpass_cdc_wsa2_macro_pbr_enable_put), }; static const struct soc_enum rx_mux_enum = @@ -2712,14 +2980,150 @@ static const struct snd_soc_dapm_route wsa2_audio_map[] = { {"WSA2_SPK2 OUT", NULL, "WSA2_MCLK"}, }; +static void lpass_cdc_wsa2_macro_init_pbr(struct snd_soc_component *component) +{ + int sys_gain, bat_cfg, rload; + int vth1, vth2, vth3, vth4, vth5, vth6, vth7, vth8, vth9; + int vth10, vth11, vth12, vth13, vth14, vth15; + struct device *wsa2_dev = NULL; + struct lpass_cdc_wsa2_macro_priv *wsa2_priv = NULL; + + if (!lpass_cdc_wsa2_macro_get_data(component, &wsa2_dev, &wsa2_priv, __func__)) + return; + + /* RX0 */ + sys_gain = wsa2_priv->wsa2_sys_gain[0]; + bat_cfg = wsa2_priv->wsa2_bat_cfg[0]; + rload = wsa2_priv->wsa2_rload[0]; + /* ILIM */ + switch (rload) { + case WSA_4_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0, 0xE0, 0x40); + break; + case WSA_6_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0, 0xE0, 0x80); + break; + case WSA_8_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0, 0xE0, 0xC0); + break; + case WSA_32_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0, 0xE0, 0xE0); + break; + default: + break; + } + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG1, 0x0F, sys_gain); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG9, 0xC0, (bat_cfg - 1) << 0x6); + /* Thesh */ + vth1 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth1_data[sys_gain][bat_cfg][rload]); + vth2 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth2_data[sys_gain][bat_cfg][rload]); + vth3 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth3_data[sys_gain][bat_cfg][rload]); + vth4 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth4_data[sys_gain][bat_cfg][rload]); + vth5 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth5_data[sys_gain][bat_cfg][rload]); + vth6 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth6_data[sys_gain][bat_cfg][rload]); + vth7 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth7_data[sys_gain][bat_cfg][rload]); + vth8 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth8_data[sys_gain][bat_cfg][rload]); + vth9 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth9_data[sys_gain][bat_cfg][rload]); + vth10 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth10_data[sys_gain][bat_cfg][rload]); + vth11 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth11_data[sys_gain][bat_cfg][rload]); + vth12 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth12_data[sys_gain][bat_cfg][rload]); + vth13 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth13_data[sys_gain][bat_cfg][rload]); + vth14 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth14_data[sys_gain][bat_cfg][rload]); + vth15 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth15_data[sys_gain][bat_cfg][rload]); + + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG1, vth1); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG2, vth2); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG3, vth3); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG4, vth4); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG5, vth5); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG6, vth6); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG7, vth7); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG8, vth8); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG9, vth9); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG10, vth10); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG11, vth11); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG12, vth12); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG13, vth13); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG14, vth14); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG15, vth15); + + /* RX1 */ + sys_gain = wsa2_priv->wsa2_sys_gain[2]; + bat_cfg = wsa2_priv->wsa2_bat_cfg[1]; + rload = wsa2_priv->wsa2_rload[1]; + /* ILIM */ + switch (rload) { + case WSA_4_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0_1, 0xE0, 0x40); + break; + case WSA_6_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0_1, 0xE0, 0x80); + break; + case WSA_8_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0_1, 0xE0, 0xC0); + break; + case WSA_32_OHMS: + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG0_1, 0xE0, 0xE0); + break; + default: + break; + } + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG1_1, 0x0F, sys_gain); + snd_soc_component_update_bits(component, + LPASS_CDC_WSA2_ILIM_CFG9, 0x30, (bat_cfg - 1) << 0x4); + /* Thesh */ + vth1 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth1_data[sys_gain][bat_cfg][rload]); + vth2 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth2_data[sys_gain][bat_cfg][rload]); + vth3 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth3_data[sys_gain][bat_cfg][rload]); + vth4 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth4_data[sys_gain][bat_cfg][rload]); + vth5 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth5_data[sys_gain][bat_cfg][rload]); + vth6 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth6_data[sys_gain][bat_cfg][rload]); + vth7 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth7_data[sys_gain][bat_cfg][rload]); + vth8 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth8_data[sys_gain][bat_cfg][rload]); + vth9 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth9_data[sys_gain][bat_cfg][rload]); + vth10 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth10_data[sys_gain][bat_cfg][rload]); + vth11 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth11_data[sys_gain][bat_cfg][rload]); + vth12 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth12_data[sys_gain][bat_cfg][rload]); + vth13 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth13_data[sys_gain][bat_cfg][rload]); + vth14 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth14_data[sys_gain][bat_cfg][rload]); + vth15 = LPASS_CDC_WSA2_MACRO_VTH_TO_REG(pbr_vth15_data[sys_gain][bat_cfg][rload]); + + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG1_1, vth1); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG2_1, vth2); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG3_1, vth3); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG4_1, vth4); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG5_1, vth5); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG6_1, vth6); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG7_1, vth7); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG8_1, vth8); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG9_1, vth9); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG10_1, vth10); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG11_1, vth11); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG12_1, vth12); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG13_1, vth13); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG14_1, vth14); + snd_soc_component_write(component, LPASS_CDC_WSA2_PBR_CFG15_1, vth15); +} + static const struct lpass_cdc_wsa2_macro_reg_mask_val lpass_cdc_wsa2_macro_reg_init[] = { {LPASS_CDC_WSA2_BOOST0_BOOST_CFG1, 0x3F, 0x12}, {LPASS_CDC_WSA2_BOOST0_BOOST_CFG2, 0x1C, 0x08}, - {LPASS_CDC_WSA2_COMPANDER0_CTL7, 0x1E, 0x18}, + {LPASS_CDC_WSA2_COMPANDER0_CTL7, 0x3E, 0x2e}, {LPASS_CDC_WSA2_BOOST1_BOOST_CFG1, 0x3F, 0x12}, {LPASS_CDC_WSA2_BOOST1_BOOST_CFG2, 0x1C, 0x08}, - {LPASS_CDC_WSA2_COMPANDER1_CTL7, 0x1E, 0x18}, + {LPASS_CDC_WSA2_COMPANDER1_CTL7, 0x3E, 0x2e}, {LPASS_CDC_WSA2_BOOST0_BOOST_CTL, 0x70, 0x58}, {LPASS_CDC_WSA2_BOOST1_BOOST_CTL, 0x70, 0x58}, {LPASS_CDC_WSA2_RX0_RX_PATH_CFG1, 0x08, 0x08}, @@ -2730,12 +3134,28 @@ static const struct lpass_cdc_wsa2_macro_reg_mask_val {LPASS_CDC_WSA2_TX1_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, {LPASS_CDC_WSA2_TX2_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, {LPASS_CDC_WSA2_TX3_SPKR_PROT_PATH_CFG0, 0x01, 0x01}, - {LPASS_CDC_WSA2_COMPANDER0_CTL7, 0x01, 0x01}, - {LPASS_CDC_WSA2_COMPANDER1_CTL7, 0x01, 0x01}, {LPASS_CDC_WSA2_RX0_RX_PATH_CFG0, 0x01, 0x01}, {LPASS_CDC_WSA2_RX1_RX_PATH_CFG0, 0x01, 0x01}, {LPASS_CDC_WSA2_RX0_RX_PATH_MIX_CFG, 0x01, 0x01}, {LPASS_CDC_WSA2_RX1_RX_PATH_MIX_CFG, 0x01, 0x01}, + {LPASS_CDC_WSA2_LA_CFG, 0x3F, 0xF}, + {LPASS_CDC_WSA2_PBR_CFG16, 0xFF, 0x42}, + {LPASS_CDC_WSA2_PBR_CFG19, 0xFF, 0xFC}, + {LPASS_CDC_WSA2_PBR_CFG20, 0xF0, 0x60}, + {LPASS_CDC_WSA2_ILIM_CFG1, 0x70, 0x40}, + {LPASS_CDC_WSA2_ILIM_CFG0, 0x03, 0x01}, + {LPASS_CDC_WSA2_ILIM_CFG3, 0x1F, 0x15}, + {LPASS_CDC_WSA2_LA_CFG_1, 0x3F, 0x0F}, + {LPASS_CDC_WSA2_PBR_CFG16_1, 0xFF, 0x42}, + {LPASS_CDC_WSA2_PBR_CFG21, 0xFF, 0xFC}, + {LPASS_CDC_WSA2_PBR_CFG22, 0xF0, 0x60}, + {LPASS_CDC_WSA2_ILIM_CFG1_1, 0x70, 0x40}, + {LPASS_CDC_WSA2_ILIM_CFG0_1, 0x03, 0x01}, + {LPASS_CDC_WSA2_ILIM_CFG4, 0x1F, 0x15}, + {LPASS_CDC_WSA2_ILIM_CFG2_1, 0xFF, 0x2A}, + {LPASS_CDC_WSA2_ILIM_CFG2, 0x3F, 0x1B}, + {LPASS_CDC_WSA2_ILIM_CFG9, 0x0F, 0x05}, + {LPASS_CDC_WSA2_IDLE_DETECT_CFG1, 0xFF, 0x1D}, }; static void lpass_cdc_wsa2_macro_init_reg(struct snd_soc_component *component) @@ -2747,6 +3167,7 @@ static void lpass_cdc_wsa2_macro_init_reg(struct snd_soc_component *component) lpass_cdc_wsa2_macro_reg_init[i].reg, lpass_cdc_wsa2_macro_reg_init[i].mask, lpass_cdc_wsa2_macro_reg_init[i].val); + lpass_cdc_wsa2_macro_init_pbr(component); } static int lpass_cdc_wsa2_macro_core_vote(void *handle, bool enable) @@ -2768,6 +3189,7 @@ static int lpass_cdc_wsa2_macro_core_vote(void *handle, bool enable) pm_runtime_put_autosuspend(wsa2_priv->dev); pm_runtime_mark_last_busy(wsa2_priv->dev); } + return rc; } @@ -2952,9 +3374,8 @@ static int lpass_cdc_wsa2_macro_init(struct snd_soc_component *component) return -EINVAL; } - ret = snd_soc_dapm_new_controls(dapm, - lpass_cdc_wsa2_macro_dapm_widgets, - ARRAY_SIZE(lpass_cdc_wsa2_macro_dapm_widgets)); + ret = snd_soc_dapm_new_controls(dapm, lpass_cdc_wsa2_macro_dapm_widgets, + ARRAY_SIZE(lpass_cdc_wsa2_macro_dapm_widgets)); if (ret < 0) { dev_err(wsa2_dev, "%s: Failed to add controls\n", __func__); return ret; @@ -2973,9 +3394,8 @@ static int lpass_cdc_wsa2_macro_init(struct snd_soc_component *component) return ret; } - ret = snd_soc_add_component_controls(component, - lpass_cdc_wsa2_macro_snd_controls, - ARRAY_SIZE(lpass_cdc_wsa2_macro_snd_controls)); + ret = snd_soc_add_component_controls(component, lpass_cdc_wsa2_macro_snd_controls, + ARRAY_SIZE(lpass_cdc_wsa2_macro_snd_controls)); if (ret < 0) { dev_err(wsa2_dev, "%s: Failed to add snd_ctls\n", __func__); return ret; @@ -2993,6 +3413,7 @@ static int lpass_cdc_wsa2_macro_init(struct snd_soc_component *component) snd_soc_dapm_sync(dapm); wsa2_priv->component = component; + wsa2_priv->spkr_gain_offset = LPASS_CDC_WSA2_MACRO_GAIN_OFFSET_0_DB; lpass_cdc_wsa2_macro_init_reg(component); return 0; @@ -3084,7 +3505,7 @@ static void lpass_cdc_wsa2_macro_add_child_devices(struct work_struct *work) swr_ctrl_data[ctrl_num].wsa2_swr_pdev = pdev; ctrl_num++; dev_dbg(&pdev->dev, - "%s: Added soundwire ctrl device(s)\n", + "%s: Adding soundwire ctrl device(s)\n", __func__); wsa2_priv->swr_ctrl_data = swr_ctrl_data; } @@ -3120,12 +3541,12 @@ static void lpass_cdc_wsa2_macro_cooling_adjust_gain(struct work_struct *work) wsa2_priv = container_of(work, struct lpass_cdc_wsa2_macro_priv, lpass_cdc_wsa2_macro_cooling_work); if (!wsa2_priv) { - pr_err_ratelimited("%s: priv is null for macro!\n", + pr_err("%s: priv is null for macro!\n", __func__); return; } if (!wsa2_priv->dev || !wsa2_priv->dev->of_node) { - dev_err_ratelimited(wsa2_priv->dev, + dev_err(wsa2_priv->dev, "%s: DT node for wsa2_priv does not exist\n", __func__); return; } @@ -3154,6 +3575,31 @@ static void lpass_cdc_wsa2_macro_cooling_adjust_gain(struct work_struct *work) return; } +static int lpass_cdc_wsa2_macro_read_array(struct platform_device *pdev, + const char *name, int num_values, + u32 *output) +{ + u32 len, ret, size; + + if (!of_find_property(pdev->dev.of_node, name, &size)) { + dev_info(&pdev->dev, "%s: missing %s\n", __func__, name); + return 0; + } + + len = size / sizeof(u32); + if (len != num_values) { + dev_info(&pdev->dev, "%s: invalid number of %s\n", __func__, name); + return -EINVAL; + } + + ret = of_property_read_u32_array(pdev->dev.of_node, name, output, len); + if (ret) + dev_info(&pdev->dev, "%s: Failed to read %s\n", __func__, name); + + return 0; + +} + static void lpass_cdc_wsa2_macro_init_ops(struct macro_ops *ops, char __iomem *wsa2_io_base) { @@ -3175,6 +3621,7 @@ static int lpass_cdc_wsa2_macro_probe(struct platform_device *pdev) char __iomem *wsa2_io_base; int ret = 0; u32 is_used_wsa2_swr_gpio = 1; + u32 noise_gate_mode; const char *is_used_wsa2_swr_gpio_dt = "qcom,is-used-swr-gpio"; if (!lpass_cdc_is_va_macro_registered(&pdev->dev)) { @@ -3183,8 +3630,7 @@ static int lpass_cdc_wsa2_macro_probe(struct platform_device *pdev) return -EPROBE_DEFER; } - wsa2_priv = devm_kzalloc(&pdev->dev, - sizeof(struct lpass_cdc_wsa2_macro_priv), + wsa2_priv = devm_kzalloc(&pdev->dev, sizeof(struct lpass_cdc_wsa2_macro_priv), GFP_KERNEL); if (!wsa2_priv) return -ENOMEM; @@ -3225,12 +3671,20 @@ static int lpass_cdc_wsa2_macro_probe(struct platform_device *pdev) wsa2_priv->wsa2_swr_gpio_p, false); wsa2_io_base = devm_ioremap(&pdev->dev, - wsa2_base_addr, - LPASS_CDC_WSA2_MACRO_MAX_OFFSET); + wsa2_base_addr, LPASS_CDC_WSA2_MACRO_MAX_OFFSET); if (!wsa2_io_base) { dev_err(&pdev->dev, "%s: ioremap failed\n", __func__); return -EINVAL; } + + lpass_cdc_wsa2_macro_read_array(pdev, "qcom,wsa2-rloads", + LPASS_CDC_WSA2_MACRO_RX1 + 1, wsa2_priv->wsa2_rload); + lpass_cdc_wsa2_macro_read_array(pdev, "qcom,wsa2-system-gains", + 2 * (LPASS_CDC_WSA2_MACRO_RX1 + 1), wsa2_priv->wsa2_sys_gain); + lpass_cdc_wsa2_macro_read_array(pdev, "qcom,wsa2-bat-cfgs", + LPASS_CDC_WSA2_MACRO_RX1 + 1, wsa2_priv->wsa2_bat_cfg); + + wsa2_priv->wsa2_io_base = wsa2_io_base; wsa2_priv->reset_swr = true; INIT_WORK(&wsa2_priv->lpass_cdc_wsa2_macro_add_child_devices_work, @@ -3250,7 +3704,7 @@ static int lpass_cdc_wsa2_macro_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "%s: could not find %s entry in dt\n", __func__, "qcom,mux0-clk-id"); - default_clk_id = WSA_CORE_CLK; + default_clk_id = WSA2_CORE_CLK; } wsa2_priv->default_clk_id = default_clk_id; @@ -3293,14 +3747,25 @@ static int lpass_cdc_wsa2_macro_probe(struct platform_device *pdev) } } + ret = of_property_read_u32(pdev->dev.of_node, + "qcom,noise-gate-mode", &noise_gate_mode); + if (ret) { + dev_info(&pdev->dev, "%s: could not find %s entry in dt\n", + __func__, "qcom,noise-gate-mode"); + wsa2_priv->noise_gate_mode = IDLE_DETECT; + } else { + if (noise_gate_mode >= IDLE_DETECT && noise_gate_mode <= NG3) + wsa2_priv->noise_gate_mode = noise_gate_mode; + else + wsa2_priv->noise_gate_mode = IDLE_DETECT; + } + pm_runtime_set_autosuspend_delay(&pdev->dev, AUTO_SUSPEND_DELAY); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_suspend_ignore_children(&pdev->dev, true); pm_runtime_enable(&pdev->dev); - schedule_work(&wsa2_priv->lpass_cdc_wsa2_macro_add_child_devices_work); - return ret; reg_macro_fail: mutex_destroy(&wsa2_priv->mclk_lock);