From b9d7807f4e49436939136935bd9a4c5916738724 Mon Sep 17 00:00:00 2001 From: Karthikeyan Mani Date: Fri, 21 Jun 2019 14:15:23 -0700 Subject: [PATCH] asoc: codecs: Change TX tuning and reduce RX click and pop Update TX requantizer gain coefficients to center gain errors around zero. To reduce click and pop on audio playback enable reference buffers of headphone path in hifi mode and then put it to the usecase specific power mode. Change-Id: I0013d6258d5e5a8c92fd0f951d1d89e5906b2faf Signed-off-by: Karthikeyan Mani --- asoc/codecs/wcd-clsh.c | 10 +- asoc/codecs/wcd938x/internal.h | 1 + asoc/codecs/wcd938x/wcd938x.c | 163 ++++++++++++++++++++++++++------- include/asoc/wcd-clsh.h | 11 ++- 4 files changed, 148 insertions(+), 37 deletions(-) diff --git a/asoc/codecs/wcd-clsh.c b/asoc/codecs/wcd-clsh.c index bda389381101..8306fa53d91e 100644 --- a/asoc/codecs/wcd-clsh.c +++ b/asoc/codecs/wcd-clsh.c @@ -243,7 +243,14 @@ static void wcd_clsh_flyback_ctrl(struct snd_soc_component *component, __func__, clsh_d->flyback_users, enable, mode_to_str(mode)); } -static void wcd_clsh_set_hph_mode(struct snd_soc_component *component, +/* + * Function: wcd_clsh_set_hph_mode + * Params: soc component, hph mode class + * Description: + * This function updates class H mode configuration based on + * the input mode. + */ +void wcd_clsh_set_hph_mode(struct snd_soc_component *component, int mode) { u8 val = 0; @@ -273,6 +280,7 @@ static void wcd_clsh_set_hph_mode(struct snd_soc_component *component, snd_soc_component_update_bits(component, WCD9XXX_ANA_HPH, 0x0C, val); } +EXPORT_SYMBOL(wcd_clsh_set_hph_mode); static void wcd_clsh_set_flyback_current(struct snd_soc_component *component, int mode) diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h index 87bea0431860..a54394446bd3 100644 --- a/asoc/codecs/wcd938x/internal.h +++ b/asoc/codecs/wcd938x/internal.h @@ -144,6 +144,7 @@ enum { WCD_BOLERO_EVT_RX_MUTE = 1, /* for RX mute/unmute */ WCD_BOLERO_EVT_IMPED_TRUE, /* for imped true */ WCD_BOLERO_EVT_IMPED_FALSE, /* for imped false */ + WCD_BOLERO_EVT_RX_COMPANDER_SOFT_RST, }; enum { diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index 3a6c895a65d7..8113ab4204f2 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -173,6 +173,16 @@ static int wcd938x_init_reg(struct snd_soc_component *component) snd_soc_component_update_bits(component, WCD938X_TX_COM_NEW_INT_TXFE_ICTRL_STG2MAIN_ULP, 0x1F, 0x08); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_0, 0xFF, 0x55); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_1, 0xFF, 0x44); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_2, 0xFF, 0x11); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_3, 0xFF, 0x00); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_TX_REQ_FB_CTL_4, 0xFF, 0x00); return 0; } @@ -618,6 +628,10 @@ static int wcd938x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); ret = swr_slvdev_datapath_control(wcd938x->rx_swr_dev, wcd938x->rx_swr_dev->dev_num, true); @@ -625,8 +639,10 @@ static int wcd938x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, WCD_CLSH_EVENT_PRE_DAC, WCD_CLSH_STATE_HPHR, hph_mode); + wcd_clsh_set_hph_mode(component, CLS_H_HIFI); snd_soc_component_update_bits(component, WCD938X_ANA_HPH, 0x10, 0x10); + wcd_clsh_set_hph_mode(component, hph_mode); /* 100 usec delay as per HW requirement */ usleep_range(100, 110); set_bit(HPH_PA_DELAY, &wcd938x->status_mask); @@ -656,26 +672,61 @@ static int wcd938x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, wcd938x->update_wcd_event(wcd938x->handle, WCD_BOLERO_EVT_RX_MUTE, (WCD_RX2 << 0x10)); + wcd_enable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHR_PDM_WD_INT); break; case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHR_PDM_WD_INT); if (wcd938x->update_wcd_event) wcd938x->update_wcd_event(wcd938x->handle, WCD_BOLERO_EVT_RX_MUTE, (WCD_RX2 << 0x10 | 0x1)); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_COMPANDER_SOFT_RST, + (WCD_RX2 << 0x10)); + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7100); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x0)); + /* 20 msec delay as per HW requirement */ + usleep_range(21000, 21100); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX2 << 0x10 | 0x1)); + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x40, 0x00); blocking_notifier_call_chain(&wcd938x->mbhc->notifier, WCD_EVENT_PRE_HPHR_PA_OFF, &wcd938x->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); break; case SND_SOC_DAPM_POST_PMD: - /* 7 msec delay as per HW requirement */ - usleep_range(7000, 7010); - snd_soc_component_update_bits(component, - WCD938X_DIGITAL_PDM_WD_CTL1, 0x17, 0x00); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } blocking_notifier_call_chain(&wcd938x->mbhc->notifier, WCD_EVENT_POST_HPHR_PA_OFF, &wcd938x->mbhc->wcd_mbhc); snd_soc_component_update_bits(component, WCD938X_ANA_HPH, 0x10, 0x00); + /* 20 msec delay as per HW requirement */ + usleep_range(20000, 20100); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL1, 0x17, 0x00); wcd_cls_h_fsm(component, &wcd938x->clsh_info, WCD_CLSH_EVENT_POST_PA, WCD_CLSH_STATE_HPHR, @@ -699,6 +750,10 @@ static int wcd938x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x01)); ret = swr_slvdev_datapath_control(wcd938x->rx_swr_dev, wcd938x->rx_swr_dev->dev_num, true); @@ -706,8 +761,10 @@ static int wcd938x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, WCD_CLSH_EVENT_PRE_DAC, WCD_CLSH_STATE_HPHL, hph_mode); + wcd_clsh_set_hph_mode(component, CLS_H_HIFI); snd_soc_component_update_bits(component, WCD938X_ANA_HPH, 0x20, 0x20); + wcd_clsh_set_hph_mode(component, hph_mode); /* 100 usec delay as per HW requirement */ usleep_range(100, 110); set_bit(HPH_PA_DELAY, &wcd938x->status_mask); @@ -737,26 +794,61 @@ static int wcd938x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, wcd938x->update_wcd_event(wcd938x->handle, WCD_BOLERO_EVT_RX_MUTE, (WCD_RX1 << 0x10)); + wcd_enable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHL_PDM_WD_INT); break; case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&wcd938x->irq_info, + WCD938X_IRQ_HPHL_PDM_WD_INT); if (wcd938x->update_wcd_event) wcd938x->update_wcd_event(wcd938x->handle, WCD_BOLERO_EVT_RX_MUTE, (WCD_RX1 << 0x10 | 0x1)); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_COMPANDER_SOFT_RST, + (WCD_RX1 << 0x10)); + /* 7 msec delay as per HW requirement */ + usleep_range(7000, 7100); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x0)); + /* 20 msec delay as per HW requirement */ + usleep_range(21000, 21100); + if (wcd938x->update_wcd_event) + wcd938x->update_wcd_event(wcd938x->handle, + WCD_BOLERO_EVT_RX_MUTE, + (WCD_RX1 << 0x10 | 0x1)); + snd_soc_component_update_bits(component, WCD938X_ANA_HPH, + 0x80, 0x00); blocking_notifier_call_chain(&wcd938x->mbhc->notifier, WCD_EVENT_PRE_HPHL_PA_OFF, &wcd938x->mbhc->wcd_mbhc); + set_bit(HPH_PA_DELAY, &wcd938x->status_mask); break; case SND_SOC_DAPM_POST_PMD: - /* 7 msec delay as per HW requirement */ - usleep_range(7000, 7010); - snd_soc_component_update_bits(component, - WCD938X_DIGITAL_PDM_WD_CTL0, 0x17, 0x00); + /* + * 7ms sleep is required if compander is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd938x->status_mask)) { + if (!wcd938x->comp1_enable) + usleep_range(21000, 21100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd938x->status_mask); + } blocking_notifier_call_chain(&wcd938x->mbhc->notifier, WCD_EVENT_POST_HPHL_PA_OFF, &wcd938x->mbhc->wcd_mbhc); snd_soc_component_update_bits(component, WCD938X_ANA_HPH, 0x20, 0x00); + /* 20 msec delay as per HW requirement */ + usleep_range(21000, 21100); + snd_soc_component_update_bits(component, + WCD938X_DIGITAL_PDM_WD_CTL0, 0x17, 0x00); wcd_cls_h_fsm(component, &wcd938x->clsh_info, WCD_CLSH_EVENT_POST_PA, WCD_CLSH_STATE_HPHL, @@ -799,8 +891,11 @@ static int wcd938x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w, wcd938x->update_wcd_event(wcd938x->handle, WCD_BOLERO_EVT_RX_MUTE, (WCD_RX3 << 0x10)); + wcd_enable_irq(&wcd938x->irq_info, WCD938X_IRQ_AUX_PDM_WD_INT); break; case SND_SOC_DAPM_PRE_PMD: + wcd_disable_irq(&wcd938x->irq_info, + WCD938X_IRQ_AUX_PDM_WD_INT); if (wcd938x->update_wcd_event) wcd938x->update_wcd_event(wcd938x->handle, WCD_BOLERO_EVT_RX_MUTE, @@ -1684,10 +1779,10 @@ static int wcd938x_codec_enable_micbias(struct snd_soc_dapm_widget *w, return __wcd938x_codec_enable_micbias(w, event); } -static inline int wcd938x_tx_path_get(const char *wname) +static inline int wcd938x_tx_path_get(const char *wname, + unsigned int *path_num) { int ret = 0; - unsigned int path_num; char *widget_name = NULL; char *w_name = NULL; char *path_num_char = NULL; @@ -1706,7 +1801,6 @@ static inline int wcd938x_tx_path_get(const char *wname) ret = -EINVAL; goto err; } - path_name = widget_name; path_num_char = strpbrk(path_name, "0123"); if (!path_num_char) { pr_err("%s: tx path index not found\n", @@ -1714,7 +1808,7 @@ static inline int wcd938x_tx_path_get(const char *wname) ret = -EINVAL; goto err; } - ret = kstrtouint(path_num_char, 10, &path_num); + ret = kstrtouint(path_num_char, 10, path_num); if (ret < 0) pr_err("%s: Invalid tx path = %s\n", __func__, w_name); @@ -1727,24 +1821,23 @@ err: static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = - snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct wcd938x_priv *wcd938x = NULL; - int path = 0; + int ret = 0; + unsigned int path = 0; if (!component) return -EINVAL; wcd938x = snd_soc_component_get_drvdata(component); - if (!widget || !widget->name || !wcd938x) + if (!wcd938x) return -EINVAL; - path = wcd938x_tx_path_get(widget->name); - if (path < 0 || path >= TX_ADC_MAX) - return -EINVAL; + ret = wcd938x_tx_path_get(kcontrol->id.name, &path); + if (ret < 0) + return ret; ucontrol->value.integer.value[0] = wcd938x->tx_mode[path]; @@ -1754,25 +1847,24 @@ static int wcd938x_tx_mode_get(struct snd_kcontrol *kcontrol, static int wcd938x_tx_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_dapm_widget *widget = - snd_soc_dapm_kcontrol_widget(kcontrol); struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); struct wcd938x_priv *wcd938x = NULL; u32 mode_val; - int path = 0; + unsigned int path = 0; + int ret = 0; if (!component) return -EINVAL; wcd938x = snd_soc_component_get_drvdata(component); - if (!widget || !widget->name || !wcd938x) + if (!wcd938x) return -EINVAL; - path = wcd938x_tx_path_get(widget->name); - if (path < 0 || path >= TX_ADC_MAX) - return -EINVAL; + ret = wcd938x_tx_path_get(kcontrol->id.name, &path); + if (ret) + return ret; mode_val = ucontrol->value.enumerated.item[0]; @@ -2199,19 +2291,19 @@ static const struct snd_soc_dapm_widget wcd938x_dapm_widgets[] = { SND_SOC_DAPM_PGA_E("EAR PGA", WCD938X_ANA_EAR, 7, 0, NULL, 0, wcd938x_codec_enable_ear_pa, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("AUX PGA", WCD938X_AUX_AUXPA, 7, 0, NULL, 0, wcd938x_codec_enable_aux_pa, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("HPHL PGA", WCD938X_ANA_HPH, 7, 0, NULL, 0, wcd938x_codec_enable_hphl_pa, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_PGA_E("HPHR PGA", WCD938X_ANA_HPH, 6, 0, NULL, 0, wcd938x_codec_enable_hphr_pa, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | - SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD), SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0, wcd938x_codec_hphl_dac_event, @@ -2840,10 +2932,10 @@ static int wcd938x_bind(struct device *dev) "HPHL PDM WD INT", wcd938x_wd_handle_irq, NULL); wcd_request_irq(&wcd938x->irq_info, WCD938X_IRQ_AUX_PDM_WD_INT, "AUX PDM WD INT", wcd938x_wd_handle_irq, NULL); - /* Enable watchdog interrupt for HPH and AUX */ - wcd_enable_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHR_PDM_WD_INT); - wcd_enable_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHL_PDM_WD_INT); - wcd_enable_irq(&wcd938x->irq_info, WCD938X_IRQ_AUX_PDM_WD_INT); + /* Disable watchdog interrupt for HPH and AUX */ + wcd_disable_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHR_PDM_WD_INT); + wcd_disable_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHL_PDM_WD_INT); + wcd_disable_irq(&wcd938x->irq_info, WCD938X_IRQ_AUX_PDM_WD_INT); ret = snd_soc_register_component(dev, &soc_codec_dev_wcd938x, NULL, 0); @@ -2865,6 +2957,9 @@ static void wcd938x_unbind(struct device *dev) { struct wcd938x_priv *wcd938x = dev_get_drvdata(dev); + wcd_free_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHR_PDM_WD_INT, NULL); + wcd_free_irq(&wcd938x->irq_info, WCD938X_IRQ_HPHL_PDM_WD_INT, NULL); + wcd_free_irq(&wcd938x->irq_info, WCD938X_IRQ_AUX_PDM_WD_INT, NULL); wcd_irq_exit(&wcd938x->irq_info, wcd938x->virq); snd_soc_unregister_component(dev); component_unbind_all(dev, wcd938x); diff --git a/include/asoc/wcd-clsh.h b/include/asoc/wcd-clsh.h index c8e49fd0b904..96d35b672b28 100644 --- a/include/asoc/wcd-clsh.h +++ b/include/asoc/wcd-clsh.h @@ -82,15 +82,22 @@ extern void wcd_cls_h_fsm(struct snd_soc_component *component, int int_mode); extern void wcd_cls_h_init(struct wcd_clsh_cdc_info *clsh); +extern void wcd_clsh_set_hph_mode(struct snd_soc_component *component, + int mode); #else -extern void wcd_cls_h_fsm(struct snd_soc_component *component, +static inline void wcd_cls_h_fsm(struct snd_soc_component *component, struct wcd_clsh_cdc_info *cdc_clsh_d, u8 clsh_event, u8 req_state, int int_mode) { } -extern void wcd_cls_h_init(struct wcd_clsh_cdc_info *clsh) +static inline extern void wcd_cls_h_init(struct wcd_clsh_cdc_info *clsh) +{ +} + +static inline extern void wcd_clsh_set_hph_mode(struct snd_soc_component *component, + int mode) { } #endif /* CONFIG_SND_SOC_WCD9XXX_V2 */