blob: d66ae95de5a66e8ae6ae97a09b02e1a1db9c8373 [file] [log] [blame]
Ram Chandrasekar6d44a342016-07-07 11:09:52 -06001/*
2 * Copyright (C) 2012 Intel Corp
3 * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
4 * Copyright (c) 2017, The Linux Foundation. All rights reserved.
5 *
6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
18 */
19
20#include <linux/thermal.h>
21#include <trace/events/thermal.h>
22
23#include "thermal_core.h"
24
25static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
26{
27 int trip_temp, trip_hyst;
28 enum thermal_trip_type trip_type;
29 struct thermal_instance *instance;
30 bool throttle;
31 int old_target;
32
33 tz->ops->get_trip_temp(tz, trip, &trip_temp);
34 tz->ops->get_trip_type(tz, trip, &trip_type);
35 if (tz->ops->get_trip_hyst) {
36 tz->ops->get_trip_hyst(tz, trip, &trip_hyst);
37 trip_hyst = trip_temp + trip_hyst;
38 } else {
39 trip_hyst = trip_temp;
40 }
41
42 mutex_lock(&tz->lock);
43
44 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
45 if (instance->trip != trip)
46 continue;
47
48 if ((tz->temperature <= trip_temp) ||
49 (instance->target != THERMAL_NO_TARGET
50 && tz->temperature <= trip_hyst))
51 throttle = true;
52 else
53 throttle = false;
54
55 dev_dbg(&tz->device,
56 "Trip%d[type=%d,temp=%d,hyst=%d],throttle=%d\n",
57 trip, trip_type, trip_temp, trip_hyst, throttle);
58
59 old_target = instance->target;
60 instance->target = (throttle) ? instance->upper
61 : THERMAL_NO_TARGET;
62 dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
63 old_target, (int)instance->target);
64
65 if (old_target == instance->target)
66 continue;
67
68 if (old_target == THERMAL_NO_TARGET &&
69 instance->target != THERMAL_NO_TARGET) {
70 trace_thermal_zone_trip(tz, trip, trip_type);
71 tz->passive += 1;
72 } else if (old_target != THERMAL_NO_TARGET &&
73 instance->target == THERMAL_NO_TARGET) {
74 tz->passive -= 1;
75 }
76
77 instance->cdev->updated = false; /* cdev needs update */
78 }
79
80 mutex_unlock(&tz->lock);
81}
82
83/**
84 * low_limits_throttle - throttles devices associated with the given zone
85 * @tz - thermal_zone_device
86 * @trip - the trip point
87 *
88 * Throttling Logic: If the sensor reading goes below a trip point, the
89 * pre-defined mitigation will be applied for the cooling device.
90 * If the sensor reading goes above the trip hysteresis, the
91 * mitigation will be removed.
92 */
93static int low_limits_throttle(struct thermal_zone_device *tz, int trip)
94{
95 struct thermal_instance *instance;
96
97 thermal_zone_trip_update(tz, trip);
98
99 mutex_lock(&tz->lock);
100
101 list_for_each_entry(instance, &tz->thermal_instances, tz_node)
102 thermal_cdev_update(instance->cdev);
103
104 mutex_unlock(&tz->lock);
105
106 return 0;
107}
108
109static struct thermal_governor thermal_gov_low_limits_floor = {
110 .name = "low_limits_floor",
111 .throttle = low_limits_throttle,
112 .min_state_throttle = 1,
113};
114
115int thermal_gov_low_limits_register(void)
116{
117 return thermal_register_governor(&thermal_gov_low_limits_floor);
118}
119
120void thermal_gov_low_limits_unregister(void)
121{
122 thermal_unregister_governor(&thermal_gov_low_limits_floor);
123}