Merge "thermal: Add Support for enabling and disabling tsens trip"

This commit is contained in:
Linux Build Service Account
2013-11-27 04:47:05 -08:00
committed by Gerrit - the friendly Code Review server
3 changed files with 251 additions and 111 deletions
+91 -14
View File
@@ -37,6 +37,7 @@
#include <linux/regulator/consumer.h>
#define MAX_RAILS 5
#define MAX_THRESHOLD 2
static struct msm_thermal_data msm_thermal_info;
static uint32_t limited_max_freq = UINT_MAX;
@@ -77,8 +78,10 @@ struct cpu_info {
uint32_t cpu;
bool offline;
bool user_offline;
bool thresh_cleared;
const char *sensor_type;
struct sensor_threshold thresh[2];
uint32_t sensor_id;
struct sensor_threshold thresh[MAX_THRESHOLD];
};
struct rail {
@@ -624,6 +627,76 @@ static int update_cpu_max_freq(int cpu, uint32_t max_freq)
return ret;
}
static int set_and_activate_threshold(uint32_t sensor_id,
struct sensor_threshold *threshold)
{
int ret = 0;
ret = sensor_set_trip(sensor_id, threshold);
if (ret != 0) {
pr_err("%s: Error in setting trip %d\n",
KBUILD_MODNAME, threshold->trip);
goto set_done;
}
ret = sensor_activate_trip(sensor_id, threshold, true);
if (ret != 0) {
pr_err("%s: Error in enabling trip %d\n",
KBUILD_MODNAME, threshold->trip);
goto set_done;
}
set_done:
return ret;
}
static int set_threshold(uint32_t sensor_id,
struct sensor_threshold *threshold)
{
struct tsens_device tsens_dev;
int i = 0, ret = 0;
long temp;
if ((!threshold) || check_sensor_id(sensor_id)) {
pr_err("%s: Invalid input\n", KBUILD_MODNAME);
ret = -EINVAL;
goto set_threshold_exit;
}
tsens_dev.sensor_num = sensor_id;
ret = tsens_get_temp(&tsens_dev, &temp);
if (ret) {
pr_err("%s: Unable to read TSENS sensor %d\n",
KBUILD_MODNAME, tsens_dev.sensor_num);
goto set_threshold_exit;
}
while (i < MAX_THRESHOLD) {
switch (threshold[i].trip) {
case THERMAL_TRIP_CONFIGURABLE_HI:
if (threshold[i].temp >= temp) {
ret = set_and_activate_threshold(sensor_id,
&threshold[i]);
if (ret)
goto set_threshold_exit;
}
break;
case THERMAL_TRIP_CONFIGURABLE_LOW:
if (threshold[i].temp <= temp) {
ret = set_and_activate_threshold(sensor_id,
&threshold[i]);
if (ret)
goto set_threshold_exit;
}
break;
default:
break;
}
i++;
}
set_threshold_exit:
return ret;
}
#ifdef CONFIG_SMP
static void __ref do_core_control(long temp)
{
@@ -677,7 +750,7 @@ static void __ref do_core_control(long temp)
/* Call with core_control_mutex locked */
static int __ref update_offline_cores(int val)
{
int cpu = 0;
uint32_t cpu = 0;
int ret = 0;
if (!core_control_enabled)
@@ -701,8 +774,7 @@ static int __ref update_offline_cores(int val)
static __ref int do_hotplug(void *data)
{
int ret = 0;
int cpu = 0;
uint32_t mask = 0;
uint32_t cpu = 0, mask = 0;
if (!core_control_enabled)
return -EINVAL;
@@ -714,6 +786,11 @@ static __ref int do_hotplug(void *data)
mutex_lock(&core_control_mutex);
for_each_possible_cpu(cpu) {
if (cpus[cpu].thresh_cleared) {
set_threshold(cpus[cpu].sensor_id,
cpus[cpu].thresh);
cpus[cpu].thresh_cleared = false;
}
if (cpus[cpu].offline || cpus[cpu].user_offline)
mask |= BIT(cpu);
}
@@ -984,10 +1061,12 @@ static int hotplug_notify(enum thermal_trip_type type, int temp, void *data)
default:
break;
}
if (hotplug_task)
if (hotplug_task) {
cpu_node->thresh_cleared = true;
complete(&hotplug_notify_complete);
else
} else {
pr_err("%s: Hotplug task is not initialized\n", KBUILD_MODNAME);
}
return 0;
}
/* Adjust cpus offlined bit based on temperature reading. */
@@ -1001,8 +1080,7 @@ static int hotplug_init_cpu_offlined(void)
for_each_possible_cpu(cpu) {
if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
continue;
tsens_dev.sensor_num = sensor_get_id(\
(char *)cpus[cpu].sensor_type);
tsens_dev.sensor_num = cpus[cpu].sensor_id;
if (tsens_get_temp(&tsens_dev, &temp)) {
pr_err("%s: Unable to read TSENS sensor %d\n",
KBUILD_MODNAME, tsens_dev.sensor_num);
@@ -1035,24 +1113,23 @@ static void hotplug_init(void)
return;
for_each_possible_cpu(cpu) {
cpus[cpu].cpu = (uint32_t)cpu;
cpus[cpu].thresh_cleared = false;
cpus[cpu].sensor_id =
sensor_get_id((char *)cpus[cpu].sensor_type);
if (!(msm_thermal_info.core_control_mask & BIT(cpus[cpu].cpu)))
continue;
cpus[cpu].cpu = (uint32_t)cpu;
cpus[cpu].thresh[0].temp = msm_thermal_info.hotplug_temp_degC;
cpus[cpu].thresh[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
cpus[cpu].thresh[0].notify = hotplug_notify;
cpus[cpu].thresh[0].data = (void *)&cpus[cpu];
sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
&cpus[cpu].thresh[0]);
cpus[cpu].thresh[1].temp = msm_thermal_info.hotplug_temp_degC -
msm_thermal_info.hotplug_temp_hysteresis_degC;
cpus[cpu].thresh[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
cpus[cpu].thresh[1].notify = hotplug_notify;
cpus[cpu].thresh[1].data = (void *)&cpus[cpu];
sensor_set_trip(sensor_get_id((char *)cpus[cpu].sensor_type),
&cpus[cpu].thresh[1]);
set_threshold(cpus[cpu].sensor_id, cpus[cpu].thresh);
}
init_completion(&hotplug_notify_complete);
hotplug_task = kthread_run(do_hotplug, NULL, "msm_thermal:hotplug");
+157 -97
View File
@@ -89,30 +89,21 @@ int sensor_get_id(char *name)
}
EXPORT_SYMBOL(sensor_get_id);
static long get_min(struct sensor_info *sensor, long temp)
static int __update_sensor_thresholds(struct sensor_info *sensor)
{
long min = LONG_MIN;
struct sensor_threshold *pos, *var;
list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW)
if (pos->temp < temp && pos->temp > min)
min = pos->temp;
}
return min;
}
static void __update_sensor_thresholds(struct sensor_info *sensor)
{
long min = LONG_MIN;
long max = LONG_MAX;
long max_of_min = LONG_MIN;
long min_of_max = LONG_MAX;
long max_of_low_thresh = LONG_MIN;
long min_of_high_thresh = LONG_MAX;
struct sensor_threshold *pos, *var;
enum thermal_trip_type type;
int i;
long curr_temp;
int i, ret = 0;
if (!sensor->tz->ops->set_trip_temp ||
!sensor->tz->ops->activate_trip_type ||
!sensor->tz->ops->get_trip_type ||
!sensor->tz->ops->get_trip_temp) {
ret = -ENODEV;
goto update_done;
}
for (i = 0; ((sensor->max_idx == -1) || (sensor->min_idx == -1)) &&
(sensor->tz->ops->get_trip_type) && (i < sensor->tz->trips);
@@ -128,60 +119,85 @@ static void __update_sensor_thresholds(struct sensor_info *sensor)
THERMAL_TRIP_CONFIGURABLE_HI, &sensor->threshold_max);
}
sensor->tz->ops->get_temp(sensor->tz, &curr_temp);
list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
if (!pos->active)
continue;
if (pos->trip == THERMAL_TRIP_CONFIGURABLE_LOW) {
if (pos->temp > max_of_min)
max_of_min = pos->temp;
if (pos->temp < curr_temp && pos->temp > min)
min = pos->temp;
if (pos->temp > max_of_low_thresh)
max_of_low_thresh = pos->temp;
}
if (pos->trip == THERMAL_TRIP_CONFIGURABLE_HI) {
if (pos->temp < min_of_max)
min_of_max = pos->temp;
if (pos->temp > curr_temp && pos->temp < max)
max = pos->temp;
if (pos->temp < min_of_high_thresh)
min_of_high_thresh = pos->temp;
}
}
pr_debug("sensor %d: min of max: %ld max of min: %ld\n",
sensor->sensor_id, max_of_min, min_of_max);
pr_debug("sensor %d: Thresholds: max of low: %ld min of high: %ld\n",
sensor->sensor_id, max_of_low_thresh,
min_of_high_thresh);
/* If we haven't found a max and min bounding the curr_temp,
* use the min of max and max of min instead.
*/
if (max == LONG_MAX)
max = min_of_max;
if (min == LONG_MIN) {
min = get_min(sensor, max);
if (min == LONG_MIN)
min = max_of_min;
if ((min_of_high_thresh != sensor->threshold_max) &&
(min_of_high_thresh != LONG_MAX)) {
ret = sensor->tz->ops->set_trip_temp(sensor->tz,
sensor->max_idx, min_of_high_thresh);
if (ret) {
pr_err("sensor %d: Unable to set high threshold %d",
sensor->sensor_id, ret);
goto update_done;
}
sensor->threshold_max = min_of_high_thresh;
}
ret = sensor->tz->ops->activate_trip_type(sensor->tz,
sensor->max_idx,
(min_of_high_thresh == LONG_MAX) ?
THERMAL_TRIP_ACTIVATION_DISABLED :
THERMAL_TRIP_ACTIVATION_ENABLED);
if (ret) {
pr_err("sensor %d: Unable to activate high threshold %d",
sensor->sensor_id, ret);
goto update_done;
}
if (sensor->tz->ops->set_trip_temp) {
if (max != sensor->threshold_max) {
sensor->tz->ops->set_trip_temp(sensor->tz,
sensor->max_idx, max);
sensor->threshold_max = max;
}
if (min != sensor->threshold_min) {
sensor->tz->ops->set_trip_temp(sensor->tz,
sensor->min_idx, min);
sensor->threshold_min = min;
if ((max_of_low_thresh != sensor->threshold_min) &&
(max_of_low_thresh != LONG_MIN)) {
ret = sensor->tz->ops->set_trip_temp(sensor->tz,
sensor->min_idx, max_of_low_thresh);
if (ret) {
pr_err("sensor %d: Unable to set low threshold %d",
sensor->sensor_id, ret);
goto update_done;
}
sensor->threshold_min = max_of_low_thresh;
}
ret = sensor->tz->ops->activate_trip_type(sensor->tz,
sensor->min_idx,
(max_of_low_thresh == LONG_MIN) ?
THERMAL_TRIP_ACTIVATION_DISABLED :
THERMAL_TRIP_ACTIVATION_ENABLED);
if (ret) {
pr_err("sensor %d: Unable to activate low threshold %d",
sensor->sensor_id, ret);
goto update_done;
}
pr_debug("sensor %d: curr_temp: %ld min: %ld max: %ld\n",
sensor->sensor_id, curr_temp,
pr_debug("sensor %d: low: %ld high: %ld\n",
sensor->sensor_id,
sensor->threshold_min, sensor->threshold_max);
update_done:
return ret;
}
static void sensor_update_work(struct work_struct *work)
{
struct sensor_info *sensor = container_of(work, struct sensor_info,
work);
int ret = 0;
mutex_lock(&sensor->lock);
__update_sensor_thresholds(sensor);
ret = __update_sensor_thresholds(sensor);
if (ret)
pr_err("sensor %d: Error %d setting threshold\n",
sensor->sensor_id, ret);
mutex_unlock(&sensor->lock);
}
@@ -202,7 +218,7 @@ int thermal_sensor_trip(struct thermal_zone_device *tz,
return 0;
list_for_each_entry_safe(pos, var, &tz->sensor.threshold_list, list) {
if (pos->trip != trip)
if ((pos->trip != trip) || (!pos->active))
continue;
if (((trip == THERMAL_TRIP_CONFIGURABLE_LOW) &&
(pos->temp <= tz->sensor.threshold_min) &&
@@ -210,6 +226,7 @@ int thermal_sensor_trip(struct thermal_zone_device *tz,
((trip == THERMAL_TRIP_CONFIGURABLE_HI) &&
(pos->temp >= tz->sensor.threshold_max) &&
(pos->temp <= temp))) {
pos->active = 0;
pos->notify(trip, temp, pos->data);
}
}
@@ -220,6 +237,29 @@ int thermal_sensor_trip(struct thermal_zone_device *tz,
}
EXPORT_SYMBOL(thermal_sensor_trip);
int sensor_activate_trip(uint32_t sensor_id,
struct sensor_threshold *threshold, bool enable)
{
struct sensor_info *sensor = get_sensor(sensor_id);
int ret = 0;
if (!sensor || !threshold) {
pr_err("Sensor %d: uninitialized data\n",
sensor_id);
ret = -ENODEV;
goto activate_trip_exit;
}
mutex_lock(&sensor->lock);
threshold->active = (enable) ? 1 : 0;
ret = __update_sensor_thresholds(sensor);
mutex_unlock(&sensor->lock);
activate_trip_exit:
return ret;
}
EXPORT_SYMBOL(sensor_activate_trip);
int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
{
struct sensor_threshold *pos, *var;
@@ -241,8 +281,7 @@ int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
INIT_LIST_HEAD(&threshold->list);
list_add(&threshold->list, &sensor->threshold_list);
}
__update_sensor_thresholds(sensor);
threshold->active = 0; /* Do not allow active threshold right away */
mutex_unlock(&sensor->lock);
return 0;
@@ -254,6 +293,7 @@ int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
{
struct sensor_threshold *pos, *var;
struct sensor_info *sensor = get_sensor(sensor_id);
int ret = 0;
if (!sensor)
return -ENODEV;
@@ -261,15 +301,16 @@ int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold)
mutex_lock(&sensor->lock);
list_for_each_entry_safe(pos, var, &sensor->threshold_list, list) {
if (pos == threshold) {
pos->active = 0;
list_del(&pos->list);
break;
}
}
__update_sensor_thresholds(sensor);
ret = __update_sensor_thresholds(sensor);
mutex_unlock(&sensor->lock);
return 0;
return ret;
}
EXPORT_SYMBOL(sensor_cancel_trip);
@@ -283,36 +324,36 @@ static int tz_notify_trip(enum thermal_trip_type type, int temp, void *data)
return 0;
}
static void get_trip_threshold(struct thermal_zone_device *tz, int trip,
struct sensor_threshold **threshold)
{
enum thermal_trip_type type;
tz->ops->get_trip_type(tz, trip, &type);
if (type == THERMAL_TRIP_CONFIGURABLE_HI)
*threshold = &tz->tz_threshold[0];
else if (type == THERMAL_TRIP_CONFIGURABLE_LOW)
*threshold = &tz->tz_threshold[1];
else
*threshold = NULL;
}
int sensor_set_trip_temp(struct thermal_zone_device *tz,
int trip, long temp)
{
int ret = 0;
enum thermal_trip_type type;
struct sensor_threshold *threshold = NULL;
if (!tz->ops->get_trip_type)
return -EPERM;
tz->ops->get_trip_type(tz, trip, &type);
switch (type) {
case THERMAL_TRIP_CONFIGURABLE_HI:
tz->tz_threshold[0].temp = temp;
tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
tz->tz_threshold[0].notify = tz_notify_trip;
tz->tz_threshold[0].data = tz;
ret = sensor_set_trip(tz->sensor.sensor_id,
&tz->tz_threshold[0]);
break;
case THERMAL_TRIP_CONFIGURABLE_LOW:
tz->tz_threshold[1].temp = temp;
tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
tz->tz_threshold[1].notify = tz_notify_trip;
tz->tz_threshold[1].data = tz;
ret = sensor_set_trip(tz->sensor.sensor_id,
&tz->tz_threshold[1]);
break;
default:
get_trip_threshold(tz, trip, &threshold);
if (threshold) {
threshold->temp = temp;
ret = sensor_set_trip(tz->sensor.sensor_id, threshold);
} else {
ret = tz->ops->set_trip_temp(tz, trip, temp);
break;
}
return ret;
@@ -333,10 +374,12 @@ int sensor_init(struct thermal_zone_device *tz)
INIT_LIST_HEAD(&sensor->threshold_list);
INIT_LIST_HEAD(&tz->tz_threshold[0].list);
INIT_LIST_HEAD(&tz->tz_threshold[1].list);
tz->tz_threshold[0].notify = NULL;
tz->tz_threshold[0].data = NULL;
tz->tz_threshold[1].notify = NULL;
tz->tz_threshold[1].data = NULL;
tz->tz_threshold[0].notify = tz_notify_trip;
tz->tz_threshold[0].data = tz;
tz->tz_threshold[0].trip = THERMAL_TRIP_CONFIGURABLE_HI;
tz->tz_threshold[1].notify = tz_notify_trip;
tz->tz_threshold[1].data = tz;
tz->tz_threshold[1].trip = THERMAL_TRIP_CONFIGURABLE_LOW;
list_add(&sensor->sensor_list, &sensor_info_list);
INIT_WORK(&sensor->work, sensor_update_work);
@@ -489,23 +532,40 @@ trip_point_type_activate(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
int trip, result;
int trip, result = 0;
bool activate;
struct sensor_threshold *threshold = NULL;
if (!tz->ops->activate_trip_type)
return -EPERM;
if (!tz->ops->get_trip_type ||
!tz->ops->activate_trip_type) {
result = -EPERM;
goto trip_activate_exit;
}
if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
return -EINVAL;
if (!strncmp(buf, "enabled", sizeof("enabled")))
result = tz->ops->activate_trip_type(tz, trip,
THERMAL_TRIP_ACTIVATION_ENABLED);
else if (!strncmp(buf, "disabled", sizeof("disabled")))
result = tz->ops->activate_trip_type(tz, trip,
THERMAL_TRIP_ACTIVATION_DISABLED);
else
if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip)) {
result = -EINVAL;
goto trip_activate_exit;
}
if (!strcmp(buf, "enabled")) {
activate = true;
} else if (!strcmp(buf, "disabled")) {
activate = false;
} else {
result = -EINVAL;
goto trip_activate_exit;
}
get_trip_threshold(tz, trip, &threshold);
if (threshold)
result = sensor_activate_trip(tz->sensor.sensor_id,
threshold, activate);
else
result = tz->ops->activate_trip_type(tz, trip,
activate ? THERMAL_TRIP_ACTIVATION_ENABLED :
THERMAL_TRIP_ACTIVATION_DISABLED);
trip_activate_exit:
if (result)
return result;
+3
View File
@@ -102,6 +102,7 @@ struct sensor_threshold {
enum thermal_trip_type trip;
int (*notify)(enum thermal_trip_type type, int temp, void *data);
void *data;
uint8_t active;
struct list_head list;
};
@@ -189,6 +190,8 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *);
int sensor_get_id(char *name);
int sensor_set_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
int sensor_cancel_trip(uint32_t sensor_id, struct sensor_threshold *threshold);
int sensor_activate_trip(uint32_t sensor_id, struct sensor_threshold *threshold,
bool enable);
int thermal_sensor_trip(struct thermal_zone_device *tz,
enum thermal_trip_type trip, long temp);