@@ -354,30 +354,48 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
tz->ops->critical(tz);
}
-static void handle_thermal_trip_crossed(struct thermal_zone_device *tz, int trip,
+static void handle_thermal_trip_crossed(struct thermal_zone_device *tz, int index,
int trip_temp, int trip_hyst,
enum thermal_trip_type trip_type)
{
+ int trip_low_temp = trip_temp - trip_hyst;
+ int trip = tz->trips_indexes[index];
+
if (tz->last_temperature == THERMAL_TEMP_INVALID)
return;
- if (tz->last_temperature < trip_temp &&
- tz->temperature >= trip_temp) {
- thermal_notify_tz_trip_up(tz->id, trip,
- tz->temperature);
- }
-
- if (tz->last_temperature >= trip_temp &&
- tz->temperature < (trip_temp - trip_hyst)) {
- thermal_notify_tz_trip_down(tz->id, trip,
- tz->temperature);
+ /*
+ * Due to the hysteresis, a third information is needed to
+ * detect when the temperature is wavering between the
+ * trip_low_temp and the trip_temp. A trip point is crossed
+ * the way up only if the temperature is above it while the
+ * previous temperature was below *and* we crossed the
+ * trip_temp_low before. The previous trip point give us the
+ * previous trip point transition. The similar problem exists
+ * when crossing the way down.
+ *
+ * Note the mechanism works only if the caller of the function
+ * invoke the function with the trip point ascending or
+ * descending regarding the temperature trend. A temperature
+ * drop trend will browse the trip point in the descending
+ * order
+ */
+ if (tz->last_temperature < trip_temp && tz->temperature >= trip_temp &&
+ index != tz->prev_index) {
+ thermal_notify_tz_trip_up(tz->id, trip, tz->temperature);
+ tz->prev_index = index;
+ } else if (tz->last_temperature >= trip_low_temp && tz->temperature < trip_low_temp &&
+ index == tz->prev_index) {
+ thermal_notify_tz_trip_down(tz->id, trip, tz->temperature);
+ tz->prev_index--;
}
}
-static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
+static void handle_thermal_trip(struct thermal_zone_device *tz, int index)
{
enum thermal_trip_type type;
int trip_temp, hyst = 0;
+ int trip = tz->trips_indexes[index];
/* Ignore disabled trip points */
if (test_bit(trip, &tz->trips_disabled))
@@ -388,7 +406,7 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
if (tz->ops->get_trip_hyst)
tz->ops->get_trip_hyst(tz, trip, &hyst);
- handle_thermal_trip_crossed(tz, trip, trip_temp, hyst, type);
+ handle_thermal_trip_crossed(tz, index, trip_temp, hyst, type);
if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
handle_critical_trips(tz, trip, trip_temp, type);
@@ -428,6 +446,7 @@ static void thermal_zone_device_init(struct thermal_zone_device *tz)
{
struct thermal_instance *pos;
tz->temperature = THERMAL_TEMP_INVALID;
+ tz->prev_index = -1;
tz->prev_low_trip = -INT_MAX;
tz->prev_high_trip = INT_MAX;
list_for_each_entry(pos, &tz->thermal_instances, tz_node)
@@ -512,8 +531,13 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
tz->notify_event = event;
- for (count = 0; count < tz->num_trips; count++)
- handle_thermal_trip(tz, count);
+ if (tz->last_temperature <= tz->temperature) {
+ for (count = 0; count < tz->num_trips; count++)
+ handle_thermal_trip(tz, count);
+ } else {
+ for (count = tz->num_trips; count >= 0; count--)
+ handle_thermal_trip(tz, count);
+ }
}
EXPORT_SYMBOL_GPL(thermal_zone_device_update);
@@ -138,6 +138,7 @@ struct thermal_cooling_device {
* @last_temperature: previous temperature read
* @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION
* @passive: 1 if you've crossed a passive trip point, 0 otherwise.
+ * @prev_index: previous index pointing to the trip point the thermal zone was
* @prev_low_trip: the low current temperature if you've crossed a passive
trip point.
* @prev_high_trip: the above current temperature if you've crossed a
@@ -175,6 +176,7 @@ struct thermal_zone_device {
int last_temperature;
int emul_temperature;
int passive;
+ int prev_index;
int prev_low_trip;
int prev_high_trip;
atomic_t need_update;