]> Git Repo - linux.git/blob - drivers/thermal/thermal_of.c
Merge tag 'audit-pr-20221003' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoor...
[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_device.h>
14 #include <linux/of_platform.h>
15 #include <linux/slab.h>
16 #include <linux/thermal.h>
17 #include <linux/types.h>
18 #include <linux/string.h>
19
20 #include "thermal_core.h"
21
22 /**
23  * of_thermal_get_ntrips - function to export number of available trip
24  *                         points.
25  * @tz: pointer to a thermal zone
26  *
27  * This function is a globally visible wrapper to get number of trip points
28  * stored in the local struct __thermal_zone
29  *
30  * Return: number of available trip points, -ENODEV when data not available
31  */
32 int of_thermal_get_ntrips(struct thermal_zone_device *tz)
33 {
34         return tz->num_trips;
35 }
36 EXPORT_SYMBOL_GPL(of_thermal_get_ntrips);
37
38 /**
39  * of_thermal_is_trip_valid - function to check if trip point is valid
40  *
41  * @tz: pointer to a thermal zone
42  * @trip:       trip point to evaluate
43  *
44  * This function is responsible for checking if passed trip point is valid
45  *
46  * Return: true if trip point is valid, false otherwise
47  */
48 bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, int trip)
49 {
50         if (trip >= tz->num_trips || trip < 0)
51                 return false;
52
53         return true;
54 }
55 EXPORT_SYMBOL_GPL(of_thermal_is_trip_valid);
56
57 /**
58  * of_thermal_get_trip_points - function to get access to a globally exported
59  *                              trip points
60  *
61  * @tz: pointer to a thermal zone
62  *
63  * This function provides a pointer to trip points table
64  *
65  * Return: pointer to trip points table, NULL otherwise
66  */
67 const struct thermal_trip *
68 of_thermal_get_trip_points(struct thermal_zone_device *tz)
69 {
70         return tz->trips;
71 }
72 EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
73
74 static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
75                                     enum thermal_trip_type *type)
76 {
77         if (trip >= tz->num_trips || trip < 0)
78                 return -EDOM;
79
80         *type = tz->trips[trip].type;
81
82         return 0;
83 }
84
85 static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
86                                     int *temp)
87 {
88         if (trip >= tz->num_trips || trip < 0)
89                 return -EDOM;
90
91         *temp = tz->trips[trip].temperature;
92
93         return 0;
94 }
95
96 static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
97                                     int *hyst)
98 {
99         if (trip >= tz->num_trips || trip < 0)
100                 return -EDOM;
101
102         *hyst = tz->trips[trip].hysteresis;
103
104         return 0;
105 }
106
107 static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
108                                     int hyst)
109 {
110         if (trip >= tz->num_trips || trip < 0)
111                 return -EDOM;
112
113         /* thermal framework should take care of data->mask & (1 << trip) */
114         tz->trips[trip].hysteresis = hyst;
115
116         return 0;
117 }
118
119 static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
120                                     int *temp)
121 {
122         int i;
123
124         for (i = 0; i < tz->num_trips; i++)
125                 if (tz->trips[i].type == THERMAL_TRIP_CRITICAL) {
126                         *temp = tz->trips[i].temperature;
127                         return 0;
128                 }
129
130         return -EINVAL;
131 }
132
133 /**
134  * thermal_zone_of_get_sensor_id - get sensor ID from a DT thermal zone
135  * @tz_np: a valid thermal zone device node.
136  * @sensor_np: a sensor node of a valid sensor device.
137  * @id: the sensor ID returned if success.
138  *
139  * This function will get sensor ID from a given thermal zone node and
140  * the sensor node must match the temperature provider @sensor_np.
141  *
142  * Return: 0 on success, proper error code otherwise.
143  */
144
145 int thermal_zone_of_get_sensor_id(struct device_node *tz_np,
146                                   struct device_node *sensor_np,
147                                   u32 *id)
148 {
149         struct of_phandle_args sensor_specs;
150         int ret;
151
152         ret = of_parse_phandle_with_args(tz_np,
153                                          "thermal-sensors",
154                                          "#thermal-sensor-cells",
155                                          0,
156                                          &sensor_specs);
157         if (ret)
158                 return ret;
159
160         if (sensor_specs.np != sensor_np) {
161                 of_node_put(sensor_specs.np);
162                 return -ENODEV;
163         }
164
165         if (sensor_specs.args_count > 1)
166                 pr_warn("%pOFn: too many cells in sensor specifier %d\n",
167                      sensor_specs.np, sensor_specs.args_count);
168
169         *id = sensor_specs.args_count ? sensor_specs.args[0] : 0;
170
171         of_node_put(sensor_specs.np);
172
173         return 0;
174 }
175 EXPORT_SYMBOL_GPL(thermal_zone_of_get_sensor_id);
176
177 /***   functions parsing device tree nodes   ***/
178
179 static int of_find_trip_id(struct device_node *np, struct device_node *trip)
180 {
181         struct device_node *trips;
182         struct device_node *t;
183         int i = 0;
184
185         trips = of_get_child_by_name(np, "trips");
186         if (!trips) {
187                 pr_err("Failed to find 'trips' node\n");
188                 return -EINVAL;
189         }
190
191         /*
192          * Find the trip id point associated with the cooling device map
193          */
194         for_each_child_of_node(trips, t) {
195
196                 if (t == trip)
197                         goto out;
198                 i++;
199         }
200
201         i = -ENXIO;
202 out:
203         of_node_put(trips);
204
205         return i;
206 }
207
208 /*
209  * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
210  * into the device tree binding of 'trip', property type.
211  */
212 static const char * const trip_types[] = {
213         [THERMAL_TRIP_ACTIVE]   = "active",
214         [THERMAL_TRIP_PASSIVE]  = "passive",
215         [THERMAL_TRIP_HOT]      = "hot",
216         [THERMAL_TRIP_CRITICAL] = "critical",
217 };
218
219 /**
220  * thermal_of_get_trip_type - Get phy mode for given device_node
221  * @np: Pointer to the given device_node
222  * @type: Pointer to resulting trip type
223  *
224  * The function gets trip type string from property 'type',
225  * and store its index in trip_types table in @type,
226  *
227  * Return: 0 on success, or errno in error case.
228  */
229 static int thermal_of_get_trip_type(struct device_node *np,
230                                     enum thermal_trip_type *type)
231 {
232         const char *t;
233         int err, i;
234
235         err = of_property_read_string(np, "type", &t);
236         if (err < 0)
237                 return err;
238
239         for (i = 0; i < ARRAY_SIZE(trip_types); i++)
240                 if (!strcasecmp(t, trip_types[i])) {
241                         *type = i;
242                         return 0;
243                 }
244
245         return -ENODEV;
246 }
247
248 static int thermal_of_populate_trip(struct device_node *np,
249                                     struct thermal_trip *trip)
250 {
251         int prop;
252         int ret;
253
254         ret = of_property_read_u32(np, "temperature", &prop);
255         if (ret < 0) {
256                 pr_err("missing temperature property\n");
257                 return ret;
258         }
259         trip->temperature = prop;
260
261         ret = of_property_read_u32(np, "hysteresis", &prop);
262         if (ret < 0) {
263                 pr_err("missing hysteresis property\n");
264                 return ret;
265         }
266         trip->hysteresis = prop;
267
268         ret = thermal_of_get_trip_type(np, &trip->type);
269         if (ret < 0) {
270                 pr_err("wrong trip type property\n");
271                 return ret;
272         }
273
274         return 0;
275 }
276
277 static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *ntrips)
278 {
279         struct thermal_trip *tt;
280         struct device_node *trips, *trip;
281         int ret, count;
282
283         trips = of_get_child_by_name(np, "trips");
284         if (!trips) {
285                 pr_err("Failed to find 'trips' node\n");
286                 return ERR_PTR(-EINVAL);
287         }
288
289         count = of_get_child_count(trips);
290         if (!count) {
291                 pr_err("No trip point defined\n");
292                 ret = -EINVAL;
293                 goto out_of_node_put;
294         }
295
296         tt = kzalloc(sizeof(*tt) * count, GFP_KERNEL);
297         if (!tt) {
298                 ret = -ENOMEM;
299                 goto out_of_node_put;
300         }
301
302         *ntrips = count;
303
304         count = 0;
305         for_each_child_of_node(trips, trip) {
306                 ret = thermal_of_populate_trip(trip, &tt[count++]);
307                 if (ret)
308                         goto out_kfree;
309         }
310
311         of_node_put(trips);
312
313         return tt;
314
315 out_kfree:
316         kfree(tt);
317         *ntrips = 0;
318 out_of_node_put:
319         of_node_put(trips);
320
321         return ERR_PTR(ret);
322 }
323
324 static struct device_node *of_thermal_zone_find(struct device_node *sensor, int id)
325 {
326         struct device_node *np, *tz;
327         struct of_phandle_args sensor_specs;
328
329         np = of_find_node_by_name(NULL, "thermal-zones");
330         if (!np) {
331                 pr_debug("No thermal zones description\n");
332                 return ERR_PTR(-ENODEV);
333         }
334
335         /*
336          * Search for each thermal zone, a defined sensor
337          * corresponding to the one passed as parameter
338          */
339         for_each_available_child_of_node(np, tz) {
340
341                 int count, i;
342
343                 count = of_count_phandle_with_args(tz, "thermal-sensors",
344                                                    "#thermal-sensor-cells");
345                 if (count <= 0) {
346                         pr_err("%pOFn: missing thermal sensor\n", tz);
347                         tz = ERR_PTR(-EINVAL);
348                         goto out;
349                 }
350
351                 for (i = 0; i < count; i++) {
352
353                         int ret;
354
355                         ret = of_parse_phandle_with_args(tz, "thermal-sensors",
356                                                          "#thermal-sensor-cells",
357                                                          i, &sensor_specs);
358                         if (ret < 0) {
359                                 pr_err("%pOFn: Failed to read thermal-sensors cells: %d\n", tz, ret);
360                                 tz = ERR_PTR(ret);
361                                 goto out;
362                         }
363
364                         if ((sensor == sensor_specs.np) && id == (sensor_specs.args_count ?
365                                                                   sensor_specs.args[0] : 0)) {
366                                 pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor, id, tz);
367                                 goto out;
368                         }
369                 }
370         }
371         tz = ERR_PTR(-ENODEV);
372 out:
373         of_node_put(np);
374         return tz;
375 }
376
377 static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdelay)
378 {
379         int ret;
380
381         ret = of_property_read_u32(np, "polling-delay-passive", pdelay);
382         if (ret < 0) {
383                 pr_err("%pOFn: missing polling-delay-passive property\n", np);
384                 return ret;
385         }
386
387         ret = of_property_read_u32(np, "polling-delay", delay);
388         if (ret < 0) {
389                 pr_err("%pOFn: missing polling-delay property\n", np);
390                 return ret;
391         }
392
393         return 0;
394 }
395
396 static struct thermal_zone_params *thermal_of_parameters_init(struct device_node *np)
397 {
398         struct thermal_zone_params *tzp;
399         int coef[2];
400         int ncoef = ARRAY_SIZE(coef);
401         int prop, ret;
402
403         tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
404         if (!tzp)
405                 return ERR_PTR(-ENOMEM);
406
407         tzp->no_hwmon = true;
408
409         if (!of_property_read_u32(np, "sustainable-power", &prop))
410                 tzp->sustainable_power = prop;
411
412         /*
413          * For now, the thermal framework supports only one sensor per
414          * thermal zone. Thus, we are considering only the first two
415          * values as slope and offset.
416          */
417         ret = of_property_read_u32_array(np, "coefficients", coef, ncoef);
418         if (ret) {
419                 coef[0] = 1;
420                 coef[1] = 0;
421         }
422
423         tzp->slope = coef[0];
424         tzp->offset = coef[1];
425
426         return tzp;
427 }
428
429 static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_device *tz)
430 {
431         struct device_node *np, *tz_np;
432
433         np = of_find_node_by_name(NULL, "thermal-zones");
434         if (!np)
435                 return ERR_PTR(-ENODEV);
436
437         tz_np = of_get_child_by_name(np, tz->type);
438
439         of_node_put(np);
440
441         if (!tz_np)
442                 return ERR_PTR(-ENODEV);
443
444         return tz_np;
445 }
446
447 static int __thermal_of_unbind(struct device_node *map_np, int index, int trip_id,
448                                struct thermal_zone_device *tz, struct thermal_cooling_device *cdev)
449 {
450         struct of_phandle_args cooling_spec;
451         int ret;
452
453         ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells",
454                                          index, &cooling_spec);
455
456         of_node_put(cooling_spec.np);
457
458         if (ret < 0) {
459                 pr_err("Invalid cooling-device entry\n");
460                 return ret;
461         }
462
463         if (cooling_spec.args_count < 2) {
464                 pr_err("wrong reference to cooling device, missing limits\n");
465                 return -EINVAL;
466         }
467
468         if (cooling_spec.np != cdev->np)
469                 return 0;
470
471         ret = thermal_zone_unbind_cooling_device(tz, trip_id, cdev);
472         if (ret)
473                 pr_err("Failed to unbind '%s' with '%s': %d\n", tz->type, cdev->type, ret);
474
475         return ret;
476 }
477
478 static int __thermal_of_bind(struct device_node *map_np, int index, int trip_id,
479                              struct thermal_zone_device *tz, struct thermal_cooling_device *cdev)
480 {
481         struct of_phandle_args cooling_spec;
482         int ret, weight = THERMAL_WEIGHT_DEFAULT;
483
484         of_property_read_u32(map_np, "contribution", &weight);
485
486         ret = of_parse_phandle_with_args(map_np, "cooling-device", "#cooling-cells",
487                                          index, &cooling_spec);
488
489         of_node_put(cooling_spec.np);
490
491         if (ret < 0) {
492                 pr_err("Invalid cooling-device entry\n");
493                 return ret;
494         }
495
496         if (cooling_spec.args_count < 2) {
497                 pr_err("wrong reference to cooling device, missing limits\n");
498                 return -EINVAL;
499         }
500
501         if (cooling_spec.np != cdev->np)
502                 return 0;
503
504         ret = thermal_zone_bind_cooling_device(tz, trip_id, cdev, cooling_spec.args[1],
505                                                cooling_spec.args[0],
506                                                weight);
507         if (ret)
508                 pr_err("Failed to bind '%s' with '%s': %d\n", tz->type, cdev->type, ret);
509
510         return ret;
511 }
512
513 static int thermal_of_for_each_cooling_device(struct device_node *tz_np, struct device_node *map_np,
514                                               struct thermal_zone_device *tz, struct thermal_cooling_device *cdev,
515                                               int (*action)(struct device_node *, int, int,
516                                                             struct thermal_zone_device *, struct thermal_cooling_device *))
517 {
518         struct device_node *tr_np;
519         int count, i, trip_id;
520
521         tr_np = of_parse_phandle(map_np, "trip", 0);
522         if (!tr_np)
523                 return -ENODEV;
524
525         trip_id = of_find_trip_id(tz_np, tr_np);
526         if (trip_id < 0)
527                 return trip_id;
528
529         count = of_count_phandle_with_args(map_np, "cooling-device", "#cooling-cells");
530         if (count <= 0) {
531                 pr_err("Add a cooling_device property with at least one device\n");
532                 return -ENOENT;
533         }
534
535         /*
536          * At this point, we don't want to bail out when there is an
537          * error, we will try to bind/unbind as many as possible
538          * cooling devices
539          */
540         for (i = 0; i < count; i++)
541                 action(map_np, i, trip_id, tz, cdev);
542
543         return 0;
544 }
545
546 static int thermal_of_for_each_cooling_maps(struct thermal_zone_device *tz,
547                                             struct thermal_cooling_device *cdev,
548                                             int (*action)(struct device_node *, int, int,
549                                                           struct thermal_zone_device *, struct thermal_cooling_device *))
550 {
551         struct device_node *tz_np, *cm_np, *child;
552         int ret = 0;
553
554         tz_np = thermal_of_zone_get_by_name(tz);
555         if (IS_ERR(tz_np)) {
556                 pr_err("Failed to get node tz by name\n");
557                 return PTR_ERR(tz_np);
558         }
559
560         cm_np = of_get_child_by_name(tz_np, "cooling-maps");
561         if (!cm_np)
562                 goto out;
563
564         for_each_child_of_node(cm_np, child) {
565                 ret = thermal_of_for_each_cooling_device(tz_np, child, tz, cdev, action);
566                 if (ret)
567                         break;
568         }
569
570         of_node_put(cm_np);
571 out:
572         of_node_put(tz_np);
573
574         return ret;
575 }
576
577 static int thermal_of_bind(struct thermal_zone_device *tz,
578                            struct thermal_cooling_device *cdev)
579 {
580         return thermal_of_for_each_cooling_maps(tz, cdev, __thermal_of_bind);
581 }
582
583 static int thermal_of_unbind(struct thermal_zone_device *tz,
584                              struct thermal_cooling_device *cdev)
585 {
586         return thermal_of_for_each_cooling_maps(tz, cdev, __thermal_of_unbind);
587 }
588
589 /**
590  * thermal_of_zone_unregister - Cleanup the specific allocated ressources
591  *
592  * This function disables the thermal zone and frees the different
593  * ressources allocated specific to the thermal OF.
594  *
595  * @tz: a pointer to the thermal zone structure
596  */
597 void thermal_of_zone_unregister(struct thermal_zone_device *tz)
598 {
599         struct thermal_trip *trips = tz->trips;
600         struct thermal_zone_params *tzp = tz->tzp;
601         struct thermal_zone_device_ops *ops = tz->ops;
602
603         thermal_zone_device_disable(tz);
604         thermal_zone_device_unregister(tz);
605         kfree(trips);
606         kfree(tzp);
607         kfree(ops);
608 }
609 EXPORT_SYMBOL_GPL(thermal_of_zone_unregister);
610
611 /**
612  * thermal_of_zone_register - Register a thermal zone with device node
613  * sensor
614  *
615  * The thermal_of_zone_register() parses a device tree given a device
616  * node sensor and identifier. It searches for the thermal zone
617  * associated to the couple sensor/id and retrieves all the thermal
618  * zone properties and registers new thermal zone with those
619  * properties.
620  *
621  * @sensor: A device node pointer corresponding to the sensor in the device tree
622  * @id: An integer as sensor identifier
623  * @data: A private data to be stored in the thermal zone dedicated private area
624  * @ops: A set of thermal sensor ops
625  *
626  * Return: a valid thermal zone structure pointer on success.
627  *      - EINVAL: if the device tree thermal description is malformed
628  *      - ENOMEM: if one structure can not be allocated
629  *      - Other negative errors are returned by the underlying called functions
630  */
631 struct thermal_zone_device *thermal_of_zone_register(struct device_node *sensor, int id, void *data,
632                                                      const struct thermal_zone_device_ops *ops)
633 {
634         struct thermal_zone_device *tz;
635         struct thermal_trip *trips;
636         struct thermal_zone_params *tzp;
637         struct thermal_zone_device_ops *of_ops;
638         struct device_node *np;
639         int delay, pdelay;
640         int ntrips, mask;
641         int ret;
642
643         of_ops = kmemdup(ops, sizeof(*ops), GFP_KERNEL);
644         if (!of_ops)
645                 return ERR_PTR(-ENOMEM);
646
647         np = of_thermal_zone_find(sensor, id);
648         if (IS_ERR(np)) {
649                 if (PTR_ERR(np) != -ENODEV)
650                         pr_err("Failed to find thermal zone for %pOFn id=%d\n", sensor, id);
651                 return ERR_CAST(np);
652         }
653
654         trips = thermal_of_trips_init(np, &ntrips);
655         if (IS_ERR(trips)) {
656                 pr_err("Failed to find trip points for %pOFn id=%d\n", sensor, id);
657                 return ERR_CAST(trips);
658         }
659
660         ret = thermal_of_monitor_init(np, &delay, &pdelay);
661         if (ret) {
662                 pr_err("Failed to initialize monitoring delays from %pOFn\n", np);
663                 goto out_kfree_trips;
664         }
665
666         tzp = thermal_of_parameters_init(np);
667         if (IS_ERR(tzp)) {
668                 ret = PTR_ERR(tzp);
669                 pr_err("Failed to initialize parameter from %pOFn: %d\n", np, ret);
670                 goto out_kfree_trips;
671         }
672
673         of_ops->get_trip_type = of_ops->get_trip_type ? : of_thermal_get_trip_type;
674         of_ops->get_trip_temp = of_ops->get_trip_temp ? : of_thermal_get_trip_temp;
675         of_ops->get_trip_hyst = of_ops->get_trip_hyst ? : of_thermal_get_trip_hyst;
676         of_ops->set_trip_hyst = of_ops->set_trip_hyst ? : of_thermal_set_trip_hyst;
677         of_ops->get_crit_temp = of_ops->get_crit_temp ? : of_thermal_get_crit_temp;
678         of_ops->bind = thermal_of_bind;
679         of_ops->unbind = thermal_of_unbind;
680
681         mask = GENMASK_ULL((ntrips) - 1, 0);
682
683         tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
684                                                      mask, data, of_ops, tzp,
685                                                      pdelay, delay);
686         if (IS_ERR(tz)) {
687                 ret = PTR_ERR(tz);
688                 pr_err("Failed to register thermal zone %pOFn: %d\n", np, ret);
689                 goto out_kfree_tzp;
690         }
691
692         ret = thermal_zone_device_enable(tz);
693         if (ret) {
694                 pr_err("Failed to enabled thermal zone '%s', id=%d: %d\n",
695                        tz->type, tz->id, ret);
696                 thermal_of_zone_unregister(tz);
697                 return ERR_PTR(ret);
698         }
699
700         return tz;
701
702 out_kfree_tzp:
703         kfree(tzp);
704 out_kfree_trips:
705         kfree(trips);
706
707         return ERR_PTR(ret);
708 }
709 EXPORT_SYMBOL_GPL(thermal_of_zone_register);
710
711 static void devm_thermal_of_zone_release(struct device *dev, void *res)
712 {
713         thermal_of_zone_unregister(*(struct thermal_zone_device **)res);
714 }
715
716 static int devm_thermal_of_zone_match(struct device *dev, void *res,
717                                       void *data)
718 {
719         struct thermal_zone_device **r = res;
720
721         if (WARN_ON(!r || !*r))
722                 return 0;
723
724         return *r == data;
725 }
726
727 /**
728  * devm_thermal_of_zone_register - register a thermal tied with the sensor life cycle
729  *
730  * This function is the device version of the thermal_of_zone_register() function.
731  *
732  * @dev: a device structure pointer to sensor to be tied with the thermal zone OF life cycle
733  * @sensor_id: the sensor identifier
734  * @data: a pointer to a private data to be stored in the thermal zone 'devdata' field
735  * @ops: a pointer to the ops structure associated with the sensor
736  */
737 struct thermal_zone_device *devm_thermal_of_zone_register(struct device *dev, int sensor_id, void *data,
738                                                           const struct thermal_zone_device_ops *ops)
739 {
740         struct thermal_zone_device **ptr, *tzd;
741
742         ptr = devres_alloc(devm_thermal_of_zone_release, sizeof(*ptr),
743                            GFP_KERNEL);
744         if (!ptr)
745                 return ERR_PTR(-ENOMEM);
746
747         tzd = thermal_of_zone_register(dev->of_node, sensor_id, data, ops);
748         if (IS_ERR(tzd)) {
749                 devres_free(ptr);
750                 return tzd;
751         }
752
753         *ptr = tzd;
754         devres_add(dev, ptr);
755
756         return tzd;
757 }
758 EXPORT_SYMBOL_GPL(devm_thermal_of_zone_register);
759
760 /**
761  * devm_thermal_of_zone_unregister - Resource managed version of
762  *                              thermal_of_zone_unregister().
763  * @dev: Device for which which resource was allocated.
764  * @tz: a pointer to struct thermal_zone where the sensor is registered.
765  *
766  * This function removes the sensor callbacks and private data from the
767  * thermal zone device registered with devm_thermal_zone_of_sensor_register()
768  * API. It will also silent the zone by remove the .get_temp() and .get_trend()
769  * thermal zone device callbacks.
770  * Normally this function will not need to be called and the resource
771  * management code will ensure that the resource is freed.
772  */
773 void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_device *tz)
774 {
775         WARN_ON(devres_release(dev, devm_thermal_of_zone_release,
776                                devm_thermal_of_zone_match, tz));
777 }
778 EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister);
This page took 0.071765 seconds and 4 git commands to generate.