aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt7
-rw-r--r--Documentation/devicetree/bindings/thermal/imx-thermal.txt4
-rw-r--r--Documentation/devicetree/bindings/thermal/thermal.txt595
-rw-r--r--MAINTAINERS1
-rw-r--r--arch/arm/boot/dts/omap4-cpu-thermal.dtsi41
-rw-r--r--arch/arm/boot/dts/omap443x.dtsi23
-rw-r--r--arch/arm/boot/dts/omap4460.dtsi29
-rw-r--r--arch/arm/boot/dts/omap5-core-thermal.dtsi28
-rw-r--r--arch/arm/boot/dts/omap5-gpu-thermal.dtsi28
-rw-r--r--arch/arm/boot/dts/omap5.dtsi14
-rw-r--r--drivers/cpufreq/Kconfig2
-rw-r--r--drivers/cpufreq/cpufreq-cpu0.c16
-rw-r--r--drivers/hwmon/lm75.c35
-rw-r--r--drivers/hwmon/tmp102.c19
-rw-r--r--drivers/thermal/Kconfig23
-rw-r--r--drivers/thermal/Makefile2
-rw-r--r--drivers/thermal/cpu_cooling.c67
-rw-r--r--drivers/thermal/imx_thermal.c54
-rw-r--r--drivers/thermal/int3403_thermal.c237
-rw-r--r--drivers/thermal/intel_powerclamp.c11
-rw-r--r--drivers/thermal/of-thermal.c849
-rw-r--r--drivers/thermal/samsung/exynos_thermal_common.c2
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c1
-rw-r--r--drivers/thermal/step_wise.c6
-rw-r--r--drivers/thermal/thermal_core.c86
-rw-r--r--drivers/thermal/thermal_core.h9
-rw-r--r--drivers/thermal/ti-soc-thermal/ti-thermal-common.c77
-rw-r--r--drivers/thermal/x86_pkg_temp_thermal.c2
-rw-r--r--include/dt-bindings/thermal/thermal.h17
-rw-r--r--include/linux/cpu_cooling.h25
-rw-r--r--include/linux/thermal.h32
31 files changed, 2271 insertions, 71 deletions
diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
index 051f764bedb8..f055515d2b62 100644
--- a/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
+++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-cpu0.txt
@@ -15,6 +15,10 @@ Optional properties:
15- clock-latency: Specify the possible maximum transition latency for clock, 15- clock-latency: Specify the possible maximum transition latency for clock,
16 in unit of nanoseconds. 16 in unit of nanoseconds.
17- voltage-tolerance: Specify the CPU voltage tolerance in percentage. 17- voltage-tolerance: Specify the CPU voltage tolerance in percentage.
18- #cooling-cells:
19- cooling-min-level:
20- cooling-max-level:
21 Please refer to Documentation/devicetree/bindings/thermal/thermal.txt.
18 22
19Examples: 23Examples:
20 24
@@ -33,6 +37,9 @@ cpus {
33 198000 850000 37 198000 850000
34 >; 38 >;
35 clock-latency = <61036>; /* two CLK32 periods */ 39 clock-latency = <61036>; /* two CLK32 periods */
40 #cooling-cells = <2>;
41 cooling-min-level = <0>;
42 cooling-max-level = <2>;
36 }; 43 };
37 44
38 cpu@1 { 45 cpu@1 {
diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.txt b/Documentation/devicetree/bindings/thermal/imx-thermal.txt
index 541c25e49abf..1f0f67234a91 100644
--- a/Documentation/devicetree/bindings/thermal/imx-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/imx-thermal.txt
@@ -8,10 +8,14 @@ Required properties:
8 calibration data, e.g. OCOTP on imx6q. The details about calibration data 8 calibration data, e.g. OCOTP on imx6q. The details about calibration data
9 can be found in SoC Reference Manual. 9 can be found in SoC Reference Manual.
10 10
11Optional properties:
12- clocks : thermal sensor's clock source.
13
11Example: 14Example:
12 15
13tempmon { 16tempmon {
14 compatible = "fsl,imx6q-tempmon"; 17 compatible = "fsl,imx6q-tempmon";
15 fsl,tempmon = <&anatop>; 18 fsl,tempmon = <&anatop>;
16 fsl,tempmon-data = <&ocotp>; 19 fsl,tempmon-data = <&ocotp>;
20 clocks = <&clks 172>;
17}; 21};
diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt
new file mode 100644
index 000000000000..f5db6b72a36f
--- /dev/null
+++ b/Documentation/devicetree/bindings/thermal/thermal.txt
@@ -0,0 +1,595 @@
1* Thermal Framework Device Tree descriptor
2
3This file describes a generic binding to provide a way of
4defining hardware thermal structure using device tree.
5A thermal structure includes thermal zones and their components,
6such as trip points, polling intervals, sensors and cooling devices
7binding descriptors.
8
9The target of device tree thermal descriptors is to describe only
10the hardware thermal aspects. The thermal device tree bindings are
11not about how the system must control or which algorithm or policy
12must be taken in place.
13
14There are five types of nodes involved to describe thermal bindings:
15- thermal sensors: devices which may be used to take temperature
16 measurements.
17- cooling devices: devices which may be used to dissipate heat.
18- trip points: describe key temperatures at which cooling is recommended. The
19 set of points should be chosen based on hardware limits.
20- cooling maps: used to describe links between trip points and cooling devices;
21- thermal zones: used to describe thermal data within the hardware;
22
23The following is a description of each of these node types.
24
25* Thermal sensor devices
26
27Thermal sensor devices are nodes providing temperature sensing capabilities on
28thermal zones. Typical devices are I2C ADC converters and bandgaps. These are
29nodes providing temperature data to thermal zones. Thermal sensor devices may
30control one or more internal sensors.
31
32Required property:
33- #thermal-sensor-cells: Used to provide sensor device specific information
34 Type: unsigned while referring to it. Typically 0 on thermal sensor
35 Size: one cell nodes with only one sensor, and at least 1 on nodes
36 with several internal sensors, in order
37 to identify uniquely the sensor instances within
38 the IC. See thermal zone binding for more details
39 on how consumers refer to sensor devices.
40
41* Cooling device nodes
42
43Cooling devices are nodes providing control on power dissipation. There
44are essentially two ways to provide control on power dissipation. First
45is by means of regulating device performance, which is known as passive
46cooling. A typical passive cooling is a CPU that has dynamic voltage and
47frequency scaling (DVFS), and uses lower frequencies as cooling states.
48Second is by means of activating devices in order to remove
49the dissipated heat, which is known as active cooling, e.g. regulating
50fan speeds. In both cases, cooling devices shall have a way to determine
51the state of cooling in which the device is.
52
53Any cooling device has a range of cooling states (i.e. different levels
54of heat dissipation). For example a fan's cooling states correspond to
55the different fan speeds possible. Cooling states are referred to by
56single unsigned integers, where larger numbers mean greater heat
57dissipation. The precise set of cooling states associated with a device
58(as referred to be the cooling-min-state and cooling-max-state
59properties) should be defined in a particular device's binding.
60For more examples of cooling devices, refer to the example sections below.
61
62Required properties:
63- cooling-min-state: An integer indicating the smallest
64 Type: unsigned cooling state accepted. Typically 0.
65 Size: one cell
66
67- cooling-max-state: An integer indicating the largest
68 Type: unsigned cooling state accepted.
69 Size: one cell
70
71- #cooling-cells: Used to provide cooling device specific information
72 Type: unsigned while referring to it. Must be at least 2, in order
73 Size: one cell to specify minimum and maximum cooling state used
74 in the reference. The first cell is the minimum
75 cooling state requested and the second cell is
76 the maximum cooling state requested in the reference.
77 See Cooling device maps section below for more details
78 on how consumers refer to cooling devices.
79
80* Trip points
81
82The trip node is a node to describe a point in the temperature domain
83in which the system takes an action. This node describes just the point,
84not the action.
85
86Required properties:
87- temperature: An integer indicating the trip temperature level,
88 Type: signed in millicelsius.
89 Size: one cell
90
91- hysteresis: A low hysteresis value on temperature property (above).
92 Type: unsigned This is a relative value, in millicelsius.
93 Size: one cell
94
95- type: a string containing the trip type. Expected values are:
96 "active": A trip point to enable active cooling
97 "passive": A trip point to enable passive cooling
98 "hot": A trip point to notify emergency
99 "critical": Hardware not reliable.
100 Type: string
101
102* Cooling device maps
103
104The cooling device maps node is a node to describe how cooling devices
105get assigned to trip points of the zone. The cooling devices are expected
106to be loaded in the target system.
107
108Required properties:
109- cooling-device: A phandle of a cooling device with its specifier,
110 Type: phandle + referring to which cooling device is used in this
111 cooling specifier binding. In the cooling specifier, the first cell
112 is the minimum cooling state and the second cell
113 is the maximum cooling state used in this map.
114- trip: A phandle of a trip point node within the same thermal
115 Type: phandle of zone.
116 trip point node
117
118Optional property:
119- contribution: The cooling contribution to the thermal zone of the
120 Type: unsigned referred cooling device at the referred trip point.
121 Size: one cell The contribution is a ratio of the sum
122 of all cooling contributions within a thermal zone.
123
124Note: Using the THERMAL_NO_LIMIT (-1UL) constant in the cooling-device phandle
125limit specifier means:
126(i) - minimum state allowed for minimum cooling state used in the reference.
127(ii) - maximum state allowed for maximum cooling state used in the reference.
128Refer to include/dt-bindings/thermal/thermal.h for definition of this constant.
129
130* Thermal zone nodes
131
132The thermal zone node is the node containing all the required info
133for describing a thermal zone, including its cooling device bindings. The
134thermal zone node must contain, apart from its own properties, one sub-node
135containing trip nodes and one sub-node containing all the zone cooling maps.
136
137Required properties:
138- polling-delay: The maximum number of milliseconds to wait between polls
139 Type: unsigned when checking this thermal zone.
140 Size: one cell
141
142- polling-delay-passive: The maximum number of milliseconds to wait
143 Type: unsigned between polls when performing passive cooling.
144 Size: one cell
145
146- thermal-sensors: A list of thermal sensor phandles and sensor specifier
147 Type: list of used while monitoring the thermal zone.
148 phandles + sensor
149 specifier
150
151- trips: A sub-node which is a container of only trip point nodes
152 Type: sub-node required to describe the thermal zone.
153
154- cooling-maps: A sub-node which is a container of only cooling device
155 Type: sub-node map nodes, used to describe the relation between trips
156 and cooling devices.
157
158Optional property:
159- coefficients: An array of integers (one signed cell) containing
160 Type: array coefficients to compose a linear relation between
161 Elem size: one cell the sensors listed in the thermal-sensors property.
162 Elem type: signed Coefficients defaults to 1, in case this property
163 is not specified. A simple linear polynomial is used:
164 Z = c0 * x0 + c1 + x1 + ... + c(n-1) * x(n-1) + cn.
165
166 The coefficients are ordered and they match with sensors
167 by means of sensor ID. Additional coefficients are
168 interpreted as constant offset.
169
170Note: The delay properties are bound to the maximum dT/dt (temperature
171derivative over time) in two situations for a thermal zone:
172(i) - when passive cooling is activated (polling-delay-passive); and
173(ii) - when the zone just needs to be monitored (polling-delay) or
174when active cooling is activated.
175
176The maximum dT/dt is highly bound to hardware power consumption and dissipation
177capability. The delays should be chosen to account for said max dT/dt,
178such that a device does not cross several trip boundaries unexpectedly
179between polls. Choosing the right polling delays shall avoid having the
180device in temperature ranges that may damage the silicon structures and
181reduce silicon lifetime.
182
183* The thermal-zones node
184
185The "thermal-zones" node is a container for all thermal zone nodes. It shall
186contain only sub-nodes describing thermal zones as in the section
187"Thermal zone nodes". The "thermal-zones" node appears under "/".
188
189* Examples
190
191Below are several examples on how to use thermal data descriptors
192using device tree bindings:
193
194(a) - CPU thermal zone
195
196The CPU thermal zone example below describes how to setup one thermal zone
197using one single sensor as temperature source and many cooling devices and
198power dissipation control sources.
199
200#include <dt-bindings/thermal/thermal.h>
201
202cpus {
203 /*
204 * Here is an example of describing a cooling device for a DVFS
205 * capable CPU. The CPU node describes its four OPPs.
206 * The cooling states possible are 0..3, and they are
207 * used as OPP indexes. The minimum cooling state is 0, which means
208 * all four OPPs can be available to the system. The maximum
209 * cooling state is 3, which means only the lowest OPPs (198MHz@0.85V)
210 * can be available in the system.
211 */
212 cpu0: cpu@0 {
213 ...
214 operating-points = <
215 /* kHz uV */
216 970000 1200000
217 792000 1100000
218 396000 950000
219 198000 850000
220 >;
221 cooling-min-state = <0>;
222 cooling-max-state = <3>;
223 #cooling-cells = <2>; /* min followed by max */
224 };
225 ...
226};
227
228&i2c1 {
229 ...
230 /*
231 * A simple fan controller which supports 10 speeds of operation
232 * (represented as 0-9).
233 */
234 fan0: fan@0x48 {
235 ...
236 cooling-min-state = <0>;
237 cooling-max-state = <9>;
238 #cooling-cells = <2>; /* min followed by max */
239 };
240};
241
242ocp {
243 ...
244 /*
245 * A simple IC with a single bandgap temperature sensor.
246 */
247 bandgap0: bandgap@0x0000ED00 {
248 ...
249 #thermal-sensor-cells = <0>;
250 };
251};
252
253thermal-zones {
254 cpu-thermal: cpu-thermal {
255 polling-delay-passive = <250>; /* milliseconds */
256 polling-delay = <1000>; /* milliseconds */
257
258 thermal-sensors = <&bandgap0>;
259
260 trips {
261 cpu-alert0: cpu-alert {
262 temperature = <90000>; /* millicelsius */
263 hysteresis = <2000>; /* millicelsius */
264 type = "active";
265 };
266 cpu-alert1: cpu-alert {
267 temperature = <100000>; /* millicelsius */
268 hysteresis = <2000>; /* millicelsius */
269 type = "passive";
270 };
271 cpu-crit: cpu-crit {
272 temperature = <125000>; /* millicelsius */
273 hysteresis = <2000>; /* millicelsius */
274 type = "critical";
275 };
276 };
277
278 cooling-maps {
279 map0 {
280 trip = <&cpu-alert0>;
281 cooling-device = <&fan0 THERMAL_NO_LIMITS 4>;
282 };
283 map1 {
284 trip = <&cpu-alert1>;
285 cooling-device = <&fan0 5 THERMAL_NO_LIMITS>;
286 };
287 map2 {
288 trip = <&cpu-alert1>;
289 cooling-device =
290 <&cpu0 THERMAL_NO_LIMITS THERMAL_NO_LIMITS>;
291 };
292 };
293 };
294};
295
296In the example above, the ADC sensor (bandgap0) at address 0x0000ED00 is
297used to monitor the zone 'cpu-thermal' using its sole sensor. A fan
298device (fan0) is controlled via I2C bus 1, at address 0x48, and has ten
299different cooling states 0-9. It is used to remove the heat out of
300the thermal zone 'cpu-thermal' using its cooling states
301from its minimum to 4, when it reaches trip point 'cpu-alert0'
302at 90C, as an example of active cooling. The same cooling device is used at
303'cpu-alert1', but from 5 to its maximum state. The cpu@0 device is also
304linked to the same thermal zone, 'cpu-thermal', as a passive cooling device,
305using all its cooling states at trip point 'cpu-alert1',
306which is a trip point at 100C. On the thermal zone 'cpu-thermal', at the
307temperature of 125C, represented by the trip point 'cpu-crit', the silicon
308is not reliable anymore.
309
310(b) - IC with several internal sensors
311
312The example below describes how to deploy several thermal zones based off a
313single sensor IC, assuming it has several internal sensors. This is a common
314case on SoC designs with several internal IPs that may need different thermal
315requirements, and thus may have their own sensor to monitor or detect internal
316hotspots in their silicon.
317
318#include <dt-bindings/thermal/thermal.h>
319
320ocp {
321 ...
322 /*
323 * A simple IC with several bandgap temperature sensors.
324 */
325 bandgap0: bandgap@0x0000ED00 {
326 ...
327 #thermal-sensor-cells = <1>;
328 };
329};
330
331thermal-zones {
332 cpu-thermal: cpu-thermal {
333 polling-delay-passive = <250>; /* milliseconds */
334 polling-delay = <1000>; /* milliseconds */
335
336 /* sensor ID */
337 thermal-sensors = <&bandgap0 0>;
338
339 trips {
340 /* each zone within the SoC may have its own trips */
341 cpu-alert: cpu-alert {
342 temperature = <100000>; /* millicelsius */
343 hysteresis = <2000>; /* millicelsius */
344 type = "passive";
345 };
346 cpu-crit: cpu-crit {
347 temperature = <125000>; /* millicelsius */
348 hysteresis = <2000>; /* millicelsius */
349 type = "critical";
350 };
351 };
352
353 cooling-maps {
354 /* each zone within the SoC may have its own cooling */
355 ...
356 };
357 };
358
359 gpu-thermal: gpu-thermal {
360 polling-delay-passive = <120>; /* milliseconds */
361 polling-delay = <1000>; /* milliseconds */
362
363 /* sensor ID */
364 thermal-sensors = <&bandgap0 1>;
365
366 trips {
367 /* each zone within the SoC may have its own trips */
368 gpu-alert: gpu-alert {
369 temperature = <90000>; /* millicelsius */
370 hysteresis = <2000>; /* millicelsius */
371 type = "passive";
372 };
373 gpu-crit: gpu-crit {
374 temperature = <105000>; /* millicelsius */
375 hysteresis = <2000>; /* millicelsius */
376 type = "critical";
377 };
378 };
379
380 cooling-maps {
381 /* each zone within the SoC may have its own cooling */
382 ...
383 };
384 };
385
386 dsp-thermal: dsp-thermal {
387 polling-delay-passive = <50>; /* milliseconds */
388 polling-delay = <1000>; /* milliseconds */
389
390 /* sensor ID */
391 thermal-sensors = <&bandgap0 2>;
392
393 trips {
394 /* each zone within the SoC may have its own trips */
395 dsp-alert: gpu-alert {
396 temperature = <90000>; /* millicelsius */
397 hysteresis = <2000>; /* millicelsius */
398 type = "passive";
399 };
400 dsp-crit: gpu-crit {
401 temperature = <135000>; /* millicelsius */
402 hysteresis = <2000>; /* millicelsius */
403 type = "critical";
404 };
405 };
406
407 cooling-maps {
408 /* each zone within the SoC may have its own cooling */
409 ...
410 };
411 };
412};
413
414In the example above, there is one bandgap IC which has the capability to
415monitor three sensors. The hardware has been designed so that sensors are
416placed on different places in the DIE to monitor different temperature
417hotspots: one for CPU thermal zone, one for GPU thermal zone and the
418other to monitor a DSP thermal zone.
419
420Thus, there is a need to assign each sensor provided by the bandgap IC
421to different thermal zones. This is achieved by means of using the
422#thermal-sensor-cells property and using the first cell of the sensor
423specifier as sensor ID. In the example, then, <bandgap 0> is used to
424monitor CPU thermal zone, <bandgap 1> is used to monitor GPU thermal
425zone and <bandgap 2> is used to monitor DSP thermal zone. Each zone
426may be uncorrelated, having its own dT/dt requirements, trips
427and cooling maps.
428
429
430(c) - Several sensors within one single thermal zone
431
432The example below illustrates how to use more than one sensor within
433one thermal zone.
434
435#include <dt-bindings/thermal/thermal.h>
436
437&i2c1 {
438 ...
439 /*
440 * A simple IC with a single temperature sensor.
441 */
442 adc: sensor@0x49 {
443 ...
444 #thermal-sensor-cells = <0>;
445 };
446};
447
448ocp {
449 ...
450 /*
451 * A simple IC with a single bandgap temperature sensor.
452 */
453 bandgap0: bandgap@0x0000ED00 {
454 ...
455 #thermal-sensor-cells = <0>;
456 };
457};
458
459thermal-zones {
460 cpu-thermal: cpu-thermal {
461 polling-delay-passive = <250>; /* milliseconds */
462 polling-delay = <1000>; /* milliseconds */
463
464 thermal-sensors = <&bandgap0>, /* cpu */
465 <&adc>; /* pcb north */
466
467 /* hotspot = 100 * bandgap - 120 * adc + 484 */
468 coefficients = <100 -120 484>;
469
470 trips {
471 ...
472 };
473
474 cooling-maps {
475 ...
476 };
477 };
478};
479
480In some cases, there is a need to use more than one sensor to extrapolate
481a thermal hotspot in the silicon. The above example illustrates this situation.
482For instance, it may be the case that a sensor external to CPU IP may be placed
483close to CPU hotspot and together with internal CPU sensor, it is used
484to determine the hotspot. Assuming this is the case for the above example,
485the hypothetical extrapolation rule would be:
486 hotspot = 100 * bandgap - 120 * adc + 484
487
488In other context, the same idea can be used to add fixed offset. For instance,
489consider the hotspot extrapolation rule below:
490 hotspot = 1 * adc + 6000
491
492In the above equation, the hotspot is always 6C higher than what is read
493from the ADC sensor. The binding would be then:
494 thermal-sensors = <&adc>;
495
496 /* hotspot = 1 * adc + 6000 */
497 coefficients = <1 6000>;
498
499(d) - Board thermal
500
501The board thermal example below illustrates how to setup one thermal zone
502with many sensors and many cooling devices.
503
504#include <dt-bindings/thermal/thermal.h>
505
506&i2c1 {
507 ...
508 /*
509 * An IC with several temperature sensor.
510 */
511 adc-dummy: sensor@0x50 {
512 ...
513 #thermal-sensor-cells = <1>; /* sensor internal ID */
514 };
515};
516
517thermal-zones {
518 batt-thermal {
519 polling-delay-passive = <500>; /* milliseconds */
520 polling-delay = <2500>; /* milliseconds */
521
522 /* sensor ID */
523 thermal-sensors = <&adc-dummy 4>;
524
525 trips {
526 ...
527 };
528
529 cooling-maps {
530 ...
531 };
532 };
533
534 board-thermal: board-thermal {
535 polling-delay-passive = <1000>; /* milliseconds */
536 polling-delay = <2500>; /* milliseconds */
537
538 /* sensor ID */
539 thermal-sensors = <&adc-dummy 0>, /* pcb top edge */
540 <&adc-dummy 1>, /* lcd */
541 <&adc-dymmy 2>; /* back cover */
542 /*
543 * An array of coefficients describing the sensor
544 * linear relation. E.g.:
545 * z = c1*x1 + c2*x2 + c3*x3
546 */
547 coefficients = <1200 -345 890>;
548
549 trips {
550 /* Trips are based on resulting linear equation */
551 cpu-trip: cpu-trip {
552 temperature = <60000>; /* millicelsius */
553 hysteresis = <2000>; /* millicelsius */
554 type = "passive";
555 };
556 gpu-trip: gpu-trip {
557 temperature = <55000>; /* millicelsius */
558 hysteresis = <2000>; /* millicelsius */
559 type = "passive";
560 }
561 lcd-trip: lcp-trip {
562 temperature = <53000>; /* millicelsius */
563 hysteresis = <2000>; /* millicelsius */
564 type = "passive";
565 };
566 crit-trip: crit-trip {
567 temperature = <68000>; /* millicelsius */
568 hysteresis = <2000>; /* millicelsius */
569 type = "critical";
570 };
571 };
572
573 cooling-maps {
574 map0 {
575 trip = <&cpu-trip>;
576 cooling-device = <&cpu0 0 2>;
577 contribution = <55>;
578 };
579 map1 {
580 trip = <&gpu-trip>;
581 cooling-device = <&gpu0 0 2>;
582 contribution = <20>;
583 };
584 map2 {
585 trip = <&lcd-trip>;
586 cooling-device = <&lcd0 5 10>;
587 contribution = <15>;
588 };
589 };
590 };
591};
592
593The above example is a mix of previous examples, a sensor IP with several internal
594sensors used to monitor different zones, one of them is composed by several sensors and
595with different cooling devices.
diff --git a/MAINTAINERS b/MAINTAINERS
index c9f0da19048b..17cabd8d0dcb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -8622,6 +8622,7 @@ S: Supported
8622F: drivers/thermal/ 8622F: drivers/thermal/
8623F: include/linux/thermal.h 8623F: include/linux/thermal.h
8624F: include/linux/cpu_cooling.h 8624F: include/linux/cpu_cooling.h
8625F: Documentation/devicetree/bindings/thermal/
8625 8626
8626THINGM BLINK(1) USB RGB LED DRIVER 8627THINGM BLINK(1) USB RGB LED DRIVER
8627M: Vivien Didelot <vivien.didelot@savoirfairelinux.com> 8628M: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
diff --git a/arch/arm/boot/dts/omap4-cpu-thermal.dtsi b/arch/arm/boot/dts/omap4-cpu-thermal.dtsi
new file mode 100644
index 000000000000..cb9458feb2e3
--- /dev/null
+++ b/arch/arm/boot/dts/omap4-cpu-thermal.dtsi
@@ -0,0 +1,41 @@
1/*
2 * Device Tree Source for OMAP4/5 SoC CPU thermal
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
5 * Contact: Eduardo Valentin <eduardo.valentin@ti.com>
6 *
7 * This file is licensed under the terms of the GNU General Public License
8 * version 2. This program is licensed "as is" without any warranty of any
9 * kind, whether express or implied.
10 */
11
12#include <dt-bindings/thermal/thermal.h>
13
14cpu_thermal: cpu_thermal {
15 polling-delay-passive = <250>; /* milliseconds */
16 polling-delay = <1000>; /* milliseconds */
17
18 /* sensor ID */
19 thermal-sensors = <&bandgap 0>;
20
21 trips {
22 cpu_alert0: cpu_alert {
23 temperature = <100000>; /* millicelsius */
24 hysteresis = <2000>; /* millicelsius */
25 type = "passive";
26 };
27 cpu_crit: cpu_crit {
28 temperature = <125000>; /* millicelsius */
29 hysteresis = <2000>; /* millicelsius */
30 type = "critical";
31 };
32 };
33
34 cooling-maps {
35 map0 {
36 trip = <&cpu_alert0>;
37 cooling-device =
38 <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
39 };
40 };
41};
diff --git a/arch/arm/boot/dts/omap443x.dtsi b/arch/arm/boot/dts/omap443x.dtsi
index bcf455efe18d..ab607a19a613 100644
--- a/arch/arm/boot/dts/omap443x.dtsi
+++ b/arch/arm/boot/dts/omap443x.dtsi
@@ -12,7 +12,7 @@
12 12
13/ { 13/ {
14 cpus { 14 cpus {
15 cpu@0 { 15 cpu0: cpu@0 {
16 /* OMAP443x variants OPP50-OPPNT */ 16 /* OMAP443x variants OPP50-OPPNT */
17 operating-points = < 17 operating-points = <
18 /* kHz uV */ 18 /* kHz uV */
@@ -22,12 +22,25 @@
22 1008000 1375000 22 1008000 1375000
23 >; 23 >;
24 clock-latency = <300000>; /* From legacy driver */ 24 clock-latency = <300000>; /* From legacy driver */
25
26 /* cooling options */
27 cooling-min-level = <0>;
28 cooling-max-level = <3>;
29 #cooling-cells = <2>; /* min followed by max */
25 }; 30 };
26 }; 31 };
27 32
28 bandgap { 33 thermal-zones {
29 reg = <0x4a002260 0x4 34 #include "omap4-cpu-thermal.dtsi"
30 0x4a00232C 0x4>; 35 };
31 compatible = "ti,omap4430-bandgap"; 36
37 ocp {
38 bandgap: bandgap {
39 reg = <0x4a002260 0x4
40 0x4a00232C 0x4>;
41 compatible = "ti,omap4430-bandgap";
42
43 #thermal-sensor-cells = <0>;
44 };
32 }; 45 };
33}; 46};
diff --git a/arch/arm/boot/dts/omap4460.dtsi b/arch/arm/boot/dts/omap4460.dtsi
index c2f0f39b5a24..11566bed0035 100644
--- a/arch/arm/boot/dts/omap4460.dtsi
+++ b/arch/arm/boot/dts/omap4460.dtsi
@@ -12,7 +12,7 @@
12/ { 12/ {
13 cpus { 13 cpus {
14 /* OMAP446x 'standard device' variants OPP50 to OPPTurbo */ 14 /* OMAP446x 'standard device' variants OPP50 to OPPTurbo */
15 cpu@0 { 15 cpu0: cpu@0 {
16 operating-points = < 16 operating-points = <
17 /* kHz uV */ 17 /* kHz uV */
18 350000 1025000 18 350000 1025000
@@ -20,6 +20,11 @@
20 920000 1313000 20 920000 1313000
21 >; 21 >;
22 clock-latency = <300000>; /* From legacy driver */ 22 clock-latency = <300000>; /* From legacy driver */
23
24 /* cooling options */
25 cooling-min-level = <0>;
26 cooling-max-level = <2>;
27 #cooling-cells = <2>; /* min followed by max */
23 }; 28 };
24 }; 29 };
25 30
@@ -30,12 +35,20 @@
30 ti,hwmods = "debugss"; 35 ti,hwmods = "debugss";
31 }; 36 };
32 37
33 bandgap { 38 thermal-zones {
34 reg = <0x4a002260 0x4 39 #include "omap4-cpu-thermal.dtsi"
35 0x4a00232C 0x4 40 };
36 0x4a002378 0x18>; 41
37 compatible = "ti,omap4460-bandgap"; 42 ocp {
38 interrupts = <0 126 IRQ_TYPE_LEVEL_HIGH>; /* talert */ 43 bandgap: bandgap {
39 gpios = <&gpio3 22 0>; /* tshut */ 44 reg = <0x4a002260 0x4
45 0x4a00232C 0x4
46 0x4a002378 0x18>;
47 compatible = "ti,omap4460-bandgap";
48 interrupts = <0 126 IRQ_TYPE_LEVEL_HIGH>; /* talert */
49 gpios = <&gpio3 22 0>; /* tshut */
50
51 #thermal-sensor-cells = <0>;
52 };
40 }; 53 };
41}; 54};
diff --git a/arch/arm/boot/dts/omap5-core-thermal.dtsi b/arch/arm/boot/dts/omap5-core-thermal.dtsi
new file mode 100644
index 000000000000..19212ac6eef0
--- /dev/null
+++ b/arch/arm/boot/dts/omap5-core-thermal.dtsi
@@ -0,0 +1,28 @@
1/*
2 * Device Tree Source for OMAP543x SoC CORE thermal
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
5 * Contact: Eduardo Valentin <eduardo.valentin@ti.com>
6 *
7 * This file is licensed under the terms of the GNU General Public License
8 * version 2. This program is licensed "as is" without any warranty of any
9 * kind, whether express or implied.
10 */
11
12#include <dt-bindings/thermal/thermal.h>
13
14core_thermal: core_thermal {
15 polling-delay-passive = <250>; /* milliseconds */
16 polling-delay = <1000>; /* milliseconds */
17
18 /* sensor ID */
19 thermal-sensors = <&bandgap 2>;
20
21 trips {
22 core_crit: core_crit {
23 temperature = <125000>; /* milliCelsius */
24 hysteresis = <2000>; /* milliCelsius */
25 type = "critical";
26 };
27 };
28};
diff --git a/arch/arm/boot/dts/omap5-gpu-thermal.dtsi b/arch/arm/boot/dts/omap5-gpu-thermal.dtsi
new file mode 100644
index 000000000000..1b87aca88b77
--- /dev/null
+++ b/arch/arm/boot/dts/omap5-gpu-thermal.dtsi
@@ -0,0 +1,28 @@
1/*
2 * Device Tree Source for OMAP543x SoC GPU thermal
3 *
4 * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
5 * Contact: Eduardo Valentin <eduardo.valentin@ti.com>
6 *
7 * This file is licensed under the terms of the GNU General Public License
8 * version 2. This program is licensed "as is" without any warranty of any
9 * kind, whether express or implied.
10 */
11
12#include <dt-bindings/thermal/thermal.h>
13
14gpu_thermal: gpu_thermal {
15 polling-delay-passive = <250>; /* milliseconds */
16 polling-delay = <1000>; /* milliseconds */
17
18 /* sensor ID */
19 thermal-sensors = <&bandgap 1>;
20
21 trips {
22 gpu_crit: gpu_crit {
23 temperature = <125000>; /* milliCelsius */
24 hysteresis = <2000>; /* milliCelsius */
25 type = "critical";
26 };
27 };
28};
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index fc3fad563861..ab9a21ae82f3 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -49,6 +49,10 @@
49 1000000 1060000 49 1000000 1060000
50 1500000 1250000 50 1500000 1250000
51 >; 51 >;
52 /* cooling options */
53 cooling-min-level = <0>;
54 cooling-max-level = <2>;
55 #cooling-cells = <2>; /* min followed by max */
52 }; 56 };
53 cpu@1 { 57 cpu@1 {
54 device_type = "cpu"; 58 device_type = "cpu";
@@ -57,6 +61,12 @@
57 }; 61 };
58 }; 62 };
59 63
64 thermal-zones {
65 #include "omap4-cpu-thermal.dtsi"
66 #include "omap5-gpu-thermal.dtsi"
67 #include "omap5-core-thermal.dtsi"
68 };
69
60 timer { 70 timer {
61 compatible = "arm,armv7-timer"; 71 compatible = "arm,armv7-timer";
62 /* PPI secure/nonsecure IRQ */ 72 /* PPI secure/nonsecure IRQ */
@@ -729,13 +739,15 @@
729 }; 739 };
730 }; 740 };
731 741
732 bandgap@4a0021e0 { 742 bandgap: bandgap@4a0021e0 {
733 reg = <0x4a0021e0 0xc 743 reg = <0x4a0021e0 0xc
734 0x4a00232c 0xc 744 0x4a00232c 0xc
735 0x4a002380 0x2c 745 0x4a002380 0x2c
736 0x4a0023C0 0x3c>; 746 0x4a0023C0 0x3c>;
737 interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>; 747 interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>;
738 compatible = "ti,omap5430-bandgap"; 748 compatible = "ti,omap5430-bandgap";
749
750 #thermal-sensor-cells = <1>;
739 }; 751 };
740 }; 752 };
741}; 753};
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index d100926aca0a..4b029c0944af 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -185,7 +185,7 @@ config CPU_FREQ_GOV_CONSERVATIVE
185 185
186config GENERIC_CPUFREQ_CPU0 186config GENERIC_CPUFREQ_CPU0
187 tristate "Generic CPU0 cpufreq driver" 187 tristate "Generic CPU0 cpufreq driver"
188 depends on HAVE_CLK && REGULATOR && OF 188 depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL
189 select PM_OPP 189 select PM_OPP
190 help 190 help
191 This adds a generic cpufreq driver for CPU0 frequency management. 191 This adds a generic cpufreq driver for CPU0 frequency management.
diff --git a/drivers/cpufreq/cpufreq-cpu0.c b/drivers/cpufreq/cpufreq-cpu0.c
index bb7b3082efb3..0c12ffc0ebcb 100644
--- a/drivers/cpufreq/cpufreq-cpu0.c
+++ b/drivers/cpufreq/cpufreq-cpu0.c
@@ -13,7 +13,9 @@
13 13
14#include <linux/clk.h> 14#include <linux/clk.h>
15#include <linux/cpu.h> 15#include <linux/cpu.h>
16#include <linux/cpu_cooling.h>
16#include <linux/cpufreq.h> 17#include <linux/cpufreq.h>
18#include <linux/cpumask.h>
17#include <linux/err.h> 19#include <linux/err.h>
18#include <linux/module.h> 20#include <linux/module.h>
19#include <linux/of.h> 21#include <linux/of.h>
@@ -21,6 +23,7 @@
21#include <linux/platform_device.h> 23#include <linux/platform_device.h>
22#include <linux/regulator/consumer.h> 24#include <linux/regulator/consumer.h>
23#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/thermal.h>
24 27
25static unsigned int transition_latency; 28static unsigned int transition_latency;
26static unsigned int voltage_tolerance; /* in percentage */ 29static unsigned int voltage_tolerance; /* in percentage */
@@ -29,6 +32,7 @@ static struct device *cpu_dev;
29static struct clk *cpu_clk; 32static struct clk *cpu_clk;
30static struct regulator *cpu_reg; 33static struct regulator *cpu_reg;
31static struct cpufreq_frequency_table *freq_table; 34static struct cpufreq_frequency_table *freq_table;
35static struct thermal_cooling_device *cdev;
32 36
33static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index) 37static int cpu0_set_target(struct cpufreq_policy *policy, unsigned int index)
34{ 38{
@@ -197,6 +201,17 @@ static int cpu0_cpufreq_probe(struct platform_device *pdev)
197 goto out_free_table; 201 goto out_free_table;
198 } 202 }
199 203
204 /*
205 * For now, just loading the cooling device;
206 * thermal DT code takes care of matching them.
207 */
208 if (of_find_property(np, "#cooling-cells", NULL)) {
209 cdev = of_cpufreq_cooling_register(np, cpu_present_mask);
210 if (IS_ERR(cdev))
211 pr_err("running cpufreq without cooling device: %ld\n",
212 PTR_ERR(cdev));
213 }
214
200 of_node_put(np); 215 of_node_put(np);
201 return 0; 216 return 0;
202 217
@@ -209,6 +224,7 @@ out_put_node:
209 224
210static int cpu0_cpufreq_remove(struct platform_device *pdev) 225static int cpu0_cpufreq_remove(struct platform_device *pdev)
211{ 226{
227 cpufreq_cooling_unregister(cdev);
212 cpufreq_unregister_driver(&cpu0_cpufreq_driver); 228 cpufreq_unregister_driver(&cpu0_cpufreq_driver);
213 dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table); 229 dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
214 230
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index 7e3ef134f1d2..84a55eacd903 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -27,6 +27,8 @@
27#include <linux/hwmon-sysfs.h> 27#include <linux/hwmon-sysfs.h>
28#include <linux/err.h> 28#include <linux/err.h>
29#include <linux/mutex.h> 29#include <linux/mutex.h>
30#include <linux/of.h>
31#include <linux/thermal.h>
30#include "lm75.h" 32#include "lm75.h"
31 33
32 34
@@ -71,6 +73,7 @@ static const u8 LM75_REG_TEMP[3] = {
71/* Each client has this additional data */ 73/* Each client has this additional data */
72struct lm75_data { 74struct lm75_data {
73 struct device *hwmon_dev; 75 struct device *hwmon_dev;
76 struct thermal_zone_device *tz;
74 struct mutex update_lock; 77 struct mutex update_lock;
75 u8 orig_conf; 78 u8 orig_conf;
76 u8 resolution; /* In bits, between 9 and 12 */ 79 u8 resolution; /* In bits, between 9 and 12 */
@@ -91,22 +94,36 @@ static struct lm75_data *lm75_update_device(struct device *dev);
91 94
92/*-----------------------------------------------------------------------*/ 95/*-----------------------------------------------------------------------*/
93 96
97static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
98{
99 return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
100}
101
94/* sysfs attributes for hwmon */ 102/* sysfs attributes for hwmon */
95 103
104static int lm75_read_temp(void *dev, long *temp)
105{
106 struct lm75_data *data = lm75_update_device(dev);
107
108 if (IS_ERR(data))
109 return PTR_ERR(data);
110
111 *temp = lm75_reg_to_mc(data->temp[0], data->resolution);
112
113 return 0;
114}
115
96static ssize_t show_temp(struct device *dev, struct device_attribute *da, 116static ssize_t show_temp(struct device *dev, struct device_attribute *da,
97 char *buf) 117 char *buf)
98{ 118{
99 struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 119 struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
100 struct lm75_data *data = lm75_update_device(dev); 120 struct lm75_data *data = lm75_update_device(dev);
101 long temp;
102 121
103 if (IS_ERR(data)) 122 if (IS_ERR(data))
104 return PTR_ERR(data); 123 return PTR_ERR(data);
105 124
106 temp = ((data->temp[attr->index] >> (16 - data->resolution)) * 1000) 125 return sprintf(buf, "%ld\n", lm75_reg_to_mc(data->temp[attr->index],
107 >> (data->resolution - 8); 126 data->resolution));
108
109 return sprintf(buf, "%ld\n", temp);
110} 127}
111 128
112static ssize_t set_temp(struct device *dev, struct device_attribute *da, 129static ssize_t set_temp(struct device *dev, struct device_attribute *da,
@@ -273,6 +290,13 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
273 goto exit_remove; 290 goto exit_remove;
274 } 291 }
275 292
293 data->tz = thermal_zone_of_sensor_register(&client->dev,
294 0,
295 &client->dev,
296 lm75_read_temp, NULL);
297 if (IS_ERR(data->tz))
298 data->tz = NULL;
299
276 dev_info(&client->dev, "%s: sensor '%s'\n", 300 dev_info(&client->dev, "%s: sensor '%s'\n",
277 dev_name(data->hwmon_dev), client->name); 301 dev_name(data->hwmon_dev), client->name);
278 302
@@ -287,6 +311,7 @@ static int lm75_remove(struct i2c_client *client)
287{ 311{
288 struct lm75_data *data = i2c_get_clientdata(client); 312 struct lm75_data *data = i2c_get_clientdata(client);
289 313
314 thermal_zone_of_sensor_unregister(&client->dev, data->tz);
290 hwmon_device_unregister(data->hwmon_dev); 315 hwmon_device_unregister(data->hwmon_dev);
291 sysfs_remove_group(&client->dev.kobj, &lm75_group); 316 sysfs_remove_group(&client->dev.kobj, &lm75_group);
292 lm75_write_value(client, LM75_REG_CONF, data->orig_conf); 317 lm75_write_value(client, LM75_REG_CONF, data->orig_conf);
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index d7b47abf37fe..6748b4583e7b 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -27,6 +27,8 @@
27#include <linux/mutex.h> 27#include <linux/mutex.h>
28#include <linux/device.h> 28#include <linux/device.h>
29#include <linux/jiffies.h> 29#include <linux/jiffies.h>
30#include <linux/thermal.h>
31#include <linux/of.h>
30 32
31#define DRIVER_NAME "tmp102" 33#define DRIVER_NAME "tmp102"
32 34
@@ -50,6 +52,7 @@
50 52
51struct tmp102 { 53struct tmp102 {
52 struct device *hwmon_dev; 54 struct device *hwmon_dev;
55 struct thermal_zone_device *tz;
53 struct mutex lock; 56 struct mutex lock;
54 u16 config_orig; 57 u16 config_orig;
55 unsigned long last_update; 58 unsigned long last_update;
@@ -93,6 +96,15 @@ static struct tmp102 *tmp102_update_device(struct i2c_client *client)
93 return tmp102; 96 return tmp102;
94} 97}
95 98
99static int tmp102_read_temp(void *dev, long *temp)
100{
101 struct tmp102 *tmp102 = tmp102_update_device(to_i2c_client(dev));
102
103 *temp = tmp102->temp[0];
104
105 return 0;
106}
107
96static ssize_t tmp102_show_temp(struct device *dev, 108static ssize_t tmp102_show_temp(struct device *dev,
97 struct device_attribute *attr, 109 struct device_attribute *attr,
98 char *buf) 110 char *buf)
@@ -204,6 +216,12 @@ static int tmp102_probe(struct i2c_client *client,
204 goto fail_remove_sysfs; 216 goto fail_remove_sysfs;
205 } 217 }
206 218
219 tmp102->tz = thermal_zone_of_sensor_register(&client->dev, 0,
220 &client->dev,
221 tmp102_read_temp, NULL);
222 if (IS_ERR(tmp102->tz))
223 tmp102->tz = NULL;
224
207 dev_info(&client->dev, "initialized\n"); 225 dev_info(&client->dev, "initialized\n");
208 226
209 return 0; 227 return 0;
@@ -220,6 +238,7 @@ static int tmp102_remove(struct i2c_client *client)
220{ 238{
221 struct tmp102 *tmp102 = i2c_get_clientdata(client); 239 struct tmp102 *tmp102 = i2c_get_clientdata(client);
222 240
241 thermal_zone_of_sensor_unregister(&client->dev, tmp102->tz);
223 hwmon_device_unregister(tmp102->hwmon_dev); 242 hwmon_device_unregister(tmp102->hwmon_dev);
224 sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group); 243 sysfs_remove_group(&client->dev.kobj, &tmp102_attr_group);
225 244
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f35a1f75b15b..35c066489a19 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -29,6 +29,19 @@ config THERMAL_HWMON
29 Say 'Y' here if you want all thermal sensors to 29 Say 'Y' here if you want all thermal sensors to
30 have hwmon sysfs interface too. 30 have hwmon sysfs interface too.
31 31
32config THERMAL_OF
33 bool
34 prompt "APIs to parse thermal data out of device tree"
35 depends on OF
36 default y
37 help
38 This options provides helpers to add the support to
39 read and parse thermal data definitions out of the
40 device tree blob.
41
42 Say 'Y' here if you need to build thermal infrastructure
43 based on device tree.
44
32choice 45choice
33 prompt "Default Thermal governor" 46 prompt "Default Thermal governor"
34 default THERMAL_DEFAULT_GOV_STEP_WISE 47 default THERMAL_DEFAULT_GOV_STEP_WISE
@@ -79,6 +92,7 @@ config THERMAL_GOV_USER_SPACE
79config CPU_THERMAL 92config CPU_THERMAL
80 bool "generic cpu cooling support" 93 bool "generic cpu cooling support"
81 depends on CPU_FREQ 94 depends on CPU_FREQ
95 depends on THERMAL_OF
82 help 96 help
83 This implements the generic cpu cooling mechanism through frequency 97 This implements the generic cpu cooling mechanism through frequency
84 reduction. An ACPI version of this already exists 98 reduction. An ACPI version of this already exists
@@ -121,7 +135,7 @@ config SPEAR_THERMAL
121 135
122config RCAR_THERMAL 136config RCAR_THERMAL
123 tristate "Renesas R-Car thermal driver" 137 tristate "Renesas R-Car thermal driver"
124 depends on ARCH_SHMOBILE 138 depends on ARCH_SHMOBILE || COMPILE_TEST
125 help 139 help
126 Enable this to plug the R-Car thermal sensor driver into the Linux 140 Enable this to plug the R-Car thermal sensor driver into the Linux
127 thermal framework. 141 thermal framework.
@@ -192,6 +206,13 @@ config X86_PKG_TEMP_THERMAL
192 two trip points which can be set by user to get notifications via thermal 206 two trip points which can be set by user to get notifications via thermal
193 notification methods. 207 notification methods.
194 208
209config ACPI_INT3403_THERMAL
210 tristate "ACPI INT3403 thermal driver"
211 depends on X86 && ACPI
212 help
213 This driver uses ACPI INT3403 device objects. If present, it will
214 register each INT3403 thermal sensor as a thermal zone.
215
195menu "Texas Instruments thermal drivers" 216menu "Texas Instruments thermal drivers"
196source "drivers/thermal/ti-soc-thermal/Kconfig" 217source "drivers/thermal/ti-soc-thermal/Kconfig"
197endmenu 218endmenu
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 584b36319d51..54e4ec9eb5df 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -7,6 +7,7 @@ thermal_sys-y += thermal_core.o
7 7
8# interface to/from other layers providing sensors 8# interface to/from other layers providing sensors
9thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o 9thermal_sys-$(CONFIG_THERMAL_HWMON) += thermal_hwmon.o
10thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o
10 11
11# governors 12# governors
12thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o 13thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o
@@ -29,3 +30,4 @@ obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
29obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o 30obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
30obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o 31obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
31obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ 32obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
33obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 02a46f23d14c..4246262c4bd2 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -174,6 +174,13 @@ static int get_property(unsigned int cpu, unsigned long input,
174 max_level++; 174 max_level++;
175 } 175 }
176 176
177 /* No valid cpu frequency entry */
178 if (max_level == 0)
179 return -EINVAL;
180
181 /* max_level is an index, not a counter */
182 max_level--;
183
177 /* get max level */ 184 /* get max level */
178 if (property == GET_MAXL) { 185 if (property == GET_MAXL) {
179 *output = (unsigned int)max_level; 186 *output = (unsigned int)max_level;
@@ -181,7 +188,7 @@ static int get_property(unsigned int cpu, unsigned long input,
181 } 188 }
182 189
183 if (property == GET_FREQ) 190 if (property == GET_FREQ)
184 level = descend ? input : (max_level - input - 1); 191 level = descend ? input : (max_level - input);
185 192
186 for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) { 193 for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
187 /* ignore invalid entry */ 194 /* ignore invalid entry */
@@ -197,7 +204,7 @@ static int get_property(unsigned int cpu, unsigned long input,
197 204
198 if (property == GET_LEVEL && (unsigned int)input == freq) { 205 if (property == GET_LEVEL && (unsigned int)input == freq) {
199 /* get level by frequency */ 206 /* get level by frequency */
200 *output = descend ? j : (max_level - j - 1); 207 *output = descend ? j : (max_level - j);
201 return 0; 208 return 0;
202 } 209 }
203 if (property == GET_FREQ && level == j) { 210 if (property == GET_FREQ && level == j) {
@@ -417,18 +424,21 @@ static struct notifier_block thermal_cpufreq_notifier_block = {
417}; 424};
418 425
419/** 426/**
420 * cpufreq_cooling_register - function to create cpufreq cooling device. 427 * __cpufreq_cooling_register - helper function to create cpufreq cooling device
428 * @np: a valid struct device_node to the cooling device device tree node
421 * @clip_cpus: cpumask of cpus where the frequency constraints will happen. 429 * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
422 * 430 *
423 * This interface function registers the cpufreq cooling device with the name 431 * This interface function registers the cpufreq cooling device with the name
424 * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq 432 * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
425 * cooling devices. 433 * cooling devices. It also gives the opportunity to link the cooling device
434 * with a device tree node, in order to bind it via the thermal DT code.
426 * 435 *
427 * Return: a valid struct thermal_cooling_device pointer on success, 436 * Return: a valid struct thermal_cooling_device pointer on success,
428 * on failure, it returns a corresponding ERR_PTR(). 437 * on failure, it returns a corresponding ERR_PTR().
429 */ 438 */
430struct thermal_cooling_device * 439static struct thermal_cooling_device *
431cpufreq_cooling_register(const struct cpumask *clip_cpus) 440__cpufreq_cooling_register(struct device_node *np,
441 const struct cpumask *clip_cpus)
432{ 442{
433 struct thermal_cooling_device *cool_dev; 443 struct thermal_cooling_device *cool_dev;
434 struct cpufreq_cooling_device *cpufreq_dev = NULL; 444 struct cpufreq_cooling_device *cpufreq_dev = NULL;
@@ -467,8 +477,8 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus)
467 snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", 477 snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d",
468 cpufreq_dev->id); 478 cpufreq_dev->id);
469 479
470 cool_dev = thermal_cooling_device_register(dev_name, cpufreq_dev, 480 cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev,
471 &cpufreq_cooling_ops); 481 &cpufreq_cooling_ops);
472 if (IS_ERR(cool_dev)) { 482 if (IS_ERR(cool_dev)) {
473 release_idr(&cpufreq_idr, cpufreq_dev->id); 483 release_idr(&cpufreq_idr, cpufreq_dev->id);
474 kfree(cpufreq_dev); 484 kfree(cpufreq_dev);
@@ -488,9 +498,50 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus)
488 498
489 return cool_dev; 499 return cool_dev;
490} 500}
501
502/**
503 * cpufreq_cooling_register - function to create cpufreq cooling device.
504 * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
505 *
506 * This interface function registers the cpufreq cooling device with the name
507 * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
508 * cooling devices.
509 *
510 * Return: a valid struct thermal_cooling_device pointer on success,
511 * on failure, it returns a corresponding ERR_PTR().
512 */
513struct thermal_cooling_device *
514cpufreq_cooling_register(const struct cpumask *clip_cpus)
515{
516 return __cpufreq_cooling_register(NULL, clip_cpus);
517}
491EXPORT_SYMBOL_GPL(cpufreq_cooling_register); 518EXPORT_SYMBOL_GPL(cpufreq_cooling_register);
492 519
493/** 520/**
521 * of_cpufreq_cooling_register - function to create cpufreq cooling device.
522 * @np: a valid struct device_node to the cooling device device tree node
523 * @clip_cpus: cpumask of cpus where the frequency constraints will happen.
524 *
525 * This interface function registers the cpufreq cooling device with the name
526 * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq
527 * cooling devices. Using this API, the cpufreq cooling device will be
528 * linked to the device tree node provided.
529 *
530 * Return: a valid struct thermal_cooling_device pointer on success,
531 * on failure, it returns a corresponding ERR_PTR().
532 */
533struct thermal_cooling_device *
534of_cpufreq_cooling_register(struct device_node *np,
535 const struct cpumask *clip_cpus)
536{
537 if (!np)
538 return ERR_PTR(-EINVAL);
539
540 return __cpufreq_cooling_register(np, clip_cpus);
541}
542EXPORT_SYMBOL_GPL(of_cpufreq_cooling_register);
543
544/**
494 * cpufreq_cooling_unregister - function to remove cpufreq cooling device. 545 * cpufreq_cooling_unregister - function to remove cpufreq cooling device.
495 * @cdev: thermal cooling device pointer. 546 * @cdev: thermal cooling device pointer.
496 * 547 *
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 1d6c801c1eb9..45af765a3198 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -7,6 +7,7 @@
7 * 7 *
8 */ 8 */
9 9
10#include <linux/clk.h>
10#include <linux/cpu_cooling.h> 11#include <linux/cpu_cooling.h>
11#include <linux/cpufreq.h> 12#include <linux/cpufreq.h>
12#include <linux/delay.h> 13#include <linux/delay.h>
@@ -73,6 +74,7 @@ struct imx_thermal_data {
73 unsigned long last_temp; 74 unsigned long last_temp;
74 bool irq_enabled; 75 bool irq_enabled;
75 int irq; 76 int irq;
77 struct clk *thermal_clk;
76}; 78};
77 79
78static void imx_set_alarm_temp(struct imx_thermal_data *data, 80static void imx_set_alarm_temp(struct imx_thermal_data *data,
@@ -284,7 +286,7 @@ static int imx_unbind(struct thermal_zone_device *tz,
284 return 0; 286 return 0;
285} 287}
286 288
287static const struct thermal_zone_device_ops imx_tz_ops = { 289static struct thermal_zone_device_ops imx_tz_ops = {
288 .bind = imx_bind, 290 .bind = imx_bind,
289 .unbind = imx_unbind, 291 .unbind = imx_unbind,
290 .get_temp = imx_get_temp, 292 .get_temp = imx_get_temp,
@@ -457,6 +459,22 @@ static int imx_thermal_probe(struct platform_device *pdev)
457 return ret; 459 return ret;
458 } 460 }
459 461
462 data->thermal_clk = devm_clk_get(&pdev->dev, NULL);
463 if (IS_ERR(data->thermal_clk)) {
464 dev_warn(&pdev->dev, "failed to get thermal clk!\n");
465 } else {
466 /*
467 * Thermal sensor needs clk on to get correct value, normally
468 * we should enable its clk before taking measurement and disable
469 * clk after measurement is done, but if alarm function is enabled,
470 * hardware will auto measure the temperature periodically, so we
471 * need to keep the clk always on for alarm function.
472 */
473 ret = clk_prepare_enable(data->thermal_clk);
474 if (ret)
475 dev_warn(&pdev->dev, "failed to enable thermal clk: %d\n", ret);
476 }
477
460 /* Enable measurements at ~ 10 Hz */ 478 /* Enable measurements at ~ 10 Hz */
461 regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ); 479 regmap_write(map, TEMPSENSE1 + REG_CLR, TEMPSENSE1_MEASURE_FREQ);
462 measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */ 480 measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
@@ -478,6 +496,8 @@ static int imx_thermal_remove(struct platform_device *pdev)
478 496
479 /* Disable measurements */ 497 /* Disable measurements */
480 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); 498 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
499 if (!IS_ERR(data->thermal_clk))
500 clk_disable_unprepare(data->thermal_clk);
481 501
482 thermal_zone_device_unregister(data->tz); 502 thermal_zone_device_unregister(data->tz);
483 cpufreq_cooling_unregister(data->cdev); 503 cpufreq_cooling_unregister(data->cdev);
@@ -490,27 +510,30 @@ static int imx_thermal_suspend(struct device *dev)
490{ 510{
491 struct imx_thermal_data *data = dev_get_drvdata(dev); 511 struct imx_thermal_data *data = dev_get_drvdata(dev);
492 struct regmap *map = data->tempmon; 512 struct regmap *map = data->tempmon;
493 u32 val;
494 513
495 regmap_read(map, TEMPSENSE0, &val); 514 /*
496 if ((val & TEMPSENSE0_POWER_DOWN) == 0) { 515 * Need to disable thermal sensor, otherwise, when thermal core
497 /* 516 * try to get temperature before thermal sensor resume, a wrong
498 * If a measurement is taking place, wait for a long enough 517 * temperature will be read as the thermal sensor is powered
499 * time for it to finish, and then check again. If it still 518 * down.
500 * does not finish, something must go wrong. 519 */
501 */ 520 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_MEASURE_TEMP);
502 udelay(50); 521 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN);
503 regmap_read(map, TEMPSENSE0, &val); 522 data->mode = THERMAL_DEVICE_DISABLED;
504 if ((val & TEMPSENSE0_POWER_DOWN) == 0)
505 return -ETIMEDOUT;
506 }
507 523
508 return 0; 524 return 0;
509} 525}
510 526
511static int imx_thermal_resume(struct device *dev) 527static int imx_thermal_resume(struct device *dev)
512{ 528{
513 /* Nothing to do for now */ 529 struct imx_thermal_data *data = dev_get_drvdata(dev);
530 struct regmap *map = data->tempmon;
531
532 /* Enabled thermal sensor after resume */
533 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
534 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
535 data->mode = THERMAL_DEVICE_ENABLED;
536
514 return 0; 537 return 0;
515} 538}
516#endif 539#endif
@@ -522,6 +545,7 @@ static const struct of_device_id of_imx_thermal_match[] = {
522 { .compatible = "fsl,imx6q-tempmon", }, 545 { .compatible = "fsl,imx6q-tempmon", },
523 { /* end */ } 546 { /* end */ }
524}; 547};
548MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
525 549
526static struct platform_driver imx_thermal = { 550static struct platform_driver imx_thermal = {
527 .driver = { 551 .driver = {
diff --git a/drivers/thermal/int3403_thermal.c b/drivers/thermal/int3403_thermal.c
new file mode 100644
index 000000000000..1301681d9a77
--- /dev/null
+++ b/drivers/thermal/int3403_thermal.c
@@ -0,0 +1,237 @@
1/*
2 * ACPI INT3403 thermal driver
3 * Copyright (c) 2013, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/types.h>
19#include <linux/acpi.h>
20#include <linux/thermal.h>
21
22#define INT3403_TYPE_SENSOR 0x03
23#define INT3403_PERF_CHANGED_EVENT 0x80
24#define INT3403_THERMAL_EVENT 0x90
25
26#define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100)
27#define KELVIN_OFFSET 2732
28#define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off))
29
30#define ACPI_INT3403_CLASS "int3403"
31#define ACPI_INT3403_FILE_STATE "state"
32
33struct int3403_sensor {
34 struct thermal_zone_device *tzone;
35 unsigned long *thresholds;
36};
37
38static int sys_get_curr_temp(struct thermal_zone_device *tzone,
39 unsigned long *temp)
40{
41 struct acpi_device *device = tzone->devdata;
42 unsigned long long tmp;
43 acpi_status status;
44
45 status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp);
46 if (ACPI_FAILURE(status))
47 return -EIO;
48
49 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET);
50
51 return 0;
52}
53
54static int sys_get_trip_hyst(struct thermal_zone_device *tzone,
55 int trip, unsigned long *temp)
56{
57 struct acpi_device *device = tzone->devdata;
58 unsigned long long hyst;
59 acpi_status status;
60
61 status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst);
62 if (ACPI_FAILURE(status))
63 return -EIO;
64
65 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(hyst, KELVIN_OFFSET);
66
67 return 0;
68}
69
70static int sys_get_trip_temp(struct thermal_zone_device *tzone,
71 int trip, unsigned long *temp)
72{
73 struct acpi_device *device = tzone->devdata;
74 struct int3403_sensor *obj = acpi_driver_data(device);
75
76 /*
77 * get_trip_temp is a mandatory callback but
78 * PATx method doesn't return any value, so return
79 * cached value, which was last set from user space.
80 */
81 *temp = obj->thresholds[trip];
82
83 return 0;
84}
85
86static int sys_get_trip_type(struct thermal_zone_device *thermal,
87 int trip, enum thermal_trip_type *type)
88{
89 /* Mandatory callback, may not mean much here */
90 *type = THERMAL_TRIP_PASSIVE;
91
92 return 0;
93}
94
95int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip,
96 unsigned long temp)
97{
98 struct acpi_device *device = tzone->devdata;
99 acpi_status status;
100 char name[10];
101 int ret = 0;
102 struct int3403_sensor *obj = acpi_driver_data(device);
103
104 snprintf(name, sizeof(name), "PAT%d", trip);
105 if (acpi_has_method(device->handle, name)) {
106 status = acpi_execute_simple_method(device->handle, name,
107 MILLI_CELSIUS_TO_DECI_KELVIN(temp,
108 KELVIN_OFFSET));
109 if (ACPI_FAILURE(status))
110 ret = -EIO;
111 else
112 obj->thresholds[trip] = temp;
113 } else {
114 ret = -EIO;
115 dev_err(&device->dev, "sys_set_trip_temp: method not found\n");
116 }
117
118 return ret;
119}
120
121static struct thermal_zone_device_ops tzone_ops = {
122 .get_temp = sys_get_curr_temp,
123 .get_trip_temp = sys_get_trip_temp,
124 .get_trip_type = sys_get_trip_type,
125 .set_trip_temp = sys_set_trip_temp,
126 .get_trip_hyst = sys_get_trip_hyst,
127};
128
129static void acpi_thermal_notify(struct acpi_device *device, u32 event)
130{
131 struct int3403_sensor *obj;
132
133 if (!device)
134 return;
135
136 obj = acpi_driver_data(device);
137 if (!obj)
138 return;
139
140 switch (event) {
141 case INT3403_PERF_CHANGED_EVENT:
142 break;
143 case INT3403_THERMAL_EVENT:
144 thermal_zone_device_update(obj->tzone);
145 break;
146 default:
147 dev_err(&device->dev, "Unsupported event [0x%x]\n", event);
148 break;
149 }
150}
151
152static int acpi_int3403_add(struct acpi_device *device)
153{
154 int result = 0;
155 unsigned long long ptyp;
156 acpi_status status;
157 struct int3403_sensor *obj;
158 unsigned long long trip_cnt;
159 int trip_mask = 0;
160
161 if (!device)
162 return -EINVAL;
163
164 status = acpi_evaluate_integer(device->handle, "PTYP", NULL, &ptyp);
165 if (ACPI_FAILURE(status))
166 return -EINVAL;
167
168 if (ptyp != INT3403_TYPE_SENSOR)
169 return -EINVAL;
170
171 obj = devm_kzalloc(&device->dev, sizeof(*obj), GFP_KERNEL);
172 if (!obj)
173 return -ENOMEM;
174
175 device->driver_data = obj;
176
177 status = acpi_evaluate_integer(device->handle, "PATC", NULL,
178 &trip_cnt);
179 if (ACPI_FAILURE(status))
180 trip_cnt = 0;
181
182 if (trip_cnt) {
183 /* We have to cache, thresholds can't be readback */
184 obj->thresholds = devm_kzalloc(&device->dev,
185 sizeof(*obj->thresholds) * trip_cnt,
186 GFP_KERNEL);
187 if (!obj->thresholds)
188 return -ENOMEM;
189 trip_mask = BIT(trip_cnt) - 1;
190 }
191 obj->tzone = thermal_zone_device_register(acpi_device_bid(device),
192 trip_cnt, trip_mask, device, &tzone_ops,
193 NULL, 0, 0);
194 if (IS_ERR(obj->tzone)) {
195 result = PTR_ERR(obj->tzone);
196 return result;
197 }
198
199 strcpy(acpi_device_name(device), "INT3403");
200 strcpy(acpi_device_class(device), ACPI_INT3403_CLASS);
201
202 return 0;
203}
204
205static int acpi_int3403_remove(struct acpi_device *device)
206{
207 struct int3403_sensor *obj;
208
209 obj = acpi_driver_data(device);
210 thermal_zone_device_unregister(obj->tzone);
211
212 return 0;
213}
214
215ACPI_MODULE_NAME("int3403");
216static const struct acpi_device_id int3403_device_ids[] = {
217 {"INT3403", 0},
218 {"", 0},
219};
220MODULE_DEVICE_TABLE(acpi, int3403_device_ids);
221
222static struct acpi_driver acpi_int3403_driver = {
223 .name = "INT3403",
224 .class = ACPI_INT3403_CLASS,
225 .ids = int3403_device_ids,
226 .ops = {
227 .add = acpi_int3403_add,
228 .remove = acpi_int3403_remove,
229 .notify = acpi_thermal_notify,
230 },
231};
232
233module_acpi_driver(acpi_int3403_driver);
234
235MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
236MODULE_LICENSE("GPL v2");
237MODULE_DESCRIPTION("ACPI INT3403 thermal driver");
diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c
index d833c8f5b465..a084325f1386 100644
--- a/drivers/thermal/intel_powerclamp.c
+++ b/drivers/thermal/intel_powerclamp.c
@@ -206,6 +206,15 @@ static void find_target_mwait(void)
206 206
207} 207}
208 208
209static bool has_pkg_state_counter(void)
210{
211 u64 tmp;
212 return !rdmsrl_safe(MSR_PKG_C2_RESIDENCY, &tmp) ||
213 !rdmsrl_safe(MSR_PKG_C3_RESIDENCY, &tmp) ||
214 !rdmsrl_safe(MSR_PKG_C6_RESIDENCY, &tmp) ||
215 !rdmsrl_safe(MSR_PKG_C7_RESIDENCY, &tmp);
216}
217
209static u64 pkg_state_counter(void) 218static u64 pkg_state_counter(void)
210{ 219{
211 u64 val; 220 u64 val;
@@ -498,7 +507,7 @@ static int start_power_clamp(void)
498 struct task_struct *thread; 507 struct task_struct *thread;
499 508
500 /* check if pkg cstate counter is completely 0, abort in this case */ 509 /* check if pkg cstate counter is completely 0, abort in this case */
501 if (!pkg_state_counter()) { 510 if (!has_pkg_state_counter()) {
502 pr_err("pkg cstate counter not functional, abort\n"); 511 pr_err("pkg cstate counter not functional, abort\n");
503 return -EINVAL; 512 return -EINVAL;
504 } 513 }
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
new file mode 100644
index 000000000000..04b1be7fa018
--- /dev/null
+++ b/drivers/thermal/of-thermal.c
@@ -0,0 +1,849 @@
1/*
2 * of-thermal.c - Generic Thermal Management device tree support.
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
6 *
7 *
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 */
25#include <linux/thermal.h>
26#include <linux/slab.h>
27#include <linux/types.h>
28#include <linux/of_device.h>
29#include <linux/of_platform.h>
30#include <linux/err.h>
31#include <linux/export.h>
32#include <linux/string.h>
33
34#include "thermal_core.h"
35
36/*** Private data structures to represent thermal device tree data ***/
37
38/**
39 * struct __thermal_trip - representation of a point in temperature domain
40 * @np: pointer to struct device_node that this trip point was created from
41 * @temperature: temperature value in miliCelsius
42 * @hysteresis: relative hysteresis in miliCelsius
43 * @type: trip point type
44 */
45
46struct __thermal_trip {
47 struct device_node *np;
48 unsigned long int temperature;
49 unsigned long int hysteresis;
50 enum thermal_trip_type type;
51};
52
53/**
54 * struct __thermal_bind_param - a match between trip and cooling device
55 * @cooling_device: a pointer to identify the referred cooling device
56 * @trip_id: the trip point index
57 * @usage: the percentage (from 0 to 100) of cooling contribution
58 * @min: minimum cooling state used at this trip point
59 * @max: maximum cooling state used at this trip point
60 */
61
62struct __thermal_bind_params {
63 struct device_node *cooling_device;
64 unsigned int trip_id;
65 unsigned int usage;
66 unsigned long min;
67 unsigned long max;
68};
69
70/**
71 * struct __thermal_zone - internal representation of a thermal zone
72 * @mode: current thermal zone device mode (enabled/disabled)
73 * @passive_delay: polling interval while passive cooling is activated
74 * @polling_delay: zone polling interval
75 * @ntrips: number of trip points
76 * @trips: an array of trip points (0..ntrips - 1)
77 * @num_tbps: number of thermal bind params
78 * @tbps: an array of thermal bind params (0..num_tbps - 1)
79 * @sensor_data: sensor private data used while reading temperature and trend
80 * @get_temp: sensor callback to read temperature
81 * @get_trend: sensor callback to read temperature trend
82 */
83
84struct __thermal_zone {
85 enum thermal_device_mode mode;
86 int passive_delay;
87 int polling_delay;
88
89 /* trip data */
90 int ntrips;
91 struct __thermal_trip *trips;
92
93 /* cooling binding data */
94 int num_tbps;
95 struct __thermal_bind_params *tbps;
96
97 /* sensor interface */
98 void *sensor_data;
99 int (*get_temp)(void *, long *);
100 int (*get_trend)(void *, long *);
101};
102
103/*** DT thermal zone device callbacks ***/
104
105static int of_thermal_get_temp(struct thermal_zone_device *tz,
106 unsigned long *temp)
107{
108 struct __thermal_zone *data = tz->devdata;
109
110 if (!data->get_temp)
111 return -EINVAL;
112
113 return data->get_temp(data->sensor_data, temp);
114}
115
116static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
117 enum thermal_trend *trend)
118{
119 struct __thermal_zone *data = tz->devdata;
120 long dev_trend;
121 int r;
122
123 if (!data->get_trend)
124 return -EINVAL;
125
126 r = data->get_trend(data->sensor_data, &dev_trend);
127 if (r)
128 return r;
129
130 /* TODO: These intervals might have some thresholds, but in core code */
131 if (dev_trend > 0)
132 *trend = THERMAL_TREND_RAISING;
133 else if (dev_trend < 0)
134 *trend = THERMAL_TREND_DROPPING;
135 else
136 *trend = THERMAL_TREND_STABLE;
137
138 return 0;
139}
140
141static int of_thermal_bind(struct thermal_zone_device *thermal,
142 struct thermal_cooling_device *cdev)
143{
144 struct __thermal_zone *data = thermal->devdata;
145 int i;
146
147 if (!data || IS_ERR(data))
148 return -ENODEV;
149
150 /* find where to bind */
151 for (i = 0; i < data->num_tbps; i++) {
152 struct __thermal_bind_params *tbp = data->tbps + i;
153
154 if (tbp->cooling_device == cdev->np) {
155 int ret;
156
157 ret = thermal_zone_bind_cooling_device(thermal,
158 tbp->trip_id, cdev,
159 tbp->min,
160 tbp->max);
161 if (ret)
162 return ret;
163 }
164 }
165
166 return 0;
167}
168
169static int of_thermal_unbind(struct thermal_zone_device *thermal,
170 struct thermal_cooling_device *cdev)
171{
172 struct __thermal_zone *data = thermal->devdata;
173 int i;
174
175 if (!data || IS_ERR(data))
176 return -ENODEV;
177
178 /* find where to unbind */
179 for (i = 0; i < data->num_tbps; i++) {
180 struct __thermal_bind_params *tbp = data->tbps + i;
181
182 if (tbp->cooling_device == cdev->np) {
183 int ret;
184
185 ret = thermal_zone_unbind_cooling_device(thermal,
186 tbp->trip_id, cdev);
187 if (ret)
188 return ret;
189 }
190 }
191
192 return 0;
193}
194
195static int of_thermal_get_mode(struct thermal_zone_device *tz,
196 enum thermal_device_mode *mode)
197{
198 struct __thermal_zone *data = tz->devdata;
199
200 *mode = data->mode;
201
202 return 0;
203}
204
205static int of_thermal_set_mode(struct thermal_zone_device *tz,
206 enum thermal_device_mode mode)
207{
208 struct __thermal_zone *data = tz->devdata;
209
210 mutex_lock(&tz->lock);
211
212 if (mode == THERMAL_DEVICE_ENABLED)
213 tz->polling_delay = data->polling_delay;
214 else
215 tz->polling_delay = 0;
216
217 mutex_unlock(&tz->lock);
218
219 data->mode = mode;
220 thermal_zone_device_update(tz);
221
222 return 0;
223}
224
225static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
226 enum thermal_trip_type *type)
227{
228 struct __thermal_zone *data = tz->devdata;
229
230 if (trip >= data->ntrips || trip < 0)
231 return -EDOM;
232
233 *type = data->trips[trip].type;
234
235 return 0;
236}
237
238static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
239 unsigned long *temp)
240{
241 struct __thermal_zone *data = tz->devdata;
242
243 if (trip >= data->ntrips || trip < 0)
244 return -EDOM;
245
246 *temp = data->trips[trip].temperature;
247
248 return 0;
249}
250
251static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
252 unsigned long temp)
253{
254 struct __thermal_zone *data = tz->devdata;
255
256 if (trip >= data->ntrips || trip < 0)
257 return -EDOM;
258
259 /* thermal framework should take care of data->mask & (1 << trip) */
260 data->trips[trip].temperature = temp;
261
262 return 0;
263}
264
265static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
266 unsigned long *hyst)
267{
268 struct __thermal_zone *data = tz->devdata;
269
270 if (trip >= data->ntrips || trip < 0)
271 return -EDOM;
272
273 *hyst = data->trips[trip].hysteresis;
274
275 return 0;
276}
277
278static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
279 unsigned long hyst)
280{
281 struct __thermal_zone *data = tz->devdata;
282
283 if (trip >= data->ntrips || trip < 0)
284 return -EDOM;
285
286 /* thermal framework should take care of data->mask & (1 << trip) */
287 data->trips[trip].hysteresis = hyst;
288
289 return 0;
290}
291
292static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
293 unsigned long *temp)
294{
295 struct __thermal_zone *data = tz->devdata;
296 int i;
297
298 for (i = 0; i < data->ntrips; i++)
299 if (data->trips[i].type == THERMAL_TRIP_CRITICAL) {
300 *temp = data->trips[i].temperature;
301 return 0;
302 }
303
304 return -EINVAL;
305}
306
307static struct thermal_zone_device_ops of_thermal_ops = {
308 .get_mode = of_thermal_get_mode,
309 .set_mode = of_thermal_set_mode,
310
311 .get_trip_type = of_thermal_get_trip_type,
312 .get_trip_temp = of_thermal_get_trip_temp,
313 .set_trip_temp = of_thermal_set_trip_temp,
314 .get_trip_hyst = of_thermal_get_trip_hyst,
315 .set_trip_hyst = of_thermal_set_trip_hyst,
316 .get_crit_temp = of_thermal_get_crit_temp,
317
318 .bind = of_thermal_bind,
319 .unbind = of_thermal_unbind,
320};
321
322/*** sensor API ***/
323
324static struct thermal_zone_device *
325thermal_zone_of_add_sensor(struct device_node *zone,
326 struct device_node *sensor, void *data,
327 int (*get_temp)(void *, long *),
328 int (*get_trend)(void *, long *))
329{
330 struct thermal_zone_device *tzd;
331 struct __thermal_zone *tz;
332
333 tzd = thermal_zone_get_zone_by_name(zone->name);
334 if (IS_ERR(tzd))
335 return ERR_PTR(-EPROBE_DEFER);
336
337 tz = tzd->devdata;
338
339 mutex_lock(&tzd->lock);
340 tz->get_temp = get_temp;
341 tz->get_trend = get_trend;
342 tz->sensor_data = data;
343
344 tzd->ops->get_temp = of_thermal_get_temp;
345 tzd->ops->get_trend = of_thermal_get_trend;
346 mutex_unlock(&tzd->lock);
347
348 return tzd;
349}
350
351/**
352 * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
353 * @dev: a valid struct device pointer of a sensor device. Must contain
354 * a valid .of_node, for the sensor node.
355 * @sensor_id: a sensor identifier, in case the sensor IP has more
356 * than one sensors
357 * @data: a private pointer (owned by the caller) that will be passed
358 * back, when a temperature reading is needed.
359 * @get_temp: a pointer to a function that reads the sensor temperature.
360 * @get_trend: a pointer to a function that reads the sensor temperature trend.
361 *
362 * This function will search the list of thermal zones described in device
363 * tree and look for the zone that refer to the sensor device pointed by
364 * @dev->of_node as temperature providers. For the zone pointing to the
365 * sensor node, the sensor will be added to the DT thermal zone device.
366 *
367 * The thermal zone temperature is provided by the @get_temp function
368 * pointer. When called, it will have the private pointer @data back.
369 *
370 * The thermal zone temperature trend is provided by the @get_trend function
371 * pointer. When called, it will have the private pointer @data back.
372 *
373 * TODO:
374 * 01 - This function must enqueue the new sensor instead of using
375 * it as the only source of temperature values.
376 *
377 * 02 - There must be a way to match the sensor with all thermal zones
378 * that refer to it.
379 *
380 * Return: On success returns a valid struct thermal_zone_device,
381 * otherwise, it returns a corresponding ERR_PTR(). Caller must
382 * check the return value with help of IS_ERR() helper.
383 */
384struct thermal_zone_device *
385thermal_zone_of_sensor_register(struct device *dev, int sensor_id,
386 void *data, int (*get_temp)(void *, long *),
387 int (*get_trend)(void *, long *))
388{
389 struct device_node *np, *child, *sensor_np;
390
391 np = of_find_node_by_name(NULL, "thermal-zones");
392 if (!np)
393 return ERR_PTR(-ENODEV);
394
395 if (!dev || !dev->of_node)
396 return ERR_PTR(-EINVAL);
397
398 sensor_np = dev->of_node;
399
400 for_each_child_of_node(np, child) {
401 struct of_phandle_args sensor_specs;
402 int ret, id;
403
404 /* For now, thermal framework supports only 1 sensor per zone */
405 ret = of_parse_phandle_with_args(child, "thermal-sensors",
406 "#thermal-sensor-cells",
407 0, &sensor_specs);
408 if (ret)
409 continue;
410
411 if (sensor_specs.args_count >= 1) {
412 id = sensor_specs.args[0];
413 WARN(sensor_specs.args_count > 1,
414 "%s: too many cells in sensor specifier %d\n",
415 sensor_specs.np->name, sensor_specs.args_count);
416 } else {
417 id = 0;
418 }
419
420 if (sensor_specs.np == sensor_np && id == sensor_id) {
421 of_node_put(np);
422 return thermal_zone_of_add_sensor(child, sensor_np,
423 data,
424 get_temp,
425 get_trend);
426 }
427 }
428 of_node_put(np);
429
430 return ERR_PTR(-ENODEV);
431}
432EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register);
433
434/**
435 * thermal_zone_of_sensor_unregister - unregisters a sensor from a DT thermal zone
436 * @dev: a valid struct device pointer of a sensor device. Must contain
437 * a valid .of_node, for the sensor node.
438 * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
439 *
440 * This function removes the sensor callbacks and private data from the
441 * thermal zone device registered with thermal_zone_of_sensor_register()
442 * API. It will also silent the zone by remove the .get_temp() and .get_trend()
443 * thermal zone device callbacks.
444 *
445 * TODO: When the support to several sensors per zone is added, this
446 * function must search the sensor list based on @dev parameter.
447 *
448 */
449void thermal_zone_of_sensor_unregister(struct device *dev,
450 struct thermal_zone_device *tzd)
451{
452 struct __thermal_zone *tz;
453
454 if (!dev || !tzd || !tzd->devdata)
455 return;
456
457 tz = tzd->devdata;
458
459 /* no __thermal_zone, nothing to be done */
460 if (!tz)
461 return;
462
463 mutex_lock(&tzd->lock);
464 tzd->ops->get_temp = NULL;
465 tzd->ops->get_trend = NULL;
466
467 tz->get_temp = NULL;
468 tz->get_trend = NULL;
469 tz->sensor_data = NULL;
470 mutex_unlock(&tzd->lock);
471}
472EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
473
474/*** functions parsing device tree nodes ***/
475
476/**
477 * thermal_of_populate_bind_params - parse and fill cooling map data
478 * @np: DT node containing a cooling-map node
479 * @__tbp: data structure to be filled with cooling map info
480 * @trips: array of thermal zone trip points
481 * @ntrips: number of trip points inside trips.
482 *
483 * This function parses a cooling-map type of node represented by
484 * @np parameter and fills the read data into @__tbp data structure.
485 * It needs the already parsed array of trip points of the thermal zone
486 * in consideration.
487 *
488 * Return: 0 on success, proper error code otherwise
489 */
490static int thermal_of_populate_bind_params(struct device_node *np,
491 struct __thermal_bind_params *__tbp,
492 struct __thermal_trip *trips,
493 int ntrips)
494{
495 struct of_phandle_args cooling_spec;
496 struct device_node *trip;
497 int ret, i;
498 u32 prop;
499
500 /* Default weight. Usage is optional */
501 __tbp->usage = 0;
502 ret = of_property_read_u32(np, "contribution", &prop);
503 if (ret == 0)
504 __tbp->usage = prop;
505
506 trip = of_parse_phandle(np, "trip", 0);
507 if (!trip) {
508 pr_err("missing trip property\n");
509 return -ENODEV;
510 }
511
512 /* match using device_node */
513 for (i = 0; i < ntrips; i++)
514 if (trip == trips[i].np) {
515 __tbp->trip_id = i;
516 break;
517 }
518
519 if (i == ntrips) {
520 ret = -ENODEV;
521 goto end;
522 }
523
524 ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells",
525 0, &cooling_spec);
526 if (ret < 0) {
527 pr_err("missing cooling_device property\n");
528 goto end;
529 }
530 __tbp->cooling_device = cooling_spec.np;
531 if (cooling_spec.args_count >= 2) { /* at least min and max */
532 __tbp->min = cooling_spec.args[0];
533 __tbp->max = cooling_spec.args[1];
534 } else {
535 pr_err("wrong reference to cooling device, missing limits\n");
536 }
537
538end:
539 of_node_put(trip);
540
541 return ret;
542}
543
544/**
545 * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
546 * into the device tree binding of 'trip', property type.
547 */
548static const char * const trip_types[] = {
549 [THERMAL_TRIP_ACTIVE] = "active",
550 [THERMAL_TRIP_PASSIVE] = "passive",
551 [THERMAL_TRIP_HOT] = "hot",
552 [THERMAL_TRIP_CRITICAL] = "critical",
553};
554
555/**
556 * thermal_of_get_trip_type - Get phy mode for given device_node
557 * @np: Pointer to the given device_node
558 * @type: Pointer to resulting trip type
559 *
560 * The function gets trip type string from property 'type',
561 * and store its index in trip_types table in @type,
562 *
563 * Return: 0 on success, or errno in error case.
564 */
565static int thermal_of_get_trip_type(struct device_node *np,
566 enum thermal_trip_type *type)
567{
568 const char *t;
569 int err, i;
570
571 err = of_property_read_string(np, "type", &t);
572 if (err < 0)
573 return err;
574
575 for (i = 0; i < ARRAY_SIZE(trip_types); i++)
576 if (!strcasecmp(t, trip_types[i])) {
577 *type = i;
578 return 0;
579 }
580
581 return -ENODEV;
582}
583
584/**
585 * thermal_of_populate_trip - parse and fill one trip point data
586 * @np: DT node containing a trip point node
587 * @trip: trip point data structure to be filled up
588 *
589 * This function parses a trip point type of node represented by
590 * @np parameter and fills the read data into @trip data structure.
591 *
592 * Return: 0 on success, proper error code otherwise
593 */
594static int thermal_of_populate_trip(struct device_node *np,
595 struct __thermal_trip *trip)
596{
597 int prop;
598 int ret;
599
600 ret = of_property_read_u32(np, "temperature", &prop);
601 if (ret < 0) {
602 pr_err("missing temperature property\n");
603 return ret;
604 }
605 trip->temperature = prop;
606
607 ret = of_property_read_u32(np, "hysteresis", &prop);
608 if (ret < 0) {
609 pr_err("missing hysteresis property\n");
610 return ret;
611 }
612 trip->hysteresis = prop;
613
614 ret = thermal_of_get_trip_type(np, &trip->type);
615 if (ret < 0) {
616 pr_err("wrong trip type property\n");
617 return ret;
618 }
619
620 /* Required for cooling map matching */
621 trip->np = np;
622
623 return 0;
624}
625
626/**
627 * thermal_of_build_thermal_zone - parse and fill one thermal zone data
628 * @np: DT node containing a thermal zone node
629 *
630 * This function parses a thermal zone type of node represented by
631 * @np parameter and fills the read data into a __thermal_zone data structure
632 * and return this pointer.
633 *
634 * TODO: Missing properties to parse: thermal-sensor-names and coefficients
635 *
636 * Return: On success returns a valid struct __thermal_zone,
637 * otherwise, it returns a corresponding ERR_PTR(). Caller must
638 * check the return value with help of IS_ERR() helper.
639 */
640static struct __thermal_zone *
641thermal_of_build_thermal_zone(struct device_node *np)
642{
643 struct device_node *child = NULL, *gchild;
644 struct __thermal_zone *tz;
645 int ret, i;
646 u32 prop;
647
648 if (!np) {
649 pr_err("no thermal zone np\n");
650 return ERR_PTR(-EINVAL);
651 }
652
653 tz = kzalloc(sizeof(*tz), GFP_KERNEL);
654 if (!tz)
655 return ERR_PTR(-ENOMEM);
656
657 ret = of_property_read_u32(np, "polling-delay-passive", &prop);
658 if (ret < 0) {
659 pr_err("missing polling-delay-passive property\n");
660 goto free_tz;
661 }
662 tz->passive_delay = prop;
663
664 ret = of_property_read_u32(np, "polling-delay", &prop);
665 if (ret < 0) {
666 pr_err("missing polling-delay property\n");
667 goto free_tz;
668 }
669 tz->polling_delay = prop;
670
671 /* trips */
672 child = of_get_child_by_name(np, "trips");
673
674 /* No trips provided */
675 if (!child)
676 goto finish;
677
678 tz->ntrips = of_get_child_count(child);
679 if (tz->ntrips == 0) /* must have at least one child */
680 goto finish;
681
682 tz->trips = kzalloc(tz->ntrips * sizeof(*tz->trips), GFP_KERNEL);
683 if (!tz->trips) {
684 ret = -ENOMEM;
685 goto free_tz;
686 }
687
688 i = 0;
689 for_each_child_of_node(child, gchild) {
690 ret = thermal_of_populate_trip(gchild, &tz->trips[i++]);
691 if (ret)
692 goto free_trips;
693 }
694
695 of_node_put(child);
696
697 /* cooling-maps */
698 child = of_get_child_by_name(np, "cooling-maps");
699
700 /* cooling-maps not provided */
701 if (!child)
702 goto finish;
703
704 tz->num_tbps = of_get_child_count(child);
705 if (tz->num_tbps == 0)
706 goto finish;
707
708 tz->tbps = kzalloc(tz->num_tbps * sizeof(*tz->tbps), GFP_KERNEL);
709 if (!tz->tbps) {
710 ret = -ENOMEM;
711 goto free_trips;
712 }
713
714 i = 0;
715 for_each_child_of_node(child, gchild)
716 ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++],
717 tz->trips, tz->ntrips);
718 if (ret)
719 goto free_tbps;
720
721finish:
722 of_node_put(child);
723 tz->mode = THERMAL_DEVICE_DISABLED;
724
725 return tz;
726
727free_tbps:
728 kfree(tz->tbps);
729free_trips:
730 kfree(tz->trips);
731free_tz:
732 kfree(tz);
733 of_node_put(child);
734
735 return ERR_PTR(ret);
736}
737
738static inline void of_thermal_free_zone(struct __thermal_zone *tz)
739{
740 kfree(tz->tbps);
741 kfree(tz->trips);
742 kfree(tz);
743}
744
745/**
746 * of_parse_thermal_zones - parse device tree thermal data
747 *
748 * Initialization function that can be called by machine initialization
749 * code to parse thermal data and populate the thermal framework
750 * with hardware thermal zones info. This function only parses thermal zones.
751 * Cooling devices and sensor devices nodes are supposed to be parsed
752 * by their respective drivers.
753 *
754 * Return: 0 on success, proper error code otherwise
755 *
756 */
757int __init of_parse_thermal_zones(void)
758{
759 struct device_node *np, *child;
760 struct __thermal_zone *tz;
761 struct thermal_zone_device_ops *ops;
762
763 np = of_find_node_by_name(NULL, "thermal-zones");
764 if (!np) {
765 pr_debug("unable to find thermal zones\n");
766 return 0; /* Run successfully on systems without thermal DT */
767 }
768
769 for_each_child_of_node(np, child) {
770 struct thermal_zone_device *zone;
771 struct thermal_zone_params *tzp;
772
773 tz = thermal_of_build_thermal_zone(child);
774 if (IS_ERR(tz)) {
775 pr_err("failed to build thermal zone %s: %ld\n",
776 child->name,
777 PTR_ERR(tz));
778 continue;
779 }
780
781 ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);
782 if (!ops)
783 goto exit_free;
784
785 tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
786 if (!tzp) {
787 kfree(ops);
788 goto exit_free;
789 }
790
791 /* No hwmon because there might be hwmon drivers registering */
792 tzp->no_hwmon = true;
793
794 zone = thermal_zone_device_register(child->name, tz->ntrips,
795 0, tz,
796 ops, tzp,
797 tz->passive_delay,
798 tz->polling_delay);
799 if (IS_ERR(zone)) {
800 pr_err("Failed to build %s zone %ld\n", child->name,
801 PTR_ERR(zone));
802 kfree(tzp);
803 kfree(ops);
804 of_thermal_free_zone(tz);
805 /* attempting to build remaining zones still */
806 }
807 }
808
809 return 0;
810
811exit_free:
812 of_thermal_free_zone(tz);
813
814 /* no memory available, so free what we have built */
815 of_thermal_destroy_zones();
816
817 return -ENOMEM;
818}
819
820/**
821 * of_thermal_destroy_zones - remove all zones parsed and allocated resources
822 *
823 * Finds all zones parsed and added to the thermal framework and remove them
824 * from the system, together with their resources.
825 *
826 */
827void of_thermal_destroy_zones(void)
828{
829 struct device_node *np, *child;
830
831 np = of_find_node_by_name(NULL, "thermal-zones");
832 if (!np) {
833 pr_err("unable to find thermal zones\n");
834 return;
835 }
836
837 for_each_child_of_node(np, child) {
838 struct thermal_zone_device *zone;
839
840 zone = thermal_zone_get_zone_by_name(child->name);
841 if (IS_ERR(zone))
842 continue;
843
844 thermal_zone_device_unregister(zone);
845 kfree(zone->tzp);
846 kfree(zone->ops);
847 of_thermal_free_zone(zone->devdata);
848 }
849}
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
index c2301da08ac7..3f5ad25ddca8 100644
--- a/drivers/thermal/samsung/exynos_thermal_common.c
+++ b/drivers/thermal/samsung/exynos_thermal_common.c
@@ -280,7 +280,7 @@ static int exynos_get_trend(struct thermal_zone_device *thermal,
280 return 0; 280 return 0;
281} 281}
282/* Operation callback functions for thermal zone */ 282/* Operation callback functions for thermal zone */
283static struct thermal_zone_device_ops const exynos_dev_ops = { 283static struct thermal_zone_device_ops exynos_dev_ops = {
284 .bind = exynos_bind, 284 .bind = exynos_bind,
285 .unbind = exynos_unbind, 285 .unbind = exynos_unbind,
286 .get_temp = exynos_get_temp, 286 .get_temp = exynos_get_temp,
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index 32f38b90c4f6..0d96a510389f 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -205,6 +205,7 @@ static int exynos_tmu_initialize(struct platform_device *pdev)
205skip_calib_data: 205skip_calib_data:
206 if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) { 206 if (pdata->max_trigger_level > MAX_THRESHOLD_LEVS) {
207 dev_err(&pdev->dev, "Invalid max trigger level\n"); 207 dev_err(&pdev->dev, "Invalid max trigger level\n");
208 ret = -EINVAL;
208 goto out; 209 goto out;
209 } 210 }
210 211
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index d89e781b0a18..f251521baaa2 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -60,6 +60,7 @@ static unsigned long get_target_state(struct thermal_instance *instance,
60 */ 60 */
61 cdev->ops->get_cur_state(cdev, &cur_state); 61 cdev->ops->get_cur_state(cdev, &cur_state);
62 next_target = instance->target; 62 next_target = instance->target;
63 dev_dbg(&cdev->device, "cur_state=%ld\n", cur_state);
63 64
64 switch (trend) { 65 switch (trend) {
65 case THERMAL_TREND_RAISING: 66 case THERMAL_TREND_RAISING:
@@ -131,6 +132,9 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
131 if (tz->temperature >= trip_temp) 132 if (tz->temperature >= trip_temp)
132 throttle = true; 133 throttle = true;
133 134
135 dev_dbg(&tz->device, "Trip%d[type=%d,temp=%ld]:trend=%d,throttle=%d\n",
136 trip, trip_type, trip_temp, trend, throttle);
137
134 mutex_lock(&tz->lock); 138 mutex_lock(&tz->lock);
135 139
136 list_for_each_entry(instance, &tz->thermal_instances, tz_node) { 140 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
@@ -139,6 +143,8 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
139 143
140 old_target = instance->target; 144 old_target = instance->target;
141 instance->target = get_target_state(instance, trend, throttle); 145 instance->target = get_target_state(instance, trend, throttle);
146 dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
147 old_target, (int)instance->target);
142 148
143 if (old_target == instance->target) 149 if (old_target == instance->target)
144 continue; 150 continue;
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index f1d511a9475b..338a88bf6662 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -34,6 +34,7 @@
34#include <linux/thermal.h> 34#include <linux/thermal.h>
35#include <linux/reboot.h> 35#include <linux/reboot.h>
36#include <linux/string.h> 36#include <linux/string.h>
37#include <linux/of.h>
37#include <net/netlink.h> 38#include <net/netlink.h>
38#include <net/genetlink.h> 39#include <net/genetlink.h>
39 40
@@ -403,7 +404,7 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
403 enum thermal_trip_type type; 404 enum thermal_trip_type type;
404#endif 405#endif
405 406
406 if (!tz || IS_ERR(tz)) 407 if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
407 goto exit; 408 goto exit;
408 409
409 mutex_lock(&tz->lock); 410 mutex_lock(&tz->lock);
@@ -450,12 +451,18 @@ static void update_temperature(struct thermal_zone_device *tz)
450 tz->last_temperature = tz->temperature; 451 tz->last_temperature = tz->temperature;
451 tz->temperature = temp; 452 tz->temperature = temp;
452 mutex_unlock(&tz->lock); 453 mutex_unlock(&tz->lock);
454
455 dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n",
456 tz->last_temperature, tz->temperature);
453} 457}
454 458
455void thermal_zone_device_update(struct thermal_zone_device *tz) 459void thermal_zone_device_update(struct thermal_zone_device *tz)
456{ 460{
457 int count; 461 int count;
458 462
463 if (!tz->ops->get_temp)
464 return;
465
459 update_temperature(tz); 466 update_temperature(tz);
460 467
461 for (count = 0; count < tz->trips; count++) 468 for (count = 0; count < tz->trips; count++)
@@ -774,6 +781,9 @@ emul_temp_store(struct device *dev, struct device_attribute *attr,
774 ret = tz->ops->set_emul_temp(tz, temperature); 781 ret = tz->ops->set_emul_temp(tz, temperature);
775 } 782 }
776 783
784 if (!ret)
785 thermal_zone_device_update(tz);
786
777 return ret ? ret : count; 787 return ret ? ret : count;
778} 788}
779static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store); 789static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
@@ -1052,7 +1062,8 @@ static struct class thermal_class = {
1052}; 1062};
1053 1063
1054/** 1064/**
1055 * thermal_cooling_device_register() - register a new thermal cooling device 1065 * __thermal_cooling_device_register() - register a new thermal cooling device
1066 * @np: a pointer to a device tree node.
1056 * @type: the thermal cooling device type. 1067 * @type: the thermal cooling device type.
1057 * @devdata: device private data. 1068 * @devdata: device private data.
1058 * @ops: standard thermal cooling devices callbacks. 1069 * @ops: standard thermal cooling devices callbacks.
@@ -1060,13 +1071,16 @@ static struct class thermal_class = {
1060 * This interface function adds a new thermal cooling device (fan/processor/...) 1071 * This interface function adds a new thermal cooling device (fan/processor/...)
1061 * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself 1072 * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
1062 * to all the thermal zone devices registered at the same time. 1073 * to all the thermal zone devices registered at the same time.
1074 * It also gives the opportunity to link the cooling device to a device tree
1075 * node, so that it can be bound to a thermal zone created out of device tree.
1063 * 1076 *
1064 * Return: a pointer to the created struct thermal_cooling_device or an 1077 * Return: a pointer to the created struct thermal_cooling_device or an
1065 * ERR_PTR. Caller must check return value with IS_ERR*() helpers. 1078 * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
1066 */ 1079 */
1067struct thermal_cooling_device * 1080static struct thermal_cooling_device *
1068thermal_cooling_device_register(char *type, void *devdata, 1081__thermal_cooling_device_register(struct device_node *np,
1069 const struct thermal_cooling_device_ops *ops) 1082 char *type, void *devdata,
1083 const struct thermal_cooling_device_ops *ops)
1070{ 1084{
1071 struct thermal_cooling_device *cdev; 1085 struct thermal_cooling_device *cdev;
1072 int result; 1086 int result;
@@ -1091,6 +1105,7 @@ thermal_cooling_device_register(char *type, void *devdata,
1091 strlcpy(cdev->type, type ? : "", sizeof(cdev->type)); 1105 strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
1092 mutex_init(&cdev->lock); 1106 mutex_init(&cdev->lock);
1093 INIT_LIST_HEAD(&cdev->thermal_instances); 1107 INIT_LIST_HEAD(&cdev->thermal_instances);
1108 cdev->np = np;
1094 cdev->ops = ops; 1109 cdev->ops = ops;
1095 cdev->updated = true; 1110 cdev->updated = true;
1096 cdev->device.class = &thermal_class; 1111 cdev->device.class = &thermal_class;
@@ -1133,9 +1148,53 @@ unregister:
1133 device_unregister(&cdev->device); 1148 device_unregister(&cdev->device);
1134 return ERR_PTR(result); 1149 return ERR_PTR(result);
1135} 1150}
1151
1152/**
1153 * thermal_cooling_device_register() - register a new thermal cooling device
1154 * @type: the thermal cooling device type.
1155 * @devdata: device private data.
1156 * @ops: standard thermal cooling devices callbacks.
1157 *
1158 * This interface function adds a new thermal cooling device (fan/processor/...)
1159 * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
1160 * to all the thermal zone devices registered at the same time.
1161 *
1162 * Return: a pointer to the created struct thermal_cooling_device or an
1163 * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
1164 */
1165struct thermal_cooling_device *
1166thermal_cooling_device_register(char *type, void *devdata,
1167 const struct thermal_cooling_device_ops *ops)
1168{
1169 return __thermal_cooling_device_register(NULL, type, devdata, ops);
1170}
1136EXPORT_SYMBOL_GPL(thermal_cooling_device_register); 1171EXPORT_SYMBOL_GPL(thermal_cooling_device_register);
1137 1172
1138/** 1173/**
1174 * thermal_of_cooling_device_register() - register an OF thermal cooling device
1175 * @np: a pointer to a device tree node.
1176 * @type: the thermal cooling device type.
1177 * @devdata: device private data.
1178 * @ops: standard thermal cooling devices callbacks.
1179 *
1180 * This function will register a cooling device with device tree node reference.
1181 * This interface function adds a new thermal cooling device (fan/processor/...)
1182 * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
1183 * to all the thermal zone devices registered at the same time.
1184 *
1185 * Return: a pointer to the created struct thermal_cooling_device or an
1186 * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
1187 */
1188struct thermal_cooling_device *
1189thermal_of_cooling_device_register(struct device_node *np,
1190 char *type, void *devdata,
1191 const struct thermal_cooling_device_ops *ops)
1192{
1193 return __thermal_cooling_device_register(np, type, devdata, ops);
1194}
1195EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
1196
1197/**
1139 * thermal_cooling_device_unregister - removes the registered thermal cooling device 1198 * thermal_cooling_device_unregister - removes the registered thermal cooling device
1140 * @cdev: the thermal cooling device to remove. 1199 * @cdev: the thermal cooling device to remove.
1141 * 1200 *
@@ -1207,6 +1266,8 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
1207 mutex_lock(&cdev->lock); 1266 mutex_lock(&cdev->lock);
1208 /* Make sure cdev enters the deepest cooling state */ 1267 /* Make sure cdev enters the deepest cooling state */
1209 list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { 1268 list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
1269 dev_dbg(&cdev->device, "zone%d->target=%lu\n",
1270 instance->tz->id, instance->target);
1210 if (instance->target == THERMAL_NO_TARGET) 1271 if (instance->target == THERMAL_NO_TARGET)
1211 continue; 1272 continue;
1212 if (instance->target > target) 1273 if (instance->target > target)
@@ -1215,6 +1276,7 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
1215 mutex_unlock(&cdev->lock); 1276 mutex_unlock(&cdev->lock);
1216 cdev->ops->set_cur_state(cdev, target); 1277 cdev->ops->set_cur_state(cdev, target);
1217 cdev->updated = true; 1278 cdev->updated = true;
1279 dev_dbg(&cdev->device, "set to state %lu\n", target);
1218} 1280}
1219EXPORT_SYMBOL(thermal_cdev_update); 1281EXPORT_SYMBOL(thermal_cdev_update);
1220 1282
@@ -1370,7 +1432,7 @@ static void remove_trip_attrs(struct thermal_zone_device *tz)
1370 */ 1432 */
1371struct thermal_zone_device *thermal_zone_device_register(const char *type, 1433struct thermal_zone_device *thermal_zone_device_register(const char *type,
1372 int trips, int mask, void *devdata, 1434 int trips, int mask, void *devdata,
1373 const struct thermal_zone_device_ops *ops, 1435 struct thermal_zone_device_ops *ops,
1374 const struct thermal_zone_params *tzp, 1436 const struct thermal_zone_params *tzp,
1375 int passive_delay, int polling_delay) 1437 int passive_delay, int polling_delay)
1376{ 1438{
@@ -1386,7 +1448,7 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
1386 if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips) 1448 if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
1387 return ERR_PTR(-EINVAL); 1449 return ERR_PTR(-EINVAL);
1388 1450
1389 if (!ops || !ops->get_temp) 1451 if (!ops)
1390 return ERR_PTR(-EINVAL); 1452 return ERR_PTR(-EINVAL);
1391 1453
1392 if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp)) 1454 if (trips > 0 && (!ops->get_trip_type || !ops->get_trip_temp))
@@ -1490,6 +1552,9 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
1490 1552
1491 INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check); 1553 INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
1492 1554
1555 if (!tz->ops->get_temp)
1556 thermal_zone_device_set_polling(tz, 0);
1557
1493 thermal_zone_device_update(tz); 1558 thermal_zone_device_update(tz);
1494 1559
1495 if (!result) 1560 if (!result)
@@ -1740,8 +1805,14 @@ static int __init thermal_init(void)
1740 if (result) 1805 if (result)
1741 goto unregister_class; 1806 goto unregister_class;
1742 1807
1808 result = of_parse_thermal_zones();
1809 if (result)
1810 goto exit_netlink;
1811
1743 return 0; 1812 return 0;
1744 1813
1814exit_netlink:
1815 genetlink_exit();
1745unregister_governors: 1816unregister_governors:
1746 thermal_unregister_governors(); 1817 thermal_unregister_governors();
1747unregister_class: 1818unregister_class:
@@ -1757,6 +1828,7 @@ error:
1757 1828
1758static void __exit thermal_exit(void) 1829static void __exit thermal_exit(void)
1759{ 1830{
1831 of_thermal_destroy_zones();
1760 genetlink_exit(); 1832 genetlink_exit();
1761 class_unregister(&thermal_class); 1833 class_unregister(&thermal_class);
1762 thermal_unregister_governors(); 1834 thermal_unregister_governors();
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 7cf2f6626251..3db339fb636f 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -77,4 +77,13 @@ static inline int thermal_gov_user_space_register(void) { return 0; }
77static inline void thermal_gov_user_space_unregister(void) {} 77static inline void thermal_gov_user_space_unregister(void) {}
78#endif /* CONFIG_THERMAL_GOV_USER_SPACE */ 78#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
79 79
80/* device tree support */
81#ifdef CONFIG_THERMAL_OF
82int of_parse_thermal_zones(void);
83void of_thermal_destroy_zones(void);
84#else
85static inline int of_parse_thermal_zones(void) { return 0; }
86static inline void of_thermal_destroy_zones(void) { }
87#endif
88
80#endif /* __THERMAL_CORE_H__ */ 89#endif /* __THERMAL_CORE_H__ */
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index 5a47cc8c8f85..9eec26dc0448 100644
--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -31,6 +31,7 @@
31#include <linux/cpufreq.h> 31#include <linux/cpufreq.h>
32#include <linux/cpumask.h> 32#include <linux/cpumask.h>
33#include <linux/cpu_cooling.h> 33#include <linux/cpu_cooling.h>
34#include <linux/of.h>
34 35
35#include "ti-thermal.h" 36#include "ti-thermal.h"
36#include "ti-bandgap.h" 37#include "ti-bandgap.h"
@@ -44,6 +45,7 @@ struct ti_thermal_data {
44 enum thermal_device_mode mode; 45 enum thermal_device_mode mode;
45 struct work_struct thermal_wq; 46 struct work_struct thermal_wq;
46 int sensor_id; 47 int sensor_id;
48 bool our_zone;
47}; 49};
48 50
49static void ti_thermal_work(struct work_struct *work) 51static void ti_thermal_work(struct work_struct *work)
@@ -75,11 +77,10 @@ static inline int ti_thermal_hotspot_temperature(int t, int s, int c)
75 77
76/* thermal zone ops */ 78/* thermal zone ops */
77/* Get temperature callback function for thermal zone*/ 79/* Get temperature callback function for thermal zone*/
78static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal, 80static inline int __ti_thermal_get_temp(void *devdata, long *temp)
79 unsigned long *temp)
80{ 81{
81 struct thermal_zone_device *pcb_tz = NULL; 82 struct thermal_zone_device *pcb_tz = NULL;
82 struct ti_thermal_data *data = thermal->devdata; 83 struct ti_thermal_data *data = devdata;
83 struct ti_bandgap *bgp; 84 struct ti_bandgap *bgp;
84 const struct ti_temp_sensor *s; 85 const struct ti_temp_sensor *s;
85 int ret, tmp, slope, constant; 86 int ret, tmp, slope, constant;
@@ -118,6 +119,14 @@ static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
118 return ret; 119 return ret;
119} 120}
120 121
122static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
123 unsigned long *temp)
124{
125 struct ti_thermal_data *data = thermal->devdata;
126
127 return __ti_thermal_get_temp(data, temp);
128}
129
121/* Bind callback functions for thermal zone */ 130/* Bind callback functions for thermal zone */
122static int ti_thermal_bind(struct thermal_zone_device *thermal, 131static int ti_thermal_bind(struct thermal_zone_device *thermal,
123 struct thermal_cooling_device *cdev) 132 struct thermal_cooling_device *cdev)
@@ -230,11 +239,9 @@ static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
230 return 0; 239 return 0;
231} 240}
232 241
233/* Get the temperature trend callback functions for thermal zone */ 242static int __ti_thermal_get_trend(void *p, long *trend)
234static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
235 int trip, enum thermal_trend *trend)
236{ 243{
237 struct ti_thermal_data *data = thermal->devdata; 244 struct ti_thermal_data *data = p;
238 struct ti_bandgap *bgp; 245 struct ti_bandgap *bgp;
239 int id, tr, ret = 0; 246 int id, tr, ret = 0;
240 247
@@ -245,6 +252,22 @@ static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
245 if (ret) 252 if (ret)
246 return ret; 253 return ret;
247 254
255 *trend = tr;
256
257 return 0;
258}
259
260/* Get the temperature trend callback functions for thermal zone */
261static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
262 int trip, enum thermal_trend *trend)
263{
264 int ret;
265 long tr;
266
267 ret = __ti_thermal_get_trend(thermal->devdata, &tr);
268 if (ret)
269 return ret;
270
248 if (tr > 0) 271 if (tr > 0)
249 *trend = THERMAL_TREND_RAISING; 272 *trend = THERMAL_TREND_RAISING;
250 else if (tr < 0) 273 else if (tr < 0)
@@ -308,16 +331,23 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id,
308 if (!data) 331 if (!data)
309 return -EINVAL; 332 return -EINVAL;
310 333
311 /* Create thermal zone */ 334 /* in case this is specified by DT */
312 data->ti_thermal = thermal_zone_device_register(domain, 335 data->ti_thermal = thermal_zone_of_sensor_register(bgp->dev, id,
336 data, __ti_thermal_get_temp,
337 __ti_thermal_get_trend);
338 if (IS_ERR(data->ti_thermal)) {
339 /* Create thermal zone */
340 data->ti_thermal = thermal_zone_device_register(domain,
313 OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops, 341 OMAP_TRIP_NUMBER, 0, data, &ti_thermal_ops,
314 NULL, FAST_TEMP_MONITORING_RATE, 342 NULL, FAST_TEMP_MONITORING_RATE,
315 FAST_TEMP_MONITORING_RATE); 343 FAST_TEMP_MONITORING_RATE);
316 if (IS_ERR(data->ti_thermal)) { 344 if (IS_ERR(data->ti_thermal)) {
317 dev_err(bgp->dev, "thermal zone device is NULL\n"); 345 dev_err(bgp->dev, "thermal zone device is NULL\n");
318 return PTR_ERR(data->ti_thermal); 346 return PTR_ERR(data->ti_thermal);
347 }
348 data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
349 data->our_zone = true;
319 } 350 }
320 data->ti_thermal->polling_delay = FAST_TEMP_MONITORING_RATE;
321 ti_bandgap_set_sensor_data(bgp, id, data); 351 ti_bandgap_set_sensor_data(bgp, id, data);
322 ti_bandgap_write_update_interval(bgp, data->sensor_id, 352 ti_bandgap_write_update_interval(bgp, data->sensor_id,
323 data->ti_thermal->polling_delay); 353 data->ti_thermal->polling_delay);
@@ -331,7 +361,13 @@ int ti_thermal_remove_sensor(struct ti_bandgap *bgp, int id)
331 361
332 data = ti_bandgap_get_sensor_data(bgp, id); 362 data = ti_bandgap_get_sensor_data(bgp, id);
333 363
334 thermal_zone_device_unregister(data->ti_thermal); 364 if (data && data->ti_thermal) {
365 if (data->our_zone)
366 thermal_zone_device_unregister(data->ti_thermal);
367 else
368 thermal_zone_of_sensor_unregister(bgp->dev,
369 data->ti_thermal);
370 }
335 371
336 return 0; 372 return 0;
337} 373}
@@ -350,6 +386,15 @@ int ti_thermal_report_sensor_temperature(struct ti_bandgap *bgp, int id)
350int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id) 386int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id)
351{ 387{
352 struct ti_thermal_data *data; 388 struct ti_thermal_data *data;
389 struct device_node *np = bgp->dev->of_node;
390
391 /*
392 * We are assuming here that if one deploys the zone
393 * using DT, then it must be aware that the cooling device
394 * loading has to happen via cpufreq driver.
395 */
396 if (of_find_property(np, "#thermal-sensor-cells", NULL))
397 return 0;
353 398
354 data = ti_bandgap_get_sensor_data(bgp, id); 399 data = ti_bandgap_get_sensor_data(bgp, id);
355 if (!data || IS_ERR(data)) 400 if (!data || IS_ERR(data))
@@ -380,7 +425,9 @@ int ti_thermal_unregister_cpu_cooling(struct ti_bandgap *bgp, int id)
380 struct ti_thermal_data *data; 425 struct ti_thermal_data *data;
381 426
382 data = ti_bandgap_get_sensor_data(bgp, id); 427 data = ti_bandgap_get_sensor_data(bgp, id);
383 cpufreq_cooling_unregister(data->cool_dev); 428
429 if (data && data->cool_dev)
430 cpufreq_cooling_unregister(data->cool_dev);
384 431
385 return 0; 432 return 0;
386} 433}
diff --git a/drivers/thermal/x86_pkg_temp_thermal.c b/drivers/thermal/x86_pkg_temp_thermal.c
index 7722cb9d5a80..972e1c73722a 100644
--- a/drivers/thermal/x86_pkg_temp_thermal.c
+++ b/drivers/thermal/x86_pkg_temp_thermal.c
@@ -215,7 +215,7 @@ static int sys_get_trip_temp(struct thermal_zone_device *tzd,
215 return 0; 215 return 0;
216} 216}
217 217
218int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip, 218static int sys_set_trip_temp(struct thermal_zone_device *tzd, int trip,
219 unsigned long temp) 219 unsigned long temp)
220{ 220{
221 u32 l, h; 221 u32 l, h;
diff --git a/include/dt-bindings/thermal/thermal.h b/include/dt-bindings/thermal/thermal.h
new file mode 100644
index 000000000000..59822a995858
--- /dev/null
+++ b/include/dt-bindings/thermal/thermal.h
@@ -0,0 +1,17 @@
1/*
2 * This header provides constants for most thermal bindings.
3 *
4 * Copyright (C) 2013 Texas Instruments
5 * Eduardo Valentin <eduardo.valentin@ti.com>
6 *
7 * GPLv2 only
8 */
9
10#ifndef _DT_BINDINGS_THERMAL_THERMAL_H
11#define _DT_BINDINGS_THERMAL_THERMAL_H
12
13/* On cooling devices upper and lower limits */
14#define THERMAL_NO_LIMIT (-1UL)
15
16#endif
17
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index a5d52eea8232..c303d383def1 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -24,6 +24,7 @@
24#ifndef __CPU_COOLING_H__ 24#ifndef __CPU_COOLING_H__
25#define __CPU_COOLING_H__ 25#define __CPU_COOLING_H__
26 26
27#include <linux/of.h>
27#include <linux/thermal.h> 28#include <linux/thermal.h>
28#include <linux/cpumask.h> 29#include <linux/cpumask.h>
29 30
@@ -36,6 +37,24 @@ struct thermal_cooling_device *
36cpufreq_cooling_register(const struct cpumask *clip_cpus); 37cpufreq_cooling_register(const struct cpumask *clip_cpus);
37 38
38/** 39/**
40 * of_cpufreq_cooling_register - create cpufreq cooling device based on DT.
41 * @np: a valid struct device_node to the cooling device device tree node.
42 * @clip_cpus: cpumask of cpus where the frequency constraints will happen
43 */
44#ifdef CONFIG_THERMAL_OF
45struct thermal_cooling_device *
46of_cpufreq_cooling_register(struct device_node *np,
47 const struct cpumask *clip_cpus);
48#else
49static inline struct thermal_cooling_device *
50of_cpufreq_cooling_register(struct device_node *np,
51 const struct cpumask *clip_cpus)
52{
53 return NULL;
54}
55#endif
56
57/**
39 * cpufreq_cooling_unregister - function to remove cpufreq cooling device. 58 * cpufreq_cooling_unregister - function to remove cpufreq cooling device.
40 * @cdev: thermal cooling device pointer. 59 * @cdev: thermal cooling device pointer.
41 */ 60 */
@@ -48,6 +67,12 @@ cpufreq_cooling_register(const struct cpumask *clip_cpus)
48{ 67{
49 return NULL; 68 return NULL;
50} 69}
70static inline struct thermal_cooling_device *
71of_cpufreq_cooling_register(struct device_node *np,
72 const struct cpumask *clip_cpus)
73{
74 return NULL;
75}
51static inline 76static inline
52void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) 77void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
53{ 78{
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index b268d3cf7ae3..f7e11c7ea7d9 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -25,6 +25,7 @@
25#ifndef __THERMAL_H__ 25#ifndef __THERMAL_H__
26#define __THERMAL_H__ 26#define __THERMAL_H__
27 27
28#include <linux/of.h>
28#include <linux/idr.h> 29#include <linux/idr.h>
29#include <linux/device.h> 30#include <linux/device.h>
30#include <linux/workqueue.h> 31#include <linux/workqueue.h>
@@ -143,6 +144,7 @@ struct thermal_cooling_device {
143 int id; 144 int id;
144 char type[THERMAL_NAME_LENGTH]; 145 char type[THERMAL_NAME_LENGTH];
145 struct device device; 146 struct device device;
147 struct device_node *np;
146 void *devdata; 148 void *devdata;
147 const struct thermal_cooling_device_ops *ops; 149 const struct thermal_cooling_device_ops *ops;
148 bool updated; /* true if the cooling device does not need update */ 150 bool updated; /* true if the cooling device does not need update */
@@ -172,7 +174,7 @@ struct thermal_zone_device {
172 int emul_temperature; 174 int emul_temperature;
173 int passive; 175 int passive;
174 unsigned int forced_passive; 176 unsigned int forced_passive;
175 const struct thermal_zone_device_ops *ops; 177 struct thermal_zone_device_ops *ops;
176 const struct thermal_zone_params *tzp; 178 const struct thermal_zone_params *tzp;
177 struct thermal_governor *governor; 179 struct thermal_governor *governor;
178 struct list_head thermal_instances; 180 struct list_head thermal_instances;
@@ -242,8 +244,31 @@ struct thermal_genl_event {
242}; 244};
243 245
244/* Function declarations */ 246/* Function declarations */
247#ifdef CONFIG_THERMAL_OF
248struct thermal_zone_device *
249thermal_zone_of_sensor_register(struct device *dev, int id,
250 void *data, int (*get_temp)(void *, long *),
251 int (*get_trend)(void *, long *));
252void thermal_zone_of_sensor_unregister(struct device *dev,
253 struct thermal_zone_device *tz);
254#else
255static inline struct thermal_zone_device *
256thermal_zone_of_sensor_register(struct device *dev, int id,
257 void *data, int (*get_temp)(void *, long *),
258 int (*get_trend)(void *, long *))
259{
260 return NULL;
261}
262
263static inline
264void thermal_zone_of_sensor_unregister(struct device *dev,
265 struct thermal_zone_device *tz)
266{
267}
268
269#endif
245struct thermal_zone_device *thermal_zone_device_register(const char *, int, int, 270struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
246 void *, const struct thermal_zone_device_ops *, 271 void *, struct thermal_zone_device_ops *,
247 const struct thermal_zone_params *, int, int); 272 const struct thermal_zone_params *, int, int);
248void thermal_zone_device_unregister(struct thermal_zone_device *); 273void thermal_zone_device_unregister(struct thermal_zone_device *);
249 274
@@ -256,6 +281,9 @@ void thermal_zone_device_update(struct thermal_zone_device *);
256 281
257struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, 282struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
258 const struct thermal_cooling_device_ops *); 283 const struct thermal_cooling_device_ops *);
284struct thermal_cooling_device *
285thermal_of_cooling_device_register(struct device_node *np, char *, void *,
286 const struct thermal_cooling_device_ops *);
259void thermal_cooling_device_unregister(struct thermal_cooling_device *); 287void thermal_cooling_device_unregister(struct thermal_cooling_device *);
260struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name); 288struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
261int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp); 289int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp);