]> Git Repo - linux.git/blob - drivers/thermal/thermal_of.c
crypto: akcipher - Drop sign/verify operations
[linux.git] / drivers / thermal / thermal_of.c
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 <[email protected]>
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 /*
24  * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
25  * into the device tree binding of 'trip', property type.
26  */
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",
32 };
33
34 /**
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
38  *
39  * The function gets trip type string from property 'type',
40  * and store its index in trip_types table in @type,
41  *
42  * Return: 0 on success, or errno in error case.
43  */
44 static int thermal_of_get_trip_type(struct device_node *np,
45                                     enum thermal_trip_type *type)
46 {
47         const char *t;
48         int err, i;
49
50         err = of_property_read_string(np, "type", &t);
51         if (err < 0)
52                 return err;
53
54         for (i = 0; i < ARRAY_SIZE(trip_types); i++)
55                 if (!strcasecmp(t, trip_types[i])) {
56                         *type = i;
57                         return 0;
58                 }
59
60         return -ENODEV;
61 }
62
63 static int thermal_of_populate_trip(struct device_node *np,
64                                     struct thermal_trip *trip)
65 {
66         int prop;
67         int ret;
68
69         ret = of_property_read_u32(np, "temperature", &prop);
70         if (ret < 0) {
71                 pr_err("missing temperature property\n");
72                 return ret;
73         }
74         trip->temperature = prop;
75
76         ret = of_property_read_u32(np, "hysteresis", &prop);
77         if (ret < 0) {
78                 pr_err("missing hysteresis property\n");
79                 return ret;
80         }
81         trip->hysteresis = prop;
82
83         ret = thermal_of_get_trip_type(np, &trip->type);
84         if (ret < 0) {
85                 pr_err("wrong trip type property\n");
86                 return ret;
87         }
88
89         trip->flags = THERMAL_TRIP_FLAG_RW_TEMP;
90
91         trip->priv = np;
92
93         return 0;
94 }
95
96 static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *ntrips)
97 {
98         struct thermal_trip *tt;
99         struct device_node *trips;
100         int ret, count;
101
102         trips = of_get_child_by_name(np, "trips");
103         if (!trips) {
104                 pr_err("Failed to find 'trips' node\n");
105                 return ERR_PTR(-EINVAL);
106         }
107
108         count = of_get_child_count(trips);
109         if (!count) {
110                 pr_err("No trip point defined\n");
111                 ret = -EINVAL;
112                 goto out_of_node_put;
113         }
114
115         tt = kzalloc(sizeof(*tt) * count, GFP_KERNEL);
116         if (!tt) {
117                 ret = -ENOMEM;
118                 goto out_of_node_put;
119         }
120
121         *ntrips = count;
122
123         count = 0;
124         for_each_child_of_node_scoped(trips, trip) {
125                 ret = thermal_of_populate_trip(trip, &tt[count++]);
126                 if (ret)
127                         goto out_kfree;
128         }
129
130         of_node_put(trips);
131
132         return tt;
133
134 out_kfree:
135         kfree(tt);
136         *ntrips = 0;
137 out_of_node_put:
138         of_node_put(trips);
139
140         return ERR_PTR(ret);
141 }
142
143 static struct device_node *of_thermal_zone_find(struct device_node *sensor, int id)
144 {
145         struct device_node *np, *tz;
146         struct of_phandle_args sensor_specs;
147
148         np = of_find_node_by_name(NULL, "thermal-zones");
149         if (!np) {
150                 pr_debug("No thermal zones description\n");
151                 return ERR_PTR(-ENODEV);
152         }
153
154         /*
155          * Search for each thermal zone, a defined sensor
156          * corresponding to the one passed as parameter
157          */
158         for_each_available_child_of_node_scoped(np, child) {
159
160                 int count, i;
161
162                 count = of_count_phandle_with_args(child, "thermal-sensors",
163                                                    "#thermal-sensor-cells");
164                 if (count <= 0) {
165                         pr_err("%pOFn: missing thermal sensor\n", child);
166                         tz = ERR_PTR(-EINVAL);
167                         goto out;
168                 }
169
170                 for (i = 0; i < count; i++) {
171
172                         int ret;
173
174                         ret = of_parse_phandle_with_args(child, "thermal-sensors",
175                                                          "#thermal-sensor-cells",
176                                                          i, &sensor_specs);
177                         if (ret < 0) {
178                                 pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", child, ret);
179                                 tz = ERR_PTR(ret);
180                                 goto out;
181                         }
182
183                         if ((sensor == sensor_specs.np) && id == (sensor_specs.args_count ?
184                                                                   sensor_specs.args[0] : 0)) {
185                                 pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor, id, child);
186                                 tz = no_free_ptr(child);
187                                 goto out;
188                         }
189                 }
190         }
191         tz = ERR_PTR(-ENODEV);
192 out:
193         of_node_put(np);
194         return tz;
195 }
196
197 static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdelay)
198 {
199         int ret;
200
201         ret = of_property_read_u32(np, "polling-delay-passive", pdelay);
202         if (ret == -EINVAL) {
203                 *pdelay = 0;
204         } else if (ret < 0) {
205                 pr_err("%pOFn: Couldn't get polling-delay-passive: %d\n", np, ret);
206                 return ret;
207         }
208
209         ret = of_property_read_u32(np, "polling-delay", delay);
210         if (ret == -EINVAL) {
211                 *delay = 0;
212         } else if (ret < 0) {
213                 pr_err("%pOFn: Couldn't get polling-delay: %d\n", np, ret);
214                 return ret;
215         }
216
217         return 0;
218 }
219
220 static void thermal_of_parameters_init(struct device_node *np,
221                                        struct thermal_zone_params *tzp)
222 {
223         int coef[2];
224         int ncoef = ARRAY_SIZE(coef);
225         int prop, ret;
226
227         tzp->no_hwmon = true;
228
229         if (!of_property_read_u32(np, "sustainable-power", &prop))
230                 tzp->sustainable_power = prop;
231
232         /*
233          * For now, the thermal framework supports only one sensor per
234          * thermal zone. Thus, we are considering only the first two
235          * values as slope and offset.
236          */
237         ret = of_property_read_u32_array(np, "coefficients", coef, ncoef);
238         if (ret) {
239                 coef[0] = 1;
240                 coef[1] = 0;
241         }
242
243         tzp->slope = coef[0];
244         tzp->offset = coef[1];
245 }
246
247 static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_device *tz)
248 {
249         struct device_node *np, *tz_np;
250
251         np = of_find_node_by_name(NULL, "thermal-zones");
252         if (!np)
253                 return ERR_PTR(-ENODEV);
254
255         tz_np = of_get_child_by_name(np, tz->type);
256
257         of_node_put(np);
258
259         if (!tz_np)
260                 return ERR_PTR(-ENODEV);
261
262         return tz_np;
263 }
264
265 static bool thermal_of_get_cooling_spec(struct device_node *map_np, int index,
266                                         struct thermal_cooling_device *cdev,
267                                         struct cooling_spec *c)
268 {
269         struct of_phandle_args cooling_spec;
270         int ret, weight = THERMAL_WEIGHT_DEFAULT;
271
272         of_property_read_u32(map_np, "contribution", &weight);
273
274         ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells",
275                                          index, &cooling_spec);
276
277         if (ret < 0) {
278                 pr_err("Invalid cooling-device entry\n");
279                 return false;
280         }
281
282         of_node_put(cooling_spec.np);
283
284         if (cooling_spec.args_count < 2) {
285                 pr_err("wrong reference to cooling device, missing limits\n");
286                 return false;
287         }
288
289         if (cooling_spec.np != cdev->np)
290                 return false;
291
292         c->lower = cooling_spec.args[0];
293         c->upper = cooling_spec.args[1];
294         c->weight = weight;
295
296         return true;
297 }
298
299 static bool thermal_of_should_bind(struct thermal_zone_device *tz,
300                                    const struct thermal_trip *trip,
301                                    struct thermal_cooling_device *cdev,
302                                    struct cooling_spec *c)
303 {
304         struct device_node *tz_np, *cm_np, *child;
305         bool result = false;
306
307         tz_np = thermal_of_zone_get_by_name(tz);
308         if (IS_ERR(tz_np)) {
309                 pr_err("Failed to get node tz by name\n");
310                 return false;
311         }
312
313         cm_np = of_get_child_by_name(tz_np, "cooling-maps");
314         if (!cm_np)
315                 goto out;
316
317         /* Look up the trip and the cdev in the cooling maps. */
318         for_each_child_of_node(cm_np, child) {
319                 struct device_node *tr_np;
320                 int count, i;
321
322                 tr_np = of_parse_phandle(child, "trip", 0);
323                 if (tr_np != trip->priv)
324                         continue;
325
326                 /* The trip has been found, look up the cdev. */
327                 count = of_count_phandle_with_args(child, "cooling-device", "#cooling-cells");
328                 if (count <= 0)
329                         pr_err("Add a cooling_device property with at least one device\n");
330
331                 for (i = 0; i < count; i++) {
332                         result = thermal_of_get_cooling_spec(child, i, cdev, c);
333                         if (result)
334                                 break;
335                 }
336
337                 of_node_put(child);
338                 break;
339         }
340
341         of_node_put(cm_np);
342 out:
343         of_node_put(tz_np);
344
345         return result;
346 }
347
348 /**
349  * thermal_of_zone_unregister - Cleanup the specific allocated ressources
350  *
351  * This function disables the thermal zone and frees the different
352  * ressources allocated specific to the thermal OF.
353  *
354  * @tz: a pointer to the thermal zone structure
355  */
356 static void thermal_of_zone_unregister(struct thermal_zone_device *tz)
357 {
358         thermal_zone_device_disable(tz);
359         thermal_zone_device_unregister(tz);
360 }
361
362 /**
363  * thermal_of_zone_register - Register a thermal zone with device node
364  * sensor
365  *
366  * The thermal_of_zone_register() parses a device tree given a device
367  * node sensor and identifier. It searches for the thermal zone
368  * associated to the couple sensor/id and retrieves all the thermal
369  * zone properties and registers new thermal zone with those
370  * properties.
371  *
372  * @sensor: A device node pointer corresponding to the sensor in the device tree
373  * @id: An integer as sensor identifier
374  * @data: A private data to be stored in the thermal zone dedicated private area
375  * @ops: A set of thermal sensor ops
376  *
377  * Return: a valid thermal zone structure pointer on success.
378  *      - EINVAL: if the device tree thermal description is malformed
379  *      - ENOMEM: if one structure can not be allocated
380  *      - Other negative errors are returned by the underlying called functions
381  */
382 static struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor, int id, void *data,
383                                                             const struct thermal_zone_device_ops *ops)
384 {
385         struct thermal_zone_device_ops of_ops = *ops;
386         struct thermal_zone_device *tz;
387         struct thermal_trip *trips;
388         struct thermal_zone_params tzp = {};
389         struct device_node *np;
390         const char *action;
391         int delay, pdelay;
392         int ntrips;
393         int ret;
394
395         np = of_thermal_zone_find(sensor, id);
396         if (IS_ERR(np)) {
397                 if (PTR_ERR(np) != -ENODEV)
398                         pr_err("Failed to find thermal zone for %pOFn id=%d\n", sensor, id);
399                 return ERR_CAST(np);
400         }
401
402         trips = thermal_of_trips_init(np, &ntrips);
403         if (IS_ERR(trips)) {
404                 pr_err("Failed to find trip points for %pOFn id=%d\n", sensor, id);
405                 ret = PTR_ERR(trips);
406                 goto out_of_node_put;
407         }
408
409         ret = thermal_of_monitor_init(np, &delay, &pdelay);
410         if (ret) {
411                 pr_err("Failed to initialize monitoring delays from %pOFn\n", np);
412                 goto out_kfree_trips;
413         }
414
415         thermal_of_parameters_init(np, &tzp);
416
417         of_ops.should_bind = thermal_of_should_bind;
418
419         ret = of_property_read_string(np, "critical-action", &action);
420         if (!ret)
421                 if (!of_ops.critical && !strcasecmp(action, "reboot"))
422                         of_ops.critical = thermal_zone_device_critical_reboot;
423
424         tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
425                                                      data, &of_ops, &tzp,
426                                                      pdelay, delay);
427         if (IS_ERR(tz)) {
428                 ret = PTR_ERR(tz);
429                 pr_err("Failed to register thermal zone %pOFn: %d\n", np, ret);
430                 goto out_kfree_trips;
431         }
432
433         of_node_put(np);
434         kfree(trips);
435
436         ret = thermal_zone_device_enable(tz);
437         if (ret) {
438                 pr_err("Failed to enabled thermal zone '%s', id=%d: %d\n",
439                        tz->type, tz->id, ret);
440                 thermal_of_zone_unregister(tz);
441                 return ERR_PTR(ret);
442         }
443
444         return tz;
445
446 out_kfree_trips:
447         kfree(trips);
448 out_of_node_put:
449         of_node_put(np);
450
451         return ERR_PTR(ret);
452 }
453
454 static void devm_thermal_of_zone_release(struct device *dev, void *res)
455 {
456         thermal_of_zone_unregister(*(struct thermal_zone_device **)res);
457 }
458
459 static int devm_thermal_of_zone_match(struct device *dev, void *res,
460                                       void *data)
461 {
462         struct thermal_zone_device **r = res;
463
464         if (WARN_ON(!r || !*r))
465                 return 0;
466
467         return *r == data;
468 }
469
470 /**
471  * devm_thermal_of_zone_register - register a thermal tied with the sensor life cycle
472  *
473  * This function is the device version of the thermal_of_zone_register() function.
474  *
475  * @dev: a device structure pointer to sensor to be tied with the thermal zone OF life cycle
476  * @sensor_id: the sensor identifier
477  * @data: a pointer to a private data to be stored in the thermal zone 'devdata' field
478  * @ops: a pointer to the ops structure associated with the sensor
479  */
480 struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, int sensor_id, void *data,
481                                                           const struct thermal_zone_device_ops *ops)
482 {
483         struct thermal_zone_device **ptr, *tzd;
484
485         ptr = devres_alloc(devm_thermal_of_zone_release, sizeof(*ptr),
486                            GFP_KERNEL);
487         if (!ptr)
488                 return ERR_PTR(-ENOMEM);
489
490         tzd = thermal_of_zone_register(dev->of_node, sensor_id, data, ops);
491         if (IS_ERR(tzd)) {
492                 devres_free(ptr);
493                 return tzd;
494         }
495
496         *ptr = tzd;
497         devres_add(dev, ptr);
498
499         return tzd;
500 }
501 EXPORT_SYMBOL_GPL(devm_thermal_of_zone_register);
502
503 /**
504  * devm_thermal_of_zone_unregister - Resource managed version of
505  *                              thermal_of_zone_unregister().
506  * @dev: Device for which which resource was allocated.
507  * @tz: a pointer to struct thermal_zone where the sensor is registered.
508  *
509  * This function removes the sensor callbacks and private data from the
510  * thermal zone device registered with devm_thermal_zone_of_sensor_register()
511  * API. It will also silent the zone by remove the .get_temp() and .get_trend()
512  * thermal zone device callbacks.
513  * Normally this function will not need to be called and the resource
514  * management code will ensure that the resource is freed.
515  */
516 void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_device *tz)
517 {
518         WARN_ON(devres_release(dev, devm_thermal_of_zone_release,
519                                devm_thermal_of_zone_match, tz));
520 }
521 EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister);
This page took 0.061224 seconds and 4 git commands to generate.