thermal: core: introduce thermal_of_cooling_device_register
[linux-3.10.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->min,
160                                                 tbp->max);
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                 /* 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 }
432 EXPORT_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  */
449 void 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 }
472 EXPORT_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  */
490 static 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
538 end:
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  */
548 static 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  */
565 static 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  */
594 static 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  */
640 static struct __thermal_zone *
641 thermal_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
721 finish:
722         of_node_put(child);
723         tz->mode = THERMAL_DEVICE_DISABLED;
724
725         return tz;
726
727 free_tbps:
728         kfree(tz->tbps);
729 free_trips:
730         kfree(tz->trips);
731 free_tz:
732         kfree(tz);
733         of_node_put(child);
734
735         return ERR_PTR(ret);
736 }
737
738 static 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  */
757 int __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
811 exit_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  */
827 void 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 }