Blame view
drivers/thermal/ti-soc-thermal/ti-thermal-common.c
10.6 KB
445eaf871 staging: omap-the... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/* * OMAP thermal driver interface * * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ * Contact: * Eduardo Valentin <eduardo.valentin@ti.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * */ #include <linux/device.h> #include <linux/err.h> #include <linux/mutex.h> #include <linux/gfp.h> #include <linux/kernel.h> #include <linux/workqueue.h> #include <linux/thermal.h> |
5035d48dd staging: omap-the... |
31 |
#include <linux/cpumask.h> |
445eaf871 staging: omap-the... |
32 |
#include <linux/cpu_cooling.h> |
26d9cc65f thermal: ti-soc-t... |
33 |
#include <linux/of.h> |
445eaf871 staging: omap-the... |
34 |
|
7372add4a staging: rename o... |
35 36 |
#include "ti-thermal.h" #include "ti-bandgap.h" |
445eaf871 staging: omap-the... |
37 38 |
/* common data structures */ |
03e859d34 staging: ti-soc-t... |
39 40 |
struct ti_thermal_data { struct thermal_zone_device *ti_thermal; |
359836e1d thermal: ti-soc-t... |
41 |
struct thermal_zone_device *pcb_tz; |
445eaf871 staging: omap-the... |
42 |
struct thermal_cooling_device *cool_dev; |
03e859d34 staging: ti-soc-t... |
43 |
struct ti_bandgap *bgp; |
445eaf871 staging: omap-the... |
44 45 46 |
enum thermal_device_mode mode; struct work_struct thermal_wq; int sensor_id; |
26d9cc65f thermal: ti-soc-t... |
47 |
bool our_zone; |
445eaf871 staging: omap-the... |
48 |
}; |
03e859d34 staging: ti-soc-t... |
49 |
static void ti_thermal_work(struct work_struct *work) |
445eaf871 staging: omap-the... |
50 |
{ |
03e859d34 staging: ti-soc-t... |
51 52 |
struct ti_thermal_data *data = container_of(work, struct ti_thermal_data, thermal_wq); |
445eaf871 staging: omap-the... |
53 |
|
0e70f466f thermal: Enhance ... |
54 |
thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED); |
445eaf871 staging: omap-the... |
55 |
|
03e859d34 staging: ti-soc-t... |
56 57 58 |
dev_dbg(&data->ti_thermal->device, "updated thermal zone %s ", data->ti_thermal->type); |
445eaf871 staging: omap-the... |
59 60 61 |
} /** |
03e859d34 staging: ti-soc-t... |
62 |
* ti_thermal_hotspot_temperature - returns sensor extrapolated temperature |
445eaf871 staging: omap-the... |
63 64 65 66 |
* @t: omap sensor temperature * @s: omap sensor slope value * @c: omap sensor const value */ |
03e859d34 staging: ti-soc-t... |
67 |
static inline int ti_thermal_hotspot_temperature(int t, int s, int c) |
445eaf871 staging: omap-the... |
68 69 70 71 72 73 74 75 76 77 |
{ int delta = t * s / 1000 + c; if (delta < 0) delta = 0; return t + delta; } /* thermal zone ops */ |
e34238bf9 cleanup ti-soc-th... |
78 |
/* Get temperature callback function for thermal zone */ |
17e8351a7 thermal: consiste... |
79 |
static inline int __ti_thermal_get_temp(void *devdata, int *temp) |
445eaf871 staging: omap-the... |
80 |
{ |
359836e1d thermal: ti-soc-t... |
81 |
struct thermal_zone_device *pcb_tz = NULL; |
26d9cc65f thermal: ti-soc-t... |
82 |
struct ti_thermal_data *data = devdata; |
03e859d34 staging: ti-soc-t... |
83 |
struct ti_bandgap *bgp; |
9879b2c46 staging: ti-soc-t... |
84 |
const struct ti_temp_sensor *s; |
359836e1d thermal: ti-soc-t... |
85 |
int ret, tmp, slope, constant; |
17e8351a7 thermal: consiste... |
86 |
int pcb_temp; |
445eaf871 staging: omap-the... |
87 |
|
04a4d10d0 staging: omap-the... |
88 89 |
if (!data) return 0; |
d7f080e62 staging: omap-the... |
90 91 |
bgp = data->bgp; s = &bgp->conf->sensors[data->sensor_id]; |
04a4d10d0 staging: omap-the... |
92 |
|
03e859d34 staging: ti-soc-t... |
93 |
ret = ti_bandgap_read_temperature(bgp, data->sensor_id, &tmp); |
445eaf871 staging: omap-the... |
94 95 |
if (ret) return ret; |
359836e1d thermal: ti-soc-t... |
96 97 98 99 100 |
/* Default constants */ slope = s->slope; constant = s->constant; pcb_tz = data->pcb_tz; |
445eaf871 staging: omap-the... |
101 |
/* In case pcb zone is available, use the extrapolation rule with it */ |
0c12b5ac8 thermal: ti-soc-t... |
102 |
if (!IS_ERR(pcb_tz)) { |
359836e1d thermal: ti-soc-t... |
103 104 105 106 107 108 109 110 111 |
ret = thermal_zone_get_temp(pcb_tz, &pcb_temp); if (!ret) { tmp -= pcb_temp; /* got a valid PCB temp */ slope = s->slope_pcb; constant = s->constant_pcb; } else { dev_err(bgp->dev, "Failed to read PCB state. Using defaults "); |
df8f13476 drivers: thermal:... |
112 |
ret = 0; |
359836e1d thermal: ti-soc-t... |
113 |
} |
445eaf871 staging: omap-the... |
114 |
} |
03e859d34 staging: ti-soc-t... |
115 |
*temp = ti_thermal_hotspot_temperature(tmp, slope, constant); |
445eaf871 staging: omap-the... |
116 117 118 |
return ret; } |
26d9cc65f thermal: ti-soc-t... |
119 |
static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal, |
17e8351a7 thermal: consiste... |
120 |
int *temp) |
26d9cc65f thermal: ti-soc-t... |
121 122 123 124 125 |
{ struct ti_thermal_data *data = thermal->devdata; return __ti_thermal_get_temp(data, temp); } |
445eaf871 staging: omap-the... |
126 |
/* Bind callback functions for thermal zone */ |
03e859d34 staging: ti-soc-t... |
127 128 |
static int ti_thermal_bind(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) |
445eaf871 staging: omap-the... |
129 |
{ |
03e859d34 staging: ti-soc-t... |
130 |
struct ti_thermal_data *data = thermal->devdata; |
5035d48dd staging: omap-the... |
131 |
int id; |
445eaf871 staging: omap-the... |
132 |
|
0c12b5ac8 thermal: ti-soc-t... |
133 |
if (!data || IS_ERR(data)) |
445eaf871 staging: omap-the... |
134 135 136 137 138 139 140 |
return -ENODEV; /* check if this is the cooling device we registered */ if (data->cool_dev != cdev) return 0; id = data->sensor_id; |
445eaf871 staging: omap-the... |
141 |
|
445eaf871 staging: omap-the... |
142 |
/* Simple thing, two trips, one passive another critical */ |
a7a3b8c86 Fix a build error. |
143 |
return thermal_zone_bind_cooling_device(thermal, 0, cdev, |
67b4c4742 staging: ti-soc-t... |
144 |
/* bind with min and max states defined by cpu_cooling */ |
a7a3b8c86 Fix a build error. |
145 |
THERMAL_NO_LIMIT, |
6cd9e9f62 thermal: of: fix ... |
146 147 |
THERMAL_NO_LIMIT, THERMAL_WEIGHT_DEFAULT); |
445eaf871 staging: omap-the... |
148 149 150 |
} /* Unbind callback functions for thermal zone */ |
03e859d34 staging: ti-soc-t... |
151 152 |
static int ti_thermal_unbind(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) |
445eaf871 staging: omap-the... |
153 |
{ |
03e859d34 staging: ti-soc-t... |
154 |
struct ti_thermal_data *data = thermal->devdata; |
445eaf871 staging: omap-the... |
155 |
|
0c12b5ac8 thermal: ti-soc-t... |
156 |
if (!data || IS_ERR(data)) |
445eaf871 staging: omap-the... |
157 158 159 160 161 162 163 164 165 166 167 |
return -ENODEV; /* check if this is the cooling device we registered */ if (data->cool_dev != cdev) return 0; /* Simple thing, two trips, one passive another critical */ return thermal_zone_unbind_cooling_device(thermal, 0, cdev); } /* Get mode callback functions for thermal zone */ |
03e859d34 staging: ti-soc-t... |
168 169 |
static int ti_thermal_get_mode(struct thermal_zone_device *thermal, enum thermal_device_mode *mode) |
445eaf871 staging: omap-the... |
170 |
{ |
03e859d34 staging: ti-soc-t... |
171 |
struct ti_thermal_data *data = thermal->devdata; |
445eaf871 staging: omap-the... |
172 173 174 175 176 177 178 179 |
if (data) *mode = data->mode; return 0; } /* Set mode callback functions for thermal zone */ |
03e859d34 staging: ti-soc-t... |
180 181 |
static int ti_thermal_set_mode(struct thermal_zone_device *thermal, enum thermal_device_mode mode) |
445eaf871 staging: omap-the... |
182 |
{ |
03e859d34 staging: ti-soc-t... |
183 |
struct ti_thermal_data *data = thermal->devdata; |
10ccff1b5 thermal: ti-soc-t... |
184 185 186 |
struct ti_bandgap *bgp; bgp = data->bgp; |
445eaf871 staging: omap-the... |
187 |
|
03e859d34 staging: ti-soc-t... |
188 |
if (!data->ti_thermal) { |
445eaf871 staging: omap-the... |
189 190 191 192 |
dev_notice(&thermal->device, "thermal zone not registered "); return 0; } |
03e859d34 staging: ti-soc-t... |
193 |
mutex_lock(&data->ti_thermal->lock); |
445eaf871 staging: omap-the... |
194 195 |
if (mode == THERMAL_DEVICE_ENABLED) |
03e859d34 staging: ti-soc-t... |
196 |
data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE; |
445eaf871 staging: omap-the... |
197 |
else |
03e859d34 staging: ti-soc-t... |
198 |
data->ti_thermal->polling_delay = 0; |
445eaf871 staging: omap-the... |
199 |
|
03e859d34 staging: ti-soc-t... |
200 |
mutex_unlock(&data->ti_thermal->lock); |
445eaf871 staging: omap-the... |
201 202 |
data->mode = mode; |
10ccff1b5 thermal: ti-soc-t... |
203 204 |
ti_bandgap_write_update_interval(bgp, data->sensor_id, data->ti_thermal->polling_delay); |
0e70f466f thermal: Enhance ... |
205 |
thermal_zone_device_update(data->ti_thermal, THERMAL_EVENT_UNSPECIFIED); |
445eaf871 staging: omap-the... |
206 207 |
dev_dbg(&thermal->device, "thermal polling set for duration=%d msec ", |
03e859d34 staging: ti-soc-t... |
208 |
data->ti_thermal->polling_delay); |
445eaf871 staging: omap-the... |
209 210 211 212 213 |
return 0; } /* Get trip type callback functions for thermal zone */ |
03e859d34 staging: ti-soc-t... |
214 215 |
static int ti_thermal_get_trip_type(struct thermal_zone_device *thermal, int trip, enum thermal_trip_type *type) |
445eaf871 staging: omap-the... |
216 |
{ |
03e859d34 staging: ti-soc-t... |
217 |
if (!ti_thermal_is_valid_trip(trip)) |
445eaf871 staging: omap-the... |
218 219 220 221 222 223 224 225 226 227 228 |
return -EINVAL; if (trip + 1 == OMAP_TRIP_NUMBER) *type = THERMAL_TRIP_CRITICAL; else *type = THERMAL_TRIP_PASSIVE; return 0; } /* Get trip temperature callback functions for thermal zone */ |
03e859d34 staging: ti-soc-t... |
229 |
static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal, |
17e8351a7 thermal: consiste... |
230 |
int trip, int *temp) |
445eaf871 staging: omap-the... |
231 |
{ |
03e859d34 staging: ti-soc-t... |
232 |
if (!ti_thermal_is_valid_trip(trip)) |
445eaf871 staging: omap-the... |
233 |
return -EINVAL; |
03e859d34 staging: ti-soc-t... |
234 |
*temp = ti_thermal_get_trip_value(trip); |
445eaf871 staging: omap-the... |
235 236 237 |
return 0; } |
e78eaf459 thermal: streamli... |
238 |
static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend) |
03b7f67bd staging: ti-soc-t... |
239 |
{ |
26d9cc65f thermal: ti-soc-t... |
240 |
struct ti_thermal_data *data = p; |
03b7f67bd staging: ti-soc-t... |
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 |
struct ti_bandgap *bgp; int id, tr, ret = 0; bgp = data->bgp; id = data->sensor_id; ret = ti_bandgap_get_trend(bgp, id, &tr); if (ret) return ret; if (tr > 0) *trend = THERMAL_TREND_RAISING; else if (tr < 0) *trend = THERMAL_TREND_DROPPING; else *trend = THERMAL_TREND_STABLE; return 0; } |
e78eaf459 thermal: streamli... |
260 261 262 263 264 265 |
/* Get the temperature trend callback functions for thermal zone */ static int ti_thermal_get_trend(struct thermal_zone_device *thermal, int trip, enum thermal_trend *trend) { return __ti_thermal_get_trend(thermal->devdata, trip, trend); } |
445eaf871 staging: omap-the... |
266 |
/* Get critical temperature callback functions for thermal zone */ |
03e859d34 staging: ti-soc-t... |
267 |
static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal, |
17e8351a7 thermal: consiste... |
268 |
int *temp) |
445eaf871 staging: omap-the... |
269 270 |
{ /* shutdown zone */ |
03e859d34 staging: ti-soc-t... |
271 |
return ti_thermal_get_trip_temp(thermal, OMAP_TRIP_NUMBER - 1, temp); |
445eaf871 staging: omap-the... |
272 |
} |
2251aef64 thermal: of: impr... |
273 274 275 276 |
static const struct thermal_zone_of_device_ops ti_of_thermal_ops = { .get_temp = __ti_thermal_get_temp, .get_trend = __ti_thermal_get_trend, }; |
03e859d34 staging: ti-soc-t... |
277 278 |
static struct thermal_zone_device_ops ti_thermal_ops = { .get_temp = ti_thermal_get_temp, |
03b7f67bd staging: ti-soc-t... |
279 |
.get_trend = ti_thermal_get_trend, |
03e859d34 staging: ti-soc-t... |
280 281 282 283 284 285 286 |
.bind = ti_thermal_bind, .unbind = ti_thermal_unbind, .get_mode = ti_thermal_get_mode, .set_mode = ti_thermal_set_mode, .get_trip_type = ti_thermal_get_trip_type, .get_trip_temp = ti_thermal_get_trip_temp, .get_crit_temp = ti_thermal_get_crit_temp, |
445eaf871 staging: omap-the... |
287 |
}; |
03e859d34 staging: ti-soc-t... |
288 289 |
static struct ti_thermal_data *ti_thermal_build_data(struct ti_bandgap *bgp, int id) |
445eaf871 staging: omap-the... |
290 |
{ |
03e859d34 staging: ti-soc-t... |
291 |
struct ti_thermal_data *data; |
445eaf871 staging: omap-the... |
292 |
|
d7f080e62 staging: omap-the... |
293 |
data = devm_kzalloc(bgp->dev, sizeof(*data), GFP_KERNEL); |
445eaf871 staging: omap-the... |
294 |
if (!data) { |
d7f080e62 staging: omap-the... |
295 296 |
dev_err(bgp->dev, "kzalloc fail "); |
04a4d10d0 staging: omap-the... |
297 |
return NULL; |
445eaf871 staging: omap-the... |
298 299 |
} data->sensor_id = id; |
d7f080e62 staging: omap-the... |
300 |
data->bgp = bgp; |
445eaf871 staging: omap-the... |
301 |
data->mode = THERMAL_DEVICE_ENABLED; |
0c12b5ac8 thermal: ti-soc-t... |
302 |
/* pcb_tz will be either valid or PTR_ERR() */ |
359836e1d thermal: ti-soc-t... |
303 |
data->pcb_tz = thermal_zone_get_zone_by_name("pcb"); |
03e859d34 staging: ti-soc-t... |
304 |
INIT_WORK(&data->thermal_wq, ti_thermal_work); |
445eaf871 staging: omap-the... |
305 |
|
04a4d10d0 staging: omap-the... |
306 307 |
return data; } |
03e859d34 staging: ti-soc-t... |
308 309 |
int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, char *domain) |
04a4d10d0 staging: omap-the... |
310 |
{ |
03e859d34 staging: ti-soc-t... |
311 |
struct ti_thermal_data *data; |
04a4d10d0 staging: omap-the... |
312 |
|
03e859d34 staging: ti-soc-t... |
313 |
data = ti_bandgap_get_sensor_data(bgp, id); |
04a4d10d0 staging: omap-the... |
314 |
|
0c12b5ac8 thermal: ti-soc-t... |
315 |
if (!data || IS_ERR(data)) |
03e859d34 staging: ti-soc-t... |
316 |
data = ti_thermal_build_data(bgp, id); |
04a4d10d0 staging: omap-the... |
317 318 319 |
if (!data) return -EINVAL; |
26d9cc65f thermal: ti-soc-t... |
320 |
/* in case this is specified by DT */ |
3982204cc thermal: convert ... |
321 |
data->ti_thermal = devm_thermal_zone_of_sensor_register(bgp->dev, id, |
2251aef64 thermal: of: impr... |
322 |
data, &ti_of_thermal_ops); |
26d9cc65f thermal: ti-soc-t... |
323 324 325 |
if (IS_ERR(data->ti_thermal)) { /* Create thermal zone */ data->ti_thermal = thermal_zone_device_register(domain, |
03e859d34 staging: ti-soc-t... |
326 |
OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops, |
50125a9b2 Thermal: Pass zon... |
327 |
NULL, FAST_TEMP_MONITORING_RATE, |
765a1939a staging: omap-the... |
328 |
FAST_TEMP_MONITORING_RATE); |
26d9cc65f thermal: ti-soc-t... |
329 330 331 332 333 334 335 |
if (IS_ERR(data->ti_thermal)) { dev_err(bgp->dev, "thermal zone device is NULL "); return PTR_ERR(data->ti_thermal); } data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE; data->our_zone = true; |
445eaf871 staging: omap-the... |
336 |
} |
03e859d34 staging: ti-soc-t... |
337 |
ti_bandgap_set_sensor_data(bgp, id, data); |
10ccff1b5 thermal: ti-soc-t... |
338 339 |
ti_bandgap_write_update_interval(bgp, data->sensor_id, data->ti_thermal->polling_delay); |
445eaf871 staging: omap-the... |
340 341 342 |
return 0; } |
03e859d34 staging: ti-soc-t... |
343 |
int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id) |
445eaf871 staging: omap-the... |
344 |
{ |
03e859d34 staging: ti-soc-t... |
345 |
struct ti_thermal_data *data; |
445eaf871 staging: omap-the... |
346 |
|
03e859d34 staging: ti-soc-t... |
347 |
data = ti_bandgap_get_sensor_data(bgp, id); |
445eaf871 staging: omap-the... |
348 |
|
26d9cc65f thermal: ti-soc-t... |
349 350 351 |
if (data && data->ti_thermal) { if (data->our_zone) thermal_zone_device_unregister(data->ti_thermal); |
26d9cc65f thermal: ti-soc-t... |
352 |
} |
445eaf871 staging: omap-the... |
353 354 355 |
return 0; } |
03e859d34 staging: ti-soc-t... |
356 |
int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id) |
445eaf871 staging: omap-the... |
357 |
{ |
03e859d34 staging: ti-soc-t... |
358 |
struct ti_thermal_data *data; |
445eaf871 staging: omap-the... |
359 |
|
03e859d34 staging: ti-soc-t... |
360 |
data = ti_bandgap_get_sensor_data(bgp, id); |
445eaf871 staging: omap-the... |
361 362 363 364 365 |
schedule_work(&data->thermal_wq); return 0; } |
03e859d34 staging: ti-soc-t... |
366 |
int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id) |
445eaf871 staging: omap-the... |
367 |
{ |
03e859d34 staging: ti-soc-t... |
368 |
struct ti_thermal_data *data; |
26d9cc65f thermal: ti-soc-t... |
369 370 371 372 373 374 375 376 377 |
struct device_node *np = bgp->dev->of_node; /* * We are assuming here that if one deploys the zone * using DT, then it must be aware that the cooling device * loading has to happen via cpufreq driver. */ if (of_find_property(np, "#thermal-sensor-cells", NULL)) return 0; |
445eaf871 staging: omap-the... |
378 |
|
03e859d34 staging: ti-soc-t... |
379 |
data = ti_bandgap_get_sensor_data(bgp, id); |
0c12b5ac8 thermal: ti-soc-t... |
380 |
if (!data || IS_ERR(data)) |
03e859d34 staging: ti-soc-t... |
381 |
data = ti_thermal_build_data(bgp, id); |
04a4d10d0 staging: omap-the... |
382 383 384 |
if (!data) return -EINVAL; |
445eaf871 staging: omap-the... |
385 |
|
445eaf871 staging: omap-the... |
386 |
/* Register cooling device */ |
5035d48dd staging: omap-the... |
387 |
data->cool_dev = cpufreq_cooling_register(cpu_present_mask); |
0c12b5ac8 thermal: ti-soc-t... |
388 |
if (IS_ERR(data->cool_dev)) { |
cffafc324 thermal: ti-soc-t... |
389 390 391 392 393 394 395 396 397 |
int ret = PTR_ERR(data->cool_dev); if (ret != -EPROBE_DEFER) dev_err(bgp->dev, "Failed to register cpu cooling device %d ", ret); return ret; |
445eaf871 staging: omap-the... |
398 |
} |
03e859d34 staging: ti-soc-t... |
399 |
ti_bandgap_set_sensor_data(bgp, id, data); |
445eaf871 staging: omap-the... |
400 401 402 |
return 0; } |
03e859d34 staging: ti-soc-t... |
403 |
int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id) |
445eaf871 staging: omap-the... |
404 |
{ |
03e859d34 staging: ti-soc-t... |
405 |
struct ti_thermal_data *data; |
445eaf871 staging: omap-the... |
406 |
|
03e859d34 staging: ti-soc-t... |
407 |
data = ti_bandgap_get_sensor_data(bgp, id); |
26d9cc65f thermal: ti-soc-t... |
408 |
|
9ca9be2b0 ti-soc-thermal: D... |
409 |
if (data) |
26d9cc65f thermal: ti-soc-t... |
410 |
cpufreq_cooling_unregister(data->cool_dev); |
445eaf871 staging: omap-the... |
411 412 413 |
return 0; } |