Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b492c607 authored by Ram Chandrasekar's avatar Ram Chandrasekar
Browse files

drivers: thermal: of-thermal: Add a snapshot of of-thermal



This is a snapshot of the thermal framework from msm-4.19 to msm-5.4
as of 'commit <f6559eba09482b9dc66279c72c8867a52f23498c>
(drivers: thermal: Use correct last temperature during trip violation
check)'.

Change-Id: I1618ee42e5948da7e3e02b0fe4b8b5650f1c7447
Signed-off-by: default avatarRam Chandrasekar <rkumbako@codeaurora.org>
parent e836a8ac
Loading
Loading
Loading
Loading
+632 −6
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 *
 *  Copyright (C) 2013 Texas Instruments
 *  Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
 *  Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -16,6 +17,7 @@
#include <linux/err.h>
#include <linux/export.h>
#include <linux/string.h>
#include <linux/list.h>

#include "thermal_core.h"

@@ -49,6 +51,104 @@ struct __thermal_bind_params {
	unsigned int usage;
};

#ifdef CONFIG_QTI_THERMAL
/**
 * struct __sensor_param - Holds individual sensor data
 * @sensor_data: sensor driver private data passed as input argument
 * @ops: sensor driver ops
 * @trip_high: last trip high value programmed in the sensor driver
 * @trip_low: last trip low value programmed in the sensor driver
 * @lock: mutex lock acquired before updating the trip temperatures
 * @first_tz: list head pointing the first thermal zone
 */
struct __sensor_param {
	void *sensor_data;
	const struct thermal_zone_of_device_ops *ops;
	int trip_high, trip_low;
	struct mutex lock;
	struct list_head first_tz;
};

/**
 * struct __thermal_zone - internal representation of a thermal zone
 * @mode: current thermal zone device mode (enabled/disabled)
 * @passive_delay: polling interval while passive cooling is activated
 * @polling_delay: zone polling interval
 * @slope: slope of the temperature adjustment curve
 * @offset: offset of the temperature adjustment curve
 * @ntrips: number of trip points
 * @trips: an array of trip points (0..ntrips - 1)
 * @num_tbps: number of thermal bind params
 * @tbps: an array of thermal bind params (0..num_tbps - 1)
 * @default_disable: Keep the thermal zone disabled by default
 * @tzd: thermal zone device pointer for this sensor
 * @list: sibling thermal zone pointer
 * @senps: sensor related parameters
 */

struct __thermal_zone {
	enum thermal_device_mode mode;
	int passive_delay;
	int polling_delay;
	int slope;
	int offset;

	/* trip data */
	int ntrips;
	struct thermal_trip *trips;

	/* cooling binding data */
	int num_tbps;
	struct __thermal_bind_params *tbps;

	struct thermal_zone_device *tzd;
	bool default_disable;
	struct list_head list;
	/* sensor interface */
	struct __sensor_param *senps;
};

static int of_thermal_aggregate_trip_types(struct thermal_zone_device *tz,
		unsigned int trip_type_mask, int *low, int *high);

/***   DT thermal zone device callbacks   ***/

static int of_thermal_get_temp(struct thermal_zone_device *tz,
			       int *temp)
{
	struct __thermal_zone *data = tz->devdata;

	if (!data->senps || !data->senps->ops->get_temp)
		return -EINVAL;
	if (data->mode == THERMAL_DEVICE_DISABLED) {
		*temp = THERMAL_TEMP_INVALID;
		return 0;
	}

	return data->senps->ops->get_temp(data->senps->sensor_data, temp);
}

static int of_thermal_set_trips(struct thermal_zone_device *tz,
				int inp_low, int inp_high)
{
	struct __thermal_zone *data = tz->devdata;
	int high = INT_MAX, low = INT_MIN, ret = 0;

	if (!data->senps || !data->senps->ops->set_trips)
		return -EINVAL;

	mutex_lock(&data->senps->lock);
	of_thermal_aggregate_trip_types(tz, GENMASK(THERMAL_TRIP_CRITICAL, 0),
					&low, &high);
	data->senps->trip_low = low;
	data->senps->trip_high = high;
	ret = data->senps->ops->set_trips(data->senps->sensor_data,
					  low, high);

	mutex_unlock(&data->senps->lock);
	return ret;
}
#else
/**
 * struct __thermal_zone - internal representation of a thermal zone
 * @mode: current thermal zone device mode (enabled/disabled)
@@ -107,7 +207,7 @@ static int of_thermal_set_trips(struct thermal_zone_device *tz,

	return data->ops->set_trips(data->sensor_data, low, high);
}

#endif
/**
 * of_thermal_get_ntrips - function to export number of available trip
 *			   points.
@@ -183,6 +283,30 @@ EXPORT_SYMBOL_GPL(of_thermal_get_trip_points);
 *
 * Return: zero on success, error code otherwise
 */
