diff options
Diffstat (limited to 'drivers/thermal/gov_bang_bang.c')
| -rw-r--r-- | drivers/thermal/gov_bang_bang.c | 115 |
1 files changed, 75 insertions, 40 deletions
diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c index acb52c9ee10f..51951967d67f 100644 --- a/drivers/thermal/gov_bang_bang.c +++ b/drivers/thermal/gov_bang_bang.c @@ -7,17 +7,6 @@ * Based on step_wise.c with following Copyrights: * Copyright (C) 2012 Intel Corp * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com> - */ - -#include <linux/thermal.h> - -#include "thermal_core.h" - -/** - * bang_bang_control - controls devices associated with the given zone - * @tz: thermal_zone_device - * @trip: the trip point - * @crossed_up: whether or not the trip has been crossed on the way up * * Regulation Logic: a two point regulation, deliver cooling state depending * on the previous state shown in this diagram: @@ -39,12 +28,43 @@ * gets turned on. * * In case the fan is running, temperature must fall below * (trip_temp - hyst) so that the fan gets turned off again. - * */ -static void bang_bang_control(struct thermal_zone_device *tz, - const struct thermal_trip *trip, - bool crossed_up) + +#include <linux/thermal.h> + +#include "thermal_core.h" + +static void bang_bang_set_instance_target(struct thermal_instance *instance, + unsigned int target) +{ + if (instance->target != 0 && instance->target != 1 && + instance->target != THERMAL_NO_TARGET) + pr_debug("Unexpected state %ld of thermal instance %s in bang-bang\n", + instance->target, instance->name); + + /* + * Enable the fan when the trip is crossed on the way up and disable it + * when the trip is crossed on the way down. + */ + instance->target = target; + instance->initialized = true; + + dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target); + + thermal_cdev_update_nocheck(instance->cdev); +} + +/** + * bang_bang_trip_crossed - controls devices associated with the given zone + * @tz: thermal_zone_device + * @trip: the trip point + * @upward: whether or not the trip has been crossed on the way up + */ +static void bang_bang_trip_crossed(struct thermal_zone_device *tz, + const struct thermal_trip *trip, + bool upward) { + const struct thermal_trip_desc *td = trip_to_trip_desc(trip); struct thermal_instance *instance; lockdep_assert_held(&tz->lock); @@ -53,42 +73,57 @@ static void bang_bang_control(struct thermal_zone_device *tz, thermal_zone_trip_id(tz, trip), trip->temperature, tz->temperature, trip->hysteresis); - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { - if (instance->trip != trip) - continue; + list_for_each_entry(instance, &td->thermal_instances, trip_node) + bang_bang_set_instance_target(instance, upward); +} - if (instance->target == THERMAL_NO_TARGET) - instance->target = 0; +static void bang_bang_manage(struct thermal_zone_device *tz) +{ + const struct thermal_trip_desc *td; + struct thermal_instance *instance; - if (instance->target != 0 && instance->target != 1) { - pr_debug("Unexpected state %ld of thermal instance %s in bang-bang\n", - instance->target, instance->name); + /* If the code below has run already, nothing needs to be done. */ + if (tz->governor_data) + return; - instance->target = 1; - } + for_each_trip_desc(tz, td) { + const struct thermal_trip *trip = &td->trip; + bool turn_on; + + if (trip->temperature == THERMAL_TEMP_INVALID || + trip->type == THERMAL_TRIP_CRITICAL || + trip->type == THERMAL_TRIP_HOT) + continue; /* - * Enable the fan when the trip is crossed on the way up and - * disable it when the trip is crossed on the way down. + * Adjust the target states for uninitialized thermal instances + * to the thermal zone temperature and the trip point threshold. */ - if (instance->target == 0 && crossed_up) - instance->target = 1; - else if (instance->target == 1 && !crossed_up) - instance->target = 0; - - dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target); - - mutex_lock(&instance->cdev->lock); - instance->cdev->updated = false; /* cdev needs update */ - mutex_unlock(&instance->cdev->lock); + turn_on = tz->temperature >= td->threshold; + list_for_each_entry(instance, &td->thermal_instances, trip_node) { + if (!instance->initialized) + bang_bang_set_instance_target(instance, turn_on); + } } - list_for_each_entry(instance, &tz->thermal_instances, tz_node) - thermal_cdev_update(instance->cdev); + tz->governor_data = (void *)true; +} + +static void bang_bang_update_tz(struct thermal_zone_device *tz, + enum thermal_notify_event reason) +{ + /* + * Let bang_bang_manage() know that it needs to walk trips after binding + * a new cdev and after system resume. + */ + if (reason == THERMAL_TZ_BIND_CDEV || reason == THERMAL_TZ_RESUME) + tz->governor_data = NULL; } static struct thermal_governor thermal_gov_bang_bang = { .name = "bang_bang", - .trip_crossed = bang_bang_control, + .trip_crossed = bang_bang_trip_crossed, + .manage = bang_bang_manage, + .update_tz = bang_bang_update_tz, }; THERMAL_GOVERNOR_DECLARE(thermal_gov_bang_bang); |
