• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <linux/thermal.h>
34 
35 #include "thermal_core.h"
36 
37 /***   Private data structures to represent thermal device tree data ***/
38 
39 /**
40  * struct __thermal_bind_param - a match between trip and cooling device
41  * @cooling_device: a pointer to identify the referred cooling device
42  * @trip_id: the trip point index
43  * @usage: the percentage (from 0 to 100) of cooling contribution
44  * @min: minimum cooling state used at this trip point
45  * @max: maximum cooling state used at this trip point
46  */
47 
48 struct __thermal_bind_params {
49 	struct device_node *cooling_device;
50 	unsigned int trip_id;
51 	unsigned int usage;
52 	unsigned long min;
53 	unsigned long max;
54 };
55 
56 /**
57  * struct __thermal_zone - internal representation of a thermal zone
58  * @mode: current thermal zone device mode (enabled/disabled)
59  * @passive_delay: polling interval while passive cooling is activated
60  * @polling_delay: zone polling interval
61  * @slope: slope of the temperature adjustment curve
62  * @offset: offset of the temperature adjustment curve
63  * @ntrips: number of trip points
64  * @trips: an array of trip points (0..ntrips - 1)
65  * @num_tbps: number of thermal bind params
66  * @tbps: an array of thermal bind params (0..num_tbps - 1)
67  * @sensor_data: sensor private data used while reading temperature and trend
68  * @ops: set of callbacks to handle the thermal zone based on DT
69  */
70 
71 struct __thermal_zone {
72 	enum thermal_device_mode mode;
73 	int passive_delay;
74 	int polling_delay;
75 	int slope;
76 	int offset;
77 
78 	/* trip data */
79 	int ntrips;
80 	struct thermal_trip *trips;
81 
82 	/* cooling binding data */
83 	int num_tbps;
84 	struct __thermal_bind_params *tbps;
85 
86 	/* sensor interface */
87 	void *sensor_data;
88 	const struct thermal_zone_of_device_ops *ops;
89 };
90 
91 /***   DT thermal zone device callbacks   ***/
92 
of_thermal_get_temp(struct thermal_zone_device * tz,int * temp)93 static int of_thermal_get_temp(struct thermal_zone_device *tz,
94 			       int *temp)
95 {
96 	struct __thermal_zone *data = tz->devdata;
97 
98 	if (!data->ops->get_temp)
99 		return -EINVAL;
100 
101 	return data->ops->get_temp(data->sensor_data, temp);
102 }
103 
104 /**
105  * of_thermal_get_ntrips - function to export number of available trip
106  *			   points.
107  * @tz: pointer to a thermal zone
108  *
109  * This function is a globally visible wrapper to get number of trip points
110  * stored in the local struct __thermal_zone
111  *
112  * Return: number of available trip points, -ENODEV when data not available
113  */
of_thermal_get_ntrips(struct thermal_zone_device * tz)114 int of_thermal_get_ntrips(struct thermal_zone_device *tz)
115 {
116 	struct __thermal_zone *data = tz->devdata;
117 
118 	if (!data || IS_ERR(data))
119 		return -ENODEV;
120 
121 	return data->ntrips;
122 }
123 EXPORT_SYMBOL_GPL(of_thermal_get_ntrips);
124 
125 /**
126  * of_thermal_is_trip_valid - function to check if trip point is valid
127  *
128  * @tz:	pointer to a thermal zone
129  * @trip:	trip point to evaluate
130  *
131  * This function is responsible for checking if passed trip point is valid
132  *
133  * Return: true if trip point is valid, false otherwise
134  */
of_thermal_is_trip_valid(struct thermal_zone_device * tz,int trip)135 bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, int trip)
136 {
137 	struct __thermal_zone *data = tz->devdata;
138 
139 	if (!data || trip >= data->ntrips || trip < 0)
140 		return false;
141 
142 	return true;
143 }
144 EXPORT_SYMBOL_GPL(of_thermal_is_trip_valid);
145 
146 /**
147  * of_thermal_get_trip_points - function to get access to a globally exported
148  *				trip points
149  *
150  * @tz:	pointer to a thermal zone
151  *
152  * This function provides a pointer to trip points table
153  *
154  * Return: pointer to trip points table, NULL otherwise
155  */
156 const struct thermal_trip *
of_thermal_get_trip_points(struct thermal_zone_device * tz)157 of_thermal_get_trip_points(struct thermal_zone_device *tz)
158 {
159 	struct __thermal_zone *data = tz->devdata;
160 
161 	if (!data)
162 		return NULL;
163 
164 	return data->trips;
165 }
166 EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
167 
168 /**
169  * of_thermal_set_emul_temp - function to set emulated temperature
170  *
171  * @tz:	pointer to a thermal zone
172  * @temp:	temperature to set
173  *
174  * This function gives the ability to set emulated value of temperature,
175  * which is handy for debugging
176  *
177  * Return: zero on success, error code otherwise
178  */
of_thermal_set_emul_temp(struct thermal_zone_device * tz,int temp)179 static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
180 				    int temp)
181 {
182 	struct __thermal_zone *data = tz->devdata;
183 
184 	if (!data->ops || !data->ops->set_emul_temp)
185 		return -EINVAL;
186 
187 	return data->ops->set_emul_temp(data->sensor_data, temp);
188 }
189 
of_thermal_get_trend(struct thermal_zone_device * tz,int trip,enum thermal_trend * trend)190 static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
191 				enum thermal_trend *trend)
192 {
193 	struct __thermal_zone *data = tz->devdata;
194 	long dev_trend;
195 	int r;
196 
197 	if (!data->ops->get_trend)
198 		return -EINVAL;
199 
200 	r = data->ops->get_trend(data->sensor_data, &dev_trend);
201 	if (r)
202 		return r;
203 
204 	/* TODO: These intervals might have some thresholds, but in core code */
205 	if (dev_trend > 0)
206 		*trend = THERMAL_TREND_RAISING;
207 	else if (dev_trend < 0)
208 		*trend = THERMAL_TREND_DROPPING;
209 	else
210 		*trend = THERMAL_TREND_STABLE;
211 
212 	return 0;
213 }
214 
of_thermal_bind(struct thermal_zone_device * thermal,struct thermal_cooling_device * cdev)215 static int of_thermal_bind(struct thermal_zone_device *thermal,
216 			   struct thermal_cooling_device *cdev)
217 {
218 	struct __thermal_zone *data = thermal->devdata;
219 	int i;
220 
221 	if (!data || IS_ERR(data))
222 		return -ENODEV;
223 
224 	/* find where to bind */
225 	for (i = 0; i < data->num_tbps; i++) {
226 		struct __thermal_bind_params *tbp = data->tbps + i;
227 
228 		if (tbp->cooling_device == cdev->np) {
229 			int ret;
230 
231 			ret = thermal_zone_bind_cooling_device(thermal,
232 						tbp->trip_id, cdev,
233 						tbp->max,
234 						tbp->min,
235 						tbp->usage);
236 			if (ret)
237 				return ret;
238 		}
239 	}
240 
241 	return 0;
242 }
243 
of_thermal_unbind(struct thermal_zone_device * thermal,struct thermal_cooling_device * cdev)244 static int of_thermal_unbind(struct thermal_zone_device *thermal,
245 			     struct thermal_cooling_device *cdev)
246 {
247 	struct __thermal_zone *data = thermal->devdata;
248 	int i;
249 
250 	if (!data || IS_ERR(data))
251 		return -ENODEV;
252 
253 	/* find where to unbind */
254 	for (i = 0; i < data->num_tbps; i++) {
255 		struct __thermal_bind_params *tbp = data->tbps + i;
256 
257 		if (tbp->cooling_device == cdev->np) {
258 			int ret;
259 
260 			ret = thermal_zone_unbind_cooling_device(thermal,
261 						tbp->trip_id, cdev);
262 			if (ret)
263 				return ret;
264 		}
265 	}
266 
267 	return 0;
268 }
269 
of_thermal_get_mode(struct thermal_zone_device * tz,enum thermal_device_mode * mode)270 static int of_thermal_get_mode(struct thermal_zone_device *tz,
271 			       enum thermal_device_mode *mode)
272 {
273 	struct __thermal_zone *data = tz->devdata;
274 
275 	*mode = data->mode;
276 
277 	return 0;
278 }
279 
of_thermal_set_mode(struct thermal_zone_device * tz,enum thermal_device_mode mode)280 static int of_thermal_set_mode(struct thermal_zone_device *tz,
281 			       enum thermal_device_mode mode)
282 {
283 	struct __thermal_zone *data = tz->devdata;
284 
285 	mutex_lock(&tz->lock);
286 
287 	if (mode == THERMAL_DEVICE_ENABLED) {
288 		tz->polling_delay = data->polling_delay;
289 		tz->passive_delay = data->passive_delay;
290 	} else {
291 		tz->polling_delay = 0;
292 		tz->passive_delay = 0;
293 	}
294 
295 	mutex_unlock(&tz->lock);
296 
297 	data->mode = mode;
298 	thermal_zone_device_update(tz);
299 
300 	return 0;
301 }
302 
of_thermal_get_trip_type(struct thermal_zone_device * tz,int trip,enum thermal_trip_type * type)303 static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
304 				    enum thermal_trip_type *type)
305 {
306 	struct __thermal_zone *data = tz->devdata;
307 
308 	if (trip >= data->ntrips || trip < 0)
309 		return -EDOM;
310 
311 	*type = data->trips[trip].type;
312 
313 	return 0;
314 }
315 
of_thermal_get_trip_temp(struct thermal_zone_device * tz,int trip,int * temp)316 static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
317 				    int *temp)
318 {
319 	struct __thermal_zone *data = tz->devdata;
320 
321 	if (trip >= data->ntrips || trip < 0)
322 		return -EDOM;
323 
324 	*temp = data->trips[trip].temperature;
325 
326 	return 0;
327 }
328 
of_thermal_set_trip_temp(struct thermal_zone_device * tz,int trip,int temp)329 static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
330 				    int temp)
331 {
332 	struct __thermal_zone *data = tz->devdata;
333 
334 	if (trip >= data->ntrips || trip < 0)
335 		return -EDOM;
336 
337 	/* thermal framework should take care of data->mask & (1 << trip) */
338 	data->trips[trip].temperature = temp;
339 
340 	return 0;
341 }
342 
of_thermal_get_trip_hyst(struct thermal_zone_device * tz,int trip,int * hyst)343 static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
344 				    int *hyst)
345 {
346 	struct __thermal_zone *data = tz->devdata;
347 
348 	if (trip >= data->ntrips || trip < 0)
349 		return -EDOM;
350 
351 	*hyst = data->trips[trip].hysteresis;
352 
353 	return 0;
354 }
355 
of_thermal_set_trip_hyst(struct thermal_zone_device * tz,int trip,int hyst)356 static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
357 				    int hyst)
358 {
359 	struct __thermal_zone *data = tz->devdata;
360 
361 	if (trip >= data->ntrips || trip < 0)
362 		return -EDOM;
363 
364 	/* thermal framework should take care of data->mask & (1 << trip) */
365 	data->trips[trip].hysteresis = hyst;
366 
367 	return 0;
368 }
369 
of_thermal_get_crit_temp(struct thermal_zone_device * tz,int * temp)370 static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
371 				    int *temp)
372 {
373 	struct __thermal_zone *data = tz->devdata;
374 	int i;
375 
376 	for (i = 0; i < data->ntrips; i++)
377 		if (data->trips[i].type == THERMAL_TRIP_CRITICAL) {
378 			*temp = data->trips[i].temperature;
379 			return 0;
380 		}
381 
382 	return -EINVAL;
383 }
384 
385 static struct thermal_zone_device_ops of_thermal_ops = {
386 	.get_mode = of_thermal_get_mode,
387 	.set_mode = of_thermal_set_mode,
388 
389 	.get_trip_type = of_thermal_get_trip_type,
390 	.get_trip_temp = of_thermal_get_trip_temp,
391 	.set_trip_temp = of_thermal_set_trip_temp,
392 	.get_trip_hyst = of_thermal_get_trip_hyst,
393 	.set_trip_hyst = of_thermal_set_trip_hyst,
394 	.get_crit_temp = of_thermal_get_crit_temp,
395 
396 	.bind = of_thermal_bind,
397 	.unbind = of_thermal_unbind,
398 };
399 
400 /***   sensor API   ***/
401 
402 static struct thermal_zone_device *
thermal_zone_of_add_sensor(struct device_node * zone,struct device_node * sensor,void * data,const struct thermal_zone_of_device_ops * ops)403 thermal_zone_of_add_sensor(struct device_node *zone,
404 			   struct device_node *sensor, void *data,
405 			   const struct thermal_zone_of_device_ops *ops)
406 {
407 	struct thermal_zone_device *tzd;
408 	struct __thermal_zone *tz;
409 
410 	tzd = thermal_zone_get_zone_by_name(zone->name);
411 	if (IS_ERR(tzd))
412 		return ERR_PTR(-EPROBE_DEFER);
413 
414 	tz = tzd->devdata;
415 
416 	if (!ops)
417 		return ERR_PTR(-EINVAL);
418 
419 	mutex_lock(&tzd->lock);
420 	tz->ops = ops;
421 	tz->sensor_data = data;
422 
423 	tzd->ops->get_temp = of_thermal_get_temp;
424 	tzd->ops->get_trend = of_thermal_get_trend;
425 	tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
426 	mutex_unlock(&tzd->lock);
427 
428 	return tzd;
429 }
430 
431 /**
432  * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
433  * @dev: a valid struct device pointer of a sensor device. Must contain
434  *       a valid .of_node, for the sensor node.
435  * @sensor_id: a sensor identifier, in case the sensor IP has more
436  *             than one sensors
437  * @data: a private pointer (owned by the caller) that will be passed
438  *        back, when a temperature reading is needed.
439  * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.
440  *
441  * This function will search the list of thermal zones described in device
442  * tree and look for the zone that refer to the sensor device pointed by
443  * @dev->of_node as temperature providers. For the zone pointing to the
444  * sensor node, the sensor will be added to the DT thermal zone device.
445  *
446  * The thermal zone temperature is provided by the @get_temp function
447  * pointer. When called, it will have the private pointer @data back.
448  *
449  * The thermal zone temperature trend is provided by the @get_trend function
450  * pointer. When called, it will have the private pointer @data back.
451  *
452  * TODO:
453  * 01 - This function must enqueue the new sensor instead of using
454  * it as the only source of temperature values.
455  *
456  * 02 - There must be a way to match the sensor with all thermal zones
457  * that refer to it.
458  *
459  * Return: On success returns a valid struct thermal_zone_device,
460  * otherwise, it returns a corresponding ERR_PTR(). Caller must
461  * check the return value with help of IS_ERR() helper.
462  */
463 struct thermal_zone_device *
thermal_zone_of_sensor_register(struct device * dev,int sensor_id,void * data,const struct thermal_zone_of_device_ops * ops)464 thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
465 				const struct thermal_zone_of_device_ops *ops)
466 {
467 	struct device_node *np, *child, *sensor_np;
468 	struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
469 
470 	np = of_find_node_by_name(NULL, "thermal-zones");
471 	if (!np)
472 		return ERR_PTR(-ENODEV);
473 
474 	if (!dev || !dev->of_node) {
475 		of_node_put(np);
476 		return ERR_PTR(-EINVAL);
477 	}
478 
479 	sensor_np = of_node_get(dev->of_node);
480 
481 	for_each_child_of_node(np, child) {
482 		struct of_phandle_args sensor_specs;
483 		int ret, id;
484 
485 		/* Check whether child is enabled or not */
486 		if (!of_device_is_available(child))
487 			continue;
488 
489 		/* For now, thermal framework supports only 1 sensor per zone */
490 		ret = of_parse_phandle_with_args(child, "thermal-sensors",
491 						 "#thermal-sensor-cells",
492 						 0, &sensor_specs);
493 		if (ret)
494 			continue;
495 
496 		if (sensor_specs.args_count >= 1) {
497 			id = sensor_specs.args[0];
498 			WARN(sensor_specs.args_count > 1,
499 			     "%s: too many cells in sensor specifier %d\n",
500 			     sensor_specs.np->name, sensor_specs.args_count);
501 		} else {
502 			id = 0;
503 		}
504 
505 		if (sensor_specs.np == sensor_np && id == sensor_id) {
506 			tzd = thermal_zone_of_add_sensor(child, sensor_np,
507 							 data, ops);
508 			if (!IS_ERR(tzd))
509 				tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
510 
511 			of_node_put(sensor_specs.np);
512 			of_node_put(child);
513 			goto exit;
514 		}
515 		of_node_put(sensor_specs.np);
516 	}
517 exit:
518 	of_node_put(sensor_np);
519 	of_node_put(np);
520 
521 	return tzd;
522 }
523 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register);
524 
525 /**
526  * thermal_zone_of_sensor_unregister - unregisters a sensor from a DT thermal zone
527  * @dev: a valid struct device pointer of a sensor device. Must contain
528  *       a valid .of_node, for the sensor node.
529  * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
530  *
531  * This function removes the sensor callbacks and private data from the
532  * thermal zone device registered with thermal_zone_of_sensor_register()
533  * API. It will also silent the zone by remove the .get_temp() and .get_trend()
534  * thermal zone device callbacks.
535  *
536  * TODO: When the support to several sensors per zone is added, this
537  * function must search the sensor list based on @dev parameter.
538  *
539  */
thermal_zone_of_sensor_unregister(struct device * dev,struct thermal_zone_device * tzd)540 void thermal_zone_of_sensor_unregister(struct device *dev,
541 				       struct thermal_zone_device *tzd)
542 {
543 	struct __thermal_zone *tz;
544 
545 	if (!dev || !tzd || !tzd->devdata)
546 		return;
547 
548 	tz = tzd->devdata;
549 
550 	/* no __thermal_zone, nothing to be done */
551 	if (!tz)
552 		return;
553 
554 	mutex_lock(&tzd->lock);
555 	tzd->ops->get_temp = NULL;
556 	tzd->ops->get_trend = NULL;
557 	tzd->ops->set_emul_temp = NULL;
558 
559 	tz->ops = NULL;
560 	tz->sensor_data = NULL;
561 	mutex_unlock(&tzd->lock);
562 }
563 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
564 
565 /***   functions parsing device tree nodes   ***/
566 
567 /**
568  * thermal_of_populate_bind_params - parse and fill cooling map data
569  * @np: DT node containing a cooling-map node
570  * @__tbp: data structure to be filled with cooling map info
571  * @trips: array of thermal zone trip points
572  * @ntrips: number of trip points inside trips.
573  *
574  * This function parses a cooling-map type of node represented by
575  * @np parameter and fills the read data into @__tbp data structure.
576  * It needs the already parsed array of trip points of the thermal zone
577  * in consideration.
578  *
579  * Return: 0 on success, proper error code otherwise
580  */
thermal_of_populate_bind_params(struct device_node * np,struct __thermal_bind_params * __tbp,struct thermal_trip * trips,int ntrips)581 static int thermal_of_populate_bind_params(struct device_node *np,
582 					   struct __thermal_bind_params *__tbp,
583 					   struct thermal_trip *trips,
584 					   int ntrips)
585 {
586 	struct of_phandle_args cooling_spec;
587 	struct device_node *trip;
588 	int ret, i;
589 	u32 prop;
590 
591 	/* Default weight. Usage is optional */
592 	__tbp->usage = THERMAL_WEIGHT_DEFAULT;
593 	ret = of_property_read_u32(np, "contribution", &prop);
594 	if (ret == 0)
595 		__tbp->usage = prop;
596 
597 	trip = of_parse_phandle(np, "trip", 0);
598 	if (!trip) {
599 		pr_err("missing trip property\n");
600 		return -ENODEV;
601 	}
602 
603 	/* match using device_node */
604 	for (i = 0; i < ntrips; i++)
605 		if (trip == trips[i].np) {
606 			__tbp->trip_id = i;
607 			break;
608 		}
609 
610 	if (i == ntrips) {
611 		ret = -ENODEV;
612 		goto end;
613 	}
614 
615 	ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells",
616 					 0, &cooling_spec);
617 	if (ret < 0) {
618 		pr_err("missing cooling_device property\n");
619 		goto end;
620 	}
621 	__tbp->cooling_device = cooling_spec.np;
622 	if (cooling_spec.args_count >= 2) { /* at least min and max */
623 		__tbp->min = cooling_spec.args[0];
624 		__tbp->max = cooling_spec.args[1];
625 	} else {
626 		pr_err("wrong reference to cooling device, missing limits\n");
627 	}
628 
629 end:
630 	of_node_put(trip);
631 
632 	return ret;
633 }
634 
635 /**
636  * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
637  * into the device tree binding of 'trip', property type.
638  */
639 static const char * const trip_types[] = {
640 	[THERMAL_TRIP_ACTIVE]	= "active",
641 	[THERMAL_TRIP_PASSIVE]	= "passive",
642 	[THERMAL_TRIP_HOT]	= "hot",
643 	[THERMAL_TRIP_CRITICAL]	= "critical",
644 };
645 
646 /**
647  * thermal_of_get_trip_type - Get phy mode for given device_node
648  * @np:	Pointer to the given device_node
649  * @type: Pointer to resulting trip type
650  *
651  * The function gets trip type string from property 'type',
652  * and store its index in trip_types table in @type,
653  *
654  * Return: 0 on success, or errno in error case.
655  */
thermal_of_get_trip_type(struct device_node * np,enum thermal_trip_type * type)656 static int thermal_of_get_trip_type(struct device_node *np,
657 				    enum thermal_trip_type *type)
658 {
659 	const char *t;
660 	int err, i;
661 
662 	err = of_property_read_string(np, "type", &t);
663 	if (err < 0)
664 		return err;
665 
666 	for (i = 0; i < ARRAY_SIZE(trip_types); i++)
667 		if (!strcasecmp(t, trip_types[i])) {
668 			*type = i;
669 			return 0;
670 		}
671 
672 	return -ENODEV;
673 }
674 
675 /**
676  * thermal_of_populate_trip - parse and fill one trip point data
677  * @np: DT node containing a trip point node
678  * @trip: trip point data structure to be filled up
679  *
680  * This function parses a trip point type of node represented by
681  * @np parameter and fills the read data into @trip data structure.
682  *
683  * Return: 0 on success, proper error code otherwise
684  */
thermal_of_populate_trip(struct device_node * np,struct thermal_trip * trip)685 static int thermal_of_populate_trip(struct device_node *np,
686 				    struct thermal_trip *trip)
687 {
688 	int prop;
689 	int ret;
690 
691 	ret = of_property_read_u32(np, "temperature", &prop);
692 	if (ret < 0) {
693 		pr_err("missing temperature property\n");
694 		return ret;
695 	}
696 	trip->temperature = prop;
697 
698 	ret = of_property_read_u32(np, "hysteresis", &prop);
699 	if (ret < 0) {
700 		pr_err("missing hysteresis property\n");
701 		return ret;
702 	}
703 	trip->hysteresis = prop;
704 
705 	ret = thermal_of_get_trip_type(np, &trip->type);
706 	if (ret < 0) {
707 		pr_err("wrong trip type property\n");
708 		return ret;
709 	}
710 
711 	/* Required for cooling map matching */
712 	trip->np = np;
713 	of_node_get(np);
714 
715 	return 0;
716 }
717 
718 /**
719  * thermal_of_build_thermal_zone - parse and fill one thermal zone data
720  * @np: DT node containing a thermal zone node
721  *
722  * This function parses a thermal zone type of node represented by
723  * @np parameter and fills the read data into a __thermal_zone data structure
724  * and return this pointer.
725  *
726  * TODO: Missing properties to parse: thermal-sensor-names
727  *
728  * Return: On success returns a valid struct __thermal_zone,
729  * otherwise, it returns a corresponding ERR_PTR(). Caller must
730  * check the return value with help of IS_ERR() helper.
731  */
732 static struct __thermal_zone *
thermal_of_build_thermal_zone(struct device_node * np)733 thermal_of_build_thermal_zone(struct device_node *np)
734 {
735 	struct device_node *child = NULL, *gchild;
736 	struct __thermal_zone *tz;
737 	int ret, i;
738 	u32 prop, coef[2];
739 
740 	if (!np) {
741 		pr_err("no thermal zone np\n");
742 		return ERR_PTR(-EINVAL);
743 	}
744 
745 	tz = kzalloc(sizeof(*tz), GFP_KERNEL);
746 	if (!tz)
747 		return ERR_PTR(-ENOMEM);
748 
749 	ret = of_property_read_u32(np, "polling-delay-passive", &prop);
750 	if (ret < 0) {
751 		pr_err("missing polling-delay-passive property\n");
752 		goto free_tz;
753 	}
754 	tz->passive_delay = prop;
755 
756 	ret = of_property_read_u32(np, "polling-delay", &prop);
757 	if (ret < 0) {
758 		pr_err("missing polling-delay property\n");
759 		goto free_tz;
760 	}
761 	tz->polling_delay = prop;
762 
763 	/*
764 	 * REVIST: for now, the thermal framework supports only
765 	 * one sensor per thermal zone. Thus, we are considering
766 	 * only the first two values as slope and offset.
767 	 */
768 	ret = of_property_read_u32_array(np, "coefficients", coef, 2);
769 	if (ret == 0) {
770 		tz->slope = coef[0];
771 		tz->offset = coef[1];
772 	} else {
773 		tz->slope = 1;
774 		tz->offset = 0;
775 	}
776 
777 	/* trips */
778 	child = of_get_child_by_name(np, "trips");
779 
780 	/* No trips provided */
781 	if (!child)
782 		goto finish;
783 
784 	tz->ntrips = of_get_child_count(child);
785 	if (tz->ntrips == 0) /* must have at least one child */
786 		goto finish;
787 
788 	tz->trips = kzalloc(tz->ntrips * sizeof(*tz->trips), GFP_KERNEL);
789 	if (!tz->trips) {
790 		ret = -ENOMEM;
791 		goto free_tz;
792 	}
793 
794 	i = 0;
795 	for_each_child_of_node(child, gchild) {
796 		ret = thermal_of_populate_trip(gchild, &tz->trips[i++]);
797 		if (ret)
798 			goto free_trips;
799 	}
800 
801 	of_node_put(child);
802 
803 	/* cooling-maps */
804 	child = of_get_child_by_name(np, "cooling-maps");
805 
806 	/* cooling-maps not provided */
807 	if (!child)
808 		goto finish;
809 
810 	tz->num_tbps = of_get_child_count(child);
811 	if (tz->num_tbps == 0)
812 		goto finish;
813 
814 	tz->tbps = kzalloc(tz->num_tbps * sizeof(*tz->tbps), GFP_KERNEL);
815 	if (!tz->tbps) {
816 		ret = -ENOMEM;
817 		goto free_trips;
818 	}
819 
820 	i = 0;
821 	for_each_child_of_node(child, gchild) {
822 		ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++],
823 						      tz->trips, tz->ntrips);
824 		if (ret)
825 			goto free_tbps;
826 	}
827 
828 finish:
829 	of_node_put(child);
830 	tz->mode = THERMAL_DEVICE_DISABLED;
831 
832 	return tz;
833 
834 free_tbps:
835 	for (i = 0; i < tz->num_tbps; i++)
836 		of_node_put(tz->tbps[i].cooling_device);
837 	kfree(tz->tbps);
838 free_trips:
839 	for (i = 0; i < tz->ntrips; i++)
840 		of_node_put(tz->trips[i].np);
841 	kfree(tz->trips);
842 	of_node_put(gchild);
843 free_tz:
844 	kfree(tz);
845 	of_node_put(child);
846 
847 	return ERR_PTR(ret);
848 }
849 
of_thermal_free_zone(struct __thermal_zone * tz)850 static inline void of_thermal_free_zone(struct __thermal_zone *tz)
851 {
852 	int i;
853 
854 	for (i = 0; i < tz->num_tbps; i++)
855 		of_node_put(tz->tbps[i].cooling_device);
856 	kfree(tz->tbps);
857 	for (i = 0; i < tz->ntrips; i++)
858 		of_node_put(tz->trips[i].np);
859 	kfree(tz->trips);
860 	kfree(tz);
861 }
862 
863 /**
864  * of_parse_thermal_zones - parse device tree thermal data
865  *
866  * Initialization function that can be called by machine initialization
867  * code to parse thermal data and populate the thermal framework
868  * with hardware thermal zones info. This function only parses thermal zones.
869  * Cooling devices and sensor devices nodes are supposed to be parsed
870  * by their respective drivers.
871  *
872  * Return: 0 on success, proper error code otherwise
873  *
874  */
of_parse_thermal_zones(void)875 int __init of_parse_thermal_zones(void)
876 {
877 	struct device_node *np, *child;
878 	struct __thermal_zone *tz;
879 	struct thermal_zone_device_ops *ops;
880 
881 	np = of_find_node_by_name(NULL, "thermal-zones");
882 	if (!np) {
883 		pr_debug("unable to find thermal zones\n");
884 		return 0; /* Run successfully on systems without thermal DT */
885 	}
886 
887 	for_each_child_of_node(np, child) {
888 		struct thermal_zone_device *zone;
889 		struct thermal_zone_params *tzp;
890 		int i, mask = 0;
891 		u32 prop;
892 
893 		/* Check whether child is enabled or not */
894 		if (!of_device_is_available(child))
895 			continue;
896 
897 		tz = thermal_of_build_thermal_zone(child);
898 		if (IS_ERR(tz)) {
899 			pr_err("failed to build thermal zone %s: %ld\n",
900 			       child->name,
901 			       PTR_ERR(tz));
902 			continue;
903 		}
904 
905 		ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);
906 		if (!ops)
907 			goto exit_free;
908 
909 		tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
910 		if (!tzp) {
911 			kfree(ops);
912 			goto exit_free;
913 		}
914 
915 		/* No hwmon because there might be hwmon drivers registering */
916 		tzp->no_hwmon = true;
917 
918 		if (!of_property_read_u32(child, "sustainable-power", &prop))
919 			tzp->sustainable_power = prop;
920 
921 		for (i = 0; i < tz->ntrips; i++)
922 			mask |= 1 << i;
923 
924 		/* these two are left for temperature drivers to use */
925 		tzp->slope = tz->slope;
926 		tzp->offset = tz->offset;
927 
928 		zone = thermal_zone_device_register(child->name, tz->ntrips,
929 						    mask, tz,
930 						    ops, tzp,
931 						    tz->passive_delay,
932 						    tz->polling_delay);
933 		if (IS_ERR(zone)) {
934 			pr_err("Failed to build %s zone %ld\n", child->name,
935 			       PTR_ERR(zone));
936 			kfree(tzp);
937 			kfree(ops);
938 			of_thermal_free_zone(tz);
939 			/* attempting to build remaining zones still */
940 		}
941 	}
942 	of_node_put(np);
943 
944 	return 0;
945 
946 exit_free:
947 	of_node_put(child);
948 	of_node_put(np);
949 	of_thermal_free_zone(tz);
950 
951 	/* no memory available, so free what we have built */
952 	of_thermal_destroy_zones();
953 
954 	return -ENOMEM;
955 }
956 
957 /**
958  * of_thermal_destroy_zones - remove all zones parsed and allocated resources
959  *
960  * Finds all zones parsed and added to the thermal framework and remove them
961  * from the system, together with their resources.
962  *
963  */
of_thermal_destroy_zones(void)964 void of_thermal_destroy_zones(void)
965 {
966 	struct device_node *np, *child;
967 
968 	np = of_find_node_by_name(NULL, "thermal-zones");
969 	if (!np) {
970 		pr_debug("unable to find thermal zones\n");
971 		return;
972 	}
973 
974 	for_each_child_of_node(np, child) {
975 		struct thermal_zone_device *zone;
976 
977 		/* Check whether child is enabled or not */
978 		if (!of_device_is_available(child))
979 			continue;
980 
981 		zone = thermal_zone_get_zone_by_name(child->name);
982 		if (IS_ERR(zone))
983 			continue;
984 
985 		thermal_zone_device_unregister(zone);
986 		kfree(zone->tzp);
987 		kfree(zone->ops);
988 		of_thermal_free_zone(zone->devdata);
989 	}
990 	of_node_put(np);
991 }
992