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