regulator: cpr-regulator: Enable/disable closed-loop CPR on temperature
Add logic to enable/disable closed-loop CPR based on TSENS temperature. Use the thermal sensor interface which allows monitoring TSENS temperature thresholds and notifies when the configured threshold is hit. Use the notification callbacks to disable/enable CPR and force open-loop voltage. CRs-Fixed: 903646 Change-Id: Id131f7570740dce4445ce1849ae0551d6207c737 Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
This commit is contained in:
parent
e8641c5aa4
commit
31eccc3394
|
@ -708,6 +708,17 @@ Optional properties:
|
|||
The number of quadruples should be equal to the number of values specified in
|
||||
the qcom,cpr-aging-sensor-id property. This property is required if
|
||||
the qcom,cpr-aging-sensor-id property has been specified.
|
||||
- qcom,cpr-thermal-sensor-id: TSENS hardware sensor-id of the sensor which
|
||||
needs to be monitored.
|
||||
- qcom,cpr-disable-temp-threshold: The TSENS temperature threshold in degrees Celsius at which CPR
|
||||
closed-loop is disabled. CPR closed-loop will stay disabled as long as the
|
||||
temperature is below this threshold. This property is required
|
||||
only if 'qcom,cpr-thermal-sensor-id' is present.
|
||||
- qcom,cpr-enable-temp-threshold: The TSENS temperature threshold in degrees Celsius at which CPR
|
||||
closed-loop is enabled. CPR closed-loop will stay enabled above this
|
||||
temperature threshold. This property is required only if
|
||||
'qcom,cpr-thermal-sensor-id' is present.
|
||||
|
||||
Example:
|
||||
apc_vreg_corner: regulator@f9018000 {
|
||||
status = "okay";
|
||||
|
@ -957,4 +968,8 @@ Example:
|
|||
qcom,cpr-fuse-aging-init-quot-diff =
|
||||
<101 0 8 0>,
|
||||
<101 8 8 0>;
|
||||
|
||||
qcom,cpr-thermal-sensor-id = <9>;
|
||||
qcom,cpr-disable-temp-threshold = <5>;
|
||||
qcom,cpr-enable-temp-threshold = <10>;
|
||||
};
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/of_regulator.h>
|
||||
#include <linux/regulator/cpr-regulator.h>
|
||||
#include <linux/msm_thermal.h>
|
||||
#include <linux/msm_tsens.h>
|
||||
#include <soc/qcom/scm.h>
|
||||
|
||||
/* Register Offsets for RB-CPR and Bit Definitions */
|
||||
|
@ -267,6 +269,7 @@ struct cpr_regulator {
|
|||
int corner;
|
||||
int ceiling_max;
|
||||
struct dentry *debugfs;
|
||||
struct device *dev;
|
||||
|
||||
/* eFuse parameters */
|
||||
phys_addr_t efuse_addr;
|
||||
|
@ -298,6 +301,14 @@ struct cpr_regulator {
|
|||
/* mem-acc regulator */
|
||||
struct regulator *mem_acc_vreg;
|
||||
|
||||
/* thermal monitor */
|
||||
int tsens_id;
|
||||
int cpr_disable_temp_threshold;
|
||||
int cpr_enable_temp_threshold;
|
||||
bool cpr_disable_on_temperature;
|
||||
bool cpr_thermal_disable;
|
||||
struct threshold_info tsens_threshold_config;
|
||||
|
||||
/* CPR parameters */
|
||||
u32 num_fuse_corners;
|
||||
u64 cpr_fuse_bits;
|
||||
|
@ -532,7 +543,8 @@ static u64 cpr_read_efuse_param(struct cpr_regulator *cpr_vreg, int row_start,
|
|||
|
||||
static bool cpr_is_allowed(struct cpr_regulator *cpr_vreg)
|
||||
{
|
||||
if (cpr_vreg->cpr_fuse_disable || !cpr_vreg->enable)
|
||||
if (cpr_vreg->cpr_fuse_disable || !cpr_vreg->enable ||
|
||||
cpr_vreg->cpr_thermal_disable)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
|
@ -4889,6 +4901,139 @@ static int cpr_vsens_init(struct platform_device *pdev,
|
|||
return rc;
|
||||
}
|
||||
|
||||
static int cpr_disable_on_temp(struct cpr_regulator *cpr_vreg, bool disable)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
mutex_lock(&cpr_vreg->cpr_mutex);
|
||||
|
||||
if (cpr_vreg->cpr_fuse_disable ||
|
||||
(cpr_vreg->cpr_thermal_disable == disable))
|
||||
goto out;
|
||||
|
||||
cpr_vreg->cpr_thermal_disable = disable;
|
||||
|
||||
if (cpr_vreg->enable && cpr_vreg->corner) {
|
||||
if (disable) {
|
||||
cpr_debug(cpr_vreg, "Disabling CPR - below temperature threshold [%d]\n",
|
||||
cpr_vreg->cpr_disable_temp_threshold);
|
||||
/* disable CPR and force open-loop */
|
||||
cpr_ctl_disable(cpr_vreg);
|
||||
rc = cpr_regulator_set_voltage(cpr_vreg->rdev,
|
||||
cpr_vreg->corner, false);
|
||||
if (rc < 0)
|
||||
cpr_err(cpr_vreg, "Failed to set voltage, rc=%d\n",
|
||||
rc);
|
||||
} else {
|
||||
/* enable CPR */
|
||||
cpr_debug(cpr_vreg, "Enabling CPR - above temperature thresold [%d]\n",
|
||||
cpr_vreg->cpr_enable_temp_threshold);
|
||||
rc = cpr_regulator_set_voltage(cpr_vreg->rdev,
|
||||
cpr_vreg->corner, true);
|
||||
if (rc < 0)
|
||||
cpr_err(cpr_vreg, "Failed to set voltage, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&cpr_vreg->cpr_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void tsens_threshold_notify(struct therm_threshold *tsens_cb_data)
|
||||
{
|
||||
struct threshold_info *info = tsens_cb_data->parent;
|
||||
struct cpr_regulator *cpr_vreg = container_of(info,
|
||||
struct cpr_regulator, tsens_threshold_config);
|
||||
int rc = 0;
|
||||
|
||||
cpr_debug(cpr_vreg, "Triggered tsens-notification trip_type=%d for thermal_zone_id=%d\n",
|
||||
tsens_cb_data->trip_triggered, tsens_cb_data->sensor_id);
|
||||
|
||||
switch (tsens_cb_data->trip_triggered) {
|
||||
case THERMAL_TRIP_CONFIGURABLE_HI:
|
||||
rc = cpr_disable_on_temp(cpr_vreg, false);
|
||||
if (rc < 0)
|
||||
cpr_err(cpr_vreg, "Failed to enable CPR, rc=%d\n", rc);
|
||||
break;
|
||||
case THERMAL_TRIP_CONFIGURABLE_LOW:
|
||||
rc = cpr_disable_on_temp(cpr_vreg, true);
|
||||
if (rc < 0)
|
||||
cpr_err(cpr_vreg, "Failed to disable CPR, rc=%d\n", rc);
|
||||
break;
|
||||
default:
|
||||
cpr_debug(cpr_vreg, "trip-type %d not supported\n",
|
||||
tsens_cb_data->trip_triggered);
|
||||
break;
|
||||
}
|
||||
|
||||
rc = sensor_mgr_set_threshold(tsens_cb_data->sensor_id,
|
||||
tsens_cb_data->threshold);
|
||||
if (rc < 0)
|
||||
cpr_err(cpr_vreg, "Failed to set temp. threshold, rc=%d\n", rc);
|
||||
}
|
||||
|
||||
static int cpr_check_tsens(struct cpr_regulator *cpr_vreg)
|
||||
{
|
||||
int rc = 0;
|
||||
struct tsens_device tsens_dev;
|
||||
unsigned long temp = 0;
|
||||
bool disable;
|
||||
|
||||
if (tsens_is_ready() > 0) {
|
||||
tsens_dev.sensor_num = cpr_vreg->tsens_id;
|
||||
rc = tsens_get_temp(&tsens_dev, &temp);
|
||||
if (rc < 0) {
|
||||
cpr_err(cpr_vreg, "Faled to read tsens, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
disable = (int) temp <= cpr_vreg->cpr_disable_temp_threshold;
|
||||
rc = cpr_disable_on_temp(cpr_vreg, disable);
|
||||
if (rc)
|
||||
cpr_err(cpr_vreg, "Failed to %s CPR, rc=%d\n",
|
||||
disable ? "disable" : "enable", rc);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int cpr_thermal_init(struct cpr_regulator *cpr_vreg)
|
||||
{
|
||||
int rc;
|
||||
struct device_node *of_node = cpr_vreg->dev->of_node;
|
||||
|
||||
if (!of_find_property(of_node, "qcom,cpr-thermal-sensor-id", NULL))
|
||||
return 0;
|
||||
|
||||
CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-thermal-sensor-id",
|
||||
&cpr_vreg->tsens_id, rc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-disable-temp-threshold",
|
||||
&cpr_vreg->cpr_disable_temp_threshold, rc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
CPR_PROP_READ_U32(cpr_vreg, of_node, "cpr-enable-temp-threshold",
|
||||
&cpr_vreg->cpr_enable_temp_threshold, rc);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (cpr_vreg->cpr_disable_temp_threshold >=
|
||||
cpr_vreg->cpr_enable_temp_threshold) {
|
||||
cpr_err(cpr_vreg, "Invalid temperature threshold cpr_disable_temp[%d] >= cpr_enable_temp[%d]\n",
|
||||
cpr_vreg->cpr_disable_temp_threshold,
|
||||
cpr_vreg->cpr_enable_temp_threshold);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cpr_vreg->cpr_disable_on_temperature = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpr_init_cpr(struct platform_device *pdev,
|
||||
struct cpr_regulator *cpr_vreg)
|
||||
{
|
||||
|
@ -5636,6 +5781,7 @@ static int cpr_regulator_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cpr_vreg->dev = &pdev->dev;
|
||||
cpr_vreg->rdesc.name = init_data->constraints.name;
|
||||
if (cpr_vreg->rdesc.name == NULL) {
|
||||
dev_err(dev, "regulator-name missing\n");
|
||||
|
@ -5732,6 +5878,12 @@ static int cpr_regulator_probe(struct platform_device *pdev)
|
|||
return rc;
|
||||
}
|
||||
|
||||
rc = cpr_thermal_init(cpr_vreg);
|
||||
if (rc) {
|
||||
cpr_err(cpr_vreg, "Thermal intialization failed rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Load per-online CPU adjustment data */
|
||||
rc = cpr_init_per_cpu_adjustments(cpr_vreg, &pdev->dev);
|
||||
if (rc) {
|
||||
|
@ -5781,6 +5933,17 @@ static int cpr_regulator_probe(struct platform_device *pdev)
|
|||
platform_set_drvdata(pdev, cpr_vreg);
|
||||
cpr_debugfs_init(cpr_vreg);
|
||||
|
||||
if (cpr_vreg->cpr_disable_on_temperature) {
|
||||
rc = cpr_check_tsens(cpr_vreg);
|
||||
if (rc < 0) {
|
||||
cpr_err(cpr_vreg, "Unable to config CPR on tsens, rc=%d\n",
|
||||
rc);
|
||||
cpr_apc_exit(cpr_vreg);
|
||||
cpr_debugfs_remove(cpr_vreg);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_lock(&cpr_regulator_list_mutex);
|
||||
list_add(&cpr_vreg->list, &cpr_regulator_list);
|
||||
mutex_unlock(&cpr_regulator_list_mutex);
|
||||
|
@ -5811,6 +5974,10 @@ static int cpr_regulator_remove(struct platform_device *pdev)
|
|||
if (cpr_vreg->cpu_notifier.notifier_call)
|
||||
unregister_hotcpu_notifier(&cpr_vreg->cpu_notifier);
|
||||
|
||||
if (cpr_vreg->cpr_disable_on_temperature)
|
||||
sensor_mgr_remove_threshold(cpr_vreg->dev,
|
||||
&cpr_vreg->tsens_threshold_config);
|
||||
|
||||
cpr_apc_exit(cpr_vreg);
|
||||
cpr_debugfs_remove(cpr_vreg);
|
||||
regulator_unregister(cpr_vreg->rdev);
|
||||
|
@ -5836,6 +6003,57 @@ static struct platform_driver cpr_regulator_driver = {
|
|||
.resume = cpr_regulator_resume,
|
||||
};
|
||||
|
||||
static int initialize_tsens_monitor(struct cpr_regulator *cpr_vreg)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = cpr_check_tsens(cpr_vreg);
|
||||
if (rc < 0) {
|
||||
cpr_err(cpr_vreg, "Unable to check tsens, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = sensor_mgr_init_threshold(cpr_vreg->dev,
|
||||
&cpr_vreg->tsens_threshold_config,
|
||||
cpr_vreg->tsens_id,
|
||||
cpr_vreg->cpr_enable_temp_threshold, /* high */
|
||||
cpr_vreg->cpr_disable_temp_threshold, /* low */
|
||||
tsens_threshold_notify);
|
||||
if (rc < 0) {
|
||||
cpr_err(cpr_vreg, "Failed to init tsens monitor, rc=%d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = sensor_mgr_convert_id_and_set_threshold(
|
||||
&cpr_vreg->tsens_threshold_config);
|
||||
if (rc < 0)
|
||||
cpr_err(cpr_vreg, "Failed to set tsens threshold, rc=%d\n",
|
||||
rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int __init cpr_regulator_late_init(void)
|
||||
{
|
||||
int rc;
|
||||
struct cpr_regulator *cpr_vreg;
|
||||
|
||||
mutex_lock(&cpr_regulator_list_mutex);
|
||||
|
||||
list_for_each_entry(cpr_vreg, &cpr_regulator_list, list) {
|
||||
if (cpr_vreg->cpr_disable_on_temperature) {
|
||||
rc = initialize_tsens_monitor(cpr_vreg);
|
||||
if (rc)
|
||||
cpr_err(cpr_vreg, "Failed to initialize temperature monitor, rc=%d\n",
|
||||
rc);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&cpr_regulator_list_mutex);
|
||||
return 0;
|
||||
}
|
||||
late_initcall(cpr_regulator_late_init);
|
||||
|
||||
/**
|
||||
* cpr_regulator_init() - register cpr-regulator driver
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue