]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: codecs: wcd937x: add playback dapm widgets
authorPrasad Kumpatla <quic_pkumpatl@quicinc.com>
Fri, 24 May 2024 03:55:33 +0000 (09:25 +0530)
committerMark Brown <broonie@kernel.org>
Mon, 10 Jun 2024 11:47:29 +0000 (12:47 +0100)
This patch adds required dapm widgets for playback.

Signed-off-by: Prasad Kumpatla <quic_pkumpatl@quicinc.com>
Co-developed-by: Mohammad Rafi Shaik <quic_mohs@quicinc.com>
Signed-off-by: Mohammad Rafi Shaik <quic_mohs@quicinc.com>
Link: https://lore.kernel.org/r/20240524035535.3119208-6-quic_mohs@quicinc.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/wcd937x.c

index 293a84a53918bc9a734c313a738d97d024706da3..3b0e4bd4eb4fddfd77baad750de7694ddd080c08 100644 (file)
@@ -342,6 +342,569 @@ static int wcd937x_rx_clk_disable(struct snd_soc_component *component)
        return 0;
 }
 
+static int wcd937x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *kcontrol,
+                                       int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+       int hph_mode = wcd937x->hph_mode;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               wcd937x_rx_clk_enable(component);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+                                             BIT(0), BIT(0));
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+                                             BIT(2), BIT(2));
+               snd_soc_component_update_bits(component,
+                                             WCD937X_HPH_RDAC_CLK_CTL1,
+                                             BIT(7), 0x00);
+               set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+                                                     0x0f, BIT(1));
+               else if (hph_mode == CLS_H_LOHIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+                                                     0x0f, 0x06);
+
+               if (wcd937x->comp1_enable) {
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_CDC_COMP_CTL_0,
+                                                     BIT(1), BIT(1));
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_L_EN,
+                                                     BIT(5), 0x00);
+
+                       if (wcd937x->comp2_enable) {
+                               snd_soc_component_update_bits(component,
+                                                             WCD937X_DIGITAL_CDC_COMP_CTL_0,
+                                                             BIT(0), BIT(0));
+                               snd_soc_component_update_bits(component,
+                                                             WCD937X_HPH_R_EN, BIT(5), 0x00);
+                       }
+
+                       if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) {
+                               usleep_range(5000, 5110);
+                               clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+                       }
+               } else {
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_CDC_COMP_CTL_0,
+                                                     BIT(1), 0x00);
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_L_EN,
+                                                     BIT(5), BIT(5));
+               }
+
+               snd_soc_component_update_bits(component,
+                                             WCD937X_HPH_NEW_INT_HPH_TIMER1,
+                                             BIT(1), 0x00);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_update_bits(component,
+                                             WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+                                             0x0f, BIT(0));
+               break;
+       }
+
+       return 0;
+}
+
+static int wcd937x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *kcontrol,
+                                       int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+       int hph_mode = wcd937x->hph_mode;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               wcd937x_rx_clk_enable(component);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_DIG_CLK_CTL, BIT(1), BIT(1));
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_HPH_GAIN_CTL, BIT(3), BIT(3));
+               snd_soc_component_update_bits(component,
+                                             WCD937X_HPH_RDAC_CLK_CTL1, BIT(7), 0x00);
+               set_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+                                                     0x0f, BIT(1));
+               else if (hph_mode == CLS_H_LOHIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+                                                     0x0f, 0x06);
+               if (wcd937x->comp2_enable) {
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_CDC_COMP_CTL_0,
+                                                     BIT(0), BIT(0));
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_R_EN, BIT(5), 0x00);
+                       if (wcd937x->comp1_enable) {
+                               snd_soc_component_update_bits(component,
+                                                             WCD937X_DIGITAL_CDC_COMP_CTL_0,
+                                                             BIT(1), BIT(1));
+                               snd_soc_component_update_bits(component,
+                                                             WCD937X_HPH_L_EN,
+                                                             BIT(5), 0x00);
+                       }
+
+                       if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) {
+                               usleep_range(5000, 5110);
+                               clear_bit(HPH_COMP_DELAY, &wcd937x->status_mask);
+                       }
+               } else {
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_CDC_COMP_CTL_0,
+                                                     BIT(0), 0x00);
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_R_EN,
+                                                     BIT(5), BIT(5));
+               }
+               snd_soc_component_update_bits(component,
+                                             WCD937X_HPH_NEW_INT_HPH_TIMER1,
+                                             BIT(1), 0x00);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_update_bits(component,
+                                             WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R,
+                                             0x0f, BIT(0));
+               break;
+       }
+
+       return 0;
+}
+
+static int wcd937x_codec_ear_dac_event(struct snd_soc_dapm_widget *w,
+                                      struct snd_kcontrol *kcontrol,
+                                      int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+       int hph_mode = wcd937x->hph_mode;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               wcd937x_rx_clk_enable(component);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_HPH_GAIN_CTL,
+                                             BIT(2), BIT(2));
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+                                             BIT(0), BIT(0));
+
+               if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_HIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+                                                     0x0f, BIT(1));
+               else if (hph_mode == CLS_H_LOHIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+                                                     0x0f, 0x06);
+               if (wcd937x->comp1_enable)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_CDC_COMP_CTL_0,
+                                                     BIT(1), BIT(1));
+               usleep_range(5000, 5010);
+
+               snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN, BIT(2), 0x00);
+               wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+                                       WCD_CLSH_EVENT_PRE_DAC,
+                                       WCD_CLSH_STATE_EAR,
+                                       hph_mode);
+
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (hph_mode == CLS_AB_HIFI || hph_mode == CLS_H_LOHIFI ||
+                   hph_mode == CLS_H_HIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L,
+                                                     0x0f, BIT(0));
+               if (wcd937x->comp1_enable)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_CDC_COMP_CTL_0,
+                                                     BIT(1), 0x00);
+               break;
+       }
+
+       return 0;
+}
+
+static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w,
+                                      struct snd_kcontrol *kcontrol,
+                                      int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+       int hph_mode = wcd937x->hph_mode;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               wcd937x_rx_clk_enable(component);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+                                             BIT(2), BIT(2));
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+                                             BIT(2), BIT(2));
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_AUX_GAIN_CTL,
+                                             BIT(0), BIT(0));
+               wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+                                       WCD_CLSH_EVENT_PRE_DAC,
+                                       WCD_CLSH_STATE_AUX,
+                                       hph_mode);
+
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_ANA_CLK_CTL,
+                                             BIT(2), 0x00);
+               break;
+       }
+
+       return 0;
+}
+
+static int wcd937x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *kcontrol,
+                                       int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+       int hph_mode = wcd937x->hph_mode;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+                                       WCD_CLSH_EVENT_PRE_DAC,
+                                       WCD_CLSH_STATE_HPHR,
+                                       hph_mode);
+               snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+                                             BIT(4), BIT(4));
+               usleep_range(100, 110);
+               set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_PDM_WD_CTL1,
+                                             0x07, 0x03);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+                       if (wcd937x->comp2_enable)
+                               usleep_range(7000, 7100);
+                       else
+                               usleep_range(20000, 20100);
+                       clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+               }
+
+               snd_soc_component_update_bits(component,
+                                             WCD937X_HPH_NEW_INT_HPH_TIMER1,
+                                             BIT(1), BIT(1));
+               if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_ANA_RX_SUPPLIES,
+                                                     BIT(1), BIT(1));
+               enable_irq(wcd937x->hphr_pdm_wd_int);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               disable_irq_nosync(wcd937x->hphr_pdm_wd_int);
+               set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+               wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHR_PA_OFF);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+                       if (wcd937x->comp2_enable)
+                               usleep_range(7000, 7100);
+                       else
+                               usleep_range(20000, 20100);
+                       clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+               }
+
+               wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHR_PA_OFF);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_PDM_WD_CTL1, 0x07, 0x00);
+               snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+                                             BIT(4), 0x00);
+               wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+                                       WCD_CLSH_EVENT_POST_PA,
+                                       WCD_CLSH_STATE_HPHR,
+                                       hph_mode);
+               break;
+       }
+
+       return 0;
+}
+
+static int wcd937x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w,
+                                       struct snd_kcontrol *kcontrol,
+                                       int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+       int hph_mode = wcd937x->hph_mode;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+                                       WCD_CLSH_EVENT_PRE_DAC,
+                                       WCD_CLSH_STATE_HPHL,
+                                       hph_mode);
+               snd_soc_component_update_bits(component, WCD937X_ANA_HPH,
+                                             BIT(5), BIT(5));
+               usleep_range(100, 110);
+               set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x03);
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+                       if (!wcd937x->comp1_enable)
+                               usleep_range(20000, 20100);
+                       else
+                               usleep_range(7000, 7100);
+                       clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+               }
+
+               snd_soc_component_update_bits(component,
+                                             WCD937X_HPH_NEW_INT_HPH_TIMER1,
+                                             BIT(1), BIT(1));
+               if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_ANA_RX_SUPPLIES,
+                                                     BIT(1), BIT(1));
+               enable_irq(wcd937x->hphl_pdm_wd_int);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+               set_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+               wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_PRE_HPHL_PA_OFF);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) {
+                       if (!wcd937x->comp1_enable)
+                               usleep_range(20000, 20100);
+                       else
+                               usleep_range(7000, 7100);
+                       clear_bit(HPH_PA_DELAY, &wcd937x->status_mask);
+               }
+
+               wcd_mbhc_event_notify(wcd937x->wcd_mbhc, WCD_EVENT_POST_HPHL_PA_OFF);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_PDM_WD_CTL0, 0x07, 0x00);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_ANA_HPH, BIT(5), 0x00);
+               wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+                                       WCD_CLSH_EVENT_POST_PA,
+                                       WCD_CLSH_STATE_HPHL,
+                                       hph_mode);
+               break;
+       }
+
+       return 0;
+}
+
+static int wcd937x_codec_enable_aux_pa(struct snd_soc_dapm_widget *w,
+                                      struct snd_kcontrol *kcontrol,
+                                      int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+       int hph_mode = wcd937x->hph_mode;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_PDM_WD_CTL2,
+                                             BIT(0), BIT(0));
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               usleep_range(1000, 1010);
+               if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_ANA_RX_SUPPLIES,
+                                                     BIT(1), BIT(1));
+               enable_irq(wcd937x->aux_pdm_wd_int);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               usleep_range(2000, 2010);
+               wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+                                       WCD_CLSH_EVENT_POST_PA,
+                                       WCD_CLSH_STATE_AUX,
+                                       hph_mode);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_PDM_WD_CTL2,
+                                             BIT(0), 0x00);
+               break;
+       }
+
+       return 0;
+}
+
+static int wcd937x_codec_enable_ear_pa(struct snd_soc_dapm_widget *w,
+                                      struct snd_kcontrol *kcontrol,
+                                      int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+       int hph_mode = wcd937x->hph_mode;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               /* Enable watchdog interrupt for HPHL or AUX depending on mux value */
+               wcd937x->ear_rx_path = snd_soc_component_read(component,
+                                                             WCD937X_DIGITAL_CDC_EAR_PATH_CTL);
+
+               if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_PDM_WD_CTL2,
+                                                     BIT(0), BIT(0));
+               else
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_PDM_WD_CTL0,
+                                                     0x07, 0x03);
+               if (!wcd937x->comp1_enable)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_ANA_EAR_COMPANDER_CTL,
+                                                     BIT(7), BIT(7));
+               break;
+       case SND_SOC_DAPM_POST_PMU:
+               usleep_range(6000, 6010);
+               if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_ANA_RX_SUPPLIES,
+                                                     BIT(1), BIT(1));
+
+               if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+                       enable_irq(wcd937x->aux_pdm_wd_int);
+               else
+                       enable_irq(wcd937x->hphl_pdm_wd_int);
+               break;
+       case SND_SOC_DAPM_PRE_PMD:
+               if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+                       disable_irq_nosync(wcd937x->aux_pdm_wd_int);
+               else
+                       disable_irq_nosync(wcd937x->hphl_pdm_wd_int);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               if (!wcd937x->comp1_enable)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_ANA_EAR_COMPANDER_CTL,
+                                                     BIT(7), 0x00);
+               usleep_range(7000, 7010);
+               wcd_clsh_ctrl_set_state(wcd937x->clsh_info,
+                                       WCD_CLSH_EVENT_POST_PA,
+                                       WCD_CLSH_STATE_EAR,
+                                       hph_mode);
+               snd_soc_component_update_bits(component, WCD937X_FLYBACK_EN,
+                                             BIT(2), BIT(2));
+
+               if (wcd937x->ear_rx_path & EAR_RX_PATH_AUX)
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_PDM_WD_CTL2,
+                                                     BIT(0), 0x00);
+               else
+                       snd_soc_component_update_bits(component,
+                                                     WCD937X_DIGITAL_PDM_WD_CTL0,
+                                                     0x07, 0x00);
+               break;
+       }
+
+       return 0;
+}
+
+static int wcd937x_enable_rx1(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *kcontrol,
+                             int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+       if (event == SND_SOC_DAPM_POST_PMD) {
+               wcd937x_rx_clk_disable(component);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+                                             BIT(0), 0x00);
+       }
+
+       return 0;
+}
+
+static int wcd937x_enable_rx2(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *kcontrol, int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+       if (event == SND_SOC_DAPM_POST_PMD) {
+               wcd937x_rx_clk_disable(component);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+                                             BIT(1), 0x00);
+       }
+
+       return 0;
+}
+
+static int wcd937x_enable_rx3(struct snd_soc_dapm_widget *w,
+                             struct snd_kcontrol *kcontrol,
+                             int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+
+       if (event == SND_SOC_DAPM_POST_PMD) {
+               usleep_range(6000, 6010);
+               wcd937x_rx_clk_disable(component);
+               snd_soc_component_update_bits(component,
+                                             WCD937X_DIGITAL_CDC_DIG_CLK_CTL,
+                                             BIT(2), 0x00);
+       }
+
+       return 0;
+}
+
+static int wcd937x_codec_enable_vdd_buck(struct snd_soc_dapm_widget *w,
+                                        struct snd_kcontrol *kcontrol,
+                                        int event)
+{
+       struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm);
+       struct wcd937x_priv *wcd937x = snd_soc_component_get_drvdata(component);
+       int ret = 0;
+
+       switch (event) {
+       case SND_SOC_DAPM_PRE_PMU:
+               if (test_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask)) {
+                       dev_err(component->dev, "buck already in enabled state\n");
+                       clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask);
+                       return 0;
+               }
+               ret = regulator_enable(wcd937x->buck_supply);
+               if (ret) {
+                       dev_err(component->dev, "VDD_BUCK is not enabled\n");
+                       return ret;
+               }
+               clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask);
+               usleep_range(200, 250);
+               break;
+       case SND_SOC_DAPM_POST_PMD:
+               set_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask);
+               break;
+       }
+
+       return 0;
+}
+
 static int wcd937x_get_micb_vout_ctl_val(u32 micb_mv)
 {
        if (micb_mv < 1000 || micb_mv > 2850) {
@@ -1349,6 +1912,108 @@ static const struct snd_kcontrol_new wcd937x_snd_controls[] = {
                       wcd937x_get_swr_port, wcd937x_set_swr_port),
 };
 
+static const struct snd_kcontrol_new ear_rdac_switch[] = {
+       SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new aux_rdac_switch[] = {
+       SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphl_rdac_switch[] = {
+       SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const struct snd_kcontrol_new hphr_rdac_switch[] = {
+       SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
+};
+
+static const char * const rdac3_mux_text[] = {
+       "RX1", "RX3"
+};
+
+static const struct soc_enum rdac3_enum =
+       SOC_ENUM_SINGLE(WCD937X_DIGITAL_CDC_EAR_PATH_CTL, 0,
+                       ARRAY_SIZE(rdac3_mux_text), rdac3_mux_text);
+
+static const struct snd_kcontrol_new rx_rdac3_mux = SOC_DAPM_ENUM("RDAC3_MUX Mux", rdac3_enum);
+
+static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = {
+       /* Input widgets */
+       SND_SOC_DAPM_INPUT("IN1_HPHL"),
+       SND_SOC_DAPM_INPUT("IN2_HPHR"),
+       SND_SOC_DAPM_INPUT("IN3_AUX"),
+
+       SND_SOC_DAPM_SUPPLY("VDD_BUCK", SND_SOC_NOPM, 0, 0,
+                           wcd937x_codec_enable_vdd_buck,
+                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, NULL, 0),
+
+       /* RX widgets */
+       SND_SOC_DAPM_PGA_E("EAR PGA", WCD937X_ANA_EAR, 7, 0, NULL, 0,
+                          wcd937x_codec_enable_ear_pa,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("AUX PGA", WCD937X_AUX_AUXPA, 7, 0, NULL, 0,
+                          wcd937x_codec_enable_aux_pa,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("HPHL PGA", WCD937X_ANA_HPH, 7, 0, NULL, 0,
+                          wcd937x_codec_enable_hphl_pa,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_PGA_E("HPHR PGA", WCD937X_ANA_HPH, 6, 0, NULL, 0,
+                          wcd937x_codec_enable_hphr_pa,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_DAC_E("RDAC1", NULL, SND_SOC_NOPM, 0, 0,
+                          wcd937x_codec_hphl_dac_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_DAC_E("RDAC2", NULL, SND_SOC_NOPM, 0, 0,
+                          wcd937x_codec_hphr_dac_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_DAC_E("RDAC3", NULL, SND_SOC_NOPM, 0, 0,
+                          wcd937x_codec_ear_dac_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_DAC_E("RDAC4", NULL, SND_SOC_NOPM, 0, 0,
+                          wcd937x_codec_aux_dac_event,
+                          SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
+                          SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
+
+       SND_SOC_DAPM_MUX("RDAC3_MUX", SND_SOC_NOPM, 0, 0, &rx_rdac3_mux),
+
+       SND_SOC_DAPM_MIXER_E("RX1", SND_SOC_NOPM, 0, 0, NULL, 0,
+                            wcd937x_enable_rx1, SND_SOC_DAPM_PRE_PMU |
+                            SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER_E("RX2", SND_SOC_NOPM, 0, 0, NULL, 0,
+                            wcd937x_enable_rx2, SND_SOC_DAPM_PRE_PMU |
+                            SND_SOC_DAPM_POST_PMD),
+       SND_SOC_DAPM_MIXER_E("RX3", SND_SOC_NOPM, 0, 0, NULL, 0,
+                            wcd937x_enable_rx3, SND_SOC_DAPM_PRE_PMU |
+                            SND_SOC_DAPM_POST_PMD),
+
+       /* RX mixer widgets*/
+       SND_SOC_DAPM_MIXER("EAR_RDAC", SND_SOC_NOPM, 0, 0,
+                          ear_rdac_switch, ARRAY_SIZE(ear_rdac_switch)),
+       SND_SOC_DAPM_MIXER("AUX_RDAC", SND_SOC_NOPM, 0, 0,
+                          aux_rdac_switch, ARRAY_SIZE(aux_rdac_switch)),
+       SND_SOC_DAPM_MIXER("HPHL_RDAC", SND_SOC_NOPM, 0, 0,
+                          hphl_rdac_switch, ARRAY_SIZE(hphl_rdac_switch)),
+       SND_SOC_DAPM_MIXER("HPHR_RDAC", SND_SOC_NOPM, 0, 0,
+                          hphr_rdac_switch, ARRAY_SIZE(hphr_rdac_switch)),
+
+       /* RX output widgets */
+       SND_SOC_DAPM_OUTPUT("EAR"),
+       SND_SOC_DAPM_OUTPUT("AUX"),
+       SND_SOC_DAPM_OUTPUT("HPHL"),
+       SND_SOC_DAPM_OUTPUT("HPHR"),
+};
+
 static int wcd937x_set_micbias_data(struct wcd937x_priv *wcd937x)
 {
        int vout_ctl[3];
@@ -1517,6 +2182,8 @@ static const struct snd_soc_component_driver soc_codec_dev_wcd937x = {
        .remove = wcd937x_soc_codec_remove,
        .controls = wcd937x_snd_controls,
        .num_controls = ARRAY_SIZE(wcd937x_snd_controls),
+       .dapm_widgets = wcd937x_dapm_widgets,
+       .num_dapm_widgets = ARRAY_SIZE(wcd937x_dapm_widgets),
        .set_jack = wcd937x_codec_set_jack,
        .endianness = 1,
 };