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