diff --git a/asoc/codecs/bolero/rx-macro.c b/asoc/codecs/bolero/rx-macro.c index 5574174702..8aca6fdc1f 100644 --- a/asoc/codecs/bolero/rx-macro.c +++ b/asoc/codecs/bolero/rx-macro.c @@ -1413,8 +1413,6 @@ static int rx_macro_config_compander(struct snd_soc_codec *codec, if (SND_SOC_DAPM_EVENT_OFF(event)) { snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x04); snd_soc_update_bits(codec, rx_path_cfg0_reg, 0x02, 0x00); - snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x02); - snd_soc_update_bits(codec, comp_ctl0_reg, 0x02, 0x00); snd_soc_update_bits(codec, comp_ctl0_reg, 0x01, 0x00); snd_soc_update_bits(codec, comp_ctl0_reg, 0x04, 0x00); } @@ -2021,7 +2019,7 @@ static void rx_macro_hphdelay_lutbypass(struct snd_soc_codec *codec, static int rx_macro_enable_interp_clk(struct snd_soc_codec *codec, int event, int interp_idx) { - u16 main_reg = 0; + u16 main_reg = 0, dsm_reg = 0, rx_cfg2_reg = 0; struct device *rx_dev = NULL; struct rx_macro_priv *rx_priv = NULL; @@ -2035,13 +2033,19 @@ static int rx_macro_enable_interp_clk(struct snd_soc_codec *codec, main_reg = BOLERO_CDC_RX_RX0_RX_PATH_CTL + (interp_idx * RX_MACRO_RX_PATH_OFFSET); + dsm_reg = BOLERO_CDC_RX_RX0_RX_PATH_DSM_CTL + + (interp_idx * RX_MACRO_RX_PATH_OFFSET); + rx_cfg2_reg = BOLERO_CDC_RX_RX0_RX_PATH_CFG2 + + (interp_idx * RX_MACRO_RX_PATH_OFFSET); if (SND_SOC_DAPM_EVENT_ON(event)) { if (rx_priv->main_clk_users[interp_idx] == 0) { + snd_soc_update_bits(codec, dsm_reg, 0x01, 0x01); /* Main path PGA mute enable */ snd_soc_update_bits(codec, main_reg, 0x10, 0x10); /* Clk enable */ snd_soc_update_bits(codec, main_reg, 0x20, 0x20); + snd_soc_update_bits(codec, rx_cfg2_reg, 0x03, 0x03); rx_macro_idle_detect_control(codec, rx_priv, interp_idx, event); if (rx_priv->hph_hd2_mode) @@ -2063,6 +2067,15 @@ static int rx_macro_enable_interp_clk(struct snd_soc_codec *codec, rx_priv->main_clk_users[interp_idx]--; if (rx_priv->main_clk_users[interp_idx] <= 0) { rx_priv->main_clk_users[interp_idx] = 0; + /* Clk Disable */ + snd_soc_update_bits(codec, dsm_reg, 0x01, 0x00); + snd_soc_update_bits(codec, main_reg, 0x20, 0x00); + /* Reset enable and disable */ + snd_soc_update_bits(codec, main_reg, 0x40, 0x40); + snd_soc_update_bits(codec, main_reg, 0x40, 0x00); + /* Reset rate to 48K*/ + snd_soc_update_bits(codec, main_reg, 0x0F, 0x04); + snd_soc_update_bits(codec, rx_cfg2_reg, 0x03, 0x00); rx_macro_config_classh(codec, rx_priv, interp_idx, event); rx_macro_config_compander(codec, rx_priv, @@ -2076,13 +2089,6 @@ static int rx_macro_enable_interp_clk(struct snd_soc_codec *codec, rx_macro_hd2_control(codec, interp_idx, event); rx_macro_idle_detect_control(codec, rx_priv, interp_idx, event); - /* Clk Disable */ - snd_soc_update_bits(codec, main_reg, 0x20, 0x00); - /* Reset enable and disable */ - snd_soc_update_bits(codec, main_reg, 0x40, 0x40); - snd_soc_update_bits(codec, main_reg, 0x40, 0x00); - /* Reset rate to 48K*/ - snd_soc_update_bits(codec, main_reg, 0x0F, 0x04); } } diff --git a/asoc/codecs/wcd937x/internal.h b/asoc/codecs/wcd937x/internal.h index d7121293e2..f1a752bc8c 100644 --- a/asoc/codecs/wcd937x/internal.h +++ b/asoc/codecs/wcd937x/internal.h @@ -68,6 +68,8 @@ struct wcd937x_priv { struct wcd_irq_info irq_info; u32 rx_clk_cnt; int num_irq_regs; + /* to track the status */ + unsigned long status_mask; u8 num_tx_ports; u8 num_rx_ports; diff --git a/asoc/codecs/wcd937x/wcd937x.c b/asoc/codecs/wcd937x/wcd937x.c index 0d88e67b0a..27e3cfaaa9 100644 --- a/asoc/codecs/wcd937x/wcd937x.c +++ b/asoc/codecs/wcd937x/wcd937x.c @@ -18,10 +18,11 @@ #include #include #include +#include +#include #include #include #include -#include #include #include #include "internal.h" @@ -45,6 +46,12 @@ enum { CODEC_RX, }; +enum { + ALLOW_BUCK_DISABLE, + HPH_COMP_DELAY, + HPH_PA_DELAY, +}; + static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1); static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1); @@ -374,7 +381,6 @@ static int wcd937x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec); int hph_mode = wcd937x->hph_mode; - int ret = 0; dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__, w->name, event); @@ -388,6 +394,7 @@ static int wcd937x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, 0x04, 0x04); snd_soc_update_bits(codec, WCD937X_HPH_RDAC_CLK_CTL1, 0x80, 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) @@ -404,6 +411,22 @@ static int wcd937x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, 0x02, 0x02); snd_soc_update_bits(codec, WCD937X_HPH_L_EN, 0x20, 0x00); + if (wcd937x->comp2_enable) { + snd_soc_update_bits(codec, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x01, 0x01); + snd_soc_update_bits(codec, + WCD937X_HPH_R_EN, 0x20, 0x00); + } + /* + * 5ms sleep is required after COMP is enabled as per + * HW requirement + */ + if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) { + usleep_range(5000, 5100); + clear_bit(HPH_COMP_DELAY, + &wcd937x->status_mask); + } } else { snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_COMP_CTL_0, @@ -411,25 +434,17 @@ static int wcd937x_codec_hphl_dac_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD937X_HPH_L_EN, 0x20, 0x20); } - usleep_range(5000, 5010); snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00); - wcd_cls_h_fsm(codec, &wcd937x->clsh_info, - WCD_CLSH_EVENT_PRE_DAC, - WCD_CLSH_STATE_HPHL, - hph_mode); break; case SND_SOC_DAPM_POST_PMD: snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x0F, 0x01); - ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev, - wcd937x->rx_swr_dev->dev_num, - false); break; } - return ret; + return 0; } static int wcd937x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, @@ -439,8 +454,6 @@ static int wcd937x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec); int hph_mode = wcd937x->hph_mode; - int ret = 0; - dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__, w->name, event); @@ -454,6 +467,7 @@ static int wcd937x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, 0x08, 0x08); snd_soc_update_bits(codec, WCD937X_HPH_RDAC_CLK_CTL1, 0x80, 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) @@ -470,6 +484,22 @@ static int wcd937x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, 0x01, 0x01); snd_soc_update_bits(codec, WCD937X_HPH_R_EN, 0x20, 0x00); + if (wcd937x->comp1_enable) { + snd_soc_update_bits(codec, + WCD937X_DIGITAL_CDC_COMP_CTL_0, + 0x02, 0x02); + snd_soc_update_bits(codec, + WCD937X_HPH_L_EN, 0x20, 0x00); + } + /* + * 5ms sleep is required after COMP is enabled as per + * HW requirement + */ + if (test_bit(HPH_COMP_DELAY, &wcd937x->status_mask)) { + usleep_range(5000, 5100); + clear_bit(HPH_COMP_DELAY, + &wcd937x->status_mask); + } } else { snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_COMP_CTL_0, @@ -477,25 +507,17 @@ static int wcd937x_codec_hphr_dac_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD937X_HPH_R_EN, 0x20, 0x20); } - usleep_range(5000, 5010); snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x00); - wcd_cls_h_fsm(codec, &wcd937x->clsh_info, - WCD_CLSH_EVENT_PRE_DAC, - WCD_CLSH_STATE_HPHR, - hph_mode); break; case SND_SOC_DAPM_POST_PMD: snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_R, 0x0F, 0x01); - ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev, - wcd937x->rx_swr_dev->dev_num, - false); break; } - return ret; + return 0; } static int wcd937x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, @@ -505,7 +527,6 @@ static int wcd937x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec); int hph_mode = wcd937x->hph_mode; - int ret = 0; dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__, w->name, event); @@ -540,12 +561,9 @@ static int wcd937x_codec_ear_dac_event(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_RDAC_HD2_CTL_L, 0x0F, 0x01); - ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev, - wcd937x->rx_swr_dev->dev_num, - false); break; }; - return ret; + return 0; } @@ -556,7 +574,6 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); struct wcd937x_priv *wcd937x = snd_soc_codec_get_drvdata(codec); int hph_mode = wcd937x->hph_mode; - int ret = 0; dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__, w->name, event); @@ -577,15 +594,12 @@ static int wcd937x_codec_aux_dac_event(struct snd_soc_dapm_widget *w, break; case SND_SOC_DAPM_POST_PMD: - ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev, - wcd937x->rx_swr_dev->dev_num, - false); wcd937x_rx_clk_disable(codec); snd_soc_update_bits(codec, WCD937X_DIGITAL_CDC_ANA_CLK_CTL, 0x04, 0x00); break; }; - return ret; + return 0; } @@ -603,14 +617,31 @@ static int wcd937x_codec_enable_hphr_pa(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev, + wcd937x->rx_swr_dev->dev_num, + true); + wcd_cls_h_fsm(codec, &wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHR, + hph_mode); snd_soc_update_bits(codec, WCD937X_ANA_HPH, 0x10, 0x10); usleep_range(100, 110); - ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev, - wcd937x->rx_swr_dev->dev_num, - true); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); break; case SND_SOC_DAPM_POST_PMU: - usleep_range(7000, 7010); + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + if (test_bit(HPH_PA_DELAY, &wcd937x->status_mask)) { + if (!wcd937x->comp2_enable) + usleep_range(20000, 20100); + else + usleep_range(7000, 7100); + clear_bit(HPH_PA_DELAY, &wcd937x->status_mask); + } + snd_soc_update_bits(codec, WCD937X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x02); if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) @@ -654,16 +685,36 @@ static int wcd937x_codec_enable_hphl_pa(struct snd_soc_dapm_widget *w, int ret = 0; int hph_mode = wcd937x->hph_mode; + dev_dbg(codec->dev, "%s wname: %s event: %d\n", __func__, + w->name, event); + switch (event) { case SND_SOC_DAPM_PRE_PMU: - snd_soc_update_bits(codec, WCD937X_ANA_HPH, 0x20, 0x20); - usleep_range(100, 110); ret = swr_slvdev_datapath_control(wcd937x->rx_swr_dev, wcd937x->rx_swr_dev->dev_num, true); + wcd_cls_h_fsm(codec, &wcd937x->clsh_info, + WCD_CLSH_EVENT_PRE_DAC, + WCD_CLSH_STATE_HPHL, + hph_mode); + snd_soc_update_bits(codec, WCD937X_ANA_HPH, 0x20, 0x20); + usleep_range(100, 110); + set_bit(HPH_PA_DELAY, &wcd937x->status_mask); break; case SND_SOC_DAPM_POST_PMU: - usleep_range(7000, 7010); + /* + * 7ms sleep is required after PA is enabled as per + * HW requirement. If compander is disabled, then + * 20ms delay is required. + */ + 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_update_bits(codec, WCD937X_HPH_NEW_INT_HPH_TIMER1, 0x02, 0x02); if (hph_mode == CLS_AB || hph_mode == CLS_AB_HIFI) @@ -805,12 +856,12 @@ static int wcd937x_enable_clsh(struct snd_soc_dapm_widget *w, mode == CLS_H_HIFI || mode == CLS_H_LP) { wcd937x_rx_connect_port(codec, CLSH, SND_SOC_DAPM_EVENT_ON(event)); - if (SND_SOC_DAPM_EVENT_OFF(event)) - ret = swr_slvdev_datapath_control( - wcd937x->rx_swr_dev, - wcd937x->rx_swr_dev->dev_num, - false); } + if (SND_SOC_DAPM_EVENT_OFF(event)) + ret = swr_slvdev_datapath_control( + wcd937x->rx_swr_dev, + wcd937x->rx_swr_dev->dev_num, + false); return ret; } @@ -1454,6 +1505,12 @@ static int wcd937x_codec_enable_vdd_buck(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_PRE_PMU: + if (test_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask)) { + dev_dbg(codec->dev, + "%s: buck already in enabled state\n", + __func__); + return 0; + } ret = msm_cdc_enable_ondemand_supply(wcd937x->dev, wcd937x->supplies, pdata->regulator, @@ -1464,6 +1521,7 @@ static int wcd937x_codec_enable_vdd_buck(struct snd_soc_dapm_widget *w, __func__); return ret; } + clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); /* * 200us sleep is required after LDO15 is enabled as per * HW requirement @@ -1471,17 +1529,7 @@ static int wcd937x_codec_enable_vdd_buck(struct snd_soc_dapm_widget *w, usleep_range(200, 250); break; case SND_SOC_DAPM_POST_PMD: - ret = msm_cdc_disable_ondemand_supply(wcd937x->dev, - wcd937x->supplies, - pdata->regulator, - pdata->num_supplies, - "cdc-vdd-buck"); - if (ret == -EINVAL) { - dev_err(codec->dev, "%s: vdd buck is not enabled\n", - __func__); - return ret; - } - + set_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); break; } return 0; @@ -1643,7 +1691,7 @@ static const struct snd_soc_dapm_widget wcd937x_dapm_widgets[] = { wcd937x_codec_enable_vdd_buck, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), - SND_SOC_DAPM_SUPPLY("CLS_H_PORT", SND_SOC_NOPM, 0, 0, + SND_SOC_DAPM_SUPPLY_S("CLS_H_PORT", 1, SND_SOC_NOPM, 0, 0, wcd937x_enable_clsh, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), @@ -1792,7 +1840,6 @@ static const struct snd_soc_dapm_widget wcd9375_dapm_widgets[] = { }; static const struct snd_soc_dapm_route wcd937x_audio_map[] = { - {"ADC1_OUTPUT", NULL, "ADC1_MIXER"}, {"ADC1_MIXER", "Switch", "ADC1 REQ"}, {"ADC1 REQ", NULL, "ADC1"}, @@ -1805,18 +1852,24 @@ static const struct snd_soc_dapm_route wcd937x_audio_map[] = { {"ADC2 MUX", "INP3", "AMIC3"}, {"ADC2 MUX", "INP2", "AMIC2"}, + {"IN1_HPHL", NULL, "VDD_BUCK"}, + {"IN1_HPHL", NULL, "CLS_H_PORT"}, {"RX1", NULL, "IN1_HPHL"}, {"RDAC1", NULL, "RX1"}, {"HPHL_RDAC", "Switch", "RDAC1"}, {"HPHL PGA", NULL, "HPHL_RDAC"}, {"HPHL", NULL, "HPHL PGA"}, + {"IN2_HPHR", NULL, "VDD_BUCK"}, + {"IN2_HPHR", NULL, "CLS_H_PORT"}, {"RX2", NULL, "IN2_HPHR"}, {"RDAC2", NULL, "RX2"}, {"HPHR_RDAC", "Switch", "RDAC2"}, {"HPHR PGA", NULL, "HPHR_RDAC"}, {"HPHR", NULL, "HPHR PGA"}, + {"IN3_AUX", NULL, "VDD_BUCK"}, + {"IN3_AUX", NULL, "CLS_H_PORT"}, {"RX3", NULL, "IN3_AUX"}, {"RDAC4", NULL, "RX3"}, {"AUX_RDAC", "Switch", "RDAC4"}, @@ -1829,16 +1882,6 @@ static const struct snd_soc_dapm_route wcd937x_audio_map[] = { {"EAR_RDAC", "Switch", "RDAC3"}, {"EAR PGA", NULL, "EAR_RDAC"}, {"EAR", NULL, "EAR PGA"}, - - {"EAR", NULL, "VDD_BUCK"}, - {"HPHR", NULL, "VDD_BUCK"}, - {"HPHL", NULL, "VDD_BUCK"}, - {"AUX", NULL, "VDD_BUCK"}, - - {"EAR", NULL, "CLS_H_PORT"}, - {"HPHR", NULL, "CLS_H_PORT"}, - {"HPHL", NULL, "CLS_H_PORT"}, - {"AUX", NULL, "CLS_H_PORT"}, }; static const struct snd_soc_dapm_route wcd9375_audio_map[] = { @@ -2097,6 +2140,49 @@ static struct snd_soc_codec_driver soc_codec_dev_wcd937x = { }, }; +#ifdef CONFIG_PM_SLEEP +static int wcd937x_suspend(struct device *dev) +{ + struct wcd937x_priv *wcd937x = NULL; + int ret = 0; + struct wcd937x_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd937x = dev_get_drvdata(dev); + if (!wcd937x) + return -EINVAL; + + pdata = dev_get_platdata(wcd937x->dev); + + if (!pdata) { + dev_err(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask)) { + ret = msm_cdc_disable_ondemand_supply(wcd937x->dev, + wcd937x->supplies, + pdata->regulator, + pdata->num_supplies, + "cdc-vdd-buck"); + if (ret == -EINVAL) { + dev_err(dev, "%s: vdd buck is not disabled\n", + __func__); + return 0; + } + clear_bit(ALLOW_BUCK_DISABLE, &wcd937x->status_mask); + } + return 0; +} + +static int wcd937x_resume(struct device *dev) +{ + return 0; +} +#endif + static int wcd937x_reset(struct device *dev) { struct wcd937x_priv *wcd937x = NULL; @@ -2490,6 +2576,15 @@ static int wcd937x_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static const struct dev_pm_ops wcd937x_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS( + wcd937x_suspend, + wcd937x_resume + ) +}; +#endif + static struct platform_driver wcd937x_codec_driver = { .probe = wcd937x_probe, .remove = wcd937x_remove, @@ -2497,6 +2592,9 @@ static struct platform_driver wcd937x_codec_driver = { .name = "wcd937x_codec", .owner = THIS_MODULE, .of_match_table = of_match_ptr(wcd937x_dt_match), +#ifdef CONFIG_PM_SLEEP + .pm = &wcd937x_dev_pm_ops, +#endif }, };