blob: af9aaaaa0c2d6ca9759550ed29d2b199e7aa5b6a [file] [log] [blame]
#include <linux/thermal.h>
#include "thermal_core.h"
static unsigned long get_target_state(struct thermal_zone_device *tz, int old)
{
int i;
unsigned long cur_state = 0, tmp_state = 0;
enum thermal_trend trend;
int trip_temp;
trend = get_tz_trend(tz, THERMAL_TRIPS_NONE);
if (THERMAL_TREND_RAISING == trend) {
for (i = 0; i < tz->trips; i++) {
tz->ops->get_trip_temp(tz, i, &trip_temp);
if (tz->temperature < trip_temp)
break;
}
if (tz->tzdctrl.state_ctrl) {
tmp_state = i;
/* only care up */
if (tmp_state > old)
cur_state = tmp_state;
else
cur_state = old;
} else
cur_state = i;
} else if (THERMAL_TREND_DROPPING == trend) {
for (i = 0; i < tz->trips; i++) {
if (tz->ops->get_trip_hyst)
tz->ops->get_trip_hyst(tz, i, &trip_temp);
else
tz->ops->get_trip_temp(tz, i, &trip_temp);
if (tz->temperature <= trip_temp)
break;
}
if (tz->tzdctrl.state_ctrl) {
tmp_state = i;
/* only care down */
if (tmp_state < old)
cur_state = tmp_state;
else
cur_state = old;
} else
cur_state = i;
} else if (THERMAL_TREND_STABLE == trend)
cur_state = old;
else
cur_state = old;
return cur_state;
}
static int bi_direction_throttle(struct thermal_zone_device *tz, int trip)
{
struct thermal_instance *instance;
int old_target;
mutex_lock(&tz->lock);
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
old_target = instance->target;
instance->target = get_target_state(tz,
(THERMAL_NO_TARGET == old_target) ? 0 : old_target);
if (old_target != instance->target) {
instance->cdev->updated = false;
thermal_cdev_update(instance->cdev);
break;
}
}
mutex_unlock(&tz->lock);
return 0;
}
static int bi_direction_gov_switch(struct thermal_zone_device *tz,
struct thermal_governor *from, struct thermal_governor *to)
{
int i;
struct thermal_instance *ins;
int trip_temp;
if (!strncasecmp(from->name, "user_space", THERMAL_NAME_LENGTH)) {
for (i = 0; i < tz->trips; i++) {
if (tz->ops->get_trip_hyst)
tz->ops->get_trip_hyst(tz, i, &trip_temp);
else
tz->ops->get_trip_temp(tz, i, &trip_temp);
if (tz->temperature <= trip_temp)
break;
}
/* init kernel constraints */
mutex_lock(&tz->lock);
list_for_each_entry(ins, &tz->thermal_instances, tz_node) {
ins->target = i;
ins->cdev->updated = false;
thermal_cdev_update(ins->cdev);
}
mutex_unlock(&tz->lock);
} else if (!strncasecmp(to->name, "user_space", THERMAL_NAME_LENGTH)) {
/* release kernel constraints */
mutex_lock(&tz->lock);
list_for_each_entry(ins, &tz->thermal_instances, tz_node) {
ins->target = 0;
ins->cdev->updated = false;
thermal_cdev_update(ins->cdev);
}
mutex_unlock(&tz->lock);
}
return 0;
}
static struct thermal_governor thermal_gov_bi_direction = {
.name = "bi_direction",
.throttle = bi_direction_throttle,
.switch_gov = bi_direction_gov_switch,
};
THERMAL_GOVERNOR_DECLARE(thermal_gov_bi_direction);