diff --git a/asoc/codecs/wcd-clsh.c b/asoc/codecs/wcd-clsh.c index bda3893811..8306fa53d9 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 87bea04318..a54394446b 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 3a6c895a65..8113ab4204 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 c8e49fd0b9..96d35b672b 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 */