#ifdef CONFIG_QTI_THERMAL
static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
				    int temp)
{
	struct __thermal_zone *data = tz->devdata;

	if (!data->senps || !data->senps->ops->set_emul_temp)
		return -EINVAL;

	return data->senps->ops->set_emul_temp(data->senps->sensor_data, temp);
}

static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
				enum thermal_trend *trend)
{
	struct __thermal_zone *data = tz->devdata;

	if (!data->senps || !data->senps->ops->get_trend)
		return -EINVAL;

	return data->senps->ops->get_trend(data->senps->sensor_data,
					   trip, trend);
}
#else
static int of_thermal_set_emul_temp(struct thermal_zone_device *tz,
				    int temp)
{
@@ -201,6 +325,7 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,

	return data->ops->get_trend(data->sensor_data, trip, trend);
}
#endif

static int of_thermal_bind(struct thermal_zone_device *thermal,
			   struct thermal_cooling_device *cdev)
@@ -328,6 +453,30 @@ static int of_thermal_get_trip_temp(struct thermal_zone_device *tz, int trip,
	return 0;
}

#ifdef CONFIG_QTI_THERMAL
static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
				    int temp)
{
	struct __thermal_zone *data = tz->devdata;

	if (trip >= data->ntrips || trip < 0)
		return -EDOM;

	if (data->senps && data->senps->ops->set_trip_temp) {
		int ret;

		ret = data->senps->ops->set_trip_temp(data->senps->sensor_data,
						      trip, temp);
		if (ret)
			return ret;
	}

	/* thermal framework should take care of data->mask & (1 << trip) */
	data->trips[trip].temperature = temp;

	return 0;
}
#else
static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,
				    int temp)
{
@@ -349,6 +498,7 @@ static int of_thermal_set_trip_temp(struct thermal_zone_device *tz, int trip,

	return 0;
}
#endif

static int of_thermal_get_trip_hyst(struct thermal_zone_device *tz, int trip,
				    int *hyst)
@@ -392,6 +542,139 @@ static int of_thermal_get_crit_temp(struct thermal_zone_device *tz,
	return -EINVAL;
}

#ifdef CONFIG_QTI_THERMAL
static int of_thermal_aggregate_trip_types(struct thermal_zone_device *tz,
		unsigned int trip_type_mask, int *low, int *high)
{
	int min = INT_MIN;
	int max = INT_MAX;
	int tt, th, trip;
	int temp = tz->temperature;
	struct thermal_zone_device *zone = NULL;
	struct __thermal_zone *data = tz->devdata;
	struct list_head *head;
	enum thermal_trip_type type = 0;

	head = &data->senps->first_tz;
	list_for_each_entry(data, head, list) {
		zone = data->tzd;
		if (data->mode == THERMAL_DEVICE_DISABLED)
			continue;
		for (trip = 0; trip < data->ntrips; trip++) {
			of_thermal_get_trip_type(zone, trip, &type);
			if (!(BIT(type) & trip_type_mask))
				continue;

			tt = data->trips[trip].temperature;
			if (tt > temp && tt < max)
				max = tt;
			th = tt - data->trips[trip].hysteresis;
			if (th < temp && th > min)
				min = th;
		}
	}

	*high = max;
	*low = min;

	return 0;
}

static bool of_thermal_is_trips_triggered(struct thermal_zone_device *tz,
		int temp)
{
	int tt, th, trip, last_temp;
	struct __thermal_zone *data = tz->devdata;
	bool triggered = false;

	mutex_lock(&tz->lock);
	last_temp = tz->temperature;
	for (trip = 0; trip < data->ntrips; trip++) {
		tt = data->trips[trip].temperature;
		if (temp >= tt && last_temp < tt) {
			triggered = true;
			break;
		}
		th = tt - data->trips[trip].hysteresis;
		if (temp <= th && last_temp > th) {
			triggered = true;
			break;
		}
	}
	mutex_unlock(&tz->lock);

	return triggered;
}

static void handle_thermal_trip(struct thermal_zone_device *tz,
		bool temp_valid, int trip_temp)
{
	struct thermal_zone_device *zone;
	struct __thermal_zone *data = tz->devdata;
	struct list_head *head;

	head = &data->senps->first_tz;
	list_for_each_entry(data, head, list) {
		zone = data->tzd;
		if (data->mode == THERMAL_DEVICE_DISABLED)
			continue;
		if (!temp_valid) {
			thermal_zone_device_update(zone,
				THERMAL_EVENT_UNSPECIFIED);
		} else {
			if (!of_thermal_is_trips_triggered(zone, trip_temp))
				continue;
			thermal_zone_device_update_temp(zone,
				THERMAL_EVENT_UNSPECIFIED, trip_temp);
		}
	}
}

/*
 * of_thermal_aggregate_trip - aggregate trip temperatures across sibling
 *				thermal zones.
 * @tz: pointer to the primary thermal zone.
 * @type: the thermal trip type to be aggregated upon
 * @low: the low trip threshold which the most lesser than the @temp
 * @high: the high trip threshold which is the least greater than the @temp
 */
int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
				enum thermal_trip_type type,
				int *low, int *high)
{
	if (type <= THERMAL_TRIP_CRITICAL)
		return of_thermal_aggregate_trip_types(tz, BIT(type), low,
						       high);

	return -EINVAL;
}
EXPORT_SYMBOL(of_thermal_aggregate_trip);

