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

Commit da62b770 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drivers: thermal: Add a snapshot of thermal framework"

parents cdeb9b27 50dc9bda
Loading
Loading
Loading
Loading
+53 −16
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 *
 *  Copyright (C) 2012 Intel Corp
 *  Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
 *  Copyright (c) 2019, The Linux Foundation. All rights reserved.
 *
 *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
@@ -41,6 +42,12 @@ static unsigned long get_target_state(struct thermal_instance *instance,
	unsigned long cur_state;
	unsigned long next_target;

	/*
	 * If the throttle condition is not reached and there is no
	 * previous mitigaiton request, then there is nothing to compute.
	 */
	if (!throttle && instance->target == THERMAL_NO_TARGET)
		return THERMAL_NO_TARGET;
	/*
	 * We keep this instance the way it is by default.
	 * Otherwise, we use the current state of the
@@ -77,7 +84,9 @@ static unsigned long get_target_state(struct thermal_instance *instance,
			next_target = instance->upper;
		break;
	case THERMAL_TREND_DROPPING:
		if (cur_state <= instance->lower) {
	case THERMAL_TREND_STABLE:
		if (cur_state <= instance->lower ||
			instance->target <= instance->lower) {
			if (!throttle)
				next_target = THERMAL_NO_TARGET;
		} else {
@@ -115,7 +124,7 @@ static void update_passive_instance(struct thermal_zone_device *tz,

static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
{
	int trip_temp;
	int trip_temp, hyst_temp;
	enum thermal_trip_type trip_type;
	enum thermal_trend trend;
	struct thermal_instance *instance;
@@ -123,20 +132,21 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
	int old_target;

	if (trip == THERMAL_TRIPS_NONE) {
		trip_temp = tz->forced_passive;
		hyst_temp = trip_temp = tz->forced_passive;
		trip_type = THERMAL_TRIPS_NONE;
	} else {
		tz->ops->get_trip_temp(tz, trip, &trip_temp);
		if (tz->ops->get_trip_hyst) {
			tz->ops->get_trip_hyst(tz, trip, &hyst_temp);
			hyst_temp = trip_temp - hyst_temp;
		} else {
			hyst_temp = trip_temp;
		}
		tz->ops->get_trip_type(tz, trip, &trip_type);
	}

	trend = get_tz_trend(tz, trip);

	if (tz->temperature >= trip_temp) {
		throttle = true;
		trace_thermal_zone_trip(tz, trip, trip_type);
	}

	dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
				trip, trip_type, trip_temp, trend, throttle);

@@ -147,6 +157,20 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
			continue;

		old_target = instance->target;
		/*
		 * Step wise has to lower the mitigation only if the
		 * temperature goes below the hysteresis temperature.
		 * Atleast, it has to hold on to mitigation device lower
		 * limit if the temperature is above the hysteresis
		 * temperature.
		 */
		if (tz->temperature >= trip_temp ||
			(tz->temperature > hyst_temp &&
			 old_target != THERMAL_NO_TARGET))
			throttle = true;
		else
			throttle = false;

		instance->target = get_target_state(instance, trend, throttle);
		dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n",
					old_target, (int)instance->target);
@@ -154,14 +178,27 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
		if (instance->initialized && old_target == instance->target)
			continue;

		if (!instance->initialized) {
			if (instance->target != THERMAL_NO_TARGET) {
				trace_thermal_zone_trip(tz, trip, trip_type,
							true);
				update_passive_instance(tz, trip_type, 1);
			}
		} else {
			/* Activate a passive thermal instance */
			if (old_target == THERMAL_NO_TARGET &&
			instance->target != THERMAL_NO_TARGET)
				instance->target != THERMAL_NO_TARGET) {
				trace_thermal_zone_trip(tz, trip, trip_type,
							true);
				update_passive_instance(tz, trip_type, 1);
			/* Deactivate a passive thermal instance */
		else if (old_target != THERMAL_NO_TARGET &&
			instance->target == THERMAL_NO_TARGET)
			} else if (old_target != THERMAL_NO_TARGET &&
				instance->target == THERMAL_NO_TARGET) {
				trace_thermal_zone_trip(tz, trip, trip_type,
							false);
				update_passive_instance(tz, trip_type, -1);
			}
		}

		instance->initialized = true;
		mutex_lock(&instance->cdev->lock);
