linux/drivers/thermal/of-thermal.c
<<
>>
Prefs
   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}
 851