Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.16-rc6 850 lines 22 kB view raw
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 46struct __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 62struct __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 84struct __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 105static 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 116static 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 141static int of_thermal_bind(struct thermal_zone_device *thermal, 142 struct thermal_cooling_device *cdev) 143{ 144 struct __thermal_zone *data = thermal->devdata; 145 int i; 146 147 if (!data || IS_ERR(data)) 148 return -ENODEV; 149 150 /* find where to bind */ 151 for (i = 0; i < data->num_tbps; i++) { 152 struct __thermal_bind_params *tbp = data->tbps + i; 153 154 if (tbp->cooling_device == cdev->np) { 155 int ret; 156 157 ret = thermal_zone_bind_cooling_device(thermal, 158 tbp->trip_id, cdev, 159 tbp->max, 160 tbp->min); 161 if (ret) 162 return ret; 163 } 164 } 165 166 return 0; 167} 168 169static 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 195static 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 205static 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 225static 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 238static 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 251static 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 265static 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 278static 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 292static 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 307static 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 324static struct thermal_zone_device * 325thermal_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 */ 384struct thermal_zone_device * 385thermal_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} 432EXPORT_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 */ 449void 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} 472EXPORT_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 */ 490static 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 538end: 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 */ 548static 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 */ 565static 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 */ 594static 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 */ 640static struct __thermal_zone * 641thermal_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 722finish: 723 of_node_put(child); 724 tz->mode = THERMAL_DEVICE_DISABLED; 725 726 return tz; 727 728free_tbps: 729 kfree(tz->tbps); 730free_trips: 731 kfree(tz->trips); 732free_tz: 733 kfree(tz); 734 of_node_put(child); 735 736 return ERR_PTR(ret); 737} 738 739static inline void of_thermal_free_zone(struct __thermal_zone *tz) 740{ 741 kfree(tz->tbps); 742 kfree(tz->trips); 743 kfree(tz); 744} 745 746/** 747 * of_parse_thermal_zones - parse device tree thermal data 748 * 749 * Initialization function that can be called by machine initialization 750 * code to parse thermal data and populate the thermal framework 751 * with hardware thermal zones info. This function only parses thermal zones. 752 * Cooling devices and sensor devices nodes are supposed to be parsed 753 * by their respective drivers. 754 * 755 * Return: 0 on success, proper error code otherwise 756 * 757 */ 758int __init of_parse_thermal_zones(void) 759{ 760 struct device_node *np, *child; 761 struct __thermal_zone *tz; 762 struct thermal_zone_device_ops *ops; 763 764 np = of_find_node_by_name(NULL, "thermal-zones"); 765 if (!np) { 766 pr_debug("unable to find thermal zones\n"); 767 return 0; /* Run successfully on systems without thermal DT */ 768 } 769 770 for_each_child_of_node(np, child) { 771 struct thermal_zone_device *zone; 772 struct thermal_zone_params *tzp; 773 774 tz = thermal_of_build_thermal_zone(child); 775 if (IS_ERR(tz)) { 776 pr_err("failed to build thermal zone %s: %ld\n", 777 child->name, 778 PTR_ERR(tz)); 779 continue; 780 } 781 782 ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL); 783 if (!ops) 784 goto exit_free; 785 786 tzp = kzalloc(sizeof(*tzp), GFP_KERNEL); 787 if (!tzp) { 788 kfree(ops); 789 goto exit_free; 790 } 791 792 /* No hwmon because there might be hwmon drivers registering */ 793 tzp->no_hwmon = true; 794 795 zone = thermal_zone_device_register(child->name, tz->ntrips, 796 0, tz, 797 ops, tzp, 798 tz->passive_delay, 799 tz->polling_delay); 800 if (IS_ERR(zone)) { 801 pr_err("Failed to build %s zone %ld\n", child->name, 802 PTR_ERR(zone)); 803 kfree(tzp); 804 kfree(ops); 805 of_thermal_free_zone(tz); 806 /* attempting to build remaining zones still */ 807 } 808 } 809 810 return 0; 811 812exit_free: 813 of_thermal_free_zone(tz); 814 815 /* no memory available, so free what we have built */ 816 of_thermal_destroy_zones(); 817 818 return -ENOMEM; 819} 820 821/** 822 * of_thermal_destroy_zones - remove all zones parsed and allocated resources 823 * 824 * Finds all zones parsed and added to the thermal framework and remove them 825 * from the system, together with their resources. 826 * 827 */ 828void of_thermal_destroy_zones(void) 829{ 830 struct device_node *np, *child; 831 832 np = of_find_node_by_name(NULL, "thermal-zones"); 833 if (!np) { 834 pr_err("unable to find thermal zones\n"); 835 return; 836 } 837 838 for_each_child_of_node(np, child) { 839 struct thermal_zone_device *zone; 840 841 zone = thermal_zone_get_zone_by_name(child->name); 842 if (IS_ERR(zone)) 843 continue; 844 845 thermal_zone_device_unregister(zone); 846 kfree(zone->tzp); 847 kfree(zone->ops); 848 of_thermal_free_zone(zone->devdata); 849 } 850}