+139 −39
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
 *  Copyright (C) 2008 Intel Corp
 *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
 *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
 *  Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -33,6 +34,8 @@ MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL v2");

#define THERMAL_MAX_ACTIVE	16

static DEFINE_IDA(thermal_tz_ida);
static DEFINE_IDA(thermal_cdev_ida);

@@ -49,6 +52,8 @@ static bool power_off_triggered;

static struct thermal_governor *def_governor;

static struct workqueue_struct *thermal_passive_wq;

/*
 * Governor section: set of functions to handle thermal governors
 *
@@ -292,19 +297,18 @@ static int __init thermal_register_governors(void)
 * - Hot trips will produce a notification to userspace;
 * - Critical trip point will cause a system shutdown.
 */
static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
static void thermal_zone_device_set_polling(struct workqueue_struct *queue,
					    struct thermal_zone_device *tz,
					    int delay)
{
	if (delay > 1000)
		mod_delayed_work(system_freezable_power_efficient_wq,
				 &tz->poll_queue,
		mod_delayed_work(queue, &tz->poll_queue,
				 round_jiffies(msecs_to_jiffies(delay)));
	else if (delay)
		mod_delayed_work(system_freezable_power_efficient_wq,
				 &tz->poll_queue,
		mod_delayed_work(queue, &tz->poll_queue,
				 msecs_to_jiffies(delay));
	else
		cancel_delayed_work_sync(&tz->poll_queue);
		cancel_delayed_work(&tz->poll_queue);
}

static void monitor_thermal_zone(struct thermal_zone_device *tz)
@@ -312,11 +316,14 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
	mutex_lock(&tz->lock);

	if (tz->passive)
		thermal_zone_device_set_polling(tz, tz->passive_delay);
		thermal_zone_device_set_polling(thermal_passive_wq,
						tz, tz->passive_delay);
	else if (tz->polling_delay)
		thermal_zone_device_set_polling(tz, tz->polling_delay);
		thermal_zone_device_set_polling(
				system_freezable_power_efficient_wq,
				tz, tz->polling_delay);
	else
		thermal_zone_device_set_polling(tz, 0);
		thermal_zone_device_set_polling(NULL, tz, 0);

	mutex_unlock(&tz->lock);
}
@@ -386,7 +393,7 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
	if (trip_temp <= 0 || tz->temperature < trip_temp)
		return;

	trace_thermal_zone_trip(tz, trip, trip_type);
	trace_thermal_zone_trip(tz, trip, trip_type, true);

	if (tz->ops->notify)
		tz->ops->notify(tz, trip, trip_type);
@@ -428,21 +435,11 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
	 * So, start monitoring again.
	 */
	monitor_thermal_zone(tz);
	trace_thermal_handle_trip(tz, trip);
}

static void update_temperature(struct thermal_zone_device *tz)
static void store_temperature(struct thermal_zone_device *tz, int temp)
{
	int temp, ret;

	ret = thermal_zone_get_temp(tz, &temp);
	if (ret) {
		if (ret != -EAGAIN)
			dev_warn(&tz->device,
				 "failed to read out thermal zone (%d)\n",
				 ret);
		return;
	}

	mutex_lock(&tz->lock);
	tz->last_temperature = tz->temperature;
	tz->temperature = temp;
@@ -457,6 +454,21 @@ static void update_temperature(struct thermal_zone_device *tz)
			tz->last_temperature, tz->temperature);
}

static void update_temperature(struct thermal_zone_device *tz)
{
	int temp, ret;

	ret = thermal_zone_get_temp(tz, &temp);
	if (ret) {
		if (ret != -EAGAIN)
			dev_warn(&tz->device,
				 "failed to read out thermal zone (%d)\n",
				 ret);
		return;
	}
	store_temperature(tz, temp);
}

