Linux Audio

Check our new training course

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