diff options
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/Makefile | 3 | ||||
-rw-r--r-- | drivers/thermal/thermal_core.c | 170 | ||||
-rw-r--r-- | drivers/thermal/thermal_helpers.c | 196 |
3 files changed, 198 insertions, 171 deletions
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 767c3c9aeeea..6a3d7b573036 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile | |||
@@ -3,7 +3,8 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-$(CONFIG_THERMAL) += thermal_sys.o | 5 | obj-$(CONFIG_THERMAL) += thermal_sys.o |
6 | thermal_sys-y += thermal_core.o thermal_sysfs.o | 6 | thermal_sys-y += thermal_core.o thermal_sysfs.o \ |
7 | thermal_helpers.o | ||
7 | 8 | ||
8 | # interface to/from other layers providing sensors | 9 | # interface to/from other layers providing sensors |
9 | thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o | 10 | thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o |
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 3a189fd729b9..519aa94d0837 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c | |||
@@ -230,48 +230,6 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id) | |||
230 | mutex_unlock(lock); | 230 | mutex_unlock(lock); |
231 | } | 231 | } |
232 | 232 | ||
233 | int get_tz_trend(struct thermal_zone_device *tz, int trip) | ||
234 | { | ||
235 | enum thermal_trend trend; | ||
236 | |||
237 | if (tz->emul_temperature || !tz->ops->get_trend || | ||
238 | tz->ops->get_trend(tz, trip, &trend)) { | ||
239 | if (tz->temperature > tz->last_temperature) | ||
240 | trend = THERMAL_TREND_RAISING; | ||
241 | else if (tz->temperature < tz->last_temperature) | ||
242 | trend = THERMAL_TREND_DROPPING; | ||
243 | else | ||
244 | trend = THERMAL_TREND_STABLE; | ||
245 | } | ||
246 | |||
247 | return trend; | ||
248 | } | ||
249 | EXPORT_SYMBOL(get_tz_trend); | ||
250 | |||
251 | struct thermal_instance * | ||
252 | get_thermal_instance(struct thermal_zone_device *tz, | ||
253 | struct thermal_cooling_device *cdev, int trip) | ||
254 | { | ||
255 | struct thermal_instance *pos = NULL; | ||
256 | struct thermal_instance *target_instance = NULL; | ||
257 | |||
258 | mutex_lock(&tz->lock); | ||
259 | mutex_lock(&cdev->lock); | ||
260 | |||
261 | list_for_each_entry(pos, &tz->thermal_instances, tz_node) { | ||
262 | if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { | ||
263 | target_instance = pos; | ||
264 | break; | ||
265 | } | ||
266 | } | ||
267 | |||
268 | mutex_unlock(&cdev->lock); | ||
269 | mutex_unlock(&tz->lock); | ||
270 | |||
271 | return target_instance; | ||
272 | } | ||
273 | EXPORT_SYMBOL(get_thermal_instance); | ||
274 | |||
275 | static void print_bind_err_msg(struct thermal_zone_device *tz, | 233 | static void print_bind_err_msg(struct thermal_zone_device *tz, |
276 | struct thermal_cooling_device *cdev, int ret) | 234 | struct thermal_cooling_device *cdev, int ret) |
277 | { | 235 | { |
@@ -472,105 +430,6 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip) | |||
472 | monitor_thermal_zone(tz); | 430 | monitor_thermal_zone(tz); |
473 | } | 431 | } |
474 | 432 | ||
475 | /** | ||
476 | * thermal_zone_get_temp() - returns the temperature of a thermal zone | ||
477 | * @tz: a valid pointer to a struct thermal_zone_device | ||
478 | * @temp: a valid pointer to where to store the resulting temperature. | ||
479 | * | ||
480 | * When a valid thermal zone reference is passed, it will fetch its | ||
481 | * temperature and fill @temp. | ||
482 | * | ||
483 | * Return: On success returns 0, an error code otherwise | ||
484 | */ | ||
485 | int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) | ||
486 | { | ||
487 | int ret = -EINVAL; | ||
488 | int count; | ||
489 | int crit_temp = INT_MAX; | ||
490 | enum thermal_trip_type type; | ||
491 | |||
492 | if (!tz || IS_ERR(tz) || !tz->ops->get_temp) | ||
493 | goto exit; | ||
494 | |||
495 | mutex_lock(&tz->lock); | ||
496 | |||
497 | ret = tz->ops->get_temp(tz, temp); | ||
498 | |||
499 | if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) { | ||
500 | for (count = 0; count < tz->trips; count++) { | ||
501 | ret = tz->ops->get_trip_type(tz, count, &type); | ||
502 | if (!ret && type == THERMAL_TRIP_CRITICAL) { | ||
503 | ret = tz->ops->get_trip_temp(tz, count, | ||
504 | &crit_temp); | ||
505 | break; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * Only allow emulating a temperature when the real temperature | ||
511 | * is below the critical temperature so that the emulation code | ||
512 | * cannot hide critical conditions. | ||
513 | */ | ||
514 | if (!ret && *temp < crit_temp) | ||
515 | *temp = tz->emul_temperature; | ||
516 | } | ||
517 | |||
518 | mutex_unlock(&tz->lock); | ||
519 | exit: | ||
520 | return ret; | ||
521 | } | ||
522 | EXPORT_SYMBOL_GPL(thermal_zone_get_temp); | ||
523 | |||
524 | void thermal_zone_set_trips(struct thermal_zone_device *tz) | ||
525 | { | ||
526 | int low = -INT_MAX; | ||
527 | int high = INT_MAX; | ||
528 | int trip_temp, hysteresis; | ||
529 | int i, ret; | ||
530 | |||
531 | mutex_lock(&tz->lock); | ||
532 | |||
533 | if (!tz->ops->set_trips || !tz->ops->get_trip_hyst) | ||
534 | goto exit; | ||
535 | |||
536 | for (i = 0; i < tz->trips; i++) { | ||
537 | int trip_low; | ||
538 | |||
539 | tz->ops->get_trip_temp(tz, i, &trip_temp); | ||
540 | tz->ops->get_trip_hyst(tz, i, &hysteresis); | ||
541 | |||
542 | trip_low = trip_temp - hysteresis; | ||
543 | |||
544 | if (trip_low < tz->temperature && trip_low > low) | ||
545 | low = trip_low; | ||
546 | |||
547 | if (trip_temp > tz->temperature && trip_temp < high) | ||
548 | high = trip_temp; | ||
549 | } | ||
550 | |||
551 | /* No need to change trip points */ | ||
552 | if (tz->prev_low_trip == low && tz->prev_high_trip == high) | ||
553 | goto exit; | ||
554 | |||
555 | tz->prev_low_trip = low; | ||
556 | tz->prev_high_trip = high; | ||
557 | |||
558 | dev_dbg(&tz->device, | ||
559 | "new temperature boundaries: %d < x < %d\n", low, high); | ||
560 | |||
561 | /* | ||
562 | * Set a temperature window. When this window is left the driver | ||
563 | * must inform the thermal core via thermal_zone_device_update. | ||
564 | */ | ||
565 | ret = tz->ops->set_trips(tz, low, high); | ||
566 | if (ret) | ||
567 | dev_err(&tz->device, "Failed to set trips: %d\n", ret); | ||
568 | |||
569 | exit: | ||
570 | mutex_unlock(&tz->lock); | ||
571 | } | ||
572 | EXPORT_SYMBOL_GPL(thermal_zone_set_trips); | ||
573 | |||
574 | static void update_temperature(struct thermal_zone_device *tz) | 433 | static void update_temperature(struct thermal_zone_device *tz) |
575 | { | 434 | { |
576 | int temp, ret; | 435 | int temp, ret; |
@@ -1178,35 +1037,6 @@ void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev) | |||
1178 | } | 1037 | } |
1179 | EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister); | 1038 | EXPORT_SYMBOL_GPL(thermal_cooling_device_unregister); |
1180 | 1039 | ||
1181 | void thermal_cdev_update(struct thermal_cooling_device *cdev) | ||
1182 | { | ||
1183 | struct thermal_instance *instance; | ||
1184 | unsigned long target = 0; | ||
1185 | |||
1186 | mutex_lock(&cdev->lock); | ||
1187 | /* cooling device is updated*/ | ||
1188 | if (cdev->updated) { | ||
1189 | mutex_unlock(&cdev->lock); | ||
1190 | return; | ||
1191 | } | ||
1192 | |||
1193 | /* Make sure cdev enters the deepest cooling state */ | ||
1194 | list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { | ||
1195 | dev_dbg(&cdev->device, "zone%d->target=%lu\n", | ||
1196 | instance->tz->id, instance->target); | ||
1197 | if (instance->target == THERMAL_NO_TARGET) | ||
1198 | continue; | ||
1199 | if (instance->target > target) | ||
1200 | target = instance->target; | ||
1201 | } | ||
1202 | cdev->ops->set_cur_state(cdev, target); | ||
1203 | cdev->updated = true; | ||
1204 | mutex_unlock(&cdev->lock); | ||
1205 | trace_cdev_update(cdev, target); | ||
1206 | dev_dbg(&cdev->device, "set to state %lu\n", target); | ||
1207 | } | ||
1208 | EXPORT_SYMBOL(thermal_cdev_update); | ||
1209 | |||
1210 | /** | 1040 | /** |
1211 | * thermal_notify_framework - Sensor drivers use this API to notify framework | 1041 | * thermal_notify_framework - Sensor drivers use this API to notify framework |
1212 | * @tz: thermal zone device | 1042 | * @tz: thermal zone device |
diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c new file mode 100644 index 000000000000..dfdba5a720cd --- /dev/null +++ b/drivers/thermal/thermal_helpers.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * thermal_helpers.c - helper functions to handle thermal devices | ||
3 | * | ||
4 | * Copyright (C) 2016 Eduardo Valentin <edubezval@gmail.com> | ||
5 | * | ||
6 | * Highly based on original thermal_core.c | ||
7 | * Copyright (C) 2008 Intel Corp | ||
8 | * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> | ||
9 | * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | */ | ||
15 | |||
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
17 | |||
18 | #include <linux/sysfs.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/string.h> | ||
23 | |||
24 | #include <trace/events/thermal.h> | ||
25 | |||
26 | #include "thermal_core.h" | ||
27 | |||
28 | int get_tz_trend(struct thermal_zone_device *tz, int trip) | ||
29 | { | ||
30 | enum thermal_trend trend; | ||
31 | |||
32 | if (tz->emul_temperature || !tz->ops->get_trend || | ||
33 | tz->ops->get_trend(tz, trip, &trend)) { | ||
34 | if (tz->temperature > tz->last_temperature) | ||
35 | trend = THERMAL_TREND_RAISING; | ||
36 | else if (tz->temperature < tz->last_temperature) | ||
37 | trend = THERMAL_TREND_DROPPING; | ||
38 | else | ||
39 | trend = THERMAL_TREND_STABLE; | ||
40 | } | ||
41 | |||
42 | return trend; | ||
43 | } | ||
44 | EXPORT_SYMBOL(get_tz_trend); | ||
45 | |||
46 | struct thermal_instance * | ||
47 | get_thermal_instance(struct thermal_zone_device *tz, | ||
48 | struct thermal_cooling_device *cdev, int trip) | ||
49 | { | ||
50 | struct thermal_instance *pos = NULL; | ||
51 | struct thermal_instance *target_instance = NULL; | ||
52 | |||
53 | mutex_lock(&tz->lock); | ||
54 | mutex_lock(&cdev->lock); | ||
55 | |||
56 | list_for_each_entry(pos, &tz->thermal_instances, tz_node) { | ||
57 | if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { | ||
58 | target_instance = pos; | ||
59 | break; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | mutex_unlock(&cdev->lock); | ||
64 | mutex_unlock(&tz->lock); | ||
65 | |||
66 | return target_instance; | ||
67 | } | ||
68 | EXPORT_SYMBOL(get_thermal_instance); | ||
69 | |||
70 | /** | ||
71 | * thermal_zone_get_temp() - returns the temperature of a thermal zone | ||
72 | * @tz: a valid pointer to a struct thermal_zone_device | ||
73 | * @temp: a valid pointer to where to store the resulting temperature. | ||
74 | * | ||
75 | * When a valid thermal zone reference is passed, it will fetch its | ||
76 | * temperature and fill @temp. | ||
77 | * | ||
78 | * Return: On success returns 0, an error code otherwise | ||
79 | */ | ||
80 | int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) | ||
81 | { | ||
82 | int ret = -EINVAL; | ||
83 | int count; | ||
84 | int crit_temp = INT_MAX; | ||
85 | enum thermal_trip_type type; | ||
86 | |||
87 | if (!tz || IS_ERR(tz) || !tz->ops->get_temp) | ||
88 | goto exit; | ||
89 | |||
90 | mutex_lock(&tz->lock); | ||
91 | |||
92 | ret = tz->ops->get_temp(tz, temp); | ||
93 | |||
94 | if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) { | ||
95 | for (count = 0; count < tz->trips; count++) { | ||
96 | ret = tz->ops->get_trip_type(tz, count, &type); | ||
97 | if (!ret && type == THERMAL_TRIP_CRITICAL) { | ||
98 | ret = tz->ops->get_trip_temp(tz, count, | ||
99 | &crit_temp); | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Only allow emulating a temperature when the real temperature | ||
106 | * is below the critical temperature so that the emulation code | ||
107 | * cannot hide critical conditions. | ||
108 | */ | ||
109 | if (!ret && *temp < crit_temp) | ||
110 | *temp = tz->emul_temperature; | ||
111 | } | ||
112 | |||
113 | mutex_unlock(&tz->lock); | ||
114 | exit: | ||
115 | return ret; | ||
116 | } | ||
117 | EXPORT_SYMBOL_GPL(thermal_zone_get_temp); | ||
118 | |||
119 | void thermal_zone_set_trips(struct thermal_zone_device *tz) | ||
120 | { | ||
121 | int low = -INT_MAX; | ||
122 | int high = INT_MAX; | ||
123 | int trip_temp, hysteresis; | ||
124 | int i, ret; | ||
125 | |||
126 | mutex_lock(&tz->lock); | ||
127 | |||
128 | if (!tz->ops->set_trips || !tz->ops->get_trip_hyst) | ||
129 | goto exit; | ||
130 | |||
131 | for (i = 0; i < tz->trips; i++) { | ||
132 | int trip_low; | ||
133 | |||
134 | tz->ops->get_trip_temp(tz, i, &trip_temp); | ||
135 | tz->ops->get_trip_hyst(tz, i, &hysteresis); | ||
136 | |||
137 | trip_low = trip_temp - hysteresis; | ||
138 | |||
139 | if (trip_low < tz->temperature && trip_low > low) | ||
140 | low = trip_low; | ||
141 | |||
142 | if (trip_temp > tz->temperature && trip_temp < high) | ||
143 | high = trip_temp; | ||
144 | } | ||
145 | |||
146 | /* No need to change trip points */ | ||
147 | if (tz->prev_low_trip == low && tz->prev_high_trip == high) | ||
148 | goto exit; | ||
149 | |||
150 | tz->prev_low_trip = low; | ||
151 | tz->prev_high_trip = high; | ||
152 | |||
153 | dev_dbg(&tz->device, | ||
154 | "new temperature boundaries: %d < x < %d\n", low, high); | ||
155 | |||
156 | /* | ||
157 | * Set a temperature window. When this window is left the driver | ||
158 | * must inform the thermal core via thermal_zone_device_update. | ||
159 | */ | ||
160 | ret = tz->ops->set_trips(tz, low, high); | ||
161 | if (ret) | ||
162 | dev_err(&tz->device, "Failed to set trips: %d\n", ret); | ||
163 | |||
164 | exit: | ||
165 | mutex_unlock(&tz->lock); | ||
166 | } | ||
167 | EXPORT_SYMBOL_GPL(thermal_zone_set_trips); | ||
168 | |||
169 | void thermal_cdev_update(struct thermal_cooling_device *cdev) | ||
170 | { | ||
171 | struct thermal_instance *instance; | ||
172 | unsigned long target = 0; | ||
173 | |||
174 | mutex_lock(&cdev->lock); | ||
175 | /* cooling device is updated*/ | ||
176 | if (cdev->updated) { | ||
177 | mutex_unlock(&cdev->lock); | ||
178 | return; | ||
179 | } | ||
180 | |||
181 | /* Make sure cdev enters the deepest cooling state */ | ||
182 | list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { | ||
183 | dev_dbg(&cdev->device, "zone%d->target=%lu\n", | ||
184 | instance->tz->id, instance->target); | ||
185 | if (instance->target == THERMAL_NO_TARGET) | ||
186 | continue; | ||
187 | if (instance->target > target) | ||
188 | target = instance->target; | ||
189 | } | ||
190 | cdev->ops->set_cur_state(cdev, target); | ||
191 | cdev->updated = true; | ||
192 | mutex_unlock(&cdev->lock); | ||
193 | trace_cdev_update(cdev, target); | ||
194 | dev_dbg(&cdev->device, "set to state %lu\n", target); | ||
195 | } | ||
196 | EXPORT_SYMBOL(thermal_cdev_update); | ||