static void thermal_zone_device_init(struct thermal_zone_device *tz)
{
	struct thermal_instance *pos;
@@ -471,17 +483,36 @@ static void thermal_zone_device_reset(struct thermal_zone_device *tz)
	thermal_zone_device_init(tz);
}

void thermal_zone_device_update_temp(struct thermal_zone_device *tz,
				enum thermal_notify_event event, int temp)
{
	int count;

	if (atomic_read(&in_suspend) && tz->polling_delay)
		return;
	trace_thermal_device_update(tz, event);
	store_temperature(tz, temp);

	thermal_zone_set_trips(tz);

	tz->notify_event = event;

	for (count = 0; count < tz->trips; count++)
		handle_thermal_trip(tz, count);
}
EXPORT_SYMBOL(thermal_zone_device_update_temp);

void thermal_zone_device_update(struct thermal_zone_device *tz,
				enum thermal_notify_event event)
{
	int count;

	if (atomic_read(&in_suspend))
	if (atomic_read(&in_suspend) && tz->polling_delay)
		return;

	if (!tz->ops->get_temp)
		return;

	trace_thermal_device_update(tz, event);
	update_temperature(tz);

	thermal_zone_set_trips(tz);
@@ -710,9 +741,26 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
	if (ret)
		return ret;

	/* lower default 0, upper default max_state */
	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
	/*
	 * If upper or lower has a MACRO to define the mitigation state,
	 * based on the MACRO determine the default state to use or the
	 * offset from the max_state.
	 */
	if (upper >= (THERMAL_MAX_LIMIT - max_state)) {
		/* upper default max_state */
		if (upper == THERMAL_NO_LIMIT)
			upper = max_state;
		else
			upper = max_state - (THERMAL_MAX_LIMIT - upper);
	}

	if (lower >= (THERMAL_MAX_LIMIT - max_state)) {
		/* lower default 0 */
		if (lower == THERMAL_NO_LIMIT)
			lower = 0;
		else
			lower =  max_state - (THERMAL_MAX_LIMIT - lower);
	}

