Commit | Line | Data |
---|---|---|
5b8de18e DL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Copyright (C) 2008 Intel Corp | |
4 | * Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com> | |
5 | * Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com> | |
6 | * Copyright 2022 Linaro Limited | |
7 | * | |
8 | * Thermal trips handling | |
9 | */ | |
10 | #include "thermal_core.h" | |
11 | ||
96b8b436 RW |
12 | int for_each_thermal_trip(struct thermal_zone_device *tz, |
13 | int (*cb)(struct thermal_trip *, void *), | |
14 | void *data) | |
5b8de18e | 15 | { |
234ed6f5 RW |
16 | struct thermal_trip *trip; |
17 | int ret; | |
5b8de18e | 18 | |
234ed6f5 RW |
19 | for_each_trip(tz, trip) { |
20 | ret = cb(trip, data); | |
5b8de18e DL |
21 | if (ret) |
22 | return ret; | |
23 | } | |
24 | ||
25 | return 0; | |
26 | } | |
96b8b436 | 27 | EXPORT_SYMBOL_GPL(for_each_thermal_trip); |
5b8de18e | 28 | |
a56cc0a8 RW |
29 | int thermal_zone_for_each_trip(struct thermal_zone_device *tz, |
30 | int (*cb)(struct thermal_trip *, void *), | |
31 | void *data) | |
32 | { | |
33 | int ret; | |
34 | ||
35 | mutex_lock(&tz->lock); | |
36 | ret = for_each_thermal_trip(tz, cb, data); | |
37 | mutex_unlock(&tz->lock); | |
38 | ||
39 | return ret; | |
40 | } | |
41 | EXPORT_SYMBOL_GPL(thermal_zone_for_each_trip); | |
42 | ||
5b8de18e DL |
43 | int thermal_zone_get_num_trips(struct thermal_zone_device *tz) |
44 | { | |
45 | return tz->num_trips; | |
46 | } | |
47 | EXPORT_SYMBOL_GPL(thermal_zone_get_num_trips); | |
48 | ||
49 | /** | |
50 | * __thermal_zone_set_trips - Computes the next trip points for the driver | |
51 | * @tz: a pointer to a thermal zone device structure | |
52 | * | |
53 | * The function computes the next temperature boundaries by browsing | |
54 | * the trip points. The result is the closer low and high trip points | |
55 | * to the current temperature. These values are passed to the backend | |
56 | * driver to let it set its own notification mechanism (usually an | |
57 | * interrupt). | |
58 | * | |
59 | * This function must be called with tz->lock held. Both tz and tz->ops | |
60 | * must be valid pointers. | |
61 | * | |
62 | * It does not return a value | |
63 | */ | |
64 | void __thermal_zone_set_trips(struct thermal_zone_device *tz) | |
65 | { | |
0c0c4740 | 66 | const struct thermal_trip *trip; |
5b8de18e | 67 | int low = -INT_MAX, high = INT_MAX; |
0c0c4740 | 68 | int ret; |
5b8de18e DL |
69 | |
70 | lockdep_assert_held(&tz->lock); | |
71 | ||
698a1eb1 | 72 | if (!tz->ops.set_trips) |
5b8de18e DL |
73 | return; |
74 | ||
0c0c4740 | 75 | for_each_trip(tz, trip) { |
5b8de18e DL |
76 | int trip_low; |
77 | ||
0c0c4740 | 78 | trip_low = trip->temperature - trip->hysteresis; |
5b8de18e | 79 | |
f67cf45d | 80 | if (trip_low < tz->temperature && trip_low > low) |
5b8de18e DL |
81 | low = trip_low; |
82 | ||
0c0c4740 | 83 | if (trip->temperature > tz->temperature && |
f67cf45d | 84 | trip->temperature < high) |
0c0c4740 | 85 | high = trip->temperature; |
5b8de18e DL |
86 | } |
87 | ||
88 | /* No need to change trip points */ | |
89 | if (tz->prev_low_trip == low && tz->prev_high_trip == high) | |
90 | return; | |
91 | ||
92 | tz->prev_low_trip = low; | |
93 | tz->prev_high_trip = high; | |
94 | ||
95 | dev_dbg(&tz->device, | |
96 | "new temperature boundaries: %d < x < %d\n", low, high); | |
97 | ||
98 | /* | |
99 | * Set a temperature window. When this window is left the driver | |
100 | * must inform the thermal core via thermal_zone_device_update. | |
101 | */ | |
698a1eb1 | 102 | ret = tz->ops.set_trips(tz, low, high); |
5b8de18e DL |
103 | if (ret) |
104 | dev_err(&tz->device, "Failed to set trips: %d\n", ret); | |
105 | } | |
106 | ||
107 | int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, | |
108 | struct thermal_trip *trip) | |
109 | { | |
9b0a6275 | 110 | if (!tz || trip_id < 0 || trip_id >= tz->num_trips || !trip) |
5b8de18e DL |
111 | return -EINVAL; |
112 | ||
35d8dbbb RW |
113 | *trip = tz->trips[trip_id]; |
114 | return 0; | |
5b8de18e DL |
115 | } |
116 | EXPORT_SYMBOL_GPL(__thermal_zone_get_trip); | |
117 | ||
118 | int thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id, | |
119 | struct thermal_trip *trip) | |
120 | { | |
121 | int ret; | |
122 | ||
123 | mutex_lock(&tz->lock); | |
124 | ret = __thermal_zone_get_trip(tz, trip_id, trip); | |
125 | mutex_unlock(&tz->lock); | |
126 | ||
127 | return ret; | |
128 | } | |
129 | EXPORT_SYMBOL_GPL(thermal_zone_get_trip); | |
130 | ||
f3808464 | 131 | int thermal_zone_trip_id(const struct thermal_zone_device *tz, |
2c7b4bfa RW |
132 | const struct thermal_trip *trip) |
133 | { | |
78869767 RW |
134 | /* |
135 | * Assume the trip to be located within the bounds of the thermal | |
136 | * zone's trips[] table. | |
137 | */ | |
138 | return trip - tz->trips; | |
2c7b4bfa | 139 | } |
be0a3600 RW |
140 | void thermal_zone_trip_updated(struct thermal_zone_device *tz, |
141 | const struct thermal_trip *trip) | |
142 | { | |
7e72fc41 | 143 | thermal_notify_tz_trip_change(tz, trip); |
be0a3600 RW |
144 | __thermal_zone_device_update(tz, THERMAL_TRIP_CHANGED); |
145 | } | |
bdc22c8d RW |
146 | |
147 | void thermal_zone_set_trip_temp(struct thermal_zone_device *tz, | |
148 | struct thermal_trip *trip, int temp) | |
149 | { | |
150 | if (trip->temperature == temp) | |
151 | return; | |
152 | ||
153 | trip->temperature = temp; | |
7e72fc41 | 154 | thermal_notify_tz_trip_change(tz, trip); |
bdc22c8d RW |
155 | } |
156 | EXPORT_SYMBOL_GPL(thermal_zone_set_trip_temp); |