Thermal: Introduce .get_trend() callback.
authorZhang Rui <rui.zhang@intel.com>
Wed, 27 Jun 2012 01:54:33 +0000 (09:54 +0800)
committerZhang Rui <rui.zhang@intel.com>
Mon, 24 Sep 2012 06:44:36 +0000 (14:44 +0800)
According to ACPI spec, tc1 and tc2 are used by OSPM
to anticipate the temperature trends.
We introduced the same concept to the generic thermal layer
for passive cooling, but now it seems that these values
are hard to be used on other platforms.

So We introduce .get_trend() as a more general solution.

For the platform thermal drivers that have their own way to
anticipate the temperature trends, they should provide
their own .get_trend() callback.
Or else, we will calculate the temperature trends by simply
comparing the current temperature and the cached previous
temperature reading.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Reviewed-by: Rafael J. Wysocki <rjw@sisk.pl>
Reviewed-by: Valentin, Eduardo <eduardo.valentin@ti.com>
drivers/acpi/thermal.c
drivers/thermal/thermal_sys.c
include/linux/thermal.h

index d7ef69d835f2197fd1d520a65140587685468b8c..bb95709a6be8c3a16ce25acfebe490e48d588c0a 100644 (file)
@@ -706,6 +706,38 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
                return -EINVAL;
 }
 
+static int thermal_get_trend(struct thermal_zone_device *thermal,
+                               int trip, enum thermal_trend *trend)
+{
+       struct acpi_thermal *tz = thermal->devdata;
+       enum thermal_trip_type type;
+       int i;
+
+       if (thermal_get_trip_type(thermal, trip, &type))
+               return -EINVAL;
+
+       /* Only PASSIVE trip points need TREND */
+       if (type != THERMAL_TRIP_PASSIVE)
+               return -EINVAL;
+
+       /*
+        * tz->temperature has already been updated by generic thermal layer,
+        * before this callback being invoked
+        */
+       i = (tz->trips.passive.tc1 * (tz->temperature - tz->last_temperature))
+               + (tz->trips.passive.tc2
+               * (tz->temperature - tz->trips.passive.temperature));
+
+       if (i > 0)
+               *trend = THERMAL_TREND_RAISING;
+       else if (i < 0)
+               *trend = THERMAL_TREND_DROPPING;
+       else
+               *trend = THERMAL_TREND_STABLE;
+       return 0;
+}
+
+
 static int thermal_notify(struct thermal_zone_device *thermal, int trip,
                           enum thermal_trip_type trip_type)
 {
@@ -838,6 +870,7 @@ static const struct thermal_zone_device_ops acpi_thermal_zone_ops = {
        .get_trip_type = thermal_get_trip_type,
        .get_trip_temp = thermal_get_trip_temp,
        .get_crit_temp = thermal_get_crit_temp,
+       .get_trend = thermal_get_trend,
        .notify = thermal_notify,
 };
 
index b04fe2c4b0d5ef0c9c554cddd4dba2f967ee956b..146aa043f15b27eb48b051925496b190b55a5d4f 100644 (file)
@@ -723,6 +723,20 @@ static void thermal_zone_device_passive(struct thermal_zone_device *tz,
        struct thermal_cooling_device *cdev;
        long state, max_state;
 
+       if (!tz->ops->get_trend ||
+           tz->ops->get_trend(tz, trip, (enum thermal_trend *)&trend)) {
+               /*
+                * compare the current temperature and previous temperature
+                * to get the thermal trend, if no special requirement
+                */
+               if (tz->temperature > tz->last_temperature)
+                       trend = THERMAL_TREND_RAISING;
+               else if (tz->temperature < tz->last_temperature)
+                       trend = THERMAL_TREND_DROPPING;
+               else
+                       trend = THERMAL_TREND_STABLE;
+       }
+
        /*
         * Above Trip?
         * -----------
@@ -1091,6 +1105,9 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
                goto leave;
        }
 
+       tz->last_temperature = tz->temperature;
+       tz->temperature = temp;
+
        for (count = 0; count < tz->trips; count++) {
                tz->ops->get_trip_type(tz, count, &trip_type);
                tz->ops->get_trip_temp(tz, count, &trip_temp);
@@ -1150,8 +1167,6 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
                thermal_zone_device_passive(tz, temp, tz->forced_passive,
                                            THERMAL_TRIPS_NONE);
 
-       tz->last_temperature = temp;
-
 leave:
        if (tz->passive)
                thermal_zone_device_set_polling(tz, tz->passive_delay);
index 5946a3b90bb2016cf16f6ae4213a36379df51468..6a1d43d2ec922969bd02c7a980d6d5e540bbe089 100644 (file)
@@ -44,6 +44,12 @@ enum thermal_trip_type {
        THERMAL_TRIP_CRITICAL,
 };
 
+enum thermal_trend {
+       THERMAL_TREND_STABLE, /* temperature is stable */
+       THERMAL_TREND_RAISING, /* temperature is raising */
+       THERMAL_TREND_DROPPING, /* temperature is dropping */
+};
+
 struct thermal_zone_device_ops {
        int (*bind) (struct thermal_zone_device *,
                     struct thermal_cooling_device *);
@@ -65,6 +71,8 @@ struct thermal_zone_device_ops {
        int (*set_trip_hyst) (struct thermal_zone_device *, int,
                              unsigned long);
        int (*get_crit_temp) (struct thermal_zone_device *, unsigned long *);
+       int (*get_trend) (struct thermal_zone_device *, int,
+                         enum thermal_trend *);
        int (*notify) (struct thermal_zone_device *, int,
                       enum thermal_trip_type);
 };
@@ -111,6 +119,7 @@ struct thermal_zone_device {
        int tc2;
        int passive_delay;
        int polling_delay;
+       int temperature;
        int last_temperature;
        bool passive;
        unsigned int forced_passive;