summaryrefslogtreecommitdiff
path: root/drivers/thermal
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2016-06-22 11:42:01 +0300
committerZhang Rui <rui.zhang@intel.com>2016-09-27 09:02:16 +0300
commit060c034a974187e930b790957cafc5047cc30a40 (patch)
tree0afdf73e38e94d0bd704ba40ae283ee088df6179 /drivers/thermal
parent032d4057291e9d017cf50be017cf09b169ff438f (diff)
downloadlinux-060c034a974187e930b790957cafc5047cc30a40.tar.xz
thermal: Add support for hardware-tracked trip points
This adds support for hardware-tracked trip points to the device tree thermal sensor framework. The framework supports an arbitrary number of trip points. Whenever the current temperature is updated, the trip points immediately below and above the current temperature are found. A .set_trips callback is then called with the temperatures. If there is no trip point above or below the current temperature, the passed trip temperature will be -INT_MAX or INT_MAX respectively. In this callback, the driver should program the hardware such that it is notified when either of these trip points are triggered. When a trip point is triggered, the driver should call `thermal_zone_device_update' for the respective thermal zone. This will cause the trip points to be updated again. If .set_trips is not implemented, the framework behaves as before. This patch is based on an earlier version from Mikko Perttunen <mikko.perttunen@kapsi.fi> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de> Signed-off-by: Caesar Wang <wxt@rock-chips.com> Cc: Zhang Rui <rui.zhang@intel.com> Cc: Eduardo Valentin <edubezval@gmail.com> Cc: linux-pm@vger.kernel.org Reviewed-by: Javi Merino <javi.merino@arm.com> Signed-off-by: Eduardo Valentin <edubezval@gmail.com> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/thermal_core.c55
1 files changed, 55 insertions, 0 deletions
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 8728cc615452..f2d55e478b2a 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -520,6 +520,56 @@ exit:
}
EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
+void thermal_zone_set_trips(struct thermal_zone_device *tz)
+{
+ int low = -INT_MAX;
+ int high = INT_MAX;
+ int trip_temp, hysteresis;
+ int i, ret;
+
+ mutex_lock(&tz->lock);
+
+ if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
+ goto exit;
+
+ for (i = 0; i < tz->trips; i++) {
+ int trip_low;
+
+ tz->ops->get_trip_temp(tz, i, &trip_temp);
+ tz->ops->get_trip_hyst(tz, i, &hysteresis);
+
+ trip_low = trip_temp - hysteresis;
+
+ if (trip_low < tz->temperature && trip_low > low)
+ low = trip_low;
+
+ if (trip_temp > tz->temperature && trip_temp < high)
+ high = trip_temp;
+ }
+
+ /* No need to change trip points */
+ if (tz->prev_low_trip == low && tz->prev_high_trip == high)
+ goto exit;
+
+ tz->prev_low_trip = low;
+ tz->prev_high_trip = high;
+
+ dev_dbg(&tz->device,
+ "new temperature boundaries: %d < x < %d\n", low, high);
+
+ /*
+ * Set a temperature window. When this window is left the driver
+ * must inform the thermal core via thermal_zone_device_update.
+ */
+ ret = tz->ops->set_trips(tz, low, high);
+ if (ret)
+ dev_err(&tz->device, "Failed to set trips: %d\n", ret);
+
+exit:
+ mutex_unlock(&tz->lock);
+}
+EXPORT_SYMBOL_GPL(thermal_zone_set_trips);
+
static void update_temperature(struct thermal_zone_device *tz)
{
int temp, ret;
@@ -569,6 +619,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
update_temperature(tz);
+ thermal_zone_set_trips(tz);
+
for (count = 0; count < tz->trips; count++)
handle_thermal_trip(tz, count);
}
@@ -754,6 +806,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
*/
ret = tz->ops->set_trip_hyst(tz, trip, temperature);
+ if (!ret)
+ thermal_zone_set_trips(tz);
+
return ret ? ret : count;
}