diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 7a7639433279..ec0657f2d15b 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -412,6 +412,48 @@ static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip, return 0; } +static bool of_thermal_is_trips_triggered(struct thermal_zone_device *tz, + int temp) +{ + int tt, th, trip, last_temp; + struct __thermal_zone *data = tz->devdata; + bool triggered = false; + + if (!tz->tzp) + return triggered; + + mutex_lock(&tz->lock); + last_temp = tz->temperature; + for (trip = 0; trip < data->ntrips; trip++) { + if (!tz->tzp->tracks_low) { + tt = data->trips[trip].temperature; + if (temp >= tt && last_temp < tt) { + triggered = true; + break; + } + th = tt - data->trips[trip].hysteresis; + if (temp <= th && last_temp > th) { + triggered = true; + break; + } + } else { + tt = data->trips[trip].temperature; + if (temp <= tt && last_temp > tt) { + triggered = true; + break; + } + th = tt + data->trips[trip].hysteresis; + if (temp >= th && last_temp < th) { + triggered = true; + break; + } + } + } + mutex_unlock(&tz->lock); + + return triggered; +} + static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip, int temp) { @@ -484,6 +526,63 @@ static bool of_thermal_is_wakeable(struct thermal_zone_device *tz) return data->is_wakeable; } +static void handle_thermal_trip(struct thermal_zone_device *tz, + bool temp_valid, int trip_temp) +{ + struct thermal_zone_device *zone; + struct __thermal_zone *data; + struct list_head *head; + + if (!tz || !tz->devdata) + return; + + data = tz->devdata; + + if (!data->senps) + return; + + head = &data->senps->first_tz; + + list_for_each_entry(data, head, list) { + zone = data->tzd; + if (data->mode == THERMAL_DEVICE_DISABLED) + continue; + if (!temp_valid) { + thermal_zone_device_update(zone, + THERMAL_EVENT_UNSPECIFIED); + } else { + if (!of_thermal_is_trips_triggered(zone, trip_temp)) + continue; + thermal_zone_device_update_temp(zone, + THERMAL_EVENT_UNSPECIFIED, trip_temp); + } + } +} + +/* + * of_thermal_handle_trip_temp - Handle thermal trip from sensors + * + * @tz: pointer to the primary thermal zone. + * @trip_temp: The temperature + */ +void of_thermal_handle_trip_temp(struct thermal_zone_device *tz, + int trip_temp) +{ + return handle_thermal_trip(tz, true, trip_temp); +} +EXPORT_SYMBOL_GPL(of_thermal_handle_trip_temp); + +/* + * of_thermal_handle_trip - Handle thermal trip from sensors + * + * @tz: pointer to the primary thermal zone. + */ +void of_thermal_handle_trip(struct thermal_zone_device *tz) +{ + return handle_thermal_trip(tz, false, 0); +} +EXPORT_SYMBOL_GPL(of_thermal_handle_trip); + static struct thermal_zone_device_ops of_thermal_ops = { .get_mode = of_thermal_get_mode, .set_mode = of_thermal_set_mode, diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index c8cf23e77b49..09abad00c249 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -424,6 +424,23 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) monitor_thermal_zone(tz); } +static void store_temperature(struct thermal_zone_device *tz, int temp) +{ + mutex_lock(&tz->lock); + tz->last_temperature = tz->temperature; + tz->temperature = temp; + mutex_unlock(&tz->lock); + + trace_thermal_temperature(tz); + if (tz->last_temperature == THERMAL_TEMP_INVALID || + tz->last_temperature == THERMAL_TEMP_INVALID_LOW) + dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n", + tz->temperature); + else + dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", + tz->last_temperature, tz->temperature); +} + static void update_temperature(struct thermal_zone_device *tz) { int temp, ret; @@ -436,19 +453,7 @@ static void update_temperature(struct thermal_zone_device *tz) ret); return; } - - mutex_lock(&tz->lock); - tz->last_temperature = tz->temperature; - tz->temperature = temp; - mutex_unlock(&tz->lock); - - trace_thermal_temperature(tz); - if (tz->last_temperature == THERMAL_TEMP_INVALID) - dev_dbg(&tz->device, "last_temperature N/A, current_temperature=%d\n", - tz->temperature); - else - dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", - tz->last_temperature, tz->temperature); + store_temperature(tz, temp); } static void thermal_zone_device_init(struct thermal_zone_device *tz) @@ -465,6 +470,28 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz) thermal_zone_device_init(tz); } +void thermal_zone_device_update_temp(struct thermal_zone_device *tz, + enum thermal_notify_event event, int temp) +{ + int count; + + if (!tz || !tz->ops) + return; + + if (atomic_read(&in_suspend) && (!tz->ops->is_wakeable || + !(tz->ops->is_wakeable(tz)))) + return; + + store_temperature(tz, temp); + + thermal_zone_set_trips(tz); + + tz->notify_event = event; + + for (count = 0; count < tz->trips; count++) + handle_thermal_trip(tz, count); +} + void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index 0df190ed82a7..d1183139e433 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -122,6 +122,9 @@ int of_thermal_get_ntrips(struct thermal_zone_device *); bool of_thermal_is_trip_valid(struct thermal_zone_device *, int); const struct thermal_trip * of_thermal_get_trip_points(struct thermal_zone_device *); +void of_thermal_handle_trip(struct thermal_zone_device *tz); +void of_thermal_handle_trip_temp(struct thermal_zone_device *tz, + int trip_temp); #else static inline int of_parse_thermal_zones(void) { return 0; } static inline void of_thermal_destroy_zones(void) { } @@ -139,6 +142,13 @@ of_thermal_get_trip_points(struct thermal_zone_device *tz) { return NULL; } +static inline +void of_thermal_handle_trip(struct thermal_zone_device *tz) +{ } +static inline +void of_thermal_handle_trip_temp(struct thermal_zone_device *tz, + int trip_temp) +{ } #endif #endif /* __THERMAL_CORE_H__ */ diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 3359840b86be..86395c856b45 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -35,6 +35,12 @@ /* use value, which < 0K, to indicate an invalid/uninitialized temperature */ #define THERMAL_TEMP_INVALID -274000 +/* + * use a high value for low temp tracking zone, + * to indicate an invalid/uninitialized temperature + */ +#define THERMAL_TEMP_INVALID_LOW 274000 + /* Unit conversion macros */ #define DECI_KELVIN_TO_CELSIUS(t) ({ \ long _t = (t); \ @@ -497,6 +503,8 @@ int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int, struct thermal_cooling_device *); void thermal_zone_device_update(struct thermal_zone_device *, enum thermal_notify_event); +void thermal_zone_device_update_temp(struct thermal_zone_device *tz, + enum thermal_notify_event event, int temp); void thermal_zone_set_trips(struct thermal_zone_device *); struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, @@ -550,6 +558,10 @@ static inline int thermal_zone_unbind_cooling_device( static inline void thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { } +static inline void thermal_zone_device_update_temp( + struct thermal_zone_device *tz, enum thermal_notify_event event, + int temp) +{ } static inline void thermal_zone_set_trips(struct thermal_zone_device *tz) { } static inline struct thermal_cooling_device *