Merge tag 'renesas-cleanup-for-v3.19' of git://git.kernel.org/pub/scm/linux/kernel...
[cascardo/linux.git] / drivers / thermal / of-thermal.c
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
46 struct __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
62 struct __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
84 struct __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
105 static 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
116 static 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
141 static 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->max,
160                                                 tbp->min);
161                         if (ret)
162                                 return ret;
163                 }
164         }
165
166         return 0;
167 }
168
169 static 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
195 static 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
205 static 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
225 static 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
238 static 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
251 static 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
265 static 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
278 static 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
292 static 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
307 static 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
324 static struct thermal_zone_device *
325 thermal_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  */
384 struct thermal_zone_device *
385 thermal_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                 /* Check whether child is enabled or not */
405                 if (!of_device_is_available(child))
406                         continue;
407
408                 /* For now, thermal framework supports only 1 sensor per zone */
409                 ret = of_parse_phandle_with_args(child, "thermal-sensors",
410                                                  "#thermal-sensor-cells",
411                                                  0, &sensor_specs);
412                 if (ret)
413                         continue;
414
415                 if (sensor_specs.args_count >= 1) {
416                         id = sensor_specs.args[0];
417                         WARN(sensor_specs.args_count > 1,
418                              "%s: too many cells in sensor specifier %d\n",
419                              sensor_specs.np->name, sensor_specs.args_count);
420                 } else {
421                         id = 0;
422                 }
423
424                 if (sensor_specs.np == sensor_np && id == sensor_id) {
425                         of_node_put(np);
426                         return thermal_zone_of_add_sensor(child, sensor_np,
427                                                           data,
428                                                           get_temp,
429                                                           get_trend);
430                 }
431         }
432         of_node_put(np);
433
434         return ERR_PTR(-ENODEV);
435 }
436 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register);
437
438 /**
439  * thermal_zone_of_sensor_unregister - unregisters a sensor from a DT thermal zone
440  * @dev: a valid struct device pointer of a sensor device. Must contain
441  *       a valid .of_node, for the sensor node.
442  * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
443  *
444  * This function removes the sensor callbacks and private data from the
445  * thermal zone device registered with thermal_zone_of_sensor_register()
446  * API. It will also silent the zone by remove the .get_temp() and .get_trend()
447  * thermal zone device callbacks.
448  *
449  * TODO: When the support to several sensors per zone is added, this
450  * function must search the sensor list based on @dev parameter.
451  *
452  */
453 void thermal_zone_of_sensor_unregister(struct device *dev,
454                                        struct thermal_zone_device *tzd)
455 {
456         struct __thermal_zone *tz;
457
458         if (!dev || !tzd || !tzd->devdata)
459                 return;
460
461         tz = tzd->devdata;
462
463         /* no __thermal_zone, nothing to be done */
464         if (!tz)
465                 return;
466
467         mutex_lock(&tzd->lock);
468         tzd->ops->get_temp = NULL;
469         tzd->ops->get_trend = NULL;
470
471         tz->get_temp = NULL;
472         tz->get_trend = NULL;
473         tz->sensor_data = NULL;
474         mutex_unlock(&tzd->lock);
475 }
476 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
477
478 /***   functions parsing device tree nodes   ***/
479
480 /**
481  * thermal_of_populate_bind_params - parse and fill cooling map data
482  * @np: DT node containing a cooling-map node
483  * @__tbp: data structure to be filled with cooling map info
484  * @trips: array of thermal zone trip points
485  * @ntrips: number of trip points inside trips.
486  *
487  * This function parses a cooling-map type of node represented by
488  * @np parameter and fills the read data into @__tbp data structure.
489  * It needs the already parsed array of trip points of the thermal zone
490  * in consideration.
491  *
492  * Return: 0 on success, proper error code otherwise
493  */
494 static int thermal_of_populate_bind_params(struct device_node *np,
495                                            struct __thermal_bind_params *__tbp,
496                                            struct __thermal_trip *trips,
497                                            int ntrips)
498 {
499         struct of_phandle_args cooling_spec;
500         struct device_node *trip;
501         int ret, i;
502         u32 prop;
503
504         /* Default weight. Usage is optional */
505         __tbp->usage = 0;
506         ret = of_property_read_u32(np, "contribution", &prop);
507         if (ret == 0)
508                 __tbp->usage = prop;
509
510         trip = of_parse_phandle(np, "trip", 0);
511         if (!trip) {
512                 pr_err("missing trip property\n");
513                 return -ENODEV;
514         }
515
516         /* match using device_node */
517         for (i = 0; i < ntrips; i++)
518                 if (trip == trips[i].np) {
519                         __tbp->trip_id = i;
520                         break;
521                 }
522
523         if (i == ntrips) {
524                 ret = -ENODEV;
525                 goto end;
526         }
527
528         ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells",
529                                          0, &cooling_spec);
530         if (ret < 0) {
531                 pr_err("missing cooling_device property\n");
532                 goto end;
533         }
534         __tbp->cooling_device = cooling_spec.np;
535         if (cooling_spec.args_count >= 2) { /* at least min and max */
536                 __tbp->min = cooling_spec.args[0];
537                 __tbp->max = cooling_spec.args[1];
538         } else {
539                 pr_err("wrong reference to cooling device, missing limits\n");
540         }
541
542 end:
543         of_node_put(trip);
544
545         return ret;
546 }
547
548 /**
549  * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
550  * into the device tree binding of 'trip', property type.
551  */
552 static const char * const trip_types[] = {
553         [THERMAL_TRIP_ACTIVE]   = "active",
554         [THERMAL_TRIP_PASSIVE]  = "passive",
555         [THERMAL_TRIP_HOT]      = "hot",
556         [THERMAL_TRIP_CRITICAL] = "critical",
557 };
558
559 /**
560  * thermal_of_get_trip_type - Get phy mode for given device_node
561  * @np: Pointer to the given device_node
562  * @type: Pointer to resulting trip type
563  *
564  * The function gets trip type string from property 'type',
565  * and store its index in trip_types table in @type,
566  *
567  * Return: 0 on success, or errno in error case.
568  */
569 static int thermal_of_get_trip_type(struct device_node *np,
570                                     enum thermal_trip_type *type)
571 {
572         const char *t;
573         int err, i;
574
575         err = of_property_read_string(np, "type", &t);
576         if (err < 0)
577                 return err;
578
579         for (i = 0; i < ARRAY_SIZE(trip_types); i++)
580                 if (!strcasecmp(t, trip_types[i])) {
581                         *type = i;
582                         return 0;
583                 }
584
585         return -ENODEV;
586 }
587
588 /**
589  * thermal_of_populate_trip - parse and fill one trip point data
590  * @np: DT node containing a trip point node
591  * @trip: trip point data structure to be filled up
592  *
593  * This function parses a trip point type of node represented by
594  * @np parameter and fills the read data into @trip data structure.
595  *
596  * Return: 0 on success, proper error code otherwise
597  */
598 static int thermal_of_populate_trip(struct device_node *np,
599                                     struct __thermal_trip *trip)
600 {
601         int prop;
602         int ret;
603
604         ret = of_property_read_u32(np, "temperature", &prop);
605         if (ret < 0) {
606                 pr_err("missing temperature property\n");
607                 return ret;
608         }
609         trip->temperature = prop;
610
611         ret = of_property_read_u32(np, "hysteresis", &prop);
612         if (ret < 0) {
613                 pr_err("missing hysteresis property\n");
614                 return ret;
615         }
616         trip->hysteresis = prop;
617
618         ret = thermal_of_get_trip_type(np, &trip->type);
619         if (ret < 0) {
620                 pr_err("wrong trip type property\n");
621                 return ret;
622         }
623
624         /* Required for cooling map matching */
625         trip->np = np;
626
627         return 0;
628 }
629
630 /**
631  * thermal_of_build_thermal_zone - parse and fill one thermal zone data
632  * @np: DT node containing a thermal zone node
633  *
634  * This function parses a thermal zone type of node represented by
635  * @np parameter and fills the read data into a __thermal_zone data structure
636  * and return this pointer.
637  *
638  * TODO: Missing properties to parse: thermal-sensor-names and coefficients
639  *
640  * Return: On success returns a valid struct __thermal_zone,
641  * otherwise, it returns a corresponding ERR_PTR(). Caller must
642  * check the return value with help of IS_ERR() helper.
643  */
644 static struct __thermal_zone *
645 thermal_of_build_thermal_zone(struct device_node *np)
646 {
647         struct device_node *child = NULL, *gchild;
648         struct __thermal_zone *tz;
649         int ret, i;
650         u32 prop;
651
652         if (!np) {
653                 pr_err("no thermal zone np\n");
654                 return ERR_PTR(-EINVAL);
655         }
656
657         tz = kzalloc(sizeof(*tz), GFP_KERNEL);
658         if (!tz)
659                 return ERR_PTR(-ENOMEM);
660
661         ret = of_property_read_u32(np, "polling-delay-passive", &prop);
662         if (ret < 0) {
663                 pr_err("missing polling-delay-passive property\n");
664                 goto free_tz;
665         }
666         tz->passive_delay = prop;
667
668         ret = of_property_read_u32(np, "polling-delay", &prop);
669         if (ret < 0) {
670                 pr_err("missing polling-delay property\n");
671                 goto free_tz;
672         }
673         tz->polling_delay = prop;
674
675         /* trips */
676         child = of_get_child_by_name(np, "trips");
677
678         /* No trips provided */
679         if (!child)
680                 goto finish;
681
682         tz->ntrips = of_get_child_count(child);
683         if (tz->ntrips == 0) /* must have at least one child */
684                 goto finish;
685
686         tz->trips = kzalloc(tz->ntrips * sizeof(*tz->trips), GFP_KERNEL);
687         if (!tz->trips) {
688                 ret = -ENOMEM;
689                 goto free_tz;
690         }
691
692         i = 0;
693         for_each_child_of_node(child, gchild) {
694                 ret = thermal_of_populate_trip(gchild, &tz->trips[i++]);
695                 if (ret)
696                         goto free_trips;
697         }
698
699         of_node_put(child);
700
701         /* cooling-maps */
702         child = of_get_child_by_name(np, "cooling-maps");
703
704         /* cooling-maps not provided */
705         if (!child)
706                 goto finish;
707
708         tz->num_tbps = of_get_child_count(child);
709         if (tz->num_tbps == 0)
710                 goto finish;
711
712         tz->tbps = kzalloc(tz->num_tbps * sizeof(*tz->tbps), GFP_KERNEL);
713         if (!tz->tbps) {
714                 ret = -ENOMEM;
715                 goto free_trips;
716         }
717
718         i = 0;
719         for_each_child_of_node(child, gchild) {
720                 ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++],
721                                                       tz->trips, tz->ntrips);
722                 if (ret)
723                         goto free_tbps;
724         }
725
726 finish:
727         of_node_put(child);
728         tz->mode = THERMAL_DEVICE_DISABLED;
729
730         return tz;
731
732 free_tbps:
733         kfree(tz->tbps);
734 free_trips:
735         kfree(tz->trips);
736 free_tz:
737         kfree(tz);
738         of_node_put(child);
739
740         return ERR_PTR(ret);
741 }
742
743 static inline void of_thermal_free_zone(struct __thermal_zone *tz)
744 {
745         kfree(tz->tbps);
746         kfree(tz->trips);
747         kfree(tz);
748 }
749
750 /**
751  * of_parse_thermal_zones - parse device tree thermal data
752  *
753  * Initialization function that can be called by machine initialization
754  * code to parse thermal data and populate the thermal framework
755  * with hardware thermal zones info. This function only parses thermal zones.
756  * Cooling devices and sensor devices nodes are supposed to be parsed
757  * by their respective drivers.
758  *
759  * Return: 0 on success, proper error code otherwise
760  *
761  */
762 int __init of_parse_thermal_zones(void)
763 {
764         struct device_node *np, *child;
765         struct __thermal_zone *tz;
766         struct thermal_zone_device_ops *ops;
767
768         np = of_find_node_by_name(NULL, "thermal-zones");
769         if (!np) {
770                 pr_debug("unable to find thermal zones\n");
771                 return 0; /* Run successfully on systems without thermal DT */
772         }
773
774         for_each_child_of_node(np, child) {
775                 struct thermal_zone_device *zone;
776                 struct thermal_zone_params *tzp;
777
778                 /* Check whether child is enabled or not */
779                 if (!of_device_is_available(child))
780                         continue;
781
782                 tz = thermal_of_build_thermal_zone(child);
783                 if (IS_ERR(tz)) {
784                         pr_err("failed to build thermal zone %s: %ld\n",
785                                child->name,
786                                PTR_ERR(tz));
787                         continue;
788                 }
789
790                 ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);
791                 if (!ops)
792                         goto exit_free;
793
794                 tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
795                 if (!tzp) {
796                         kfree(ops);
797                         goto exit_free;
798                 }
799
800                 /* No hwmon because there might be hwmon drivers registering */
801                 tzp->no_hwmon = true;
802
803                 zone = thermal_zone_device_register(child->name, tz->ntrips,
804                                                     0, tz,
805                                                     ops, tzp,
806                                                     tz->passive_delay,
807                                                     tz->polling_delay);
808                 if (IS_ERR(zone)) {
809                         pr_err("Failed to build %s zone %ld\n", child->name,
810                                PTR_ERR(zone));
811                         kfree(tzp);
812                         kfree(ops);
813                         of_thermal_free_zone(tz);
814                         /* attempting to build remaining zones still */
815                 }
816         }
817
818         return 0;
819
820 exit_free:
821         of_thermal_free_zone(tz);
822
823         /* no memory available, so free what we have built */
824         of_thermal_destroy_zones();
825
826         return -ENOMEM;
827 }
828
829 /**
830  * of_thermal_destroy_zones - remove all zones parsed and allocated resources
831  *
832  * Finds all zones parsed and added to the thermal framework and remove them
833  * from the system, together with their resources.
834  *
835  */
836 void of_thermal_destroy_zones(void)
837 {
838         struct device_node *np, *child;
839
840         np = of_find_node_by_name(NULL, "thermal-zones");
841         if (!np) {
842                 pr_err("unable to find thermal zones\n");
843                 return;
844         }
845
846         for_each_child_of_node(np, child) {
847                 struct thermal_zone_device *zone;
848
849                 /* Check whether child is enabled or not */
850                 if (!of_device_is_available(child))
851                         continue;
852
853                 zone = thermal_zone_get_zone_by_name(child->name);
854                 if (IS_ERR(zone))
855                         continue;
856
857                 thermal_zone_device_unregister(zone);
858                 kfree(zone->tzp);
859                 kfree(zone->ops);
860                 of_thermal_free_zone(zone->devdata);
861         }
862 }