diff --git a/asoc/codecs/msm-cdc-supply.c b/asoc/codecs/msm-cdc-supply.c index 230a7f9981..1618b83a55 100644 --- a/asoc/codecs/msm-cdc-supply.c +++ b/asoc/codecs/msm-cdc-supply.c @@ -60,9 +60,22 @@ static int msm_cdc_dt_parse_vreg_info(struct device *dev, } cdc_vreg->optimum_uA = prop_val; - dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d\n", + /* Parse supply - LPM or NOM mode(default NOM) */ + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-lpm-supported", name); + rc = of_property_read_u32(dev->of_node, prop_name, &prop_val); + if (rc) { + dev_dbg(dev, "%s: Looking up %s property in node %s failed", + __func__, prop_name, dev->of_node->full_name); + cdc_vreg->lpm_supported = 0; + rc = 0; + } else { + cdc_vreg->lpm_supported = prop_val; + } + + dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d lpm %d\n", __func__, cdc_vreg->name, cdc_vreg->min_uV, cdc_vreg->max_uV, - cdc_vreg->optimum_uA, cdc_vreg->ondemand); + cdc_vreg->optimum_uA, cdc_vreg->ondemand, + cdc_vreg->lpm_supported); done: return rc; @@ -260,6 +273,59 @@ int msm_cdc_enable_ondemand_supply(struct device *dev, } EXPORT_SYMBOL(msm_cdc_enable_ondemand_supply); +/* + * msm_cdc_set_supplies_lpm_mode: + * Update load for given supply string + * + * @dev: pointer to codec device + * @supplies: pointer to regulator bulk data + * @cdc_vreg: pointer to platform regulator data + * @num_supplies: number of supplies + * @supply_name: supply name to be checked + * @min_max: Apply optimum or 0 current + * + * Return error code if set current fail + */ +int msm_cdc_set_supplies_lpm_mode(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + bool flag) +{ + int rc = 0, i; + + if (!supplies) { + pr_err("%s: supplies is NULL\n", + __func__); + return -EINVAL; + } + /* input parameter validation */ + rc = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (rc) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].lpm_supported) { + rc = regulator_set_load( + supplies[i].consumer, + flag ? 0 : cdc_vreg[i].optimum_uA); + if (rc) + dev_err(dev, + "%s: failed to set supply %s to %s, err:%d\n", + __func__, supplies[i].supply, + flag ? "LPM" : "NOM", + rc); + else + dev_dbg(dev, "%s: regulator %s load set to %s\n", + __func__, supplies[i].supply, + flag ? "LPM" : "NOM"); + } + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_set_supplies_lpm_mode); + /* * msm_cdc_disable_static_supplies: * Disable codec static supplies diff --git a/asoc/codecs/wcd938x/internal.h b/asoc/codecs/wcd938x/internal.h index 0baf0ded9b..84a8a42409 100644 --- a/asoc/codecs/wcd938x/internal.h +++ b/asoc/codecs/wcd938x/internal.h @@ -73,6 +73,7 @@ struct wcd938x_priv { bool comp2_enable; bool ldoh; bool bcs_dis; + bool dapm_bias_off; struct irq_domain *virq; struct wcd_irq_info irq_info; u32 rx_clk_cnt; diff --git a/asoc/codecs/wcd938x/wcd938x.c b/asoc/codecs/wcd938x/wcd938x.c index a6652bd4e4..2ed99ea0c5 100644 --- a/asoc/codecs/wcd938x/wcd938x.c +++ b/asoc/codecs/wcd938x/wcd938x.c @@ -72,6 +72,7 @@ enum { HPH_COMP_DELAY, HPH_PA_DELAY, AMIC2_BCS_ENABLE, + WCD_SUPPLIES_LPM_MODE, }; enum { @@ -3713,6 +3714,26 @@ static void wcd938x_soc_codec_remove(struct snd_soc_component *component) false); } +static int wcd938x_soc_codec_suspend(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) + return 0; + wcd938x->dapm_bias_off = true; + return 0; +} + +static int wcd938x_soc_codec_resume(struct snd_soc_component *component) +{ + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + + if (!wcd938x) + return 0; + wcd938x->dapm_bias_off = false; + return 0; +} + static struct snd_soc_component_driver soc_codec_dev_wcd938x = { .name = WCD938X_DRV_NAME, .probe = wcd938x_soc_codec_probe, @@ -3723,6 +3744,8 @@ static struct snd_soc_component_driver soc_codec_dev_wcd938x = { .num_dapm_widgets = ARRAY_SIZE(wcd938x_dapm_widgets), .dapm_routes = wcd938x_audio_map, .num_dapm_routes = ARRAY_SIZE(wcd938x_audio_map), + .suspend = wcd938x_soc_codec_suspend, + .resume = wcd938x_soc_codec_resume, }; static int wcd938x_reset(struct device *dev) @@ -4242,19 +4265,51 @@ static int wcd938x_suspend(struct device *dev) } clear_bit(ALLOW_BUCK_DISABLE, &wcd938x->status_mask); } + if (wcd938x->dapm_bias_off) { + msm_cdc_set_supplies_lpm_mode(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + true); + set_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask); + } return 0; } static int wcd938x_resume(struct device *dev) { + struct wcd938x_priv *wcd938x = NULL; + struct wcd938x_pdata *pdata = NULL; + + if (!dev) + return -ENODEV; + + wcd938x = dev_get_drvdata(dev); + if (!wcd938x) + return -EINVAL; + + pdata = dev_get_platdata(wcd938x->dev); + + if (!pdata) { + dev_err(dev, "%s: pdata is NULL\n", __func__); + return -EINVAL; + } + + if (test_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask)) { + msm_cdc_set_supplies_lpm_mode(wcd938x->dev, + wcd938x->supplies, + pdata->regulator, + pdata->num_supplies, + false); + clear_bit(WCD_SUPPLIES_LPM_MODE, &wcd938x->status_mask); + } + return 0; } static const struct dev_pm_ops wcd938x_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS( - wcd938x_suspend, - wcd938x_resume - ) + .suspend_late = wcd938x_suspend, + .resume_early = wcd938x_resume, }; #endif diff --git a/asoc/codecs/wsa883x/internal.h b/asoc/codecs/wsa883x/internal.h index 4868d2df83..3dc362784d 100644 --- a/asoc/codecs/wsa883x/internal.h +++ b/asoc/codecs/wsa883x/internal.h @@ -97,6 +97,7 @@ struct wsa883x_priv { bool comp_enable; bool visense_enable; bool ext_vdd_spk; + bool dapm_bias_off; struct swr_port port[WSA883X_MAX_SWR_PORTS]; int global_pa_cnt; int dev_mode; diff --git a/asoc/codecs/wsa883x/wsa883x.c b/asoc/codecs/wsa883x/wsa883x.c index de83f2c535..8b3d588130 100644 --- a/asoc/codecs/wsa883x/wsa883x.c +++ b/asoc/codecs/wsa883x/wsa883x.c @@ -132,6 +132,7 @@ enum { enum { SPKR_STATUS = 0, + WSA_SUPPLIES_LPM_MODE, }; enum { @@ -1220,6 +1221,28 @@ static void wsa883x_codec_remove(struct snd_soc_component *component) return; } +static int wsa883x_soc_codec_suspend(struct snd_soc_component *component) +{ + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + if (!wsa883x) + return 0; + + wsa883x->dapm_bias_off = true; + return 0; +} + +static int wsa883x_soc_codec_resume(struct snd_soc_component *component) +{ + struct wsa883x_priv *wsa883x = snd_soc_component_get_drvdata(component); + + if (!wsa883x) + return 0; + + wsa883x->dapm_bias_off = false; + return 0; +} + static const struct snd_soc_component_driver soc_codec_dev_wsa883x_wsa = { .name = "", .probe = wsa883x_codec_probe, @@ -1230,6 +1253,8 @@ static const struct snd_soc_component_driver soc_codec_dev_wsa883x_wsa = { .num_dapm_widgets = ARRAY_SIZE(wsa883x_dapm_widgets), .dapm_routes = wsa883x_audio_map, .num_dapm_routes = ARRAY_SIZE(wsa883x_audio_map), + .suspend = wsa883x_soc_codec_suspend, + .resume = wsa883x_soc_codec_resume, }; static int wsa883x_gpio_ctrl(struct wsa883x_priv *wsa883x, bool enable) @@ -1692,7 +1717,20 @@ static int wsa883x_swr_remove(struct swr_device *pdev) #ifdef CONFIG_PM_SLEEP static int wsa883x_swr_suspend(struct device *dev) { + struct wsa883x_priv *wsa883x = swr_get_dev_data(to_swr_device(dev)); + + if (!wsa883x) { + dev_err(dev, "%s: wsa883x private data is NULL\n", __func__); + return -EINVAL; + } dev_dbg(dev, "%s: system suspend\n", __func__); + if (wsa883x->dapm_bias_off) { + msm_cdc_set_supplies_lpm_mode(dev, wsa883x->supplies, + wsa883x->regulator, + wsa883x->num_supplies, + true); + set_bit(WSA_SUPPLIES_LPM_MODE, &wsa883x->status_mask); + } return 0; } @@ -1704,13 +1742,21 @@ static int wsa883x_swr_resume(struct device *dev) dev_err(dev, "%s: wsa883x private data is NULL\n", __func__); return -EINVAL; } + if (test_bit(WSA_SUPPLIES_LPM_MODE, &wsa883x->status_mask)) { + msm_cdc_set_supplies_lpm_mode(dev, wsa883x->supplies, + wsa883x->regulator, + wsa883x->num_supplies, + false); + clear_bit(WSA_SUPPLIES_LPM_MODE, &wsa883x->status_mask); + } dev_dbg(dev, "%s: system resume\n", __func__); return 0; } #endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops wsa883x_swr_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(wsa883x_swr_suspend, wsa883x_swr_resume) + .suspend_late = wsa883x_swr_suspend, + .resume_early = wsa883x_swr_resume, }; static const struct swr_device_id wsa883x_swr_id[] = { diff --git a/include/asoc/msm-cdc-supply.h b/include/asoc/msm-cdc-supply.h index f7fec21c03..c740400754 100644 --- a/include/asoc/msm-cdc-supply.h +++ b/include/asoc/msm-cdc-supply.h @@ -15,6 +15,7 @@ struct cdc_regulator { int max_uV; int optimum_uA; bool ondemand; + bool lpm_supported; struct regulator *regulator; }; @@ -51,6 +52,11 @@ extern int msm_cdc_enable_static_supplies(struct device *dev, struct regulator_bulk_data *supplies, struct cdc_regulator *cdc_vreg, int num_supplies); +extern int msm_cdc_set_supplies_lpm_mode(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + bool flag); extern int msm_cdc_init_supplies(struct device *dev, struct regulator_bulk_data **supplies, struct cdc_regulator *cdc_vreg,