	if (lower > upper || upper > max_state)
		return -EINVAL;
@@ -839,6 +887,7 @@ static void thermal_release(struct device *dev)
{
	struct thermal_zone_device *tz;
	struct thermal_cooling_device *cdev;
	struct thermal_instance *instance;

	if (!strncmp(dev_name(dev), "thermal_zone",
		     sizeof("thermal_zone") - 1)) {
@@ -848,6 +897,12 @@ static void thermal_release(struct device *dev)
	} else if (!strncmp(dev_name(dev), "cooling_device",
			    sizeof("cooling_device") - 1)) {
		cdev = to_cooling_device(dev);
		if (list_is_singular(&cdev->thermal_instances)) {
			instance = list_first_entry(&cdev->thermal_instances,
					typeof(*instance), cdev_node);
			list_del(&instance->cdev_node);
			kfree(instance);
		}
		kfree(cdev);
	}
}
@@ -953,6 +1008,7 @@ __thermal_cooling_device_register(struct device_node *np,
	struct thermal_cooling_device *cdev;
	struct thermal_zone_device *pos = NULL;
	int result;
	struct thermal_instance *instance;

	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
		return ERR_PTR(-EINVAL);
@@ -965,9 +1021,16 @@ __thermal_cooling_device_register(struct device_node *np,
	if (!cdev)
		return ERR_PTR(-ENOMEM);

	instance = kzalloc(sizeof(*instance), GFP_KERNEL);
	if (!instance) {
		kfree(cdev);
		return ERR_PTR(-ENOMEM);
	}

	result = ida_simple_get(&thermal_cdev_ida, 0, 0, GFP_KERNEL);
	if (result < 0) {
		kfree(cdev);
		kfree(instance);
		return ERR_PTR(result);
	}

@@ -975,6 +1038,8 @@ __thermal_cooling_device_register(struct device_node *np,
	strlcpy(cdev->type, type ? : "", sizeof(cdev->type));
	mutex_init(&cdev->lock);
	INIT_LIST_HEAD(&cdev->thermal_instances);
	instance->target = THERMAL_NO_TARGET;
	list_add_tail(&instance->cdev_node, &cdev->thermal_instances);
	cdev->np = np;
	cdev->ops = ops;
	cdev->updated = false;
@@ -1345,7 +1410,7 @@ thermal_zone_device_register(const char *type, int trips, int mask,
	/* Bind cooling devices for this zone */
	bind_tz(tz);

	INIT_DELAYED_WORK(&tz->poll_queue, thermal_zone_device_check);
	INIT_DEFERRABLE_WORK(&(tz->poll_queue), thermal_zone_device_check);

	thermal_zone_device_reset(tz);
	/* Update the new thermal zone and mark it as already updated. */
@@ -1414,7 +1479,7 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)

	mutex_unlock(&thermal_list_lock);

	thermal_zone_device_set_polling(tz, 0);
	cancel_delayed_work_sync(&tz->poll_queue);

	thermal_set_governor(tz, NULL);

@@ -1576,7 +1641,8 @@ static int thermal_pm_notify(struct notifier_block *nb,
			if (tz->ops->get_mode)
				tz->ops->get_mode(tz, &tz_mode);

			if (tz_mode == THERMAL_DEVICE_DISABLED)
			if (tz_mode == THERMAL_DEVICE_DISABLED ||
				tz->polling_delay == 0)
				continue;

			thermal_zone_device_init(tz);
@@ -1599,21 +1665,26 @@ static int __init thermal_init(void)
	int result;

	mutex_init(&poweroff_lock);
	thermal_passive_wq = alloc_workqueue("thermal_passive_wq",
						WQ_HIGHPRI | WQ_UNBOUND
						| WQ_FREEZABLE,
						THERMAL_MAX_ACTIVE);
	if (!thermal_passive_wq) {
		result = -ENOMEM;
		goto error;
	}

	result = thermal_register_governors();
	if (result)
		goto error;
		goto destroy_wq;

	result = class_register(&thermal_class);
	if (result)
		goto unregister_governors;

	result = genetlink_init();
	if (result)
		goto unregister_class;

	result = of_parse_thermal_zones();
	if (result)
		goto exit_netlink;
		goto unregister_class;

	result = register_pm_notifier(&thermal_pm_nb);
	if (result)
@@ -1622,12 +1693,12 @@ static int __init thermal_init(void)

	return 0;

exit_netlink:
	genetlink_exit();
unregister_class:
	class_unregister(&thermal_class);
unregister_governors:
	thermal_unregister_governors();
destroy_wq:
	destroy_workqueue(thermal_passive_wq);
error:
	ida_destroy(&thermal_tz_ida);
	ida_destroy(&thermal_cdev_ida);
@@ -1636,4 +1707,33 @@ static int __init thermal_init(void)
	mutex_destroy(&poweroff_lock);
	return result;
}
fs_initcall(thermal_init);

static void thermal_exit(void)
{
	unregister_pm_notifier(&thermal_pm_nb);
	of_thermal_destroy_zones();
	destroy_workqueue(thermal_passive_wq);
	genetlink_exit();
	class_unregister(&thermal_class);
	thermal_unregister_governors();
	ida_destroy(&thermal_tz_ida);
	ida_destroy(&thermal_cdev_ida);
	mutex_destroy(&thermal_list_lock);
	mutex_destroy(&thermal_governor_lock);
}

static int __init thermal_netlink_init(void)
{
	int ret = 0;

	ret = genetlink_init();
	if (!ret)
		goto exit_netlink;

	thermal_exit();
exit_netlink:
	return ret;
}

subsys_initcall(thermal_init);
fs_initcall(thermal_netlink_init);
+20 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 *
 *  Copyright (C) 2012  Intel Corp
 *  Author: Durgadoss R <durgadoss.r@intel.com>
 *  Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */

#ifndef __THERMAL_CORE_H__
@@ -97,6 +98,12 @@ int of_thermal_get_ntrips(struct thermal_zone_device *);
bool of_thermal_is_trip_valid(struct thermal_zone_device *, int);
const struct thermal_trip *
of_thermal_get_trip_points(struct thermal_zone_device *);
int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
			      enum thermal_trip_type type,
			      int *low, int *high);
void of_thermal_handle_trip(struct thermal_zone_device *tz);
void of_thermal_handle_trip_temp(struct thermal_zone_device *tz,
					int trip_temp);
#else
static inline int of_parse_thermal_zones(void) { return 0; }
static inline void of_thermal_destroy_zones(void) { }
@@ -114,6 +121,19 @@ of_thermal_get_trip_points(struct thermal_zone_device *tz)
{
	return NULL;
}
static inline int of_thermal_aggregate_trip(struct thermal_zone_device *tz,
					    enum thermal_trip_type type,
					    int *low, int *high)
{
	return -ENODEV;
}
static inline
void of_thermal_handle_trip(struct thermal_zone_device *tz)
{ }
static inline
void of_thermal_handle_trip_temp(struct thermal_zone_device *tz,
					int trip_temp)
{ }
#endif

#endif /* __THERMAL_CORE_H__ */
+10 −7
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 *  Copyright (C) 2008 Intel Corp
 *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
 *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
 *  Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -106,7 +107,7 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
		if (!ret && *temp < crit_temp)
			*temp = tz->emul_temperature;
	}

	trace_thermal_query_temp(tz, *temp);
	mutex_unlock(&tz->lock);
exit:
	return ret;
@@ -140,10 +141,6 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz)
			high = trip_temp;
	}

	/* No need to change trip points */
	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
		goto exit;

	tz->prev_low_trip = low;
	tz->prev_high_trip = high;

