Notify all related thermal zones when the sensor reports a thermal trip. Signed-off-by: Lina Iyer <ilina@xxxxxxxxxxxxxx> --- drivers/thermal/of-thermal.c | 83 ++++++++++++++++++++++++++++++++++-- include/linux/thermal.h | 4 ++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 6fb2eeb5b6cf..9b42bfed78bf 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -41,12 +41,18 @@ struct __thermal_bind_params { * @ops: sensor driver ops * @tz_list: list of thermal zones for this sensor * @lock: lock sensor during operations + * @low_trip: sensor's low trip temp + * @high_trip: sensor's high trip temp + * @low_tz: the thermal zone whose low trip is used as @low_trip + * @high_tz: the thermal zone whose high trip is used as @high_trip */ struct thermal_sensor { void *sensor_data; const struct thermal_zone_of_device_ops *ops; struct list_head tz_list; struct mutex lock; + int low_trip, high_trip; + struct thermal_zone_device *low_tz, *high_tz; }; /** @@ -102,18 +108,26 @@ static void __of_thermal_agg_trip(struct thermal_sensor *sensor, int low, high; int max_lo = INT_MIN; int min_hi = INT_MAX; - struct thermal_zone_device *tz; + struct thermal_zone_device *tz, *lo_tz = NULL, *hi_tz = NULL; list_for_each_entry(tz, &sensor->tz_list, sensor_tzd) { thermal_zone_get_trip(tz, &low, &high); - if (low > max_lo) + if (low > max_lo) { max_lo = low; - if (high < min_hi) + lo_tz = tz; + } + if (high < min_hi) { min_hi = high; + hi_tz = tz; + } } *floor = max_lo; *ceil = min_hi; + sensor->low_trip = max_lo; + sensor->high_trip = min_hi; + sensor->low_tz = lo_tz; + sensor->high_tz = hi_tz; } static int of_thermal_set_trips(struct thermal_zone_device *tz, @@ -427,6 +441,69 @@ static struct thermal_zone_device_ops of_thermal_ops = { /*** sensor API ***/ +static void thermal_zone_of_get_trip(struct thermal_zone_device *tz, + int temp, int *low_trip, int *hi_trip) +{ + struct __thermal_zone *data = tz->devdata; + int low = INT_MIN; + int hi = INT_MAX; + int i; + + for (i = 0; i < data->ntrips; i++) { + int trip_temp = data->trips[i].temperature; + + if (trip_temp < temp && trip_temp > low) + *low_trip = i; + if (trip_temp > temp && trip_temp < hi) + *hi_trip = i; + } +} + +/** + * thermal_zone_of_sensor_notify - notify framework of a trip + * @tzd: the thermal zone device + * + * Sensor drivers may use this API to notify the thermal framework that the + * temperature has crossed the trip threshold. This function is akin to + * thermal_notify_framework() call, but is expected to be called by a sensor + * that registered itself with the framework using the + * thermal_zone_of_add_sensor() function. + */ +void thermal_zone_of_sensor_notify(struct thermal_zone_device *tzd) +{ + struct __thermal_zone *tz = tzd->devdata; + struct thermal_sensor *sensor = tz->sensor; + int temp, low_trip, hi_trip, *trip; + struct thermal_zone_device *trip_tz = NULL; + + if (!tz->sensor) + return; + + if (of_thermal_get_temp(tzd, &temp)) + return; + + mutex_lock(&sensor->lock); + if (tzd->temperature < sensor->low_trip && sensor->low_tz) { + trip_tz = sensor->low_tz; + trip = &low_trip; + } + if (tzd->temperature > sensor->high_trip && sensor->high_tz) { + trip_tz = sensor->high_tz; + trip = &hi_trip; + } + + if (trip_tz) + thermal_zone_of_get_trip(trip_tz, temp, &low_trip, &hi_trip); + + mutex_unlock(&sensor->lock); + + if (!trip_tz) + return; + + thermal_notify_framework(trip_tz, *trip); +} +EXPORT_SYMBOL(thermal_zone_of_sensor_notify); + static struct thermal_zone_device * thermal_zone_of_add_sensor(struct device_node *zone, struct device_node *sensor_np, diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 000ae6a97678..603bf8065d7d 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -388,6 +388,7 @@ struct thermal_zone_device *devm_thermal_zone_of_sensor_register( const struct thermal_zone_of_device_ops *ops); void devm_thermal_zone_of_sensor_unregister(struct device *dev, struct thermal_zone_device *tz); +void thermal_zone_of_sensor_notify(struct thermal_zone_device *tzd); #else static inline struct thermal_zone_device * thermal_zone_of_sensor_register(struct device *dev, int id, void *data, @@ -415,6 +416,9 @@ void devm_thermal_zone_of_sensor_unregister(struct device *dev, { } +static inline +void thermal_zone_of_sensor_notify(struct thermal_zone_device *tzd) +{ } #endif #if IS_ENABLED(CONFIG_THERMAL) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html