Browse Source

Merge "asoc: codec: Unvote wcd939x vdd-px supply"

qctecmdr 1 year ago
parent
commit
36aae5ef90
3 changed files with 180 additions and 6 deletions
  1. 123 6
      asoc/codecs/msm-cdc-supply.c
  2. 46 0
      asoc/codecs/wcd939x/wcd939x.c
  3. 11 0
      include/asoc/msm-cdc-supply.h

+ 123 - 6
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 <linux/kernel.h>
@@ -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);

+ 46 - 0
asoc/codecs/wcd939x/wcd939x.c

@@ -12,6 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/component.h>
 #include <linux/stringify.h>
+#include <linux/regulator/consumer.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
 #include <soc/soundwire.h>
@@ -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,

+ 11 - 0
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,