xref: /openbmc/linux/drivers/thermal/thermal_of.c (revision 1b36955c)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  of-thermal.c - Generic Thermal Management device tree support.
4  *
5  *  Copyright (C) 2013 Texas Instruments
6  *  Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
7  */
8 
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 
11 #include <linux/err.h>
12 #include <linux/export.h>
13 #include <linux/of.h>
14 #include <linux/slab.h>
15 #include <linux/thermal.h>
16 #include <linux/types.h>
17 #include <linux/string.h>
18 
19 #include "thermal_core.h"
20 
21 /***   functions parsing device tree nodes   ***/
22 
23 static int of_find_trip_id(struct device_node *np, struct device_node *trip)
24 {
25 	struct device_node *trips;
26 	struct device_node *t;
27 	int i = 0;
28 
29 	trips = of_get_child_by_name(np, "trips");
30 	if (!trips) {
31 		pr_err("Failed to find 'trips' node\n");
32 		return -EINVAL;
33 	}
34 
35 	/*
36 	 * Find the trip id point associated with the cooling device map
37 	 */
38 	for_each_child_of_node(trips, t) {
39 
40 		if (t == trip)
41 			goto out;
42 		i++;
43 	}
44 
45 	i = -ENXIO;
46 out:
47 	of_node_put(trips);
48 
49 	return i;
50 }
51 
52 /*
53  * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
54  * into the device tree binding of 'trip', property type.
55  */
56 static const char * const trip_types[] = {
57 	[THERMAL_TRIP_ACTIVE]	= "active",
58 	[THERMAL_TRIP_PASSIVE]	= "passive",
59 	[THERMAL_TRIP_HOT]	= "hot",
60 	[THERMAL_TRIP_CRITICAL]	= "critical",
61 };
62 
63 /**
64  * thermal_of_get_trip_type - Get phy mode for given device_node
65  * @np:	Pointer to the given device_node
66  * @type: Pointer to resulting trip type
67  *
68  * The function gets trip type string from property 'type',
69  * and store its index in trip_types table in @type,
70  *
71  * Return: 0 on success, or errno in error case.
72  */
73 static int thermal_of_get_trip_type(struct device_node *np,
74 				    enum thermal_trip_type *type)
75 {
76 	const char *t;
77 	int err, i;
78 
79 	err = of_property_read_string(np, "type", &t);
80 	if (err < 0)
81 		return err;
82 
83 	for (i = 0; i < ARRAY_SIZE(trip_types); i++)
84 		if (!strcasecmp(t, trip_types[i])) {
85 			*type = i;
86 			return 0;
87 		}
88 
89 	return -ENODEV;
90 }
91 
92 static int thermal_of_populate_trip(struct device_node *np,
93 				    struct thermal_trip *trip)
94 {
95 	int prop;
96 	int ret;
97 
98 	ret = of_property_read_u32(np, "temperature", &prop);
99 	if (ret < 0) {
100 		pr_err("missing temperature property\n");
101 		return ret;
102 	}
103 	trip->temperature = prop;
104 
105 	ret = of_property_read_u32(np, "hysteresis", &prop);
106 	if (ret < 0) {
107 		pr_err("missing hysteresis property\n");
108 		return ret;
109 	}
110 	trip->hysteresis = prop;
111 
112 	ret = thermal_of_get_trip_type(np, &trip->type);
113 	if (ret < 0) {
114 		pr_err("wrong trip type property\n");
115 		return ret;
116 	}
117 
118 	return 0;
119 }
120 
121 static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *ntrips)
122 {
123 	struct thermal_trip *tt;
124 	struct device_node *trips, *trip;
125 	int ret, count;
126 
127 	trips = of_get_child_by_name(np, "trips");
128 	if (!trips) {
129 		pr_err("Failed to find 'trips' node\n");
130 		return ERR_PTR(-EINVAL);
131 	}
132 
133 	count = of_get_child_count(trips);
134 	if (!count) {
135 		pr_err("No trip point defined\n");
136 		ret = -EINVAL;
137 		goto out_of_node_put;
138 	}
139 
140 	tt = kzalloc(sizeof(*tt) * count, GFP_KERNEL);
141 	if (!tt) {
142 		ret = -ENOMEM;
143 		goto out_of_node_put;
144 	}
145 
146 	*ntrips = count;
147 
148 	count = 0;
149 	for_each_child_of_node(trips, trip) {
150 		ret = thermal_of_populate_trip(trip, &tt[count++]);
151 		if (ret)
152 			goto out_kfree;
153 	}
154 
155 	of_node_put(trips);
156 
157 	return tt;
158 
159 out_kfree:
160 	kfree(tt);
161 	*ntrips = 0;
162 out_of_node_put:
163 	of_node_put(trips);
164 
165 	return ERR_PTR(ret);
166 }
167 
168 static struct device_node *of_thermal_zone_find(struct device_node *sensor, int id)
169 {
170 	struct device_node *np, *tz;
171 	struct of_phandle_args sensor_specs;
172 
173 	np = of_find_node_by_name(NULL, "thermal-zones");
174 	if (!np) {
175 		pr_debug("No thermal zones description\n");
176 		return ERR_PTR(-ENODEV);
177 	}
178 
179 	/*
180 	 * Search for each thermal zone, a defined sensor
181 	 * corresponding to the one passed as parameter
182 	 */
183 	for_each_available_child_of_node(np, tz) {
184 
185 		int count, i;
186 
187 		count = of_count_phandle_with_args(tz, "thermal-sensors",
188 						   "#thermal-sensor-cells");
189 		if (count <= 0) {
190 			pr_err("%pOFn: missing thermal sensor\n", tz);
191 			tz = ERR_PTR(-EINVAL);
192 			goto out;
193 		}
194 
195 		for (i = 0; i < count; i++) {
196 
197 			int ret;
198 
199 			ret = of_parse_phandle_with_args(tz, "thermal-sensors",
200 							 "#thermal-sensor-cells",
201 							 i, &sensor_specs);
202 			if (ret < 0) {
203 				pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", tz, ret);
204 				tz = ERR_PTR(ret);
205 				goto out;
206 			}
207 
208 			if ((sensor == sensor_specs.np) && id == (sensor_specs.args_count ?
209 								  sensor_specs.args[0] : 0)) {
210 				pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor, id, tz);
211 				goto out;
212 			}
213 		}
214 	}
215 	tz = ERR_PTR(-ENODEV);
216 out:
217 	of_node_put(np);
218 	return tz;
219 }
220 
221 static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdelay)
222 {
223 	int ret;
224 
225 	ret = of_property_read_u32(np, "polling-delay-passive", pdelay);
226 	if (ret < 0) {
227 		pr_err("%pOFn: missing polling-delay-passive property\n", np);
228 		return ret;
229 	}
230 
231 	ret = of_property_read_u32(np, "polling-delay", delay);
232 	if (ret < 0) {
233 		pr_err("%pOFn: missing polling-delay property\n", np);
234 		return ret;
235 	}
236 
237 	return 0;
238 }
239 
240 static void thermal_of_parameters_init(struct device_node *np,
241 				       struct thermal_zone_params *tzp)
242 {
243 	int coef[2];
244 	int ncoef = ARRAY_SIZE(coef);
245 	int prop, ret;
246 
247 	tzp->no_hwmon = true;
248 
249 	if (!of_property_read_u32(np, "sustainable-power", &prop))
250 		tzp->sustainable_power = prop;
251 
252 	/*
253 	 * For now, the thermal framework supports only one sensor per
254 	 * thermal zone. Thus, we are considering only the first two
255 	 * values as slope and offset.
256 	 */
257 	ret = of_property_read_u32_array(np, "coefficients", coef, ncoef);
258 	if (ret) {
259 		coef[0] = 1;
260 		coef[1] = 0;
261 	}
262 
263 	tzp->slope = coef[0];
264 	tzp->offset = coef[1];
265 }
266 
267 static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_device *tz)
268 {
269 	struct device_node *np, *tz_np;
270 
271 	np = of_find_node_by_name(NULL, "thermal-zones");
272 	if (!np)
273 		return ERR_PTR(-ENODEV);
274 
275 	tz_np = of_get_child_by_name(np, tz->type);
276 
277 	of_node_put(np);
278 
279 	if (!tz_np)
280 		return ERR_PTR(-ENODEV);
281 
282 	return tz_np;
283 }
284 
285 static int __thermal_of_unbind(struct device_node *map_np, int index, int trip_id,
286 			       struct thermal_zone_device *tz, struct thermal_cooling_device *cdev)
287 {
288 	struct of_phandle_args cooling_spec;
289 	int ret;
290 
291 	ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells",
292 					 index, &cooling_spec);
293 
294 	if (ret < 0) {
295 		pr_err("Invalid cooling-device entry\n");
296 		return ret;
297 	}
298 
299 	of_node_put(cooling_spec.np);
300 
301 	if (cooling_spec.args_count < 2) {
302 		pr_err("wrong reference to cooling device, missing limits\n");
303 		return -EINVAL;
304 	}
305 
306 	if (cooling_spec.np != cdev->np)
307 		return 0;
308 
309 	ret = thermal_zone_unbind_cooling_device(tz, trip_id, cdev);
310 	if (ret)
311 		pr_err("Failed to unbind '%s' with '%s': %d\n", tz->type, cdev->type, ret);
312 
313 	return ret;
314 }
315 
316 static int __thermal_of_bind(struct device_node *map_np, int index, int trip_id,
317 			     struct thermal_zone_device *tz, struct thermal_cooling_device *cdev)
318 {
319 	struct of_phandle_args cooling_spec;
320 	int ret, weight = THERMAL_WEIGHT_DEFAULT;
321 
322 	of_property_read_u32(map_np, "contribution", &weight);
323 
324 	ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells",
325 					 index, &cooling_spec);
326 
327 	if (ret < 0) {
328 		pr_err("Invalid cooling-device entry\n");
329 		return ret;
330 	}
331 
332 	of_node_put(cooling_spec.np);
333 
334 	if (cooling_spec.args_count < 2) {
335 		pr_err("wrong reference to cooling device, missing limits\n");
336 		return -EINVAL;
337 	}
338 
339 	if (cooling_spec.np != cdev->np)
340 		return 0;
341 
342 	ret = thermal_zone_bind_cooling_device(tz, trip_id, cdev, cooling_spec.args[1],
343 					       cooling_spec.args[0],
344 					       weight);
345 	if (ret)
346 		pr_err("Failed to bind '%s' with '%s': %d\n", tz->type, cdev->type, ret);
347 
348 	return ret;
349 }
350 
351 static int thermal_of_for_each_cooling_device(struct device_node *tz_np, struct device_node *map_np,
352 					      struct thermal_zone_device *tz, struct thermal_cooling_device *cdev,
353 					      int (*action)(struct device_node *, int, int,
354 							    struct thermal_zone_device *, struct thermal_cooling_device *))
355 {
356 	struct device_node *tr_np;
357 	int count, i, trip_id;
358 
359 	tr_np = of_parse_phandle(map_np, "trip", 0);
360 	if (!tr_np)
361 		return -ENODEV;
362 
363 	trip_id = of_find_trip_id(tz_np, tr_np);
364 	if (trip_id < 0)
365 		return trip_id;
366 
367 	count = of_count_phandle_with_args(map_np, "cooling-device", "#cooling-cells");
368 	if (count <= 0) {
369 		pr_err("Add a cooling_device property with at least one device\n");
370 		return -ENOENT;
371 	}
372 
373 	/*
374 	 * At this point, we don't want to bail out when there is an
375 	 * error, we will try to bind/unbind as many as possible
376 	 * cooling devices
377 	 */
378 	for (i = 0; i < count; i++)
379 		action(map_np, i, trip_id, tz, cdev);
380 
381 	return 0;
382 }
383 
384 static int thermal_of_for_each_cooling_maps(struct thermal_zone_device *tz,
385 					    struct thermal_cooling_device *cdev,
386 					    int (*action)(struct device_node *, int, int,
387 							  struct thermal_zone_device *, struct thermal_cooling_device *))
388 {
389 	struct device_node *tz_np, *cm_np, *child;
390 	int ret = 0;
391 
392 	tz_np = thermal_of_zone_get_by_name(tz);
393 	if (IS_ERR(tz_np)) {
394 		pr_err("Failed to get node tz by name\n");
395 		return PTR_ERR(tz_np);
396 	}
397 
398 	cm_np = of_get_child_by_name(tz_np, "cooling-maps");
399 	if (!cm_np)
400 		goto out;
401 
402 	for_each_child_of_node(cm_np, child) {
403 		ret = thermal_of_for_each_cooling_device(tz_np, child, tz, cdev, action);
404 		if (ret)
405 			break;
406 	}
407 
408 	of_node_put(cm_np);
409 out:
410 	of_node_put(tz_np);
411 
412 	return ret;
413 }
414 
415 static int thermal_of_bind(struct thermal_zone_device *tz,
416 			   struct thermal_cooling_device *cdev)
417 {
418 	return thermal_of_for_each_cooling_maps(tz, cdev, __thermal_of_bind);
419 }
420 
421 static int thermal_of_unbind(struct thermal_zone_device *tz,
422 			     struct thermal_cooling_device *cdev)
423 {
424 	return thermal_of_for_each_cooling_maps(tz, cdev, __thermal_of_unbind);
425 }
426 
427 /**
428  * thermal_of_zone_unregister - Cleanup the specific allocated ressources
429  *
430  * This function disables the thermal zone and frees the different
431  * ressources allocated specific to the thermal OF.
432  *
433  * @tz: a pointer to the thermal zone structure
434  */
435 static void thermal_of_zone_unregister(struct thermal_zone_device *tz)
436 {
437 	struct thermal_trip *trips = tz->trips;
438 	struct thermal_zone_device_ops *ops = tz->ops;
439 
440 	thermal_zone_device_disable(tz);
441 	thermal_zone_device_unregister(tz);
442 	kfree(trips);
443 	kfree(ops);
444 }
445 
446 /**
447  * thermal_of_zone_register - Register a thermal zone with device node
448  * sensor
449  *
450  * The thermal_of_zone_register() parses a device tree given a device
451  * node sensor and identifier. It searches for the thermal zone
452  * associated to the couple sensor/id and retrieves all the thermal
453  * zone properties and registers new thermal zone with those
454  * properties.
455  *
456  * @sensor: A device node pointer corresponding to the sensor in the device tree
457  * @id: An integer as sensor identifier
458  * @data: A private data to be stored in the thermal zone dedicated private area
459  * @ops: A set of thermal sensor ops
460  *
461  * Return: a valid thermal zone structure pointer on success.
462  * 	- EINVAL: if the device tree thermal description is malformed
463  *	- ENOMEM: if one structure can not be allocated
464  *	- Other negative errors are returned by the underlying called functions
465  */
466 static struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor, int id, void *data,
467 							    const struct thermal_zone_device_ops *ops)
468 {
469 	struct thermal_zone_device *tz;
470 	struct thermal_trip *trips;
471 	struct thermal_zone_params tzp = {};
472 	struct thermal_zone_device_ops *of_ops;
473 	struct device_node *np;
474 	int delay, pdelay;
475 	int ntrips, mask;
476 	int ret;
477 
478 	of_ops = kmemdup(ops, sizeof(*ops), GFP_KERNEL);
479 	if (!of_ops)
480 		return ERR_PTR(-ENOMEM);
481 
482 	np = of_thermal_zone_find(sensor, id);
483 	if (IS_ERR(np)) {
484 		if (PTR_ERR(np) != -ENODEV)
485 			pr_err("Failed to find thermal zone for %pOFn id=%d\n", sensor, id);
486 		ret = PTR_ERR(np);
487 		goto out_kfree_of_ops;
488 	}
489 
490 	trips = thermal_of_trips_init(np, &ntrips);
491 	if (IS_ERR(trips)) {
492 		pr_err("Failed to find trip points for %pOFn id=%d\n", sensor, id);
493 		ret = PTR_ERR(trips);
494 		goto out_kfree_of_ops;
495 	}
496 
497 	ret = thermal_of_monitor_init(np, &delay, &pdelay);
498 	if (ret) {
499 		pr_err("Failed to initialize monitoring delays from %pOFn\n", np);
500 		goto out_kfree_trips;
501 	}
502 
503 	thermal_of_parameters_init(np, &tzp);
504 
505 	of_ops->bind = thermal_of_bind;
506 	of_ops->unbind = thermal_of_unbind;
507 
508 	mask = GENMASK_ULL((ntrips) - 1, 0);
509 
510 	tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
511 						     mask, data, of_ops, &tzp,
512 						     pdelay, delay);
513 	if (IS_ERR(tz)) {
514 		ret = PTR_ERR(tz);
515 		pr_err("Failed to register thermal zone %pOFn: %d\n", np, ret);
516 		goto out_kfree_trips;
517 	}
518 
519 	ret = thermal_zone_device_enable(tz);
520 	if (ret) {
521 		pr_err("Failed to enabled thermal zone '%s', id=%d: %d\n",
522 		       tz->type, tz->id, ret);
523 		thermal_of_zone_unregister(tz);
524 		return ERR_PTR(ret);
525 	}
526 
527 	return tz;
528 
529 out_kfree_trips:
530 	kfree(trips);
531 out_kfree_of_ops:
532 	kfree(of_ops);
533 
534 	return ERR_PTR(ret);
535 }
536 
537 static void devm_thermal_of_zone_release(struct device *dev, void *res)
538 {
539 	thermal_of_zone_unregister(*(struct thermal_zone_device **)res);
540 }
541 
542 static int devm_thermal_of_zone_match(struct device *dev, void *res,
543 				      void *data)
544 {
545 	struct thermal_zone_device **r = res;
546 
547 	if (WARN_ON(!r || !*r))
548 		return 0;
549 
550 	return *r == data;
551 }
552 
553 /**
554  * devm_thermal_of_zone_register - register a thermal tied with the sensor life cycle
555  *
556  * This function is the device version of the thermal_of_zone_register() function.
557  *
558  * @dev: a device structure pointer to sensor to be tied with the thermal zone OF life cycle
559  * @sensor_id: the sensor identifier
560  * @data: a pointer to a private data to be stored in the thermal zone 'devdata' field
561  * @ops: a pointer to the ops structure associated with the sensor
562  */
563 struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, int sensor_id, void *data,
564 							  const struct thermal_zone_device_ops *ops)
565 {
566 	struct thermal_zone_device **ptr, *tzd;
567 
568 	ptr = devres_alloc(devm_thermal_of_zone_release, sizeof(*ptr),
569 			   GFP_KERNEL);
570 	if (!ptr)
571 		return ERR_PTR(-ENOMEM);
572 
573 	tzd = thermal_of_zone_register(dev->of_node, sensor_id, data, ops);
574 	if (IS_ERR(tzd)) {
575 		devres_free(ptr);
576 		return tzd;
577 	}
578 
579 	*ptr = tzd;
580 	devres_add(dev, ptr);
581 
582 	return tzd;
583 }
584 EXPORT_SYMBOL_GPL(devm_thermal_of_zone_register);
585 
586 /**
587  * devm_thermal_of_zone_unregister - Resource managed version of
588  *				thermal_of_zone_unregister().
589  * @dev: Device for which which resource was allocated.
590  * @tz: a pointer to struct thermal_zone where the sensor is registered.
591  *
592  * This function removes the sensor callbacks and private data from the
593  * thermal zone device registered with devm_thermal_zone_of_sensor_register()
594  * API. It will also silent the zone by remove the .get_temp() and .get_trend()
595  * thermal zone device callbacks.
596  * Normally this function will not need to be called and the resource
597  * management code will ensure that the resource is freed.
598  */
599 void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_device *tz)
600 {
601 	WARN_ON(devres_release(dev, devm_thermal_of_zone_release,
602 			       devm_thermal_of_zone_match, tz));
603 }
604 EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister);
605