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 v4.15-rc3 1069 lines 28 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#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}