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