Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  of-thermal.c - Generic Thermal Management device tree support.
0004  *
0005  *  Copyright (C) 2013 Texas Instruments
0006  *  Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #include <linux/err.h>
0012 #include <linux/export.h>
0013 #include <linux/of_device.h>
0014 #include <linux/of_platform.h>
0015 #include <linux/slab.h>
0016 #include <linux/thermal.h>
0017 #include <linux/types.h>
0018 #include <linux/string.h>
0019 
0020 #include "thermal_core.h"
0021 
0022 /***   Private data structures to represent thermal device tree data ***/
0023 
0024 /**
0025  * struct __thermal_cooling_bind_param - a cooling device for a trip point
0026  * @cooling_device: a pointer to identify the referred cooling device
0027  * @min: minimum cooling state used at this trip point
0028  * @max: maximum cooling state used at this trip point
0029  */
0030 
0031 struct __thermal_cooling_bind_param {
0032     struct device_node *cooling_device;
0033     unsigned long min;
0034     unsigned long max;
0035 };
0036 
0037 /**
0038  * struct __thermal_bind_params - a match between trip and cooling device
0039  * @tcbp: a pointer to an array of cooling devices
0040  * @count: number of elements in array
0041  * @trip_id: the trip point index
0042  * @usage: the percentage (from 0 to 100) of cooling contribution
0043  */
0044 
0045 struct __thermal_bind_params {
0046     struct __thermal_cooling_bind_param *tcbp;
0047     unsigned int count;
0048     unsigned int trip_id;
0049     unsigned int usage;
0050 };
0051 
0052 /**
0053  * struct __thermal_zone - internal representation of a thermal zone
0054  * @passive_delay: polling interval while passive cooling is activated
0055  * @polling_delay: zone polling interval
0056  * @slope: slope of the temperature adjustment curve
0057  * @offset: offset of the temperature adjustment curve
0058  * @ntrips: number of trip points
0059  * @trips: an array of trip points (0..ntrips - 1)
0060  * @num_tbps: number of thermal bind params
0061  * @tbps: an array of thermal bind params (0..num_tbps - 1)
0062  * @sensor_data: sensor private data used while reading temperature and trend
0063  * @ops: set of callbacks to handle the thermal zone based on DT
0064  */
0065 
0066 struct __thermal_zone {
0067     int passive_delay;
0068     int polling_delay;
0069     int slope;
0070     int offset;
0071 
0072     /* trip data */
0073     int ntrips;
0074     struct thermal_trip *trips;
0075 
0076     /* cooling binding data */
0077     int num_tbps;
0078     struct __thermal_bind_params *tbps;
0079 
0080     /* sensor interface */
0081     void *sensor_data;
0082     const struct thermal_zone_of_device_ops *ops;
0083 };
0084 
0085 /***   DT thermal zone device callbacks   ***/
0086 
0087 static int of_thermal_get_temp(struct thermal_zone_device *tz,
0088                    int *temp)
0089 {
0090     struct __thermal_zone *data = tz->devdata;
0091 
0092     if (!data->ops || !data->ops->get_temp)
0093         return -EINVAL;
0094 
0095     return data->ops->get_temp(data->sensor_data, temp);
0096 }
0097 
0098 static int of_thermal_set_trips(struct thermal_zone_device *tz,
0099                 int low, int high)
0100 {
0101     struct __thermal_zone *data = tz->devdata;
0102 
0103     if (!data->ops || !data->ops->set_trips)
0104         return -EINVAL;
0105 
0106     return data->ops->set_trips(data->sensor_data, low, high);
0107 }
0108 
0109 /**
0110  * of_thermal_get_ntrips - function to export number of available trip
0111  *             points.
0112  * @tz: pointer to a thermal zone
0113  *
0114  * This function is a globally visible wrapper to get number of trip points
0115  * stored in the local struct __thermal_zone
0116  *
0117  * Return: number of available trip points, -ENODEV when data not available
0118  */
0119 int of_thermal_get_ntrips(struct thermal_zone_device *tz)
0120 {
0121     return tz->num_trips;
0122 }
0123 EXPORT_SYMBOL_GPL(of_thermal_get_ntrips);
0124 
0125 /**
0126  * of_thermal_is_trip_valid - function to check if trip point is valid
0127  *
0128  * @tz: pointer to a thermal zone
0129  * @trip:   trip point to evaluate
0130  *
0131  * This function is responsible for checking if passed trip point is valid
0132  *
0133  * Return: true if trip point is valid, false otherwise
0134  */
0135 bool of_thermal_is_trip_valid(struct thermal_zone_device *tz, int trip)
0136 {
0137     if (trip >= tz->num_trips || trip < 0)
0138         return false;
0139 
0140     return true;
0141 }
0142 EXPORT_SYMBOL_GPL(of_thermal_is_trip_valid);
0143 
0144 /**
0145  * of_thermal_get_trip_points - function to get access to a globally exported
0146  *              trip points
0147  *
0148  * @tz: pointer to a thermal zone
0149  *
0150  * This function provides a pointer to trip points table
0151  *
0152  * Return: pointer to trip points table, NULL otherwise
0153  */
0154 const struct thermal_trip *
0155 of_thermal_get_trip_points(struct thermal_zone_device *tz)
0156 {
0157     return tz->trips;
0158 }
0159 EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
0160 
0161 /**
0162  * of_thermal_set_emul_temp - function to set emulated temperature
0163  *
0164  * @tz: pointer to a thermal zone
0165  * @temp:   temperature to set
0166  *
0167  * This function gives the ability to set emulated value of temperature,
0168  * which is handy for debugging
0169  *
0170  * Return: zero on success, error code otherwise
0171  */
0172 static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
0173                     int temp)
0174 {
0175     struct __thermal_zone *data = tz->devdata;
0176 
0177     if (!data->ops || !data->ops->set_emul_temp)
0178         return -EINVAL;
0179 
0180     return data->ops->set_emul_temp(data->sensor_data, temp);
0181 }
0182 
0183 static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
0184                 enum thermal_trend *trend)
0185 {
0186     struct __thermal_zone *data = tz->devdata;
0187 
0188     if (!data->ops || !data->ops->get_trend)
0189         return -EINVAL;
0190 
0191     return data->ops->get_trend(data->sensor_data, trip, trend);
0192 }
0193 
0194 static int of_thermal_change_mode(struct thermal_zone_device *tz,
0195                 enum thermal_device_mode mode)
0196 {
0197     struct __thermal_zone *data = tz->devdata;
0198 
0199     return data->ops->change_mode(data->sensor_data, mode);
0200 }
0201 
0202 static int of_thermal_bind(struct thermal_zone_device *thermal,
0203                struct thermal_cooling_device *cdev)
0204 {
0205     struct __thermal_zone *data = thermal->devdata;
0206     struct __thermal_bind_params *tbp;
0207     struct __thermal_cooling_bind_param *tcbp;
0208     int i, j;
0209 
0210     if (!data || IS_ERR(data))
0211         return -ENODEV;
0212 
0213     /* find where to bind */
0214     for (i = 0; i < data->num_tbps; i++) {
0215         tbp = data->tbps + i;
0216 
0217         for (j = 0; j < tbp->count; j++) {
0218             tcbp = tbp->tcbp + j;
0219 
0220             if (tcbp->cooling_device == cdev->np) {
0221                 int ret;
0222 
0223                 ret = thermal_zone_bind_cooling_device(thermal,
0224                         tbp->trip_id, cdev,
0225                         tcbp->max,
0226                         tcbp->min,
0227                         tbp->usage);
0228                 if (ret)
0229                     return ret;
0230             }
0231         }
0232     }
0233 
0234     return 0;
0235 }
0236 
0237 static int of_thermal_unbind(struct thermal_zone_device *thermal,
0238                  struct thermal_cooling_device *cdev)
0239 {
0240     struct __thermal_zone *data = thermal->devdata;
0241     struct __thermal_bind_params *tbp;
0242     struct __thermal_cooling_bind_param *tcbp;
0243     int i, j;
0244 
0245     if (!data || IS_ERR(data))
0246         return -ENODEV;
0247 
0248     /* find where to unbind */
0249     for (i = 0; i < data->num_tbps; i++) {
0250         tbp = data->tbps + i;
0251 
0252         for (j = 0; j < tbp->count; j++) {
0253             tcbp = tbp->tcbp + j;
0254 
0255             if (tcbp->cooling_device == cdev->np) {
0256                 int ret;
0257 
0258                 ret = thermal_zone_unbind_cooling_device(thermal,
0259                             tbp->trip_id, cdev);
0260                 if (ret)
0261                     return ret;
0262             }
0263         }
0264     }
0265 
0266     return 0;
0267 }
0268 
0269 static int of_thermal_get_trip_type(struct thermal_zone_device *tz, int trip,
0270                     enum thermal_trip_type *type)
0271 {
0272     if (trip >= tz->num_trips || trip < 0)
0273         return -EDOM;
0274 
0275     *type = tz->trips[trip].type;
0276 
0277     return 0;
0278 }
0279 
0280 static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
0281                     int *temp)
0282 {
0283     if (trip >= tz->num_trips || trip < 0)
0284         return -EDOM;
0285 
0286     *temp = tz->trips[trip].temperature;
0287 
0288     return 0;
0289 }
0290 
0291 static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
0292                     int temp)
0293 {
0294     struct __thermal_zone *data = tz->devdata;
0295 
0296     if (trip >= tz->num_trips || trip < 0)
0297         return -EDOM;
0298 
0299     if (data->ops && data->ops->set_trip_temp) {
0300         int ret;
0301 
0302         ret = data->ops->set_trip_temp(data->sensor_data, trip, temp);
0303         if (ret)
0304             return ret;
0305     }
0306 
0307     /* thermal framework should take care of data->mask & (1 << trip) */
0308     tz->trips[trip].temperature = temp;
0309 
0310     return 0;
0311 }
0312 
0313 static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
0314                     int *hyst)
0315 {
0316     if (trip >= tz->num_trips || trip < 0)
0317         return -EDOM;
0318 
0319     *hyst = tz->trips[trip].hysteresis;
0320 
0321     return 0;
0322 }
0323 
0324 static int of_thermal_set_trip_hyst(struct thermal_zone_device *tz, int trip,
0325                     int hyst)
0326 {
0327     if (trip >= tz->num_trips || trip < 0)
0328         return -EDOM;
0329 
0330     /* thermal framework should take care of data->mask & (1 << trip) */
0331     tz->trips[trip].hysteresis = hyst;
0332 
0333     return 0;
0334 }
0335 
0336 static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
0337                     int *temp)
0338 {
0339     int i;
0340 
0341     for (i = 0; i < tz->num_trips; i++)
0342         if (tz->trips[i].type == THERMAL_TRIP_CRITICAL) {
0343             *temp = tz->trips[i].temperature;
0344             return 0;
0345         }
0346 
0347     return -EINVAL;
0348 }
0349 
0350 static struct thermal_zone_device_ops of_thermal_ops = {
0351     .get_trip_type = of_thermal_get_trip_type,
0352     .get_trip_temp = of_thermal_get_trip_temp,
0353     .set_trip_temp = of_thermal_set_trip_temp,
0354     .get_trip_hyst = of_thermal_get_trip_hyst,
0355     .set_trip_hyst = of_thermal_set_trip_hyst,
0356     .get_crit_temp = of_thermal_get_crit_temp,
0357 
0358     .bind = of_thermal_bind,
0359     .unbind = of_thermal_unbind,
0360 };
0361 
0362 /***   sensor API   ***/
0363 
0364 static struct thermal_zone_device *
0365 thermal_zone_of_add_sensor(struct device_node *zone,
0366                struct device_node *sensor, void *data,
0367                const struct thermal_zone_of_device_ops *ops)
0368 {
0369     struct thermal_zone_device *tzd;
0370     struct __thermal_zone *tz;
0371 
0372     tzd = thermal_zone_get_zone_by_name(zone->name);
0373     if (IS_ERR(tzd))
0374         return ERR_PTR(-EPROBE_DEFER);
0375 
0376     tz = tzd->devdata;
0377 
0378     if (!ops)
0379         return ERR_PTR(-EINVAL);
0380 
0381     mutex_lock(&tzd->lock);
0382     tz->ops = ops;
0383     tz->sensor_data = data;
0384 
0385     tzd->ops->get_temp = of_thermal_get_temp;
0386     tzd->ops->get_trend = of_thermal_get_trend;
0387 
0388     /*
0389      * The thermal zone core will calculate the window if they have set the
0390      * optional set_trips pointer.
0391      */
0392     if (ops->set_trips)
0393         tzd->ops->set_trips = of_thermal_set_trips;
0394 
0395     if (ops->set_emul_temp)
0396         tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
0397 
0398     if (ops->change_mode)
0399         tzd->ops->change_mode = of_thermal_change_mode;
0400 
0401     mutex_unlock(&tzd->lock);
0402 
0403     return tzd;
0404 }
0405 
0406 /**
0407  * thermal_zone_of_get_sensor_id - get sensor ID from a DT thermal zone
0408  * @tz_np: a valid thermal zone device node.
0409  * @sensor_np: a sensor node of a valid sensor device.
0410  * @id: the sensor ID returned if success.
0411  *
0412  * This function will get sensor ID from a given thermal zone node and
0413  * the sensor node must match the temperature provider @sensor_np.
0414  *
0415  * Return: 0 on success, proper error code otherwise.
0416  */
0417 
0418 int thermal_zone_of_get_sensor_id(struct device_node *tz_np,
0419                   struct device_node *sensor_np,
0420                   u32 *id)
0421 {
0422     struct of_phandle_args sensor_specs;
0423     int ret;
0424 
0425     ret = of_parse_phandle_with_args(tz_np,
0426                      "thermal-sensors",
0427                      "#thermal-sensor-cells",
0428                      0,
0429                      &sensor_specs);
0430     if (ret)
0431         return ret;
0432 
0433     if (sensor_specs.np != sensor_np) {
0434         of_node_put(sensor_specs.np);
0435         return -ENODEV;
0436     }
0437 
0438     if (sensor_specs.args_count > 1)
0439         pr_warn("%pOFn: too many cells in sensor specifier %d\n",
0440              sensor_specs.np, sensor_specs.args_count);
0441 
0442     *id = sensor_specs.args_count ? sensor_specs.args[0] : 0;
0443 
0444     of_node_put(sensor_specs.np);
0445 
0446     return 0;
0447 }
0448 EXPORT_SYMBOL_GPL(thermal_zone_of_get_sensor_id);
0449 
0450 /**
0451  * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
0452  * @dev: a valid struct device pointer of a sensor device. Must contain
0453  *       a valid .of_node, for the sensor node.
0454  * @sensor_id: a sensor identifier, in case the sensor IP has more
0455  *             than one sensors
0456  * @data: a private pointer (owned by the caller) that will be passed
0457  *        back, when a temperature reading is needed.
0458  * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.
0459  *
0460  * This function will search the list of thermal zones described in device
0461  * tree and look for the zone that refer to the sensor device pointed by
0462  * @dev->of_node as temperature providers. For the zone pointing to the
0463  * sensor node, the sensor will be added to the DT thermal zone device.
0464  *
0465  * The thermal zone temperature is provided by the @get_temp function
0466  * pointer. When called, it will have the private pointer @data back.
0467  *
0468  * The thermal zone temperature trend is provided by the @get_trend function
0469  * pointer. When called, it will have the private pointer @data back.
0470  *
0471  * TODO:
0472  * 01 - This function must enqueue the new sensor instead of using
0473  * it as the only source of temperature values.
0474  *
0475  * 02 - There must be a way to match the sensor with all thermal zones
0476  * that refer to it.
0477  *
0478  * Return: On success returns a valid struct thermal_zone_device,
0479  * otherwise, it returns a corresponding ERR_PTR(). Caller must
0480  * check the return value with help of IS_ERR() helper.
0481  */
0482 struct thermal_zone_device *
0483 thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
0484                 const struct thermal_zone_of_device_ops *ops)
0485 {
0486     struct device_node *np, *child, *sensor_np;
0487     struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
0488 
0489     np = of_find_node_by_name(NULL, "thermal-zones");
0490     if (!np)
0491         return ERR_PTR(-ENODEV);
0492 
0493     if (!dev || !dev->of_node) {
0494         of_node_put(np);
0495         return ERR_PTR(-ENODEV);
0496     }
0497 
0498     sensor_np = of_node_get(dev->of_node);
0499 
0500     for_each_available_child_of_node(np, child) {
0501         int ret, id;
0502 
0503         /* For now, thermal framework supports only 1 sensor per zone */
0504         ret = thermal_zone_of_get_sensor_id(child, sensor_np, &id);
0505         if (ret)
0506             continue;
0507 
0508         if (id == sensor_id) {
0509             tzd = thermal_zone_of_add_sensor(child, sensor_np,
0510                              data, ops);
0511             if (!IS_ERR(tzd))
0512                 thermal_zone_device_enable(tzd);
0513 
0514             of_node_put(child);
0515             goto exit;
0516         }
0517     }
0518 exit:
0519     of_node_put(sensor_np);
0520     of_node_put(np);
0521 
0522     return tzd;
0523 }
0524 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_register);
0525 
0526 /**
0527  * thermal_zone_of_sensor_unregister - unregisters a sensor from a DT thermal zone
0528  * @dev: a valid struct device pointer of a sensor device. Must contain
0529  *       a valid .of_node, for the sensor node.
0530  * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
0531  *
0532  * This function removes the sensor callbacks and private data from the
0533  * thermal zone device registered with thermal_zone_of_sensor_register()
0534  * API. It will also silent the zone by remove the .get_temp() and .get_trend()
0535  * thermal zone device callbacks.
0536  *
0537  * TODO: When the support to several sensors per zone is added, this
0538  * function must search the sensor list based on @dev parameter.
0539  *
0540  */
0541 void thermal_zone_of_sensor_unregister(struct device *dev,
0542                        struct thermal_zone_device *tzd)
0543 {
0544     struct __thermal_zone *tz;
0545 
0546     if (!dev || !tzd || !tzd->devdata)
0547         return;
0548 
0549     tz = tzd->devdata;
0550 
0551     /* no __thermal_zone, nothing to be done */
0552     if (!tz)
0553         return;
0554 
0555     /* stop temperature polling */
0556     thermal_zone_device_disable(tzd);
0557 
0558     mutex_lock(&tzd->lock);
0559     tzd->ops->get_temp = NULL;
0560     tzd->ops->get_trend = NULL;
0561     tzd->ops->set_emul_temp = NULL;
0562     tzd->ops->change_mode = NULL;
0563 
0564     tz->ops = NULL;
0565     tz->sensor_data = NULL;
0566     mutex_unlock(&tzd->lock);
0567 }
0568 EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
0569 
0570 static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res)
0571 {
0572     thermal_zone_of_sensor_unregister(dev,
0573                       *(struct thermal_zone_device **)res);
0574 }
0575 
0576 static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res,
0577                          void *data)
0578 {
0579     struct thermal_zone_device **r = res;
0580 
0581     if (WARN_ON(!r || !*r))
0582         return 0;
0583 
0584     return *r == data;
0585 }
0586 
0587 /**
0588  * devm_thermal_zone_of_sensor_register - Resource managed version of
0589  *              thermal_zone_of_sensor_register()
0590  * @dev: a valid struct device pointer of a sensor device. Must contain
0591  *       a valid .of_node, for the sensor node.
0592  * @sensor_id: a sensor identifier, in case the sensor IP has more
0593  *         than one sensors
0594  * @data: a private pointer (owned by the caller) that will be passed
0595  *    back, when a temperature reading is needed.
0596  * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.
0597  *
0598  * Refer thermal_zone_of_sensor_register() for more details.
0599  *
0600  * Return: On success returns a valid struct thermal_zone_device,
0601  * otherwise, it returns a corresponding ERR_PTR(). Caller must
0602  * check the return value with help of IS_ERR() helper.
0603  * Registered thermal_zone_device device will automatically be
0604  * released when device is unbounded.
0605  */
0606 struct thermal_zone_device *devm_thermal_zone_of_sensor_register(
0607     struct device *dev, int sensor_id,
0608     void *data, const struct thermal_zone_of_device_ops *ops)
0609 {
0610     struct thermal_zone_device **ptr, *tzd;
0611 
0612     ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr),
0613                GFP_KERNEL);
0614     if (!ptr)
0615         return ERR_PTR(-ENOMEM);
0616 
0617     tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops);
0618     if (IS_ERR(tzd)) {
0619         devres_free(ptr);
0620         return tzd;
0621     }
0622 
0623     *ptr = tzd;
0624     devres_add(dev, ptr);
0625 
0626     return tzd;
0627 }
0628 EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register);
0629 
0630 /**
0631  * devm_thermal_zone_of_sensor_unregister - Resource managed version of
0632  *              thermal_zone_of_sensor_unregister().
0633  * @dev: Device for which which resource was allocated.
0634  * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
0635  *
0636  * This function removes the sensor callbacks and private data from the
0637  * thermal zone device registered with devm_thermal_zone_of_sensor_register()
0638  * API. It will also silent the zone by remove the .get_temp() and .get_trend()
0639  * thermal zone device callbacks.
0640  * Normally this function will not need to be called and the resource
0641  * management code will ensure that the resource is freed.
0642  */
0643 void devm_thermal_zone_of_sensor_unregister(struct device *dev,
0644                         struct thermal_zone_device *tzd)
0645 {
0646     WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release,
0647                    devm_thermal_zone_of_sensor_match, tzd));
0648 }
0649 EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister);
0650 
0651 /***   functions parsing device tree nodes   ***/
0652 
0653 static int of_find_trip_id(struct device_node *np, struct device_node *trip)
0654 {
0655     struct device_node *trips;
0656     struct device_node *t;
0657     int i = 0;
0658 
0659     trips = of_get_child_by_name(np, "trips");
0660     if (!trips) {
0661         pr_err("Failed to find 'trips' node\n");
0662         return -EINVAL;
0663     }
0664 
0665     /*
0666      * Find the trip id point associated with the cooling device map
0667      */
0668     for_each_child_of_node(trips, t) {
0669 
0670         if (t == trip)
0671             goto out;
0672         i++;
0673     }
0674 
0675     i = -ENXIO;
0676 out:
0677     of_node_put(trips);
0678 
0679     return i;
0680 }
0681 
0682 /**
0683  * thermal_of_populate_bind_params - parse and fill cooling map data
0684  * @np: DT node containing a cooling-map node
0685  * @__tbp: data structure to be filled with cooling map info
0686  * @trips: array of thermal zone trip points
0687  * @ntrips: number of trip points inside trips.
0688  *
0689  * This function parses a cooling-map type of node represented by
0690  * @np parameter and fills the read data into @__tbp data structure.
0691  * It needs the already parsed array of trip points of the thermal zone
0692  * in consideration.
0693  *
0694  * Return: 0 on success, proper error code otherwise
0695  */
0696 static int thermal_of_populate_bind_params(struct device_node *tz_np,
0697                        struct device_node *np,
0698                        struct __thermal_bind_params *__tbp)
0699 {
0700     struct of_phandle_args cooling_spec;
0701     struct __thermal_cooling_bind_param *__tcbp;
0702     struct device_node *trip;
0703     int ret, i, count;
0704     int trip_id;
0705     u32 prop;
0706 
0707     /* Default weight. Usage is optional */
0708     __tbp->usage = THERMAL_WEIGHT_DEFAULT;
0709     ret = of_property_read_u32(np, "contribution", &prop);
0710     if (ret == 0)
0711         __tbp->usage = prop;
0712 
0713     trip = of_parse_phandle(np, "trip", 0);
0714     if (!trip) {
0715         pr_err("missing trip property\n");
0716         return -ENODEV;
0717     }
0718 
0719     trip_id = of_find_trip_id(tz_np, trip);
0720     if (trip_id < 0) {
0721         ret = trip_id;
0722         goto end;
0723     }
0724 
0725     __tbp->trip_id = trip_id;
0726 
0727     count = of_count_phandle_with_args(np, "cooling-device",
0728                        "#cooling-cells");
0729     if (count <= 0) {
0730         pr_err("Add a cooling_device property with at least one device\n");
0731         ret = -ENOENT;
0732         goto end;
0733     }
0734 
0735     __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL);
0736     if (!__tcbp) {
0737         ret = -ENOMEM;
0738         goto end;
0739     }
0740 
0741     for (i = 0; i < count; i++) {
0742         ret = of_parse_phandle_with_args(np, "cooling-device",
0743                 "#cooling-cells", i, &cooling_spec);
0744         if (ret < 0) {
0745             pr_err("Invalid cooling-device entry\n");
0746             goto free_tcbp;
0747         }
0748 
0749         __tcbp[i].cooling_device = cooling_spec.np;
0750 
0751         if (cooling_spec.args_count >= 2) { /* at least min and max */
0752             __tcbp[i].min = cooling_spec.args[0];
0753             __tcbp[i].max = cooling_spec.args[1];
0754         } else {
0755             pr_err("wrong reference to cooling device, missing limits\n");
0756         }
0757     }
0758 
0759     __tbp->tcbp = __tcbp;
0760     __tbp->count = count;
0761 
0762     goto end;
0763 
0764 free_tcbp:
0765     for (i = i - 1; i >= 0; i--)
0766         of_node_put(__tcbp[i].cooling_device);
0767     kfree(__tcbp);
0768 end:
0769     of_node_put(trip);
0770 
0771     return ret;
0772 }
0773 
0774 /*
0775  * It maps 'enum thermal_trip_type' found in include/linux/thermal.h
0776  * into the device tree binding of 'trip', property type.
0777  */
0778 static const char * const trip_types[] = {
0779     [THERMAL_TRIP_ACTIVE]   = "active",
0780     [THERMAL_TRIP_PASSIVE]  = "passive",
0781     [THERMAL_TRIP_HOT]  = "hot",
0782     [THERMAL_TRIP_CRITICAL] = "critical",
0783 };
0784 
0785 /**
0786  * thermal_of_get_trip_type - Get phy mode for given device_node
0787  * @np: Pointer to the given device_node
0788  * @type: Pointer to resulting trip type
0789  *
0790  * The function gets trip type string from property 'type',
0791  * and store its index in trip_types table in @type,
0792  *
0793  * Return: 0 on success, or errno in error case.
0794  */
0795 static int thermal_of_get_trip_type(struct device_node *np,
0796                     enum thermal_trip_type *type)
0797 {
0798     const char *t;
0799     int err, i;
0800 
0801     err = of_property_read_string(np, "type", &t);
0802     if (err < 0)
0803         return err;
0804 
0805     for (i = 0; i < ARRAY_SIZE(trip_types); i++)
0806         if (!strcasecmp(t, trip_types[i])) {
0807             *type = i;
0808             return 0;
0809         }
0810 
0811     return -ENODEV;
0812 }
0813 
0814 /**
0815  * thermal_of_populate_trip - parse and fill one trip point data
0816  * @np: DT node containing a trip point node
0817  * @trip: trip point data structure to be filled up
0818  *
0819  * This function parses a trip point type of node represented by
0820  * @np parameter and fills the read data into @trip data structure.
0821  *
0822  * Return: 0 on success, proper error code otherwise
0823  */
0824 static int thermal_of_populate_trip(struct device_node *np,
0825                     struct thermal_trip *trip)
0826 {
0827     int prop;
0828     int ret;
0829 
0830     ret = of_property_read_u32(np, "temperature", &prop);
0831     if (ret < 0) {
0832         pr_err("missing temperature property\n");
0833         return ret;
0834     }
0835     trip->temperature = prop;
0836 
0837     ret = of_property_read_u32(np, "hysteresis", &prop);
0838     if (ret < 0) {
0839         pr_err("missing hysteresis property\n");
0840         return ret;
0841     }
0842     trip->hysteresis = prop;
0843 
0844     ret = thermal_of_get_trip_type(np, &trip->type);
0845     if (ret < 0) {
0846         pr_err("wrong trip type property\n");
0847         return ret;
0848     }
0849 
0850     return 0;
0851 }
0852 
0853 static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *ntrips)
0854 {
0855     struct thermal_trip *tt;
0856     struct device_node *trips, *trip;
0857     int ret, count;
0858 
0859     trips = of_get_child_by_name(np, "trips");
0860     if (!trips) {
0861         pr_err("Failed to find 'trips' node\n");
0862         return ERR_PTR(-EINVAL);
0863     }
0864 
0865     count = of_get_child_count(trips);
0866     if (!count) {
0867         pr_err("No trip point defined\n");
0868         ret = -EINVAL;
0869         goto out_of_node_put;
0870     }
0871 
0872     tt = kzalloc(sizeof(*tt) * count, GFP_KERNEL);
0873     if (!tt) {
0874         ret = -ENOMEM;
0875         goto out_of_node_put;
0876     }
0877 
0878     *ntrips = count;
0879 
0880     count = 0;
0881     for_each_child_of_node(trips, trip) {
0882         ret = thermal_of_populate_trip(trip, &tt[count++]);
0883         if (ret)
0884             goto out_kfree;
0885     }
0886 
0887     of_node_put(trips);
0888 
0889     return tt;
0890 
0891 out_kfree:
0892     kfree(tt);
0893     *ntrips = 0;
0894 out_of_node_put:
0895     of_node_put(trips);
0896 
0897     return ERR_PTR(ret);
0898 }
0899 
0900 /**
0901  * thermal_of_build_thermal_zone - parse and fill one thermal zone data
0902  * @np: DT node containing a thermal zone node
0903  *
0904  * This function parses a thermal zone type of node represented by
0905  * @np parameter and fills the read data into a __thermal_zone data structure
0906  * and return this pointer.
0907  *
0908  * TODO: Missing properties to parse: thermal-sensor-names
0909  *
0910  * Return: On success returns a valid struct __thermal_zone,
0911  * otherwise, it returns a corresponding ERR_PTR(). Caller must
0912  * check the return value with help of IS_ERR() helper.
0913  */
0914 static struct __thermal_zone
0915 __init *thermal_of_build_thermal_zone(struct device_node *np)
0916 {
0917     struct device_node *child = NULL, *gchild;
0918     struct __thermal_zone *tz;
0919     int ret, i;
0920     u32 prop, coef[2];
0921 
0922     if (!np) {
0923         pr_err("no thermal zone np\n");
0924         return ERR_PTR(-EINVAL);
0925     }
0926 
0927     tz = kzalloc(sizeof(*tz), GFP_KERNEL);
0928     if (!tz)
0929         return ERR_PTR(-ENOMEM);
0930 
0931     ret = of_property_read_u32(np, "polling-delay-passive", &prop);
0932     if (ret < 0) {
0933         pr_err("%pOFn: missing polling-delay-passive property\n", np);
0934         goto free_tz;
0935     }
0936     tz->passive_delay = prop;
0937 
0938     ret = of_property_read_u32(np, "polling-delay", &prop);
0939     if (ret < 0) {
0940         pr_err("%pOFn: missing polling-delay property\n", np);
0941         goto free_tz;
0942     }
0943     tz->polling_delay = prop;
0944 
0945     /*
0946      * REVIST: for now, the thermal framework supports only
0947      * one sensor per thermal zone. Thus, we are considering
0948      * only the first two values as slope and offset.
0949      */
0950     ret = of_property_read_u32_array(np, "coefficients", coef, 2);
0951     if (ret == 0) {
0952         tz->slope = coef[0];
0953         tz->offset = coef[1];
0954     } else {
0955         tz->slope = 1;
0956         tz->offset = 0;
0957     }
0958 
0959     tz->trips = thermal_of_trips_init(np, &tz->ntrips);
0960     if (IS_ERR(tz->trips)) {
0961         ret = PTR_ERR(tz->trips);
0962         goto finish;
0963     }
0964 
0965     /* cooling-maps */
0966     child = of_get_child_by_name(np, "cooling-maps");
0967 
0968     /* cooling-maps not provided */
0969     if (!child)
0970         goto finish;
0971 
0972     tz->num_tbps = of_get_child_count(child);
0973     if (tz->num_tbps == 0)
0974         goto finish;
0975 
0976     tz->tbps = kcalloc(tz->num_tbps, sizeof(*tz->tbps), GFP_KERNEL);
0977     if (!tz->tbps) {
0978         ret = -ENOMEM;
0979         goto free_trips;
0980     }
0981 
0982     i = 0;
0983     for_each_child_of_node(child, gchild) {
0984         ret = thermal_of_populate_bind_params(np, gchild, &tz->tbps[i++]);
0985         if (ret) {
0986             of_node_put(gchild);
0987             goto free_tbps;
0988         }
0989     }
0990 
0991 finish:
0992     of_node_put(child);
0993 
0994     return tz;
0995 
0996 free_tbps:
0997     for (i = i - 1; i >= 0; i--) {
0998         struct __thermal_bind_params *tbp = tz->tbps + i;
0999         int j;
1000 
1001         for (j = 0; j < tbp->count; j++)
1002             of_node_put(tbp->tcbp[j].cooling_device);
1003 
1004         kfree(tbp->tcbp);
1005     }
1006 
1007     kfree(tz->tbps);
1008 free_trips:
1009     kfree(tz->trips);
1010 free_tz:
1011     kfree(tz);
1012     of_node_put(child);
1013 
1014     return ERR_PTR(ret);
1015 }
1016 
1017 static __init void of_thermal_free_zone(struct __thermal_zone *tz)
1018 {
1019     struct __thermal_bind_params *tbp;
1020     int i, j;
1021 
1022     for (i = 0; i < tz->num_tbps; i++) {
1023         tbp = tz->tbps + i;
1024 
1025         for (j = 0; j < tbp->count; j++)
1026             of_node_put(tbp->tcbp[j].cooling_device);
1027 
1028         kfree(tbp->tcbp);
1029     }
1030 
1031     kfree(tz->tbps);
1032     kfree(tz->trips);
1033     kfree(tz);
1034 }
1035 
1036 /**
1037  * of_thermal_destroy_zones - remove all zones parsed and allocated resources
1038  *
1039  * Finds all zones parsed and added to the thermal framework and remove them
1040  * from the system, together with their resources.
1041  *
1042  */
1043 static __init void of_thermal_destroy_zones(void)
1044 {
1045     struct device_node *np, *child;
1046 
1047     np = of_find_node_by_name(NULL, "thermal-zones");
1048     if (!np) {
1049         pr_debug("unable to find thermal zones\n");
1050         return;
1051     }
1052 
1053     for_each_available_child_of_node(np, child) {
1054         struct thermal_zone_device *zone;
1055 
1056         zone = thermal_zone_get_zone_by_name(child->name);
1057         if (IS_ERR(zone))
1058             continue;
1059 
1060         thermal_zone_device_unregister(zone);
1061         kfree(zone->tzp);
1062         kfree(zone->ops);
1063         of_thermal_free_zone(zone->devdata);
1064     }
1065     of_node_put(np);
1066 }
1067 
1068 /**
1069  * of_parse_thermal_zones - parse device tree thermal data
1070  *
1071  * Initialization function that can be called by machine initialization
1072  * code to parse thermal data and populate the thermal framework
1073  * with hardware thermal zones info. This function only parses thermal zones.
1074  * Cooling devices and sensor devices nodes are supposed to be parsed
1075  * by their respective drivers.
1076  *
1077  * Return: 0 on success, proper error code otherwise
1078  *
1079  */
1080 int __init of_parse_thermal_zones(void)
1081 {
1082     struct device_node *np, *child;
1083     struct __thermal_zone *tz;
1084     struct thermal_zone_device_ops *ops;
1085 
1086     np = of_find_node_by_name(NULL, "thermal-zones");
1087     if (!np) {
1088         pr_debug("unable to find thermal zones\n");
1089         return 0; /* Run successfully on systems without thermal DT */
1090     }
1091 
1092     for_each_available_child_of_node(np, child) {
1093         struct thermal_zone_device *zone;
1094         struct thermal_zone_params *tzp;
1095         int i, mask = 0;
1096         u32 prop;
1097 
1098         tz = thermal_of_build_thermal_zone(child);
1099         if (IS_ERR(tz)) {
1100             pr_err("failed to build thermal zone %pOFn: %ld\n",
1101                    child,
1102                    PTR_ERR(tz));
1103             continue;
1104         }
1105 
1106         ops = kmemdup(&of_thermal_ops, sizeof(*ops), GFP_KERNEL);
1107         if (!ops)
1108             goto exit_free;
1109 
1110         tzp = kzalloc(sizeof(*tzp), GFP_KERNEL);
1111         if (!tzp) {
1112             kfree(ops);
1113             goto exit_free;
1114         }
1115 
1116         /* No hwmon because there might be hwmon drivers registering */
1117         tzp->no_hwmon = true;
1118 
1119         if (!of_property_read_u32(child, "sustainable-power", &prop))
1120             tzp->sustainable_power = prop;
1121 
1122         for (i = 0; i < tz->ntrips; i++)
1123             mask |= 1 << i;
1124 
1125         /* these two are left for temperature drivers to use */
1126         tzp->slope = tz->slope;
1127         tzp->offset = tz->offset;
1128 
1129         zone = thermal_zone_device_register_with_trips(child->name, tz->trips, tz->ntrips,
1130                                    mask, tz, ops, tzp, tz->passive_delay,
1131                                    tz->polling_delay);
1132         if (IS_ERR(zone)) {
1133             pr_err("Failed to build %pOFn zone %ld\n", child,
1134                    PTR_ERR(zone));
1135             kfree(tzp);
1136             kfree(ops);
1137             of_thermal_free_zone(tz);
1138             /* attempting to build remaining zones still */
1139         }
1140     }
1141     of_node_put(np);
1142 
1143     return 0;
1144 
1145 exit_free:
1146     of_node_put(child);
1147     of_node_put(np);
1148     of_thermal_free_zone(tz);
1149 
1150     /* no memory available, so free what we have built */
1151     of_thermal_destroy_zones();
1152 
1153     return -ENOMEM;
1154 }