cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

thermal_of.c (28717B)


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