@@ -157,6 +154,7 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz)
	ret = tz->ops->set_trips(tz, low, high);
	if (ret)
		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
	trace_thermal_set_trip(tz);

exit:
	mutex_unlock(&tz->lock);
@@ -177,6 +175,11 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)

	/* Make sure cdev enters the deepest cooling state */
	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
		if (list_is_first(&instance->cdev_node,
					&cdev->thermal_instances))
			dev_dbg(&cdev->device, "userspace->target=%lu\n",
				instance->target);
		else
			dev_dbg(&cdev->device, "zone%d->target=%lu\n",
				instance->tz->id, instance->target);
		if (instance->target == THERMAL_NO_TARGET)
+71 −8
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
 *  Copyright (C) 2008 Intel Corp
 *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
 *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
 *  Copyright (c) 2019, The Linux Foundation. All rights reserved.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -63,6 +64,28 @@ mode_show(struct device *dev, struct device_attribute *attr, char *buf)
		       : "disabled");
}

static int thermal_zone_device_clear(struct thermal_zone_device *tz)
{
	struct thermal_instance *pos;
	int ret = 0;

	ret = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
	mutex_lock(&tz->lock);
	tz->temperature = THERMAL_TEMP_INVALID;
	tz->passive = 0;
	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
		pos->initialized = false;
		pos->target = THERMAL_NO_TARGET;
		mutex_lock(&pos->cdev->lock);
		pos->cdev->updated = false; /* cdev needs update */
		mutex_unlock(&pos->cdev->lock);
		thermal_cdev_update(pos->cdev);
	}
	mutex_unlock(&tz->lock);

	return ret;
}

static ssize_t
mode_store(struct device *dev, struct device_attribute *attr,
	   const char *buf, size_t count)
