1 // SPDX-License-Identifier: GPL-2.0
3 * of-thermal.c - Generic Thermal Management device tree support.
5 * Copyright (C) 2013 Texas Instruments
6 * Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 #include <linux/err.h>
12 #include <linux/export.h>
14 #include <linux/slab.h>
15 #include <linux/thermal.h>
16 #include <linux/types.h>
17 #include <linux/string.h>
19 #include "thermal_core.h"
21 /*** functions parsing device tree nodes ***/
24 * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
25 * into the device tree binding of 'trip', property type.
27 static const char * const trip_types
[] = {
28 [THERMAL_TRIP_ACTIVE
] = "active",
29 [THERMAL_TRIP_PASSIVE
] = "passive",
30 [THERMAL_TRIP_HOT
] = "hot",
31 [THERMAL_TRIP_CRITICAL
] = "critical",
35 * thermal_of_get_trip_type - Get phy mode for given device_node
36 * @np: Pointer to the given device_node
37 * @type: Pointer to resulting trip type
39 * The function gets trip type string from property 'type',
40 * and store its index in trip_types table in @type,
42 * Return: 0 on success, or errno in error case.
44 static int thermal_of_get_trip_type(struct device_node
*np
,
45 enum thermal_trip_type
*type
)
50 err
= of_property_read_string(np
, "type", &t
);
54 for (i
= 0; i
< ARRAY_SIZE(trip_types
); i
++)
55 if (!strcasecmp(t
, trip_types
[i
])) {
63 static int thermal_of_populate_trip(struct device_node
*np
,
64 struct thermal_trip
*trip
)
69 ret
= of_property_read_u32(np
, "temperature", &prop
);
71 pr_err("missing temperature property\n");
74 trip
->temperature
= prop
;
76 ret
= of_property_read_u32(np
, "hysteresis", &prop
);
78 pr_err("missing hysteresis property\n");
81 trip
->hysteresis
= prop
;
83 ret
= thermal_of_get_trip_type(np
, &trip
->type
);
85 pr_err("wrong trip type property\n");
89 trip
->flags
= THERMAL_TRIP_FLAG_RW_TEMP
;
96 static struct thermal_trip
*thermal_of_trips_init(struct device_node
*np
, int *ntrips
)
102 struct device_node
*trips
__free(device_node
) = of_get_child_by_name(np
, "trips");
106 count
= of_get_child_count(trips
);
110 struct thermal_trip
*tt
__free(kfree
) = kzalloc(sizeof(*tt
) * count
, GFP_KERNEL
);
112 return ERR_PTR(-ENOMEM
);
115 for_each_child_of_node_scoped(trips
, trip
) {
116 ret
= thermal_of_populate_trip(trip
, &tt
[count
++]);
123 return no_free_ptr(tt
);
126 static struct device_node
*of_thermal_zone_find(struct device_node
*sensor
, int id
)
128 struct of_phandle_args sensor_specs
;
130 struct device_node
*np
__free(device_node
) = of_find_node_by_name(NULL
, "thermal-zones");
132 pr_debug("No thermal zones description\n");
133 return ERR_PTR(-ENODEV
);
137 * Search for each thermal zone, a defined sensor
138 * corresponding to the one passed as parameter
140 for_each_available_child_of_node_scoped(np
, child
) {
144 count
= of_count_phandle_with_args(child
, "thermal-sensors",
145 "#thermal-sensor-cells");
147 pr_err("%pOFn: missing thermal sensor\n", child
);
148 return ERR_PTR(-EINVAL
);
151 for (i
= 0; i
< count
; i
++) {
155 ret
= of_parse_phandle_with_args(child
, "thermal-sensors",
156 "#thermal-sensor-cells",
159 pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", child
, ret
);
163 if ((sensor
== sensor_specs
.np
) && id
== (sensor_specs
.args_count
?
164 sensor_specs
.args
[0] : 0)) {
165 pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor
, id
, child
);
166 return no_free_ptr(child
);
171 return ERR_PTR(-ENODEV
);
174 static int thermal_of_monitor_init(struct device_node
*np
, int *delay
, int *pdelay
)
178 ret
= of_property_read_u32(np
, "polling-delay-passive", pdelay
);
179 if (ret
== -EINVAL
) {
181 } else if (ret
< 0) {
182 pr_err("%pOFn: Couldn't get polling-delay-passive: %d\n", np
, ret
);
186 ret
= of_property_read_u32(np
, "polling-delay", delay
);
187 if (ret
== -EINVAL
) {
189 } else if (ret
< 0) {
190 pr_err("%pOFn: Couldn't get polling-delay: %d\n", np
, ret
);
197 static void thermal_of_parameters_init(struct device_node
*np
,
198 struct thermal_zone_params
*tzp
)
201 int ncoef
= ARRAY_SIZE(coef
);
204 tzp
->no_hwmon
= true;
206 if (!of_property_read_u32(np
, "sustainable-power", &prop
))
207 tzp
->sustainable_power
= prop
;
210 * For now, the thermal framework supports only one sensor per
211 * thermal zone. Thus, we are considering only the first two
212 * values as slope and offset.
214 ret
= of_property_read_u32_array(np
, "coefficients", coef
, ncoef
);
220 tzp
->slope
= coef
[0];
221 tzp
->offset
= coef
[1];
224 static struct device_node
*thermal_of_zone_get_by_name(struct thermal_zone_device
*tz
)
226 struct device_node
*np
, *tz_np
;
228 np
= of_find_node_by_name(NULL
, "thermal-zones");
230 return ERR_PTR(-ENODEV
);
232 tz_np
= of_get_child_by_name(np
, tz
->type
);
237 return ERR_PTR(-ENODEV
);
242 static bool thermal_of_get_cooling_spec(struct device_node
*map_np
, int index
,
243 struct thermal_cooling_device
*cdev
,
244 struct cooling_spec
*c
)
246 struct of_phandle_args cooling_spec
;
247 int ret
, weight
= THERMAL_WEIGHT_DEFAULT
;
249 of_property_read_u32(map_np
, "contribution", &weight
);
251 ret
= of_parse_phandle_with_args(map_np
, "cooling-device", "#cooling-cells",
252 index
, &cooling_spec
);
255 pr_err("Invalid cooling-device entry\n");
259 of_node_put(cooling_spec
.np
);
261 if (cooling_spec
.args_count
< 2) {
262 pr_err("wrong reference to cooling device, missing limits\n");
266 if (cooling_spec
.np
!= cdev
->np
)
269 c
->lower
= cooling_spec
.args
[0];
270 c
->upper
= cooling_spec
.args
[1];
276 static bool thermal_of_should_bind(struct thermal_zone_device
*tz
,
277 const struct thermal_trip
*trip
,
278 struct thermal_cooling_device
*cdev
,
279 struct cooling_spec
*c
)
281 struct device_node
*tz_np
, *cm_np
;
284 tz_np
= thermal_of_zone_get_by_name(tz
);
286 pr_err("Failed to get node tz by name\n");
290 cm_np
= of_get_child_by_name(tz_np
, "cooling-maps");
294 /* Look up the trip and the cdev in the cooling maps. */
295 for_each_child_of_node_scoped(cm_np
, child
) {
296 struct device_node
*tr_np
;
299 tr_np
= of_parse_phandle(child
, "trip", 0);
300 if (tr_np
!= trip
->priv
)
303 /* The trip has been found, look up the cdev. */
304 count
= of_count_phandle_with_args(child
, "cooling-device", "#cooling-cells");
306 pr_err("Add a cooling_device property with at least one device\n");
308 for (i
= 0; i
< count
; i
++) {
309 result
= thermal_of_get_cooling_spec(child
, i
, cdev
, c
);
325 * thermal_of_zone_unregister - Cleanup the specific allocated ressources
327 * This function disables the thermal zone and frees the different
328 * ressources allocated specific to the thermal OF.
330 * @tz: a pointer to the thermal zone structure
332 static void thermal_of_zone_unregister(struct thermal_zone_device
*tz
)
334 thermal_zone_device_disable(tz
);
335 thermal_zone_device_unregister(tz
);
339 * thermal_of_zone_register - Register a thermal zone with device node
342 * The thermal_of_zone_register() parses a device tree given a device
343 * node sensor and identifier. It searches for the thermal zone
344 * associated to the couple sensor/id and retrieves all the thermal
345 * zone properties and registers new thermal zone with those
348 * @sensor: A device node pointer corresponding to the sensor in the device tree
349 * @id: An integer as sensor identifier
350 * @data: A private data to be stored in the thermal zone dedicated private area
351 * @ops: A set of thermal sensor ops
353 * Return: a valid thermal zone structure pointer on success.
354 * - EINVAL: if the device tree thermal description is malformed
355 * - ENOMEM: if one structure can not be allocated
356 * - Other negative errors are returned by the underlying called functions
358 static struct thermal_zone_device
*thermal_of_zone_register(struct device_node
*sensor
, int id
, void *data
,
359 const struct thermal_zone_device_ops
*ops
)
361 struct thermal_zone_device_ops of_ops
= *ops
;
362 struct thermal_zone_device
*tz
;
363 struct thermal_trip
*trips
;
364 struct thermal_zone_params tzp
= {};
365 struct device_node
*np
;
371 np
= of_thermal_zone_find(sensor
, id
);
373 if (PTR_ERR(np
) != -ENODEV
)
374 pr_err("Failed to find thermal zone for %pOFn id=%d\n", sensor
, id
);
378 trips
= thermal_of_trips_init(np
, &ntrips
);
380 pr_err("Failed to parse trip points for %pOFn id=%d\n", sensor
, id
);
381 ret
= PTR_ERR(trips
);
382 goto out_of_node_put
;
386 pr_info("No trip points found for %pOFn id=%d\n", sensor
, id
);
388 ret
= thermal_of_monitor_init(np
, &delay
, &pdelay
);
390 pr_err("Failed to initialize monitoring delays from %pOFn\n", np
);
391 goto out_kfree_trips
;
394 thermal_of_parameters_init(np
, &tzp
);
396 of_ops
.should_bind
= thermal_of_should_bind
;
398 ret
= of_property_read_string(np
, "critical-action", &action
);
400 if (!of_ops
.critical
&& !strcasecmp(action
, "reboot"))
401 of_ops
.critical
= thermal_zone_device_critical_reboot
;
403 tz
= thermal_zone_device_register_with_trips(np
->name
, trips
, ntrips
,
408 pr_err("Failed to register thermal zone %pOFn: %d\n", np
, ret
);
409 goto out_kfree_trips
;
415 ret
= thermal_zone_device_enable(tz
);
417 pr_err("Failed to enabled thermal zone '%s', id=%d: %d\n",
418 tz
->type
, tz
->id
, ret
);
419 thermal_of_zone_unregister(tz
);
433 static void devm_thermal_of_zone_release(struct device
*dev
, void *res
)
435 thermal_of_zone_unregister(*(struct thermal_zone_device
**)res
);
438 static int devm_thermal_of_zone_match(struct device
*dev
, void *res
,
441 struct thermal_zone_device
**r
= res
;
443 if (WARN_ON(!r
|| !*r
))
450 * devm_thermal_of_zone_register - register a thermal tied with the sensor life cycle
452 * This function is the device version of the thermal_of_zone_register() function.
454 * @dev: a device structure pointer to sensor to be tied with the thermal zone OF life cycle
455 * @sensor_id: the sensor identifier
456 * @data: a pointer to a private data to be stored in the thermal zone 'devdata' field
457 * @ops: a pointer to the ops structure associated with the sensor
459 struct thermal_zone_device
*devm_thermal_of_zone_register(struct device
*dev
, int sensor_id
, void *data
,
460 const struct thermal_zone_device_ops
*ops
)
462 struct thermal_zone_device
**ptr
, *tzd
;
464 ptr
= devres_alloc(devm_thermal_of_zone_release
, sizeof(*ptr
),
467 return ERR_PTR(-ENOMEM
);
469 tzd
= thermal_of_zone_register(dev
->of_node
, sensor_id
, data
, ops
);
476 devres_add(dev
, ptr
);
480 EXPORT_SYMBOL_GPL(devm_thermal_of_zone_register
);
483 * devm_thermal_of_zone_unregister - Resource managed version of
484 * thermal_of_zone_unregister().
485 * @dev: Device for which which resource was allocated.
486 * @tz: a pointer to struct thermal_zone where the sensor is registered.
488 * This function removes the sensor callbacks and private data from the
489 * thermal zone device registered with devm_thermal_zone_of_sensor_register()
490 * API. It will also silent the zone by remove the .get_temp() and .get_trend()
491 * thermal zone device callbacks.
492 * Normally this function will not need to be called and the resource
493 * management code will ensure that the resource is freed.
495 void devm_thermal_of_zone_unregister(struct device
*dev
, struct thermal_zone_device
*tz
)
497 WARN_ON(devres_release(dev
, devm_thermal_of_zone_release
,
498 devm_thermal_of_zone_match
, tz
));
500 EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister
);