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