/*
 * of_thermal_handle_trip_temp - Handle thermal trip from sensors
 *
 * @tz: pointer to the primary thermal zone.
 * @trip_temp: The temperature
 */
void of_thermal_handle_trip_temp(struct thermal_zone_device *tz,
		int trip_temp)
{
	return handle_thermal_trip(tz, true, trip_temp);
}
EXPORT_SYMBOL(of_thermal_handle_trip_temp);

/*
 * of_thermal_handle_trip - Handle thermal trip from sensors
 *
 * @tz: pointer to the primary thermal zone.
 */
void of_thermal_handle_trip(struct thermal_zone_device *tz)
{
	return handle_thermal_trip(tz, false, 0);
}
EXPORT_SYMBOL(of_thermal_handle_trip);
#endif

static struct thermal_zone_device_ops of_thermal_ops = {
	.get_mode = of_thermal_get_mode,
	.set_mode = of_thermal_set_mode,
@@ -408,7 +691,194 @@ static struct thermal_zone_device_ops of_thermal_ops = {
};

/***   sensor API   ***/
#ifdef CONFIG_QTI_THERMAL
static struct thermal_zone_device *
thermal_zone_of_add_sensor(struct device_node *zone,
			   struct device_node *sensor,
			   struct __sensor_param *sens_param)
{
	struct thermal_zone_device *tzd;
	struct __thermal_zone *tz;

	tzd = thermal_zone_get_zone_by_name(zone->name);
	if (IS_ERR(tzd))
		return ERR_PTR(-EPROBE_DEFER);

	tz = tzd->devdata;

	if (!sens_param->ops)
		return ERR_PTR(-EINVAL);

	mutex_lock(&tzd->lock);
	tz->senps = sens_param;

	tzd->ops->get_temp = of_thermal_get_temp;
	tzd->ops->get_trend = of_thermal_get_trend;

	/*
	 * The thermal zone core will calculate the window if they have set the
	 * optional set_trips pointer.
	 */
	if (sens_param->ops->set_trips)
		tzd->ops->set_trips = of_thermal_set_trips;

	if (sens_param->ops->set_emul_temp)
		tzd->ops->set_emul_temp = of_thermal_set_emul_temp;

	list_add_tail(&tz->list, &sens_param->first_tz);
	mutex_unlock(&tzd->lock);

