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