@@ -76,7 +99,7 @@ mode_store(struct device *dev, struct device_attribute *attr,
	if (!strncmp(buf, "enabled", sizeof("enabled") - 1))
		result = tz->ops->set_mode(tz, THERMAL_DEVICE_ENABLED);
	else if (!strncmp(buf, "disabled", sizeof("disabled") - 1))
		result = tz->ops->set_mode(tz, THERMAL_DEVICE_DISABLED);
		result = thermal_zone_device_clear(tz);
	else
		result = -EINVAL;

@@ -348,6 +371,24 @@ sustainable_power_store(struct device *dev, struct device_attribute *devattr,
	return count;
}

static ssize_t
polling_delay_show(struct device *dev, struct device_attribute *attr,
		   char *buf)
{
	struct thermal_zone_device *tz = to_thermal_zone(dev);

	return scnprintf(buf, PAGE_SIZE, "%d\n", tz->polling_delay);
}

static ssize_t
passive_delay_show(struct device *dev, struct device_attribute *attr,
		   char *buf)
{
	struct thermal_zone_device *tz = to_thermal_zone(dev);

	return scnprintf(buf, PAGE_SIZE, "%d\n", tz->passive_delay);
}

#define create_s32_tzp_attr(name)					\
	static ssize_t							\
	name##_show(struct device *dev, struct device_attribute *devattr, \
@@ -399,6 +440,8 @@ static DEVICE_ATTR_RO(temp);
static DEVICE_ATTR_RW(policy);
static DEVICE_ATTR_RO(available_policies);
static DEVICE_ATTR_RW(sustainable_power);
static DEVICE_ATTR_RO(passive_delay);
static DEVICE_ATTR_RO(polling_delay);

/* These thermal zone device attributes are created based on conditions */
static DEVICE_ATTR_RW(mode);
@@ -414,6 +457,8 @@ static struct attribute *thermal_zone_dev_attrs[] = {
	&dev_attr_policy.attr,
	&dev_attr_available_policies.attr,
	&dev_attr_sustainable_power.attr,
	&dev_attr_passive_delay.attr,
	&dev_attr_polling_delay.attr,
	&dev_attr_k_po.attr,
	&dev_attr_k_pu.attr,
	&dev_attr_k_i.attr,
@@ -704,7 +749,7 @@ cur_state_store(struct device *dev, struct device_attribute *attr,
{
	struct thermal_cooling_device *cdev = to_cooling_device(dev);
	unsigned long state;
	int result;
	struct thermal_instance *instance = NULL;

	if (sscanf(buf, "%ld\n", &state) != 1)
		return -EINVAL;
@@ -713,13 +758,15 @@ cur_state_store(struct device *dev, struct device_attribute *attr,
		return -EINVAL;

	mutex_lock(&cdev->lock);
	instance = list_first_entry(&cdev->thermal_instances,
			typeof(*instance), cdev_node);
	instance->target = state;

	result = cdev->ops->set_cur_state(cdev, state);
	if (!result)
		thermal_cooling_device_stats_update(cdev, state);

	cdev->updated = false;
	mutex_unlock(&cdev->lock);
	return result ? result : count;
	thermal_cdev_update(cdev);

	return count;
}

static struct device_attribute
@@ -770,6 +817,9 @@ void thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
{
	struct cooling_dev_stats *stats = cdev->stats;

	if (!stats)
		return;

	spin_lock(&stats->lock);

	if (stats->state == new_state)
@@ -791,6 +841,9 @@ static ssize_t total_trans_show(struct device *dev,
	struct cooling_dev_stats *stats = cdev->stats;
	int ret;

	if (!stats)
		return -ENODEV;

	spin_lock(&stats->lock);
	ret = sprintf(buf, "%u\n", stats->total_trans);
	spin_unlock(&stats->lock);
@@ -807,6 +860,9 @@ time_in_state_ms_show(struct device *dev, struct device_attribute *attr,
	ssize_t len = 0;
	int i;

	if (!stats)
		return -ENODEV;

	spin_lock(&stats->lock);
	update_time_in_state(stats);

@@ -825,8 +881,12 @@ reset_store(struct device *dev, struct device_attribute *attr, const char *buf,
{
	struct thermal_cooling_device *cdev = to_cooling_device(dev);
	struct cooling_dev_stats *stats = cdev->stats;
	int i, states = stats->max_states;
	int i, states;

	if (!stats)
		return -ENODEV;

	states = stats->max_states;
	spin_lock(&stats->lock);

	stats->total_trans = 0;
@@ -850,6 +910,9 @@ static ssize_t trans_table_show(struct device *dev,
	ssize_t len = 0;
	int i, j;

	if (!stats)
		return -ENODEV;

	len += snprintf(buf + len, PAGE_SIZE - len, " From  :    To\n");
	len += snprintf(buf + len, PAGE_SIZE - len, "       : ");
	for (i = 0; i < stats->max_states; i++) {
Loading