From af6068fd31cc42dc32ba340cc0664fd3f3882f16 Mon Sep 17 00:00:00 2001 From: Eric Rosas Date: Thu, 13 Jul 2023 22:25:48 -0700 Subject: [PATCH] asoc: codec: Unvote wcd939x vdd-px supply When codec goes into suspend, disable vdd-px which will cause an unvote in PM. Change-Id: Ia9f958d67fc57dbf3932733797bce7b0eb742363 Signed-off-by: Eric Rosas --- asoc/codecs/msm-cdc-supply.c | 129 ++++++++++++++++++++++++++++++++-- asoc/codecs/wcd939x/wcd939x.c | 46 ++++++++++++ include/asoc/msm-cdc-supply.h | 11 +++ 3 files changed, 180 insertions(+), 6 deletions(-) diff --git a/asoc/codecs/msm-cdc-supply.c b/asoc/codecs/msm-cdc-supply.c index 0ff61d678e..ad7cad3f1e 100644 --- a/asoc/codecs/msm-cdc-supply.c +++ b/asoc/codecs/msm-cdc-supply.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -72,10 +73,22 @@ static int msm_cdc_dt_parse_vreg_info(struct device *dev, cdc_vreg->lpm_supported = prop_val; } - dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d lpm %d\n", + /* Parse supply - retention mode */ + snprintf(prop_name, CODEC_DT_MAX_PROP_SIZE, "qcom,%s-rem-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->rem_supported = 0; + rc = 0; + } else { + cdc_vreg->rem_supported = prop_val; + } + + dev_info(dev, "%s: %s: vol=[%d %d]uV, curr=[%d]uA, ond %d lpm %d rem %d\n", __func__, cdc_vreg->name, cdc_vreg->min_uV, cdc_vreg->max_uV, cdc_vreg->optimum_uA, cdc_vreg->ondemand, - cdc_vreg->lpm_supported); + cdc_vreg->lpm_supported, cdc_vreg->rem_supported); done: return rc; @@ -173,6 +186,94 @@ bool msm_cdc_is_ondemand_supply(struct device *dev, } EXPORT_SYMBOL(msm_cdc_is_ondemand_supply); +/* + * msm_cdc_supply_supports_retention_mode: + * On certain hardware configurations, This means that the + * PM will disable the supply and remove its power vote + * if the PM enters into a suspended state. + * + * return if supply supports retention mode or not + * + * @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 + * + * Return true/false + */ +bool msm_cdc_supply_supports_retention_mode(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, char *supply_name) +{ + bool rc = false; + int ret, i; + + if ((!supply_name) || (!supplies)) { + pr_err_ratelimited("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return rc; + } + /* input parameter validation */ + ret = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (ret) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (cdc_vreg[i].rem_supported && + !strcmp(cdc_vreg[i].name, supply_name)) + return true; + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_supply_supports_retention_mode); + +/* + * msm_cdc_check_supply_vote: + * + * return true if supply has voted for regulator enable + * + * @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 + * + * Return true/false + */ +bool msm_cdc_check_supply_vote(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, + char *supply_name) +{ + bool rc = false; + int ret, i; + + if ((!supply_name) || (!supplies)) { + pr_err_ratelimited("%s: either dev or supplies or cdc_vreg is NULL\n", + __func__); + return rc; + } + + /* input parameter validation */ + ret = msm_cdc_check_supply_param(dev, cdc_vreg, num_supplies); + if (ret) + return rc; + + for (i = 0; i < num_supplies; i++) { + if (strcmp(cdc_vreg[i].name, supply_name) != 0) + continue; + + return cdc_vreg[i].vote; + } + + return rc; +} +EXPORT_SYMBOL(msm_cdc_check_supply_vote); + /* * msm_cdc_set_supply_min_voltage: * Set min supply voltage for particular supply @@ -257,6 +358,7 @@ int msm_cdc_disable_ondemand_supply(struct device *dev, dev_err_ratelimited(dev, "%s: failed to disable supply %s, err:%d\n", __func__, supplies[i].supply, rc); + cdc_vreg[i].vote = false; break; } } @@ -307,6 +409,7 @@ int msm_cdc_enable_ondemand_supply(struct device *dev, if (rc) dev_err_ratelimited(dev, "%s: failed to enable supply %s, rc: %d\n", __func__, supplies[i].supply, rc); + cdc_vreg[i].vote = true; break; } } @@ -409,9 +512,11 @@ int msm_cdc_disable_static_supplies(struct device *dev, if (rc) dev_err(dev, "%s: failed to disable supply %s, err:%d\n", __func__, supplies[i].supply, rc); - else + else { + cdc_vreg[i].vote = false; dev_dbg(dev, "%s: disabled regulator %s\n", __func__, supplies[i].supply); + } } return rc; @@ -500,11 +605,21 @@ int msm_cdc_enable_static_supplies(struct device *dev, __func__, supplies[i].supply, rc); break; } + cdc_vreg[i].vote = true; } - while (rc && i--) - if (!cdc_vreg[i].ondemand) - regulator_disable(supplies[i].consumer); + if (rc) { + while (i--) { + if (cdc_vreg[i].ondemand) + continue; + + if (regulator_disable(supplies[i].consumer) == 0) + cdc_vreg[i].vote = false; + else + dev_err(dev, "%s: failed to disable supply %s during unwind\n", + __func__, supplies[i].supply); + } + } return rc; } @@ -594,6 +709,8 @@ int msm_cdc_init_supplies_v2(struct device *dev, if (cdc_vreg[i].ondemand && vote_regulator_on_demand) continue; + cdc_vreg[i].regulator = vsup[i].consumer; + rc = regulator_set_voltage(vsup[i].consumer, cdc_vreg[i].min_uV, cdc_vreg[i].max_uV); diff --git a/asoc/codecs/wcd939x/wcd939x.c b/asoc/codecs/wcd939x/wcd939x.c index 2cab25dfcc..a37c4d8263 100644 --- a/asoc/codecs/wcd939x/wcd939x.c +++ b/asoc/codecs/wcd939x/wcd939x.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -5316,6 +5317,18 @@ static int wcd939x_probe(struct platform_device *pdev) return ret; } + if (msm_cdc_is_ondemand_supply(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px")) { + ret = msm_cdc_enable_ondemand_supply(wcd939x->dev, + wcd939x->supplies, pdata->regulator, + pdata->num_supplies, "cdc-vdd-px"); + if (ret) { + dev_err(dev, "%s: vdd px supply enable failed!\n", + __func__); + return ret; + } + } + ret = wcd939x_parse_port_mapping(dev, "qcom,rx_swr_ch_map", CODEC_RX); ret |= wcd939x_parse_port_mapping(dev, "qcom,tx_swr_ch_map", @@ -5409,12 +5422,30 @@ static int wcd939x_suspend(struct device *dev) pdata->num_supplies, true); set_bit(WCD_SUPPLIES_LPM_MODE, &wcd939x->status_mask); + if (msm_cdc_is_ondemand_supply(wcd939x->dev, wcd939x->supplies, pdata->regulator, + pdata->num_supplies, "cdc-vdd-px")) { + + if (msm_cdc_supply_supports_retention_mode(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px") && + msm_cdc_check_supply_vote(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px")) { + ret = msm_cdc_disable_ondemand_supply(wcd939x->dev, + wcd939x->supplies, pdata->regulator, + pdata->num_supplies, "cdc-vdd-px"); + if (ret) { + dev_dbg(dev, "%s: vdd px supply suspend failed!\n", + __func__); + } + } + } } + return 0; } static int wcd939x_resume(struct device *dev) { + int ret = 0; struct wcd939x_priv *wcd939x = NULL; struct wcd939x_pdata *pdata = NULL; @@ -5432,6 +5463,21 @@ static int wcd939x_resume(struct device *dev) return -EINVAL; } + if (msm_cdc_is_ondemand_supply(wcd939x->dev, wcd939x->supplies, pdata->regulator, + pdata->num_supplies, "cdc-vdd-px")) { + if (msm_cdc_supply_supports_retention_mode(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px") && + !msm_cdc_check_supply_vote(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px")) { + ret = msm_cdc_enable_ondemand_supply(wcd939x->dev, wcd939x->supplies, + pdata->regulator, pdata->num_supplies, "cdc-vdd-px"); + if (ret) { + dev_dbg(dev, "%s: vdd px supply resume failed!\n", + __func__); + } + } + } + if (test_bit(WCD_SUPPLIES_LPM_MODE, &wcd939x->status_mask)) { msm_cdc_set_supplies_lpm_mode(wcd939x->dev, wcd939x->supplies, diff --git a/include/asoc/msm-cdc-supply.h b/include/asoc/msm-cdc-supply.h index 3b19387d47..33cfaccc56 100644 --- a/include/asoc/msm-cdc-supply.h +++ b/include/asoc/msm-cdc-supply.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* Copyright (c) 2016, 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef __CODEC_POWER_SUPPLY_H__ @@ -16,6 +17,8 @@ struct cdc_regulator { int optimum_uA; bool ondemand; bool lpm_supported; + bool rem_supported; + bool vote; struct regulator *regulator; }; @@ -32,6 +35,14 @@ extern bool msm_cdc_is_ondemand_supply(struct device *dev, struct regulator_bulk_data *supplies, struct cdc_regulator *cdc_vreg, int num_supplies, char *supply_name); +extern bool msm_cdc_supply_supports_retention_mode(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, char *supply_name); +extern bool msm_cdc_check_supply_vote(struct device *dev, + struct regulator_bulk_data *supplies, + struct cdc_regulator *cdc_vreg, + int num_supplies, char *supply_name); extern int msm_cdc_disable_ondemand_supply(struct device *dev, struct regulator_bulk_data *supplies, struct cdc_regulator *cdc_vreg,