	return tzd;
}

/**
 * thermal_zone_of_sensor_register - registers a sensor to a DT thermal zone
 * @dev: a valid struct device pointer of a sensor device. Must contain
 *       a valid .of_node, for the sensor node.
 * @sensor_id: a sensor identifier, in case the sensor IP has more
 *             than one sensors
 * @data: a private pointer (owned by the caller) that will be passed
 *        back, when a temperature reading is needed.
 * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp.
 *
 * This function will search the list of thermal zones described in device
 * tree and look for the zone that refer to the sensor device pointed by
 * @dev->of_node as temperature providers. For the zone pointing to the
 * sensor node, the sensor will be added to the DT thermal zone device.
 *
 * The thermal zone temperature is provided by the @get_temp function
 * pointer. When called, it will have the private pointer @data back.
 *
 * The thermal zone temperature trend is provided by the @get_trend function
 * pointer. When called, it will have the private pointer @data back.
 *
 * Return: On success returns a valid struct thermal_zone_device,
 * otherwise, it returns a corresponding ERR_PTR(). Incase there are multiple
 * thermal zones referencing the same sensor, the return value will be
 * thermal_zone_device pointer of the first thermal zone. Caller must
 * check the return value with help of IS_ERR() helper.
 */
struct thermal_zone_device *
thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
				const struct thermal_zone_of_device_ops *ops)
{
	struct device_node *np, *child, *sensor_np;
	struct thermal_zone_device *tzd = ERR_PTR(-ENODEV);
	struct thermal_zone_device *first_tzd = NULL;
	struct __sensor_param *sens_param = NULL;

	np = of_find_node_by_name(NULL, "thermal-zones");
	if (!np)
		return ERR_PTR(-ENODEV);

	if (!dev || !dev->of_node) {
		of_node_put(np);
		return ERR_PTR(-EINVAL);
	}

	sens_param = devm_kzalloc(dev, sizeof(*sens_param), GFP_KERNEL);
	if (!sens_param) {
		of_node_put(np);
		return ERR_PTR(-ENOMEM);
	}
	sens_param->sensor_data = data;
	sens_param->ops = ops;
	INIT_LIST_HEAD(&sens_param->first_tz);
	sens_param->trip_high = INT_MAX;
	sens_param->trip_low = INT_MIN;
	mutex_init(&sens_param->lock);
	sensor_np = of_node_get(dev->of_node);

	for_each_available_child_of_node(np, child) {
		struct of_phandle_args sensor_specs;
		int ret, id;
		struct __thermal_zone *tz;

		/* For now, thermal framework supports only 1 sensor per zone */
		ret = of_parse_phandle_with_args(child, "thermal-sensors",
						 "#thermal-sensor-cells",
						 0, &sensor_specs);
		if (ret)
			continue;

		if (sensor_specs.args_count >= 1) {
			id = sensor_specs.args[0];
			WARN(sensor_specs.args_count > 1,
			     "%pKOFn: too many cells in sensor specifier %d\n",
			     sensor_specs.np, sensor_specs.args_count);
		} else {
			id = 0;
		}

		if (sensor_specs.np == sensor_np && id == sensor_id) {
			tzd = thermal_zone_of_add_sensor(child, sensor_np,
							 sens_param);
			if (!IS_ERR(tzd)) {
				if (!first_tzd)
					first_tzd = tzd;
				tz = tzd->devdata;
				if (!tz->default_disable)
					tzd->ops->set_mode(tzd,
						THERMAL_DEVICE_ENABLED);
			}
		}
		of_node_put(sensor_specs.np);
	}
	of_node_put(sensor_np);
	of_node_put(np);

	if (!first_tzd) {
		first_tzd = ERR_PTR(-ENODEV);
		devm_kfree(dev, sens_param);
	}
	return first_tzd;
}
EXPORT_SYMBOL(thermal_zone_of_sensor_register);

/**
 * thermal_zone_of_sensor_unregister - unregisters a sensor from a DT
 *					thermal zone
 * @dev: a valid struct device pointer of a sensor device. Must contain
 *       a valid .of_node, for the sensor node.
 * @tzd: a pointer to struct thermal_zone_device where the sensor is registered.
 *
 * This function removes the sensor callbacks and private data from the
 * thermal zone device registered with thermal_zone_of_sensor_register()
 * API. It will also silent the zone by remove the .get_temp() and .get_trend()
 * thermal zone device callbacks.
 */
void thermal_zone_of_sensor_unregister(struct device *dev,
				       struct thermal_zone_device *tzd)
{
	struct __thermal_zone *tz, *next;
	struct thermal_zone_device *pos;
	struct list_head *head;

