summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/thermal/sysfs-api.txt7
-rw-r--r--drivers/thermal/thermal_core.c55
-rw-r--r--include/linux/thermal.h10
3 files changed, 72 insertions, 0 deletions
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index 755476ea3fda..ef473dc7f55e 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -49,6 +49,9 @@ temperature) and throttle appropriate devices.
.bind: bind the thermal zone device with a thermal cooling device.
.unbind: unbind the thermal zone device with a thermal cooling device.
.get_temp: get the current temperature of the thermal zone.
+ .set_trips: set the trip points window. Whenever the current temperature
+ is updated, the trip points immediately below and above the
+ current temperature are found.
.get_mode: get the current mode (enabled/disabled) of the thermal zone.
- "enabled" means the kernel thermal management is enabled.
- "disabled" will prevent kernel thermal driver action upon trip points
@@ -95,6 +98,10 @@ temperature) and throttle appropriate devices.
get_temp: a pointer to a function that reads the
sensor temperature. This is mandatory
callback provided by sensor driver.
+ set_trips: a pointer to a function that sets a
+ temperature window. When this window is
+ left the driver must inform the thermal
+ core via thermal_zone_device_update.
get_trend: a pointer to a function that reads the
sensor temperature trend.
set_emul_temp: a pointer to a function that sets
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;
}
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 707d7353c28b..54cdfeaaedd4 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -98,6 +98,7 @@ struct thermal_zone_device_ops {
int (*unbind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*get_temp) (struct thermal_zone_device *, int *);
+ int (*set_trips) (struct thermal_zone_device *, int, int);
int (*get_mode) (struct thermal_zone_device *,
enum thermal_device_mode *);
int (*set_mode) (struct thermal_zone_device *,
@@ -168,6 +169,10 @@ struct thermal_attr {
* @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_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
+ passive trip point.
* @forced_passive: If > 0, temperature at which to switch on all ACPI
* processor cooling devices. Currently only used by the
* step-wise governor.
@@ -199,6 +204,8 @@ struct thermal_zone_device {
int last_temperature;
int emul_temperature;
int passive;
+ int prev_low_trip;
+ int prev_high_trip;
unsigned int forced_passive;
atomic_t need_update;
struct thermal_zone_device_ops *ops;
@@ -426,6 +433,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
void thermal_zone_device_update(struct thermal_zone_device *);
+void thermal_zone_set_trips(struct thermal_zone_device *);
struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
const struct thermal_cooling_device_ops *);
@@ -477,6 +485,8 @@ static inline int thermal_zone_unbind_cooling_device(
{ return -ENODEV; }
static inline void thermal_zone_device_update(struct thermal_zone_device *tz)
{ }
+static inline void thermal_zone_set_trips(struct thermal_zone_device *tz)
+{ }
static inline struct thermal_cooling_device *
thermal_cooling_device_register(char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)