	if (!dev || !tzd || !tzd->devdata)
		return;

	tz = tzd->devdata;

	/* no __thermal_zone, nothing to be done */
	if (!tz)
		return;

	head = &tz->senps->first_tz;
	list_for_each_entry_safe(tz, next, head, list) {
		pos = tz->tzd;
		mutex_lock(&pos->lock);
		pos->ops->get_temp = NULL;
		pos->ops->get_trend = NULL;
		pos->ops->set_emul_temp = NULL;
		pos->ops = NULL;

		list_del(&tz->list);
		tz->senps = NULL;
		mutex_unlock(&pos->lock);
	}
}
EXPORT_SYMBOL(thermal_zone_of_sensor_unregister);
#else
static struct thermal_zone_device *
thermal_zone_of_add_sensor(struct device_node *zone,
			   struct device_node *sensor, void *data,
@@ -512,7 +982,7 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
		if (sensor_specs.args_count >= 1) {
			id = sensor_specs.args[0];
			WARN(sensor_specs.args_count > 1,
			     "%pOFn: too many cells in sensor specifier %d\n",
			     "%pKOFn: too many cells in sensor specifier %d\n",
			     sensor_specs.np, sensor_specs.args_count);
		} else {
			id = 0;
@@ -577,6 +1047,7 @@ void thermal_zone_of_sensor_unregister(struct device *dev,
	mutex_unlock(&tzd->lock);
}
EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister);
#endif

static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res)
{
@@ -851,6 +1322,7 @@ static int thermal_of_populate_trip(struct device_node *np,
 * otherwise, it returns a corresponding ERR_PTR(). Caller must
 * check the return value with help of IS_ERR() helper.
 */
#ifdef CONFIG_QTI_THERMAL
static struct __thermal_zone
__init *thermal_of_build_thermal_zone(struct device_node *np)
{
@@ -870,18 +1342,22 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)

	ret = of_property_read_u32(np, "polling-delay-passive", &prop);
	if (ret < 0) {
		pr_err("%pOFn: missing polling-delay-passive property\n", np);
		pr_err("%pKOFn: missing polling-delay-passive property\n", np);
		goto free_tz;
	}
	tz->passive_delay = prop;

	ret = of_property_read_u32(np, "polling-delay", &prop);
	if (ret < 0) {
		pr_err("%pOFn: missing polling-delay property\n", np);
		pr_err("%pKOFn: missing polling-delay property\n", np);
		goto free_tz;
	}
	tz->polling_delay = prop;

	INIT_LIST_HEAD(&tz->list);
	tz->default_disable = of_property_read_bool(np,
					"disable-thermal-zone");

	/*
	 * REVIST: for now, the thermal framework supports only
	 * one sensor per thermal zone. Thus, we are considering
@@ -976,6 +1452,133 @@ __init *thermal_of_build_thermal_zone(struct device_node *np)

	return ERR_PTR(ret);
}
#else
static struct __thermal_zone
__init *thermal_of_build_thermal_zone(struct device_node *np)
{
	struct device_node *child = NULL, *gchild;
	struct __thermal_zone *tz;
	int ret, i;
	u32 prop, coef[2];

	if (!np) {
		pr_err("no thermal zone np\n");
		return ERR_PTR(-EINVAL);
	}

	tz = kzalloc(sizeof(*tz), GFP_KERNEL);
	if (!tz)
		return ERR_PTR(-ENOMEM);

	ret = of_property_read_u32(np, "polling-delay-passive", &prop);
	if (ret < 0) {
		pr_err("%pKOFn: missing polling-delay-passive property\n", np);
		goto free_tz;
	}
	tz->passive_delay = prop;

	ret = of_property_read_u32(np, "polling-delay", &prop);
	if (ret < 0) {
		pr_err("%pKOFn: missing polling-delay property\n", np);
		goto free_tz;
	}
	tz->polling_delay = prop;

	/*
	 * REVIST: for now, the thermal framework supports only
	 * one sensor per thermal zone. Thus, we are considering
	 * only the first two values as slope and offset.
	 */
	ret = of_property_read_u32_array(np, "coefficients", coef, 2);
	if (ret == 0) {
		tz->slope = coef[0];
		tz->offset = coef[1];
	} else {
		tz->slope = 1;
		tz->offset = 0;
	}

	/* trips */
	child = of_get_child_by_name(np, "trips");

	/* No trips provided */
	if (!child)
		goto finish;

	tz->ntrips = of_get_child_count(child);
	if (tz->ntrips == 0) /* must have at least one child */
		goto finish;

	tz->trips = kcalloc(tz->ntrips, sizeof(*tz->trips), GFP_KERNEL);
	if (!tz->trips) {
		ret = -ENOMEM;
		goto free_tz;
	}

	i = 0;
	for_each_child_of_node(child, gchild) {
		ret = thermal_of_populate_trip(gchild, &tz->trips[i++]);
		if (ret)
			goto free_trips;
	}

	of_node_put(child);

	/* cooling-maps */
	child = of_get_child_by_name(np, "cooling-maps");

	/* cooling-maps not provided */
	if (!child)
		goto finish;

	tz->num_tbps = of_get_child_count(child);
	if (tz->num_tbps == 0)
		goto finish;

	tz->tbps = kcalloc(tz->num_tbps, sizeof(*tz->tbps), GFP_KERNEL);
	if (!tz->tbps) {
		ret = -ENOMEM;
		goto free_trips;
	}

	i = 0;
	for_each_child_of_node(child, gchild) {
		ret = thermal_of_populate_bind_params(gchild, &tz->tbps[i++],
						      tz->trips, tz->ntrips);
		if (ret)
			goto free_tbps;
	}

finish:
	of_node_put(child);
	tz->mode = THERMAL_DEVICE_DISABLED;

	return tz;

free_tbps:
	for (i = i - 1; i >= 0; i--) {
		struct __thermal_bind_params *tbp = tz->tbps + i;
		int j;

		for (j = 0; j < tbp->count; j++)
			of_node_put(tbp->tcbp[j].cooling_device);

		kfree(tbp->tcbp);
	}

	kfree(tz->tbps);
free_trips:
	for (i = 0; i < tz->ntrips; i++)
		of_node_put(tz->trips[i].np);
	kfree(tz->trips);
	of_node_put(gchild);
free_tz:
	kfree(tz);
	of_node_put(child);

	return ERR_PTR(ret);
}
#endif

static inline void of_thermal_free_zone(struct __thermal_zone *tz)
{
@@ -1027,10 +1630,13 @@ int __init of_parse_thermal_zones(void)
		struct thermal_zone_params *tzp;
		int i, mask = 0;
		u32 prop;
#ifdef CONFIG_QTI_THERMAL
		const char *governor_name;
#endif

		tz = thermal_of_build_thermal_zone(child);
		if (IS_ERR(tz)) {
			pr_err("failed to build thermal zone %pOFn: %ld\n",
			pr_err("failed to build thermal zone %pKOFn: %ld\n",
			       child,
			       PTR_ERR(tz));
			continue;
@@ -1049,6 +1655,13 @@ int __init of_parse_thermal_zones(void)
		/* No hwmon because there might be hwmon drivers registering */
		tzp->no_hwmon = true;

#ifdef CONFIG_QTI_THERMAL
		if (!of_property_read_string(child, "thermal-governor",
						&governor_name))
			strlcpy(tzp->governor_name, governor_name,
					THERMAL_NAME_LENGTH);
#endif

		if (!of_property_read_u32(child, "sustainable-power", &prop))
			tzp->sustainable_power = prop;

@@ -1064,14 +1677,27 @@ int __init of_parse_thermal_zones(void)
						    ops, tzp,
						    tz->passive_delay,
						    tz->polling_delay);
#ifdef CONFIG_QTI_THERMAL
		if (IS_ERR(zone)) {
			pr_err("Failed to build %pKOFn zone %ld\n", child,
			       PTR_ERR(zone));
			kfree(tzp);
			kfree(ops);
			of_thermal_free_zone(tz);
			/* attempting to build remaining zones still */
			continue;
		}
		tz->tzd = zone;
#else
		if (IS_ERR(zone)) {
			pr_err("Failed to build %pOFn zone %ld\n", child,
			pr_err("Failed to build %pKOFn zone %ld\n", child,
			       PTR_ERR(zone));
			kfree(tzp);
			kfree(ops);
			of_thermal_free_zone(tz);
			/* attempting to build remaining zones still */
		}
#endif
	}
	of_node_put(np);