All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/5] Thermal: build all thermal framework code into thermal_sys module
@ 2013-03-26 16:26 Zhang Rui
  2013-03-26 16:26 ` [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c Zhang Rui
                   ` (4 more replies)
  0 siblings, 5 replies; 23+ messages in thread
From: Zhang Rui @ 2013-03-26 16:26 UTC (permalink / raw)
  To: linux-pm, linux-kernel; +Cc: amit.daniel, durgadoss.r, andi, Zhang Rui

A regression introduced by thermal governor feature
is reported in http://marc.info/?l=linux-kernel&m=136085598604095&w=2

And the root cause is that all the thermal governors can not be registered
successfully when the thermal framework is built as a module.

Thus I made this patch set to build all the thermal framework component,
including governors and cpu_cooling feature into one module so that all the
thermal features are loaded/unloaded altogether.

any comments?

thanks,
rui

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c
  2013-03-26 16:26 [RFC PATCH 0/5] Thermal: build all thermal framework code into thermal_sys module Zhang Rui
@ 2013-03-26 16:26 ` Zhang Rui
  2013-03-26 16:56   ` R, Durgadoss
  2013-03-26 22:04     ` Eduardo Valentin
  2013-03-26 16:26 ` [RFC PATCH 2/5] Thermal: thermal framework registration failure case cleanup Zhang Rui
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 23+ messages in thread
From: Zhang Rui @ 2013-03-26 16:26 UTC (permalink / raw)
  To: linux-pm, linux-kernel; +Cc: amit.daniel, durgadoss.r, andi, Zhang Rui

No functional change in this patch.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/Makefile       |    1 +
 drivers/thermal/thermal_core.c | 1888 ++++++++++++++++++++++++++++++++++++++++
 drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------
 3 files changed, 1889 insertions(+), 1888 deletions(-)
 create mode 100644 drivers/thermal/thermal_core.c
 delete mode 100644 drivers/thermal/thermal_sys.c

diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index d3a2b38..b2009bd 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_THERMAL)		+= thermal_sys.o
+thermal_sys-y			+= thermal_core.o
 
 # governors
 obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
new file mode 100644
index 0000000..5b7863a
--- /dev/null
+++ b/drivers/thermal/thermal_core.c
@@ -0,0 +1,1888 @@
+/*
+ *  thermal.c - Generic Thermal Management Sysfs support.
+ *
+ *  Copyright (C) 2008 Intel Corp
+ *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
+ *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
+ *
+ *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+#include <linux/thermal.h>
+#include <linux/reboot.h>
+#include <net/netlink.h>
+#include <net/genetlink.h>
+
+#include "thermal_core.h"
+
+MODULE_AUTHOR("Zhang Rui");
+MODULE_DESCRIPTION("Generic thermal management sysfs support");
+MODULE_LICENSE("GPL");
+
+static DEFINE_IDR(thermal_tz_idr);
+static DEFINE_IDR(thermal_cdev_idr);
+static DEFINE_MUTEX(thermal_idr_lock);
+
+static LIST_HEAD(thermal_tz_list);
+static LIST_HEAD(thermal_cdev_list);
+static LIST_HEAD(thermal_governor_list);
+
+static DEFINE_MUTEX(thermal_list_lock);
+static DEFINE_MUTEX(thermal_governor_lock);
+
+static struct thermal_governor *__find_governor(const char *name)
+{
+	struct thermal_governor *pos;
+
+	list_for_each_entry(pos, &thermal_governor_list, governor_list)
+		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
+			return pos;
+
+	return NULL;
+}
+
+int thermal_register_governor(struct thermal_governor *governor)
+{
+	int err;
+	const char *name;
+	struct thermal_zone_device *pos;
+
+	if (!governor)
+		return -EINVAL;
+
+	mutex_lock(&thermal_governor_lock);
+
+	err = -EBUSY;
+	if (__find_governor(governor->name) == NULL) {
+		err = 0;
+		list_add(&governor->governor_list, &thermal_governor_list);
+	}
+
+	mutex_lock(&thermal_list_lock);
+
+	list_for_each_entry(pos, &thermal_tz_list, node) {
+		if (pos->governor)
+			continue;
+		if (pos->tzp)
+			name = pos->tzp->governor_name;
+		else
+			name = DEFAULT_THERMAL_GOVERNOR;
+		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
+			pos->governor = governor;
+	}
+
+	mutex_unlock(&thermal_list_lock);
+	mutex_unlock(&thermal_governor_lock);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(thermal_register_governor);
+
+void thermal_unregister_governor(struct thermal_governor *governor)
+{
+	struct thermal_zone_device *pos;
+
+	if (!governor)
+		return;
+
+	mutex_lock(&thermal_governor_lock);
+
+	if (__find_governor(governor->name) == NULL)
+		goto exit;
+
+	mutex_lock(&thermal_list_lock);
+
+	list_for_each_entry(pos, &thermal_tz_list, node) {
+		if (!strnicmp(pos->governor->name, governor->name,
+						THERMAL_NAME_LENGTH))
+			pos->governor = NULL;
+	}
+
+	mutex_unlock(&thermal_list_lock);
+	list_del(&governor->governor_list);
+exit:
+	mutex_unlock(&thermal_governor_lock);
+	return;
+}
+EXPORT_SYMBOL_GPL(thermal_unregister_governor);
+
+static int get_idr(struct idr *idr, struct mutex *lock, int *id)
+{
+	int ret;
+
+	if (lock)
+		mutex_lock(lock);
+	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
+	if (lock)
+		mutex_unlock(lock);
+	if (unlikely(ret < 0))
+		return ret;
+	*id = ret;
+	return 0;
+}
+
+static void release_idr(struct idr *idr, struct mutex *lock, int id)
+{
+	if (lock)
+		mutex_lock(lock);
+	idr_remove(idr, id);
+	if (lock)
+		mutex_unlock(lock);
+}
+
+int get_tz_trend(struct thermal_zone_device *tz, int trip)
+{
+	enum thermal_trend trend;
+
+	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
+		if (tz->temperature > tz->last_temperature)
+			trend = THERMAL_TREND_RAISING;
+		else if (tz->temperature < tz->last_temperature)
+			trend = THERMAL_TREND_DROPPING;
+		else
+			trend = THERMAL_TREND_STABLE;
+	}
+
+	return trend;
+}
+EXPORT_SYMBOL(get_tz_trend);
+
+struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
+			struct thermal_cooling_device *cdev, int trip)
+{
+	struct thermal_instance *pos = NULL;
+	struct thermal_instance *target_instance = NULL;
+
+	mutex_lock(&tz->lock);
+	mutex_lock(&cdev->lock);
+
+	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
+		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
+			target_instance = pos;
+			break;
+		}
+	}
+
+	mutex_unlock(&cdev->lock);
+	mutex_unlock(&tz->lock);
+
+	return target_instance;
+}
+EXPORT_SYMBOL(get_thermal_instance);
+
+static void print_bind_err_msg(struct thermal_zone_device *tz,
+			struct thermal_cooling_device *cdev, int ret)
+{
+	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
+				tz->type, cdev->type, ret);
+}
+
+static void __bind(struct thermal_zone_device *tz, int mask,
+			struct thermal_cooling_device *cdev)
+{
+	int i, ret;
+
+	for (i = 0; i < tz->trips; i++) {
+		if (mask & (1 << i)) {
+			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
+					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
+			if (ret)
+				print_bind_err_msg(tz, cdev, ret);
+		}
+	}
+}
+
+static void __unbind(struct thermal_zone_device *tz, int mask,
+			struct thermal_cooling_device *cdev)
+{
+	int i;
+
+	for (i = 0; i < tz->trips; i++)
+		if (mask & (1 << i))
+			thermal_zone_unbind_cooling_device(tz, i, cdev);
+}
+
+static void bind_cdev(struct thermal_cooling_device *cdev)
+{
+	int i, ret;
+	const struct thermal_zone_params *tzp;
+	struct thermal_zone_device *pos = NULL;
+
+	mutex_lock(&thermal_list_lock);
+
+	list_for_each_entry(pos, &thermal_tz_list, node) {
+		if (!pos->tzp && !pos->ops->bind)
+			continue;
+
+		if (!pos->tzp && pos->ops->bind) {
+			ret = pos->ops->bind(pos, cdev);
+			if (ret)
+				print_bind_err_msg(pos, cdev, ret);
+		}
+
+		tzp = pos->tzp;
+		if (!tzp || !tzp->tbp)
+			continue;
+
+		for (i = 0; i < tzp->num_tbps; i++) {
+			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
+				continue;
+			if (tzp->tbp[i].match(pos, cdev))
+				continue;
+			tzp->tbp[i].cdev = cdev;
+			__bind(pos, tzp->tbp[i].trip_mask, cdev);
+		}
+	}
+
+	mutex_unlock(&thermal_list_lock);
+}
+
+static void bind_tz(struct thermal_zone_device *tz)
+{
+	int i, ret;
+	struct thermal_cooling_device *pos = NULL;
+	const struct thermal_zone_params *tzp = tz->tzp;
+
+	if (!tzp && !tz->ops->bind)
+		return;
+
+	mutex_lock(&thermal_list_lock);
+
+	/* If there is no platform data, try to use ops->bind */
+	if (!tzp && tz->ops->bind) {
+		list_for_each_entry(pos, &thermal_cdev_list, node) {
+			ret = tz->ops->bind(tz, pos);
+			if (ret)
+				print_bind_err_msg(tz, pos, ret);
+		}
+		goto exit;
+	}
+
+	if (!tzp || !tzp->tbp)
+		goto exit;
+
+	list_for_each_entry(pos, &thermal_cdev_list, node) {
+		for (i = 0; i < tzp->num_tbps; i++) {
+			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
+				continue;
+			if (tzp->tbp[i].match(tz, pos))
+				continue;
+			tzp->tbp[i].cdev = pos;
+			__bind(tz, tzp->tbp[i].trip_mask, pos);
+		}
+	}
+exit:
+	mutex_unlock(&thermal_list_lock);
+}
+
+static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
+					    int delay)
+{
+	if (delay > 1000)
+		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+				 round_jiffies(msecs_to_jiffies(delay)));
+	else if (delay)
+		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
+				 msecs_to_jiffies(delay));
+	else
+		cancel_delayed_work(&tz->poll_queue);
+}
+
+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);
+	else if (tz->polling_delay)
+		thermal_zone_device_set_polling(tz, tz->polling_delay);
+	else
+		thermal_zone_device_set_polling(tz, 0);
+
+	mutex_unlock(&tz->lock);
+}
+
+static void handle_non_critical_trips(struct thermal_zone_device *tz,
+			int trip, enum thermal_trip_type trip_type)
+{
+	if (tz->governor)
+		tz->governor->throttle(tz, trip);
+}
+
+static void handle_critical_trips(struct thermal_zone_device *tz,
+				int trip, enum thermal_trip_type trip_type)
+{
+	long trip_temp;
+
+	tz->ops->get_trip_temp(tz, trip, &trip_temp);
+
+	/* If we have not crossed the trip_temp, we do not care. */
+	if (tz->temperature < trip_temp)
+		return;
+
+	if (tz->ops->notify)
+		tz->ops->notify(tz, trip, trip_type);
+
+	if (trip_type == THERMAL_TRIP_CRITICAL) {
+		dev_emerg(&tz->device,
+			  "critical temperature reached(%d C),shutting down\n",
+			  tz->temperature / 1000);
+		orderly_poweroff(true);
+	}
+}
+
+static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
+{
+	enum thermal_trip_type type;
+
+	tz->ops->get_trip_type(tz, trip, &type);
+
+	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
+		handle_critical_trips(tz, trip, type);
+	else
+		handle_non_critical_trips(tz, trip, type);
+	/*
+	 * Alright, we handled this trip successfully.
+	 * So, start monitoring again.
+	 */
+	monitor_thermal_zone(tz);
+}
+
+static int thermal_zone_get_temp(struct thermal_zone_device *tz,
+				unsigned long *temp)
+{
+	int ret = 0;
+#ifdef CONFIG_THERMAL_EMULATION
+	int count;
+	unsigned long crit_temp = -1UL;
+	enum thermal_trip_type type;
+#endif
+
+	mutex_lock(&tz->lock);
+
+	ret = tz->ops->get_temp(tz, temp);
+#ifdef CONFIG_THERMAL_EMULATION
+	if (!tz->emul_temperature)
+		goto skip_emul;
+
+	for (count = 0; count < tz->trips; count++) {
+		ret = tz->ops->get_trip_type(tz, count, &type);
+		if (!ret && type == THERMAL_TRIP_CRITICAL) {
+			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
+			break;
+		}
+	}
+
+	if (ret)
+		goto skip_emul;
+
+	if (*temp < crit_temp)
+		*temp = tz->emul_temperature;
+skip_emul:
+#endif
+	mutex_unlock(&tz->lock);
+	return ret;
+}
+
+static void update_temperature(struct thermal_zone_device *tz)
+{
+	long temp;
+	int ret;
+
+	ret = thermal_zone_get_temp(tz, &temp);
+	if (ret) {
+		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
+			 tz->id);
+		return;
+	}
+
+	mutex_lock(&tz->lock);
+	tz->last_temperature = tz->temperature;
+	tz->temperature = temp;
+	mutex_unlock(&tz->lock);
+}
+
+void thermal_zone_device_update(struct thermal_zone_device *tz)
+{
+	int count;
+
+	update_temperature(tz);
+
+	for (count = 0; count < tz->trips; count++)
+		handle_thermal_trip(tz, count);
+}
+EXPORT_SYMBOL(thermal_zone_device_update);
+
+static void thermal_zone_device_check(struct work_struct *work)
+{
+	struct thermal_zone_device *tz = container_of(work, struct
+						      thermal_zone_device,
+						      poll_queue.work);
+	thermal_zone_device_update(tz);
+}
+
+/* sys I/F for thermal zone */
+
+#define to_thermal_zone(_dev) \
+	container_of(_dev, struct thermal_zone_device, device)
+
+static ssize_t
+type_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+	return sprintf(buf, "%s\n", tz->type);
+}
+
+static ssize_t
+temp_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	long temperature;
+	int ret;
+
+	ret = thermal_zone_get_temp(tz, &temperature);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%ld\n", temperature);
+}
+
+static ssize_t
+mode_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	enum thermal_device_mode mode;
+	int result;
+
+	if (!tz->ops->get_mode)
+		return -EPERM;
+
+	result = tz->ops->get_mode(tz, &mode);
+	if (result)
+		return result;
+
+	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
+		       : "disabled");
+}
+
+static ssize_t
+mode_store(struct device *dev, struct device_attribute *attr,
+	   const char *buf, size_t count)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int result;
+
+	if (!tz->ops->set_mode)
+		return -EPERM;
+
+	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);
+	else
+		result = -EINVAL;
+
+	if (result)
+		return result;
+
+	return count;
+}
+
+static ssize_t
+trip_point_type_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	enum thermal_trip_type type;
+	int trip, result;
+
+	if (!tz->ops->get_trip_type)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
+		return -EINVAL;
+
+	result = tz->ops->get_trip_type(tz, trip, &type);
+	if (result)
+		return result;
+
+	switch (type) {
+	case THERMAL_TRIP_CRITICAL:
+		return sprintf(buf, "critical\n");
+	case THERMAL_TRIP_HOT:
+		return sprintf(buf, "hot\n");
+	case THERMAL_TRIP_PASSIVE:
+		return sprintf(buf, "passive\n");
+	case THERMAL_TRIP_ACTIVE:
+		return sprintf(buf, "active\n");
+	default:
+		return sprintf(buf, "unknown\n");
+	}
+}
+
+static ssize_t
+trip_point_temp_store(struct device *dev, struct device_attribute *attr,
+		     const char *buf, size_t count)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int trip, ret;
+	unsigned long temperature;
+
+	if (!tz->ops->set_trip_temp)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
+		return -EINVAL;
+
+	if (kstrtoul(buf, 10, &temperature))
+		return -EINVAL;
+
+	ret = tz->ops->set_trip_temp(tz, trip, temperature);
+
+	return ret ? ret : count;
+}
+
+static ssize_t
+trip_point_temp_show(struct device *dev, struct device_attribute *attr,
+		     char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int trip, ret;
+	long temperature;
+
+	if (!tz->ops->get_trip_temp)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
+		return -EINVAL;
+
+	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%ld\n", temperature);
+}
+
+static ssize_t
+trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
+			const char *buf, size_t count)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int trip, ret;
+	unsigned long temperature;
+
+	if (!tz->ops->set_trip_hyst)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
+		return -EINVAL;
+
+	if (kstrtoul(buf, 10, &temperature))
+		return -EINVAL;
+
+	/*
+	 * We are not doing any check on the 'temperature' value
+	 * here. The driver implementing 'set_trip_hyst' has to
+	 * take care of this.
+	 */
+	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
+
+	return ret ? ret : count;
+}
+
+static ssize_t
+trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
+			char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int trip, ret;
+	unsigned long temperature;
+
+	if (!tz->ops->get_trip_hyst)
+		return -EPERM;
+
+	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
+		return -EINVAL;
+
+	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
+
+	return ret ? ret : sprintf(buf, "%ld\n", temperature);
+}
+
+static ssize_t
+passive_store(struct device *dev, struct device_attribute *attr,
+		    const char *buf, size_t count)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	struct thermal_cooling_device *cdev = NULL;
+	int state;
+
+	if (!sscanf(buf, "%d\n", &state))
+		return -EINVAL;
+
+	/* sanity check: values below 1000 millicelcius don't make sense
+	 * and can cause the system to go into a thermal heart attack
+	 */
+	if (state && state < 1000)
+		return -EINVAL;
+
+	if (state && !tz->forced_passive) {
+		mutex_lock(&thermal_list_lock);
+		list_for_each_entry(cdev, &thermal_cdev_list, node) {
+			if (!strncmp("Processor", cdev->type,
+				     sizeof("Processor")))
+				thermal_zone_bind_cooling_device(tz,
+						THERMAL_TRIPS_NONE, cdev,
+						THERMAL_NO_LIMIT,
+						THERMAL_NO_LIMIT);
+		}
+		mutex_unlock(&thermal_list_lock);
+		if (!tz->passive_delay)
+			tz->passive_delay = 1000;
+	} else if (!state && tz->forced_passive) {
+		mutex_lock(&thermal_list_lock);
+		list_for_each_entry(cdev, &thermal_cdev_list, node) {
+			if (!strncmp("Processor", cdev->type,
+				     sizeof("Processor")))
+				thermal_zone_unbind_cooling_device(tz,
+								   THERMAL_TRIPS_NONE,
+								   cdev);
+		}
+		mutex_unlock(&thermal_list_lock);
+		tz->passive_delay = 0;
+	}
+
+	tz->forced_passive = state;
+
+	thermal_zone_device_update(tz);
+
+	return count;
+}
+
+static ssize_t
+passive_show(struct device *dev, struct device_attribute *attr,
+		   char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+	return sprintf(buf, "%d\n", tz->forced_passive);
+}
+
+static ssize_t
+policy_store(struct device *dev, struct device_attribute *attr,
+		    const char *buf, size_t count)
+{
+	int ret = -EINVAL;
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	struct thermal_governor *gov;
+
+	mutex_lock(&thermal_governor_lock);
+
+	gov = __find_governor(buf);
+	if (!gov)
+		goto exit;
+
+	tz->governor = gov;
+	ret = count;
+
+exit:
+	mutex_unlock(&thermal_governor_lock);
+	return ret;
+}
+
+static ssize_t
+policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+
+	return sprintf(buf, "%s\n", tz->governor->name);
+}
+
+#ifdef CONFIG_THERMAL_EMULATION
+static ssize_t
+emul_temp_store(struct device *dev, struct device_attribute *attr,
+		     const char *buf, size_t count)
+{
+	struct thermal_zone_device *tz = to_thermal_zone(dev);
+	int ret = 0;
+	unsigned long temperature;
+
+	if (kstrtoul(buf, 10, &temperature))
+		return -EINVAL;
+
+	if (!tz->ops->set_emul_temp) {
+		mutex_lock(&tz->lock);
+		tz->emul_temperature = temperature;
+		mutex_unlock(&tz->lock);
+	} else {
+		ret = tz->ops->set_emul_temp(tz, temperature);
+	}
+
+	return ret ? ret : count;
+}
+static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
+#endif/*CONFIG_THERMAL_EMULATION*/
+
+static DEVICE_ATTR(type, 0444, type_show, NULL);
+static DEVICE_ATTR(temp, 0444, temp_show, NULL);
+static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
+static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
+static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
+
+/* sys I/F for cooling device */
+#define to_cooling_device(_dev)	\
+	container_of(_dev, struct thermal_cooling_device, device)
+
+static ssize_t
+thermal_cooling_device_type_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+
+	return sprintf(buf, "%s\n", cdev->type);
+}
+
+static ssize_t
+thermal_cooling_device_max_state_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+	unsigned long state;
+	int ret;
+
+	ret = cdev->ops->get_max_state(cdev, &state);
+	if (ret)
+		return ret;
+	return sprintf(buf, "%ld\n", state);
+}
+
+static ssize_t
+thermal_cooling_device_cur_state_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+	unsigned long state;
+	int ret;
+
+	ret = cdev->ops->get_cur_state(cdev, &state);
+	if (ret)
+		return ret;
+	return sprintf(buf, "%ld\n", state);
+}
+
+static ssize_t
+thermal_cooling_device_cur_state_store(struct device *dev,
+				       struct device_attribute *attr,
+				       const char *buf, size_t count)
+{
+	struct thermal_cooling_device *cdev = to_cooling_device(dev);
+	unsigned long state;
+	int result;
+
+	if (!sscanf(buf, "%ld\n", &state))
+		return -EINVAL;
+
+	if ((long)state < 0)
+		return -EINVAL;
+
+	result = cdev->ops->set_cur_state(cdev, state);
+	if (result)
+		return result;
+	return count;
+}
+
+static struct device_attribute dev_attr_cdev_type =
+__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
+static DEVICE_ATTR(max_state, 0444,
+		   thermal_cooling_device_max_state_show, NULL);
+static DEVICE_ATTR(cur_state, 0644,
+		   thermal_cooling_device_cur_state_show,
+		   thermal_cooling_device_cur_state_store);
+
+static ssize_t
+thermal_cooling_device_trip_point_show(struct device *dev,
+				       struct device_attribute *attr, char *buf)
+{
+	struct thermal_instance *instance;
+
+	instance =
+	    container_of(attr, struct thermal_instance, attr);
+
+	if (instance->trip == THERMAL_TRIPS_NONE)
+		return sprintf(buf, "-1\n");
+	else
+		return sprintf(buf, "%d\n", instance->trip);
+}
+
+/* Device management */
+
+#if defined(CONFIG_THERMAL_HWMON)
+
+/* hwmon sys I/F */
+#include <linux/hwmon.h>
+
+/* thermal zone devices with the same type share one hwmon device */
+struct thermal_hwmon_device {
+	char type[THERMAL_NAME_LENGTH];
+	struct device *device;
+	int count;
+	struct list_head tz_list;
+	struct list_head node;
+};
+
+struct thermal_hwmon_attr {
+	struct device_attribute attr;
+	char name[16];
+};
+
+/* one temperature input for each thermal zone */
+struct thermal_hwmon_temp {
+	struct list_head hwmon_node;
+	struct thermal_zone_device *tz;
+	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
+	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
+};
+
+static LIST_HEAD(thermal_hwmon_list);
+
+static ssize_t
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
+	return sprintf(buf, "%s\n", hwmon->type);
+}
+static DEVICE_ATTR(name, 0444, name_show, NULL);
+
+static ssize_t
+temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	long temperature;
+	int ret;
+	struct thermal_hwmon_attr *hwmon_attr
+			= container_of(attr, struct thermal_hwmon_attr, attr);
+	struct thermal_hwmon_temp *temp
+			= container_of(hwmon_attr, struct thermal_hwmon_temp,
+				       temp_input);
+	struct thermal_zone_device *tz = temp->tz;
+
+	ret = thermal_zone_get_temp(tz, &temperature);
+
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%ld\n", temperature);
+}
+
+static ssize_t
+temp_crit_show(struct device *dev, struct device_attribute *attr,
+		char *buf)
+{
+	struct thermal_hwmon_attr *hwmon_attr
+			= container_of(attr, struct thermal_hwmon_attr, attr);
+	struct thermal_hwmon_temp *temp
+			= container_of(hwmon_attr, struct thermal_hwmon_temp,
+				       temp_crit);
+	struct thermal_zone_device *tz = temp->tz;
+	long temperature;
+	int ret;
+
+	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
+	if (ret)
+		return ret;
+
+	return sprintf(buf, "%ld\n", temperature);
+}
+
+
+static struct thermal_hwmon_device *
+thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
+{
+	struct thermal_hwmon_device *hwmon;
+
+	mutex_lock(&thermal_list_lock);
+	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
+		if (!strcmp(hwmon->type, tz->type)) {
+			mutex_unlock(&thermal_list_lock);
+			return hwmon;
+		}
+	mutex_unlock(&thermal_list_lock);
+
+	return NULL;
+}
+
+/* Find the temperature input matching a given thermal zone */
+static struct thermal_hwmon_temp *
+thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
+			  const struct thermal_zone_device *tz)
+{
+	struct thermal_hwmon_temp *temp;
+
+	mutex_lock(&thermal_list_lock);
+	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
+		if (temp->tz == tz) {
+			mutex_unlock(&thermal_list_lock);
+			return temp;
+		}
+	mutex_unlock(&thermal_list_lock);
+
+	return NULL;
+}
+
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+	struct thermal_hwmon_device *hwmon;
+	struct thermal_hwmon_temp *temp;
+	int new_hwmon_device = 1;
+	int result;
+
+	hwmon = thermal_hwmon_lookup_by_type(tz);
+	if (hwmon) {
+		new_hwmon_device = 0;
+		goto register_sys_interface;
+	}
+
+	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
+	if (!hwmon)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&hwmon->tz_list);
+	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
+	hwmon->device = hwmon_device_register(NULL);
+	if (IS_ERR(hwmon->device)) {
+		result = PTR_ERR(hwmon->device);
+		goto free_mem;
+	}
+	dev_set_drvdata(hwmon->device, hwmon);
+	result = device_create_file(hwmon->device, &dev_attr_name);
+	if (result)
+		goto free_mem;
+
+ register_sys_interface:
+	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
+	if (!temp) {
+		result = -ENOMEM;
+		goto unregister_name;
+	}
+
+	temp->tz = tz;
+	hwmon->count++;
+
+	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
+		 "temp%d_input", hwmon->count);
+	temp->temp_input.attr.attr.name = temp->temp_input.name;
+	temp->temp_input.attr.attr.mode = 0444;
+	temp->temp_input.attr.show = temp_input_show;
+	sysfs_attr_init(&temp->temp_input.attr.attr);
+	result = device_create_file(hwmon->device, &temp->temp_input.attr);
+	if (result)
+		goto free_temp_mem;
+
+	if (tz->ops->get_crit_temp) {
+		unsigned long temperature;
+		if (!tz->ops->get_crit_temp(tz, &temperature)) {
+			snprintf(temp->temp_crit.name,
+				 sizeof(temp->temp_crit.name),
+				"temp%d_crit", hwmon->count);
+			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
+			temp->temp_crit.attr.attr.mode = 0444;
+			temp->temp_crit.attr.show = temp_crit_show;
+			sysfs_attr_init(&temp->temp_crit.attr.attr);
+			result = device_create_file(hwmon->device,
+						    &temp->temp_crit.attr);
+			if (result)
+				goto unregister_input;
+		}
+	}
+
+	mutex_lock(&thermal_list_lock);
+	if (new_hwmon_device)
+		list_add_tail(&hwmon->node, &thermal_hwmon_list);
+	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
+	mutex_unlock(&thermal_list_lock);
+
+	return 0;
+
+ unregister_input:
+	device_remove_file(hwmon->device, &temp->temp_input.attr);
+ free_temp_mem:
+	kfree(temp);
+ unregister_name:
+	if (new_hwmon_device) {
+		device_remove_file(hwmon->device, &dev_attr_name);
+		hwmon_device_unregister(hwmon->device);
+	}
+ free_mem:
+	if (new_hwmon_device)
+		kfree(hwmon);
+
+	return result;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+	struct thermal_hwmon_device *hwmon;
+	struct thermal_hwmon_temp *temp;
+
+	hwmon = thermal_hwmon_lookup_by_type(tz);
+	if (unlikely(!hwmon)) {
+		/* Should never happen... */
+		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
+		return;
+	}
+
+	temp = thermal_hwmon_lookup_temp(hwmon, tz);
+	if (unlikely(!temp)) {
+		/* Should never happen... */
+		dev_dbg(&tz->device, "temperature input lookup failed!\n");
+		return;
+	}
+
+	device_remove_file(hwmon->device, &temp->temp_input.attr);
+	if (tz->ops->get_crit_temp)
+		device_remove_file(hwmon->device, &temp->temp_crit.attr);
+
+	mutex_lock(&thermal_list_lock);
+	list_del(&temp->hwmon_node);
+	kfree(temp);
+	if (!list_empty(&hwmon->tz_list)) {
+		mutex_unlock(&thermal_list_lock);
+		return;
+	}
+	list_del(&hwmon->node);
+	mutex_unlock(&thermal_list_lock);
+
+	device_remove_file(hwmon->device, &dev_attr_name);
+	hwmon_device_unregister(hwmon->device);
+	kfree(hwmon);
+}
+#else
+static int
+thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+	return 0;
+}
+
+static void
+thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
+{
+}
+#endif
+
+/**
+ * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
+ * @tz:		thermal zone device
+ * @trip:	indicates which trip point the cooling devices is
+ *		associated with in this thermal zone.
+ * @cdev:	thermal cooling device
+ *
+ * This function is usually called in the thermal zone device .bind callback.
+ */
+int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
+				     int trip,
+				     struct thermal_cooling_device *cdev,
+				     unsigned long upper, unsigned long lower)
+{
+	struct thermal_instance *dev;
+	struct thermal_instance *pos;
+	struct thermal_zone_device *pos1;
+	struct thermal_cooling_device *pos2;
+	unsigned long max_state;
+	int result;
+
+	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
+		return -EINVAL;
+
+	list_for_each_entry(pos1, &thermal_tz_list, node) {
+		if (pos1 == tz)
+			break;
+	}
+	list_for_each_entry(pos2, &thermal_cdev_list, node) {
+		if (pos2 == cdev)
+			break;
+	}
+
+	if (tz != pos1 || cdev != pos2)
+		return -EINVAL;
+
+	cdev->ops->get_max_state(cdev, &max_state);
+
+	/* lower default 0, upper default max_state */
+	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
+	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
+
+	if (lower > upper || upper > max_state)
+		return -EINVAL;
+
+	dev =
+	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+	dev->tz = tz;
+	dev->cdev = cdev;
+	dev->trip = trip;
+	dev->upper = upper;
+	dev->lower = lower;
+	dev->target = THERMAL_NO_TARGET;
+
+	result = get_idr(&tz->idr, &tz->lock, &dev->id);
+	if (result)
+		goto free_mem;
+
+	sprintf(dev->name, "cdev%d", dev->id);
+	result =
+	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
+	if (result)
+		goto release_idr;
+
+	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
+	sysfs_attr_init(&dev->attr.attr);
+	dev->attr.attr.name = dev->attr_name;
+	dev->attr.attr.mode = 0444;
+	dev->attr.show = thermal_cooling_device_trip_point_show;
+	result = device_create_file(&tz->device, &dev->attr);
+	if (result)
+		goto remove_symbol_link;
+
+	mutex_lock(&tz->lock);
+	mutex_lock(&cdev->lock);
+	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
+	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
+		result = -EEXIST;
+		break;
+	}
+	if (!result) {
+		list_add_tail(&dev->tz_node, &tz->thermal_instances);
+		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
+	}
+	mutex_unlock(&cdev->lock);
+	mutex_unlock(&tz->lock);
+
+	if (!result)
+		return 0;
+
+	device_remove_file(&tz->device, &dev->attr);
+remove_symbol_link:
+	sysfs_remove_link(&tz->device.kobj, dev->name);
+release_idr:
+	release_idr(&tz->idr, &tz->lock, dev->id);
+free_mem:
+	kfree(dev);
+	return result;
+}
+EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
+
+/**
+ * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
+ * @tz:		thermal zone device
+ * @trip:	indicates which trip point the cooling devices is
+ *		associated with in this thermal zone.
+ * @cdev:	thermal cooling device
+ *
+ * This function is usually called in the thermal zone device .unbind callback.
+ */
+int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
+				       int trip,
+				       struct thermal_cooling_device *cdev)
+{
+	struct thermal_instance *pos, *next;
+
+	mutex_lock(&tz->lock);
+	mutex_lock(&cdev->lock);
+	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
+		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
+			list_del(&pos->tz_node);
+			list_del(&pos->cdev_node);
+			mutex_unlock(&cdev->lock);
+			mutex_unlock(&tz->lock);
+			goto unbind;
+		}
+	}
+	mutex_unlock(&cdev->lock);
+	mutex_unlock(&tz->lock);
+
+	return -ENODEV;
+
+unbind:
+	device_remove_file(&tz->device, &pos->attr);
+	sysfs_remove_link(&tz->device.kobj, pos->name);
+	release_idr(&tz->idr, &tz->lock, pos->id);
+	kfree(pos);
+	return 0;
+}
+EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
+
+static void thermal_release(struct device *dev)
+{
+	struct thermal_zone_device *tz;
+	struct thermal_cooling_device *cdev;
+
+	if (!strncmp(dev_name(dev), "thermal_zone",
+		     sizeof("thermal_zone") - 1)) {
+		tz = to_thermal_zone(dev);
+		kfree(tz);
+	} else {
+		cdev = to_cooling_device(dev);
+		kfree(cdev);
+	}
+}
+
+static struct class thermal_class = {
+	.name = "thermal",
+	.dev_release = thermal_release,
+};
+
+/**
+ * thermal_cooling_device_register - register a new thermal cooling device
+ * @type:	the thermal cooling device type.
+ * @devdata:	device private data.
+ * @ops:		standard thermal cooling devices callbacks.
+ */
+struct thermal_cooling_device *
+thermal_cooling_device_register(char *type, void *devdata,
+				const struct thermal_cooling_device_ops *ops)
+{
+	struct thermal_cooling_device *cdev;
+	int result;
+
+	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
+		return ERR_PTR(-EINVAL);
+
+	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
+	    !ops->set_cur_state)
+		return ERR_PTR(-EINVAL);
+
+	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
+	if (!cdev)
+		return ERR_PTR(-ENOMEM);
+
+	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
+	if (result) {
+		kfree(cdev);
+		return ERR_PTR(result);
+	}
+
+	strcpy(cdev->type, type ? : "");
+	mutex_init(&cdev->lock);
+	INIT_LIST_HEAD(&cdev->thermal_instances);
+	cdev->ops = ops;
+	cdev->updated = true;
+	cdev->device.class = &thermal_class;
+	cdev->devdata = devdata;
+	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
+	result = device_register(&cdev->device);
+	if (result) {
+		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+		kfree(cdev);
+		return ERR_PTR(result);
+	}
+
+	/* sys I/F */
+	if (type) {
+		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
+		if (result)
+			goto unregister;
+	}
+
+	result = device_create_file(&cdev->device, &dev_attr_max_state);
+	if (result)
+		goto unregister;
+
+	result = device_create_file(&cdev->device, &dev_attr_cur_state);
+	if (result)
+		goto unregister;
+
+	/* Add 'this' new cdev to the global cdev list */
+	mutex_lock(&thermal_list_lock);
+	list_add(&cdev->node, &thermal_cdev_list);
+	mutex_unlock(&thermal_list_lock);
+
+	/* Update binding information for 'this' new cdev */
+	bind_cdev(cdev);
+
+	return cdev;
+
+unregister:
+	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+	device_unregister(&cdev->device);
+	return ERR_PTR(result);
+}
+EXPORT_SYMBOL(thermal_cooling_device_register);
+
+/**
+ * thermal_cooling_device_unregister - removes the registered thermal cooling device
+ * @cdev:	the thermal cooling device to remove.
+ *
+ * thermal_cooling_device_unregister() must be called when the device is no
+ * longer needed.
+ */
+void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
+{
+	int i;
+	const struct thermal_zone_params *tzp;
+	struct thermal_zone_device *tz;
+	struct thermal_cooling_device *pos = NULL;
+
+	if (!cdev)
+		return;
+
+	mutex_lock(&thermal_list_lock);
+	list_for_each_entry(pos, &thermal_cdev_list, node)
+	    if (pos == cdev)
+		break;
+	if (pos != cdev) {
+		/* thermal cooling device not found */
+		mutex_unlock(&thermal_list_lock);
+		return;
+	}
+	list_del(&cdev->node);
+
+	/* Unbind all thermal zones associated with 'this' cdev */
+	list_for_each_entry(tz, &thermal_tz_list, node) {
+		if (tz->ops->unbind) {
+			tz->ops->unbind(tz, cdev);
+			continue;
+		}
+
+		if (!tz->tzp || !tz->tzp->tbp)
+			continue;
+
+		tzp = tz->tzp;
+		for (i = 0; i < tzp->num_tbps; i++) {
+			if (tzp->tbp[i].cdev == cdev) {
+				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
+				tzp->tbp[i].cdev = NULL;
+			}
+		}
+	}
+
+	mutex_unlock(&thermal_list_lock);
+
+	if (cdev->type[0])
+		device_remove_file(&cdev->device, &dev_attr_cdev_type);
+	device_remove_file(&cdev->device, &dev_attr_max_state);
+	device_remove_file(&cdev->device, &dev_attr_cur_state);
+
+	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
+	device_unregister(&cdev->device);
+	return;
+}
+EXPORT_SYMBOL(thermal_cooling_device_unregister);
+
+void thermal_cdev_update(struct thermal_cooling_device *cdev)
+{
+	struct thermal_instance *instance;
+	unsigned long target = 0;
+
+	/* cooling device is updated*/
+	if (cdev->updated)
+		return;
+
+	mutex_lock(&cdev->lock);
+	/* Make sure cdev enters the deepest cooling state */
+	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
+		if (instance->target == THERMAL_NO_TARGET)
+			continue;
+		if (instance->target > target)
+			target = instance->target;
+	}
+	mutex_unlock(&cdev->lock);
+	cdev->ops->set_cur_state(cdev, target);
+	cdev->updated = true;
+}
+EXPORT_SYMBOL(thermal_cdev_update);
+
+/**
+ * notify_thermal_framework - Sensor drivers use this API to notify framework
+ * @tz:		thermal zone device
+ * @trip:	indicates which trip point has been crossed
+ *
+ * This function handles the trip events from sensor drivers. It starts
+ * throttling the cooling devices according to the policy configured.
+ * For CRITICAL and HOT trip points, this notifies the respective drivers,
+ * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
+ * The throttling policy is based on the configured platform data; if no
+ * platform data is provided, this uses the step_wise throttling policy.
+ */
+void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
+{
+	handle_thermal_trip(tz, trip);
+}
+EXPORT_SYMBOL(notify_thermal_framework);
+
+/**
+ * create_trip_attrs - create attributes for trip points
+ * @tz:		the thermal zone device
+ * @mask:	Writeable trip point bitmap.
+ */
+static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
+{
+	int indx;
+	int size = sizeof(struct thermal_attr) * tz->trips;
+
+	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
+	if (!tz->trip_type_attrs)
+		return -ENOMEM;
+
+	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
+	if (!tz->trip_temp_attrs) {
+		kfree(tz->trip_type_attrs);
+		return -ENOMEM;
+	}
+
+	if (tz->ops->get_trip_hyst) {
+		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
+		if (!tz->trip_hyst_attrs) {
+			kfree(tz->trip_type_attrs);
+			kfree(tz->trip_temp_attrs);
+			return -ENOMEM;
+		}
+	}
+
+
+	for (indx = 0; indx < tz->trips; indx++) {
+		/* create trip type attribute */
+		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
+			 "trip_point_%d_type", indx);
+
+		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
+		tz->trip_type_attrs[indx].attr.attr.name =
+						tz->trip_type_attrs[indx].name;
+		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
+		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
+
+		device_create_file(&tz->device,
+				   &tz->trip_type_attrs[indx].attr);
+
+		/* create trip temp attribute */
+		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
+			 "trip_point_%d_temp", indx);
+
+		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
+		tz->trip_temp_attrs[indx].attr.attr.name =
+						tz->trip_temp_attrs[indx].name;
+		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
+		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
+		if (mask & (1 << indx)) {
+			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
+			tz->trip_temp_attrs[indx].attr.store =
+							trip_point_temp_store;
+		}
+
+		device_create_file(&tz->device,
+				   &tz->trip_temp_attrs[indx].attr);
+
+		/* create Optional trip hyst attribute */
+		if (!tz->ops->get_trip_hyst)
+			continue;
+		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
+			 "trip_point_%d_hyst", indx);
+
+		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
+		tz->trip_hyst_attrs[indx].attr.attr.name =
+					tz->trip_hyst_attrs[indx].name;
+		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
+		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
+		if (tz->ops->set_trip_hyst) {
+			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
+			tz->trip_hyst_attrs[indx].attr.store =
+					trip_point_hyst_store;
+		}
+
+		device_create_file(&tz->device,
+				   &tz->trip_hyst_attrs[indx].attr);
+	}
+	return 0;
+}
+
+static void remove_trip_attrs(struct thermal_zone_device *tz)
+{
+	int indx;
+
+	for (indx = 0; indx < tz->trips; indx++) {
+		device_remove_file(&tz->device,
+				   &tz->trip_type_attrs[indx].attr);
+		device_remove_file(&tz->device,
+				   &tz->trip_temp_attrs[indx].attr);
+		if (tz->ops->get_trip_hyst)
+			device_remove_file(&tz->device,
+				  &tz->trip_hyst_attrs[indx].attr);
+	}
+	kfree(tz->trip_type_attrs);
+	kfree(tz->trip_temp_attrs);
+	kfree(tz->trip_hyst_attrs);
+}
+
+/**
+ * thermal_zone_device_register - register a new thermal zone device
+ * @type:	the thermal zone device type
+ * @trips:	the number of trip points the thermal zone support
+ * @mask:	a bit string indicating the writeablility of trip points
+ * @devdata:	private device data
+ * @ops:	standard thermal zone device callbacks
+ * @tzp:	thermal zone platform parameters
+ * @passive_delay: number of milliseconds to wait between polls when
+ *		   performing passive cooling
+ * @polling_delay: number of milliseconds to wait between polls when checking
+ *		   whether trip points have been crossed (0 for interrupt
+ *		   driven systems)
+ *
+ * thermal_zone_device_unregister() must be called when the device is no
+ * longer needed. The passive cooling depends on the .get_trend() return value.
+ */
+struct thermal_zone_device *thermal_zone_device_register(const char *type,
+	int trips, int mask, void *devdata,
+	const struct thermal_zone_device_ops *ops,
+	const struct thermal_zone_params *tzp,
+	int passive_delay, int polling_delay)
+{
+	struct thermal_zone_device *tz;
+	enum thermal_trip_type trip_type;
+	int result;
+	int count;
+	int passive = 0;
+
+	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
+		return ERR_PTR(-EINVAL);
+
+	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
+		return ERR_PTR(-EINVAL);
+
+	if (!ops || !ops->get_temp)
+		return ERR_PTR(-EINVAL);
+
+	if (trips > 0 && !ops->get_trip_type)
+		return ERR_PTR(-EINVAL);
+
+	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
+	if (!tz)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&tz->thermal_instances);
+	idr_init(&tz->idr);
+	mutex_init(&tz->lock);
+	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
+	if (result) {
+		kfree(tz);
+		return ERR_PTR(result);
+	}
+
+	strcpy(tz->type, type ? : "");
+	tz->ops = ops;
+	tz->tzp = tzp;
+	tz->device.class = &thermal_class;
+	tz->devdata = devdata;
+	tz->trips = trips;
+	tz->passive_delay = passive_delay;
+	tz->polling_delay = polling_delay;
+
+	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
+	result = device_register(&tz->device);
+	if (result) {
+		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+		kfree(tz);
+		return ERR_PTR(result);
+	}
+
+	/* sys I/F */
+	if (type) {
+		result = device_create_file(&tz->device, &dev_attr_type);
+		if (result)
+			goto unregister;
+	}
+
+	result = device_create_file(&tz->device, &dev_attr_temp);
+	if (result)
+		goto unregister;
+
+	if (ops->get_mode) {
+		result = device_create_file(&tz->device, &dev_attr_mode);
+		if (result)
+			goto unregister;
+	}
+
+	result = create_trip_attrs(tz, mask);
+	if (result)
+		goto unregister;
+
+	for (count = 0; count < trips; count++) {
+		tz->ops->get_trip_type(tz, count, &trip_type);
+		if (trip_type == THERMAL_TRIP_PASSIVE)
+			passive = 1;
+	}
+
+	if (!passive) {
+		result = device_create_file(&tz->device, &dev_attr_passive);
+		if (result)
+			goto unregister;
+	}
+
+#ifdef CONFIG_THERMAL_EMULATION
+	result = device_create_file(&tz->device, &dev_attr_emul_temp);
+	if (result)
+		goto unregister;
+#endif
+	/* Create policy attribute */
+	result = device_create_file(&tz->device, &dev_attr_policy);
+	if (result)
+		goto unregister;
+
+	/* Update 'this' zone's governor information */
+	mutex_lock(&thermal_governor_lock);
+
+	if (tz->tzp)
+		tz->governor = __find_governor(tz->tzp->governor_name);
+	else
+		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
+
+	mutex_unlock(&thermal_governor_lock);
+
+	result = thermal_add_hwmon_sysfs(tz);
+	if (result)
+		goto unregister;
+
+	mutex_lock(&thermal_list_lock);
+	list_add_tail(&tz->node, &thermal_tz_list);
+	mutex_unlock(&thermal_list_lock);
+
+	/* Bind cooling devices for this zone */
+	bind_tz(tz);
+
+	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
+
+	thermal_zone_device_update(tz);
+
+	if (!result)
+		return tz;
+
+unregister:
+	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+	device_unregister(&tz->device);
+	return ERR_PTR(result);
+}
+EXPORT_SYMBOL(thermal_zone_device_register);
+
+/**
+ * thermal_device_unregister - removes the registered thermal zone device
+ * @tz: the thermal zone device to remove
+ */
+void thermal_zone_device_unregister(struct thermal_zone_device *tz)
+{
+	int i;
+	const struct thermal_zone_params *tzp;
+	struct thermal_cooling_device *cdev;
+	struct thermal_zone_device *pos = NULL;
+
+	if (!tz)
+		return;
+
+	tzp = tz->tzp;
+
+	mutex_lock(&thermal_list_lock);
+	list_for_each_entry(pos, &thermal_tz_list, node)
+	    if (pos == tz)
+		break;
+	if (pos != tz) {
+		/* thermal zone device not found */
+		mutex_unlock(&thermal_list_lock);
+		return;
+	}
+	list_del(&tz->node);
+
+	/* Unbind all cdevs associated with 'this' thermal zone */
+	list_for_each_entry(cdev, &thermal_cdev_list, node) {
+		if (tz->ops->unbind) {
+			tz->ops->unbind(tz, cdev);
+			continue;
+		}
+
+		if (!tzp || !tzp->tbp)
+			break;
+
+		for (i = 0; i < tzp->num_tbps; i++) {
+			if (tzp->tbp[i].cdev == cdev) {
+				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
+				tzp->tbp[i].cdev = NULL;
+			}
+		}
+	}
+
+	mutex_unlock(&thermal_list_lock);
+
+	thermal_zone_device_set_polling(tz, 0);
+
+	if (tz->type[0])
+		device_remove_file(&tz->device, &dev_attr_type);
+	device_remove_file(&tz->device, &dev_attr_temp);
+	if (tz->ops->get_mode)
+		device_remove_file(&tz->device, &dev_attr_mode);
+	device_remove_file(&tz->device, &dev_attr_policy);
+	remove_trip_attrs(tz);
+	tz->governor = NULL;
+
+	thermal_remove_hwmon_sysfs(tz);
+	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
+	idr_destroy(&tz->idr);
+	mutex_destroy(&tz->lock);
+	device_unregister(&tz->device);
+	return;
+}
+EXPORT_SYMBOL(thermal_zone_device_unregister);
+
+#ifdef CONFIG_NET
+static struct genl_family thermal_event_genl_family = {
+	.id = GENL_ID_GENERATE,
+	.name = THERMAL_GENL_FAMILY_NAME,
+	.version = THERMAL_GENL_VERSION,
+	.maxattr = THERMAL_GENL_ATTR_MAX,
+};
+
+static struct genl_multicast_group thermal_event_mcgrp = {
+	.name = THERMAL_GENL_MCAST_GROUP_NAME,
+};
+
+int thermal_generate_netlink_event(struct thermal_zone_device *tz,
+					enum events event)
+{
+	struct sk_buff *skb;
+	struct nlattr *attr;
+	struct thermal_genl_event *thermal_event;
+	void *msg_header;
+	int size;
+	int result;
+	static unsigned int thermal_event_seqnum;
+
+	if (!tz)
+		return -EINVAL;
+
+	/* allocate memory */
+	size = nla_total_size(sizeof(struct thermal_genl_event)) +
+	       nla_total_size(0);
+
+	skb = genlmsg_new(size, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	/* add the genetlink message header */
+	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
+				 &thermal_event_genl_family, 0,
+				 THERMAL_GENL_CMD_EVENT);
+	if (!msg_header) {
+		nlmsg_free(skb);
+		return -ENOMEM;
+	}
+
+	/* fill the data */
+	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
+			   sizeof(struct thermal_genl_event));
+
+	if (!attr) {
+		nlmsg_free(skb);
+		return -EINVAL;
+	}
+
+	thermal_event = nla_data(attr);
+	if (!thermal_event) {
+		nlmsg_free(skb);
+		return -EINVAL;
+	}
+
+	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
+
+	thermal_event->orig = tz->id;
+	thermal_event->event = event;
+
+	/* send multicast genetlink message */
+	result = genlmsg_end(skb, msg_header);
+	if (result < 0) {
+		nlmsg_free(skb);
+		return result;
+	}
+
+	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
+	if (result)
+		dev_err(&tz->device, "Failed to send netlink event:%d", result);
+
+	return result;
+}
+EXPORT_SYMBOL(thermal_generate_netlink_event);
+
+static int genetlink_init(void)
+{
+	int result;
+
+	result = genl_register_family(&thermal_event_genl_family);
+	if (result)
+		return result;
+
+	result = genl_register_mc_group(&thermal_event_genl_family,
+					&thermal_event_mcgrp);
+	if (result)
+		genl_unregister_family(&thermal_event_genl_family);
+	return result;
+}
+
+static void genetlink_exit(void)
+{
+	genl_unregister_family(&thermal_event_genl_family);
+}
+#else /* !CONFIG_NET */
+static inline int genetlink_init(void) { return 0; }
+static inline void genetlink_exit(void) {}
+#endif /* !CONFIG_NET */
+
+static int __init thermal_init(void)
+{
+	int result = 0;
+
+	result = class_register(&thermal_class);
+	if (result) {
+		idr_destroy(&thermal_tz_idr);
+		idr_destroy(&thermal_cdev_idr);
+		mutex_destroy(&thermal_idr_lock);
+		mutex_destroy(&thermal_list_lock);
+		return result;
+	}
+	result = genetlink_init();
+	return result;
+}
+
+static void __exit thermal_exit(void)
+{
+	class_unregister(&thermal_class);
+	idr_destroy(&thermal_tz_idr);
+	idr_destroy(&thermal_cdev_idr);
+	mutex_destroy(&thermal_idr_lock);
+	mutex_destroy(&thermal_list_lock);
+	genetlink_exit();
+}
+
+fs_initcall(thermal_init);
+module_exit(thermal_exit);
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
deleted file mode 100644
index 5b7863a..0000000
--- a/drivers/thermal/thermal_sys.c
+++ /dev/null
@@ -1,1888 +0,0 @@
-/*
- *  thermal.c - Generic Thermal Management Sysfs support.
- *
- *  Copyright (C) 2008 Intel Corp
- *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
- *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
- *
- *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; version 2 of the License.
- *
- *  This program is distributed in the hope that it will be useful, but
- *  WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/kdev_t.h>
-#include <linux/idr.h>
-#include <linux/thermal.h>
-#include <linux/reboot.h>
-#include <net/netlink.h>
-#include <net/genetlink.h>
-
-#include "thermal_core.h"
-
-MODULE_AUTHOR("Zhang Rui");
-MODULE_DESCRIPTION("Generic thermal management sysfs support");
-MODULE_LICENSE("GPL");
-
-static DEFINE_IDR(thermal_tz_idr);
-static DEFINE_IDR(thermal_cdev_idr);
-static DEFINE_MUTEX(thermal_idr_lock);
-
-static LIST_HEAD(thermal_tz_list);
-static LIST_HEAD(thermal_cdev_list);
-static LIST_HEAD(thermal_governor_list);
-
-static DEFINE_MUTEX(thermal_list_lock);
-static DEFINE_MUTEX(thermal_governor_lock);
-
-static struct thermal_governor *__find_governor(const char *name)
-{
-	struct thermal_governor *pos;
-
-	list_for_each_entry(pos, &thermal_governor_list, governor_list)
-		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
-			return pos;
-
-	return NULL;
-}
-
-int thermal_register_governor(struct thermal_governor *governor)
-{
-	int err;
-	const char *name;
-	struct thermal_zone_device *pos;
-
-	if (!governor)
-		return -EINVAL;
-
-	mutex_lock(&thermal_governor_lock);
-
-	err = -EBUSY;
-	if (__find_governor(governor->name) == NULL) {
-		err = 0;
-		list_add(&governor->governor_list, &thermal_governor_list);
-	}
-
-	mutex_lock(&thermal_list_lock);
-
-	list_for_each_entry(pos, &thermal_tz_list, node) {
-		if (pos->governor)
-			continue;
-		if (pos->tzp)
-			name = pos->tzp->governor_name;
-		else
-			name = DEFAULT_THERMAL_GOVERNOR;
-		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
-			pos->governor = governor;
-	}
-
-	mutex_unlock(&thermal_list_lock);
-	mutex_unlock(&thermal_governor_lock);
-
-	return err;
-}
-EXPORT_SYMBOL_GPL(thermal_register_governor);
-
-void thermal_unregister_governor(struct thermal_governor *governor)
-{
-	struct thermal_zone_device *pos;
-
-	if (!governor)
-		return;
-
-	mutex_lock(&thermal_governor_lock);
-
-	if (__find_governor(governor->name) == NULL)
-		goto exit;
-
-	mutex_lock(&thermal_list_lock);
-
-	list_for_each_entry(pos, &thermal_tz_list, node) {
-		if (!strnicmp(pos->governor->name, governor->name,
-						THERMAL_NAME_LENGTH))
-			pos->governor = NULL;
-	}
-
-	mutex_unlock(&thermal_list_lock);
-	list_del(&governor->governor_list);
-exit:
-	mutex_unlock(&thermal_governor_lock);
-	return;
-}
-EXPORT_SYMBOL_GPL(thermal_unregister_governor);
-
-static int get_idr(struct idr *idr, struct mutex *lock, int *id)
-{
-	int ret;
-
-	if (lock)
-		mutex_lock(lock);
-	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
-	if (lock)
-		mutex_unlock(lock);
-	if (unlikely(ret < 0))
-		return ret;
-	*id = ret;
-	return 0;
-}
-
-static void release_idr(struct idr *idr, struct mutex *lock, int id)
-{
-	if (lock)
-		mutex_lock(lock);
-	idr_remove(idr, id);
-	if (lock)
-		mutex_unlock(lock);
-}
-
-int get_tz_trend(struct thermal_zone_device *tz, int trip)
-{
-	enum thermal_trend trend;
-
-	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
-		if (tz->temperature > tz->last_temperature)
-			trend = THERMAL_TREND_RAISING;
-		else if (tz->temperature < tz->last_temperature)
-			trend = THERMAL_TREND_DROPPING;
-		else
-			trend = THERMAL_TREND_STABLE;
-	}
-
-	return trend;
-}
-EXPORT_SYMBOL(get_tz_trend);
-
-struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
-			struct thermal_cooling_device *cdev, int trip)
-{
-	struct thermal_instance *pos = NULL;
-	struct thermal_instance *target_instance = NULL;
-
-	mutex_lock(&tz->lock);
-	mutex_lock(&cdev->lock);
-
-	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
-		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
-			target_instance = pos;
-			break;
-		}
-	}
-
-	mutex_unlock(&cdev->lock);
-	mutex_unlock(&tz->lock);
-
-	return target_instance;
-}
-EXPORT_SYMBOL(get_thermal_instance);
-
-static void print_bind_err_msg(struct thermal_zone_device *tz,
-			struct thermal_cooling_device *cdev, int ret)
-{
-	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
-				tz->type, cdev->type, ret);
-}
-
-static void __bind(struct thermal_zone_device *tz, int mask,
-			struct thermal_cooling_device *cdev)
-{
-	int i, ret;
-
-	for (i = 0; i < tz->trips; i++) {
-		if (mask & (1 << i)) {
-			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
-					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
-			if (ret)
-				print_bind_err_msg(tz, cdev, ret);
-		}
-	}
-}
-
-static void __unbind(struct thermal_zone_device *tz, int mask,
-			struct thermal_cooling_device *cdev)
-{
-	int i;
-
-	for (i = 0; i < tz->trips; i++)
-		if (mask & (1 << i))
-			thermal_zone_unbind_cooling_device(tz, i, cdev);
-}
-
-static void bind_cdev(struct thermal_cooling_device *cdev)
-{
-	int i, ret;
-	const struct thermal_zone_params *tzp;
-	struct thermal_zone_device *pos = NULL;
-
-	mutex_lock(&thermal_list_lock);
-
-	list_for_each_entry(pos, &thermal_tz_list, node) {
-		if (!pos->tzp && !pos->ops->bind)
-			continue;
-
-		if (!pos->tzp && pos->ops->bind) {
-			ret = pos->ops->bind(pos, cdev);
-			if (ret)
-				print_bind_err_msg(pos, cdev, ret);
-		}
-
-		tzp = pos->tzp;
-		if (!tzp || !tzp->tbp)
-			continue;
-
-		for (i = 0; i < tzp->num_tbps; i++) {
-			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
-				continue;
-			if (tzp->tbp[i].match(pos, cdev))
-				continue;
-			tzp->tbp[i].cdev = cdev;
-			__bind(pos, tzp->tbp[i].trip_mask, cdev);
-		}
-	}
-
-	mutex_unlock(&thermal_list_lock);
-}
-
-static void bind_tz(struct thermal_zone_device *tz)
-{
-	int i, ret;
-	struct thermal_cooling_device *pos = NULL;
-	const struct thermal_zone_params *tzp = tz->tzp;
-
-	if (!tzp && !tz->ops->bind)
-		return;
-
-	mutex_lock(&thermal_list_lock);
-
-	/* If there is no platform data, try to use ops->bind */
-	if (!tzp && tz->ops->bind) {
-		list_for_each_entry(pos, &thermal_cdev_list, node) {
-			ret = tz->ops->bind(tz, pos);
-			if (ret)
-				print_bind_err_msg(tz, pos, ret);
-		}
-		goto exit;
-	}
-
-	if (!tzp || !tzp->tbp)
-		goto exit;
-
-	list_for_each_entry(pos, &thermal_cdev_list, node) {
-		for (i = 0; i < tzp->num_tbps; i++) {
-			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
-				continue;
-			if (tzp->tbp[i].match(tz, pos))
-				continue;
-			tzp->tbp[i].cdev = pos;
-			__bind(tz, tzp->tbp[i].trip_mask, pos);
-		}
-	}
-exit:
-	mutex_unlock(&thermal_list_lock);
-}
-
-static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
-					    int delay)
-{
-	if (delay > 1000)
-		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
-				 round_jiffies(msecs_to_jiffies(delay)));
-	else if (delay)
-		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
-				 msecs_to_jiffies(delay));
-	else
-		cancel_delayed_work(&tz->poll_queue);
-}
-
-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);
-	else if (tz->polling_delay)
-		thermal_zone_device_set_polling(tz, tz->polling_delay);
-	else
-		thermal_zone_device_set_polling(tz, 0);
-
-	mutex_unlock(&tz->lock);
-}
-
-static void handle_non_critical_trips(struct thermal_zone_device *tz,
-			int trip, enum thermal_trip_type trip_type)
-{
-	if (tz->governor)
-		tz->governor->throttle(tz, trip);
-}
-
-static void handle_critical_trips(struct thermal_zone_device *tz,
-				int trip, enum thermal_trip_type trip_type)
-{
-	long trip_temp;
-
-	tz->ops->get_trip_temp(tz, trip, &trip_temp);
-
-	/* If we have not crossed the trip_temp, we do not care. */
-	if (tz->temperature < trip_temp)
-		return;
-
-	if (tz->ops->notify)
-		tz->ops->notify(tz, trip, trip_type);
-
-	if (trip_type == THERMAL_TRIP_CRITICAL) {
-		dev_emerg(&tz->device,
-			  "critical temperature reached(%d C),shutting down\n",
-			  tz->temperature / 1000);
-		orderly_poweroff(true);
-	}
-}
-
-static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
-{
-	enum thermal_trip_type type;
-
-	tz->ops->get_trip_type(tz, trip, &type);
-
-	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
-		handle_critical_trips(tz, trip, type);
-	else
-		handle_non_critical_trips(tz, trip, type);
-	/*
-	 * Alright, we handled this trip successfully.
-	 * So, start monitoring again.
-	 */
-	monitor_thermal_zone(tz);
-}
-
-static int thermal_zone_get_temp(struct thermal_zone_device *tz,
-				unsigned long *temp)
-{
-	int ret = 0;
-#ifdef CONFIG_THERMAL_EMULATION
-	int count;
-	unsigned long crit_temp = -1UL;
-	enum thermal_trip_type type;
-#endif
-
-	mutex_lock(&tz->lock);
-
-	ret = tz->ops->get_temp(tz, temp);
-#ifdef CONFIG_THERMAL_EMULATION
-	if (!tz->emul_temperature)
-		goto skip_emul;
-
-	for (count = 0; count < tz->trips; count++) {
-		ret = tz->ops->get_trip_type(tz, count, &type);
-		if (!ret && type == THERMAL_TRIP_CRITICAL) {
-			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
-			break;
-		}
-	}
-
-	if (ret)
-		goto skip_emul;
-
-	if (*temp < crit_temp)
-		*temp = tz->emul_temperature;
-skip_emul:
-#endif
-	mutex_unlock(&tz->lock);
-	return ret;
-}
-
-static void update_temperature(struct thermal_zone_device *tz)
-{
-	long temp;
-	int ret;
-
-	ret = thermal_zone_get_temp(tz, &temp);
-	if (ret) {
-		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
-			 tz->id);
-		return;
-	}
-
-	mutex_lock(&tz->lock);
-	tz->last_temperature = tz->temperature;
-	tz->temperature = temp;
-	mutex_unlock(&tz->lock);
-}
-
-void thermal_zone_device_update(struct thermal_zone_device *tz)
-{
-	int count;
-
-	update_temperature(tz);
-
-	for (count = 0; count < tz->trips; count++)
-		handle_thermal_trip(tz, count);
-}
-EXPORT_SYMBOL(thermal_zone_device_update);
-
-static void thermal_zone_device_check(struct work_struct *work)
-{
-	struct thermal_zone_device *tz = container_of(work, struct
-						      thermal_zone_device,
-						      poll_queue.work);
-	thermal_zone_device_update(tz);
-}
-
-/* sys I/F for thermal zone */
-
-#define to_thermal_zone(_dev) \
-	container_of(_dev, struct thermal_zone_device, device)
-
-static ssize_t
-type_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-
-	return sprintf(buf, "%s\n", tz->type);
-}
-
-static ssize_t
-temp_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	long temperature;
-	int ret;
-
-	ret = thermal_zone_get_temp(tz, &temperature);
-
-	if (ret)
-		return ret;
-
-	return sprintf(buf, "%ld\n", temperature);
-}
-
-static ssize_t
-mode_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	enum thermal_device_mode mode;
-	int result;
-
-	if (!tz->ops->get_mode)
-		return -EPERM;
-
-	result = tz->ops->get_mode(tz, &mode);
-	if (result)
-		return result;
-
-	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
-		       : "disabled");
-}
-
-static ssize_t
-mode_store(struct device *dev, struct device_attribute *attr,
-	   const char *buf, size_t count)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	int result;
-
-	if (!tz->ops->set_mode)
-		return -EPERM;
-
-	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);
-	else
-		result = -EINVAL;
-
-	if (result)
-		return result;
-
-	return count;
-}
-
-static ssize_t
-trip_point_type_show(struct device *dev, struct device_attribute *attr,
-		     char *buf)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	enum thermal_trip_type type;
-	int trip, result;
-
-	if (!tz->ops->get_trip_type)
-		return -EPERM;
-
-	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
-		return -EINVAL;
-
-	result = tz->ops->get_trip_type(tz, trip, &type);
-	if (result)
-		return result;
-
-	switch (type) {
-	case THERMAL_TRIP_CRITICAL:
-		return sprintf(buf, "critical\n");
-	case THERMAL_TRIP_HOT:
-		return sprintf(buf, "hot\n");
-	case THERMAL_TRIP_PASSIVE:
-		return sprintf(buf, "passive\n");
-	case THERMAL_TRIP_ACTIVE:
-		return sprintf(buf, "active\n");
-	default:
-		return sprintf(buf, "unknown\n");
-	}
-}
-
-static ssize_t
-trip_point_temp_store(struct device *dev, struct device_attribute *attr,
-		     const char *buf, size_t count)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	int trip, ret;
-	unsigned long temperature;
-
-	if (!tz->ops->set_trip_temp)
-		return -EPERM;
-
-	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
-		return -EINVAL;
-
-	if (kstrtoul(buf, 10, &temperature))
-		return -EINVAL;
-
-	ret = tz->ops->set_trip_temp(tz, trip, temperature);
-
-	return ret ? ret : count;
-}
-
-static ssize_t
-trip_point_temp_show(struct device *dev, struct device_attribute *attr,
-		     char *buf)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	int trip, ret;
-	long temperature;
-
-	if (!tz->ops->get_trip_temp)
-		return -EPERM;
-
-	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
-		return -EINVAL;
-
-	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
-
-	if (ret)
-		return ret;
-
-	return sprintf(buf, "%ld\n", temperature);
-}
-
-static ssize_t
-trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
-			const char *buf, size_t count)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	int trip, ret;
-	unsigned long temperature;
-
-	if (!tz->ops->set_trip_hyst)
-		return -EPERM;
-
-	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
-		return -EINVAL;
-
-	if (kstrtoul(buf, 10, &temperature))
-		return -EINVAL;
-
-	/*
-	 * We are not doing any check on the 'temperature' value
-	 * here. The driver implementing 'set_trip_hyst' has to
-	 * take care of this.
-	 */
-	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
-
-	return ret ? ret : count;
-}
-
-static ssize_t
-trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
-			char *buf)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	int trip, ret;
-	unsigned long temperature;
-
-	if (!tz->ops->get_trip_hyst)
-		return -EPERM;
-
-	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
-		return -EINVAL;
-
-	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
-
-	return ret ? ret : sprintf(buf, "%ld\n", temperature);
-}
-
-static ssize_t
-passive_store(struct device *dev, struct device_attribute *attr,
-		    const char *buf, size_t count)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	struct thermal_cooling_device *cdev = NULL;
-	int state;
-
-	if (!sscanf(buf, "%d\n", &state))
-		return -EINVAL;
-
-	/* sanity check: values below 1000 millicelcius don't make sense
-	 * and can cause the system to go into a thermal heart attack
-	 */
-	if (state && state < 1000)
-		return -EINVAL;
-
-	if (state && !tz->forced_passive) {
-		mutex_lock(&thermal_list_lock);
-		list_for_each_entry(cdev, &thermal_cdev_list, node) {
-			if (!strncmp("Processor", cdev->type,
-				     sizeof("Processor")))
-				thermal_zone_bind_cooling_device(tz,
-						THERMAL_TRIPS_NONE, cdev,
-						THERMAL_NO_LIMIT,
-						THERMAL_NO_LIMIT);
-		}
-		mutex_unlock(&thermal_list_lock);
-		if (!tz->passive_delay)
-			tz->passive_delay = 1000;
-	} else if (!state && tz->forced_passive) {
-		mutex_lock(&thermal_list_lock);
-		list_for_each_entry(cdev, &thermal_cdev_list, node) {
-			if (!strncmp("Processor", cdev->type,
-				     sizeof("Processor")))
-				thermal_zone_unbind_cooling_device(tz,
-								   THERMAL_TRIPS_NONE,
-								   cdev);
-		}
-		mutex_unlock(&thermal_list_lock);
-		tz->passive_delay = 0;
-	}
-
-	tz->forced_passive = state;
-
-	thermal_zone_device_update(tz);
-
-	return count;
-}
-
-static ssize_t
-passive_show(struct device *dev, struct device_attribute *attr,
-		   char *buf)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-
-	return sprintf(buf, "%d\n", tz->forced_passive);
-}
-
-static ssize_t
-policy_store(struct device *dev, struct device_attribute *attr,
-		    const char *buf, size_t count)
-{
-	int ret = -EINVAL;
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	struct thermal_governor *gov;
-
-	mutex_lock(&thermal_governor_lock);
-
-	gov = __find_governor(buf);
-	if (!gov)
-		goto exit;
-
-	tz->governor = gov;
-	ret = count;
-
-exit:
-	mutex_unlock(&thermal_governor_lock);
-	return ret;
-}
-
-static ssize_t
-policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-
-	return sprintf(buf, "%s\n", tz->governor->name);
-}
-
-#ifdef CONFIG_THERMAL_EMULATION
-static ssize_t
-emul_temp_store(struct device *dev, struct device_attribute *attr,
-		     const char *buf, size_t count)
-{
-	struct thermal_zone_device *tz = to_thermal_zone(dev);
-	int ret = 0;
-	unsigned long temperature;
-
-	if (kstrtoul(buf, 10, &temperature))
-		return -EINVAL;
-
-	if (!tz->ops->set_emul_temp) {
-		mutex_lock(&tz->lock);
-		tz->emul_temperature = temperature;
-		mutex_unlock(&tz->lock);
-	} else {
-		ret = tz->ops->set_emul_temp(tz, temperature);
-	}
-
-	return ret ? ret : count;
-}
-static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
-#endif/*CONFIG_THERMAL_EMULATION*/
-
-static DEVICE_ATTR(type, 0444, type_show, NULL);
-static DEVICE_ATTR(temp, 0444, temp_show, NULL);
-static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
-static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
-static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
-
-/* sys I/F for cooling device */
-#define to_cooling_device(_dev)	\
-	container_of(_dev, struct thermal_cooling_device, device)
-
-static ssize_t
-thermal_cooling_device_type_show(struct device *dev,
-				 struct device_attribute *attr, char *buf)
-{
-	struct thermal_cooling_device *cdev = to_cooling_device(dev);
-
-	return sprintf(buf, "%s\n", cdev->type);
-}
-
-static ssize_t
-thermal_cooling_device_max_state_show(struct device *dev,
-				      struct device_attribute *attr, char *buf)
-{
-	struct thermal_cooling_device *cdev = to_cooling_device(dev);
-	unsigned long state;
-	int ret;
-
-	ret = cdev->ops->get_max_state(cdev, &state);
-	if (ret)
-		return ret;
-	return sprintf(buf, "%ld\n", state);
-}
-
-static ssize_t
-thermal_cooling_device_cur_state_show(struct device *dev,
-				      struct device_attribute *attr, char *buf)
-{
-	struct thermal_cooling_device *cdev = to_cooling_device(dev);
-	unsigned long state;
-	int ret;
-
-	ret = cdev->ops->get_cur_state(cdev, &state);
-	if (ret)
-		return ret;
-	return sprintf(buf, "%ld\n", state);
-}
-
-static ssize_t
-thermal_cooling_device_cur_state_store(struct device *dev,
-				       struct device_attribute *attr,
-				       const char *buf, size_t count)
-{
-	struct thermal_cooling_device *cdev = to_cooling_device(dev);
-	unsigned long state;
-	int result;
-
-	if (!sscanf(buf, "%ld\n", &state))
-		return -EINVAL;
-
-	if ((long)state < 0)
-		return -EINVAL;
-
-	result = cdev->ops->set_cur_state(cdev, state);
-	if (result)
-		return result;
-	return count;
-}
-
-static struct device_attribute dev_attr_cdev_type =
-__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
-static DEVICE_ATTR(max_state, 0444,
-		   thermal_cooling_device_max_state_show, NULL);
-static DEVICE_ATTR(cur_state, 0644,
-		   thermal_cooling_device_cur_state_show,
-		   thermal_cooling_device_cur_state_store);
-
-static ssize_t
-thermal_cooling_device_trip_point_show(struct device *dev,
-				       struct device_attribute *attr, char *buf)
-{
-	struct thermal_instance *instance;
-
-	instance =
-	    container_of(attr, struct thermal_instance, attr);
-
-	if (instance->trip == THERMAL_TRIPS_NONE)
-		return sprintf(buf, "-1\n");
-	else
-		return sprintf(buf, "%d\n", instance->trip);
-}
-
-/* Device management */
-
-#if defined(CONFIG_THERMAL_HWMON)
-
-/* hwmon sys I/F */
-#include <linux/hwmon.h>
-
-/* thermal zone devices with the same type share one hwmon device */
-struct thermal_hwmon_device {
-	char type[THERMAL_NAME_LENGTH];
-	struct device *device;
-	int count;
-	struct list_head tz_list;
-	struct list_head node;
-};
-
-struct thermal_hwmon_attr {
-	struct device_attribute attr;
-	char name[16];
-};
-
-/* one temperature input for each thermal zone */
-struct thermal_hwmon_temp {
-	struct list_head hwmon_node;
-	struct thermal_zone_device *tz;
-	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
-	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
-};
-
-static LIST_HEAD(thermal_hwmon_list);
-
-static ssize_t
-name_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
-	return sprintf(buf, "%s\n", hwmon->type);
-}
-static DEVICE_ATTR(name, 0444, name_show, NULL);
-
-static ssize_t
-temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
-{
-	long temperature;
-	int ret;
-	struct thermal_hwmon_attr *hwmon_attr
-			= container_of(attr, struct thermal_hwmon_attr, attr);
-	struct thermal_hwmon_temp *temp
-			= container_of(hwmon_attr, struct thermal_hwmon_temp,
-				       temp_input);
-	struct thermal_zone_device *tz = temp->tz;
-
-	ret = thermal_zone_get_temp(tz, &temperature);
-
-	if (ret)
-		return ret;
-
-	return sprintf(buf, "%ld\n", temperature);
-}
-
-static ssize_t
-temp_crit_show(struct device *dev, struct device_attribute *attr,
-		char *buf)
-{
-	struct thermal_hwmon_attr *hwmon_attr
-			= container_of(attr, struct thermal_hwmon_attr, attr);
-	struct thermal_hwmon_temp *temp
-			= container_of(hwmon_attr, struct thermal_hwmon_temp,
-				       temp_crit);
-	struct thermal_zone_device *tz = temp->tz;
-	long temperature;
-	int ret;
-
-	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
-	if (ret)
-		return ret;
-
-	return sprintf(buf, "%ld\n", temperature);
-}
-
-
-static struct thermal_hwmon_device *
-thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
-{
-	struct thermal_hwmon_device *hwmon;
-
-	mutex_lock(&thermal_list_lock);
-	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
-		if (!strcmp(hwmon->type, tz->type)) {
-			mutex_unlock(&thermal_list_lock);
-			return hwmon;
-		}
-	mutex_unlock(&thermal_list_lock);
-
-	return NULL;
-}
-
-/* Find the temperature input matching a given thermal zone */
-static struct thermal_hwmon_temp *
-thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
-			  const struct thermal_zone_device *tz)
-{
-	struct thermal_hwmon_temp *temp;
-
-	mutex_lock(&thermal_list_lock);
-	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
-		if (temp->tz == tz) {
-			mutex_unlock(&thermal_list_lock);
-			return temp;
-		}
-	mutex_unlock(&thermal_list_lock);
-
-	return NULL;
-}
-
-static int
-thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
-{
-	struct thermal_hwmon_device *hwmon;
-	struct thermal_hwmon_temp *temp;
-	int new_hwmon_device = 1;
-	int result;
-
-	hwmon = thermal_hwmon_lookup_by_type(tz);
-	if (hwmon) {
-		new_hwmon_device = 0;
-		goto register_sys_interface;
-	}
-
-	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
-	if (!hwmon)
-		return -ENOMEM;
-
-	INIT_LIST_HEAD(&hwmon->tz_list);
-	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
-	hwmon->device = hwmon_device_register(NULL);
-	if (IS_ERR(hwmon->device)) {
-		result = PTR_ERR(hwmon->device);
-		goto free_mem;
-	}
-	dev_set_drvdata(hwmon->device, hwmon);
-	result = device_create_file(hwmon->device, &dev_attr_name);
-	if (result)
-		goto free_mem;
-
- register_sys_interface:
-	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
-	if (!temp) {
-		result = -ENOMEM;
-		goto unregister_name;
-	}
-
-	temp->tz = tz;
-	hwmon->count++;
-
-	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
-		 "temp%d_input", hwmon->count);
-	temp->temp_input.attr.attr.name = temp->temp_input.name;
-	temp->temp_input.attr.attr.mode = 0444;
-	temp->temp_input.attr.show = temp_input_show;
-	sysfs_attr_init(&temp->temp_input.attr.attr);
-	result = device_create_file(hwmon->device, &temp->temp_input.attr);
-	if (result)
-		goto free_temp_mem;
-
-	if (tz->ops->get_crit_temp) {
-		unsigned long temperature;
-		if (!tz->ops->get_crit_temp(tz, &temperature)) {
-			snprintf(temp->temp_crit.name,
-				 sizeof(temp->temp_crit.name),
-				"temp%d_crit", hwmon->count);
-			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
-			temp->temp_crit.attr.attr.mode = 0444;
-			temp->temp_crit.attr.show = temp_crit_show;
-			sysfs_attr_init(&temp->temp_crit.attr.attr);
-			result = device_create_file(hwmon->device,
-						    &temp->temp_crit.attr);
-			if (result)
-				goto unregister_input;
-		}
-	}
-
-	mutex_lock(&thermal_list_lock);
-	if (new_hwmon_device)
-		list_add_tail(&hwmon->node, &thermal_hwmon_list);
-	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
-	mutex_unlock(&thermal_list_lock);
-
-	return 0;
-
- unregister_input:
-	device_remove_file(hwmon->device, &temp->temp_input.attr);
- free_temp_mem:
-	kfree(temp);
- unregister_name:
-	if (new_hwmon_device) {
-		device_remove_file(hwmon->device, &dev_attr_name);
-		hwmon_device_unregister(hwmon->device);
-	}
- free_mem:
-	if (new_hwmon_device)
-		kfree(hwmon);
-
-	return result;
-}
-
-static void
-thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
-{
-	struct thermal_hwmon_device *hwmon;
-	struct thermal_hwmon_temp *temp;
-
-	hwmon = thermal_hwmon_lookup_by_type(tz);
-	if (unlikely(!hwmon)) {
-		/* Should never happen... */
-		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
-		return;
-	}
-
-	temp = thermal_hwmon_lookup_temp(hwmon, tz);
-	if (unlikely(!temp)) {
-		/* Should never happen... */
-		dev_dbg(&tz->device, "temperature input lookup failed!\n");
-		return;
-	}
-
-	device_remove_file(hwmon->device, &temp->temp_input.attr);
-	if (tz->ops->get_crit_temp)
-		device_remove_file(hwmon->device, &temp->temp_crit.attr);
-
-	mutex_lock(&thermal_list_lock);
-	list_del(&temp->hwmon_node);
-	kfree(temp);
-	if (!list_empty(&hwmon->tz_list)) {
-		mutex_unlock(&thermal_list_lock);
-		return;
-	}
-	list_del(&hwmon->node);
-	mutex_unlock(&thermal_list_lock);
-
-	device_remove_file(hwmon->device, &dev_attr_name);
-	hwmon_device_unregister(hwmon->device);
-	kfree(hwmon);
-}
-#else
-static int
-thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
-{
-	return 0;
-}
-
-static void
-thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
-{
-}
-#endif
-
-/**
- * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
- * @tz:		thermal zone device
- * @trip:	indicates which trip point the cooling devices is
- *		associated with in this thermal zone.
- * @cdev:	thermal cooling device
- *
- * This function is usually called in the thermal zone device .bind callback.
- */
-int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
-				     int trip,
-				     struct thermal_cooling_device *cdev,
-				     unsigned long upper, unsigned long lower)
-{
-	struct thermal_instance *dev;
-	struct thermal_instance *pos;
-	struct thermal_zone_device *pos1;
-	struct thermal_cooling_device *pos2;
-	unsigned long max_state;
-	int result;
-
-	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
-		return -EINVAL;
-
-	list_for_each_entry(pos1, &thermal_tz_list, node) {
-		if (pos1 == tz)
-			break;
-	}
-	list_for_each_entry(pos2, &thermal_cdev_list, node) {
-		if (pos2 == cdev)
-			break;
-	}
-
-	if (tz != pos1 || cdev != pos2)
-		return -EINVAL;
-
-	cdev->ops->get_max_state(cdev, &max_state);
-
-	/* lower default 0, upper default max_state */
-	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
-	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
-
-	if (lower > upper || upper > max_state)
-		return -EINVAL;
-
-	dev =
-	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
-	if (!dev)
-		return -ENOMEM;
-	dev->tz = tz;
-	dev->cdev = cdev;
-	dev->trip = trip;
-	dev->upper = upper;
-	dev->lower = lower;
-	dev->target = THERMAL_NO_TARGET;
-
-	result = get_idr(&tz->idr, &tz->lock, &dev->id);
-	if (result)
-		goto free_mem;
-
-	sprintf(dev->name, "cdev%d", dev->id);
-	result =
-	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
-	if (result)
-		goto release_idr;
-
-	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
-	sysfs_attr_init(&dev->attr.attr);
-	dev->attr.attr.name = dev->attr_name;
-	dev->attr.attr.mode = 0444;
-	dev->attr.show = thermal_cooling_device_trip_point_show;
-	result = device_create_file(&tz->device, &dev->attr);
-	if (result)
-		goto remove_symbol_link;
-
-	mutex_lock(&tz->lock);
-	mutex_lock(&cdev->lock);
-	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
-	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
-		result = -EEXIST;
-		break;
-	}
-	if (!result) {
-		list_add_tail(&dev->tz_node, &tz->thermal_instances);
-		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
-	}
-	mutex_unlock(&cdev->lock);
-	mutex_unlock(&tz->lock);
-
-	if (!result)
-		return 0;
-
-	device_remove_file(&tz->device, &dev->attr);
-remove_symbol_link:
-	sysfs_remove_link(&tz->device.kobj, dev->name);
-release_idr:
-	release_idr(&tz->idr, &tz->lock, dev->id);
-free_mem:
-	kfree(dev);
-	return result;
-}
-EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
-
-/**
- * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
- * @tz:		thermal zone device
- * @trip:	indicates which trip point the cooling devices is
- *		associated with in this thermal zone.
- * @cdev:	thermal cooling device
- *
- * This function is usually called in the thermal zone device .unbind callback.
- */
-int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
-				       int trip,
-				       struct thermal_cooling_device *cdev)
-{
-	struct thermal_instance *pos, *next;
-
-	mutex_lock(&tz->lock);
-	mutex_lock(&cdev->lock);
-	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
-		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
-			list_del(&pos->tz_node);
-			list_del(&pos->cdev_node);
-			mutex_unlock(&cdev->lock);
-			mutex_unlock(&tz->lock);
-			goto unbind;
-		}
-	}
-	mutex_unlock(&cdev->lock);
-	mutex_unlock(&tz->lock);
-
-	return -ENODEV;
-
-unbind:
-	device_remove_file(&tz->device, &pos->attr);
-	sysfs_remove_link(&tz->device.kobj, pos->name);
-	release_idr(&tz->idr, &tz->lock, pos->id);
-	kfree(pos);
-	return 0;
-}
-EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
-
-static void thermal_release(struct device *dev)
-{
-	struct thermal_zone_device *tz;
-	struct thermal_cooling_device *cdev;
-
-	if (!strncmp(dev_name(dev), "thermal_zone",
-		     sizeof("thermal_zone") - 1)) {
-		tz = to_thermal_zone(dev);
-		kfree(tz);
-	} else {
-		cdev = to_cooling_device(dev);
-		kfree(cdev);
-	}
-}
-
-static struct class thermal_class = {
-	.name = "thermal",
-	.dev_release = thermal_release,
-};
-
-/**
- * thermal_cooling_device_register - register a new thermal cooling device
- * @type:	the thermal cooling device type.
- * @devdata:	device private data.
- * @ops:		standard thermal cooling devices callbacks.
- */
-struct thermal_cooling_device *
-thermal_cooling_device_register(char *type, void *devdata,
-				const struct thermal_cooling_device_ops *ops)
-{
-	struct thermal_cooling_device *cdev;
-	int result;
-
-	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
-		return ERR_PTR(-EINVAL);
-
-	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
-	    !ops->set_cur_state)
-		return ERR_PTR(-EINVAL);
-
-	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
-	if (!cdev)
-		return ERR_PTR(-ENOMEM);
-
-	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
-	if (result) {
-		kfree(cdev);
-		return ERR_PTR(result);
-	}
-
-	strcpy(cdev->type, type ? : "");
-	mutex_init(&cdev->lock);
-	INIT_LIST_HEAD(&cdev->thermal_instances);
-	cdev->ops = ops;
-	cdev->updated = true;
-	cdev->device.class = &thermal_class;
-	cdev->devdata = devdata;
-	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
-	result = device_register(&cdev->device);
-	if (result) {
-		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
-		kfree(cdev);
-		return ERR_PTR(result);
-	}
-
-	/* sys I/F */
-	if (type) {
-		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
-		if (result)
-			goto unregister;
-	}
-
-	result = device_create_file(&cdev->device, &dev_attr_max_state);
-	if (result)
-		goto unregister;
-
-	result = device_create_file(&cdev->device, &dev_attr_cur_state);
-	if (result)
-		goto unregister;
-
-	/* Add 'this' new cdev to the global cdev list */
-	mutex_lock(&thermal_list_lock);
-	list_add(&cdev->node, &thermal_cdev_list);
-	mutex_unlock(&thermal_list_lock);
-
-	/* Update binding information for 'this' new cdev */
-	bind_cdev(cdev);
-
-	return cdev;
-
-unregister:
-	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
-	device_unregister(&cdev->device);
-	return ERR_PTR(result);
-}
-EXPORT_SYMBOL(thermal_cooling_device_register);
-
-/**
- * thermal_cooling_device_unregister - removes the registered thermal cooling device
- * @cdev:	the thermal cooling device to remove.
- *
- * thermal_cooling_device_unregister() must be called when the device is no
- * longer needed.
- */
-void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
-{
-	int i;
-	const struct thermal_zone_params *tzp;
-	struct thermal_zone_device *tz;
-	struct thermal_cooling_device *pos = NULL;
-
-	if (!cdev)
-		return;
-
-	mutex_lock(&thermal_list_lock);
-	list_for_each_entry(pos, &thermal_cdev_list, node)
-	    if (pos == cdev)
-		break;
-	if (pos != cdev) {
-		/* thermal cooling device not found */
-		mutex_unlock(&thermal_list_lock);
-		return;
-	}
-	list_del(&cdev->node);
-
-	/* Unbind all thermal zones associated with 'this' cdev */
-	list_for_each_entry(tz, &thermal_tz_list, node) {
-		if (tz->ops->unbind) {
-			tz->ops->unbind(tz, cdev);
-			continue;
-		}
-
-		if (!tz->tzp || !tz->tzp->tbp)
-			continue;
-
-		tzp = tz->tzp;
-		for (i = 0; i < tzp->num_tbps; i++) {
-			if (tzp->tbp[i].cdev == cdev) {
-				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
-				tzp->tbp[i].cdev = NULL;
-			}
-		}
-	}
-
-	mutex_unlock(&thermal_list_lock);
-
-	if (cdev->type[0])
-		device_remove_file(&cdev->device, &dev_attr_cdev_type);
-	device_remove_file(&cdev->device, &dev_attr_max_state);
-	device_remove_file(&cdev->device, &dev_attr_cur_state);
-
-	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
-	device_unregister(&cdev->device);
-	return;
-}
-EXPORT_SYMBOL(thermal_cooling_device_unregister);
-
-void thermal_cdev_update(struct thermal_cooling_device *cdev)
-{
-	struct thermal_instance *instance;
-	unsigned long target = 0;
-
-	/* cooling device is updated*/
-	if (cdev->updated)
-		return;
-
-	mutex_lock(&cdev->lock);
-	/* Make sure cdev enters the deepest cooling state */
-	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
-		if (instance->target == THERMAL_NO_TARGET)
-			continue;
-		if (instance->target > target)
-			target = instance->target;
-	}
-	mutex_unlock(&cdev->lock);
-	cdev->ops->set_cur_state(cdev, target);
-	cdev->updated = true;
-}
-EXPORT_SYMBOL(thermal_cdev_update);
-
-/**
- * notify_thermal_framework - Sensor drivers use this API to notify framework
- * @tz:		thermal zone device
- * @trip:	indicates which trip point has been crossed
- *
- * This function handles the trip events from sensor drivers. It starts
- * throttling the cooling devices according to the policy configured.
- * For CRITICAL and HOT trip points, this notifies the respective drivers,
- * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
- * The throttling policy is based on the configured platform data; if no
- * platform data is provided, this uses the step_wise throttling policy.
- */
-void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
-{
-	handle_thermal_trip(tz, trip);
-}
-EXPORT_SYMBOL(notify_thermal_framework);
-
-/**
- * create_trip_attrs - create attributes for trip points
- * @tz:		the thermal zone device
- * @mask:	Writeable trip point bitmap.
- */
-static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
-{
-	int indx;
-	int size = sizeof(struct thermal_attr) * tz->trips;
-
-	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
-	if (!tz->trip_type_attrs)
-		return -ENOMEM;
-
-	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
-	if (!tz->trip_temp_attrs) {
-		kfree(tz->trip_type_attrs);
-		return -ENOMEM;
-	}
-
-	if (tz->ops->get_trip_hyst) {
-		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
-		if (!tz->trip_hyst_attrs) {
-			kfree(tz->trip_type_attrs);
-			kfree(tz->trip_temp_attrs);
-			return -ENOMEM;
-		}
-	}
-
-
-	for (indx = 0; indx < tz->trips; indx++) {
-		/* create trip type attribute */
-		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
-			 "trip_point_%d_type", indx);
-
-		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
-		tz->trip_type_attrs[indx].attr.attr.name =
-						tz->trip_type_attrs[indx].name;
-		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
-		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
-
-		device_create_file(&tz->device,
-				   &tz->trip_type_attrs[indx].attr);
-
-		/* create trip temp attribute */
-		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
-			 "trip_point_%d_temp", indx);
-
-		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
-		tz->trip_temp_attrs[indx].attr.attr.name =
-						tz->trip_temp_attrs[indx].name;
-		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
-		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
-		if (mask & (1 << indx)) {
-			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
-			tz->trip_temp_attrs[indx].attr.store =
-							trip_point_temp_store;
-		}
-
-		device_create_file(&tz->device,
-				   &tz->trip_temp_attrs[indx].attr);
-
-		/* create Optional trip hyst attribute */
-		if (!tz->ops->get_trip_hyst)
-			continue;
-		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
-			 "trip_point_%d_hyst", indx);
-
-		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
-		tz->trip_hyst_attrs[indx].attr.attr.name =
-					tz->trip_hyst_attrs[indx].name;
-		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
-		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
-		if (tz->ops->set_trip_hyst) {
-			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
-			tz->trip_hyst_attrs[indx].attr.store =
-					trip_point_hyst_store;
-		}
-
-		device_create_file(&tz->device,
-				   &tz->trip_hyst_attrs[indx].attr);
-	}
-	return 0;
-}
-
-static void remove_trip_attrs(struct thermal_zone_device *tz)
-{
-	int indx;
-
-	for (indx = 0; indx < tz->trips; indx++) {
-		device_remove_file(&tz->device,
-				   &tz->trip_type_attrs[indx].attr);
-		device_remove_file(&tz->device,
-				   &tz->trip_temp_attrs[indx].attr);
-		if (tz->ops->get_trip_hyst)
-			device_remove_file(&tz->device,
-				  &tz->trip_hyst_attrs[indx].attr);
-	}
-	kfree(tz->trip_type_attrs);
-	kfree(tz->trip_temp_attrs);
-	kfree(tz->trip_hyst_attrs);
-}
-
-/**
- * thermal_zone_device_register - register a new thermal zone device
- * @type:	the thermal zone device type
- * @trips:	the number of trip points the thermal zone support
- * @mask:	a bit string indicating the writeablility of trip points
- * @devdata:	private device data
- * @ops:	standard thermal zone device callbacks
- * @tzp:	thermal zone platform parameters
- * @passive_delay: number of milliseconds to wait between polls when
- *		   performing passive cooling
- * @polling_delay: number of milliseconds to wait between polls when checking
- *		   whether trip points have been crossed (0 for interrupt
- *		   driven systems)
- *
- * thermal_zone_device_unregister() must be called when the device is no
- * longer needed. The passive cooling depends on the .get_trend() return value.
- */
-struct thermal_zone_device *thermal_zone_device_register(const char *type,
-	int trips, int mask, void *devdata,
-	const struct thermal_zone_device_ops *ops,
-	const struct thermal_zone_params *tzp,
-	int passive_delay, int polling_delay)
-{
-	struct thermal_zone_device *tz;
-	enum thermal_trip_type trip_type;
-	int result;
-	int count;
-	int passive = 0;
-
-	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
-		return ERR_PTR(-EINVAL);
-
-	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
-		return ERR_PTR(-EINVAL);
-
-	if (!ops || !ops->get_temp)
-		return ERR_PTR(-EINVAL);
-
-	if (trips > 0 && !ops->get_trip_type)
-		return ERR_PTR(-EINVAL);
-
-	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
-	if (!tz)
-		return ERR_PTR(-ENOMEM);
-
-	INIT_LIST_HEAD(&tz->thermal_instances);
-	idr_init(&tz->idr);
-	mutex_init(&tz->lock);
-	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
-	if (result) {
-		kfree(tz);
-		return ERR_PTR(result);
-	}
-
-	strcpy(tz->type, type ? : "");
-	tz->ops = ops;
-	tz->tzp = tzp;
-	tz->device.class = &thermal_class;
-	tz->devdata = devdata;
-	tz->trips = trips;
-	tz->passive_delay = passive_delay;
-	tz->polling_delay = polling_delay;
-
-	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
-	result = device_register(&tz->device);
-	if (result) {
-		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
-		kfree(tz);
-		return ERR_PTR(result);
-	}
-
-	/* sys I/F */
-	if (type) {
-		result = device_create_file(&tz->device, &dev_attr_type);
-		if (result)
-			goto unregister;
-	}
-
-	result = device_create_file(&tz->device, &dev_attr_temp);
-	if (result)
-		goto unregister;
-
-	if (ops->get_mode) {
-		result = device_create_file(&tz->device, &dev_attr_mode);
-		if (result)
-			goto unregister;
-	}
-
-	result = create_trip_attrs(tz, mask);
-	if (result)
-		goto unregister;
-
-	for (count = 0; count < trips; count++) {
-		tz->ops->get_trip_type(tz, count, &trip_type);
-		if (trip_type == THERMAL_TRIP_PASSIVE)
-			passive = 1;
-	}
-
-	if (!passive) {
-		result = device_create_file(&tz->device, &dev_attr_passive);
-		if (result)
-			goto unregister;
-	}
-
-#ifdef CONFIG_THERMAL_EMULATION
-	result = device_create_file(&tz->device, &dev_attr_emul_temp);
-	if (result)
-		goto unregister;
-#endif
-	/* Create policy attribute */
-	result = device_create_file(&tz->device, &dev_attr_policy);
-	if (result)
-		goto unregister;
-
-	/* Update 'this' zone's governor information */
-	mutex_lock(&thermal_governor_lock);
-
-	if (tz->tzp)
-		tz->governor = __find_governor(tz->tzp->governor_name);
-	else
-		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
-
-	mutex_unlock(&thermal_governor_lock);
-
-	result = thermal_add_hwmon_sysfs(tz);
-	if (result)
-		goto unregister;
-
-	mutex_lock(&thermal_list_lock);
-	list_add_tail(&tz->node, &thermal_tz_list);
-	mutex_unlock(&thermal_list_lock);
-
-	/* Bind cooling devices for this zone */
-	bind_tz(tz);
-
-	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
-
-	thermal_zone_device_update(tz);
-
-	if (!result)
-		return tz;
-
-unregister:
-	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
-	device_unregister(&tz->device);
-	return ERR_PTR(result);
-}
-EXPORT_SYMBOL(thermal_zone_device_register);
-
-/**
- * thermal_device_unregister - removes the registered thermal zone device
- * @tz: the thermal zone device to remove
- */
-void thermal_zone_device_unregister(struct thermal_zone_device *tz)
-{
-	int i;
-	const struct thermal_zone_params *tzp;
-	struct thermal_cooling_device *cdev;
-	struct thermal_zone_device *pos = NULL;
-
-	if (!tz)
-		return;
-
-	tzp = tz->tzp;
-
-	mutex_lock(&thermal_list_lock);
-	list_for_each_entry(pos, &thermal_tz_list, node)
-	    if (pos == tz)
-		break;
-	if (pos != tz) {
-		/* thermal zone device not found */
-		mutex_unlock(&thermal_list_lock);
-		return;
-	}
-	list_del(&tz->node);
-
-	/* Unbind all cdevs associated with 'this' thermal zone */
-	list_for_each_entry(cdev, &thermal_cdev_list, node) {
-		if (tz->ops->unbind) {
-			tz->ops->unbind(tz, cdev);
-			continue;
-		}
-
-		if (!tzp || !tzp->tbp)
-			break;
-
-		for (i = 0; i < tzp->num_tbps; i++) {
-			if (tzp->tbp[i].cdev == cdev) {
-				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
-				tzp->tbp[i].cdev = NULL;
-			}
-		}
-	}
-
-	mutex_unlock(&thermal_list_lock);
-
-	thermal_zone_device_set_polling(tz, 0);
-
-	if (tz->type[0])
-		device_remove_file(&tz->device, &dev_attr_type);
-	device_remove_file(&tz->device, &dev_attr_temp);
-	if (tz->ops->get_mode)
-		device_remove_file(&tz->device, &dev_attr_mode);
-	device_remove_file(&tz->device, &dev_attr_policy);
-	remove_trip_attrs(tz);
-	tz->governor = NULL;
-
-	thermal_remove_hwmon_sysfs(tz);
-	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
-	idr_destroy(&tz->idr);
-	mutex_destroy(&tz->lock);
-	device_unregister(&tz->device);
-	return;
-}
-EXPORT_SYMBOL(thermal_zone_device_unregister);
-
-#ifdef CONFIG_NET
-static struct genl_family thermal_event_genl_family = {
-	.id = GENL_ID_GENERATE,
-	.name = THERMAL_GENL_FAMILY_NAME,
-	.version = THERMAL_GENL_VERSION,
-	.maxattr = THERMAL_GENL_ATTR_MAX,
-};
-
-static struct genl_multicast_group thermal_event_mcgrp = {
-	.name = THERMAL_GENL_MCAST_GROUP_NAME,
-};
-
-int thermal_generate_netlink_event(struct thermal_zone_device *tz,
-					enum events event)
-{
-	struct sk_buff *skb;
-	struct nlattr *attr;
-	struct thermal_genl_event *thermal_event;
-	void *msg_header;
-	int size;
-	int result;
-	static unsigned int thermal_event_seqnum;
-
-	if (!tz)
-		return -EINVAL;
-
-	/* allocate memory */
-	size = nla_total_size(sizeof(struct thermal_genl_event)) +
-	       nla_total_size(0);
-
-	skb = genlmsg_new(size, GFP_ATOMIC);
-	if (!skb)
-		return -ENOMEM;
-
-	/* add the genetlink message header */
-	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
-				 &thermal_event_genl_family, 0,
-				 THERMAL_GENL_CMD_EVENT);
-	if (!msg_header) {
-		nlmsg_free(skb);
-		return -ENOMEM;
-	}
-
-	/* fill the data */
-	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
-			   sizeof(struct thermal_genl_event));
-
-	if (!attr) {
-		nlmsg_free(skb);
-		return -EINVAL;
-	}
-
-	thermal_event = nla_data(attr);
-	if (!thermal_event) {
-		nlmsg_free(skb);
-		return -EINVAL;
-	}
-
-	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
-
-	thermal_event->orig = tz->id;
-	thermal_event->event = event;
-
-	/* send multicast genetlink message */
-	result = genlmsg_end(skb, msg_header);
-	if (result < 0) {
-		nlmsg_free(skb);
-		return result;
-	}
-
-	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
-	if (result)
-		dev_err(&tz->device, "Failed to send netlink event:%d", result);
-
-	return result;
-}
-EXPORT_SYMBOL(thermal_generate_netlink_event);
-
-static int genetlink_init(void)
-{
-	int result;
-
-	result = genl_register_family(&thermal_event_genl_family);
-	if (result)
-		return result;
-
-	result = genl_register_mc_group(&thermal_event_genl_family,
-					&thermal_event_mcgrp);
-	if (result)
-		genl_unregister_family(&thermal_event_genl_family);
-	return result;
-}
-
-static void genetlink_exit(void)
-{
-	genl_unregister_family(&thermal_event_genl_family);
-}
-#else /* !CONFIG_NET */
-static inline int genetlink_init(void) { return 0; }
-static inline void genetlink_exit(void) {}
-#endif /* !CONFIG_NET */
-
-static int __init thermal_init(void)
-{
-	int result = 0;
-
-	result = class_register(&thermal_class);
-	if (result) {
-		idr_destroy(&thermal_tz_idr);
-		idr_destroy(&thermal_cdev_idr);
-		mutex_destroy(&thermal_idr_lock);
-		mutex_destroy(&thermal_list_lock);
-		return result;
-	}
-	result = genetlink_init();
-	return result;
-}
-
-static void __exit thermal_exit(void)
-{
-	class_unregister(&thermal_class);
-	idr_destroy(&thermal_tz_idr);
-	idr_destroy(&thermal_cdev_idr);
-	mutex_destroy(&thermal_idr_lock);
-	mutex_destroy(&thermal_list_lock);
-	genetlink_exit();
-}
-
-fs_initcall(thermal_init);
-module_exit(thermal_exit);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH 2/5] Thermal: thermal framework registration failure case cleanup
  2013-03-26 16:26 [RFC PATCH 0/5] Thermal: build all thermal framework code into thermal_sys module Zhang Rui
  2013-03-26 16:26 ` [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c Zhang Rui
@ 2013-03-26 16:26 ` Zhang Rui
  2013-03-26 22:22     ` Eduardo Valentin
  2013-03-26 16:26 ` [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys module Zhang Rui
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 23+ messages in thread
From: Zhang Rui @ 2013-03-26 16:26 UTC (permalink / raw)
  To: linux-pm, linux-kernel; +Cc: amit.daniel, durgadoss.r, andi, Zhang Rui

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_core.c |   12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 5b7863a..845ed6e 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1863,13 +1863,9 @@ static int __init thermal_init(void)
 	int result = 0;
 
 	result = class_register(&thermal_class);
-	if (result) {
-		idr_destroy(&thermal_tz_idr);
-		idr_destroy(&thermal_cdev_idr);
-		mutex_destroy(&thermal_idr_lock);
-		mutex_destroy(&thermal_list_lock);
+	if (result)
 		return result;
-	}
+
 	result = genetlink_init();
 	return result;
 }
@@ -1877,10 +1873,6 @@ static int __init thermal_init(void)
 static void __exit thermal_exit(void)
 {
 	class_unregister(&thermal_class);
-	idr_destroy(&thermal_tz_idr);
-	idr_destroy(&thermal_cdev_idr);
-	mutex_destroy(&thermal_idr_lock);
-	mutex_destroy(&thermal_list_lock);
 	genetlink_exit();
 }
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys module
  2013-03-26 16:26 [RFC PATCH 0/5] Thermal: build all thermal framework code into thermal_sys module Zhang Rui
  2013-03-26 16:26 ` [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c Zhang Rui
  2013-03-26 16:26 ` [RFC PATCH 2/5] Thermal: thermal framework registration failure case cleanup Zhang Rui
@ 2013-03-26 16:26 ` Zhang Rui
  2013-03-26 16:53   ` R, Durgadoss
  2013-03-26 22:31     ` Eduardo Valentin
  2013-03-26 16:26 ` [RFC PATCH 4/5] Thermal: governor API cleanup Zhang Rui
  2013-03-26 16:26 ` [RFC PATCH 5/5] Thermal: build cpu_cooling code into thermal_sys module Zhang Rui
  4 siblings, 2 replies; 23+ messages in thread
From: Zhang Rui @ 2013-03-26 16:26 UTC (permalink / raw)
  To: linux-pm, linux-kernel; +Cc: amit.daniel, durgadoss.r, andi, Zhang Rui

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/Makefile       |    6 +++---
 drivers/thermal/fair_share.c   |   15 ++-------------
 drivers/thermal/step_wise.c    |   16 ++--------------
 drivers/thermal/thermal_core.c |   36 ++++++++++++++++++++++++++++++++++--
 drivers/thermal/thermal_core.h |   25 +++++++++++++++++++++++++
 drivers/thermal/user_space.c   |   15 ++-------------
 include/linux/thermal.h        |    1 -
 7 files changed, 68 insertions(+), 46 deletions(-)

diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index b2009bd..b7fffc7 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -6,9 +6,9 @@ obj-$(CONFIG_THERMAL)		+= thermal_sys.o
 thermal_sys-y			+= thermal_core.o
 
 # governors
-obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
-obj-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
-obj-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
+thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
+thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
+thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
 
 # cpufreq cooling
 obj-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
index 792479f..944ba2f 100644
--- a/drivers/thermal/fair_share.c
+++ b/drivers/thermal/fair_share.c
@@ -22,9 +22,6 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
 #include <linux/thermal.h>
 
 #include "thermal_core.h"
@@ -111,23 +108,15 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
 static struct thermal_governor thermal_gov_fair_share = {
 	.name		= "fair_share",
 	.throttle	= fair_share_throttle,
-	.owner		= THIS_MODULE,
 };
 
-static int __init thermal_gov_fair_share_init(void)
+int thermal_gov_fair_share_register(void)
 {
 	return thermal_register_governor(&thermal_gov_fair_share);
 }
 
-static void __exit thermal_gov_fair_share_exit(void)
+void thermal_gov_fair_share_unregister(void)
 {
 	thermal_unregister_governor(&thermal_gov_fair_share);
 }
 
-/* This should load after thermal framework */
-fs_initcall(thermal_gov_fair_share_init);
-module_exit(thermal_gov_fair_share_exit);
-
-MODULE_AUTHOR("Durgadoss R");
-MODULE_DESCRIPTION("A simple weight based thermal throttling governor");
-MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index 407cde3..a6c9666 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -22,9 +22,6 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
 #include <linux/thermal.h>
 
 #include "thermal_core.h"
@@ -180,23 +177,14 @@ static int step_wise_throttle(struct thermal_zone_device *tz, int trip)
 static struct thermal_governor thermal_gov_step_wise = {
 	.name		= "step_wise",
 	.throttle	= step_wise_throttle,
-	.owner		= THIS_MODULE,
 };
 
-static int __init thermal_gov_step_wise_init(void)
+int thermal_gov_step_wise_register(void)
 {
 	return thermal_register_governor(&thermal_gov_step_wise);
 }
 
-static void __exit thermal_gov_step_wise_exit(void)
+void thermal_gov_step_wise_unregister(void)
 {
 	thermal_unregister_governor(&thermal_gov_step_wise);
 }
-
-/* This should load after thermal framework */
-fs_initcall(thermal_gov_step_wise_init);
-module_exit(thermal_gov_step_wise_exit);
-
-MODULE_AUTHOR("Durgadoss R");
-MODULE_DESCRIPTION("A step-by-step thermal throttling governor");
-MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 845ed6e..eac9745 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1858,22 +1858,54 @@ static inline int genetlink_init(void) { return 0; }
 static inline void genetlink_exit(void) {}
 #endif /* !CONFIG_NET */
 
+static int __init thermal_register_governors(void)
+{
+	int result;
+
+	result = thermal_gov_step_wise_register();
+	if (result)
+		return result;
+
+	result = thermal_gov_fair_share_register();
+	if (result)
+		return result;
+
+	result = thermal_gov_user_space_register();
+
+	return result;
+}
+
+static void __exit thermal_unregister_governors(void)
+{
+	thermal_gov_step_wise_unregister();
+	thermal_gov_fair_share_unregister();
+	thermal_gov_user_space_unregister();
+}
+
 static int __init thermal_init(void)
 {
-	int result = 0;
+	int result;
+
+	result = thermal_register_governors();
+	if (result)
+		return result;
 
 	result = class_register(&thermal_class);
 	if (result)
 		return result;
 
 	result = genetlink_init();
+	if (result)
+		class_unregister(&thermal_class);
+
 	return result;
 }
 
 static void __exit thermal_exit(void)
 {
-	class_unregister(&thermal_class);
 	genetlink_exit();
+	class_unregister(&thermal_class);
+	thermal_unregister_governors();
 }
 
 fs_initcall(thermal_init);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 0d3205a..f84ea0f 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -50,4 +50,29 @@ struct thermal_instance {
 	struct list_head cdev_node; /* node in cdev->thermal_instances */
 };
 
+
+#ifdef CONFIG_THERMAL_GOV_STEP_WISE
+extern int thermal_gov_step_wise_register(void);
+extern void thermal_gov_step_wise_unregister(void);
+#else
+static inline int thermal_gov_step_wise_register(void) { return 0; }
+static inline void thermal_gov_step_wise_unregister(void) {}
+#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
+
+#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE
+extern int thermal_gov_fair_share_register(void);
+extern void thermal_gov_fair_share_unregister(void);
+#else
+static inline int thermal_gov_fair_share_register(void) { return 0; }
+static inline void thermal_gov_fair_share_unregister(void) {}
+#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
+
+#ifdef CONFIG_THERMAL_GOV_USER_SPACE
+extern int thermal_gov_user_space_register(void);
+extern void thermal_gov_user_space_unregister(void);
+#else
+static inline int thermal_gov_user_space_register(void) { return 0; }
+static inline void thermal_gov_user_space_unregister(void) {}
+#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
+
 #endif /* __THERMAL_CORE_H__ */
diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
index 6bbb380..10adcdd 100644
--- a/drivers/thermal/user_space.c
+++ b/drivers/thermal/user_space.c
@@ -22,9 +22,6 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
 #include <linux/thermal.h>
 
 #include "thermal_core.h"
@@ -46,23 +43,15 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip)
 static struct thermal_governor thermal_gov_user_space = {
 	.name		= "user_space",
 	.throttle	= notify_user_space,
-	.owner		= THIS_MODULE,
 };
 
-static int __init thermal_gov_user_space_init(void)
+int thermal_gov_user_space_register(void)
 {
 	return thermal_register_governor(&thermal_gov_user_space);
 }
 
-static void __exit thermal_gov_user_space_exit(void)
+void thermal_gov_user_space_unregister(void)
 {
 	thermal_unregister_governor(&thermal_gov_user_space);
 }
 
-/* This should load after thermal framework */
-fs_initcall(thermal_gov_user_space_init);
-module_exit(thermal_gov_user_space_exit);
-
-MODULE_AUTHOR("Durgadoss R");
-MODULE_DESCRIPTION("A user space Thermal notifier");
-MODULE_LICENSE("GPL");
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f0bd7f9..2eeec01 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -184,7 +184,6 @@ struct thermal_governor {
 	char name[THERMAL_NAME_LENGTH];
 	int (*throttle)(struct thermal_zone_device *tz, int trip);
 	struct list_head	governor_list;
-	struct module		*owner;
 };
 
 /* Structure that holds binding parameters for a zone */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH 4/5] Thermal: governor API cleanup
  2013-03-26 16:26 [RFC PATCH 0/5] Thermal: build all thermal framework code into thermal_sys module Zhang Rui
                   ` (2 preceding siblings ...)
  2013-03-26 16:26 ` [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys module Zhang Rui
@ 2013-03-26 16:26 ` Zhang Rui
  2013-03-26 22:35     ` Eduardo Valentin
  2013-03-26 16:26 ` [RFC PATCH 5/5] Thermal: build cpu_cooling code into thermal_sys module Zhang Rui
  4 siblings, 1 reply; 23+ messages in thread
From: Zhang Rui @ 2013-03-26 16:26 UTC (permalink / raw)
  To: linux-pm, linux-kernel; +Cc: amit.daniel, durgadoss.r, andi, Zhang Rui

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/thermal_core.c |    2 --
 drivers/thermal/thermal_core.h |    2 ++
 include/linux/thermal.h        |    3 ---
 3 files changed, 2 insertions(+), 5 deletions(-)

diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index eac9745..f645757 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -99,7 +99,6 @@ int thermal_register_governor(struct thermal_governor *governor)
 
 	return err;
 }
-EXPORT_SYMBOL_GPL(thermal_register_governor);
 
 void thermal_unregister_governor(struct thermal_governor *governor)
 {
@@ -127,7 +126,6 @@ void thermal_unregister_governor(struct thermal_governor *governor)
 	mutex_unlock(&thermal_governor_lock);
 	return;
 }
-EXPORT_SYMBOL_GPL(thermal_unregister_governor);
 
 static int get_idr(struct idr *idr, struct mutex *lock, int *id)
 {
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index f84ea0f..a1f8278 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -50,6 +50,8 @@ struct thermal_instance {
 	struct list_head cdev_node; /* node in cdev->thermal_instances */
 };
 
+extern int thermal_register_governor(struct thermal_governor *);
+extern void thermal_unregister_governor(struct thermal_governor *);
 
 #ifdef CONFIG_THERMAL_GOV_STEP_WISE
 extern int thermal_gov_step_wise_register(void);
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 2eeec01..af03ea6 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -243,9 +243,6 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
 void thermal_cdev_update(struct thermal_cooling_device *);
 void notify_thermal_framework(struct thermal_zone_device *, int);
 
-int thermal_register_governor(struct thermal_governor *);
-void thermal_unregister_governor(struct thermal_governor *);
-
 #ifdef CONFIG_NET
 extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
 						enum events event);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFC PATCH 5/5] Thermal: build cpu_cooling code into thermal_sys module
  2013-03-26 16:26 [RFC PATCH 0/5] Thermal: build all thermal framework code into thermal_sys module Zhang Rui
                   ` (3 preceding siblings ...)
  2013-03-26 16:26 ` [RFC PATCH 4/5] Thermal: governor API cleanup Zhang Rui
@ 2013-03-26 16:26 ` Zhang Rui
  4 siblings, 0 replies; 23+ messages in thread
From: Zhang Rui @ 2013-03-26 16:26 UTC (permalink / raw)
  To: linux-pm, linux-kernel; +Cc: amit.daniel, durgadoss.r, andi, Zhang Rui

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/Kconfig     |    2 +-
 drivers/thermal/Makefile    |    2 +-
 include/linux/cpu_cooling.h |    2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index a764f16..10014de 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -67,7 +67,7 @@ config THERMAL_GOV_USER_SPACE
 	  Enable this to let the user space manage the platform thermals.
 
 config CPU_THERMAL
-	tristate "generic cpu cooling support"
+	bool "generic cpu cooling support"
 	depends on CPU_FREQ
 	select CPU_FREQ_TABLE
 	help
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index b7fffc7..cae124f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -11,7 +11,7 @@ thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
 thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
 
 # cpufreq cooling
-obj-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
+thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
 
 # platform thermal drivers
 obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h
index 40b4ef5..b30cc79c 100644
--- a/include/linux/cpu_cooling.h
+++ b/include/linux/cpu_cooling.h
@@ -29,7 +29,7 @@
 #define CPUFREQ_COOLING_START		0
 #define CPUFREQ_COOLING_STOP		1
 
-#if defined(CONFIG_CPU_THERMAL) || defined(CONFIG_CPU_THERMAL_MODULE)
+#ifdef CONFIG_CPU_THERMAL
 /**
  * cpufreq_cooling_register - function to create cpufreq cooling device.
  * @clip_cpus: cpumask of cpus where the frequency constraints will happen
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* RE: [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys module
  2013-03-26 16:26 ` [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys module Zhang Rui
@ 2013-03-26 16:53   ` R, Durgadoss
  2013-03-26 17:12     ` Zhang Rui
  2013-03-26 22:31     ` Eduardo Valentin
  1 sibling, 1 reply; 23+ messages in thread
From: R, Durgadoss @ 2013-03-26 16:53 UTC (permalink / raw)
  To: Zhang, Rui, linux-pm, linux-kernel; +Cc: amit.daniel, andi

Hi Rui,

> -----Original Message-----
> From: Zhang, Rui
> Sent: Tuesday, March 26, 2013 9:56 PM
> To: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org
> Cc: amit.daniel@samsung.com; R, Durgadoss; andi@lisas.de; Zhang, Rui
> Subject: [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys
> module
> 
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> ---
>  drivers/thermal/Makefile       |    6 +++---
>  drivers/thermal/fair_share.c   |   15 ++-------------
>  drivers/thermal/step_wise.c    |   16 ++--------------
>  drivers/thermal/thermal_core.c |   36
> ++++++++++++++++++++++++++++++++++--
>  drivers/thermal/thermal_core.h |   25 +++++++++++++++++++++++++
>  drivers/thermal/user_space.c   |   15 ++-------------
>  include/linux/thermal.h        |    1 -
>  7 files changed, 68 insertions(+), 46 deletions(-)
> 
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index b2009bd..b7fffc7 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -6,9 +6,9 @@ obj-$(CONFIG_THERMAL)		+= thermal_sys.o
>  thermal_sys-y			+= thermal_core.o
> 
>  # governors
> -obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> -obj-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
> -obj-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
> +thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+=
> fair_share.o
> +thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
> +thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE)	+=
> user_space.o
> 
>  # cpufreq cooling
>  obj-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
> diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
> index 792479f..944ba2f 100644
> --- a/drivers/thermal/fair_share.c
> +++ b/drivers/thermal/fair_share.c
> @@ -22,9 +22,6 @@
>   *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
>   */
> 
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
>  #include <linux/thermal.h>
> 
>  #include "thermal_core.h"
> @@ -111,23 +108,15 @@ static int fair_share_throttle(struct
> thermal_zone_device *tz, int trip)
>  static struct thermal_governor thermal_gov_fair_share = {
>  	.name		= "fair_share",
>  	.throttle	= fair_share_throttle,
> -	.owner		= THIS_MODULE,
>  };
> 
> -static int __init thermal_gov_fair_share_init(void)
> +int thermal_gov_fair_share_register(void)
>  {
>  	return thermal_register_governor(&thermal_gov_fair_share);
>  }
> 
> -static void __exit thermal_gov_fair_share_exit(void)
> +void thermal_gov_fair_share_unregister(void)
>  {
>  	thermal_unregister_governor(&thermal_gov_fair_share);
>  }
> 
> -/* This should load after thermal framework */
> -fs_initcall(thermal_gov_fair_share_init);
> -module_exit(thermal_gov_fair_share_exit);
> -
> -MODULE_AUTHOR("Durgadoss R");
> -MODULE_DESCRIPTION("A simple weight based thermal throttling
> governor");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
> index 407cde3..a6c9666 100644
> --- a/drivers/thermal/step_wise.c
> +++ b/drivers/thermal/step_wise.c
> @@ -22,9 +22,6 @@
>   *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
>   */
> 
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
>  #include <linux/thermal.h>
> 
>  #include "thermal_core.h"
> @@ -180,23 +177,14 @@ static int step_wise_throttle(struct
> thermal_zone_device *tz, int trip)
>  static struct thermal_governor thermal_gov_step_wise = {
>  	.name		= "step_wise",
>  	.throttle	= step_wise_throttle,
> -	.owner		= THIS_MODULE,
>  };
> 
> -static int __init thermal_gov_step_wise_init(void)
> +int thermal_gov_step_wise_register(void)
>  {
>  	return thermal_register_governor(&thermal_gov_step_wise);
>  }
> 
> -static void __exit thermal_gov_step_wise_exit(void)
> +void thermal_gov_step_wise_unregister(void)
>  {
>  	thermal_unregister_governor(&thermal_gov_step_wise);
>  }
> -
> -/* This should load after thermal framework */
> -fs_initcall(thermal_gov_step_wise_init);
> -module_exit(thermal_gov_step_wise_exit);
> -
> -MODULE_AUTHOR("Durgadoss R");
> -MODULE_DESCRIPTION("A step-by-step thermal throttling governor");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/thermal/thermal_core.c
> b/drivers/thermal/thermal_core.c
> index 845ed6e..eac9745 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -1858,22 +1858,54 @@ static inline int genetlink_init(void) { return 0; }
>  static inline void genetlink_exit(void) {}
>  #endif /* !CONFIG_NET */
> 
> +static int __init thermal_register_governors(void)
> +{
> +	int result;
> +
> +	result = thermal_gov_step_wise_register();
> +	if (result)

[Patches 1,2 are fine with me].

A pr_err statement here, saying the registration failed,
would help us a lot.

> +		return result;
> +
> +	result = thermal_gov_fair_share_register();
> +	if (result)
> +		return result;
> +
> +	result = thermal_gov_user_space_register();

Same check + print statement for the other two as well.

> +
> +	return result;
> +}
> +
> +static void __exit thermal_unregister_governors(void)
> +{
> +	thermal_gov_step_wise_unregister();
> +	thermal_gov_fair_share_unregister();
> +	thermal_gov_user_space_unregister();
> +}
> +
>  static int __init thermal_init(void)
>  {
> -	int result = 0;
> +	int result;
> +
> +	result = thermal_register_governors();
> +	if (result)
> +		return result;
> 
>  	result = class_register(&thermal_class);
>  	if (result)

Shouldn't we do thermal_unregister_governors here ?

>  		return result;
> 
>  	result = genetlink_init();
> +	if (result)
> +		class_unregister(&thermal_class);

Shouldn't we do thermal_unregister_governors here ?
Probably a goto would make things simpler..

> +
>  	return result;
>  }
> 
>  static void __exit thermal_exit(void)
>  {
> -	class_unregister(&thermal_class);
>  	genetlink_exit();
> +	class_unregister(&thermal_class);
> +	thermal_unregister_governors();
>  }
> 
>  fs_initcall(thermal_init);
> diff --git a/drivers/thermal/thermal_core.h
> b/drivers/thermal/thermal_core.h
> index 0d3205a..f84ea0f 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -50,4 +50,29 @@ struct thermal_instance {
>  	struct list_head cdev_node; /* node in cdev->thermal_instances */
>  };
> 
> +
> +#ifdef CONFIG_THERMAL_GOV_STEP_WISE
> +extern int thermal_gov_step_wise_register(void);
> +extern void thermal_gov_step_wise_unregister(void);
> +#else
> +static inline int thermal_gov_step_wise_register(void) { return 0; }
> +static inline void thermal_gov_step_wise_unregister(void) {}
> +#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
> +
> +#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE
> +extern int thermal_gov_fair_share_register(void);
> +extern void thermal_gov_fair_share_unregister(void);
> +#else
> +static inline int thermal_gov_fair_share_register(void) { return 0; }
> +static inline void thermal_gov_fair_share_unregister(void) {}
> +#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
> +
> +#ifdef CONFIG_THERMAL_GOV_USER_SPACE
> +extern int thermal_gov_user_space_register(void);
> +extern void thermal_gov_user_space_unregister(void);
> +#else
> +static inline int thermal_gov_user_space_register(void) { return 0; }
> +static inline void thermal_gov_user_space_unregister(void) {}
> +#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
> +
>  #endif /* __THERMAL_CORE_H__ */
> diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
> index 6bbb380..10adcdd 100644
> --- a/drivers/thermal/user_space.c
> +++ b/drivers/thermal/user_space.c
> @@ -22,9 +22,6 @@
>   *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
>   */
> 
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
>  #include <linux/thermal.h>
> 
>  #include "thermal_core.h"
> @@ -46,23 +43,15 @@ static int notify_user_space(struct
> thermal_zone_device *tz, int trip)
>  static struct thermal_governor thermal_gov_user_space = {
>  	.name		= "user_space",
>  	.throttle	= notify_user_space,
> -	.owner		= THIS_MODULE,
>  };
> 
> -static int __init thermal_gov_user_space_init(void)
> +int thermal_gov_user_space_register(void)
>  {
>  	return thermal_register_governor(&thermal_gov_user_space);
>  }
> 
> -static void __exit thermal_gov_user_space_exit(void)
> +void thermal_gov_user_space_unregister(void)
>  {
>  	thermal_unregister_governor(&thermal_gov_user_space);
>  }
> 
> -/* This should load after thermal framework */
> -fs_initcall(thermal_gov_user_space_init);
> -module_exit(thermal_gov_user_space_exit);
> -
> -MODULE_AUTHOR("Durgadoss R");
> -MODULE_DESCRIPTION("A user space Thermal notifier");
> -MODULE_LICENSE("GPL");
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index f0bd7f9..2eeec01 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -184,7 +184,6 @@ struct thermal_governor {
>  	char name[THERMAL_NAME_LENGTH];
>  	int (*throttle)(struct thermal_zone_device *tz, int trip);
>  	struct list_head	governor_list;
> -	struct module		*owner;
>  };
> 
>  /* Structure that holds binding parameters for a zone */
> --
> 1.7.9.5


^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c
  2013-03-26 16:26 ` [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c Zhang Rui
@ 2013-03-26 16:56   ` R, Durgadoss
  2013-03-26 17:08     ` Zhang Rui
  2013-03-26 22:04     ` Eduardo Valentin
  1 sibling, 1 reply; 23+ messages in thread
From: R, Durgadoss @ 2013-03-26 16:56 UTC (permalink / raw)
  To: Zhang, Rui, linux-pm, linux-kernel; +Cc: amit.daniel, andi

> -----Original Message-----
> From: Zhang, Rui
> Sent: Tuesday, March 26, 2013 9:56 PM
> To: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org
> Cc: amit.daniel@samsung.com; R, Durgadoss; andi@lisas.de; Zhang, Rui
> Subject: [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c
> 
> No functional change in this patch.
> 
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> ---
>  drivers/thermal/Makefile       |    1 +
>  drivers/thermal/thermal_core.c | 1888
> ++++++++++++++++++++++++++++++++++++++++
>  drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------
>  3 files changed, 1889 insertions(+), 1888 deletions(-)
>  create mode 100644 drivers/thermal/thermal_core.c
>  delete mode 100644 drivers/thermal/thermal_sys.c
> 
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index d3a2b38..b2009bd 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -3,6 +3,7 @@
>  #
> 
>  obj-$(CONFIG_THERMAL)		+= thermal_sys.o

Should we keep the _sys suffix ?
Can we just rename it to thermal.o ?

> +thermal_sys-y			+= thermal_core.o
> 
>  # governors
>  obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> diff --git a/drivers/thermal/thermal_core.c
> b/drivers/thermal/thermal_core.c
> new file mode 100644
> index 0000000..5b7863a
> --- /dev/null
> +++ b/drivers/thermal/thermal_core.c
> @@ -0,0 +1,1888 @@
> +/*
> + *  thermal.c - Generic Thermal Management Sysfs support.
> + *
> + *  Copyright (C) 2008 Intel Corp
> + *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> + *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> + *
> + *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; version 2 of the License.
> + *
> + *  This program is distributed in the hope that it will be useful, but
> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU
> + *  General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License
> along
> + *  with this program; if not, write to the Free Software Foundation, Inc.,
> + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> + *
> + *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/kdev_t.h>
> +#include <linux/idr.h>
> +#include <linux/thermal.h>
> +#include <linux/reboot.h>
> +#include <net/netlink.h>
> +#include <net/genetlink.h>
> +
> +#include "thermal_core.h"
> +
> +MODULE_AUTHOR("Zhang Rui");
> +MODULE_DESCRIPTION("Generic thermal management sysfs support");
> +MODULE_LICENSE("GPL");
> +
> +static DEFINE_IDR(thermal_tz_idr);
> +static DEFINE_IDR(thermal_cdev_idr);
> +static DEFINE_MUTEX(thermal_idr_lock);
> +
> +static LIST_HEAD(thermal_tz_list);
> +static LIST_HEAD(thermal_cdev_list);
> +static LIST_HEAD(thermal_governor_list);
> +
> +static DEFINE_MUTEX(thermal_list_lock);
> +static DEFINE_MUTEX(thermal_governor_lock);
> +
> +static struct thermal_governor *__find_governor(const char *name)
> +{
> +	struct thermal_governor *pos;
> +
> +	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> +		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> +			return pos;
> +
> +	return NULL;
> +}
> +
> +int thermal_register_governor(struct thermal_governor *governor)
> +{
> +	int err;
> +	const char *name;
> +	struct thermal_zone_device *pos;
> +
> +	if (!governor)
> +		return -EINVAL;
> +
> +	mutex_lock(&thermal_governor_lock);
> +
> +	err = -EBUSY;
> +	if (__find_governor(governor->name) == NULL) {
> +		err = 0;
> +		list_add(&governor->governor_list,
> &thermal_governor_list);
> +	}
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> +		if (pos->governor)
> +			continue;
> +		if (pos->tzp)
> +			name = pos->tzp->governor_name;
> +		else
> +			name = DEFAULT_THERMAL_GOVERNOR;
> +		if (!strnicmp(name, governor->name,
> THERMAL_NAME_LENGTH))
> +			pos->governor = governor;
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +	mutex_unlock(&thermal_governor_lock);
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(thermal_register_governor);
> +
> +void thermal_unregister_governor(struct thermal_governor *governor)
> +{
> +	struct thermal_zone_device *pos;
> +
> +	if (!governor)
> +		return;
> +
> +	mutex_lock(&thermal_governor_lock);
> +
> +	if (__find_governor(governor->name) == NULL)
> +		goto exit;
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> +		if (!strnicmp(pos->governor->name, governor->name,
> +						THERMAL_NAME_LENGTH))
> +			pos->governor = NULL;
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +	list_del(&governor->governor_list);
> +exit:
> +	mutex_unlock(&thermal_governor_lock);
> +	return;
> +}
> +EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> +
> +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> +{
> +	int ret;
> +
> +	if (lock)
> +		mutex_lock(lock);
> +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> +	if (lock)
> +		mutex_unlock(lock);
> +	if (unlikely(ret < 0))
> +		return ret;
> +	*id = ret;
> +	return 0;
> +}
> +
> +static void release_idr(struct idr *idr, struct mutex *lock, int id)
> +{
> +	if (lock)
> +		mutex_lock(lock);
> +	idr_remove(idr, id);
> +	if (lock)
> +		mutex_unlock(lock);
> +}
> +
> +int get_tz_trend(struct thermal_zone_device *tz, int trip)
> +{
> +	enum thermal_trend trend;
> +
> +	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> +		if (tz->temperature > tz->last_temperature)
> +			trend = THERMAL_TREND_RAISING;
> +		else if (tz->temperature < tz->last_temperature)
> +			trend = THERMAL_TREND_DROPPING;
> +		else
> +			trend = THERMAL_TREND_STABLE;
> +	}
> +
> +	return trend;
> +}
> +EXPORT_SYMBOL(get_tz_trend);
> +
> +struct thermal_instance *get_thermal_instance(struct
> thermal_zone_device *tz,
> +			struct thermal_cooling_device *cdev, int trip)
> +{
> +	struct thermal_instance *pos = NULL;
> +	struct thermal_instance *target_instance = NULL;
> +
> +	mutex_lock(&tz->lock);
> +	mutex_lock(&cdev->lock);
> +
> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> +			target_instance = pos;
> +			break;
> +		}
> +	}
> +
> +	mutex_unlock(&cdev->lock);
> +	mutex_unlock(&tz->lock);
> +
> +	return target_instance;
> +}
> +EXPORT_SYMBOL(get_thermal_instance);
> +
> +static void print_bind_err_msg(struct thermal_zone_device *tz,
> +			struct thermal_cooling_device *cdev, int ret)
> +{
> +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> +				tz->type, cdev->type, ret);
> +}
> +
> +static void __bind(struct thermal_zone_device *tz, int mask,
> +			struct thermal_cooling_device *cdev)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < tz->trips; i++) {
> +		if (mask & (1 << i)) {
> +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> +					THERMAL_NO_LIMIT,
> THERMAL_NO_LIMIT);
> +			if (ret)
> +				print_bind_err_msg(tz, cdev, ret);
> +		}
> +	}
> +}
> +
> +static void __unbind(struct thermal_zone_device *tz, int mask,
> +			struct thermal_cooling_device *cdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < tz->trips; i++)
> +		if (mask & (1 << i))
> +			thermal_zone_unbind_cooling_device(tz, i, cdev);
> +}
> +
> +static void bind_cdev(struct thermal_cooling_device *cdev)
> +{
> +	int i, ret;
> +	const struct thermal_zone_params *tzp;
> +	struct thermal_zone_device *pos = NULL;
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> +		if (!pos->tzp && !pos->ops->bind)
> +			continue;
> +
> +		if (!pos->tzp && pos->ops->bind) {
> +			ret = pos->ops->bind(pos, cdev);
> +			if (ret)
> +				print_bind_err_msg(pos, cdev, ret);
> +		}
> +
> +		tzp = pos->tzp;
> +		if (!tzp || !tzp->tbp)
> +			continue;
> +
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> +				continue;
> +			if (tzp->tbp[i].match(pos, cdev))
> +				continue;
> +			tzp->tbp[i].cdev = cdev;
> +			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> +		}
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +}
> +
> +static void bind_tz(struct thermal_zone_device *tz)
> +{
> +	int i, ret;
> +	struct thermal_cooling_device *pos = NULL;
> +	const struct thermal_zone_params *tzp = tz->tzp;
> +
> +	if (!tzp && !tz->ops->bind)
> +		return;
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	/* If there is no platform data, try to use ops->bind */
> +	if (!tzp && tz->ops->bind) {
> +		list_for_each_entry(pos, &thermal_cdev_list, node) {
> +			ret = tz->ops->bind(tz, pos);
> +			if (ret)
> +				print_bind_err_msg(tz, pos, ret);
> +		}
> +		goto exit;
> +	}
> +
> +	if (!tzp || !tzp->tbp)
> +		goto exit;
> +
> +	list_for_each_entry(pos, &thermal_cdev_list, node) {
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> +				continue;
> +			if (tzp->tbp[i].match(tz, pos))
> +				continue;
> +			tzp->tbp[i].cdev = pos;
> +			__bind(tz, tzp->tbp[i].trip_mask, pos);
> +		}
> +	}
> +exit:
> +	mutex_unlock(&thermal_list_lock);
> +}
> +
> +static void thermal_zone_device_set_polling(struct thermal_zone_device
> *tz,
> +					    int delay)
> +{
> +	if (delay > 1000)
> +		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> +				 round_jiffies(msecs_to_jiffies(delay)));
> +	else if (delay)
> +		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> +				 msecs_to_jiffies(delay));
> +	else
> +		cancel_delayed_work(&tz->poll_queue);
> +}
> +
> +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);
> +	else if (tz->polling_delay)
> +		thermal_zone_device_set_polling(tz, tz->polling_delay);
> +	else
> +		thermal_zone_device_set_polling(tz, 0);
> +
> +	mutex_unlock(&tz->lock);
> +}
> +
> +static void handle_non_critical_trips(struct thermal_zone_device *tz,
> +			int trip, enum thermal_trip_type trip_type)
> +{
> +	if (tz->governor)
> +		tz->governor->throttle(tz, trip);
> +}
> +
> +static void handle_critical_trips(struct thermal_zone_device *tz,
> +				int trip, enum thermal_trip_type trip_type)
> +{
> +	long trip_temp;
> +
> +	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> +
> +	/* If we have not crossed the trip_temp, we do not care. */
> +	if (tz->temperature < trip_temp)
> +		return;
> +
> +	if (tz->ops->notify)
> +		tz->ops->notify(tz, trip, trip_type);
> +
> +	if (trip_type == THERMAL_TRIP_CRITICAL) {
> +		dev_emerg(&tz->device,
> +			  "critical temperature reached(%d C),shutting
> down\n",
> +			  tz->temperature / 1000);
> +		orderly_poweroff(true);
> +	}
> +}
> +
> +static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> +{
> +	enum thermal_trip_type type;
> +
> +	tz->ops->get_trip_type(tz, trip, &type);
> +
> +	if (type == THERMAL_TRIP_CRITICAL || type ==
> THERMAL_TRIP_HOT)
> +		handle_critical_trips(tz, trip, type);
> +	else
> +		handle_non_critical_trips(tz, trip, type);
> +	/*
> +	 * Alright, we handled this trip successfully.
> +	 * So, start monitoring again.
> +	 */
> +	monitor_thermal_zone(tz);
> +}
> +
> +static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> +				unsigned long *temp)
> +{
> +	int ret = 0;
> +#ifdef CONFIG_THERMAL_EMULATION
> +	int count;
> +	unsigned long crit_temp = -1UL;
> +	enum thermal_trip_type type;
> +#endif
> +
> +	mutex_lock(&tz->lock);
> +
> +	ret = tz->ops->get_temp(tz, temp);
> +#ifdef CONFIG_THERMAL_EMULATION
> +	if (!tz->emul_temperature)
> +		goto skip_emul;
> +
> +	for (count = 0; count < tz->trips; count++) {
> +		ret = tz->ops->get_trip_type(tz, count, &type);
> +		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> +			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> +			break;
> +		}
> +	}
> +
> +	if (ret)
> +		goto skip_emul;
> +
> +	if (*temp < crit_temp)
> +		*temp = tz->emul_temperature;
> +skip_emul:
> +#endif
> +	mutex_unlock(&tz->lock);
> +	return ret;
> +}
> +
> +static void update_temperature(struct thermal_zone_device *tz)
> +{
> +	long temp;
> +	int ret;
> +
> +	ret = thermal_zone_get_temp(tz, &temp);
> +	if (ret) {
> +		dev_warn(&tz->device, "failed to read out thermal zone
> %d\n",
> +			 tz->id);
> +		return;
> +	}
> +
> +	mutex_lock(&tz->lock);
> +	tz->last_temperature = tz->temperature;
> +	tz->temperature = temp;
> +	mutex_unlock(&tz->lock);
> +}
> +
> +void thermal_zone_device_update(struct thermal_zone_device *tz)
> +{
> +	int count;
> +
> +	update_temperature(tz);
> +
> +	for (count = 0; count < tz->trips; count++)
> +		handle_thermal_trip(tz, count);
> +}
> +EXPORT_SYMBOL(thermal_zone_device_update);
> +
> +static void thermal_zone_device_check(struct work_struct *work)
> +{
> +	struct thermal_zone_device *tz = container_of(work, struct
> +						      thermal_zone_device,
> +						      poll_queue.work);
> +	thermal_zone_device_update(tz);
> +}
> +
> +/* sys I/F for thermal zone */
> +
> +#define to_thermal_zone(_dev) \
> +	container_of(_dev, struct thermal_zone_device, device)
> +
> +static ssize_t
> +type_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> +	return sprintf(buf, "%s\n", tz->type);
> +}
> +
> +static ssize_t
> +temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	long temperature;
> +	int ret;
> +
> +	ret = thermal_zone_get_temp(tz, &temperature);
> +
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	enum thermal_device_mode mode;
> +	int result;
> +
> +	if (!tz->ops->get_mode)
> +		return -EPERM;
> +
> +	result = tz->ops->get_mode(tz, &mode);
> +	if (result)
> +		return result;
> +
> +	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ?
> "enabled"
> +		       : "disabled");
> +}
> +
> +static ssize_t
> +mode_store(struct device *dev, struct device_attribute *attr,
> +	   const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int result;
> +
> +	if (!tz->ops->set_mode)
> +		return -EPERM;
> +
> +	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);
> +	else
> +		result = -EINVAL;
> +
> +	if (result)
> +		return result;
> +
> +	return count;
> +}
> +
> +static ssize_t
> +trip_point_type_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	enum thermal_trip_type type;
> +	int trip, result;
> +
> +	if (!tz->ops->get_trip_type)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> +		return -EINVAL;
> +
> +	result = tz->ops->get_trip_type(tz, trip, &type);
> +	if (result)
> +		return result;
> +
> +	switch (type) {
> +	case THERMAL_TRIP_CRITICAL:
> +		return sprintf(buf, "critical\n");
> +	case THERMAL_TRIP_HOT:
> +		return sprintf(buf, "hot\n");
> +	case THERMAL_TRIP_PASSIVE:
> +		return sprintf(buf, "passive\n");
> +	case THERMAL_TRIP_ACTIVE:
> +		return sprintf(buf, "active\n");
> +	default:
> +		return sprintf(buf, "unknown\n");
> +	}
> +}
> +
> +static ssize_t
> +trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> +		     const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	unsigned long temperature;
> +
> +	if (!tz->ops->set_trip_temp)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> +		return -EINVAL;
> +
> +	if (kstrtoul(buf, 10, &temperature))
> +		return -EINVAL;
> +
> +	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> +
> +	return ret ? ret : count;
> +}
> +
> +static ssize_t
> +trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	long temperature;
> +
> +	if (!tz->ops->get_trip_temp)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> +		return -EINVAL;
> +
> +	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> +
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> +			const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	unsigned long temperature;
> +
> +	if (!tz->ops->set_trip_hyst)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> +		return -EINVAL;
> +
> +	if (kstrtoul(buf, 10, &temperature))
> +		return -EINVAL;
> +
> +	/*
> +	 * We are not doing any check on the 'temperature' value
> +	 * here. The driver implementing 'set_trip_hyst' has to
> +	 * take care of this.
> +	 */
> +	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> +
> +	return ret ? ret : count;
> +}
> +
> +static ssize_t
> +trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> +			char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	unsigned long temperature;
> +
> +	if (!tz->ops->get_trip_hyst)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> +		return -EINVAL;
> +
> +	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> +
> +	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +passive_store(struct device *dev, struct device_attribute *attr,
> +		    const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	struct thermal_cooling_device *cdev = NULL;
> +	int state;
> +
> +	if (!sscanf(buf, "%d\n", &state))
> +		return -EINVAL;
> +
> +	/* sanity check: values below 1000 millicelcius don't make sense
> +	 * and can cause the system to go into a thermal heart attack
> +	 */
> +	if (state && state < 1000)
> +		return -EINVAL;
> +
> +	if (state && !tz->forced_passive) {
> +		mutex_lock(&thermal_list_lock);
> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> +			if (!strncmp("Processor", cdev->type,
> +				     sizeof("Processor")))
> +				thermal_zone_bind_cooling_device(tz,
> +						THERMAL_TRIPS_NONE,
> cdev,
> +						THERMAL_NO_LIMIT,
> +						THERMAL_NO_LIMIT);
> +		}
> +		mutex_unlock(&thermal_list_lock);
> +		if (!tz->passive_delay)
> +			tz->passive_delay = 1000;
> +	} else if (!state && tz->forced_passive) {
> +		mutex_lock(&thermal_list_lock);
> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> +			if (!strncmp("Processor", cdev->type,
> +				     sizeof("Processor")))
> +				thermal_zone_unbind_cooling_device(tz,
> +
> THERMAL_TRIPS_NONE,
> +								   cdev);
> +		}
> +		mutex_unlock(&thermal_list_lock);
> +		tz->passive_delay = 0;
> +	}
> +
> +	tz->forced_passive = state;
> +
> +	thermal_zone_device_update(tz);
> +
> +	return count;
> +}
> +
> +static ssize_t
> +passive_show(struct device *dev, struct device_attribute *attr,
> +		   char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> +	return sprintf(buf, "%d\n", tz->forced_passive);
> +}
> +
> +static ssize_t
> +policy_store(struct device *dev, struct device_attribute *attr,
> +		    const char *buf, size_t count)
> +{
> +	int ret = -EINVAL;
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	struct thermal_governor *gov;
> +
> +	mutex_lock(&thermal_governor_lock);
> +
> +	gov = __find_governor(buf);
> +	if (!gov)
> +		goto exit;
> +
> +	tz->governor = gov;
> +	ret = count;
> +
> +exit:
> +	mutex_unlock(&thermal_governor_lock);
> +	return ret;
> +}
> +
> +static ssize_t
> +policy_show(struct device *dev, struct device_attribute *devattr, char
> *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> +	return sprintf(buf, "%s\n", tz->governor->name);
> +}
> +
> +#ifdef CONFIG_THERMAL_EMULATION
> +static ssize_t
> +emul_temp_store(struct device *dev, struct device_attribute *attr,
> +		     const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int ret = 0;
> +	unsigned long temperature;
> +
> +	if (kstrtoul(buf, 10, &temperature))
> +		return -EINVAL;
> +
> +	if (!tz->ops->set_emul_temp) {
> +		mutex_lock(&tz->lock);
> +		tz->emul_temperature = temperature;
> +		mutex_unlock(&tz->lock);
> +	} else {
> +		ret = tz->ops->set_emul_temp(tz, temperature);
> +	}
> +
> +	return ret ? ret : count;
> +}
> +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> +#endif/*CONFIG_THERMAL_EMULATION*/
> +
> +static DEVICE_ATTR(type, 0444, type_show, NULL);
> +static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> +static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show,
> passive_store);
> +static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show,
> policy_store);
> +
> +/* sys I/F for cooling device */
> +#define to_cooling_device(_dev)	\
> +	container_of(_dev, struct thermal_cooling_device, device)
> +
> +static ssize_t
> +thermal_cooling_device_type_show(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +
> +	return sprintf(buf, "%s\n", cdev->type);
> +}
> +
> +static ssize_t
> +thermal_cooling_device_max_state_show(struct device *dev,
> +				      struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +	unsigned long state;
> +	int ret;
> +
> +	ret = cdev->ops->get_max_state(cdev, &state);
> +	if (ret)
> +		return ret;
> +	return sprintf(buf, "%ld\n", state);
> +}
> +
> +static ssize_t
> +thermal_cooling_device_cur_state_show(struct device *dev,
> +				      struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +	unsigned long state;
> +	int ret;
> +
> +	ret = cdev->ops->get_cur_state(cdev, &state);
> +	if (ret)
> +		return ret;
> +	return sprintf(buf, "%ld\n", state);
> +}
> +
> +static ssize_t
> +thermal_cooling_device_cur_state_store(struct device *dev,
> +				       struct device_attribute *attr,
> +				       const char *buf, size_t count)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +	unsigned long state;
> +	int result;
> +
> +	if (!sscanf(buf, "%ld\n", &state))
> +		return -EINVAL;
> +
> +	if ((long)state < 0)
> +		return -EINVAL;
> +
> +	result = cdev->ops->set_cur_state(cdev, state);
> +	if (result)
> +		return result;
> +	return count;
> +}
> +
> +static struct device_attribute dev_attr_cdev_type =
> +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> +static DEVICE_ATTR(max_state, 0444,
> +		   thermal_cooling_device_max_state_show, NULL);
> +static DEVICE_ATTR(cur_state, 0644,
> +		   thermal_cooling_device_cur_state_show,
> +		   thermal_cooling_device_cur_state_store);
> +
> +static ssize_t
> +thermal_cooling_device_trip_point_show(struct device *dev,
> +				       struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_instance *instance;
> +
> +	instance =
> +	    container_of(attr, struct thermal_instance, attr);
> +
> +	if (instance->trip == THERMAL_TRIPS_NONE)
> +		return sprintf(buf, "-1\n");
> +	else
> +		return sprintf(buf, "%d\n", instance->trip);
> +}
> +
> +/* Device management */
> +
> +#if defined(CONFIG_THERMAL_HWMON)
> +
> +/* hwmon sys I/F */
> +#include <linux/hwmon.h>
> +
> +/* thermal zone devices with the same type share one hwmon device */
> +struct thermal_hwmon_device {
> +	char type[THERMAL_NAME_LENGTH];
> +	struct device *device;
> +	int count;
> +	struct list_head tz_list;
> +	struct list_head node;
> +};
> +
> +struct thermal_hwmon_attr {
> +	struct device_attribute attr;
> +	char name[16];
> +};
> +
> +/* one temperature input for each thermal zone */
> +struct thermal_hwmon_temp {
> +	struct list_head hwmon_node;
> +	struct thermal_zone_device *tz;
> +	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> +	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> +};
> +
> +static LIST_HEAD(thermal_hwmon_list);
> +
> +static ssize_t
> +name_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> +	return sprintf(buf, "%s\n", hwmon->type);
> +}
> +static DEVICE_ATTR(name, 0444, name_show, NULL);
> +
> +static ssize_t
> +temp_input_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> +{
> +	long temperature;
> +	int ret;
> +	struct thermal_hwmon_attr *hwmon_attr
> +			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> +	struct thermal_hwmon_temp *temp
> +			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> +				       temp_input);
> +	struct thermal_zone_device *tz = temp->tz;
> +
> +	ret = thermal_zone_get_temp(tz, &temperature);
> +
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +temp_crit_show(struct device *dev, struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct thermal_hwmon_attr *hwmon_attr
> +			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> +	struct thermal_hwmon_temp *temp
> +			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> +				       temp_crit);
> +	struct thermal_zone_device *tz = temp->tz;
> +	long temperature;
> +	int ret;
> +
> +	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +
> +static struct thermal_hwmon_device *
> +thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_device *hwmon;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> +		if (!strcmp(hwmon->type, tz->type)) {
> +			mutex_unlock(&thermal_list_lock);
> +			return hwmon;
> +		}
> +	mutex_unlock(&thermal_list_lock);
> +
> +	return NULL;
> +}
> +
> +/* Find the temperature input matching a given thermal zone */
> +static struct thermal_hwmon_temp *
> +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device
> *hwmon,
> +			  const struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_temp *temp;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> +		if (temp->tz == tz) {
> +			mutex_unlock(&thermal_list_lock);
> +			return temp;
> +		}
> +	mutex_unlock(&thermal_list_lock);
> +
> +	return NULL;
> +}
> +
> +static int
> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_device *hwmon;
> +	struct thermal_hwmon_temp *temp;
> +	int new_hwmon_device = 1;
> +	int result;
> +
> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> +	if (hwmon) {
> +		new_hwmon_device = 0;
> +		goto register_sys_interface;
> +	}
> +
> +	hwmon = kzalloc(sizeof(struct thermal_hwmon_device),
> GFP_KERNEL);
> +	if (!hwmon)
> +		return -ENOMEM;
> +
> +	INIT_LIST_HEAD(&hwmon->tz_list);
> +	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> +	hwmon->device = hwmon_device_register(NULL);
> +	if (IS_ERR(hwmon->device)) {
> +		result = PTR_ERR(hwmon->device);
> +		goto free_mem;
> +	}
> +	dev_set_drvdata(hwmon->device, hwmon);
> +	result = device_create_file(hwmon->device, &dev_attr_name);
> +	if (result)
> +		goto free_mem;
> +
> + register_sys_interface:
> +	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> +	if (!temp) {
> +		result = -ENOMEM;
> +		goto unregister_name;
> +	}
> +
> +	temp->tz = tz;
> +	hwmon->count++;
> +
> +	snprintf(temp->temp_input.name, sizeof(temp-
> >temp_input.name),
> +		 "temp%d_input", hwmon->count);
> +	temp->temp_input.attr.attr.name = temp->temp_input.name;
> +	temp->temp_input.attr.attr.mode = 0444;
> +	temp->temp_input.attr.show = temp_input_show;
> +	sysfs_attr_init(&temp->temp_input.attr.attr);
> +	result = device_create_file(hwmon->device, &temp-
> >temp_input.attr);
> +	if (result)
> +		goto free_temp_mem;
> +
> +	if (tz->ops->get_crit_temp) {
> +		unsigned long temperature;
> +		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> +			snprintf(temp->temp_crit.name,
> +				 sizeof(temp->temp_crit.name),
> +				"temp%d_crit", hwmon->count);
> +			temp->temp_crit.attr.attr.name = temp-
> >temp_crit.name;
> +			temp->temp_crit.attr.attr.mode = 0444;
> +			temp->temp_crit.attr.show = temp_crit_show;
> +			sysfs_attr_init(&temp->temp_crit.attr.attr);
> +			result = device_create_file(hwmon->device,
> +						    &temp->temp_crit.attr);
> +			if (result)
> +				goto unregister_input;
> +		}
> +	}
> +
> +	mutex_lock(&thermal_list_lock);
> +	if (new_hwmon_device)
> +		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> +	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	return 0;
> +
> + unregister_input:
> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> + free_temp_mem:
> +	kfree(temp);
> + unregister_name:
> +	if (new_hwmon_device) {
> +		device_remove_file(hwmon->device, &dev_attr_name);
> +		hwmon_device_unregister(hwmon->device);
> +	}
> + free_mem:
> +	if (new_hwmon_device)
> +		kfree(hwmon);
> +
> +	return result;
> +}
> +
> +static void
> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_device *hwmon;
> +	struct thermal_hwmon_temp *temp;
> +
> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> +	if (unlikely(!hwmon)) {
> +		/* Should never happen... */
> +		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> +		return;
> +	}
> +
> +	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> +	if (unlikely(!temp)) {
> +		/* Should never happen... */
> +		dev_dbg(&tz->device, "temperature input lookup
> failed!\n");
> +		return;
> +	}
> +
> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> +	if (tz->ops->get_crit_temp)
> +		device_remove_file(hwmon->device, &temp-
> >temp_crit.attr);
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_del(&temp->hwmon_node);
> +	kfree(temp);
> +	if (!list_empty(&hwmon->tz_list)) {
> +		mutex_unlock(&thermal_list_lock);
> +		return;
> +	}
> +	list_del(&hwmon->node);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	device_remove_file(hwmon->device, &dev_attr_name);
> +	hwmon_device_unregister(hwmon->device);
> +	kfree(hwmon);
> +}
> +#else
> +static int
> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +	return 0;
> +}
> +
> +static void
> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +}
> +#endif
> +
> +/**
> + * thermal_zone_bind_cooling_device - bind a cooling device to a thermal
> zone
> + * @tz:		thermal zone device
> + * @trip:	indicates which trip point the cooling devices is
> + *		associated with in this thermal zone.
> + * @cdev:	thermal cooling device
> + *
> + * This function is usually called in the thermal zone device .bind callback.
> + */
> +int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> +				     int trip,
> +				     struct thermal_cooling_device *cdev,
> +				     unsigned long upper, unsigned long lower)
> +{
> +	struct thermal_instance *dev;
> +	struct thermal_instance *pos;
> +	struct thermal_zone_device *pos1;
> +	struct thermal_cooling_device *pos2;
> +	unsigned long max_state;
> +	int result;
> +
> +	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> +		return -EINVAL;
> +
> +	list_for_each_entry(pos1, &thermal_tz_list, node) {
> +		if (pos1 == tz)
> +			break;
> +	}
> +	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> +		if (pos2 == cdev)
> +			break;
> +	}
> +
> +	if (tz != pos1 || cdev != pos2)
> +		return -EINVAL;
> +
> +	cdev->ops->get_max_state(cdev, &max_state);
> +
> +	/* lower default 0, upper default max_state */
> +	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> +	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> +
> +	if (lower > upper || upper > max_state)
> +		return -EINVAL;
> +
> +	dev =
> +	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> +	if (!dev)
> +		return -ENOMEM;
> +	dev->tz = tz;
> +	dev->cdev = cdev;
> +	dev->trip = trip;
> +	dev->upper = upper;
> +	dev->lower = lower;
> +	dev->target = THERMAL_NO_TARGET;
> +
> +	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> +	if (result)
> +		goto free_mem;
> +
> +	sprintf(dev->name, "cdev%d", dev->id);
> +	result =
> +	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev-
> >name);
> +	if (result)
> +		goto release_idr;
> +
> +	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> +	sysfs_attr_init(&dev->attr.attr);
> +	dev->attr.attr.name = dev->attr_name;
> +	dev->attr.attr.mode = 0444;
> +	dev->attr.show = thermal_cooling_device_trip_point_show;
> +	result = device_create_file(&tz->device, &dev->attr);
> +	if (result)
> +		goto remove_symbol_link;
> +
> +	mutex_lock(&tz->lock);
> +	mutex_lock(&cdev->lock);
> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> +	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> +		result = -EEXIST;
> +		break;
> +	}
> +	if (!result) {
> +		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> +		list_add_tail(&dev->cdev_node, &cdev-
> >thermal_instances);
> +	}
> +	mutex_unlock(&cdev->lock);
> +	mutex_unlock(&tz->lock);
> +
> +	if (!result)
> +		return 0;
> +
> +	device_remove_file(&tz->device, &dev->attr);
> +remove_symbol_link:
> +	sysfs_remove_link(&tz->device.kobj, dev->name);
> +release_idr:
> +	release_idr(&tz->idr, &tz->lock, dev->id);
> +free_mem:
> +	kfree(dev);
> +	return result;
> +}
> +EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> +
> +/**
> + * thermal_zone_unbind_cooling_device - unbind a cooling device from a
> thermal zone
> + * @tz:		thermal zone device
> + * @trip:	indicates which trip point the cooling devices is
> + *		associated with in this thermal zone.
> + * @cdev:	thermal cooling device
> + *
> + * This function is usually called in the thermal zone device .unbind callback.
> + */
> +int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> +				       int trip,
> +				       struct thermal_cooling_device *cdev)
> +{
> +	struct thermal_instance *pos, *next;
> +
> +	mutex_lock(&tz->lock);
> +	mutex_lock(&cdev->lock);
> +	list_for_each_entry_safe(pos, next, &tz->thermal_instances,
> tz_node) {
> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> +			list_del(&pos->tz_node);
> +			list_del(&pos->cdev_node);
> +			mutex_unlock(&cdev->lock);
> +			mutex_unlock(&tz->lock);
> +			goto unbind;
> +		}
> +	}
> +	mutex_unlock(&cdev->lock);
> +	mutex_unlock(&tz->lock);
> +
> +	return -ENODEV;
> +
> +unbind:
> +	device_remove_file(&tz->device, &pos->attr);
> +	sysfs_remove_link(&tz->device.kobj, pos->name);
> +	release_idr(&tz->idr, &tz->lock, pos->id);
> +	kfree(pos);
> +	return 0;
> +}
> +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> +
> +static void thermal_release(struct device *dev)
> +{
> +	struct thermal_zone_device *tz;
> +	struct thermal_cooling_device *cdev;
> +
> +	if (!strncmp(dev_name(dev), "thermal_zone",
> +		     sizeof("thermal_zone") - 1)) {
> +		tz = to_thermal_zone(dev);
> +		kfree(tz);
> +	} else {
> +		cdev = to_cooling_device(dev);
> +		kfree(cdev);
> +	}
> +}
> +
> +static struct class thermal_class = {
> +	.name = "thermal",
> +	.dev_release = thermal_release,
> +};
> +
> +/**
> + * thermal_cooling_device_register - register a new thermal cooling device
> + * @type:	the thermal cooling device type.
> + * @devdata:	device private data.
> + * @ops:		standard thermal cooling devices callbacks.
> + */
> +struct thermal_cooling_device *
> +thermal_cooling_device_register(char *type, void *devdata,
> +				const struct thermal_cooling_device_ops
> *ops)
> +{
> +	struct thermal_cooling_device *cdev;
> +	int result;
> +
> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> +	    !ops->set_cur_state)
> +		return ERR_PTR(-EINVAL);
> +
> +	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> +	if (!cdev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> +	if (result) {
> +		kfree(cdev);
> +		return ERR_PTR(result);
> +	}
> +
> +	strcpy(cdev->type, type ? : "");
> +	mutex_init(&cdev->lock);
> +	INIT_LIST_HEAD(&cdev->thermal_instances);
> +	cdev->ops = ops;
> +	cdev->updated = true;
> +	cdev->device.class = &thermal_class;
> +	cdev->devdata = devdata;
> +	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> +	result = device_register(&cdev->device);
> +	if (result) {
> +		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev-
> >id);
> +		kfree(cdev);
> +		return ERR_PTR(result);
> +	}
> +
> +	/* sys I/F */
> +	if (type) {
> +		result = device_create_file(&cdev->device,
> &dev_attr_cdev_type);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +	result = device_create_file(&cdev->device, &dev_attr_max_state);
> +	if (result)
> +		goto unregister;
> +
> +	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> +	if (result)
> +		goto unregister;
> +
> +	/* Add 'this' new cdev to the global cdev list */
> +	mutex_lock(&thermal_list_lock);
> +	list_add(&cdev->node, &thermal_cdev_list);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	/* Update binding information for 'this' new cdev */
> +	bind_cdev(cdev);
> +
> +	return cdev;
> +
> +unregister:
> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> +	device_unregister(&cdev->device);
> +	return ERR_PTR(result);
> +}
> +EXPORT_SYMBOL(thermal_cooling_device_register);
> +
> +/**
> + * thermal_cooling_device_unregister - removes the registered thermal
> cooling device
> + * @cdev:	the thermal cooling device to remove.
> + *
> + * thermal_cooling_device_unregister() must be called when the device is
> no
> + * longer needed.
> + */
> +void thermal_cooling_device_unregister(struct thermal_cooling_device
> *cdev)
> +{
> +	int i;
> +	const struct thermal_zone_params *tzp;
> +	struct thermal_zone_device *tz;
> +	struct thermal_cooling_device *pos = NULL;
> +
> +	if (!cdev)
> +		return;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(pos, &thermal_cdev_list, node)
> +	    if (pos == cdev)
> +		break;
> +	if (pos != cdev) {
> +		/* thermal cooling device not found */
> +		mutex_unlock(&thermal_list_lock);
> +		return;
> +	}
> +	list_del(&cdev->node);
> +
> +	/* Unbind all thermal zones associated with 'this' cdev */
> +	list_for_each_entry(tz, &thermal_tz_list, node) {
> +		if (tz->ops->unbind) {
> +			tz->ops->unbind(tz, cdev);
> +			continue;
> +		}
> +
> +		if (!tz->tzp || !tz->tzp->tbp)
> +			continue;
> +
> +		tzp = tz->tzp;
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev == cdev) {
> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> +				tzp->tbp[i].cdev = NULL;
> +			}
> +		}
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +
> +	if (cdev->type[0])
> +		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> +	device_remove_file(&cdev->device, &dev_attr_max_state);
> +	device_remove_file(&cdev->device, &dev_attr_cur_state);
> +
> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> +	device_unregister(&cdev->device);
> +	return;
> +}
> +EXPORT_SYMBOL(thermal_cooling_device_unregister);
> +
> +void thermal_cdev_update(struct thermal_cooling_device *cdev)
> +{
> +	struct thermal_instance *instance;
> +	unsigned long target = 0;
> +
> +	/* cooling device is updated*/
> +	if (cdev->updated)
> +		return;
> +
> +	mutex_lock(&cdev->lock);
> +	/* Make sure cdev enters the deepest cooling state */
> +	list_for_each_entry(instance, &cdev->thermal_instances,
> cdev_node) {
> +		if (instance->target == THERMAL_NO_TARGET)
> +			continue;
> +		if (instance->target > target)
> +			target = instance->target;
> +	}
> +	mutex_unlock(&cdev->lock);
> +	cdev->ops->set_cur_state(cdev, target);
> +	cdev->updated = true;
> +}
> +EXPORT_SYMBOL(thermal_cdev_update);
> +
> +/**
> + * notify_thermal_framework - Sensor drivers use this API to notify
> framework
> + * @tz:		thermal zone device
> + * @trip:	indicates which trip point has been crossed
> + *
> + * This function handles the trip events from sensor drivers. It starts
> + * throttling the cooling devices according to the policy configured.
> + * For CRITICAL and HOT trip points, this notifies the respective drivers,
> + * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> + * The throttling policy is based on the configured platform data; if no
> + * platform data is provided, this uses the step_wise throttling policy.
> + */
> +void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> +{
> +	handle_thermal_trip(tz, trip);
> +}
> +EXPORT_SYMBOL(notify_thermal_framework);
> +
> +/**
> + * create_trip_attrs - create attributes for trip points
> + * @tz:		the thermal zone device
> + * @mask:	Writeable trip point bitmap.
> + */
> +static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> +{
> +	int indx;
> +	int size = sizeof(struct thermal_attr) * tz->trips;
> +
> +	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> +	if (!tz->trip_type_attrs)
> +		return -ENOMEM;
> +
> +	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> +	if (!tz->trip_temp_attrs) {
> +		kfree(tz->trip_type_attrs);
> +		return -ENOMEM;
> +	}
> +
> +	if (tz->ops->get_trip_hyst) {
> +		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> +		if (!tz->trip_hyst_attrs) {
> +			kfree(tz->trip_type_attrs);
> +			kfree(tz->trip_temp_attrs);
> +			return -ENOMEM;
> +		}
> +	}
> +
> +
> +	for (indx = 0; indx < tz->trips; indx++) {
> +		/* create trip type attribute */
> +		snprintf(tz->trip_type_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> +			 "trip_point_%d_type", indx);
> +
> +		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> +		tz->trip_type_attrs[indx].attr.attr.name =
> +						tz-
> >trip_type_attrs[indx].name;
> +		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> +		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> +
> +		device_create_file(&tz->device,
> +				   &tz->trip_type_attrs[indx].attr);
> +
> +		/* create trip temp attribute */
> +		snprintf(tz->trip_temp_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> +			 "trip_point_%d_temp", indx);
> +
> +		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> +		tz->trip_temp_attrs[indx].attr.attr.name =
> +						tz-
> >trip_temp_attrs[indx].name;
> +		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> +		tz->trip_temp_attrs[indx].attr.show =
> trip_point_temp_show;
> +		if (mask & (1 << indx)) {
> +			tz->trip_temp_attrs[indx].attr.attr.mode |=
> S_IWUSR;
> +			tz->trip_temp_attrs[indx].attr.store =
> +
> 	trip_point_temp_store;
> +		}
> +
> +		device_create_file(&tz->device,
> +				   &tz->trip_temp_attrs[indx].attr);
> +
> +		/* create Optional trip hyst attribute */
> +		if (!tz->ops->get_trip_hyst)
> +			continue;
> +		snprintf(tz->trip_hyst_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> +			 "trip_point_%d_hyst", indx);
> +
> +		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> +		tz->trip_hyst_attrs[indx].attr.attr.name =
> +					tz->trip_hyst_attrs[indx].name;
> +		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> +		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> +		if (tz->ops->set_trip_hyst) {
> +			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> +			tz->trip_hyst_attrs[indx].attr.store =
> +					trip_point_hyst_store;
> +		}
> +
> +		device_create_file(&tz->device,
> +				   &tz->trip_hyst_attrs[indx].attr);
> +	}
> +	return 0;
> +}
> +
> +static void remove_trip_attrs(struct thermal_zone_device *tz)
> +{
> +	int indx;
> +
> +	for (indx = 0; indx < tz->trips; indx++) {
> +		device_remove_file(&tz->device,
> +				   &tz->trip_type_attrs[indx].attr);
> +		device_remove_file(&tz->device,
> +				   &tz->trip_temp_attrs[indx].attr);
> +		if (tz->ops->get_trip_hyst)
> +			device_remove_file(&tz->device,
> +				  &tz->trip_hyst_attrs[indx].attr);
> +	}
> +	kfree(tz->trip_type_attrs);
> +	kfree(tz->trip_temp_attrs);
> +	kfree(tz->trip_hyst_attrs);
> +}
> +
> +/**
> + * thermal_zone_device_register - register a new thermal zone device
> + * @type:	the thermal zone device type
> + * @trips:	the number of trip points the thermal zone support
> + * @mask:	a bit string indicating the writeablility of trip points
> + * @devdata:	private device data
> + * @ops:	standard thermal zone device callbacks
> + * @tzp:	thermal zone platform parameters
> + * @passive_delay: number of milliseconds to wait between polls when
> + *		   performing passive cooling
> + * @polling_delay: number of milliseconds to wait between polls when
> checking
> + *		   whether trip points have been crossed (0 for interrupt
> + *		   driven systems)
> + *
> + * thermal_zone_device_unregister() must be called when the device is no
> + * longer needed. The passive cooling depends on the .get_trend() return
> value.
> + */
> +struct thermal_zone_device *thermal_zone_device_register(const char
> *type,
> +	int trips, int mask, void *devdata,
> +	const struct thermal_zone_device_ops *ops,
> +	const struct thermal_zone_params *tzp,
> +	int passive_delay, int polling_delay)
> +{
> +	struct thermal_zone_device *tz;
> +	enum thermal_trip_type trip_type;
> +	int result;
> +	int count;
> +	int passive = 0;
> +
> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!ops || !ops->get_temp)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (trips > 0 && !ops->get_trip_type)
> +		return ERR_PTR(-EINVAL);
> +
> +	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> +	if (!tz)
> +		return ERR_PTR(-ENOMEM);
> +
> +	INIT_LIST_HEAD(&tz->thermal_instances);
> +	idr_init(&tz->idr);
> +	mutex_init(&tz->lock);
> +	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> +	if (result) {
> +		kfree(tz);
> +		return ERR_PTR(result);
> +	}
> +
> +	strcpy(tz->type, type ? : "");
> +	tz->ops = ops;
> +	tz->tzp = tzp;
> +	tz->device.class = &thermal_class;
> +	tz->devdata = devdata;
> +	tz->trips = trips;
> +	tz->passive_delay = passive_delay;
> +	tz->polling_delay = polling_delay;
> +
> +	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> +	result = device_register(&tz->device);
> +	if (result) {
> +		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> +		kfree(tz);
> +		return ERR_PTR(result);
> +	}
> +
> +	/* sys I/F */
> +	if (type) {
> +		result = device_create_file(&tz->device, &dev_attr_type);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +	result = device_create_file(&tz->device, &dev_attr_temp);
> +	if (result)
> +		goto unregister;
> +
> +	if (ops->get_mode) {
> +		result = device_create_file(&tz->device, &dev_attr_mode);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +	result = create_trip_attrs(tz, mask);
> +	if (result)
> +		goto unregister;
> +
> +	for (count = 0; count < trips; count++) {
> +		tz->ops->get_trip_type(tz, count, &trip_type);
> +		if (trip_type == THERMAL_TRIP_PASSIVE)
> +			passive = 1;
> +	}
> +
> +	if (!passive) {
> +		result = device_create_file(&tz->device, &dev_attr_passive);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +#ifdef CONFIG_THERMAL_EMULATION
> +	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> +	if (result)
> +		goto unregister;
> +#endif
> +	/* Create policy attribute */
> +	result = device_create_file(&tz->device, &dev_attr_policy);
> +	if (result)
> +		goto unregister;
> +
> +	/* Update 'this' zone's governor information */
> +	mutex_lock(&thermal_governor_lock);
> +
> +	if (tz->tzp)
> +		tz->governor = __find_governor(tz->tzp->governor_name);
> +	else
> +		tz->governor =
> __find_governor(DEFAULT_THERMAL_GOVERNOR);
> +
> +	mutex_unlock(&thermal_governor_lock);
> +
> +	result = thermal_add_hwmon_sysfs(tz);
> +	if (result)
> +		goto unregister;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_add_tail(&tz->node, &thermal_tz_list);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	/* Bind cooling devices for this zone */
> +	bind_tz(tz);
> +
> +	INIT_DELAYED_WORK(&(tz->poll_queue),
> thermal_zone_device_check);
> +
> +	thermal_zone_device_update(tz);
> +
> +	if (!result)
> +		return tz;
> +
> +unregister:
> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> +	device_unregister(&tz->device);
> +	return ERR_PTR(result);
> +}
> +EXPORT_SYMBOL(thermal_zone_device_register);
> +
> +/**
> + * thermal_device_unregister - removes the registered thermal zone
> device
> + * @tz: the thermal zone device to remove
> + */
> +void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> +{
> +	int i;
> +	const struct thermal_zone_params *tzp;
> +	struct thermal_cooling_device *cdev;
> +	struct thermal_zone_device *pos = NULL;
> +
> +	if (!tz)
> +		return;
> +
> +	tzp = tz->tzp;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(pos, &thermal_tz_list, node)
> +	    if (pos == tz)
> +		break;
> +	if (pos != tz) {
> +		/* thermal zone device not found */
> +		mutex_unlock(&thermal_list_lock);
> +		return;
> +	}
> +	list_del(&tz->node);
> +
> +	/* Unbind all cdevs associated with 'this' thermal zone */
> +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> +		if (tz->ops->unbind) {
> +			tz->ops->unbind(tz, cdev);
> +			continue;
> +		}
> +
> +		if (!tzp || !tzp->tbp)
> +			break;
> +
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev == cdev) {
> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> +				tzp->tbp[i].cdev = NULL;
> +			}
> +		}
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +
> +	thermal_zone_device_set_polling(tz, 0);
> +
> +	if (tz->type[0])
> +		device_remove_file(&tz->device, &dev_attr_type);
> +	device_remove_file(&tz->device, &dev_attr_temp);
> +	if (tz->ops->get_mode)
> +		device_remove_file(&tz->device, &dev_attr_mode);
> +	device_remove_file(&tz->device, &dev_attr_policy);
> +	remove_trip_attrs(tz);
> +	tz->governor = NULL;
> +
> +	thermal_remove_hwmon_sysfs(tz);
> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> +	idr_destroy(&tz->idr);
> +	mutex_destroy(&tz->lock);
> +	device_unregister(&tz->device);
> +	return;
> +}
> +EXPORT_SYMBOL(thermal_zone_device_unregister);
> +
> +#ifdef CONFIG_NET
> +static struct genl_family thermal_event_genl_family = {
> +	.id = GENL_ID_GENERATE,
> +	.name = THERMAL_GENL_FAMILY_NAME,
> +	.version = THERMAL_GENL_VERSION,
> +	.maxattr = THERMAL_GENL_ATTR_MAX,
> +};
> +
> +static struct genl_multicast_group thermal_event_mcgrp = {
> +	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> +};
> +
> +int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> +					enum events event)
> +{
> +	struct sk_buff *skb;
> +	struct nlattr *attr;
> +	struct thermal_genl_event *thermal_event;
> +	void *msg_header;
> +	int size;
> +	int result;
> +	static unsigned int thermal_event_seqnum;
> +
> +	if (!tz)
> +		return -EINVAL;
> +
> +	/* allocate memory */
> +	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> +	       nla_total_size(0);
> +
> +	skb = genlmsg_new(size, GFP_ATOMIC);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	/* add the genetlink message header */
> +	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> +				 &thermal_event_genl_family, 0,
> +				 THERMAL_GENL_CMD_EVENT);
> +	if (!msg_header) {
> +		nlmsg_free(skb);
> +		return -ENOMEM;
> +	}
> +
> +	/* fill the data */
> +	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> +			   sizeof(struct thermal_genl_event));
> +
> +	if (!attr) {
> +		nlmsg_free(skb);
> +		return -EINVAL;
> +	}
> +
> +	thermal_event = nla_data(attr);
> +	if (!thermal_event) {
> +		nlmsg_free(skb);
> +		return -EINVAL;
> +	}
> +
> +	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> +
> +	thermal_event->orig = tz->id;
> +	thermal_event->event = event;
> +
> +	/* send multicast genetlink message */
> +	result = genlmsg_end(skb, msg_header);
> +	if (result < 0) {
> +		nlmsg_free(skb);
> +		return result;
> +	}
> +
> +	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id,
> GFP_ATOMIC);
> +	if (result)
> +		dev_err(&tz->device, "Failed to send netlink event:%d",
> result);
> +
> +	return result;
> +}
> +EXPORT_SYMBOL(thermal_generate_netlink_event);
> +
> +static int genetlink_init(void)
> +{
> +	int result;
> +
> +	result = genl_register_family(&thermal_event_genl_family);
> +	if (result)
> +		return result;
> +
> +	result = genl_register_mc_group(&thermal_event_genl_family,
> +					&thermal_event_mcgrp);
> +	if (result)
> +		genl_unregister_family(&thermal_event_genl_family);
> +	return result;
> +}
> +
> +static void genetlink_exit(void)
> +{
> +	genl_unregister_family(&thermal_event_genl_family);
> +}
> +#else /* !CONFIG_NET */
> +static inline int genetlink_init(void) { return 0; }
> +static inline void genetlink_exit(void) {}
> +#endif /* !CONFIG_NET */
> +
> +static int __init thermal_init(void)
> +{
> +	int result = 0;
> +
> +	result = class_register(&thermal_class);
> +	if (result) {
> +		idr_destroy(&thermal_tz_idr);
> +		idr_destroy(&thermal_cdev_idr);
> +		mutex_destroy(&thermal_idr_lock);
> +		mutex_destroy(&thermal_list_lock);
> +		return result;
> +	}
> +	result = genetlink_init();
> +	return result;
> +}
> +
> +static void __exit thermal_exit(void)
> +{
> +	class_unregister(&thermal_class);
> +	idr_destroy(&thermal_tz_idr);
> +	idr_destroy(&thermal_cdev_idr);
> +	mutex_destroy(&thermal_idr_lock);
> +	mutex_destroy(&thermal_list_lock);
> +	genetlink_exit();
> +}
> +
> +fs_initcall(thermal_init);
> +module_exit(thermal_exit);
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> deleted file mode 100644
> index 5b7863a..0000000
> --- a/drivers/thermal/thermal_sys.c
> +++ /dev/null
> @@ -1,1888 +0,0 @@
> -/*
> - *  thermal.c - Generic Thermal Management Sysfs support.
> - *
> - *  Copyright (C) 2008 Intel Corp
> - *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> - *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> - *
> - *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> - *
> - *  This program is free software; you can redistribute it and/or modify
> - *  it under the terms of the GNU General Public License as published by
> - *  the Free Software Foundation; version 2 of the License.
> - *
> - *  This program is distributed in the hope that it will be useful, but
> - *  WITHOUT ANY WARRANTY; without even the implied warranty of
> - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> GNU
> - *  General Public License for more details.
> - *
> - *  You should have received a copy of the GNU General Public License along
> - *  with this program; if not, write to the Free Software Foundation, Inc.,
> - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> - *
> - *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
> -#include <linux/device.h>
> -#include <linux/err.h>
> -#include <linux/slab.h>
> -#include <linux/kdev_t.h>
> -#include <linux/idr.h>
> -#include <linux/thermal.h>
> -#include <linux/reboot.h>
> -#include <net/netlink.h>
> -#include <net/genetlink.h>
> -
> -#include "thermal_core.h"
> -
> -MODULE_AUTHOR("Zhang Rui");
> -MODULE_DESCRIPTION("Generic thermal management sysfs support");
> -MODULE_LICENSE("GPL");
> -
> -static DEFINE_IDR(thermal_tz_idr);
> -static DEFINE_IDR(thermal_cdev_idr);
> -static DEFINE_MUTEX(thermal_idr_lock);
> -
> -static LIST_HEAD(thermal_tz_list);
> -static LIST_HEAD(thermal_cdev_list);
> -static LIST_HEAD(thermal_governor_list);
> -
> -static DEFINE_MUTEX(thermal_list_lock);
> -static DEFINE_MUTEX(thermal_governor_lock);
> -
> -static struct thermal_governor *__find_governor(const char *name)
> -{
> -	struct thermal_governor *pos;
> -
> -	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> -		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> -			return pos;
> -
> -	return NULL;
> -}
> -
> -int thermal_register_governor(struct thermal_governor *governor)
> -{
> -	int err;
> -	const char *name;
> -	struct thermal_zone_device *pos;
> -
> -	if (!governor)
> -		return -EINVAL;
> -
> -	mutex_lock(&thermal_governor_lock);
> -
> -	err = -EBUSY;
> -	if (__find_governor(governor->name) == NULL) {
> -		err = 0;
> -		list_add(&governor->governor_list,
> &thermal_governor_list);
> -	}
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> -		if (pos->governor)
> -			continue;
> -		if (pos->tzp)
> -			name = pos->tzp->governor_name;
> -		else
> -			name = DEFAULT_THERMAL_GOVERNOR;
> -		if (!strnicmp(name, governor->name,
> THERMAL_NAME_LENGTH))
> -			pos->governor = governor;
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -	mutex_unlock(&thermal_governor_lock);
> -
> -	return err;
> -}
> -EXPORT_SYMBOL_GPL(thermal_register_governor);
> -
> -void thermal_unregister_governor(struct thermal_governor *governor)
> -{
> -	struct thermal_zone_device *pos;
> -
> -	if (!governor)
> -		return;
> -
> -	mutex_lock(&thermal_governor_lock);
> -
> -	if (__find_governor(governor->name) == NULL)
> -		goto exit;
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> -		if (!strnicmp(pos->governor->name, governor->name,
> -						THERMAL_NAME_LENGTH))
> -			pos->governor = NULL;
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -	list_del(&governor->governor_list);
> -exit:
> -	mutex_unlock(&thermal_governor_lock);
> -	return;
> -}
> -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> -
> -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> -{
> -	int ret;
> -
> -	if (lock)
> -		mutex_lock(lock);
> -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> -	if (lock)
> -		mutex_unlock(lock);
> -	if (unlikely(ret < 0))
> -		return ret;
> -	*id = ret;
> -	return 0;
> -}
> -
> -static void release_idr(struct idr *idr, struct mutex *lock, int id)
> -{
> -	if (lock)
> -		mutex_lock(lock);
> -	idr_remove(idr, id);
> -	if (lock)
> -		mutex_unlock(lock);
> -}
> -
> -int get_tz_trend(struct thermal_zone_device *tz, int trip)
> -{
> -	enum thermal_trend trend;
> -
> -	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> -		if (tz->temperature > tz->last_temperature)
> -			trend = THERMAL_TREND_RAISING;
> -		else if (tz->temperature < tz->last_temperature)
> -			trend = THERMAL_TREND_DROPPING;
> -		else
> -			trend = THERMAL_TREND_STABLE;
> -	}
> -
> -	return trend;
> -}
> -EXPORT_SYMBOL(get_tz_trend);
> -
> -struct thermal_instance *get_thermal_instance(struct
> thermal_zone_device *tz,
> -			struct thermal_cooling_device *cdev, int trip)
> -{
> -	struct thermal_instance *pos = NULL;
> -	struct thermal_instance *target_instance = NULL;
> -
> -	mutex_lock(&tz->lock);
> -	mutex_lock(&cdev->lock);
> -
> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> -			target_instance = pos;
> -			break;
> -		}
> -	}
> -
> -	mutex_unlock(&cdev->lock);
> -	mutex_unlock(&tz->lock);
> -
> -	return target_instance;
> -}
> -EXPORT_SYMBOL(get_thermal_instance);
> -
> -static void print_bind_err_msg(struct thermal_zone_device *tz,
> -			struct thermal_cooling_device *cdev, int ret)
> -{
> -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> -				tz->type, cdev->type, ret);
> -}
> -
> -static void __bind(struct thermal_zone_device *tz, int mask,
> -			struct thermal_cooling_device *cdev)
> -{
> -	int i, ret;
> -
> -	for (i = 0; i < tz->trips; i++) {
> -		if (mask & (1 << i)) {
> -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> -					THERMAL_NO_LIMIT,
> THERMAL_NO_LIMIT);
> -			if (ret)
> -				print_bind_err_msg(tz, cdev, ret);
> -		}
> -	}
> -}
> -
> -static void __unbind(struct thermal_zone_device *tz, int mask,
> -			struct thermal_cooling_device *cdev)
> -{
> -	int i;
> -
> -	for (i = 0; i < tz->trips; i++)
> -		if (mask & (1 << i))
> -			thermal_zone_unbind_cooling_device(tz, i, cdev);
> -}
> -
> -static void bind_cdev(struct thermal_cooling_device *cdev)
> -{
> -	int i, ret;
> -	const struct thermal_zone_params *tzp;
> -	struct thermal_zone_device *pos = NULL;
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> -		if (!pos->tzp && !pos->ops->bind)
> -			continue;
> -
> -		if (!pos->tzp && pos->ops->bind) {
> -			ret = pos->ops->bind(pos, cdev);
> -			if (ret)
> -				print_bind_err_msg(pos, cdev, ret);
> -		}
> -
> -		tzp = pos->tzp;
> -		if (!tzp || !tzp->tbp)
> -			continue;
> -
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> -				continue;
> -			if (tzp->tbp[i].match(pos, cdev))
> -				continue;
> -			tzp->tbp[i].cdev = cdev;
> -			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> -		}
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -}
> -
> -static void bind_tz(struct thermal_zone_device *tz)
> -{
> -	int i, ret;
> -	struct thermal_cooling_device *pos = NULL;
> -	const struct thermal_zone_params *tzp = tz->tzp;
> -
> -	if (!tzp && !tz->ops->bind)
> -		return;
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	/* If there is no platform data, try to use ops->bind */
> -	if (!tzp && tz->ops->bind) {
> -		list_for_each_entry(pos, &thermal_cdev_list, node) {
> -			ret = tz->ops->bind(tz, pos);
> -			if (ret)
> -				print_bind_err_msg(tz, pos, ret);
> -		}
> -		goto exit;
> -	}
> -
> -	if (!tzp || !tzp->tbp)
> -		goto exit;
> -
> -	list_for_each_entry(pos, &thermal_cdev_list, node) {
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> -				continue;
> -			if (tzp->tbp[i].match(tz, pos))
> -				continue;
> -			tzp->tbp[i].cdev = pos;
> -			__bind(tz, tzp->tbp[i].trip_mask, pos);
> -		}
> -	}
> -exit:
> -	mutex_unlock(&thermal_list_lock);
> -}
> -
> -static void thermal_zone_device_set_polling(struct thermal_zone_device
> *tz,
> -					    int delay)
> -{
> -	if (delay > 1000)
> -		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> -				 round_jiffies(msecs_to_jiffies(delay)));
> -	else if (delay)
> -		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> -				 msecs_to_jiffies(delay));
> -	else
> -		cancel_delayed_work(&tz->poll_queue);
> -}
> -
> -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);
> -	else if (tz->polling_delay)
> -		thermal_zone_device_set_polling(tz, tz->polling_delay);
> -	else
> -		thermal_zone_device_set_polling(tz, 0);
> -
> -	mutex_unlock(&tz->lock);
> -}
> -
> -static void handle_non_critical_trips(struct thermal_zone_device *tz,
> -			int trip, enum thermal_trip_type trip_type)
> -{
> -	if (tz->governor)
> -		tz->governor->throttle(tz, trip);
> -}
> -
> -static void handle_critical_trips(struct thermal_zone_device *tz,
> -				int trip, enum thermal_trip_type trip_type)
> -{
> -	long trip_temp;
> -
> -	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> -
> -	/* If we have not crossed the trip_temp, we do not care. */
> -	if (tz->temperature < trip_temp)
> -		return;
> -
> -	if (tz->ops->notify)
> -		tz->ops->notify(tz, trip, trip_type);
> -
> -	if (trip_type == THERMAL_TRIP_CRITICAL) {
> -		dev_emerg(&tz->device,
> -			  "critical temperature reached(%d C),shutting
> down\n",
> -			  tz->temperature / 1000);
> -		orderly_poweroff(true);
> -	}
> -}
> -
> -static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> -{
> -	enum thermal_trip_type type;
> -
> -	tz->ops->get_trip_type(tz, trip, &type);
> -
> -	if (type == THERMAL_TRIP_CRITICAL || type ==
> THERMAL_TRIP_HOT)
> -		handle_critical_trips(tz, trip, type);
> -	else
> -		handle_non_critical_trips(tz, trip, type);
> -	/*
> -	 * Alright, we handled this trip successfully.
> -	 * So, start monitoring again.
> -	 */
> -	monitor_thermal_zone(tz);
> -}
> -
> -static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> -				unsigned long *temp)
> -{
> -	int ret = 0;
> -#ifdef CONFIG_THERMAL_EMULATION
> -	int count;
> -	unsigned long crit_temp = -1UL;
> -	enum thermal_trip_type type;
> -#endif
> -
> -	mutex_lock(&tz->lock);
> -
> -	ret = tz->ops->get_temp(tz, temp);
> -#ifdef CONFIG_THERMAL_EMULATION
> -	if (!tz->emul_temperature)
> -		goto skip_emul;
> -
> -	for (count = 0; count < tz->trips; count++) {
> -		ret = tz->ops->get_trip_type(tz, count, &type);
> -		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> -			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> -			break;
> -		}
> -	}
> -
> -	if (ret)
> -		goto skip_emul;
> -
> -	if (*temp < crit_temp)
> -		*temp = tz->emul_temperature;
> -skip_emul:
> -#endif
> -	mutex_unlock(&tz->lock);
> -	return ret;
> -}
> -
> -static void update_temperature(struct thermal_zone_device *tz)
> -{
> -	long temp;
> -	int ret;
> -
> -	ret = thermal_zone_get_temp(tz, &temp);
> -	if (ret) {
> -		dev_warn(&tz->device, "failed to read out thermal zone
> %d\n",
> -			 tz->id);
> -		return;
> -	}
> -
> -	mutex_lock(&tz->lock);
> -	tz->last_temperature = tz->temperature;
> -	tz->temperature = temp;
> -	mutex_unlock(&tz->lock);
> -}
> -
> -void thermal_zone_device_update(struct thermal_zone_device *tz)
> -{
> -	int count;
> -
> -	update_temperature(tz);
> -
> -	for (count = 0; count < tz->trips; count++)
> -		handle_thermal_trip(tz, count);
> -}
> -EXPORT_SYMBOL(thermal_zone_device_update);
> -
> -static void thermal_zone_device_check(struct work_struct *work)
> -{
> -	struct thermal_zone_device *tz = container_of(work, struct
> -						      thermal_zone_device,
> -						      poll_queue.work);
> -	thermal_zone_device_update(tz);
> -}
> -
> -/* sys I/F for thermal zone */
> -
> -#define to_thermal_zone(_dev) \
> -	container_of(_dev, struct thermal_zone_device, device)
> -
> -static ssize_t
> -type_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -
> -	return sprintf(buf, "%s\n", tz->type);
> -}
> -
> -static ssize_t
> -temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	long temperature;
> -	int ret;
> -
> -	ret = thermal_zone_get_temp(tz, &temperature);
> -
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	enum thermal_device_mode mode;
> -	int result;
> -
> -	if (!tz->ops->get_mode)
> -		return -EPERM;
> -
> -	result = tz->ops->get_mode(tz, &mode);
> -	if (result)
> -		return result;
> -
> -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ?
> "enabled"
> -		       : "disabled");
> -}
> -
> -static ssize_t
> -mode_store(struct device *dev, struct device_attribute *attr,
> -	   const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int result;
> -
> -	if (!tz->ops->set_mode)
> -		return -EPERM;
> -
> -	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);
> -	else
> -		result = -EINVAL;
> -
> -	if (result)
> -		return result;
> -
> -	return count;
> -}
> -
> -static ssize_t
> -trip_point_type_show(struct device *dev, struct device_attribute *attr,
> -		     char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	enum thermal_trip_type type;
> -	int trip, result;
> -
> -	if (!tz->ops->get_trip_type)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> -		return -EINVAL;
> -
> -	result = tz->ops->get_trip_type(tz, trip, &type);
> -	if (result)
> -		return result;
> -
> -	switch (type) {
> -	case THERMAL_TRIP_CRITICAL:
> -		return sprintf(buf, "critical\n");
> -	case THERMAL_TRIP_HOT:
> -		return sprintf(buf, "hot\n");
> -	case THERMAL_TRIP_PASSIVE:
> -		return sprintf(buf, "passive\n");
> -	case THERMAL_TRIP_ACTIVE:
> -		return sprintf(buf, "active\n");
> -	default:
> -		return sprintf(buf, "unknown\n");
> -	}
> -}
> -
> -static ssize_t
> -trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> -		     const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	unsigned long temperature;
> -
> -	if (!tz->ops->set_trip_temp)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> -		return -EINVAL;
> -
> -	if (kstrtoul(buf, 10, &temperature))
> -		return -EINVAL;
> -
> -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> -
> -	return ret ? ret : count;
> -}
> -
> -static ssize_t
> -trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> -		     char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	long temperature;
> -
> -	if (!tz->ops->get_trip_temp)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> -		return -EINVAL;
> -
> -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> -
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> -			const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	unsigned long temperature;
> -
> -	if (!tz->ops->set_trip_hyst)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> -		return -EINVAL;
> -
> -	if (kstrtoul(buf, 10, &temperature))
> -		return -EINVAL;
> -
> -	/*
> -	 * We are not doing any check on the 'temperature' value
> -	 * here. The driver implementing 'set_trip_hyst' has to
> -	 * take care of this.
> -	 */
> -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> -
> -	return ret ? ret : count;
> -}
> -
> -static ssize_t
> -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> -			char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	unsigned long temperature;
> -
> -	if (!tz->ops->get_trip_hyst)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> -		return -EINVAL;
> -
> -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> -
> -	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -passive_store(struct device *dev, struct device_attribute *attr,
> -		    const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	struct thermal_cooling_device *cdev = NULL;
> -	int state;
> -
> -	if (!sscanf(buf, "%d\n", &state))
> -		return -EINVAL;
> -
> -	/* sanity check: values below 1000 millicelcius don't make sense
> -	 * and can cause the system to go into a thermal heart attack
> -	 */
> -	if (state && state < 1000)
> -		return -EINVAL;
> -
> -	if (state && !tz->forced_passive) {
> -		mutex_lock(&thermal_list_lock);
> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> -			if (!strncmp("Processor", cdev->type,
> -				     sizeof("Processor")))
> -				thermal_zone_bind_cooling_device(tz,
> -						THERMAL_TRIPS_NONE,
> cdev,
> -						THERMAL_NO_LIMIT,
> -						THERMAL_NO_LIMIT);
> -		}
> -		mutex_unlock(&thermal_list_lock);
> -		if (!tz->passive_delay)
> -			tz->passive_delay = 1000;
> -	} else if (!state && tz->forced_passive) {
> -		mutex_lock(&thermal_list_lock);
> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> -			if (!strncmp("Processor", cdev->type,
> -				     sizeof("Processor")))
> -				thermal_zone_unbind_cooling_device(tz,
> -
> THERMAL_TRIPS_NONE,
> -								   cdev);
> -		}
> -		mutex_unlock(&thermal_list_lock);
> -		tz->passive_delay = 0;
> -	}
> -
> -	tz->forced_passive = state;
> -
> -	thermal_zone_device_update(tz);
> -
> -	return count;
> -}
> -
> -static ssize_t
> -passive_show(struct device *dev, struct device_attribute *attr,
> -		   char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -
> -	return sprintf(buf, "%d\n", tz->forced_passive);
> -}
> -
> -static ssize_t
> -policy_store(struct device *dev, struct device_attribute *attr,
> -		    const char *buf, size_t count)
> -{
> -	int ret = -EINVAL;
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	struct thermal_governor *gov;
> -
> -	mutex_lock(&thermal_governor_lock);
> -
> -	gov = __find_governor(buf);
> -	if (!gov)
> -		goto exit;
> -
> -	tz->governor = gov;
> -	ret = count;
> -
> -exit:
> -	mutex_unlock(&thermal_governor_lock);
> -	return ret;
> -}
> -
> -static ssize_t
> -policy_show(struct device *dev, struct device_attribute *devattr, char
> *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -
> -	return sprintf(buf, "%s\n", tz->governor->name);
> -}
> -
> -#ifdef CONFIG_THERMAL_EMULATION
> -static ssize_t
> -emul_temp_store(struct device *dev, struct device_attribute *attr,
> -		     const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int ret = 0;
> -	unsigned long temperature;
> -
> -	if (kstrtoul(buf, 10, &temperature))
> -		return -EINVAL;
> -
> -	if (!tz->ops->set_emul_temp) {
> -		mutex_lock(&tz->lock);
> -		tz->emul_temperature = temperature;
> -		mutex_unlock(&tz->lock);
> -	} else {
> -		ret = tz->ops->set_emul_temp(tz, temperature);
> -	}
> -
> -	return ret ? ret : count;
> -}
> -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> -#endif/*CONFIG_THERMAL_EMULATION*/
> -
> -static DEVICE_ATTR(type, 0444, type_show, NULL);
> -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show,
> passive_store);
> -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show,
> policy_store);
> -
> -/* sys I/F for cooling device */
> -#define to_cooling_device(_dev)	\
> -	container_of(_dev, struct thermal_cooling_device, device)
> -
> -static ssize_t
> -thermal_cooling_device_type_show(struct device *dev,
> -				 struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -
> -	return sprintf(buf, "%s\n", cdev->type);
> -}
> -
> -static ssize_t
> -thermal_cooling_device_max_state_show(struct device *dev,
> -				      struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -	unsigned long state;
> -	int ret;
> -
> -	ret = cdev->ops->get_max_state(cdev, &state);
> -	if (ret)
> -		return ret;
> -	return sprintf(buf, "%ld\n", state);
> -}
> -
> -static ssize_t
> -thermal_cooling_device_cur_state_show(struct device *dev,
> -				      struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -	unsigned long state;
> -	int ret;
> -
> -	ret = cdev->ops->get_cur_state(cdev, &state);
> -	if (ret)
> -		return ret;
> -	return sprintf(buf, "%ld\n", state);
> -}
> -
> -static ssize_t
> -thermal_cooling_device_cur_state_store(struct device *dev,
> -				       struct device_attribute *attr,
> -				       const char *buf, size_t count)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -	unsigned long state;
> -	int result;
> -
> -	if (!sscanf(buf, "%ld\n", &state))
> -		return -EINVAL;
> -
> -	if ((long)state < 0)
> -		return -EINVAL;
> -
> -	result = cdev->ops->set_cur_state(cdev, state);
> -	if (result)
> -		return result;
> -	return count;
> -}
> -
> -static struct device_attribute dev_attr_cdev_type =
> -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> -static DEVICE_ATTR(max_state, 0444,
> -		   thermal_cooling_device_max_state_show, NULL);
> -static DEVICE_ATTR(cur_state, 0644,
> -		   thermal_cooling_device_cur_state_show,
> -		   thermal_cooling_device_cur_state_store);
> -
> -static ssize_t
> -thermal_cooling_device_trip_point_show(struct device *dev,
> -				       struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_instance *instance;
> -
> -	instance =
> -	    container_of(attr, struct thermal_instance, attr);
> -
> -	if (instance->trip == THERMAL_TRIPS_NONE)
> -		return sprintf(buf, "-1\n");
> -	else
> -		return sprintf(buf, "%d\n", instance->trip);
> -}
> -
> -/* Device management */
> -
> -#if defined(CONFIG_THERMAL_HWMON)
> -
> -/* hwmon sys I/F */
> -#include <linux/hwmon.h>
> -
> -/* thermal zone devices with the same type share one hwmon device */
> -struct thermal_hwmon_device {
> -	char type[THERMAL_NAME_LENGTH];
> -	struct device *device;
> -	int count;
> -	struct list_head tz_list;
> -	struct list_head node;
> -};
> -
> -struct thermal_hwmon_attr {
> -	struct device_attribute attr;
> -	char name[16];
> -};
> -
> -/* one temperature input for each thermal zone */
> -struct thermal_hwmon_temp {
> -	struct list_head hwmon_node;
> -	struct thermal_zone_device *tz;
> -	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> -	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> -};
> -
> -static LIST_HEAD(thermal_hwmon_list);
> -
> -static ssize_t
> -name_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> -	return sprintf(buf, "%s\n", hwmon->type);
> -}
> -static DEVICE_ATTR(name, 0444, name_show, NULL);
> -
> -static ssize_t
> -temp_input_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> -{
> -	long temperature;
> -	int ret;
> -	struct thermal_hwmon_attr *hwmon_attr
> -			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> -	struct thermal_hwmon_temp *temp
> -			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> -				       temp_input);
> -	struct thermal_zone_device *tz = temp->tz;
> -
> -	ret = thermal_zone_get_temp(tz, &temperature);
> -
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -temp_crit_show(struct device *dev, struct device_attribute *attr,
> -		char *buf)
> -{
> -	struct thermal_hwmon_attr *hwmon_attr
> -			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> -	struct thermal_hwmon_temp *temp
> -			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> -				       temp_crit);
> -	struct thermal_zone_device *tz = temp->tz;
> -	long temperature;
> -	int ret;
> -
> -	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -
> -static struct thermal_hwmon_device *
> -thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_device *hwmon;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> -		if (!strcmp(hwmon->type, tz->type)) {
> -			mutex_unlock(&thermal_list_lock);
> -			return hwmon;
> -		}
> -	mutex_unlock(&thermal_list_lock);
> -
> -	return NULL;
> -}
> -
> -/* Find the temperature input matching a given thermal zone */
> -static struct thermal_hwmon_temp *
> -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device
> *hwmon,
> -			  const struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_temp *temp;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> -		if (temp->tz == tz) {
> -			mutex_unlock(&thermal_list_lock);
> -			return temp;
> -		}
> -	mutex_unlock(&thermal_list_lock);
> -
> -	return NULL;
> -}
> -
> -static int
> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_device *hwmon;
> -	struct thermal_hwmon_temp *temp;
> -	int new_hwmon_device = 1;
> -	int result;
> -
> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> -	if (hwmon) {
> -		new_hwmon_device = 0;
> -		goto register_sys_interface;
> -	}
> -
> -	hwmon = kzalloc(sizeof(struct thermal_hwmon_device),
> GFP_KERNEL);
> -	if (!hwmon)
> -		return -ENOMEM;
> -
> -	INIT_LIST_HEAD(&hwmon->tz_list);
> -	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> -	hwmon->device = hwmon_device_register(NULL);
> -	if (IS_ERR(hwmon->device)) {
> -		result = PTR_ERR(hwmon->device);
> -		goto free_mem;
> -	}
> -	dev_set_drvdata(hwmon->device, hwmon);
> -	result = device_create_file(hwmon->device, &dev_attr_name);
> -	if (result)
> -		goto free_mem;
> -
> - register_sys_interface:
> -	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> -	if (!temp) {
> -		result = -ENOMEM;
> -		goto unregister_name;
> -	}
> -
> -	temp->tz = tz;
> -	hwmon->count++;
> -
> -	snprintf(temp->temp_input.name, sizeof(temp-
> >temp_input.name),
> -		 "temp%d_input", hwmon->count);
> -	temp->temp_input.attr.attr.name = temp->temp_input.name;
> -	temp->temp_input.attr.attr.mode = 0444;
> -	temp->temp_input.attr.show = temp_input_show;
> -	sysfs_attr_init(&temp->temp_input.attr.attr);
> -	result = device_create_file(hwmon->device, &temp-
> >temp_input.attr);
> -	if (result)
> -		goto free_temp_mem;
> -
> -	if (tz->ops->get_crit_temp) {
> -		unsigned long temperature;
> -		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> -			snprintf(temp->temp_crit.name,
> -				 sizeof(temp->temp_crit.name),
> -				"temp%d_crit", hwmon->count);
> -			temp->temp_crit.attr.attr.name = temp-
> >temp_crit.name;
> -			temp->temp_crit.attr.attr.mode = 0444;
> -			temp->temp_crit.attr.show = temp_crit_show;
> -			sysfs_attr_init(&temp->temp_crit.attr.attr);
> -			result = device_create_file(hwmon->device,
> -						    &temp->temp_crit.attr);
> -			if (result)
> -				goto unregister_input;
> -		}
> -	}
> -
> -	mutex_lock(&thermal_list_lock);
> -	if (new_hwmon_device)
> -		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> -	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	return 0;
> -
> - unregister_input:
> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> - free_temp_mem:
> -	kfree(temp);
> - unregister_name:
> -	if (new_hwmon_device) {
> -		device_remove_file(hwmon->device, &dev_attr_name);
> -		hwmon_device_unregister(hwmon->device);
> -	}
> - free_mem:
> -	if (new_hwmon_device)
> -		kfree(hwmon);
> -
> -	return result;
> -}
> -
> -static void
> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_device *hwmon;
> -	struct thermal_hwmon_temp *temp;
> -
> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> -	if (unlikely(!hwmon)) {
> -		/* Should never happen... */
> -		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> -		return;
> -	}
> -
> -	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> -	if (unlikely(!temp)) {
> -		/* Should never happen... */
> -		dev_dbg(&tz->device, "temperature input lookup
> failed!\n");
> -		return;
> -	}
> -
> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> -	if (tz->ops->get_crit_temp)
> -		device_remove_file(hwmon->device, &temp-
> >temp_crit.attr);
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_del(&temp->hwmon_node);
> -	kfree(temp);
> -	if (!list_empty(&hwmon->tz_list)) {
> -		mutex_unlock(&thermal_list_lock);
> -		return;
> -	}
> -	list_del(&hwmon->node);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	device_remove_file(hwmon->device, &dev_attr_name);
> -	hwmon_device_unregister(hwmon->device);
> -	kfree(hwmon);
> -}
> -#else
> -static int
> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -	return 0;
> -}
> -
> -static void
> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -}
> -#endif
> -
> -/**
> - * thermal_zone_bind_cooling_device - bind a cooling device to a thermal
> zone
> - * @tz:		thermal zone device
> - * @trip:	indicates which trip point the cooling devices is
> - *		associated with in this thermal zone.
> - * @cdev:	thermal cooling device
> - *
> - * This function is usually called in the thermal zone device .bind callback.
> - */
> -int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> -				     int trip,
> -				     struct thermal_cooling_device *cdev,
> -				     unsigned long upper, unsigned long lower)
> -{
> -	struct thermal_instance *dev;
> -	struct thermal_instance *pos;
> -	struct thermal_zone_device *pos1;
> -	struct thermal_cooling_device *pos2;
> -	unsigned long max_state;
> -	int result;
> -
> -	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> -		return -EINVAL;
> -
> -	list_for_each_entry(pos1, &thermal_tz_list, node) {
> -		if (pos1 == tz)
> -			break;
> -	}
> -	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> -		if (pos2 == cdev)
> -			break;
> -	}
> -
> -	if (tz != pos1 || cdev != pos2)
> -		return -EINVAL;
> -
> -	cdev->ops->get_max_state(cdev, &max_state);
> -
> -	/* lower default 0, upper default max_state */
> -	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> -	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> -
> -	if (lower > upper || upper > max_state)
> -		return -EINVAL;
> -
> -	dev =
> -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> -	if (!dev)
> -		return -ENOMEM;
> -	dev->tz = tz;
> -	dev->cdev = cdev;
> -	dev->trip = trip;
> -	dev->upper = upper;
> -	dev->lower = lower;
> -	dev->target = THERMAL_NO_TARGET;
> -
> -	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> -	if (result)
> -		goto free_mem;
> -
> -	sprintf(dev->name, "cdev%d", dev->id);
> -	result =
> -	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev-
> >name);
> -	if (result)
> -		goto release_idr;
> -
> -	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> -	sysfs_attr_init(&dev->attr.attr);
> -	dev->attr.attr.name = dev->attr_name;
> -	dev->attr.attr.mode = 0444;
> -	dev->attr.show = thermal_cooling_device_trip_point_show;
> -	result = device_create_file(&tz->device, &dev->attr);
> -	if (result)
> -		goto remove_symbol_link;
> -
> -	mutex_lock(&tz->lock);
> -	mutex_lock(&cdev->lock);
> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> -		result = -EEXIST;
> -		break;
> -	}
> -	if (!result) {
> -		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> -		list_add_tail(&dev->cdev_node, &cdev-
> >thermal_instances);
> -	}
> -	mutex_unlock(&cdev->lock);
> -	mutex_unlock(&tz->lock);
> -
> -	if (!result)
> -		return 0;
> -
> -	device_remove_file(&tz->device, &dev->attr);
> -remove_symbol_link:
> -	sysfs_remove_link(&tz->device.kobj, dev->name);
> -release_idr:
> -	release_idr(&tz->idr, &tz->lock, dev->id);
> -free_mem:
> -	kfree(dev);
> -	return result;
> -}
> -EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> -
> -/**
> - * thermal_zone_unbind_cooling_device - unbind a cooling device from a
> thermal zone
> - * @tz:		thermal zone device
> - * @trip:	indicates which trip point the cooling devices is
> - *		associated with in this thermal zone.
> - * @cdev:	thermal cooling device
> - *
> - * This function is usually called in the thermal zone device .unbind callback.
> - */
> -int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> -				       int trip,
> -				       struct thermal_cooling_device *cdev)
> -{
> -	struct thermal_instance *pos, *next;
> -
> -	mutex_lock(&tz->lock);
> -	mutex_lock(&cdev->lock);
> -	list_for_each_entry_safe(pos, next, &tz->thermal_instances,
> tz_node) {
> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> -			list_del(&pos->tz_node);
> -			list_del(&pos->cdev_node);
> -			mutex_unlock(&cdev->lock);
> -			mutex_unlock(&tz->lock);
> -			goto unbind;
> -		}
> -	}
> -	mutex_unlock(&cdev->lock);
> -	mutex_unlock(&tz->lock);
> -
> -	return -ENODEV;
> -
> -unbind:
> -	device_remove_file(&tz->device, &pos->attr);
> -	sysfs_remove_link(&tz->device.kobj, pos->name);
> -	release_idr(&tz->idr, &tz->lock, pos->id);
> -	kfree(pos);
> -	return 0;
> -}
> -EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> -
> -static void thermal_release(struct device *dev)
> -{
> -	struct thermal_zone_device *tz;
> -	struct thermal_cooling_device *cdev;
> -
> -	if (!strncmp(dev_name(dev), "thermal_zone",
> -		     sizeof("thermal_zone") - 1)) {
> -		tz = to_thermal_zone(dev);
> -		kfree(tz);
> -	} else {
> -		cdev = to_cooling_device(dev);
> -		kfree(cdev);
> -	}
> -}
> -
> -static struct class thermal_class = {
> -	.name = "thermal",
> -	.dev_release = thermal_release,
> -};
> -
> -/**
> - * thermal_cooling_device_register - register a new thermal cooling device
> - * @type:	the thermal cooling device type.
> - * @devdata:	device private data.
> - * @ops:		standard thermal cooling devices callbacks.
> - */
> -struct thermal_cooling_device *
> -thermal_cooling_device_register(char *type, void *devdata,
> -				const struct thermal_cooling_device_ops
> *ops)
> -{
> -	struct thermal_cooling_device *cdev;
> -	int result;
> -
> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> -	    !ops->set_cur_state)
> -		return ERR_PTR(-EINVAL);
> -
> -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> -	if (!cdev)
> -		return ERR_PTR(-ENOMEM);
> -
> -	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> -	if (result) {
> -		kfree(cdev);
> -		return ERR_PTR(result);
> -	}
> -
> -	strcpy(cdev->type, type ? : "");
> -	mutex_init(&cdev->lock);
> -	INIT_LIST_HEAD(&cdev->thermal_instances);
> -	cdev->ops = ops;
> -	cdev->updated = true;
> -	cdev->device.class = &thermal_class;
> -	cdev->devdata = devdata;
> -	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> -	result = device_register(&cdev->device);
> -	if (result) {
> -		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev-
> >id);
> -		kfree(cdev);
> -		return ERR_PTR(result);
> -	}
> -
> -	/* sys I/F */
> -	if (type) {
> -		result = device_create_file(&cdev->device,
> &dev_attr_cdev_type);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -	result = device_create_file(&cdev->device, &dev_attr_max_state);
> -	if (result)
> -		goto unregister;
> -
> -	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> -	if (result)
> -		goto unregister;
> -
> -	/* Add 'this' new cdev to the global cdev list */
> -	mutex_lock(&thermal_list_lock);
> -	list_add(&cdev->node, &thermal_cdev_list);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	/* Update binding information for 'this' new cdev */
> -	bind_cdev(cdev);
> -
> -	return cdev;
> -
> -unregister:
> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> -	device_unregister(&cdev->device);
> -	return ERR_PTR(result);
> -}
> -EXPORT_SYMBOL(thermal_cooling_device_register);
> -
> -/**
> - * thermal_cooling_device_unregister - removes the registered thermal
> cooling device
> - * @cdev:	the thermal cooling device to remove.
> - *
> - * thermal_cooling_device_unregister() must be called when the device is
> no
> - * longer needed.
> - */
> -void thermal_cooling_device_unregister(struct thermal_cooling_device
> *cdev)
> -{
> -	int i;
> -	const struct thermal_zone_params *tzp;
> -	struct thermal_zone_device *tz;
> -	struct thermal_cooling_device *pos = NULL;
> -
> -	if (!cdev)
> -		return;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(pos, &thermal_cdev_list, node)
> -	    if (pos == cdev)
> -		break;
> -	if (pos != cdev) {
> -		/* thermal cooling device not found */
> -		mutex_unlock(&thermal_list_lock);
> -		return;
> -	}
> -	list_del(&cdev->node);
> -
> -	/* Unbind all thermal zones associated with 'this' cdev */
> -	list_for_each_entry(tz, &thermal_tz_list, node) {
> -		if (tz->ops->unbind) {
> -			tz->ops->unbind(tz, cdev);
> -			continue;
> -		}
> -
> -		if (!tz->tzp || !tz->tzp->tbp)
> -			continue;
> -
> -		tzp = tz->tzp;
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev == cdev) {
> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> -				tzp->tbp[i].cdev = NULL;
> -			}
> -		}
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -
> -	if (cdev->type[0])
> -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> -	device_remove_file(&cdev->device, &dev_attr_max_state);
> -	device_remove_file(&cdev->device, &dev_attr_cur_state);
> -
> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> -	device_unregister(&cdev->device);
> -	return;
> -}
> -EXPORT_SYMBOL(thermal_cooling_device_unregister);
> -
> -void thermal_cdev_update(struct thermal_cooling_device *cdev)
> -{
> -	struct thermal_instance *instance;
> -	unsigned long target = 0;
> -
> -	/* cooling device is updated*/
> -	if (cdev->updated)
> -		return;
> -
> -	mutex_lock(&cdev->lock);
> -	/* Make sure cdev enters the deepest cooling state */
> -	list_for_each_entry(instance, &cdev->thermal_instances,
> cdev_node) {
> -		if (instance->target == THERMAL_NO_TARGET)
> -			continue;
> -		if (instance->target > target)
> -			target = instance->target;
> -	}
> -	mutex_unlock(&cdev->lock);
> -	cdev->ops->set_cur_state(cdev, target);
> -	cdev->updated = true;
> -}
> -EXPORT_SYMBOL(thermal_cdev_update);
> -
> -/**
> - * notify_thermal_framework - Sensor drivers use this API to notify
> framework
> - * @tz:		thermal zone device
> - * @trip:	indicates which trip point has been crossed
> - *
> - * This function handles the trip events from sensor drivers. It starts
> - * throttling the cooling devices according to the policy configured.
> - * For CRITICAL and HOT trip points, this notifies the respective drivers,
> - * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> - * The throttling policy is based on the configured platform data; if no
> - * platform data is provided, this uses the step_wise throttling policy.
> - */
> -void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> -{
> -	handle_thermal_trip(tz, trip);
> -}
> -EXPORT_SYMBOL(notify_thermal_framework);
> -
> -/**
> - * create_trip_attrs - create attributes for trip points
> - * @tz:		the thermal zone device
> - * @mask:	Writeable trip point bitmap.
> - */
> -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> -{
> -	int indx;
> -	int size = sizeof(struct thermal_attr) * tz->trips;
> -
> -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> -	if (!tz->trip_type_attrs)
> -		return -ENOMEM;
> -
> -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> -	if (!tz->trip_temp_attrs) {
> -		kfree(tz->trip_type_attrs);
> -		return -ENOMEM;
> -	}
> -
> -	if (tz->ops->get_trip_hyst) {
> -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> -		if (!tz->trip_hyst_attrs) {
> -			kfree(tz->trip_type_attrs);
> -			kfree(tz->trip_temp_attrs);
> -			return -ENOMEM;
> -		}
> -	}
> -
> -
> -	for (indx = 0; indx < tz->trips; indx++) {
> -		/* create trip type attribute */
> -		snprintf(tz->trip_type_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> -			 "trip_point_%d_type", indx);
> -
> -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> -		tz->trip_type_attrs[indx].attr.attr.name =
> -						tz-
> >trip_type_attrs[indx].name;
> -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> -
> -		device_create_file(&tz->device,
> -				   &tz->trip_type_attrs[indx].attr);
> -
> -		/* create trip temp attribute */
> -		snprintf(tz->trip_temp_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> -			 "trip_point_%d_temp", indx);
> -
> -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> -		tz->trip_temp_attrs[indx].attr.attr.name =
> -						tz-
> >trip_temp_attrs[indx].name;
> -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> -		tz->trip_temp_attrs[indx].attr.show =
> trip_point_temp_show;
> -		if (mask & (1 << indx)) {
> -			tz->trip_temp_attrs[indx].attr.attr.mode |=
> S_IWUSR;
> -			tz->trip_temp_attrs[indx].attr.store =
> -
> 	trip_point_temp_store;
> -		}
> -
> -		device_create_file(&tz->device,
> -				   &tz->trip_temp_attrs[indx].attr);
> -
> -		/* create Optional trip hyst attribute */
> -		if (!tz->ops->get_trip_hyst)
> -			continue;
> -		snprintf(tz->trip_hyst_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> -			 "trip_point_%d_hyst", indx);
> -
> -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> -		tz->trip_hyst_attrs[indx].attr.attr.name =
> -					tz->trip_hyst_attrs[indx].name;
> -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> -		if (tz->ops->set_trip_hyst) {
> -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> -			tz->trip_hyst_attrs[indx].attr.store =
> -					trip_point_hyst_store;
> -		}
> -
> -		device_create_file(&tz->device,
> -				   &tz->trip_hyst_attrs[indx].attr);
> -	}
> -	return 0;
> -}
> -
> -static void remove_trip_attrs(struct thermal_zone_device *tz)
> -{
> -	int indx;
> -
> -	for (indx = 0; indx < tz->trips; indx++) {
> -		device_remove_file(&tz->device,
> -				   &tz->trip_type_attrs[indx].attr);
> -		device_remove_file(&tz->device,
> -				   &tz->trip_temp_attrs[indx].attr);
> -		if (tz->ops->get_trip_hyst)
> -			device_remove_file(&tz->device,
> -				  &tz->trip_hyst_attrs[indx].attr);
> -	}
> -	kfree(tz->trip_type_attrs);
> -	kfree(tz->trip_temp_attrs);
> -	kfree(tz->trip_hyst_attrs);
> -}
> -
> -/**
> - * thermal_zone_device_register - register a new thermal zone device
> - * @type:	the thermal zone device type
> - * @trips:	the number of trip points the thermal zone support
> - * @mask:	a bit string indicating the writeablility of trip points
> - * @devdata:	private device data
> - * @ops:	standard thermal zone device callbacks
> - * @tzp:	thermal zone platform parameters
> - * @passive_delay: number of milliseconds to wait between polls when
> - *		   performing passive cooling
> - * @polling_delay: number of milliseconds to wait between polls when
> checking
> - *		   whether trip points have been crossed (0 for interrupt
> - *		   driven systems)
> - *
> - * thermal_zone_device_unregister() must be called when the device is no
> - * longer needed. The passive cooling depends on the .get_trend() return
> value.
> - */
> -struct thermal_zone_device *thermal_zone_device_register(const char
> *type,
> -	int trips, int mask, void *devdata,
> -	const struct thermal_zone_device_ops *ops,
> -	const struct thermal_zone_params *tzp,
> -	int passive_delay, int polling_delay)
> -{
> -	struct thermal_zone_device *tz;
> -	enum thermal_trip_type trip_type;
> -	int result;
> -	int count;
> -	int passive = 0;
> -
> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (!ops || !ops->get_temp)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (trips > 0 && !ops->get_trip_type)
> -		return ERR_PTR(-EINVAL);
> -
> -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> -	if (!tz)
> -		return ERR_PTR(-ENOMEM);
> -
> -	INIT_LIST_HEAD(&tz->thermal_instances);
> -	idr_init(&tz->idr);
> -	mutex_init(&tz->lock);
> -	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> -	if (result) {
> -		kfree(tz);
> -		return ERR_PTR(result);
> -	}
> -
> -	strcpy(tz->type, type ? : "");
> -	tz->ops = ops;
> -	tz->tzp = tzp;
> -	tz->device.class = &thermal_class;
> -	tz->devdata = devdata;
> -	tz->trips = trips;
> -	tz->passive_delay = passive_delay;
> -	tz->polling_delay = polling_delay;
> -
> -	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> -	result = device_register(&tz->device);
> -	if (result) {
> -		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> -		kfree(tz);
> -		return ERR_PTR(result);
> -	}
> -
> -	/* sys I/F */
> -	if (type) {
> -		result = device_create_file(&tz->device, &dev_attr_type);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -	result = device_create_file(&tz->device, &dev_attr_temp);
> -	if (result)
> -		goto unregister;
> -
> -	if (ops->get_mode) {
> -		result = device_create_file(&tz->device, &dev_attr_mode);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -	result = create_trip_attrs(tz, mask);
> -	if (result)
> -		goto unregister;
> -
> -	for (count = 0; count < trips; count++) {
> -		tz->ops->get_trip_type(tz, count, &trip_type);
> -		if (trip_type == THERMAL_TRIP_PASSIVE)
> -			passive = 1;
> -	}
> -
> -	if (!passive) {
> -		result = device_create_file(&tz->device, &dev_attr_passive);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -#ifdef CONFIG_THERMAL_EMULATION
> -	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> -	if (result)
> -		goto unregister;
> -#endif
> -	/* Create policy attribute */
> -	result = device_create_file(&tz->device, &dev_attr_policy);
> -	if (result)
> -		goto unregister;
> -
> -	/* Update 'this' zone's governor information */
> -	mutex_lock(&thermal_governor_lock);
> -
> -	if (tz->tzp)
> -		tz->governor = __find_governor(tz->tzp->governor_name);
> -	else
> -		tz->governor =
> __find_governor(DEFAULT_THERMAL_GOVERNOR);
> -
> -	mutex_unlock(&thermal_governor_lock);
> -
> -	result = thermal_add_hwmon_sysfs(tz);
> -	if (result)
> -		goto unregister;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_add_tail(&tz->node, &thermal_tz_list);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	/* Bind cooling devices for this zone */
> -	bind_tz(tz);
> -
> -	INIT_DELAYED_WORK(&(tz->poll_queue),
> thermal_zone_device_check);
> -
> -	thermal_zone_device_update(tz);
> -
> -	if (!result)
> -		return tz;
> -
> -unregister:
> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> -	device_unregister(&tz->device);
> -	return ERR_PTR(result);
> -}
> -EXPORT_SYMBOL(thermal_zone_device_register);
> -
> -/**
> - * thermal_device_unregister - removes the registered thermal zone device
> - * @tz: the thermal zone device to remove
> - */
> -void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> -{
> -	int i;
> -	const struct thermal_zone_params *tzp;
> -	struct thermal_cooling_device *cdev;
> -	struct thermal_zone_device *pos = NULL;
> -
> -	if (!tz)
> -		return;
> -
> -	tzp = tz->tzp;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(pos, &thermal_tz_list, node)
> -	    if (pos == tz)
> -		break;
> -	if (pos != tz) {
> -		/* thermal zone device not found */
> -		mutex_unlock(&thermal_list_lock);
> -		return;
> -	}
> -	list_del(&tz->node);
> -
> -	/* Unbind all cdevs associated with 'this' thermal zone */
> -	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> -		if (tz->ops->unbind) {
> -			tz->ops->unbind(tz, cdev);
> -			continue;
> -		}
> -
> -		if (!tzp || !tzp->tbp)
> -			break;
> -
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev == cdev) {
> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> -				tzp->tbp[i].cdev = NULL;
> -			}
> -		}
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -
> -	thermal_zone_device_set_polling(tz, 0);
> -
> -	if (tz->type[0])
> -		device_remove_file(&tz->device, &dev_attr_type);
> -	device_remove_file(&tz->device, &dev_attr_temp);
> -	if (tz->ops->get_mode)
> -		device_remove_file(&tz->device, &dev_attr_mode);
> -	device_remove_file(&tz->device, &dev_attr_policy);
> -	remove_trip_attrs(tz);
> -	tz->governor = NULL;
> -
> -	thermal_remove_hwmon_sysfs(tz);
> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> -	idr_destroy(&tz->idr);
> -	mutex_destroy(&tz->lock);
> -	device_unregister(&tz->device);
> -	return;
> -}
> -EXPORT_SYMBOL(thermal_zone_device_unregister);
> -
> -#ifdef CONFIG_NET
> -static struct genl_family thermal_event_genl_family = {
> -	.id = GENL_ID_GENERATE,
> -	.name = THERMAL_GENL_FAMILY_NAME,
> -	.version = THERMAL_GENL_VERSION,
> -	.maxattr = THERMAL_GENL_ATTR_MAX,
> -};
> -
> -static struct genl_multicast_group thermal_event_mcgrp = {
> -	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> -};
> -
> -int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> -					enum events event)
> -{
> -	struct sk_buff *skb;
> -	struct nlattr *attr;
> -	struct thermal_genl_event *thermal_event;
> -	void *msg_header;
> -	int size;
> -	int result;
> -	static unsigned int thermal_event_seqnum;
> -
> -	if (!tz)
> -		return -EINVAL;
> -
> -	/* allocate memory */
> -	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> -	       nla_total_size(0);
> -
> -	skb = genlmsg_new(size, GFP_ATOMIC);
> -	if (!skb)
> -		return -ENOMEM;
> -
> -	/* add the genetlink message header */
> -	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> -				 &thermal_event_genl_family, 0,
> -				 THERMAL_GENL_CMD_EVENT);
> -	if (!msg_header) {
> -		nlmsg_free(skb);
> -		return -ENOMEM;
> -	}
> -
> -	/* fill the data */
> -	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> -			   sizeof(struct thermal_genl_event));
> -
> -	if (!attr) {
> -		nlmsg_free(skb);
> -		return -EINVAL;
> -	}
> -
> -	thermal_event = nla_data(attr);
> -	if (!thermal_event) {
> -		nlmsg_free(skb);
> -		return -EINVAL;
> -	}
> -
> -	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> -
> -	thermal_event->orig = tz->id;
> -	thermal_event->event = event;
> -
> -	/* send multicast genetlink message */
> -	result = genlmsg_end(skb, msg_header);
> -	if (result < 0) {
> -		nlmsg_free(skb);
> -		return result;
> -	}
> -
> -	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id,
> GFP_ATOMIC);
> -	if (result)
> -		dev_err(&tz->device, "Failed to send netlink event:%d",
> result);
> -
> -	return result;
> -}
> -EXPORT_SYMBOL(thermal_generate_netlink_event);
> -
> -static int genetlink_init(void)
> -{
> -	int result;
> -
> -	result = genl_register_family(&thermal_event_genl_family);
> -	if (result)
> -		return result;
> -
> -	result = genl_register_mc_group(&thermal_event_genl_family,
> -					&thermal_event_mcgrp);
> -	if (result)
> -		genl_unregister_family(&thermal_event_genl_family);
> -	return result;
> -}
> -
> -static void genetlink_exit(void)
> -{
> -	genl_unregister_family(&thermal_event_genl_family);
> -}
> -#else /* !CONFIG_NET */
> -static inline int genetlink_init(void) { return 0; }
> -static inline void genetlink_exit(void) {}
> -#endif /* !CONFIG_NET */
> -
> -static int __init thermal_init(void)
> -{
> -	int result = 0;
> -
> -	result = class_register(&thermal_class);
> -	if (result) {
> -		idr_destroy(&thermal_tz_idr);
> -		idr_destroy(&thermal_cdev_idr);
> -		mutex_destroy(&thermal_idr_lock);
> -		mutex_destroy(&thermal_list_lock);
> -		return result;
> -	}
> -	result = genetlink_init();
> -	return result;
> -}
> -
> -static void __exit thermal_exit(void)
> -{
> -	class_unregister(&thermal_class);
> -	idr_destroy(&thermal_tz_idr);
> -	idr_destroy(&thermal_cdev_idr);
> -	mutex_destroy(&thermal_idr_lock);
> -	mutex_destroy(&thermal_list_lock);
> -	genetlink_exit();
> -}
> -
> -fs_initcall(thermal_init);
> -module_exit(thermal_exit);
> --
> 1.7.9.5


^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c
  2013-03-26 16:56   ` R, Durgadoss
@ 2013-03-26 17:08     ` Zhang Rui
  0 siblings, 0 replies; 23+ messages in thread
From: Zhang Rui @ 2013-03-26 17:08 UTC (permalink / raw)
  To: R, Durgadoss; +Cc: linux-pm, linux-kernel, amit.daniel, andi

On Tue, 2013-03-26 at 10:56 -0600, R, Durgadoss wrote:
> > -----Original Message-----
> > From: Zhang, Rui
> > Sent: Tuesday, March 26, 2013 9:56 PM
> > To: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org
> > Cc: amit.daniel@samsung.com; R, Durgadoss; andi@lisas.de; Zhang, Rui
> > Subject: [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c
> > 
> > No functional change in this patch.
> > 
> > Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> > ---
> >  drivers/thermal/Makefile       |    1 +
> >  drivers/thermal/thermal_core.c | 1888
> > ++++++++++++++++++++++++++++++++++++++++
> >  drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------
> >  3 files changed, 1889 insertions(+), 1888 deletions(-)
> >  create mode 100644 drivers/thermal/thermal_core.c
> >  delete mode 100644 drivers/thermal/thermal_sys.c
> > 
> > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> > index d3a2b38..b2009bd 100644
> > --- a/drivers/thermal/Makefile
> > +++ b/drivers/thermal/Makefile
> > @@ -3,6 +3,7 @@
> >  #
> > 
> >  obj-$(CONFIG_THERMAL)		+= thermal_sys.o
> 
> Should we keep the _sys suffix ?
> Can we just rename it to thermal.o ?
> 
thermal.ko already exists, aka, drivers/acpi/thermal.c.

thanks,
rui
> > +thermal_sys-y			+= thermal_core.o
> > 
> >  # governors
> >  obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> > diff --git a/drivers/thermal/thermal_core.c
> > b/drivers/thermal/thermal_core.c
> > new file mode 100644
> > index 0000000..5b7863a
> > --- /dev/null
> > +++ b/drivers/thermal/thermal_core.c
> > @@ -0,0 +1,1888 @@
> > +/*
> > + *  thermal.c - Generic Thermal Management Sysfs support.
> > + *
> > + *  Copyright (C) 2008 Intel Corp
> > + *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> > + *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> > + *
> > + *
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > ~~~~~~~~~~~~~~~~
> > + *
> > + *  This program is free software; you can redistribute it and/or modify
> > + *  it under the terms of the GNU General Public License as published by
> > + *  the Free Software Foundation; version 2 of the License.
> > + *
> > + *  This program is distributed in the hope that it will be useful, but
> > + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> > + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > GNU
> > + *  General Public License for more details.
> > + *
> > + *  You should have received a copy of the GNU General Public License
> > along
> > + *  with this program; if not, write to the Free Software Foundation, Inc.,
> > + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> > + *
> > + *
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > ~~~~~~~~~~~~~~~~
> > + */
> > +
> > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > +
> > +#include <linux/module.h>
> > +#include <linux/device.h>
> > +#include <linux/err.h>
> > +#include <linux/slab.h>
> > +#include <linux/kdev_t.h>
> > +#include <linux/idr.h>
> > +#include <linux/thermal.h>
> > +#include <linux/reboot.h>
> > +#include <net/netlink.h>
> > +#include <net/genetlink.h>
> > +
> > +#include "thermal_core.h"
> > +
> > +MODULE_AUTHOR("Zhang Rui");
> > +MODULE_DESCRIPTION("Generic thermal management sysfs support");
> > +MODULE_LICENSE("GPL");
> > +
> > +static DEFINE_IDR(thermal_tz_idr);
> > +static DEFINE_IDR(thermal_cdev_idr);
> > +static DEFINE_MUTEX(thermal_idr_lock);
> > +
> > +static LIST_HEAD(thermal_tz_list);
> > +static LIST_HEAD(thermal_cdev_list);
> > +static LIST_HEAD(thermal_governor_list);
> > +
> > +static DEFINE_MUTEX(thermal_list_lock);
> > +static DEFINE_MUTEX(thermal_governor_lock);
> > +
> > +static struct thermal_governor *__find_governor(const char *name)
> > +{
> > +	struct thermal_governor *pos;
> > +
> > +	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> > +		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> > +			return pos;
> > +
> > +	return NULL;
> > +}
> > +
> > +int thermal_register_governor(struct thermal_governor *governor)
> > +{
> > +	int err;
> > +	const char *name;
> > +	struct thermal_zone_device *pos;
> > +
> > +	if (!governor)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&thermal_governor_lock);
> > +
> > +	err = -EBUSY;
> > +	if (__find_governor(governor->name) == NULL) {
> > +		err = 0;
> > +		list_add(&governor->governor_list,
> > &thermal_governor_list);
> > +	}
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +
> > +	list_for_each_entry(pos, &thermal_tz_list, node) {
> > +		if (pos->governor)
> > +			continue;
> > +		if (pos->tzp)
> > +			name = pos->tzp->governor_name;
> > +		else
> > +			name = DEFAULT_THERMAL_GOVERNOR;
> > +		if (!strnicmp(name, governor->name,
> > THERMAL_NAME_LENGTH))
> > +			pos->governor = governor;
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +	mutex_unlock(&thermal_governor_lock);
> > +
> > +	return err;
> > +}
> > +EXPORT_SYMBOL_GPL(thermal_register_governor);
> > +
> > +void thermal_unregister_governor(struct thermal_governor *governor)
> > +{
> > +	struct thermal_zone_device *pos;
> > +
> > +	if (!governor)
> > +		return;
> > +
> > +	mutex_lock(&thermal_governor_lock);
> > +
> > +	if (__find_governor(governor->name) == NULL)
> > +		goto exit;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +
> > +	list_for_each_entry(pos, &thermal_tz_list, node) {
> > +		if (!strnicmp(pos->governor->name, governor->name,
> > +						THERMAL_NAME_LENGTH))
> > +			pos->governor = NULL;
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +	list_del(&governor->governor_list);
> > +exit:
> > +	mutex_unlock(&thermal_governor_lock);
> > +	return;
> > +}
> > +EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> > +
> > +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> > +{
> > +	int ret;
> > +
> > +	if (lock)
> > +		mutex_lock(lock);
> > +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> > +	if (lock)
> > +		mutex_unlock(lock);
> > +	if (unlikely(ret < 0))
> > +		return ret;
> > +	*id = ret;
> > +	return 0;
> > +}
> > +
> > +static void release_idr(struct idr *idr, struct mutex *lock, int id)
> > +{
> > +	if (lock)
> > +		mutex_lock(lock);
> > +	idr_remove(idr, id);
> > +	if (lock)
> > +		mutex_unlock(lock);
> > +}
> > +
> > +int get_tz_trend(struct thermal_zone_device *tz, int trip)
> > +{
> > +	enum thermal_trend trend;
> > +
> > +	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> > +		if (tz->temperature > tz->last_temperature)
> > +			trend = THERMAL_TREND_RAISING;
> > +		else if (tz->temperature < tz->last_temperature)
> > +			trend = THERMAL_TREND_DROPPING;
> > +		else
> > +			trend = THERMAL_TREND_STABLE;
> > +	}
> > +
> > +	return trend;
> > +}
> > +EXPORT_SYMBOL(get_tz_trend);
> > +
> > +struct thermal_instance *get_thermal_instance(struct
> > thermal_zone_device *tz,
> > +			struct thermal_cooling_device *cdev, int trip)
> > +{
> > +	struct thermal_instance *pos = NULL;
> > +	struct thermal_instance *target_instance = NULL;
> > +
> > +	mutex_lock(&tz->lock);
> > +	mutex_lock(&cdev->lock);
> > +
> > +	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> > +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > +			target_instance = pos;
> > +			break;
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&cdev->lock);
> > +	mutex_unlock(&tz->lock);
> > +
> > +	return target_instance;
> > +}
> > +EXPORT_SYMBOL(get_thermal_instance);
> > +
> > +static void print_bind_err_msg(struct thermal_zone_device *tz,
> > +			struct thermal_cooling_device *cdev, int ret)
> > +{
> > +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> > +				tz->type, cdev->type, ret);
> > +}
> > +
> > +static void __bind(struct thermal_zone_device *tz, int mask,
> > +			struct thermal_cooling_device *cdev)
> > +{
> > +	int i, ret;
> > +
> > +	for (i = 0; i < tz->trips; i++) {
> > +		if (mask & (1 << i)) {
> > +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> > +					THERMAL_NO_LIMIT,
> > THERMAL_NO_LIMIT);
> > +			if (ret)
> > +				print_bind_err_msg(tz, cdev, ret);
> > +		}
> > +	}
> > +}
> > +
> > +static void __unbind(struct thermal_zone_device *tz, int mask,
> > +			struct thermal_cooling_device *cdev)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < tz->trips; i++)
> > +		if (mask & (1 << i))
> > +			thermal_zone_unbind_cooling_device(tz, i, cdev);
> > +}
> > +
> > +static void bind_cdev(struct thermal_cooling_device *cdev)
> > +{
> > +	int i, ret;
> > +	const struct thermal_zone_params *tzp;
> > +	struct thermal_zone_device *pos = NULL;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +
> > +	list_for_each_entry(pos, &thermal_tz_list, node) {
> > +		if (!pos->tzp && !pos->ops->bind)
> > +			continue;
> > +
> > +		if (!pos->tzp && pos->ops->bind) {
> > +			ret = pos->ops->bind(pos, cdev);
> > +			if (ret)
> > +				print_bind_err_msg(pos, cdev, ret);
> > +		}
> > +
> > +		tzp = pos->tzp;
> > +		if (!tzp || !tzp->tbp)
> > +			continue;
> > +
> > +		for (i = 0; i < tzp->num_tbps; i++) {
> > +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> > +				continue;
> > +			if (tzp->tbp[i].match(pos, cdev))
> > +				continue;
> > +			tzp->tbp[i].cdev = cdev;
> > +			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +}
> > +
> > +static void bind_tz(struct thermal_zone_device *tz)
> > +{
> > +	int i, ret;
> > +	struct thermal_cooling_device *pos = NULL;
> > +	const struct thermal_zone_params *tzp = tz->tzp;
> > +
> > +	if (!tzp && !tz->ops->bind)
> > +		return;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +
> > +	/* If there is no platform data, try to use ops->bind */
> > +	if (!tzp && tz->ops->bind) {
> > +		list_for_each_entry(pos, &thermal_cdev_list, node) {
> > +			ret = tz->ops->bind(tz, pos);
> > +			if (ret)
> > +				print_bind_err_msg(tz, pos, ret);
> > +		}
> > +		goto exit;
> > +	}
> > +
> > +	if (!tzp || !tzp->tbp)
> > +		goto exit;
> > +
> > +	list_for_each_entry(pos, &thermal_cdev_list, node) {
> > +		for (i = 0; i < tzp->num_tbps; i++) {
> > +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> > +				continue;
> > +			if (tzp->tbp[i].match(tz, pos))
> > +				continue;
> > +			tzp->tbp[i].cdev = pos;
> > +			__bind(tz, tzp->tbp[i].trip_mask, pos);
> > +		}
> > +	}
> > +exit:
> > +	mutex_unlock(&thermal_list_lock);
> > +}
> > +
> > +static void thermal_zone_device_set_polling(struct thermal_zone_device
> > *tz,
> > +					    int delay)
> > +{
> > +	if (delay > 1000)
> > +		mod_delayed_work(system_freezable_wq, &tz-
> > >poll_queue,
> > +				 round_jiffies(msecs_to_jiffies(delay)));
> > +	else if (delay)
> > +		mod_delayed_work(system_freezable_wq, &tz-
> > >poll_queue,
> > +				 msecs_to_jiffies(delay));
> > +	else
> > +		cancel_delayed_work(&tz->poll_queue);
> > +}
> > +
> > +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);
> > +	else if (tz->polling_delay)
> > +		thermal_zone_device_set_polling(tz, tz->polling_delay);
> > +	else
> > +		thermal_zone_device_set_polling(tz, 0);
> > +
> > +	mutex_unlock(&tz->lock);
> > +}
> > +
> > +static void handle_non_critical_trips(struct thermal_zone_device *tz,
> > +			int trip, enum thermal_trip_type trip_type)
> > +{
> > +	if (tz->governor)
> > +		tz->governor->throttle(tz, trip);
> > +}
> > +
> > +static void handle_critical_trips(struct thermal_zone_device *tz,
> > +				int trip, enum thermal_trip_type trip_type)
> > +{
> > +	long trip_temp;
> > +
> > +	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> > +
> > +	/* If we have not crossed the trip_temp, we do not care. */
> > +	if (tz->temperature < trip_temp)
> > +		return;
> > +
> > +	if (tz->ops->notify)
> > +		tz->ops->notify(tz, trip, trip_type);
> > +
> > +	if (trip_type == THERMAL_TRIP_CRITICAL) {
> > +		dev_emerg(&tz->device,
> > +			  "critical temperature reached(%d C),shutting
> > down\n",
> > +			  tz->temperature / 1000);
> > +		orderly_poweroff(true);
> > +	}
> > +}
> > +
> > +static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> > +{
> > +	enum thermal_trip_type type;
> > +
> > +	tz->ops->get_trip_type(tz, trip, &type);
> > +
> > +	if (type == THERMAL_TRIP_CRITICAL || type ==
> > THERMAL_TRIP_HOT)
> > +		handle_critical_trips(tz, trip, type);
> > +	else
> > +		handle_non_critical_trips(tz, trip, type);
> > +	/*
> > +	 * Alright, we handled this trip successfully.
> > +	 * So, start monitoring again.
> > +	 */
> > +	monitor_thermal_zone(tz);
> > +}
> > +
> > +static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> > +				unsigned long *temp)
> > +{
> > +	int ret = 0;
> > +#ifdef CONFIG_THERMAL_EMULATION
> > +	int count;
> > +	unsigned long crit_temp = -1UL;
> > +	enum thermal_trip_type type;
> > +#endif
> > +
> > +	mutex_lock(&tz->lock);
> > +
> > +	ret = tz->ops->get_temp(tz, temp);
> > +#ifdef CONFIG_THERMAL_EMULATION
> > +	if (!tz->emul_temperature)
> > +		goto skip_emul;
> > +
> > +	for (count = 0; count < tz->trips; count++) {
> > +		ret = tz->ops->get_trip_type(tz, count, &type);
> > +		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> > +			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> > +			break;
> > +		}
> > +	}
> > +
> > +	if (ret)
> > +		goto skip_emul;
> > +
> > +	if (*temp < crit_temp)
> > +		*temp = tz->emul_temperature;
> > +skip_emul:
> > +#endif
> > +	mutex_unlock(&tz->lock);
> > +	return ret;
> > +}
> > +
> > +static void update_temperature(struct thermal_zone_device *tz)
> > +{
> > +	long temp;
> > +	int ret;
> > +
> > +	ret = thermal_zone_get_temp(tz, &temp);
> > +	if (ret) {
> > +		dev_warn(&tz->device, "failed to read out thermal zone
> > %d\n",
> > +			 tz->id);
> > +		return;
> > +	}
> > +
> > +	mutex_lock(&tz->lock);
> > +	tz->last_temperature = tz->temperature;
> > +	tz->temperature = temp;
> > +	mutex_unlock(&tz->lock);
> > +}
> > +
> > +void thermal_zone_device_update(struct thermal_zone_device *tz)
> > +{
> > +	int count;
> > +
> > +	update_temperature(tz);
> > +
> > +	for (count = 0; count < tz->trips; count++)
> > +		handle_thermal_trip(tz, count);
> > +}
> > +EXPORT_SYMBOL(thermal_zone_device_update);
> > +
> > +static void thermal_zone_device_check(struct work_struct *work)
> > +{
> > +	struct thermal_zone_device *tz = container_of(work, struct
> > +						      thermal_zone_device,
> > +						      poll_queue.work);
> > +	thermal_zone_device_update(tz);
> > +}
> > +
> > +/* sys I/F for thermal zone */
> > +
> > +#define to_thermal_zone(_dev) \
> > +	container_of(_dev, struct thermal_zone_device, device)
> > +
> > +static ssize_t
> > +type_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +
> > +	return sprintf(buf, "%s\n", tz->type);
> > +}
> > +
> > +static ssize_t
> > +temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	long temperature;
> > +	int ret;
> > +
> > +	ret = thermal_zone_get_temp(tz, &temperature);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +static ssize_t
> > +mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	enum thermal_device_mode mode;
> > +	int result;
> > +
> > +	if (!tz->ops->get_mode)
> > +		return -EPERM;
> > +
> > +	result = tz->ops->get_mode(tz, &mode);
> > +	if (result)
> > +		return result;
> > +
> > +	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ?
> > "enabled"
> > +		       : "disabled");
> > +}
> > +
> > +static ssize_t
> > +mode_store(struct device *dev, struct device_attribute *attr,
> > +	   const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int result;
> > +
> > +	if (!tz->ops->set_mode)
> > +		return -EPERM;
> > +
> > +	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);
> > +	else
> > +		result = -EINVAL;
> > +
> > +	if (result)
> > +		return result;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t
> > +trip_point_type_show(struct device *dev, struct device_attribute *attr,
> > +		     char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	enum thermal_trip_type type;
> > +	int trip, result;
> > +
> > +	if (!tz->ops->get_trip_type)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> > +		return -EINVAL;
> > +
> > +	result = tz->ops->get_trip_type(tz, trip, &type);
> > +	if (result)
> > +		return result;
> > +
> > +	switch (type) {
> > +	case THERMAL_TRIP_CRITICAL:
> > +		return sprintf(buf, "critical\n");
> > +	case THERMAL_TRIP_HOT:
> > +		return sprintf(buf, "hot\n");
> > +	case THERMAL_TRIP_PASSIVE:
> > +		return sprintf(buf, "passive\n");
> > +	case THERMAL_TRIP_ACTIVE:
> > +		return sprintf(buf, "active\n");
> > +	default:
> > +		return sprintf(buf, "unknown\n");
> > +	}
> > +}
> > +
> > +static ssize_t
> > +trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> > +		     const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int trip, ret;
> > +	unsigned long temperature;
> > +
> > +	if (!tz->ops->set_trip_temp)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> > +		return -EINVAL;
> > +
> > +	if (kstrtoul(buf, 10, &temperature))
> > +		return -EINVAL;
> > +
> > +	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> > +
> > +	return ret ? ret : count;
> > +}
> > +
> > +static ssize_t
> > +trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> > +		     char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int trip, ret;
> > +	long temperature;
> > +
> > +	if (!tz->ops->get_trip_temp)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> > +		return -EINVAL;
> > +
> > +	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +static ssize_t
> > +trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> > +			const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int trip, ret;
> > +	unsigned long temperature;
> > +
> > +	if (!tz->ops->set_trip_hyst)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> > +		return -EINVAL;
> > +
> > +	if (kstrtoul(buf, 10, &temperature))
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * We are not doing any check on the 'temperature' value
> > +	 * here. The driver implementing 'set_trip_hyst' has to
> > +	 * take care of this.
> > +	 */
> > +	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> > +
> > +	return ret ? ret : count;
> > +}
> > +
> > +static ssize_t
> > +trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> > +			char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int trip, ret;
> > +	unsigned long temperature;
> > +
> > +	if (!tz->ops->get_trip_hyst)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> > +		return -EINVAL;
> > +
> > +	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> > +
> > +	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +static ssize_t
> > +passive_store(struct device *dev, struct device_attribute *attr,
> > +		    const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	struct thermal_cooling_device *cdev = NULL;
> > +	int state;
> > +
> > +	if (!sscanf(buf, "%d\n", &state))
> > +		return -EINVAL;
> > +
> > +	/* sanity check: values below 1000 millicelcius don't make sense
> > +	 * and can cause the system to go into a thermal heart attack
> > +	 */
> > +	if (state && state < 1000)
> > +		return -EINVAL;
> > +
> > +	if (state && !tz->forced_passive) {
> > +		mutex_lock(&thermal_list_lock);
> > +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > +			if (!strncmp("Processor", cdev->type,
> > +				     sizeof("Processor")))
> > +				thermal_zone_bind_cooling_device(tz,
> > +						THERMAL_TRIPS_NONE,
> > cdev,
> > +						THERMAL_NO_LIMIT,
> > +						THERMAL_NO_LIMIT);
> > +		}
> > +		mutex_unlock(&thermal_list_lock);
> > +		if (!tz->passive_delay)
> > +			tz->passive_delay = 1000;
> > +	} else if (!state && tz->forced_passive) {
> > +		mutex_lock(&thermal_list_lock);
> > +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > +			if (!strncmp("Processor", cdev->type,
> > +				     sizeof("Processor")))
> > +				thermal_zone_unbind_cooling_device(tz,
> > +
> > THERMAL_TRIPS_NONE,
> > +								   cdev);
> > +		}
> > +		mutex_unlock(&thermal_list_lock);
> > +		tz->passive_delay = 0;
> > +	}
> > +
> > +	tz->forced_passive = state;
> > +
> > +	thermal_zone_device_update(tz);
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t
> > +passive_show(struct device *dev, struct device_attribute *attr,
> > +		   char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +
> > +	return sprintf(buf, "%d\n", tz->forced_passive);
> > +}
> > +
> > +static ssize_t
> > +policy_store(struct device *dev, struct device_attribute *attr,
> > +		    const char *buf, size_t count)
> > +{
> > +	int ret = -EINVAL;
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	struct thermal_governor *gov;
> > +
> > +	mutex_lock(&thermal_governor_lock);
> > +
> > +	gov = __find_governor(buf);
> > +	if (!gov)
> > +		goto exit;
> > +
> > +	tz->governor = gov;
> > +	ret = count;
> > +
> > +exit:
> > +	mutex_unlock(&thermal_governor_lock);
> > +	return ret;
> > +}
> > +
> > +static ssize_t
> > +policy_show(struct device *dev, struct device_attribute *devattr, char
> > *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +
> > +	return sprintf(buf, "%s\n", tz->governor->name);
> > +}
> > +
> > +#ifdef CONFIG_THERMAL_EMULATION
> > +static ssize_t
> > +emul_temp_store(struct device *dev, struct device_attribute *attr,
> > +		     const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int ret = 0;
> > +	unsigned long temperature;
> > +
> > +	if (kstrtoul(buf, 10, &temperature))
> > +		return -EINVAL;
> > +
> > +	if (!tz->ops->set_emul_temp) {
> > +		mutex_lock(&tz->lock);
> > +		tz->emul_temperature = temperature;
> > +		mutex_unlock(&tz->lock);
> > +	} else {
> > +		ret = tz->ops->set_emul_temp(tz, temperature);
> > +	}
> > +
> > +	return ret ? ret : count;
> > +}
> > +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> > +#endif/*CONFIG_THERMAL_EMULATION*/
> > +
> > +static DEVICE_ATTR(type, 0444, type_show, NULL);
> > +static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> > +static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> > +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show,
> > passive_store);
> > +static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show,
> > policy_store);
> > +
> > +/* sys I/F for cooling device */
> > +#define to_cooling_device(_dev)	\
> > +	container_of(_dev, struct thermal_cooling_device, device)
> > +
> > +static ssize_t
> > +thermal_cooling_device_type_show(struct device *dev,
> > +				 struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > +
> > +	return sprintf(buf, "%s\n", cdev->type);
> > +}
> > +
> > +static ssize_t
> > +thermal_cooling_device_max_state_show(struct device *dev,
> > +				      struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > +	unsigned long state;
> > +	int ret;
> > +
> > +	ret = cdev->ops->get_max_state(cdev, &state);
> > +	if (ret)
> > +		return ret;
> > +	return sprintf(buf, "%ld\n", state);
> > +}
> > +
> > +static ssize_t
> > +thermal_cooling_device_cur_state_show(struct device *dev,
> > +				      struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > +	unsigned long state;
> > +	int ret;
> > +
> > +	ret = cdev->ops->get_cur_state(cdev, &state);
> > +	if (ret)
> > +		return ret;
> > +	return sprintf(buf, "%ld\n", state);
> > +}
> > +
> > +static ssize_t
> > +thermal_cooling_device_cur_state_store(struct device *dev,
> > +				       struct device_attribute *attr,
> > +				       const char *buf, size_t count)
> > +{
> > +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > +	unsigned long state;
> > +	int result;
> > +
> > +	if (!sscanf(buf, "%ld\n", &state))
> > +		return -EINVAL;
> > +
> > +	if ((long)state < 0)
> > +		return -EINVAL;
> > +
> > +	result = cdev->ops->set_cur_state(cdev, state);
> > +	if (result)
> > +		return result;
> > +	return count;
> > +}
> > +
> > +static struct device_attribute dev_attr_cdev_type =
> > +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> > +static DEVICE_ATTR(max_state, 0444,
> > +		   thermal_cooling_device_max_state_show, NULL);
> > +static DEVICE_ATTR(cur_state, 0644,
> > +		   thermal_cooling_device_cur_state_show,
> > +		   thermal_cooling_device_cur_state_store);
> > +
> > +static ssize_t
> > +thermal_cooling_device_trip_point_show(struct device *dev,
> > +				       struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_instance *instance;
> > +
> > +	instance =
> > +	    container_of(attr, struct thermal_instance, attr);
> > +
> > +	if (instance->trip == THERMAL_TRIPS_NONE)
> > +		return sprintf(buf, "-1\n");
> > +	else
> > +		return sprintf(buf, "%d\n", instance->trip);
> > +}
> > +
> > +/* Device management */
> > +
> > +#if defined(CONFIG_THERMAL_HWMON)
> > +
> > +/* hwmon sys I/F */
> > +#include <linux/hwmon.h>
> > +
> > +/* thermal zone devices with the same type share one hwmon device */
> > +struct thermal_hwmon_device {
> > +	char type[THERMAL_NAME_LENGTH];
> > +	struct device *device;
> > +	int count;
> > +	struct list_head tz_list;
> > +	struct list_head node;
> > +};
> > +
> > +struct thermal_hwmon_attr {
> > +	struct device_attribute attr;
> > +	char name[16];
> > +};
> > +
> > +/* one temperature input for each thermal zone */
> > +struct thermal_hwmon_temp {
> > +	struct list_head hwmon_node;
> > +	struct thermal_zone_device *tz;
> > +	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> > +	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> > +};
> > +
> > +static LIST_HEAD(thermal_hwmon_list);
> > +
> > +static ssize_t
> > +name_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> > +	return sprintf(buf, "%s\n", hwmon->type);
> > +}
> > +static DEVICE_ATTR(name, 0444, name_show, NULL);
> > +
> > +static ssize_t
> > +temp_input_show(struct device *dev, struct device_attribute *attr, char
> > *buf)
> > +{
> > +	long temperature;
> > +	int ret;
> > +	struct thermal_hwmon_attr *hwmon_attr
> > +			= container_of(attr, struct thermal_hwmon_attr,
> > attr);
> > +	struct thermal_hwmon_temp *temp
> > +			= container_of(hwmon_attr, struct
> > thermal_hwmon_temp,
> > +				       temp_input);
> > +	struct thermal_zone_device *tz = temp->tz;
> > +
> > +	ret = thermal_zone_get_temp(tz, &temperature);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +static ssize_t
> > +temp_crit_show(struct device *dev, struct device_attribute *attr,
> > +		char *buf)
> > +{
> > +	struct thermal_hwmon_attr *hwmon_attr
> > +			= container_of(attr, struct thermal_hwmon_attr,
> > attr);
> > +	struct thermal_hwmon_temp *temp
> > +			= container_of(hwmon_attr, struct
> > thermal_hwmon_temp,
> > +				       temp_crit);
> > +	struct thermal_zone_device *tz = temp->tz;
> > +	long temperature;
> > +	int ret;
> > +
> > +	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +
> > +static struct thermal_hwmon_device *
> > +thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> > +{
> > +	struct thermal_hwmon_device *hwmon;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> > +		if (!strcmp(hwmon->type, tz->type)) {
> > +			mutex_unlock(&thermal_list_lock);
> > +			return hwmon;
> > +		}
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	return NULL;
> > +}
> > +
> > +/* Find the temperature input matching a given thermal zone */
> > +static struct thermal_hwmon_temp *
> > +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device
> > *hwmon,
> > +			  const struct thermal_zone_device *tz)
> > +{
> > +	struct thermal_hwmon_temp *temp;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> > +		if (temp->tz == tz) {
> > +			mutex_unlock(&thermal_list_lock);
> > +			return temp;
> > +		}
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	return NULL;
> > +}
> > +
> > +static int
> > +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> > +{
> > +	struct thermal_hwmon_device *hwmon;
> > +	struct thermal_hwmon_temp *temp;
> > +	int new_hwmon_device = 1;
> > +	int result;
> > +
> > +	hwmon = thermal_hwmon_lookup_by_type(tz);
> > +	if (hwmon) {
> > +		new_hwmon_device = 0;
> > +		goto register_sys_interface;
> > +	}
> > +
> > +	hwmon = kzalloc(sizeof(struct thermal_hwmon_device),
> > GFP_KERNEL);
> > +	if (!hwmon)
> > +		return -ENOMEM;
> > +
> > +	INIT_LIST_HEAD(&hwmon->tz_list);
> > +	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> > +	hwmon->device = hwmon_device_register(NULL);
> > +	if (IS_ERR(hwmon->device)) {
> > +		result = PTR_ERR(hwmon->device);
> > +		goto free_mem;
> > +	}
> > +	dev_set_drvdata(hwmon->device, hwmon);
> > +	result = device_create_file(hwmon->device, &dev_attr_name);
> > +	if (result)
> > +		goto free_mem;
> > +
> > + register_sys_interface:
> > +	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> > +	if (!temp) {
> > +		result = -ENOMEM;
> > +		goto unregister_name;
> > +	}
> > +
> > +	temp->tz = tz;
> > +	hwmon->count++;
> > +
> > +	snprintf(temp->temp_input.name, sizeof(temp-
> > >temp_input.name),
> > +		 "temp%d_input", hwmon->count);
> > +	temp->temp_input.attr.attr.name = temp->temp_input.name;
> > +	temp->temp_input.attr.attr.mode = 0444;
> > +	temp->temp_input.attr.show = temp_input_show;
> > +	sysfs_attr_init(&temp->temp_input.attr.attr);
> > +	result = device_create_file(hwmon->device, &temp-
> > >temp_input.attr);
> > +	if (result)
> > +		goto free_temp_mem;
> > +
> > +	if (tz->ops->get_crit_temp) {
> > +		unsigned long temperature;
> > +		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> > +			snprintf(temp->temp_crit.name,
> > +				 sizeof(temp->temp_crit.name),
> > +				"temp%d_crit", hwmon->count);
> > +			temp->temp_crit.attr.attr.name = temp-
> > >temp_crit.name;
> > +			temp->temp_crit.attr.attr.mode = 0444;
> > +			temp->temp_crit.attr.show = temp_crit_show;
> > +			sysfs_attr_init(&temp->temp_crit.attr.attr);
> > +			result = device_create_file(hwmon->device,
> > +						    &temp->temp_crit.attr);
> > +			if (result)
> > +				goto unregister_input;
> > +		}
> > +	}
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	if (new_hwmon_device)
> > +		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> > +	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	return 0;
> > +
> > + unregister_input:
> > +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> > + free_temp_mem:
> > +	kfree(temp);
> > + unregister_name:
> > +	if (new_hwmon_device) {
> > +		device_remove_file(hwmon->device, &dev_attr_name);
> > +		hwmon_device_unregister(hwmon->device);
> > +	}
> > + free_mem:
> > +	if (new_hwmon_device)
> > +		kfree(hwmon);
> > +
> > +	return result;
> > +}
> > +
> > +static void
> > +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> > +{
> > +	struct thermal_hwmon_device *hwmon;
> > +	struct thermal_hwmon_temp *temp;
> > +
> > +	hwmon = thermal_hwmon_lookup_by_type(tz);
> > +	if (unlikely(!hwmon)) {
> > +		/* Should never happen... */
> > +		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> > +		return;
> > +	}
> > +
> > +	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> > +	if (unlikely(!temp)) {
> > +		/* Should never happen... */
> > +		dev_dbg(&tz->device, "temperature input lookup
> > failed!\n");
> > +		return;
> > +	}
> > +
> > +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> > +	if (tz->ops->get_crit_temp)
> > +		device_remove_file(hwmon->device, &temp-
> > >temp_crit.attr);
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_del(&temp->hwmon_node);
> > +	kfree(temp);
> > +	if (!list_empty(&hwmon->tz_list)) {
> > +		mutex_unlock(&thermal_list_lock);
> > +		return;
> > +	}
> > +	list_del(&hwmon->node);
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	device_remove_file(hwmon->device, &dev_attr_name);
> > +	hwmon_device_unregister(hwmon->device);
> > +	kfree(hwmon);
> > +}
> > +#else
> > +static int
> > +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> > +{
> > +	return 0;
> > +}
> > +
> > +static void
> > +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> > +{
> > +}
> > +#endif
> > +
> > +/**
> > + * thermal_zone_bind_cooling_device - bind a cooling device to a thermal
> > zone
> > + * @tz:		thermal zone device
> > + * @trip:	indicates which trip point the cooling devices is
> > + *		associated with in this thermal zone.
> > + * @cdev:	thermal cooling device
> > + *
> > + * This function is usually called in the thermal zone device .bind callback.
> > + */
> > +int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> > +				     int trip,
> > +				     struct thermal_cooling_device *cdev,
> > +				     unsigned long upper, unsigned long lower)
> > +{
> > +	struct thermal_instance *dev;
> > +	struct thermal_instance *pos;
> > +	struct thermal_zone_device *pos1;
> > +	struct thermal_cooling_device *pos2;
> > +	unsigned long max_state;
> > +	int result;
> > +
> > +	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> > +		return -EINVAL;
> > +
> > +	list_for_each_entry(pos1, &thermal_tz_list, node) {
> > +		if (pos1 == tz)
> > +			break;
> > +	}
> > +	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> > +		if (pos2 == cdev)
> > +			break;
> > +	}
> > +
> > +	if (tz != pos1 || cdev != pos2)
> > +		return -EINVAL;
> > +
> > +	cdev->ops->get_max_state(cdev, &max_state);
> > +
> > +	/* lower default 0, upper default max_state */
> > +	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> > +	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> > +
> > +	if (lower > upper || upper > max_state)
> > +		return -EINVAL;
> > +
> > +	dev =
> > +	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> > +	if (!dev)
> > +		return -ENOMEM;
> > +	dev->tz = tz;
> > +	dev->cdev = cdev;
> > +	dev->trip = trip;
> > +	dev->upper = upper;
> > +	dev->lower = lower;
> > +	dev->target = THERMAL_NO_TARGET;
> > +
> > +	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> > +	if (result)
> > +		goto free_mem;
> > +
> > +	sprintf(dev->name, "cdev%d", dev->id);
> > +	result =
> > +	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev-
> > >name);
> > +	if (result)
> > +		goto release_idr;
> > +
> > +	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> > +	sysfs_attr_init(&dev->attr.attr);
> > +	dev->attr.attr.name = dev->attr_name;
> > +	dev->attr.attr.mode = 0444;
> > +	dev->attr.show = thermal_cooling_device_trip_point_show;
> > +	result = device_create_file(&tz->device, &dev->attr);
> > +	if (result)
> > +		goto remove_symbol_link;
> > +
> > +	mutex_lock(&tz->lock);
> > +	mutex_lock(&cdev->lock);
> > +	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> > +	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > +		result = -EEXIST;
> > +		break;
> > +	}
> > +	if (!result) {
> > +		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> > +		list_add_tail(&dev->cdev_node, &cdev-
> > >thermal_instances);
> > +	}
> > +	mutex_unlock(&cdev->lock);
> > +	mutex_unlock(&tz->lock);
> > +
> > +	if (!result)
> > +		return 0;
> > +
> > +	device_remove_file(&tz->device, &dev->attr);
> > +remove_symbol_link:
> > +	sysfs_remove_link(&tz->device.kobj, dev->name);
> > +release_idr:
> > +	release_idr(&tz->idr, &tz->lock, dev->id);
> > +free_mem:
> > +	kfree(dev);
> > +	return result;
> > +}
> > +EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> > +
> > +/**
> > + * thermal_zone_unbind_cooling_device - unbind a cooling device from a
> > thermal zone
> > + * @tz:		thermal zone device
> > + * @trip:	indicates which trip point the cooling devices is
> > + *		associated with in this thermal zone.
> > + * @cdev:	thermal cooling device
> > + *
> > + * This function is usually called in the thermal zone device .unbind callback.
> > + */
> > +int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> > +				       int trip,
> > +				       struct thermal_cooling_device *cdev)
> > +{
> > +	struct thermal_instance *pos, *next;
> > +
> > +	mutex_lock(&tz->lock);
> > +	mutex_lock(&cdev->lock);
> > +	list_for_each_entry_safe(pos, next, &tz->thermal_instances,
> > tz_node) {
> > +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > +			list_del(&pos->tz_node);
> > +			list_del(&pos->cdev_node);
> > +			mutex_unlock(&cdev->lock);
> > +			mutex_unlock(&tz->lock);
> > +			goto unbind;
> > +		}
> > +	}
> > +	mutex_unlock(&cdev->lock);
> > +	mutex_unlock(&tz->lock);
> > +
> > +	return -ENODEV;
> > +
> > +unbind:
> > +	device_remove_file(&tz->device, &pos->attr);
> > +	sysfs_remove_link(&tz->device.kobj, pos->name);
> > +	release_idr(&tz->idr, &tz->lock, pos->id);
> > +	kfree(pos);
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> > +
> > +static void thermal_release(struct device *dev)
> > +{
> > +	struct thermal_zone_device *tz;
> > +	struct thermal_cooling_device *cdev;
> > +
> > +	if (!strncmp(dev_name(dev), "thermal_zone",
> > +		     sizeof("thermal_zone") - 1)) {
> > +		tz = to_thermal_zone(dev);
> > +		kfree(tz);
> > +	} else {
> > +		cdev = to_cooling_device(dev);
> > +		kfree(cdev);
> > +	}
> > +}
> > +
> > +static struct class thermal_class = {
> > +	.name = "thermal",
> > +	.dev_release = thermal_release,
> > +};
> > +
> > +/**
> > + * thermal_cooling_device_register - register a new thermal cooling device
> > + * @type:	the thermal cooling device type.
> > + * @devdata:	device private data.
> > + * @ops:		standard thermal cooling devices callbacks.
> > + */
> > +struct thermal_cooling_device *
> > +thermal_cooling_device_register(char *type, void *devdata,
> > +				const struct thermal_cooling_device_ops
> > *ops)
> > +{
> > +	struct thermal_cooling_device *cdev;
> > +	int result;
> > +
> > +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> > +	    !ops->set_cur_state)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> > +	if (!cdev)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> > +	if (result) {
> > +		kfree(cdev);
> > +		return ERR_PTR(result);
> > +	}
> > +
> > +	strcpy(cdev->type, type ? : "");
> > +	mutex_init(&cdev->lock);
> > +	INIT_LIST_HEAD(&cdev->thermal_instances);
> > +	cdev->ops = ops;
> > +	cdev->updated = true;
> > +	cdev->device.class = &thermal_class;
> > +	cdev->devdata = devdata;
> > +	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> > +	result = device_register(&cdev->device);
> > +	if (result) {
> > +		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev-
> > >id);
> > +		kfree(cdev);
> > +		return ERR_PTR(result);
> > +	}
> > +
> > +	/* sys I/F */
> > +	if (type) {
> > +		result = device_create_file(&cdev->device,
> > &dev_attr_cdev_type);
> > +		if (result)
> > +			goto unregister;
> > +	}
> > +
> > +	result = device_create_file(&cdev->device, &dev_attr_max_state);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	/* Add 'this' new cdev to the global cdev list */
> > +	mutex_lock(&thermal_list_lock);
> > +	list_add(&cdev->node, &thermal_cdev_list);
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	/* Update binding information for 'this' new cdev */
> > +	bind_cdev(cdev);
> > +
> > +	return cdev;
> > +
> > +unregister:
> > +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > +	device_unregister(&cdev->device);
> > +	return ERR_PTR(result);
> > +}
> > +EXPORT_SYMBOL(thermal_cooling_device_register);
> > +
> > +/**
> > + * thermal_cooling_device_unregister - removes the registered thermal
> > cooling device
> > + * @cdev:	the thermal cooling device to remove.
> > + *
> > + * thermal_cooling_device_unregister() must be called when the device is
> > no
> > + * longer needed.
> > + */
> > +void thermal_cooling_device_unregister(struct thermal_cooling_device
> > *cdev)
> > +{
> > +	int i;
> > +	const struct thermal_zone_params *tzp;
> > +	struct thermal_zone_device *tz;
> > +	struct thermal_cooling_device *pos = NULL;
> > +
> > +	if (!cdev)
> > +		return;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_for_each_entry(pos, &thermal_cdev_list, node)
> > +	    if (pos == cdev)
> > +		break;
> > +	if (pos != cdev) {
> > +		/* thermal cooling device not found */
> > +		mutex_unlock(&thermal_list_lock);
> > +		return;
> > +	}
> > +	list_del(&cdev->node);
> > +
> > +	/* Unbind all thermal zones associated with 'this' cdev */
> > +	list_for_each_entry(tz, &thermal_tz_list, node) {
> > +		if (tz->ops->unbind) {
> > +			tz->ops->unbind(tz, cdev);
> > +			continue;
> > +		}
> > +
> > +		if (!tz->tzp || !tz->tzp->tbp)
> > +			continue;
> > +
> > +		tzp = tz->tzp;
> > +		for (i = 0; i < tzp->num_tbps; i++) {
> > +			if (tzp->tbp[i].cdev == cdev) {
> > +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> > +				tzp->tbp[i].cdev = NULL;
> > +			}
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	if (cdev->type[0])
> > +		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> > +	device_remove_file(&cdev->device, &dev_attr_max_state);
> > +	device_remove_file(&cdev->device, &dev_attr_cur_state);
> > +
> > +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > +	device_unregister(&cdev->device);
> > +	return;
> > +}
> > +EXPORT_SYMBOL(thermal_cooling_device_unregister);
> > +
> > +void thermal_cdev_update(struct thermal_cooling_device *cdev)
> > +{
> > +	struct thermal_instance *instance;
> > +	unsigned long target = 0;
> > +
> > +	/* cooling device is updated*/
> > +	if (cdev->updated)
> > +		return;
> > +
> > +	mutex_lock(&cdev->lock);
> > +	/* Make sure cdev enters the deepest cooling state */
> > +	list_for_each_entry(instance, &cdev->thermal_instances,
> > cdev_node) {
> > +		if (instance->target == THERMAL_NO_TARGET)
> > +			continue;
> > +		if (instance->target > target)
> > +			target = instance->target;
> > +	}
> > +	mutex_unlock(&cdev->lock);
> > +	cdev->ops->set_cur_state(cdev, target);
> > +	cdev->updated = true;
> > +}
> > +EXPORT_SYMBOL(thermal_cdev_update);
> > +
> > +/**
> > + * notify_thermal_framework - Sensor drivers use this API to notify
> > framework
> > + * @tz:		thermal zone device
> > + * @trip:	indicates which trip point has been crossed
> > + *
> > + * This function handles the trip events from sensor drivers. It starts
> > + * throttling the cooling devices according to the policy configured.
> > + * For CRITICAL and HOT trip points, this notifies the respective drivers,
> > + * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> > + * The throttling policy is based on the configured platform data; if no
> > + * platform data is provided, this uses the step_wise throttling policy.
> > + */
> > +void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> > +{
> > +	handle_thermal_trip(tz, trip);
> > +}
> > +EXPORT_SYMBOL(notify_thermal_framework);
> > +
> > +/**
> > + * create_trip_attrs - create attributes for trip points
> > + * @tz:		the thermal zone device
> > + * @mask:	Writeable trip point bitmap.
> > + */
> > +static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> > +{
> > +	int indx;
> > +	int size = sizeof(struct thermal_attr) * tz->trips;
> > +
> > +	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> > +	if (!tz->trip_type_attrs)
> > +		return -ENOMEM;
> > +
> > +	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> > +	if (!tz->trip_temp_attrs) {
> > +		kfree(tz->trip_type_attrs);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	if (tz->ops->get_trip_hyst) {
> > +		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> > +		if (!tz->trip_hyst_attrs) {
> > +			kfree(tz->trip_type_attrs);
> > +			kfree(tz->trip_temp_attrs);
> > +			return -ENOMEM;
> > +		}
> > +	}
> > +
> > +
> > +	for (indx = 0; indx < tz->trips; indx++) {
> > +		/* create trip type attribute */
> > +		snprintf(tz->trip_type_attrs[indx].name,
> > THERMAL_NAME_LENGTH,
> > +			 "trip_point_%d_type", indx);
> > +
> > +		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> > +		tz->trip_type_attrs[indx].attr.attr.name =
> > +						tz-
> > >trip_type_attrs[indx].name;
> > +		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> > +		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> > +
> > +		device_create_file(&tz->device,
> > +				   &tz->trip_type_attrs[indx].attr);
> > +
> > +		/* create trip temp attribute */
> > +		snprintf(tz->trip_temp_attrs[indx].name,
> > THERMAL_NAME_LENGTH,
> > +			 "trip_point_%d_temp", indx);
> > +
> > +		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> > +		tz->trip_temp_attrs[indx].attr.attr.name =
> > +						tz-
> > >trip_temp_attrs[indx].name;
> > +		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> > +		tz->trip_temp_attrs[indx].attr.show =
> > trip_point_temp_show;
> > +		if (mask & (1 << indx)) {
> > +			tz->trip_temp_attrs[indx].attr.attr.mode |=
> > S_IWUSR;
> > +			tz->trip_temp_attrs[indx].attr.store =
> > +
> > 	trip_point_temp_store;
> > +		}
> > +
> > +		device_create_file(&tz->device,
> > +				   &tz->trip_temp_attrs[indx].attr);
> > +
> > +		/* create Optional trip hyst attribute */
> > +		if (!tz->ops->get_trip_hyst)
> > +			continue;
> > +		snprintf(tz->trip_hyst_attrs[indx].name,
> > THERMAL_NAME_LENGTH,
> > +			 "trip_point_%d_hyst", indx);
> > +
> > +		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> > +		tz->trip_hyst_attrs[indx].attr.attr.name =
> > +					tz->trip_hyst_attrs[indx].name;
> > +		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> > +		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> > +		if (tz->ops->set_trip_hyst) {
> > +			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> > +			tz->trip_hyst_attrs[indx].attr.store =
> > +					trip_point_hyst_store;
> > +		}
> > +
> > +		device_create_file(&tz->device,
> > +				   &tz->trip_hyst_attrs[indx].attr);
> > +	}
> > +	return 0;
> > +}
> > +
> > +static void remove_trip_attrs(struct thermal_zone_device *tz)
> > +{
> > +	int indx;
> > +
> > +	for (indx = 0; indx < tz->trips; indx++) {
> > +		device_remove_file(&tz->device,
> > +				   &tz->trip_type_attrs[indx].attr);
> > +		device_remove_file(&tz->device,
> > +				   &tz->trip_temp_attrs[indx].attr);
> > +		if (tz->ops->get_trip_hyst)
> > +			device_remove_file(&tz->device,
> > +				  &tz->trip_hyst_attrs[indx].attr);
> > +	}
> > +	kfree(tz->trip_type_attrs);
> > +	kfree(tz->trip_temp_attrs);
> > +	kfree(tz->trip_hyst_attrs);
> > +}
> > +
> > +/**
> > + * thermal_zone_device_register - register a new thermal zone device
> > + * @type:	the thermal zone device type
> > + * @trips:	the number of trip points the thermal zone support
> > + * @mask:	a bit string indicating the writeablility of trip points
> > + * @devdata:	private device data
> > + * @ops:	standard thermal zone device callbacks
> > + * @tzp:	thermal zone platform parameters
> > + * @passive_delay: number of milliseconds to wait between polls when
> > + *		   performing passive cooling
> > + * @polling_delay: number of milliseconds to wait between polls when
> > checking
> > + *		   whether trip points have been crossed (0 for interrupt
> > + *		   driven systems)
> > + *
> > + * thermal_zone_device_unregister() must be called when the device is no
> > + * longer needed. The passive cooling depends on the .get_trend() return
> > value.
> > + */
> > +struct thermal_zone_device *thermal_zone_device_register(const char
> > *type,
> > +	int trips, int mask, void *devdata,
> > +	const struct thermal_zone_device_ops *ops,
> > +	const struct thermal_zone_params *tzp,
> > +	int passive_delay, int polling_delay)
> > +{
> > +	struct thermal_zone_device *tz;
> > +	enum thermal_trip_type trip_type;
> > +	int result;
> > +	int count;
> > +	int passive = 0;
> > +
> > +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	if (!ops || !ops->get_temp)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	if (trips > 0 && !ops->get_trip_type)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> > +	if (!tz)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	INIT_LIST_HEAD(&tz->thermal_instances);
> > +	idr_init(&tz->idr);
> > +	mutex_init(&tz->lock);
> > +	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> > +	if (result) {
> > +		kfree(tz);
> > +		return ERR_PTR(result);
> > +	}
> > +
> > +	strcpy(tz->type, type ? : "");
> > +	tz->ops = ops;
> > +	tz->tzp = tzp;
> > +	tz->device.class = &thermal_class;
> > +	tz->devdata = devdata;
> > +	tz->trips = trips;
> > +	tz->passive_delay = passive_delay;
> > +	tz->polling_delay = polling_delay;
> > +
> > +	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> > +	result = device_register(&tz->device);
> > +	if (result) {
> > +		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > +		kfree(tz);
> > +		return ERR_PTR(result);
> > +	}
> > +
> > +	/* sys I/F */
> > +	if (type) {
> > +		result = device_create_file(&tz->device, &dev_attr_type);
> > +		if (result)
> > +			goto unregister;
> > +	}
> > +
> > +	result = device_create_file(&tz->device, &dev_attr_temp);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	if (ops->get_mode) {
> > +		result = device_create_file(&tz->device, &dev_attr_mode);
> > +		if (result)
> > +			goto unregister;
> > +	}
> > +
> > +	result = create_trip_attrs(tz, mask);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	for (count = 0; count < trips; count++) {
> > +		tz->ops->get_trip_type(tz, count, &trip_type);
> > +		if (trip_type == THERMAL_TRIP_PASSIVE)
> > +			passive = 1;
> > +	}
> > +
> > +	if (!passive) {
> > +		result = device_create_file(&tz->device, &dev_attr_passive);
> > +		if (result)
> > +			goto unregister;
> > +	}
> > +
> > +#ifdef CONFIG_THERMAL_EMULATION
> > +	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> > +	if (result)
> > +		goto unregister;
> > +#endif
> > +	/* Create policy attribute */
> > +	result = device_create_file(&tz->device, &dev_attr_policy);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	/* Update 'this' zone's governor information */
> > +	mutex_lock(&thermal_governor_lock);
> > +
> > +	if (tz->tzp)
> > +		tz->governor = __find_governor(tz->tzp->governor_name);
> > +	else
> > +		tz->governor =
> > __find_governor(DEFAULT_THERMAL_GOVERNOR);
> > +
> > +	mutex_unlock(&thermal_governor_lock);
> > +
> > +	result = thermal_add_hwmon_sysfs(tz);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_add_tail(&tz->node, &thermal_tz_list);
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	/* Bind cooling devices for this zone */
> > +	bind_tz(tz);
> > +
> > +	INIT_DELAYED_WORK(&(tz->poll_queue),
> > thermal_zone_device_check);
> > +
> > +	thermal_zone_device_update(tz);
> > +
> > +	if (!result)
> > +		return tz;
> > +
> > +unregister:
> > +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > +	device_unregister(&tz->device);
> > +	return ERR_PTR(result);
> > +}
> > +EXPORT_SYMBOL(thermal_zone_device_register);
> > +
> > +/**
> > + * thermal_device_unregister - removes the registered thermal zone
> > device
> > + * @tz: the thermal zone device to remove
> > + */
> > +void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> > +{
> > +	int i;
> > +	const struct thermal_zone_params *tzp;
> > +	struct thermal_cooling_device *cdev;
> > +	struct thermal_zone_device *pos = NULL;
> > +
> > +	if (!tz)
> > +		return;
> > +
> > +	tzp = tz->tzp;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_for_each_entry(pos, &thermal_tz_list, node)
> > +	    if (pos == tz)
> > +		break;
> > +	if (pos != tz) {
> > +		/* thermal zone device not found */
> > +		mutex_unlock(&thermal_list_lock);
> > +		return;
> > +	}
> > +	list_del(&tz->node);
> > +
> > +	/* Unbind all cdevs associated with 'this' thermal zone */
> > +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > +		if (tz->ops->unbind) {
> > +			tz->ops->unbind(tz, cdev);
> > +			continue;
> > +		}
> > +
> > +		if (!tzp || !tzp->tbp)
> > +			break;
> > +
> > +		for (i = 0; i < tzp->num_tbps; i++) {
> > +			if (tzp->tbp[i].cdev == cdev) {
> > +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> > +				tzp->tbp[i].cdev = NULL;
> > +			}
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	thermal_zone_device_set_polling(tz, 0);
> > +
> > +	if (tz->type[0])
> > +		device_remove_file(&tz->device, &dev_attr_type);
> > +	device_remove_file(&tz->device, &dev_attr_temp);
> > +	if (tz->ops->get_mode)
> > +		device_remove_file(&tz->device, &dev_attr_mode);
> > +	device_remove_file(&tz->device, &dev_attr_policy);
> > +	remove_trip_attrs(tz);
> > +	tz->governor = NULL;
> > +
> > +	thermal_remove_hwmon_sysfs(tz);
> > +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > +	idr_destroy(&tz->idr);
> > +	mutex_destroy(&tz->lock);
> > +	device_unregister(&tz->device);
> > +	return;
> > +}
> > +EXPORT_SYMBOL(thermal_zone_device_unregister);
> > +
> > +#ifdef CONFIG_NET
> > +static struct genl_family thermal_event_genl_family = {
> > +	.id = GENL_ID_GENERATE,
> > +	.name = THERMAL_GENL_FAMILY_NAME,
> > +	.version = THERMAL_GENL_VERSION,
> > +	.maxattr = THERMAL_GENL_ATTR_MAX,
> > +};
> > +
> > +static struct genl_multicast_group thermal_event_mcgrp = {
> > +	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> > +};
> > +
> > +int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> > +					enum events event)
> > +{
> > +	struct sk_buff *skb;
> > +	struct nlattr *attr;
> > +	struct thermal_genl_event *thermal_event;
> > +	void *msg_header;
> > +	int size;
> > +	int result;
> > +	static unsigned int thermal_event_seqnum;
> > +
> > +	if (!tz)
> > +		return -EINVAL;
> > +
> > +	/* allocate memory */
> > +	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> > +	       nla_total_size(0);
> > +
> > +	skb = genlmsg_new(size, GFP_ATOMIC);
> > +	if (!skb)
> > +		return -ENOMEM;
> > +
> > +	/* add the genetlink message header */
> > +	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> > +				 &thermal_event_genl_family, 0,
> > +				 THERMAL_GENL_CMD_EVENT);
> > +	if (!msg_header) {
> > +		nlmsg_free(skb);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	/* fill the data */
> > +	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> > +			   sizeof(struct thermal_genl_event));
> > +
> > +	if (!attr) {
> > +		nlmsg_free(skb);
> > +		return -EINVAL;
> > +	}
> > +
> > +	thermal_event = nla_data(attr);
> > +	if (!thermal_event) {
> > +		nlmsg_free(skb);
> > +		return -EINVAL;
> > +	}
> > +
> > +	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> > +
> > +	thermal_event->orig = tz->id;
> > +	thermal_event->event = event;
> > +
> > +	/* send multicast genetlink message */
> > +	result = genlmsg_end(skb, msg_header);
> > +	if (result < 0) {
> > +		nlmsg_free(skb);
> > +		return result;
> > +	}
> > +
> > +	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id,
> > GFP_ATOMIC);
> > +	if (result)
> > +		dev_err(&tz->device, "Failed to send netlink event:%d",
> > result);
> > +
> > +	return result;
> > +}
> > +EXPORT_SYMBOL(thermal_generate_netlink_event);
> > +
> > +static int genetlink_init(void)
> > +{
> > +	int result;
> > +
> > +	result = genl_register_family(&thermal_event_genl_family);
> > +	if (result)
> > +		return result;
> > +
> > +	result = genl_register_mc_group(&thermal_event_genl_family,
> > +					&thermal_event_mcgrp);
> > +	if (result)
> > +		genl_unregister_family(&thermal_event_genl_family);
> > +	return result;
> > +}
> > +
> > +static void genetlink_exit(void)
> > +{
> > +	genl_unregister_family(&thermal_event_genl_family);
> > +}
> > +#else /* !CONFIG_NET */
> > +static inline int genetlink_init(void) { return 0; }
> > +static inline void genetlink_exit(void) {}
> > +#endif /* !CONFIG_NET */
> > +
> > +static int __init thermal_init(void)
> > +{
> > +	int result = 0;
> > +
> > +	result = class_register(&thermal_class);
> > +	if (result) {
> > +		idr_destroy(&thermal_tz_idr);
> > +		idr_destroy(&thermal_cdev_idr);
> > +		mutex_destroy(&thermal_idr_lock);
> > +		mutex_destroy(&thermal_list_lock);
> > +		return result;
> > +	}
> > +	result = genetlink_init();
> > +	return result;
> > +}
> > +
> > +static void __exit thermal_exit(void)
> > +{
> > +	class_unregister(&thermal_class);
> > +	idr_destroy(&thermal_tz_idr);
> > +	idr_destroy(&thermal_cdev_idr);
> > +	mutex_destroy(&thermal_idr_lock);
> > +	mutex_destroy(&thermal_list_lock);
> > +	genetlink_exit();
> > +}
> > +
> > +fs_initcall(thermal_init);
> > +module_exit(thermal_exit);
> > diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> > deleted file mode 100644
> > index 5b7863a..0000000
> > --- a/drivers/thermal/thermal_sys.c
> > +++ /dev/null
> > @@ -1,1888 +0,0 @@
> > -/*
> > - *  thermal.c - Generic Thermal Management Sysfs support.
> > - *
> > - *  Copyright (C) 2008 Intel Corp
> > - *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> > - *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> > - *
> > - *
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > ~~~~~~~~~~~~~~~~
> > - *
> > - *  This program is free software; you can redistribute it and/or modify
> > - *  it under the terms of the GNU General Public License as published by
> > - *  the Free Software Foundation; version 2 of the License.
> > - *
> > - *  This program is distributed in the hope that it will be useful, but
> > - *  WITHOUT ANY WARRANTY; without even the implied warranty of
> > - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > GNU
> > - *  General Public License for more details.
> > - *
> > - *  You should have received a copy of the GNU General Public License along
> > - *  with this program; if not, write to the Free Software Foundation, Inc.,
> > - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> > - *
> > - *
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > ~~~~~~~~~~~~~~~~
> > - */
> > -
> > -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > -
> > -#include <linux/module.h>
> > -#include <linux/device.h>
> > -#include <linux/err.h>
> > -#include <linux/slab.h>
> > -#include <linux/kdev_t.h>
> > -#include <linux/idr.h>
> > -#include <linux/thermal.h>
> > -#include <linux/reboot.h>
> > -#include <net/netlink.h>
> > -#include <net/genetlink.h>
> > -
> > -#include "thermal_core.h"
> > -
> > -MODULE_AUTHOR("Zhang Rui");
> > -MODULE_DESCRIPTION("Generic thermal management sysfs support");
> > -MODULE_LICENSE("GPL");
> > -
> > -static DEFINE_IDR(thermal_tz_idr);
> > -static DEFINE_IDR(thermal_cdev_idr);
> > -static DEFINE_MUTEX(thermal_idr_lock);
> > -
> > -static LIST_HEAD(thermal_tz_list);
> > -static LIST_HEAD(thermal_cdev_list);
> > -static LIST_HEAD(thermal_governor_list);
> > -
> > -static DEFINE_MUTEX(thermal_list_lock);
> > -static DEFINE_MUTEX(thermal_governor_lock);
> > -
> > -static struct thermal_governor *__find_governor(const char *name)
> > -{
> > -	struct thermal_governor *pos;
> > -
> > -	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> > -		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> > -			return pos;
> > -
> > -	return NULL;
> > -}
> > -
> > -int thermal_register_governor(struct thermal_governor *governor)
> > -{
> > -	int err;
> > -	const char *name;
> > -	struct thermal_zone_device *pos;
> > -
> > -	if (!governor)
> > -		return -EINVAL;
> > -
> > -	mutex_lock(&thermal_governor_lock);
> > -
> > -	err = -EBUSY;
> > -	if (__find_governor(governor->name) == NULL) {
> > -		err = 0;
> > -		list_add(&governor->governor_list,
> > &thermal_governor_list);
> > -	}
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -
> > -	list_for_each_entry(pos, &thermal_tz_list, node) {
> > -		if (pos->governor)
> > -			continue;
> > -		if (pos->tzp)
> > -			name = pos->tzp->governor_name;
> > -		else
> > -			name = DEFAULT_THERMAL_GOVERNOR;
> > -		if (!strnicmp(name, governor->name,
> > THERMAL_NAME_LENGTH))
> > -			pos->governor = governor;
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -	mutex_unlock(&thermal_governor_lock);
> > -
> > -	return err;
> > -}
> > -EXPORT_SYMBOL_GPL(thermal_register_governor);
> > -
> > -void thermal_unregister_governor(struct thermal_governor *governor)
> > -{
> > -	struct thermal_zone_device *pos;
> > -
> > -	if (!governor)
> > -		return;
> > -
> > -	mutex_lock(&thermal_governor_lock);
> > -
> > -	if (__find_governor(governor->name) == NULL)
> > -		goto exit;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -
> > -	list_for_each_entry(pos, &thermal_tz_list, node) {
> > -		if (!strnicmp(pos->governor->name, governor->name,
> > -						THERMAL_NAME_LENGTH))
> > -			pos->governor = NULL;
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -	list_del(&governor->governor_list);
> > -exit:
> > -	mutex_unlock(&thermal_governor_lock);
> > -	return;
> > -}
> > -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> > -
> > -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> > -{
> > -	int ret;
> > -
> > -	if (lock)
> > -		mutex_lock(lock);
> > -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> > -	if (lock)
> > -		mutex_unlock(lock);
> > -	if (unlikely(ret < 0))
> > -		return ret;
> > -	*id = ret;
> > -	return 0;
> > -}
> > -
> > -static void release_idr(struct idr *idr, struct mutex *lock, int id)
> > -{
> > -	if (lock)
> > -		mutex_lock(lock);
> > -	idr_remove(idr, id);
> > -	if (lock)
> > -		mutex_unlock(lock);
> > -}
> > -
> > -int get_tz_trend(struct thermal_zone_device *tz, int trip)
> > -{
> > -	enum thermal_trend trend;
> > -
> > -	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> > -		if (tz->temperature > tz->last_temperature)
> > -			trend = THERMAL_TREND_RAISING;
> > -		else if (tz->temperature < tz->last_temperature)
> > -			trend = THERMAL_TREND_DROPPING;
> > -		else
> > -			trend = THERMAL_TREND_STABLE;
> > -	}
> > -
> > -	return trend;
> > -}
> > -EXPORT_SYMBOL(get_tz_trend);
> > -
> > -struct thermal_instance *get_thermal_instance(struct
> > thermal_zone_device *tz,
> > -			struct thermal_cooling_device *cdev, int trip)
> > -{
> > -	struct thermal_instance *pos = NULL;
> > -	struct thermal_instance *target_instance = NULL;
> > -
> > -	mutex_lock(&tz->lock);
> > -	mutex_lock(&cdev->lock);
> > -
> > -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> > -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > -			target_instance = pos;
> > -			break;
> > -		}
> > -	}
> > -
> > -	mutex_unlock(&cdev->lock);
> > -	mutex_unlock(&tz->lock);
> > -
> > -	return target_instance;
> > -}
> > -EXPORT_SYMBOL(get_thermal_instance);
> > -
> > -static void print_bind_err_msg(struct thermal_zone_device *tz,
> > -			struct thermal_cooling_device *cdev, int ret)
> > -{
> > -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> > -				tz->type, cdev->type, ret);
> > -}
> > -
> > -static void __bind(struct thermal_zone_device *tz, int mask,
> > -			struct thermal_cooling_device *cdev)
> > -{
> > -	int i, ret;
> > -
> > -	for (i = 0; i < tz->trips; i++) {
> > -		if (mask & (1 << i)) {
> > -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> > -					THERMAL_NO_LIMIT,
> > THERMAL_NO_LIMIT);
> > -			if (ret)
> > -				print_bind_err_msg(tz, cdev, ret);
> > -		}
> > -	}
> > -}
> > -
> > -static void __unbind(struct thermal_zone_device *tz, int mask,
> > -			struct thermal_cooling_device *cdev)
> > -{
> > -	int i;
> > -
> > -	for (i = 0; i < tz->trips; i++)
> > -		if (mask & (1 << i))
> > -			thermal_zone_unbind_cooling_device(tz, i, cdev);
> > -}
> > -
> > -static void bind_cdev(struct thermal_cooling_device *cdev)
> > -{
> > -	int i, ret;
> > -	const struct thermal_zone_params *tzp;
> > -	struct thermal_zone_device *pos = NULL;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -
> > -	list_for_each_entry(pos, &thermal_tz_list, node) {
> > -		if (!pos->tzp && !pos->ops->bind)
> > -			continue;
> > -
> > -		if (!pos->tzp && pos->ops->bind) {
> > -			ret = pos->ops->bind(pos, cdev);
> > -			if (ret)
> > -				print_bind_err_msg(pos, cdev, ret);
> > -		}
> > -
> > -		tzp = pos->tzp;
> > -		if (!tzp || !tzp->tbp)
> > -			continue;
> > -
> > -		for (i = 0; i < tzp->num_tbps; i++) {
> > -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> > -				continue;
> > -			if (tzp->tbp[i].match(pos, cdev))
> > -				continue;
> > -			tzp->tbp[i].cdev = cdev;
> > -			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> > -		}
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -}
> > -
> > -static void bind_tz(struct thermal_zone_device *tz)
> > -{
> > -	int i, ret;
> > -	struct thermal_cooling_device *pos = NULL;
> > -	const struct thermal_zone_params *tzp = tz->tzp;
> > -
> > -	if (!tzp && !tz->ops->bind)
> > -		return;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -
> > -	/* If there is no platform data, try to use ops->bind */
> > -	if (!tzp && tz->ops->bind) {
> > -		list_for_each_entry(pos, &thermal_cdev_list, node) {
> > -			ret = tz->ops->bind(tz, pos);
> > -			if (ret)
> > -				print_bind_err_msg(tz, pos, ret);
> > -		}
> > -		goto exit;
> > -	}
> > -
> > -	if (!tzp || !tzp->tbp)
> > -		goto exit;
> > -
> > -	list_for_each_entry(pos, &thermal_cdev_list, node) {
> > -		for (i = 0; i < tzp->num_tbps; i++) {
> > -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> > -				continue;
> > -			if (tzp->tbp[i].match(tz, pos))
> > -				continue;
> > -			tzp->tbp[i].cdev = pos;
> > -			__bind(tz, tzp->tbp[i].trip_mask, pos);
> > -		}
> > -	}
> > -exit:
> > -	mutex_unlock(&thermal_list_lock);
> > -}
> > -
> > -static void thermal_zone_device_set_polling(struct thermal_zone_device
> > *tz,
> > -					    int delay)
> > -{
> > -	if (delay > 1000)
> > -		mod_delayed_work(system_freezable_wq, &tz-
> > >poll_queue,
> > -				 round_jiffies(msecs_to_jiffies(delay)));
> > -	else if (delay)
> > -		mod_delayed_work(system_freezable_wq, &tz-
> > >poll_queue,
> > -				 msecs_to_jiffies(delay));
> > -	else
> > -		cancel_delayed_work(&tz->poll_queue);
> > -}
> > -
> > -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);
> > -	else if (tz->polling_delay)
> > -		thermal_zone_device_set_polling(tz, tz->polling_delay);
> > -	else
> > -		thermal_zone_device_set_polling(tz, 0);
> > -
> > -	mutex_unlock(&tz->lock);
> > -}
> > -
> > -static void handle_non_critical_trips(struct thermal_zone_device *tz,
> > -			int trip, enum thermal_trip_type trip_type)
> > -{
> > -	if (tz->governor)
> > -		tz->governor->throttle(tz, trip);
> > -}
> > -
> > -static void handle_critical_trips(struct thermal_zone_device *tz,
> > -				int trip, enum thermal_trip_type trip_type)
> > -{
> > -	long trip_temp;
> > -
> > -	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> > -
> > -	/* If we have not crossed the trip_temp, we do not care. */
> > -	if (tz->temperature < trip_temp)
> > -		return;
> > -
> > -	if (tz->ops->notify)
> > -		tz->ops->notify(tz, trip, trip_type);
> > -
> > -	if (trip_type == THERMAL_TRIP_CRITICAL) {
> > -		dev_emerg(&tz->device,
> > -			  "critical temperature reached(%d C),shutting
> > down\n",
> > -			  tz->temperature / 1000);
> > -		orderly_poweroff(true);
> > -	}
> > -}
> > -
> > -static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> > -{
> > -	enum thermal_trip_type type;
> > -
> > -	tz->ops->get_trip_type(tz, trip, &type);
> > -
> > -	if (type == THERMAL_TRIP_CRITICAL || type ==
> > THERMAL_TRIP_HOT)
> > -		handle_critical_trips(tz, trip, type);
> > -	else
> > -		handle_non_critical_trips(tz, trip, type);
> > -	/*
> > -	 * Alright, we handled this trip successfully.
> > -	 * So, start monitoring again.
> > -	 */
> > -	monitor_thermal_zone(tz);
> > -}
> > -
> > -static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> > -				unsigned long *temp)
> > -{
> > -	int ret = 0;
> > -#ifdef CONFIG_THERMAL_EMULATION
> > -	int count;
> > -	unsigned long crit_temp = -1UL;
> > -	enum thermal_trip_type type;
> > -#endif
> > -
> > -	mutex_lock(&tz->lock);
> > -
> > -	ret = tz->ops->get_temp(tz, temp);
> > -#ifdef CONFIG_THERMAL_EMULATION
> > -	if (!tz->emul_temperature)
> > -		goto skip_emul;
> > -
> > -	for (count = 0; count < tz->trips; count++) {
> > -		ret = tz->ops->get_trip_type(tz, count, &type);
> > -		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> > -			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> > -			break;
> > -		}
> > -	}
> > -
> > -	if (ret)
> > -		goto skip_emul;
> > -
> > -	if (*temp < crit_temp)
> > -		*temp = tz->emul_temperature;
> > -skip_emul:
> > -#endif
> > -	mutex_unlock(&tz->lock);
> > -	return ret;
> > -}
> > -
> > -static void update_temperature(struct thermal_zone_device *tz)
> > -{
> > -	long temp;
> > -	int ret;
> > -
> > -	ret = thermal_zone_get_temp(tz, &temp);
> > -	if (ret) {
> > -		dev_warn(&tz->device, "failed to read out thermal zone
> > %d\n",
> > -			 tz->id);
> > -		return;
> > -	}
> > -
> > -	mutex_lock(&tz->lock);
> > -	tz->last_temperature = tz->temperature;
> > -	tz->temperature = temp;
> > -	mutex_unlock(&tz->lock);
> > -}
> > -
> > -void thermal_zone_device_update(struct thermal_zone_device *tz)
> > -{
> > -	int count;
> > -
> > -	update_temperature(tz);
> > -
> > -	for (count = 0; count < tz->trips; count++)
> > -		handle_thermal_trip(tz, count);
> > -}
> > -EXPORT_SYMBOL(thermal_zone_device_update);
> > -
> > -static void thermal_zone_device_check(struct work_struct *work)
> > -{
> > -	struct thermal_zone_device *tz = container_of(work, struct
> > -						      thermal_zone_device,
> > -						      poll_queue.work);
> > -	thermal_zone_device_update(tz);
> > -}
> > -
> > -/* sys I/F for thermal zone */
> > -
> > -#define to_thermal_zone(_dev) \
> > -	container_of(_dev, struct thermal_zone_device, device)
> > -
> > -static ssize_t
> > -type_show(struct device *dev, struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -
> > -	return sprintf(buf, "%s\n", tz->type);
> > -}
> > -
> > -static ssize_t
> > -temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	long temperature;
> > -	int ret;
> > -
> > -	ret = thermal_zone_get_temp(tz, &temperature);
> > -
> > -	if (ret)
> > -		return ret;
> > -
> > -	return sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -static ssize_t
> > -mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	enum thermal_device_mode mode;
> > -	int result;
> > -
> > -	if (!tz->ops->get_mode)
> > -		return -EPERM;
> > -
> > -	result = tz->ops->get_mode(tz, &mode);
> > -	if (result)
> > -		return result;
> > -
> > -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ?
> > "enabled"
> > -		       : "disabled");
> > -}
> > -
> > -static ssize_t
> > -mode_store(struct device *dev, struct device_attribute *attr,
> > -	   const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int result;
> > -
> > -	if (!tz->ops->set_mode)
> > -		return -EPERM;
> > -
> > -	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);
> > -	else
> > -		result = -EINVAL;
> > -
> > -	if (result)
> > -		return result;
> > -
> > -	return count;
> > -}
> > -
> > -static ssize_t
> > -trip_point_type_show(struct device *dev, struct device_attribute *attr,
> > -		     char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	enum thermal_trip_type type;
> > -	int trip, result;
> > -
> > -	if (!tz->ops->get_trip_type)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> > -		return -EINVAL;
> > -
> > -	result = tz->ops->get_trip_type(tz, trip, &type);
> > -	if (result)
> > -		return result;
> > -
> > -	switch (type) {
> > -	case THERMAL_TRIP_CRITICAL:
> > -		return sprintf(buf, "critical\n");
> > -	case THERMAL_TRIP_HOT:
> > -		return sprintf(buf, "hot\n");
> > -	case THERMAL_TRIP_PASSIVE:
> > -		return sprintf(buf, "passive\n");
> > -	case THERMAL_TRIP_ACTIVE:
> > -		return sprintf(buf, "active\n");
> > -	default:
> > -		return sprintf(buf, "unknown\n");
> > -	}
> > -}
> > -
> > -static ssize_t
> > -trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> > -		     const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int trip, ret;
> > -	unsigned long temperature;
> > -
> > -	if (!tz->ops->set_trip_temp)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> > -		return -EINVAL;
> > -
> > -	if (kstrtoul(buf, 10, &temperature))
> > -		return -EINVAL;
> > -
> > -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> > -
> > -	return ret ? ret : count;
> > -}
> > -
> > -static ssize_t
> > -trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> > -		     char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int trip, ret;
> > -	long temperature;
> > -
> > -	if (!tz->ops->get_trip_temp)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> > -		return -EINVAL;
> > -
> > -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> > -
> > -	if (ret)
> > -		return ret;
> > -
> > -	return sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -static ssize_t
> > -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> > -			const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int trip, ret;
> > -	unsigned long temperature;
> > -
> > -	if (!tz->ops->set_trip_hyst)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> > -		return -EINVAL;
> > -
> > -	if (kstrtoul(buf, 10, &temperature))
> > -		return -EINVAL;
> > -
> > -	/*
> > -	 * We are not doing any check on the 'temperature' value
> > -	 * here. The driver implementing 'set_trip_hyst' has to
> > -	 * take care of this.
> > -	 */
> > -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> > -
> > -	return ret ? ret : count;
> > -}
> > -
> > -static ssize_t
> > -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> > -			char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int trip, ret;
> > -	unsigned long temperature;
> > -
> > -	if (!tz->ops->get_trip_hyst)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> > -		return -EINVAL;
> > -
> > -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> > -
> > -	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -static ssize_t
> > -passive_store(struct device *dev, struct device_attribute *attr,
> > -		    const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	struct thermal_cooling_device *cdev = NULL;
> > -	int state;
> > -
> > -	if (!sscanf(buf, "%d\n", &state))
> > -		return -EINVAL;
> > -
> > -	/* sanity check: values below 1000 millicelcius don't make sense
> > -	 * and can cause the system to go into a thermal heart attack
> > -	 */
> > -	if (state && state < 1000)
> > -		return -EINVAL;
> > -
> > -	if (state && !tz->forced_passive) {
> > -		mutex_lock(&thermal_list_lock);
> > -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > -			if (!strncmp("Processor", cdev->type,
> > -				     sizeof("Processor")))
> > -				thermal_zone_bind_cooling_device(tz,
> > -						THERMAL_TRIPS_NONE,
> > cdev,
> > -						THERMAL_NO_LIMIT,
> > -						THERMAL_NO_LIMIT);
> > -		}
> > -		mutex_unlock(&thermal_list_lock);
> > -		if (!tz->passive_delay)
> > -			tz->passive_delay = 1000;
> > -	} else if (!state && tz->forced_passive) {
> > -		mutex_lock(&thermal_list_lock);
> > -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > -			if (!strncmp("Processor", cdev->type,
> > -				     sizeof("Processor")))
> > -				thermal_zone_unbind_cooling_device(tz,
> > -
> > THERMAL_TRIPS_NONE,
> > -								   cdev);
> > -		}
> > -		mutex_unlock(&thermal_list_lock);
> > -		tz->passive_delay = 0;
> > -	}
> > -
> > -	tz->forced_passive = state;
> > -
> > -	thermal_zone_device_update(tz);
> > -
> > -	return count;
> > -}
> > -
> > -static ssize_t
> > -passive_show(struct device *dev, struct device_attribute *attr,
> > -		   char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -
> > -	return sprintf(buf, "%d\n", tz->forced_passive);
> > -}
> > -
> > -static ssize_t
> > -policy_store(struct device *dev, struct device_attribute *attr,
> > -		    const char *buf, size_t count)
> > -{
> > -	int ret = -EINVAL;
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	struct thermal_governor *gov;
> > -
> > -	mutex_lock(&thermal_governor_lock);
> > -
> > -	gov = __find_governor(buf);
> > -	if (!gov)
> > -		goto exit;
> > -
> > -	tz->governor = gov;
> > -	ret = count;
> > -
> > -exit:
> > -	mutex_unlock(&thermal_governor_lock);
> > -	return ret;
> > -}
> > -
> > -static ssize_t
> > -policy_show(struct device *dev, struct device_attribute *devattr, char
> > *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -
> > -	return sprintf(buf, "%s\n", tz->governor->name);
> > -}
> > -
> > -#ifdef CONFIG_THERMAL_EMULATION
> > -static ssize_t
> > -emul_temp_store(struct device *dev, struct device_attribute *attr,
> > -		     const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int ret = 0;
> > -	unsigned long temperature;
> > -
> > -	if (kstrtoul(buf, 10, &temperature))
> > -		return -EINVAL;
> > -
> > -	if (!tz->ops->set_emul_temp) {
> > -		mutex_lock(&tz->lock);
> > -		tz->emul_temperature = temperature;
> > -		mutex_unlock(&tz->lock);
> > -	} else {
> > -		ret = tz->ops->set_emul_temp(tz, temperature);
> > -	}
> > -
> > -	return ret ? ret : count;
> > -}
> > -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> > -#endif/*CONFIG_THERMAL_EMULATION*/
> > -
> > -static DEVICE_ATTR(type, 0444, type_show, NULL);
> > -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> > -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> > -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show,
> > passive_store);
> > -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show,
> > policy_store);
> > -
> > -/* sys I/F for cooling device */
> > -#define to_cooling_device(_dev)	\
> > -	container_of(_dev, struct thermal_cooling_device, device)
> > -
> > -static ssize_t
> > -thermal_cooling_device_type_show(struct device *dev,
> > -				 struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > -
> > -	return sprintf(buf, "%s\n", cdev->type);
> > -}
> > -
> > -static ssize_t
> > -thermal_cooling_device_max_state_show(struct device *dev,
> > -				      struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > -	unsigned long state;
> > -	int ret;
> > -
> > -	ret = cdev->ops->get_max_state(cdev, &state);
> > -	if (ret)
> > -		return ret;
> > -	return sprintf(buf, "%ld\n", state);
> > -}
> > -
> > -static ssize_t
> > -thermal_cooling_device_cur_state_show(struct device *dev,
> > -				      struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > -	unsigned long state;
> > -	int ret;
> > -
> > -	ret = cdev->ops->get_cur_state(cdev, &state);
> > -	if (ret)
> > -		return ret;
> > -	return sprintf(buf, "%ld\n", state);
> > -}
> > -
> > -static ssize_t
> > -thermal_cooling_device_cur_state_store(struct device *dev,
> > -				       struct device_attribute *attr,
> > -				       const char *buf, size_t count)
> > -{
> > -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > -	unsigned long state;
> > -	int result;
> > -
> > -	if (!sscanf(buf, "%ld\n", &state))
> > -		return -EINVAL;
> > -
> > -	if ((long)state < 0)
> > -		return -EINVAL;
> > -
> > -	result = cdev->ops->set_cur_state(cdev, state);
> > -	if (result)
> > -		return result;
> > -	return count;
> > -}
> > -
> > -static struct device_attribute dev_attr_cdev_type =
> > -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> > -static DEVICE_ATTR(max_state, 0444,
> > -		   thermal_cooling_device_max_state_show, NULL);
> > -static DEVICE_ATTR(cur_state, 0644,
> > -		   thermal_cooling_device_cur_state_show,
> > -		   thermal_cooling_device_cur_state_store);
> > -
> > -static ssize_t
> > -thermal_cooling_device_trip_point_show(struct device *dev,
> > -				       struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_instance *instance;
> > -
> > -	instance =
> > -	    container_of(attr, struct thermal_instance, attr);
> > -
> > -	if (instance->trip == THERMAL_TRIPS_NONE)
> > -		return sprintf(buf, "-1\n");
> > -	else
> > -		return sprintf(buf, "%d\n", instance->trip);
> > -}
> > -
> > -/* Device management */
> > -
> > -#if defined(CONFIG_THERMAL_HWMON)
> > -
> > -/* hwmon sys I/F */
> > -#include <linux/hwmon.h>
> > -
> > -/* thermal zone devices with the same type share one hwmon device */
> > -struct thermal_hwmon_device {
> > -	char type[THERMAL_NAME_LENGTH];
> > -	struct device *device;
> > -	int count;
> > -	struct list_head tz_list;
> > -	struct list_head node;
> > -};
> > -
> > -struct thermal_hwmon_attr {
> > -	struct device_attribute attr;
> > -	char name[16];
> > -};
> > -
> > -/* one temperature input for each thermal zone */
> > -struct thermal_hwmon_temp {
> > -	struct list_head hwmon_node;
> > -	struct thermal_zone_device *tz;
> > -	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> > -	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> > -};
> > -
> > -static LIST_HEAD(thermal_hwmon_list);
> > -
> > -static ssize_t
> > -name_show(struct device *dev, struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> > -	return sprintf(buf, "%s\n", hwmon->type);
> > -}
> > -static DEVICE_ATTR(name, 0444, name_show, NULL);
> > -
> > -static ssize_t
> > -temp_input_show(struct device *dev, struct device_attribute *attr, char
> > *buf)
> > -{
> > -	long temperature;
> > -	int ret;
> > -	struct thermal_hwmon_attr *hwmon_attr
> > -			= container_of(attr, struct thermal_hwmon_attr,
> > attr);
> > -	struct thermal_hwmon_temp *temp
> > -			= container_of(hwmon_attr, struct
> > thermal_hwmon_temp,
> > -				       temp_input);
> > -	struct thermal_zone_device *tz = temp->tz;
> > -
> > -	ret = thermal_zone_get_temp(tz, &temperature);
> > -
> > -	if (ret)
> > -		return ret;
> > -
> > -	return sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -static ssize_t
> > -temp_crit_show(struct device *dev, struct device_attribute *attr,
> > -		char *buf)
> > -{
> > -	struct thermal_hwmon_attr *hwmon_attr
> > -			= container_of(attr, struct thermal_hwmon_attr,
> > attr);
> > -	struct thermal_hwmon_temp *temp
> > -			= container_of(hwmon_attr, struct
> > thermal_hwmon_temp,
> > -				       temp_crit);
> > -	struct thermal_zone_device *tz = temp->tz;
> > -	long temperature;
> > -	int ret;
> > -
> > -	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> > -	if (ret)
> > -		return ret;
> > -
> > -	return sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -
> > -static struct thermal_hwmon_device *
> > -thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> > -{
> > -	struct thermal_hwmon_device *hwmon;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> > -		if (!strcmp(hwmon->type, tz->type)) {
> > -			mutex_unlock(&thermal_list_lock);
> > -			return hwmon;
> > -		}
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	return NULL;
> > -}
> > -
> > -/* Find the temperature input matching a given thermal zone */
> > -static struct thermal_hwmon_temp *
> > -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device
> > *hwmon,
> > -			  const struct thermal_zone_device *tz)
> > -{
> > -	struct thermal_hwmon_temp *temp;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> > -		if (temp->tz == tz) {
> > -			mutex_unlock(&thermal_list_lock);
> > -			return temp;
> > -		}
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	return NULL;
> > -}
> > -
> > -static int
> > -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> > -{
> > -	struct thermal_hwmon_device *hwmon;
> > -	struct thermal_hwmon_temp *temp;
> > -	int new_hwmon_device = 1;
> > -	int result;
> > -
> > -	hwmon = thermal_hwmon_lookup_by_type(tz);
> > -	if (hwmon) {
> > -		new_hwmon_device = 0;
> > -		goto register_sys_interface;
> > -	}
> > -
> > -	hwmon = kzalloc(sizeof(struct thermal_hwmon_device),
> > GFP_KERNEL);
> > -	if (!hwmon)
> > -		return -ENOMEM;
> > -
> > -	INIT_LIST_HEAD(&hwmon->tz_list);
> > -	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> > -	hwmon->device = hwmon_device_register(NULL);
> > -	if (IS_ERR(hwmon->device)) {
> > -		result = PTR_ERR(hwmon->device);
> > -		goto free_mem;
> > -	}
> > -	dev_set_drvdata(hwmon->device, hwmon);
> > -	result = device_create_file(hwmon->device, &dev_attr_name);
> > -	if (result)
> > -		goto free_mem;
> > -
> > - register_sys_interface:
> > -	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> > -	if (!temp) {
> > -		result = -ENOMEM;
> > -		goto unregister_name;
> > -	}
> > -
> > -	temp->tz = tz;
> > -	hwmon->count++;
> > -
> > -	snprintf(temp->temp_input.name, sizeof(temp-
> > >temp_input.name),
> > -		 "temp%d_input", hwmon->count);
> > -	temp->temp_input.attr.attr.name = temp->temp_input.name;
> > -	temp->temp_input.attr.attr.mode = 0444;
> > -	temp->temp_input.attr.show = temp_input_show;
> > -	sysfs_attr_init(&temp->temp_input.attr.attr);
> > -	result = device_create_file(hwmon->device, &temp-
> > >temp_input.attr);
> > -	if (result)
> > -		goto free_temp_mem;
> > -
> > -	if (tz->ops->get_crit_temp) {
> > -		unsigned long temperature;
> > -		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> > -			snprintf(temp->temp_crit.name,
> > -				 sizeof(temp->temp_crit.name),
> > -				"temp%d_crit", hwmon->count);
> > -			temp->temp_crit.attr.attr.name = temp-
> > >temp_crit.name;
> > -			temp->temp_crit.attr.attr.mode = 0444;
> > -			temp->temp_crit.attr.show = temp_crit_show;
> > -			sysfs_attr_init(&temp->temp_crit.attr.attr);
> > -			result = device_create_file(hwmon->device,
> > -						    &temp->temp_crit.attr);
> > -			if (result)
> > -				goto unregister_input;
> > -		}
> > -	}
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	if (new_hwmon_device)
> > -		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> > -	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	return 0;
> > -
> > - unregister_input:
> > -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> > - free_temp_mem:
> > -	kfree(temp);
> > - unregister_name:
> > -	if (new_hwmon_device) {
> > -		device_remove_file(hwmon->device, &dev_attr_name);
> > -		hwmon_device_unregister(hwmon->device);
> > -	}
> > - free_mem:
> > -	if (new_hwmon_device)
> > -		kfree(hwmon);
> > -
> > -	return result;
> > -}
> > -
> > -static void
> > -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> > -{
> > -	struct thermal_hwmon_device *hwmon;
> > -	struct thermal_hwmon_temp *temp;
> > -
> > -	hwmon = thermal_hwmon_lookup_by_type(tz);
> > -	if (unlikely(!hwmon)) {
> > -		/* Should never happen... */
> > -		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> > -		return;
> > -	}
> > -
> > -	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> > -	if (unlikely(!temp)) {
> > -		/* Should never happen... */
> > -		dev_dbg(&tz->device, "temperature input lookup
> > failed!\n");
> > -		return;
> > -	}
> > -
> > -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> > -	if (tz->ops->get_crit_temp)
> > -		device_remove_file(hwmon->device, &temp-
> > >temp_crit.attr);
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_del(&temp->hwmon_node);
> > -	kfree(temp);
> > -	if (!list_empty(&hwmon->tz_list)) {
> > -		mutex_unlock(&thermal_list_lock);
> > -		return;
> > -	}
> > -	list_del(&hwmon->node);
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	device_remove_file(hwmon->device, &dev_attr_name);
> > -	hwmon_device_unregister(hwmon->device);
> > -	kfree(hwmon);
> > -}
> > -#else
> > -static int
> > -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> > -{
> > -	return 0;
> > -}
> > -
> > -static void
> > -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> > -{
> > -}
> > -#endif
> > -
> > -/**
> > - * thermal_zone_bind_cooling_device - bind a cooling device to a thermal
> > zone
> > - * @tz:		thermal zone device
> > - * @trip:	indicates which trip point the cooling devices is
> > - *		associated with in this thermal zone.
> > - * @cdev:	thermal cooling device
> > - *
> > - * This function is usually called in the thermal zone device .bind callback.
> > - */
> > -int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> > -				     int trip,
> > -				     struct thermal_cooling_device *cdev,
> > -				     unsigned long upper, unsigned long lower)
> > -{
> > -	struct thermal_instance *dev;
> > -	struct thermal_instance *pos;
> > -	struct thermal_zone_device *pos1;
> > -	struct thermal_cooling_device *pos2;
> > -	unsigned long max_state;
> > -	int result;
> > -
> > -	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> > -		return -EINVAL;
> > -
> > -	list_for_each_entry(pos1, &thermal_tz_list, node) {
> > -		if (pos1 == tz)
> > -			break;
> > -	}
> > -	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> > -		if (pos2 == cdev)
> > -			break;
> > -	}
> > -
> > -	if (tz != pos1 || cdev != pos2)
> > -		return -EINVAL;
> > -
> > -	cdev->ops->get_max_state(cdev, &max_state);
> > -
> > -	/* lower default 0, upper default max_state */
> > -	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> > -	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> > -
> > -	if (lower > upper || upper > max_state)
> > -		return -EINVAL;
> > -
> > -	dev =
> > -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> > -	if (!dev)
> > -		return -ENOMEM;
> > -	dev->tz = tz;
> > -	dev->cdev = cdev;
> > -	dev->trip = trip;
> > -	dev->upper = upper;
> > -	dev->lower = lower;
> > -	dev->target = THERMAL_NO_TARGET;
> > -
> > -	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> > -	if (result)
> > -		goto free_mem;
> > -
> > -	sprintf(dev->name, "cdev%d", dev->id);
> > -	result =
> > -	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev-
> > >name);
> > -	if (result)
> > -		goto release_idr;
> > -
> > -	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> > -	sysfs_attr_init(&dev->attr.attr);
> > -	dev->attr.attr.name = dev->attr_name;
> > -	dev->attr.attr.mode = 0444;
> > -	dev->attr.show = thermal_cooling_device_trip_point_show;
> > -	result = device_create_file(&tz->device, &dev->attr);
> > -	if (result)
> > -		goto remove_symbol_link;
> > -
> > -	mutex_lock(&tz->lock);
> > -	mutex_lock(&cdev->lock);
> > -	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> > -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > -		result = -EEXIST;
> > -		break;
> > -	}
> > -	if (!result) {
> > -		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> > -		list_add_tail(&dev->cdev_node, &cdev-
> > >thermal_instances);
> > -	}
> > -	mutex_unlock(&cdev->lock);
> > -	mutex_unlock(&tz->lock);
> > -
> > -	if (!result)
> > -		return 0;
> > -
> > -	device_remove_file(&tz->device, &dev->attr);
> > -remove_symbol_link:
> > -	sysfs_remove_link(&tz->device.kobj, dev->name);
> > -release_idr:
> > -	release_idr(&tz->idr, &tz->lock, dev->id);
> > -free_mem:
> > -	kfree(dev);
> > -	return result;
> > -}
> > -EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> > -
> > -/**
> > - * thermal_zone_unbind_cooling_device - unbind a cooling device from a
> > thermal zone
> > - * @tz:		thermal zone device
> > - * @trip:	indicates which trip point the cooling devices is
> > - *		associated with in this thermal zone.
> > - * @cdev:	thermal cooling device
> > - *
> > - * This function is usually called in the thermal zone device .unbind callback.
> > - */
> > -int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> > -				       int trip,
> > -				       struct thermal_cooling_device *cdev)
> > -{
> > -	struct thermal_instance *pos, *next;
> > -
> > -	mutex_lock(&tz->lock);
> > -	mutex_lock(&cdev->lock);
> > -	list_for_each_entry_safe(pos, next, &tz->thermal_instances,
> > tz_node) {
> > -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > -			list_del(&pos->tz_node);
> > -			list_del(&pos->cdev_node);
> > -			mutex_unlock(&cdev->lock);
> > -			mutex_unlock(&tz->lock);
> > -			goto unbind;
> > -		}
> > -	}
> > -	mutex_unlock(&cdev->lock);
> > -	mutex_unlock(&tz->lock);
> > -
> > -	return -ENODEV;
> > -
> > -unbind:
> > -	device_remove_file(&tz->device, &pos->attr);
> > -	sysfs_remove_link(&tz->device.kobj, pos->name);
> > -	release_idr(&tz->idr, &tz->lock, pos->id);
> > -	kfree(pos);
> > -	return 0;
> > -}
> > -EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> > -
> > -static void thermal_release(struct device *dev)
> > -{
> > -	struct thermal_zone_device *tz;
> > -	struct thermal_cooling_device *cdev;
> > -
> > -	if (!strncmp(dev_name(dev), "thermal_zone",
> > -		     sizeof("thermal_zone") - 1)) {
> > -		tz = to_thermal_zone(dev);
> > -		kfree(tz);
> > -	} else {
> > -		cdev = to_cooling_device(dev);
> > -		kfree(cdev);
> > -	}
> > -}
> > -
> > -static struct class thermal_class = {
> > -	.name = "thermal",
> > -	.dev_release = thermal_release,
> > -};
> > -
> > -/**
> > - * thermal_cooling_device_register - register a new thermal cooling device
> > - * @type:	the thermal cooling device type.
> > - * @devdata:	device private data.
> > - * @ops:		standard thermal cooling devices callbacks.
> > - */
> > -struct thermal_cooling_device *
> > -thermal_cooling_device_register(char *type, void *devdata,
> > -				const struct thermal_cooling_device_ops
> > *ops)
> > -{
> > -	struct thermal_cooling_device *cdev;
> > -	int result;
> > -
> > -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> > -	    !ops->set_cur_state)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> > -	if (!cdev)
> > -		return ERR_PTR(-ENOMEM);
> > -
> > -	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> > -	if (result) {
> > -		kfree(cdev);
> > -		return ERR_PTR(result);
> > -	}
> > -
> > -	strcpy(cdev->type, type ? : "");
> > -	mutex_init(&cdev->lock);
> > -	INIT_LIST_HEAD(&cdev->thermal_instances);
> > -	cdev->ops = ops;
> > -	cdev->updated = true;
> > -	cdev->device.class = &thermal_class;
> > -	cdev->devdata = devdata;
> > -	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> > -	result = device_register(&cdev->device);
> > -	if (result) {
> > -		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev-
> > >id);
> > -		kfree(cdev);
> > -		return ERR_PTR(result);
> > -	}
> > -
> > -	/* sys I/F */
> > -	if (type) {
> > -		result = device_create_file(&cdev->device,
> > &dev_attr_cdev_type);
> > -		if (result)
> > -			goto unregister;
> > -	}
> > -
> > -	result = device_create_file(&cdev->device, &dev_attr_max_state);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	/* Add 'this' new cdev to the global cdev list */
> > -	mutex_lock(&thermal_list_lock);
> > -	list_add(&cdev->node, &thermal_cdev_list);
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	/* Update binding information for 'this' new cdev */
> > -	bind_cdev(cdev);
> > -
> > -	return cdev;
> > -
> > -unregister:
> > -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > -	device_unregister(&cdev->device);
> > -	return ERR_PTR(result);
> > -}
> > -EXPORT_SYMBOL(thermal_cooling_device_register);
> > -
> > -/**
> > - * thermal_cooling_device_unregister - removes the registered thermal
> > cooling device
> > - * @cdev:	the thermal cooling device to remove.
> > - *
> > - * thermal_cooling_device_unregister() must be called when the device is
> > no
> > - * longer needed.
> > - */
> > -void thermal_cooling_device_unregister(struct thermal_cooling_device
> > *cdev)
> > -{
> > -	int i;
> > -	const struct thermal_zone_params *tzp;
> > -	struct thermal_zone_device *tz;
> > -	struct thermal_cooling_device *pos = NULL;
> > -
> > -	if (!cdev)
> > -		return;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_for_each_entry(pos, &thermal_cdev_list, node)
> > -	    if (pos == cdev)
> > -		break;
> > -	if (pos != cdev) {
> > -		/* thermal cooling device not found */
> > -		mutex_unlock(&thermal_list_lock);
> > -		return;
> > -	}
> > -	list_del(&cdev->node);
> > -
> > -	/* Unbind all thermal zones associated with 'this' cdev */
> > -	list_for_each_entry(tz, &thermal_tz_list, node) {
> > -		if (tz->ops->unbind) {
> > -			tz->ops->unbind(tz, cdev);
> > -			continue;
> > -		}
> > -
> > -		if (!tz->tzp || !tz->tzp->tbp)
> > -			continue;
> > -
> > -		tzp = tz->tzp;
> > -		for (i = 0; i < tzp->num_tbps; i++) {
> > -			if (tzp->tbp[i].cdev == cdev) {
> > -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> > -				tzp->tbp[i].cdev = NULL;
> > -			}
> > -		}
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	if (cdev->type[0])
> > -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> > -	device_remove_file(&cdev->device, &dev_attr_max_state);
> > -	device_remove_file(&cdev->device, &dev_attr_cur_state);
> > -
> > -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > -	device_unregister(&cdev->device);
> > -	return;
> > -}
> > -EXPORT_SYMBOL(thermal_cooling_device_unregister);
> > -
> > -void thermal_cdev_update(struct thermal_cooling_device *cdev)
> > -{
> > -	struct thermal_instance *instance;
> > -	unsigned long target = 0;
> > -
> > -	/* cooling device is updated*/
> > -	if (cdev->updated)
> > -		return;
> > -
> > -	mutex_lock(&cdev->lock);
> > -	/* Make sure cdev enters the deepest cooling state */
> > -	list_for_each_entry(instance, &cdev->thermal_instances,
> > cdev_node) {
> > -		if (instance->target == THERMAL_NO_TARGET)
> > -			continue;
> > -		if (instance->target > target)
> > -			target = instance->target;
> > -	}
> > -	mutex_unlock(&cdev->lock);
> > -	cdev->ops->set_cur_state(cdev, target);
> > -	cdev->updated = true;
> > -}
> > -EXPORT_SYMBOL(thermal_cdev_update);
> > -
> > -/**
> > - * notify_thermal_framework - Sensor drivers use this API to notify
> > framework
> > - * @tz:		thermal zone device
> > - * @trip:	indicates which trip point has been crossed
> > - *
> > - * This function handles the trip events from sensor drivers. It starts
> > - * throttling the cooling devices according to the policy configured.
> > - * For CRITICAL and HOT trip points, this notifies the respective drivers,
> > - * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> > - * The throttling policy is based on the configured platform data; if no
> > - * platform data is provided, this uses the step_wise throttling policy.
> > - */
> > -void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> > -{
> > -	handle_thermal_trip(tz, trip);
> > -}
> > -EXPORT_SYMBOL(notify_thermal_framework);
> > -
> > -/**
> > - * create_trip_attrs - create attributes for trip points
> > - * @tz:		the thermal zone device
> > - * @mask:	Writeable trip point bitmap.
> > - */
> > -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> > -{
> > -	int indx;
> > -	int size = sizeof(struct thermal_attr) * tz->trips;
> > -
> > -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> > -	if (!tz->trip_type_attrs)
> > -		return -ENOMEM;
> > -
> > -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> > -	if (!tz->trip_temp_attrs) {
> > -		kfree(tz->trip_type_attrs);
> > -		return -ENOMEM;
> > -	}
> > -
> > -	if (tz->ops->get_trip_hyst) {
> > -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> > -		if (!tz->trip_hyst_attrs) {
> > -			kfree(tz->trip_type_attrs);
> > -			kfree(tz->trip_temp_attrs);
> > -			return -ENOMEM;
> > -		}
> > -	}
> > -
> > -
> > -	for (indx = 0; indx < tz->trips; indx++) {
> > -		/* create trip type attribute */
> > -		snprintf(tz->trip_type_attrs[indx].name,
> > THERMAL_NAME_LENGTH,
> > -			 "trip_point_%d_type", indx);
> > -
> > -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> > -		tz->trip_type_attrs[indx].attr.attr.name =
> > -						tz-
> > >trip_type_attrs[indx].name;
> > -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> > -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> > -
> > -		device_create_file(&tz->device,
> > -				   &tz->trip_type_attrs[indx].attr);
> > -
> > -		/* create trip temp attribute */
> > -		snprintf(tz->trip_temp_attrs[indx].name,
> > THERMAL_NAME_LENGTH,
> > -			 "trip_point_%d_temp", indx);
> > -
> > -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> > -		tz->trip_temp_attrs[indx].attr.attr.name =
> > -						tz-
> > >trip_temp_attrs[indx].name;
> > -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> > -		tz->trip_temp_attrs[indx].attr.show =
> > trip_point_temp_show;
> > -		if (mask & (1 << indx)) {
> > -			tz->trip_temp_attrs[indx].attr.attr.mode |=
> > S_IWUSR;
> > -			tz->trip_temp_attrs[indx].attr.store =
> > -
> > 	trip_point_temp_store;
> > -		}
> > -
> > -		device_create_file(&tz->device,
> > -				   &tz->trip_temp_attrs[indx].attr);
> > -
> > -		/* create Optional trip hyst attribute */
> > -		if (!tz->ops->get_trip_hyst)
> > -			continue;
> > -		snprintf(tz->trip_hyst_attrs[indx].name,
> > THERMAL_NAME_LENGTH,
> > -			 "trip_point_%d_hyst", indx);
> > -
> > -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> > -		tz->trip_hyst_attrs[indx].attr.attr.name =
> > -					tz->trip_hyst_attrs[indx].name;
> > -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> > -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> > -		if (tz->ops->set_trip_hyst) {
> > -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> > -			tz->trip_hyst_attrs[indx].attr.store =
> > -					trip_point_hyst_store;
> > -		}
> > -
> > -		device_create_file(&tz->device,
> > -				   &tz->trip_hyst_attrs[indx].attr);
> > -	}
> > -	return 0;
> > -}
> > -
> > -static void remove_trip_attrs(struct thermal_zone_device *tz)
> > -{
> > -	int indx;
> > -
> > -	for (indx = 0; indx < tz->trips; indx++) {
> > -		device_remove_file(&tz->device,
> > -				   &tz->trip_type_attrs[indx].attr);
> > -		device_remove_file(&tz->device,
> > -				   &tz->trip_temp_attrs[indx].attr);
> > -		if (tz->ops->get_trip_hyst)
> > -			device_remove_file(&tz->device,
> > -				  &tz->trip_hyst_attrs[indx].attr);
> > -	}
> > -	kfree(tz->trip_type_attrs);
> > -	kfree(tz->trip_temp_attrs);
> > -	kfree(tz->trip_hyst_attrs);
> > -}
> > -
> > -/**
> > - * thermal_zone_device_register - register a new thermal zone device
> > - * @type:	the thermal zone device type
> > - * @trips:	the number of trip points the thermal zone support
> > - * @mask:	a bit string indicating the writeablility of trip points
> > - * @devdata:	private device data
> > - * @ops:	standard thermal zone device callbacks
> > - * @tzp:	thermal zone platform parameters
> > - * @passive_delay: number of milliseconds to wait between polls when
> > - *		   performing passive cooling
> > - * @polling_delay: number of milliseconds to wait between polls when
> > checking
> > - *		   whether trip points have been crossed (0 for interrupt
> > - *		   driven systems)
> > - *
> > - * thermal_zone_device_unregister() must be called when the device is no
> > - * longer needed. The passive cooling depends on the .get_trend() return
> > value.
> > - */
> > -struct thermal_zone_device *thermal_zone_device_register(const char
> > *type,
> > -	int trips, int mask, void *devdata,
> > -	const struct thermal_zone_device_ops *ops,
> > -	const struct thermal_zone_params *tzp,
> > -	int passive_delay, int polling_delay)
> > -{
> > -	struct thermal_zone_device *tz;
> > -	enum thermal_trip_type trip_type;
> > -	int result;
> > -	int count;
> > -	int passive = 0;
> > -
> > -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	if (!ops || !ops->get_temp)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	if (trips > 0 && !ops->get_trip_type)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> > -	if (!tz)
> > -		return ERR_PTR(-ENOMEM);
> > -
> > -	INIT_LIST_HEAD(&tz->thermal_instances);
> > -	idr_init(&tz->idr);
> > -	mutex_init(&tz->lock);
> > -	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> > -	if (result) {
> > -		kfree(tz);
> > -		return ERR_PTR(result);
> > -	}
> > -
> > -	strcpy(tz->type, type ? : "");
> > -	tz->ops = ops;
> > -	tz->tzp = tzp;
> > -	tz->device.class = &thermal_class;
> > -	tz->devdata = devdata;
> > -	tz->trips = trips;
> > -	tz->passive_delay = passive_delay;
> > -	tz->polling_delay = polling_delay;
> > -
> > -	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> > -	result = device_register(&tz->device);
> > -	if (result) {
> > -		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > -		kfree(tz);
> > -		return ERR_PTR(result);
> > -	}
> > -
> > -	/* sys I/F */
> > -	if (type) {
> > -		result = device_create_file(&tz->device, &dev_attr_type);
> > -		if (result)
> > -			goto unregister;
> > -	}
> > -
> > -	result = device_create_file(&tz->device, &dev_attr_temp);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	if (ops->get_mode) {
> > -		result = device_create_file(&tz->device, &dev_attr_mode);
> > -		if (result)
> > -			goto unregister;
> > -	}
> > -
> > -	result = create_trip_attrs(tz, mask);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	for (count = 0; count < trips; count++) {
> > -		tz->ops->get_trip_type(tz, count, &trip_type);
> > -		if (trip_type == THERMAL_TRIP_PASSIVE)
> > -			passive = 1;
> > -	}
> > -
> > -	if (!passive) {
> > -		result = device_create_file(&tz->device, &dev_attr_passive);
> > -		if (result)
> > -			goto unregister;
> > -	}
> > -
> > -#ifdef CONFIG_THERMAL_EMULATION
> > -	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> > -	if (result)
> > -		goto unregister;
> > -#endif
> > -	/* Create policy attribute */
> > -	result = device_create_file(&tz->device, &dev_attr_policy);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	/* Update 'this' zone's governor information */
> > -	mutex_lock(&thermal_governor_lock);
> > -
> > -	if (tz->tzp)
> > -		tz->governor = __find_governor(tz->tzp->governor_name);
> > -	else
> > -		tz->governor =
> > __find_governor(DEFAULT_THERMAL_GOVERNOR);
> > -
> > -	mutex_unlock(&thermal_governor_lock);
> > -
> > -	result = thermal_add_hwmon_sysfs(tz);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_add_tail(&tz->node, &thermal_tz_list);
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	/* Bind cooling devices for this zone */
> > -	bind_tz(tz);
> > -
> > -	INIT_DELAYED_WORK(&(tz->poll_queue),
> > thermal_zone_device_check);
> > -
> > -	thermal_zone_device_update(tz);
> > -
> > -	if (!result)
> > -		return tz;
> > -
> > -unregister:
> > -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > -	device_unregister(&tz->device);
> > -	return ERR_PTR(result);
> > -}
> > -EXPORT_SYMBOL(thermal_zone_device_register);
> > -
> > -/**
> > - * thermal_device_unregister - removes the registered thermal zone device
> > - * @tz: the thermal zone device to remove
> > - */
> > -void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> > -{
> > -	int i;
> > -	const struct thermal_zone_params *tzp;
> > -	struct thermal_cooling_device *cdev;
> > -	struct thermal_zone_device *pos = NULL;
> > -
> > -	if (!tz)
> > -		return;
> > -
> > -	tzp = tz->tzp;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_for_each_entry(pos, &thermal_tz_list, node)
> > -	    if (pos == tz)
> > -		break;
> > -	if (pos != tz) {
> > -		/* thermal zone device not found */
> > -		mutex_unlock(&thermal_list_lock);
> > -		return;
> > -	}
> > -	list_del(&tz->node);
> > -
> > -	/* Unbind all cdevs associated with 'this' thermal zone */
> > -	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > -		if (tz->ops->unbind) {
> > -			tz->ops->unbind(tz, cdev);
> > -			continue;
> > -		}
> > -
> > -		if (!tzp || !tzp->tbp)
> > -			break;
> > -
> > -		for (i = 0; i < tzp->num_tbps; i++) {
> > -			if (tzp->tbp[i].cdev == cdev) {
> > -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> > -				tzp->tbp[i].cdev = NULL;
> > -			}
> > -		}
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	thermal_zone_device_set_polling(tz, 0);
> > -
> > -	if (tz->type[0])
> > -		device_remove_file(&tz->device, &dev_attr_type);
> > -	device_remove_file(&tz->device, &dev_attr_temp);
> > -	if (tz->ops->get_mode)
> > -		device_remove_file(&tz->device, &dev_attr_mode);
> > -	device_remove_file(&tz->device, &dev_attr_policy);
> > -	remove_trip_attrs(tz);
> > -	tz->governor = NULL;
> > -
> > -	thermal_remove_hwmon_sysfs(tz);
> > -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > -	idr_destroy(&tz->idr);
> > -	mutex_destroy(&tz->lock);
> > -	device_unregister(&tz->device);
> > -	return;
> > -}
> > -EXPORT_SYMBOL(thermal_zone_device_unregister);
> > -
> > -#ifdef CONFIG_NET
> > -static struct genl_family thermal_event_genl_family = {
> > -	.id = GENL_ID_GENERATE,
> > -	.name = THERMAL_GENL_FAMILY_NAME,
> > -	.version = THERMAL_GENL_VERSION,
> > -	.maxattr = THERMAL_GENL_ATTR_MAX,
> > -};
> > -
> > -static struct genl_multicast_group thermal_event_mcgrp = {
> > -	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> > -};
> > -
> > -int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> > -					enum events event)
> > -{
> > -	struct sk_buff *skb;
> > -	struct nlattr *attr;
> > -	struct thermal_genl_event *thermal_event;
> > -	void *msg_header;
> > -	int size;
> > -	int result;
> > -	static unsigned int thermal_event_seqnum;
> > -
> > -	if (!tz)
> > -		return -EINVAL;
> > -
> > -	/* allocate memory */
> > -	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> > -	       nla_total_size(0);
> > -
> > -	skb = genlmsg_new(size, GFP_ATOMIC);
> > -	if (!skb)
> > -		return -ENOMEM;
> > -
> > -	/* add the genetlink message header */
> > -	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> > -				 &thermal_event_genl_family, 0,
> > -				 THERMAL_GENL_CMD_EVENT);
> > -	if (!msg_header) {
> > -		nlmsg_free(skb);
> > -		return -ENOMEM;
> > -	}
> > -
> > -	/* fill the data */
> > -	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> > -			   sizeof(struct thermal_genl_event));
> > -
> > -	if (!attr) {
> > -		nlmsg_free(skb);
> > -		return -EINVAL;
> > -	}
> > -
> > -	thermal_event = nla_data(attr);
> > -	if (!thermal_event) {
> > -		nlmsg_free(skb);
> > -		return -EINVAL;
> > -	}
> > -
> > -	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> > -
> > -	thermal_event->orig = tz->id;
> > -	thermal_event->event = event;
> > -
> > -	/* send multicast genetlink message */
> > -	result = genlmsg_end(skb, msg_header);
> > -	if (result < 0) {
> > -		nlmsg_free(skb);
> > -		return result;
> > -	}
> > -
> > -	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id,
> > GFP_ATOMIC);
> > -	if (result)
> > -		dev_err(&tz->device, "Failed to send netlink event:%d",
> > result);
> > -
> > -	return result;
> > -}
> > -EXPORT_SYMBOL(thermal_generate_netlink_event);
> > -
> > -static int genetlink_init(void)
> > -{
> > -	int result;
> > -
> > -	result = genl_register_family(&thermal_event_genl_family);
> > -	if (result)
> > -		return result;
> > -
> > -	result = genl_register_mc_group(&thermal_event_genl_family,
> > -					&thermal_event_mcgrp);
> > -	if (result)
> > -		genl_unregister_family(&thermal_event_genl_family);
> > -	return result;
> > -}
> > -
> > -static void genetlink_exit(void)
> > -{
> > -	genl_unregister_family(&thermal_event_genl_family);
> > -}
> > -#else /* !CONFIG_NET */
> > -static inline int genetlink_init(void) { return 0; }
> > -static inline void genetlink_exit(void) {}
> > -#endif /* !CONFIG_NET */
> > -
> > -static int __init thermal_init(void)
> > -{
> > -	int result = 0;
> > -
> > -	result = class_register(&thermal_class);
> > -	if (result) {
> > -		idr_destroy(&thermal_tz_idr);
> > -		idr_destroy(&thermal_cdev_idr);
> > -		mutex_destroy(&thermal_idr_lock);
> > -		mutex_destroy(&thermal_list_lock);
> > -		return result;
> > -	}
> > -	result = genetlink_init();
> > -	return result;
> > -}
> > -
> > -static void __exit thermal_exit(void)
> > -{
> > -	class_unregister(&thermal_class);
> > -	idr_destroy(&thermal_tz_idr);
> > -	idr_destroy(&thermal_cdev_idr);
> > -	mutex_destroy(&thermal_idr_lock);
> > -	mutex_destroy(&thermal_list_lock);
> > -	genetlink_exit();
> > -}
> > -
> > -fs_initcall(thermal_init);
> > -module_exit(thermal_exit);
> > --
> > 1.7.9.5
> 



^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys module
  2013-03-26 16:53   ` R, Durgadoss
@ 2013-03-26 17:12     ` Zhang Rui
  0 siblings, 0 replies; 23+ messages in thread
From: Zhang Rui @ 2013-03-26 17:12 UTC (permalink / raw)
  To: R, Durgadoss; +Cc: linux-pm, linux-kernel, amit.daniel, andi

On Tue, 2013-03-26 at 10:53 -0600, R, Durgadoss wrote:
> Hi Rui,
> 
> > -----Original Message-----
> > From: Zhang, Rui
> > Sent: Tuesday, March 26, 2013 9:56 PM
> > To: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org
> > Cc: amit.daniel@samsung.com; R, Durgadoss; andi@lisas.de; Zhang, Rui
> > Subject: [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys
> > module
> > 
> > Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> > ---
> >  drivers/thermal/Makefile       |    6 +++---
> >  drivers/thermal/fair_share.c   |   15 ++-------------
> >  drivers/thermal/step_wise.c    |   16 ++--------------
> >  drivers/thermal/thermal_core.c |   36
> > ++++++++++++++++++++++++++++++++++--
> >  drivers/thermal/thermal_core.h |   25 +++++++++++++++++++++++++
> >  drivers/thermal/user_space.c   |   15 ++-------------
> >  include/linux/thermal.h        |    1 -
> >  7 files changed, 68 insertions(+), 46 deletions(-)
> > 
> > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> > index b2009bd..b7fffc7 100644
> > --- a/drivers/thermal/Makefile
> > +++ b/drivers/thermal/Makefile
> > @@ -6,9 +6,9 @@ obj-$(CONFIG_THERMAL)		+= thermal_sys.o
> >  thermal_sys-y			+= thermal_core.o
> > 
> >  # governors
> > -obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> > -obj-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
> > -obj-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
> > +thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+=
> > fair_share.o
> > +thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
> > +thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE)	+=
> > user_space.o
> > 
> >  # cpufreq cooling
> >  obj-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
> > diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
> > index 792479f..944ba2f 100644
> > --- a/drivers/thermal/fair_share.c
> > +++ b/drivers/thermal/fair_share.c
> > @@ -22,9 +22,6 @@
> >   *
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > ~~~~~~~~~~~~~~~~
> >   */
> > 
> > -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > -
> > -#include <linux/module.h>
> >  #include <linux/thermal.h>
> > 
> >  #include "thermal_core.h"
> > @@ -111,23 +108,15 @@ static int fair_share_throttle(struct
> > thermal_zone_device *tz, int trip)
> >  static struct thermal_governor thermal_gov_fair_share = {
> >  	.name		= "fair_share",
> >  	.throttle	= fair_share_throttle,
> > -	.owner		= THIS_MODULE,
> >  };
> > 
> > -static int __init thermal_gov_fair_share_init(void)
> > +int thermal_gov_fair_share_register(void)
> >  {
> >  	return thermal_register_governor(&thermal_gov_fair_share);
> >  }
> > 
> > -static void __exit thermal_gov_fair_share_exit(void)
> > +void thermal_gov_fair_share_unregister(void)
> >  {
> >  	thermal_unregister_governor(&thermal_gov_fair_share);
> >  }
> > 
> > -/* This should load after thermal framework */
> > -fs_initcall(thermal_gov_fair_share_init);
> > -module_exit(thermal_gov_fair_share_exit);
> > -
> > -MODULE_AUTHOR("Durgadoss R");
> > -MODULE_DESCRIPTION("A simple weight based thermal throttling
> > governor");
> > -MODULE_LICENSE("GPL");
> > diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
> > index 407cde3..a6c9666 100644
> > --- a/drivers/thermal/step_wise.c
> > +++ b/drivers/thermal/step_wise.c
> > @@ -22,9 +22,6 @@
> >   *
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > ~~~~~~~~~~~~~~~~
> >   */
> > 
> > -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > -
> > -#include <linux/module.h>
> >  #include <linux/thermal.h>
> > 
> >  #include "thermal_core.h"
> > @@ -180,23 +177,14 @@ static int step_wise_throttle(struct
> > thermal_zone_device *tz, int trip)
> >  static struct thermal_governor thermal_gov_step_wise = {
> >  	.name		= "step_wise",
> >  	.throttle	= step_wise_throttle,
> > -	.owner		= THIS_MODULE,
> >  };
> > 
> > -static int __init thermal_gov_step_wise_init(void)
> > +int thermal_gov_step_wise_register(void)
> >  {
> >  	return thermal_register_governor(&thermal_gov_step_wise);
> >  }
> > 
> > -static void __exit thermal_gov_step_wise_exit(void)
> > +void thermal_gov_step_wise_unregister(void)
> >  {
> >  	thermal_unregister_governor(&thermal_gov_step_wise);
> >  }
> > -
> > -/* This should load after thermal framework */
> > -fs_initcall(thermal_gov_step_wise_init);
> > -module_exit(thermal_gov_step_wise_exit);
> > -
> > -MODULE_AUTHOR("Durgadoss R");
> > -MODULE_DESCRIPTION("A step-by-step thermal throttling governor");
> > -MODULE_LICENSE("GPL");
> > diff --git a/drivers/thermal/thermal_core.c
> > b/drivers/thermal/thermal_core.c
> > index 845ed6e..eac9745 100644
> > --- a/drivers/thermal/thermal_core.c
> > +++ b/drivers/thermal/thermal_core.c
> > @@ -1858,22 +1858,54 @@ static inline int genetlink_init(void) { return 0; }
> >  static inline void genetlink_exit(void) {}
> >  #endif /* !CONFIG_NET */
> > 
> > +static int __init thermal_register_governors(void)
> > +{
> > +	int result;
> > +
> > +	result = thermal_gov_step_wise_register();
> > +	if (result)
> 
> [Patches 1,2 are fine with me].
> 
thanks.

> A pr_err statement here, saying the registration failed,
> would help us a lot.
> 
yes. sounds reasonable to me.
Will add it in V2.

> > +		return result;
> > +
> > +	result = thermal_gov_fair_share_register();
> > +	if (result)
> > +		return result;
> > +
> > +	result = thermal_gov_user_space_register();
> 
> Same check + print statement for the other two as well.
> 
yep.

> > +
> > +	return result;
> > +}
> > +
> > +static void __exit thermal_unregister_governors(void)
> > +{
> > +	thermal_gov_step_wise_unregister();
> > +	thermal_gov_fair_share_unregister();
> > +	thermal_gov_user_space_unregister();
> > +}
> > +
> >  static int __init thermal_init(void)
> >  {
> > -	int result = 0;
> > +	int result;
> > +
> > +	result = thermal_register_governors();
> > +	if (result)
> > +		return result;
> > 
> >  	result = class_register(&thermal_class);
> >  	if (result)
> 
> Shouldn't we do thermal_unregister_governors here ?
> 
> >  		return result;
> > 
> >  	result = genetlink_init();
> > +	if (result)
> > +		class_unregister(&thermal_class);
> 
> Shouldn't we do thermal_unregister_governors here ?
> Probably a goto would make things simpler..
> 
IMO, these are not worth cleaning up because the driver will be unloaded
soon.

thanks,
rui
> > +
> >  	return result;
> >  }
> > 
> >  static void __exit thermal_exit(void)
> >  {
> > -	class_unregister(&thermal_class);
> >  	genetlink_exit();
> > +	class_unregister(&thermal_class);
> > +	thermal_unregister_governors();
> >  }
> > 
> >  fs_initcall(thermal_init);
> > diff --git a/drivers/thermal/thermal_core.h
> > b/drivers/thermal/thermal_core.h
> > index 0d3205a..f84ea0f 100644
> > --- a/drivers/thermal/thermal_core.h
> > +++ b/drivers/thermal/thermal_core.h
> > @@ -50,4 +50,29 @@ struct thermal_instance {
> >  	struct list_head cdev_node; /* node in cdev->thermal_instances */
> >  };
> > 
> > +
> > +#ifdef CONFIG_THERMAL_GOV_STEP_WISE
> > +extern int thermal_gov_step_wise_register(void);
> > +extern void thermal_gov_step_wise_unregister(void);
> > +#else
> > +static inline int thermal_gov_step_wise_register(void) { return 0; }
> > +static inline void thermal_gov_step_wise_unregister(void) {}
> > +#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
> > +
> > +#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE
> > +extern int thermal_gov_fair_share_register(void);
> > +extern void thermal_gov_fair_share_unregister(void);
> > +#else
> > +static inline int thermal_gov_fair_share_register(void) { return 0; }
> > +static inline void thermal_gov_fair_share_unregister(void) {}
> > +#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
> > +
> > +#ifdef CONFIG_THERMAL_GOV_USER_SPACE
> > +extern int thermal_gov_user_space_register(void);
> > +extern void thermal_gov_user_space_unregister(void);
> > +#else
> > +static inline int thermal_gov_user_space_register(void) { return 0; }
> > +static inline void thermal_gov_user_space_unregister(void) {}
> > +#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
> > +
> >  #endif /* __THERMAL_CORE_H__ */
> > diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
> > index 6bbb380..10adcdd 100644
> > --- a/drivers/thermal/user_space.c
> > +++ b/drivers/thermal/user_space.c
> > @@ -22,9 +22,6 @@
> >   *
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > ~~~~~~~~~~~~~~~~
> >   */
> > 
> > -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > -
> > -#include <linux/module.h>
> >  #include <linux/thermal.h>
> > 
> >  #include "thermal_core.h"
> > @@ -46,23 +43,15 @@ static int notify_user_space(struct
> > thermal_zone_device *tz, int trip)
> >  static struct thermal_governor thermal_gov_user_space = {
> >  	.name		= "user_space",
> >  	.throttle	= notify_user_space,
> > -	.owner		= THIS_MODULE,
> >  };
> > 
> > -static int __init thermal_gov_user_space_init(void)
> > +int thermal_gov_user_space_register(void)
> >  {
> >  	return thermal_register_governor(&thermal_gov_user_space);
> >  }
> > 
> > -static void __exit thermal_gov_user_space_exit(void)
> > +void thermal_gov_user_space_unregister(void)
> >  {
> >  	thermal_unregister_governor(&thermal_gov_user_space);
> >  }
> > 
> > -/* This should load after thermal framework */
> > -fs_initcall(thermal_gov_user_space_init);
> > -module_exit(thermal_gov_user_space_exit);
> > -
> > -MODULE_AUTHOR("Durgadoss R");
> > -MODULE_DESCRIPTION("A user space Thermal notifier");
> > -MODULE_LICENSE("GPL");
> > diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> > index f0bd7f9..2eeec01 100644
> > --- a/include/linux/thermal.h
> > +++ b/include/linux/thermal.h
> > @@ -184,7 +184,6 @@ struct thermal_governor {
> >  	char name[THERMAL_NAME_LENGTH];
> >  	int (*throttle)(struct thermal_zone_device *tz, int trip);
> >  	struct list_head	governor_list;
> > -	struct module		*owner;
> >  };
> > 
> >  /* Structure that holds binding parameters for a zone */
> > --
> > 1.7.9.5
> 



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC,1/5] Thermal: rename thermal_sys.c to thermal_core.c
  2013-03-26 16:26 ` [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c Zhang Rui
@ 2013-03-26 22:04     ` Eduardo Valentin
  2013-03-26 22:04     ` Eduardo Valentin
  1 sibling, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-03-26 22:04 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

Hi Rui,

A side note:
I'd really appreciate if you could copy on your patches on 
drivers/thermal/. I had some issues with TI server and got un subscribed 
from linux-pm. Now I will try to catch up any way,

Some comments.

On 26-03-2013 12:26, Zhang Rui wrote:
> No functional change in this patch.
>

Just a better description would also help on code version control.

> Signed-off-by: Zhang Rui <rui.zhang@intel.com>

Apart from minor comments, I agreed with this change. So feel free to 
add my:

Acked-by: Eduardo Valentin <eduardo.valentin@ti.com>

>
> ---
> drivers/thermal/Makefile       |    1 +
>   drivers/thermal/thermal_core.c | 1888 ++++++++++++++++++++++++++++++++++++++++
>   drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------

When sending renames, use git format-patch --find-renames, it makes a 
better summary of what you have done, specially if you have changed 
something in the file while renaming.

>   3 files changed, 1889 insertions(+), 1888 deletions(-)
>   create mode 100644 drivers/thermal/thermal_core.c
>   delete mode 100644 drivers/thermal/thermal_sys.c
>
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index d3a2b38..b2009bd 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -3,6 +3,7 @@
>   #
>
>   obj-$(CONFIG_THERMAL)		+= thermal_sys.o

I know this is for fixing the annoying bug with fan max speed. But while 
still here, do you think 'thermal_sys' is a good name for thermal 
framework driver? Maybe just 'thermal' would suffice?

> +thermal_sys-y			+= thermal_core.o
>
>   # governors
>   obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> new file mode 100644
> index 0000000..5b7863a
> --- /dev/null
> +++ b/drivers/thermal/thermal_core.c
> @@ -0,0 +1,1888 @@
> +/*
> + *  thermal.c - Generic Thermal Management Sysfs support.
> + *
> + *  Copyright (C) 2008 Intel Corp
> + *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> + *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> + *
> + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; version 2 of the License.
> + *
> + *  This program is distributed in the hope that it will be useful, but
> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License along
> + *  with this program; if not, write to the Free Software Foundation, Inc.,
> + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/kdev_t.h>
> +#include <linux/idr.h>
> +#include <linux/thermal.h>
> +#include <linux/reboot.h>
> +#include <net/netlink.h>
> +#include <net/genetlink.h>
> +
> +#include "thermal_core.h"
> +
> +MODULE_AUTHOR("Zhang Rui");
> +MODULE_DESCRIPTION("Generic thermal management sysfs support");
> +MODULE_LICENSE("GPL");
> +
> +static DEFINE_IDR(thermal_tz_idr);
> +static DEFINE_IDR(thermal_cdev_idr);
> +static DEFINE_MUTEX(thermal_idr_lock);
> +
> +static LIST_HEAD(thermal_tz_list);
> +static LIST_HEAD(thermal_cdev_list);
> +static LIST_HEAD(thermal_governor_list);
> +
> +static DEFINE_MUTEX(thermal_list_lock);
> +static DEFINE_MUTEX(thermal_governor_lock);
> +
> +static struct thermal_governor *__find_governor(const char *name)
> +{
> +	struct thermal_governor *pos;
> +
> +	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> +		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> +			return pos;
> +
> +	return NULL;
> +}
> +
> +int thermal_register_governor(struct thermal_governor *governor)
> +{
> +	int err;
> +	const char *name;
> +	struct thermal_zone_device *pos;
> +
> +	if (!governor)
> +		return -EINVAL;
> +
> +	mutex_lock(&thermal_governor_lock);
> +
> +	err = -EBUSY;
> +	if (__find_governor(governor->name) == NULL) {
> +		err = 0;
> +		list_add(&governor->governor_list, &thermal_governor_list);
> +	}
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> +		if (pos->governor)
> +			continue;
> +		if (pos->tzp)
> +			name = pos->tzp->governor_name;
> +		else
> +			name = DEFAULT_THERMAL_GOVERNOR;
> +		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
> +			pos->governor = governor;
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +	mutex_unlock(&thermal_governor_lock);
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(thermal_register_governor);
> +
> +void thermal_unregister_governor(struct thermal_governor *governor)
> +{
> +	struct thermal_zone_device *pos;
> +
> +	if (!governor)
> +		return;
> +
> +	mutex_lock(&thermal_governor_lock);
> +
> +	if (__find_governor(governor->name) == NULL)
> +		goto exit;
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> +		if (!strnicmp(pos->governor->name, governor->name,
> +						THERMAL_NAME_LENGTH))
> +			pos->governor = NULL;
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +	list_del(&governor->governor_list);
> +exit:
> +	mutex_unlock(&thermal_governor_lock);
> +	return;
> +}
> +EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> +
> +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> +{
> +	int ret;
> +
> +	if (lock)
> +		mutex_lock(lock);
> +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> +	if (lock)
> +		mutex_unlock(lock);
> +	if (unlikely(ret < 0))
> +		return ret;
> +	*id = ret;
> +	return 0;
> +}
> +
> +static void release_idr(struct idr *idr, struct mutex *lock, int id)
> +{
> +	if (lock)
> +		mutex_lock(lock);
> +	idr_remove(idr, id);
> +	if (lock)
> +		mutex_unlock(lock);
> +}
> +
> +int get_tz_trend(struct thermal_zone_device *tz, int trip)
> +{
> +	enum thermal_trend trend;
> +
> +	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> +		if (tz->temperature > tz->last_temperature)
> +			trend = THERMAL_TREND_RAISING;
> +		else if (tz->temperature < tz->last_temperature)
> +			trend = THERMAL_TREND_DROPPING;
> +		else
> +			trend = THERMAL_TREND_STABLE;
> +	}
> +
> +	return trend;
> +}
> +EXPORT_SYMBOL(get_tz_trend);
> +
> +struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
> +			struct thermal_cooling_device *cdev, int trip)
> +{
> +	struct thermal_instance *pos = NULL;
> +	struct thermal_instance *target_instance = NULL;
> +
> +	mutex_lock(&tz->lock);
> +	mutex_lock(&cdev->lock);
> +
> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> +			target_instance = pos;
> +			break;
> +		}
> +	}
> +
> +	mutex_unlock(&cdev->lock);
> +	mutex_unlock(&tz->lock);
> +
> +	return target_instance;
> +}
> +EXPORT_SYMBOL(get_thermal_instance);
> +
> +static void print_bind_err_msg(struct thermal_zone_device *tz,
> +			struct thermal_cooling_device *cdev, int ret)
> +{
> +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> +				tz->type, cdev->type, ret);
> +}
> +
> +static void __bind(struct thermal_zone_device *tz, int mask,
> +			struct thermal_cooling_device *cdev)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < tz->trips; i++) {
> +		if (mask & (1 << i)) {
> +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> +					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
> +			if (ret)
> +				print_bind_err_msg(tz, cdev, ret);
> +		}
> +	}
> +}
> +
> +static void __unbind(struct thermal_zone_device *tz, int mask,
> +			struct thermal_cooling_device *cdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < tz->trips; i++)
> +		if (mask & (1 << i))
> +			thermal_zone_unbind_cooling_device(tz, i, cdev);
> +}
> +
> +static void bind_cdev(struct thermal_cooling_device *cdev)
> +{
> +	int i, ret;
> +	const struct thermal_zone_params *tzp;
> +	struct thermal_zone_device *pos = NULL;
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> +		if (!pos->tzp && !pos->ops->bind)
> +			continue;
> +
> +		if (!pos->tzp && pos->ops->bind) {
> +			ret = pos->ops->bind(pos, cdev);
> +			if (ret)
> +				print_bind_err_msg(pos, cdev, ret);
> +		}
> +
> +		tzp = pos->tzp;
> +		if (!tzp || !tzp->tbp)
> +			continue;
> +
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> +				continue;
> +			if (tzp->tbp[i].match(pos, cdev))
> +				continue;
> +			tzp->tbp[i].cdev = cdev;
> +			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> +		}
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +}
> +
> +static void bind_tz(struct thermal_zone_device *tz)
> +{
> +	int i, ret;
> +	struct thermal_cooling_device *pos = NULL;
> +	const struct thermal_zone_params *tzp = tz->tzp;
> +
> +	if (!tzp && !tz->ops->bind)
> +		return;
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	/* If there is no platform data, try to use ops->bind */
> +	if (!tzp && tz->ops->bind) {
> +		list_for_each_entry(pos, &thermal_cdev_list, node) {
> +			ret = tz->ops->bind(tz, pos);
> +			if (ret)
> +				print_bind_err_msg(tz, pos, ret);
> +		}
> +		goto exit;
> +	}
> +
> +	if (!tzp || !tzp->tbp)
> +		goto exit;
> +
> +	list_for_each_entry(pos, &thermal_cdev_list, node) {
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> +				continue;
> +			if (tzp->tbp[i].match(tz, pos))
> +				continue;
> +			tzp->tbp[i].cdev = pos;
> +			__bind(tz, tzp->tbp[i].trip_mask, pos);
> +		}
> +	}
> +exit:
> +	mutex_unlock(&thermal_list_lock);
> +}
> +
> +static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
> +					    int delay)
> +{
> +	if (delay > 1000)
> +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> +				 round_jiffies(msecs_to_jiffies(delay)));
> +	else if (delay)
> +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> +				 msecs_to_jiffies(delay));
> +	else
> +		cancel_delayed_work(&tz->poll_queue);
> +}
> +
> +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);
> +	else if (tz->polling_delay)
> +		thermal_zone_device_set_polling(tz, tz->polling_delay);
> +	else
> +		thermal_zone_device_set_polling(tz, 0);
> +
> +	mutex_unlock(&tz->lock);
> +}
> +
> +static void handle_non_critical_trips(struct thermal_zone_device *tz,
> +			int trip, enum thermal_trip_type trip_type)
> +{
> +	if (tz->governor)
> +		tz->governor->throttle(tz, trip);
> +}
> +
> +static void handle_critical_trips(struct thermal_zone_device *tz,
> +				int trip, enum thermal_trip_type trip_type)
> +{
> +	long trip_temp;
> +
> +	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> +
> +	/* If we have not crossed the trip_temp, we do not care. */
> +	if (tz->temperature < trip_temp)
> +		return;
> +
> +	if (tz->ops->notify)
> +		tz->ops->notify(tz, trip, trip_type);
> +
> +	if (trip_type == THERMAL_TRIP_CRITICAL) {
> +		dev_emerg(&tz->device,
> +			  "critical temperature reached(%d C),shutting down\n",
> +			  tz->temperature / 1000);
> +		orderly_poweroff(true);
> +	}
> +}
> +
> +static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> +{
> +	enum thermal_trip_type type;
> +
> +	tz->ops->get_trip_type(tz, trip, &type);
> +
> +	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
> +		handle_critical_trips(tz, trip, type);
> +	else
> +		handle_non_critical_trips(tz, trip, type);
> +	/*
> +	 * Alright, we handled this trip successfully.
> +	 * So, start monitoring again.
> +	 */
> +	monitor_thermal_zone(tz);
> +}
> +
> +static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> +				unsigned long *temp)
> +{
> +	int ret = 0;
> +#ifdef CONFIG_THERMAL_EMULATION
> +	int count;
> +	unsigned long crit_temp = -1UL;
> +	enum thermal_trip_type type;
> +#endif
> +
> +	mutex_lock(&tz->lock);
> +
> +	ret = tz->ops->get_temp(tz, temp);
> +#ifdef CONFIG_THERMAL_EMULATION
> +	if (!tz->emul_temperature)
> +		goto skip_emul;
> +
> +	for (count = 0; count < tz->trips; count++) {
> +		ret = tz->ops->get_trip_type(tz, count, &type);
> +		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> +			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> +			break;
> +		}
> +	}
> +
> +	if (ret)
> +		goto skip_emul;
> +
> +	if (*temp < crit_temp)
> +		*temp = tz->emul_temperature;
> +skip_emul:
> +#endif
> +	mutex_unlock(&tz->lock);
> +	return ret;
> +}
> +
> +static void update_temperature(struct thermal_zone_device *tz)
> +{
> +	long temp;
> +	int ret;
> +
> +	ret = thermal_zone_get_temp(tz, &temp);
> +	if (ret) {
> +		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
> +			 tz->id);
> +		return;
> +	}
> +
> +	mutex_lock(&tz->lock);
> +	tz->last_temperature = tz->temperature;
> +	tz->temperature = temp;
> +	mutex_unlock(&tz->lock);
> +}
> +
> +void thermal_zone_device_update(struct thermal_zone_device *tz)
> +{
> +	int count;
> +
> +	update_temperature(tz);
> +
> +	for (count = 0; count < tz->trips; count++)
> +		handle_thermal_trip(tz, count);
> +}
> +EXPORT_SYMBOL(thermal_zone_device_update);
> +
> +static void thermal_zone_device_check(struct work_struct *work)
> +{
> +	struct thermal_zone_device *tz = container_of(work, struct
> +						      thermal_zone_device,
> +						      poll_queue.work);
> +	thermal_zone_device_update(tz);
> +}
> +
> +/* sys I/F for thermal zone */
> +
> +#define to_thermal_zone(_dev) \
> +	container_of(_dev, struct thermal_zone_device, device)
> +
> +static ssize_t
> +type_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> +	return sprintf(buf, "%s\n", tz->type);
> +}
> +
> +static ssize_t
> +temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	long temperature;
> +	int ret;
> +
> +	ret = thermal_zone_get_temp(tz, &temperature);
> +
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	enum thermal_device_mode mode;
> +	int result;
> +
> +	if (!tz->ops->get_mode)
> +		return -EPERM;
> +
> +	result = tz->ops->get_mode(tz, &mode);
> +	if (result)
> +		return result;
> +
> +	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
> +		       : "disabled");
> +}
> +
> +static ssize_t
> +mode_store(struct device *dev, struct device_attribute *attr,
> +	   const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int result;
> +
> +	if (!tz->ops->set_mode)
> +		return -EPERM;
> +
> +	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);
> +	else
> +		result = -EINVAL;
> +
> +	if (result)
> +		return result;
> +
> +	return count;
> +}
> +
> +static ssize_t
> +trip_point_type_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	enum thermal_trip_type type;
> +	int trip, result;
> +
> +	if (!tz->ops->get_trip_type)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> +		return -EINVAL;
> +
> +	result = tz->ops->get_trip_type(tz, trip, &type);
> +	if (result)
> +		return result;
> +
> +	switch (type) {
> +	case THERMAL_TRIP_CRITICAL:
> +		return sprintf(buf, "critical\n");
> +	case THERMAL_TRIP_HOT:
> +		return sprintf(buf, "hot\n");
> +	case THERMAL_TRIP_PASSIVE:
> +		return sprintf(buf, "passive\n");
> +	case THERMAL_TRIP_ACTIVE:
> +		return sprintf(buf, "active\n");
> +	default:
> +		return sprintf(buf, "unknown\n");
> +	}
> +}
> +
> +static ssize_t
> +trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> +		     const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	unsigned long temperature;
> +
> +	if (!tz->ops->set_trip_temp)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> +		return -EINVAL;
> +
> +	if (kstrtoul(buf, 10, &temperature))
> +		return -EINVAL;
> +
> +	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> +
> +	return ret ? ret : count;
> +}
> +
> +static ssize_t
> +trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	long temperature;
> +
> +	if (!tz->ops->get_trip_temp)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> +		return -EINVAL;
> +
> +	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> +
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> +			const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	unsigned long temperature;
> +
> +	if (!tz->ops->set_trip_hyst)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> +		return -EINVAL;
> +
> +	if (kstrtoul(buf, 10, &temperature))
> +		return -EINVAL;
> +
> +	/*
> +	 * We are not doing any check on the 'temperature' value
> +	 * here. The driver implementing 'set_trip_hyst' has to
> +	 * take care of this.
> +	 */
> +	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> +
> +	return ret ? ret : count;
> +}
> +
> +static ssize_t
> +trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> +			char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	unsigned long temperature;
> +
> +	if (!tz->ops->get_trip_hyst)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> +		return -EINVAL;
> +
> +	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> +
> +	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +passive_store(struct device *dev, struct device_attribute *attr,
> +		    const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	struct thermal_cooling_device *cdev = NULL;
> +	int state;
> +
> +	if (!sscanf(buf, "%d\n", &state))
> +		return -EINVAL;
> +
> +	/* sanity check: values below 1000 millicelcius don't make sense
> +	 * and can cause the system to go into a thermal heart attack
> +	 */
> +	if (state && state < 1000)
> +		return -EINVAL;
> +
> +	if (state && !tz->forced_passive) {
> +		mutex_lock(&thermal_list_lock);
> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> +			if (!strncmp("Processor", cdev->type,
> +				     sizeof("Processor")))
> +				thermal_zone_bind_cooling_device(tz,
> +						THERMAL_TRIPS_NONE, cdev,
> +						THERMAL_NO_LIMIT,
> +						THERMAL_NO_LIMIT);
> +		}
> +		mutex_unlock(&thermal_list_lock);
> +		if (!tz->passive_delay)
> +			tz->passive_delay = 1000;
> +	} else if (!state && tz->forced_passive) {
> +		mutex_lock(&thermal_list_lock);
> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> +			if (!strncmp("Processor", cdev->type,
> +				     sizeof("Processor")))
> +				thermal_zone_unbind_cooling_device(tz,
> +								   THERMAL_TRIPS_NONE,
> +								   cdev);
> +		}
> +		mutex_unlock(&thermal_list_lock);
> +		tz->passive_delay = 0;
> +	}
> +
> +	tz->forced_passive = state;
> +
> +	thermal_zone_device_update(tz);
> +
> +	return count;
> +}
> +
> +static ssize_t
> +passive_show(struct device *dev, struct device_attribute *attr,
> +		   char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> +	return sprintf(buf, "%d\n", tz->forced_passive);
> +}
> +
> +static ssize_t
> +policy_store(struct device *dev, struct device_attribute *attr,
> +		    const char *buf, size_t count)
> +{
> +	int ret = -EINVAL;
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	struct thermal_governor *gov;
> +
> +	mutex_lock(&thermal_governor_lock);
> +
> +	gov = __find_governor(buf);
> +	if (!gov)
> +		goto exit;
> +
> +	tz->governor = gov;
> +	ret = count;
> +
> +exit:
> +	mutex_unlock(&thermal_governor_lock);
> +	return ret;
> +}
> +
> +static ssize_t
> +policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> +	return sprintf(buf, "%s\n", tz->governor->name);
> +}
> +
> +#ifdef CONFIG_THERMAL_EMULATION
> +static ssize_t
> +emul_temp_store(struct device *dev, struct device_attribute *attr,
> +		     const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int ret = 0;
> +	unsigned long temperature;
> +
> +	if (kstrtoul(buf, 10, &temperature))
> +		return -EINVAL;
> +
> +	if (!tz->ops->set_emul_temp) {
> +		mutex_lock(&tz->lock);
> +		tz->emul_temperature = temperature;
> +		mutex_unlock(&tz->lock);
> +	} else {
> +		ret = tz->ops->set_emul_temp(tz, temperature);
> +	}
> +
> +	return ret ? ret : count;
> +}
> +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> +#endif/*CONFIG_THERMAL_EMULATION*/
> +
> +static DEVICE_ATTR(type, 0444, type_show, NULL);
> +static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> +static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
> +static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
> +
> +/* sys I/F for cooling device */
> +#define to_cooling_device(_dev)	\
> +	container_of(_dev, struct thermal_cooling_device, device)
> +
> +static ssize_t
> +thermal_cooling_device_type_show(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +
> +	return sprintf(buf, "%s\n", cdev->type);
> +}
> +
> +static ssize_t
> +thermal_cooling_device_max_state_show(struct device *dev,
> +				      struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +	unsigned long state;
> +	int ret;
> +
> +	ret = cdev->ops->get_max_state(cdev, &state);
> +	if (ret)
> +		return ret;
> +	return sprintf(buf, "%ld\n", state);
> +}
> +
> +static ssize_t
> +thermal_cooling_device_cur_state_show(struct device *dev,
> +				      struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +	unsigned long state;
> +	int ret;
> +
> +	ret = cdev->ops->get_cur_state(cdev, &state);
> +	if (ret)
> +		return ret;
> +	return sprintf(buf, "%ld\n", state);
> +}
> +
> +static ssize_t
> +thermal_cooling_device_cur_state_store(struct device *dev,
> +				       struct device_attribute *attr,
> +				       const char *buf, size_t count)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +	unsigned long state;
> +	int result;
> +
> +	if (!sscanf(buf, "%ld\n", &state))
> +		return -EINVAL;
> +
> +	if ((long)state < 0)
> +		return -EINVAL;
> +
> +	result = cdev->ops->set_cur_state(cdev, state);
> +	if (result)
> +		return result;
> +	return count;
> +}
> +
> +static struct device_attribute dev_attr_cdev_type =
> +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> +static DEVICE_ATTR(max_state, 0444,
> +		   thermal_cooling_device_max_state_show, NULL);
> +static DEVICE_ATTR(cur_state, 0644,
> +		   thermal_cooling_device_cur_state_show,
> +		   thermal_cooling_device_cur_state_store);
> +
> +static ssize_t
> +thermal_cooling_device_trip_point_show(struct device *dev,
> +				       struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_instance *instance;
> +
> +	instance =
> +	    container_of(attr, struct thermal_instance, attr);
> +
> +	if (instance->trip == THERMAL_TRIPS_NONE)
> +		return sprintf(buf, "-1\n");
> +	else
> +		return sprintf(buf, "%d\n", instance->trip);
> +}
> +
> +/* Device management */
> +
> +#if defined(CONFIG_THERMAL_HWMON)
> +
> +/* hwmon sys I/F */
> +#include <linux/hwmon.h>
> +
> +/* thermal zone devices with the same type share one hwmon device */
> +struct thermal_hwmon_device {
> +	char type[THERMAL_NAME_LENGTH];
> +	struct device *device;
> +	int count;
> +	struct list_head tz_list;
> +	struct list_head node;
> +};
> +
> +struct thermal_hwmon_attr {
> +	struct device_attribute attr;
> +	char name[16];
> +};
> +
> +/* one temperature input for each thermal zone */
> +struct thermal_hwmon_temp {
> +	struct list_head hwmon_node;
> +	struct thermal_zone_device *tz;
> +	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> +	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> +};
> +
> +static LIST_HEAD(thermal_hwmon_list);
> +
> +static ssize_t
> +name_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> +	return sprintf(buf, "%s\n", hwmon->type);
> +}
> +static DEVICE_ATTR(name, 0444, name_show, NULL);
> +
> +static ssize_t
> +temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	long temperature;
> +	int ret;
> +	struct thermal_hwmon_attr *hwmon_attr
> +			= container_of(attr, struct thermal_hwmon_attr, attr);
> +	struct thermal_hwmon_temp *temp
> +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> +				       temp_input);
> +	struct thermal_zone_device *tz = temp->tz;
> +
> +	ret = thermal_zone_get_temp(tz, &temperature);
> +
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +temp_crit_show(struct device *dev, struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct thermal_hwmon_attr *hwmon_attr
> +			= container_of(attr, struct thermal_hwmon_attr, attr);
> +	struct thermal_hwmon_temp *temp
> +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> +				       temp_crit);
> +	struct thermal_zone_device *tz = temp->tz;
> +	long temperature;
> +	int ret;
> +
> +	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +
> +static struct thermal_hwmon_device *
> +thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_device *hwmon;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> +		if (!strcmp(hwmon->type, tz->type)) {
> +			mutex_unlock(&thermal_list_lock);
> +			return hwmon;
> +		}
> +	mutex_unlock(&thermal_list_lock);
> +
> +	return NULL;
> +}
> +
> +/* Find the temperature input matching a given thermal zone */
> +static struct thermal_hwmon_temp *
> +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
> +			  const struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_temp *temp;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> +		if (temp->tz == tz) {
> +			mutex_unlock(&thermal_list_lock);
> +			return temp;
> +		}
> +	mutex_unlock(&thermal_list_lock);
> +
> +	return NULL;
> +}
> +
> +static int
> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_device *hwmon;
> +	struct thermal_hwmon_temp *temp;
> +	int new_hwmon_device = 1;
> +	int result;
> +
> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> +	if (hwmon) {
> +		new_hwmon_device = 0;
> +		goto register_sys_interface;
> +	}
> +
> +	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
> +	if (!hwmon)
> +		return -ENOMEM;
> +
> +	INIT_LIST_HEAD(&hwmon->tz_list);
> +	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> +	hwmon->device = hwmon_device_register(NULL);
> +	if (IS_ERR(hwmon->device)) {
> +		result = PTR_ERR(hwmon->device);
> +		goto free_mem;
> +	}
> +	dev_set_drvdata(hwmon->device, hwmon);
> +	result = device_create_file(hwmon->device, &dev_attr_name);
> +	if (result)
> +		goto free_mem;
> +
> + register_sys_interface:
> +	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> +	if (!temp) {
> +		result = -ENOMEM;
> +		goto unregister_name;
> +	}
> +
> +	temp->tz = tz;
> +	hwmon->count++;
> +
> +	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
> +		 "temp%d_input", hwmon->count);
> +	temp->temp_input.attr.attr.name = temp->temp_input.name;
> +	temp->temp_input.attr.attr.mode = 0444;
> +	temp->temp_input.attr.show = temp_input_show;
> +	sysfs_attr_init(&temp->temp_input.attr.attr);
> +	result = device_create_file(hwmon->device, &temp->temp_input.attr);
> +	if (result)
> +		goto free_temp_mem;
> +
> +	if (tz->ops->get_crit_temp) {
> +		unsigned long temperature;
> +		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> +			snprintf(temp->temp_crit.name,
> +				 sizeof(temp->temp_crit.name),
> +				"temp%d_crit", hwmon->count);
> +			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
> +			temp->temp_crit.attr.attr.mode = 0444;
> +			temp->temp_crit.attr.show = temp_crit_show;
> +			sysfs_attr_init(&temp->temp_crit.attr.attr);
> +			result = device_create_file(hwmon->device,
> +						    &temp->temp_crit.attr);
> +			if (result)
> +				goto unregister_input;
> +		}
> +	}
> +
> +	mutex_lock(&thermal_list_lock);
> +	if (new_hwmon_device)
> +		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> +	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	return 0;
> +
> + unregister_input:
> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> + free_temp_mem:
> +	kfree(temp);
> + unregister_name:
> +	if (new_hwmon_device) {
> +		device_remove_file(hwmon->device, &dev_attr_name);
> +		hwmon_device_unregister(hwmon->device);
> +	}
> + free_mem:
> +	if (new_hwmon_device)
> +		kfree(hwmon);
> +
> +	return result;
> +}
> +
> +static void
> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_device *hwmon;
> +	struct thermal_hwmon_temp *temp;
> +
> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> +	if (unlikely(!hwmon)) {
> +		/* Should never happen... */
> +		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> +		return;
> +	}
> +
> +	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> +	if (unlikely(!temp)) {
> +		/* Should never happen... */
> +		dev_dbg(&tz->device, "temperature input lookup failed!\n");
> +		return;
> +	}
> +
> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> +	if (tz->ops->get_crit_temp)
> +		device_remove_file(hwmon->device, &temp->temp_crit.attr);
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_del(&temp->hwmon_node);
> +	kfree(temp);
> +	if (!list_empty(&hwmon->tz_list)) {
> +		mutex_unlock(&thermal_list_lock);
> +		return;
> +	}
> +	list_del(&hwmon->node);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	device_remove_file(hwmon->device, &dev_attr_name);
> +	hwmon_device_unregister(hwmon->device);
> +	kfree(hwmon);
> +}
> +#else
> +static int
> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +	return 0;
> +}
> +
> +static void
> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +}
> +#endif
> +
> +/**
> + * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
> + * @tz:		thermal zone device
> + * @trip:	indicates which trip point the cooling devices is
> + *		associated with in this thermal zone.
> + * @cdev:	thermal cooling device
> + *
> + * This function is usually called in the thermal zone device .bind callback.
> + */
> +int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> +				     int trip,
> +				     struct thermal_cooling_device *cdev,
> +				     unsigned long upper, unsigned long lower)
> +{
> +	struct thermal_instance *dev;
> +	struct thermal_instance *pos;
> +	struct thermal_zone_device *pos1;
> +	struct thermal_cooling_device *pos2;
> +	unsigned long max_state;
> +	int result;
> +
> +	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> +		return -EINVAL;
> +
> +	list_for_each_entry(pos1, &thermal_tz_list, node) {
> +		if (pos1 == tz)
> +			break;
> +	}
> +	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> +		if (pos2 == cdev)
> +			break;
> +	}
> +
> +	if (tz != pos1 || cdev != pos2)
> +		return -EINVAL;
> +
> +	cdev->ops->get_max_state(cdev, &max_state);
> +
> +	/* lower default 0, upper default max_state */
> +	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> +	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> +
> +	if (lower > upper || upper > max_state)
> +		return -EINVAL;
> +
> +	dev =
> +	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> +	if (!dev)
> +		return -ENOMEM;
> +	dev->tz = tz;
> +	dev->cdev = cdev;
> +	dev->trip = trip;
> +	dev->upper = upper;
> +	dev->lower = lower;
> +	dev->target = THERMAL_NO_TARGET;
> +
> +	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> +	if (result)
> +		goto free_mem;
> +
> +	sprintf(dev->name, "cdev%d", dev->id);
> +	result =
> +	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
> +	if (result)
> +		goto release_idr;
> +
> +	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> +	sysfs_attr_init(&dev->attr.attr);
> +	dev->attr.attr.name = dev->attr_name;
> +	dev->attr.attr.mode = 0444;
> +	dev->attr.show = thermal_cooling_device_trip_point_show;
> +	result = device_create_file(&tz->device, &dev->attr);
> +	if (result)
> +		goto remove_symbol_link;
> +
> +	mutex_lock(&tz->lock);
> +	mutex_lock(&cdev->lock);
> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> +	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> +		result = -EEXIST;
> +		break;
> +	}
> +	if (!result) {
> +		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> +		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
> +	}
> +	mutex_unlock(&cdev->lock);
> +	mutex_unlock(&tz->lock);
> +
> +	if (!result)
> +		return 0;
> +
> +	device_remove_file(&tz->device, &dev->attr);
> +remove_symbol_link:
> +	sysfs_remove_link(&tz->device.kobj, dev->name);
> +release_idr:
> +	release_idr(&tz->idr, &tz->lock, dev->id);
> +free_mem:
> +	kfree(dev);
> +	return result;
> +}
> +EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> +
> +/**
> + * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
> + * @tz:		thermal zone device
> + * @trip:	indicates which trip point the cooling devices is
> + *		associated with in this thermal zone.
> + * @cdev:	thermal cooling device
> + *
> + * This function is usually called in the thermal zone device .unbind callback.
> + */
> +int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> +				       int trip,
> +				       struct thermal_cooling_device *cdev)
> +{
> +	struct thermal_instance *pos, *next;
> +
> +	mutex_lock(&tz->lock);
> +	mutex_lock(&cdev->lock);
> +	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> +			list_del(&pos->tz_node);
> +			list_del(&pos->cdev_node);
> +			mutex_unlock(&cdev->lock);
> +			mutex_unlock(&tz->lock);
> +			goto unbind;
> +		}
> +	}
> +	mutex_unlock(&cdev->lock);
> +	mutex_unlock(&tz->lock);
> +
> +	return -ENODEV;
> +
> +unbind:
> +	device_remove_file(&tz->device, &pos->attr);
> +	sysfs_remove_link(&tz->device.kobj, pos->name);
> +	release_idr(&tz->idr, &tz->lock, pos->id);
> +	kfree(pos);
> +	return 0;
> +}
> +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> +
> +static void thermal_release(struct device *dev)
> +{
> +	struct thermal_zone_device *tz;
> +	struct thermal_cooling_device *cdev;
> +
> +	if (!strncmp(dev_name(dev), "thermal_zone",
> +		     sizeof("thermal_zone") - 1)) {
> +		tz = to_thermal_zone(dev);
> +		kfree(tz);
> +	} else {
> +		cdev = to_cooling_device(dev);
> +		kfree(cdev);
> +	}
> +}
> +
> +static struct class thermal_class = {
> +	.name = "thermal",
> +	.dev_release = thermal_release,
> +};
> +
> +/**
> + * thermal_cooling_device_register - register a new thermal cooling device
> + * @type:	the thermal cooling device type.
> + * @devdata:	device private data.
> + * @ops:		standard thermal cooling devices callbacks.
> + */
> +struct thermal_cooling_device *
> +thermal_cooling_device_register(char *type, void *devdata,
> +				const struct thermal_cooling_device_ops *ops)
> +{
> +	struct thermal_cooling_device *cdev;
> +	int result;
> +
> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> +	    !ops->set_cur_state)
> +		return ERR_PTR(-EINVAL);
> +
> +	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> +	if (!cdev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> +	if (result) {
> +		kfree(cdev);
> +		return ERR_PTR(result);
> +	}
> +
> +	strcpy(cdev->type, type ? : "");
> +	mutex_init(&cdev->lock);
> +	INIT_LIST_HEAD(&cdev->thermal_instances);
> +	cdev->ops = ops;
> +	cdev->updated = true;
> +	cdev->device.class = &thermal_class;
> +	cdev->devdata = devdata;
> +	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> +	result = device_register(&cdev->device);
> +	if (result) {
> +		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> +		kfree(cdev);
> +		return ERR_PTR(result);
> +	}
> +
> +	/* sys I/F */
> +	if (type) {
> +		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +	result = device_create_file(&cdev->device, &dev_attr_max_state);
> +	if (result)
> +		goto unregister;
> +
> +	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> +	if (result)
> +		goto unregister;
> +
> +	/* Add 'this' new cdev to the global cdev list */
> +	mutex_lock(&thermal_list_lock);
> +	list_add(&cdev->node, &thermal_cdev_list);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	/* Update binding information for 'this' new cdev */
> +	bind_cdev(cdev);
> +
> +	return cdev;
> +
> +unregister:
> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> +	device_unregister(&cdev->device);
> +	return ERR_PTR(result);
> +}
> +EXPORT_SYMBOL(thermal_cooling_device_register);
> +
> +/**
> + * thermal_cooling_device_unregister - removes the registered thermal cooling device
> + * @cdev:	the thermal cooling device to remove.
> + *
> + * thermal_cooling_device_unregister() must be called when the device is no
> + * longer needed.
> + */
> +void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
> +{
> +	int i;
> +	const struct thermal_zone_params *tzp;
> +	struct thermal_zone_device *tz;
> +	struct thermal_cooling_device *pos = NULL;
> +
> +	if (!cdev)
> +		return;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(pos, &thermal_cdev_list, node)
> +	    if (pos == cdev)
> +		break;
> +	if (pos != cdev) {
> +		/* thermal cooling device not found */
> +		mutex_unlock(&thermal_list_lock);
> +		return;
> +	}
> +	list_del(&cdev->node);
> +
> +	/* Unbind all thermal zones associated with 'this' cdev */
> +	list_for_each_entry(tz, &thermal_tz_list, node) {
> +		if (tz->ops->unbind) {
> +			tz->ops->unbind(tz, cdev);
> +			continue;
> +		}
> +
> +		if (!tz->tzp || !tz->tzp->tbp)
> +			continue;
> +
> +		tzp = tz->tzp;
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev == cdev) {
> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> +				tzp->tbp[i].cdev = NULL;
> +			}
> +		}
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +
> +	if (cdev->type[0])
> +		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> +	device_remove_file(&cdev->device, &dev_attr_max_state);
> +	device_remove_file(&cdev->device, &dev_attr_cur_state);
> +
> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> +	device_unregister(&cdev->device);
> +	return;
> +}
> +EXPORT_SYMBOL(thermal_cooling_device_unregister);
> +
> +void thermal_cdev_update(struct thermal_cooling_device *cdev)
> +{
> +	struct thermal_instance *instance;
> +	unsigned long target = 0;
> +
> +	/* cooling device is updated*/
> +	if (cdev->updated)
> +		return;
> +
> +	mutex_lock(&cdev->lock);
> +	/* Make sure cdev enters the deepest cooling state */
> +	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
> +		if (instance->target == THERMAL_NO_TARGET)
> +			continue;
> +		if (instance->target > target)
> +			target = instance->target;
> +	}
> +	mutex_unlock(&cdev->lock);
> +	cdev->ops->set_cur_state(cdev, target);
> +	cdev->updated = true;
> +}
> +EXPORT_SYMBOL(thermal_cdev_update);
> +
> +/**
> + * notify_thermal_framework - Sensor drivers use this API to notify framework
> + * @tz:		thermal zone device
> + * @trip:	indicates which trip point has been crossed
> + *
> + * This function handles the trip events from sensor drivers. It starts
> + * throttling the cooling devices according to the policy configured.
> + * For CRITICAL and HOT trip points, this notifies the respective drivers,
> + * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> + * The throttling policy is based on the configured platform data; if no
> + * platform data is provided, this uses the step_wise throttling policy.
> + */
> +void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> +{
> +	handle_thermal_trip(tz, trip);
> +}
> +EXPORT_SYMBOL(notify_thermal_framework);
> +
> +/**
> + * create_trip_attrs - create attributes for trip points
> + * @tz:		the thermal zone device
> + * @mask:	Writeable trip point bitmap.
> + */
> +static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> +{
> +	int indx;
> +	int size = sizeof(struct thermal_attr) * tz->trips;
> +
> +	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> +	if (!tz->trip_type_attrs)
> +		return -ENOMEM;
> +
> +	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> +	if (!tz->trip_temp_attrs) {
> +		kfree(tz->trip_type_attrs);
> +		return -ENOMEM;
> +	}
> +
> +	if (tz->ops->get_trip_hyst) {
> +		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> +		if (!tz->trip_hyst_attrs) {
> +			kfree(tz->trip_type_attrs);
> +			kfree(tz->trip_temp_attrs);
> +			return -ENOMEM;
> +		}
> +	}
> +
> +
> +	for (indx = 0; indx < tz->trips; indx++) {
> +		/* create trip type attribute */
> +		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
> +			 "trip_point_%d_type", indx);
> +
> +		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> +		tz->trip_type_attrs[indx].attr.attr.name =
> +						tz->trip_type_attrs[indx].name;
> +		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> +		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> +
> +		device_create_file(&tz->device,
> +				   &tz->trip_type_attrs[indx].attr);
> +
> +		/* create trip temp attribute */
> +		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
> +			 "trip_point_%d_temp", indx);
> +
> +		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> +		tz->trip_temp_attrs[indx].attr.attr.name =
> +						tz->trip_temp_attrs[indx].name;
> +		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> +		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
> +		if (mask & (1 << indx)) {
> +			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
> +			tz->trip_temp_attrs[indx].attr.store =
> +							trip_point_temp_store;
> +		}
> +
> +		device_create_file(&tz->device,
> +				   &tz->trip_temp_attrs[indx].attr);
> +
> +		/* create Optional trip hyst attribute */
> +		if (!tz->ops->get_trip_hyst)
> +			continue;
> +		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
> +			 "trip_point_%d_hyst", indx);
> +
> +		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> +		tz->trip_hyst_attrs[indx].attr.attr.name =
> +					tz->trip_hyst_attrs[indx].name;
> +		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> +		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> +		if (tz->ops->set_trip_hyst) {
> +			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> +			tz->trip_hyst_attrs[indx].attr.store =
> +					trip_point_hyst_store;
> +		}
> +
> +		device_create_file(&tz->device,
> +				   &tz->trip_hyst_attrs[indx].attr);
> +	}
> +	return 0;
> +}
> +
> +static void remove_trip_attrs(struct thermal_zone_device *tz)
> +{
> +	int indx;
> +
> +	for (indx = 0; indx < tz->trips; indx++) {
> +		device_remove_file(&tz->device,
> +				   &tz->trip_type_attrs[indx].attr);
> +		device_remove_file(&tz->device,
> +				   &tz->trip_temp_attrs[indx].attr);
> +		if (tz->ops->get_trip_hyst)
> +			device_remove_file(&tz->device,
> +				  &tz->trip_hyst_attrs[indx].attr);
> +	}
> +	kfree(tz->trip_type_attrs);
> +	kfree(tz->trip_temp_attrs);
> +	kfree(tz->trip_hyst_attrs);
> +}
> +
> +/**
> + * thermal_zone_device_register - register a new thermal zone device
> + * @type:	the thermal zone device type
> + * @trips:	the number of trip points the thermal zone support
> + * @mask:	a bit string indicating the writeablility of trip points
> + * @devdata:	private device data
> + * @ops:	standard thermal zone device callbacks
> + * @tzp:	thermal zone platform parameters
> + * @passive_delay: number of milliseconds to wait between polls when
> + *		   performing passive cooling
> + * @polling_delay: number of milliseconds to wait between polls when checking
> + *		   whether trip points have been crossed (0 for interrupt
> + *		   driven systems)
> + *
> + * thermal_zone_device_unregister() must be called when the device is no
> + * longer needed. The passive cooling depends on the .get_trend() return value.
> + */
> +struct thermal_zone_device *thermal_zone_device_register(const char *type,
> +	int trips, int mask, void *devdata,
> +	const struct thermal_zone_device_ops *ops,
> +	const struct thermal_zone_params *tzp,
> +	int passive_delay, int polling_delay)
> +{
> +	struct thermal_zone_device *tz;
> +	enum thermal_trip_type trip_type;
> +	int result;
> +	int count;
> +	int passive = 0;
> +
> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!ops || !ops->get_temp)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (trips > 0 && !ops->get_trip_type)
> +		return ERR_PTR(-EINVAL);
> +
> +	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> +	if (!tz)
> +		return ERR_PTR(-ENOMEM);
> +
> +	INIT_LIST_HEAD(&tz->thermal_instances);
> +	idr_init(&tz->idr);
> +	mutex_init(&tz->lock);
> +	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> +	if (result) {
> +		kfree(tz);
> +		return ERR_PTR(result);
> +	}
> +
> +	strcpy(tz->type, type ? : "");
> +	tz->ops = ops;
> +	tz->tzp = tzp;
> +	tz->device.class = &thermal_class;
> +	tz->devdata = devdata;
> +	tz->trips = trips;
> +	tz->passive_delay = passive_delay;
> +	tz->polling_delay = polling_delay;
> +
> +	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> +	result = device_register(&tz->device);
> +	if (result) {
> +		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> +		kfree(tz);
> +		return ERR_PTR(result);
> +	}
> +
> +	/* sys I/F */
> +	if (type) {
> +		result = device_create_file(&tz->device, &dev_attr_type);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +	result = device_create_file(&tz->device, &dev_attr_temp);
> +	if (result)
> +		goto unregister;
> +
> +	if (ops->get_mode) {
> +		result = device_create_file(&tz->device, &dev_attr_mode);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +	result = create_trip_attrs(tz, mask);
> +	if (result)
> +		goto unregister;
> +
> +	for (count = 0; count < trips; count++) {
> +		tz->ops->get_trip_type(tz, count, &trip_type);
> +		if (trip_type == THERMAL_TRIP_PASSIVE)
> +			passive = 1;
> +	}
> +
> +	if (!passive) {
> +		result = device_create_file(&tz->device, &dev_attr_passive);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +#ifdef CONFIG_THERMAL_EMULATION
> +	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> +	if (result)
> +		goto unregister;
> +#endif
> +	/* Create policy attribute */
> +	result = device_create_file(&tz->device, &dev_attr_policy);
> +	if (result)
> +		goto unregister;
> +
> +	/* Update 'this' zone's governor information */
> +	mutex_lock(&thermal_governor_lock);
> +
> +	if (tz->tzp)
> +		tz->governor = __find_governor(tz->tzp->governor_name);
> +	else
> +		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
> +
> +	mutex_unlock(&thermal_governor_lock);
> +
> +	result = thermal_add_hwmon_sysfs(tz);
> +	if (result)
> +		goto unregister;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_add_tail(&tz->node, &thermal_tz_list);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	/* Bind cooling devices for this zone */
> +	bind_tz(tz);
> +
> +	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
> +
> +	thermal_zone_device_update(tz);
> +
> +	if (!result)
> +		return tz;
> +
> +unregister:
> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> +	device_unregister(&tz->device);
> +	return ERR_PTR(result);
> +}
> +EXPORT_SYMBOL(thermal_zone_device_register);
> +
> +/**
> + * thermal_device_unregister - removes the registered thermal zone device
> + * @tz: the thermal zone device to remove
> + */
> +void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> +{
> +	int i;
> +	const struct thermal_zone_params *tzp;
> +	struct thermal_cooling_device *cdev;
> +	struct thermal_zone_device *pos = NULL;
> +
> +	if (!tz)
> +		return;
> +
> +	tzp = tz->tzp;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(pos, &thermal_tz_list, node)
> +	    if (pos == tz)
> +		break;
> +	if (pos != tz) {
> +		/* thermal zone device not found */
> +		mutex_unlock(&thermal_list_lock);
> +		return;
> +	}
> +	list_del(&tz->node);
> +
> +	/* Unbind all cdevs associated with 'this' thermal zone */
> +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> +		if (tz->ops->unbind) {
> +			tz->ops->unbind(tz, cdev);
> +			continue;
> +		}
> +
> +		if (!tzp || !tzp->tbp)
> +			break;
> +
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev == cdev) {
> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> +				tzp->tbp[i].cdev = NULL;
> +			}
> +		}
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +
> +	thermal_zone_device_set_polling(tz, 0);
> +
> +	if (tz->type[0])
> +		device_remove_file(&tz->device, &dev_attr_type);
> +	device_remove_file(&tz->device, &dev_attr_temp);
> +	if (tz->ops->get_mode)
> +		device_remove_file(&tz->device, &dev_attr_mode);
> +	device_remove_file(&tz->device, &dev_attr_policy);
> +	remove_trip_attrs(tz);
> +	tz->governor = NULL;
> +
> +	thermal_remove_hwmon_sysfs(tz);
> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> +	idr_destroy(&tz->idr);
> +	mutex_destroy(&tz->lock);
> +	device_unregister(&tz->device);
> +	return;
> +}
> +EXPORT_SYMBOL(thermal_zone_device_unregister);
> +
> +#ifdef CONFIG_NET
> +static struct genl_family thermal_event_genl_family = {
> +	.id = GENL_ID_GENERATE,
> +	.name = THERMAL_GENL_FAMILY_NAME,
> +	.version = THERMAL_GENL_VERSION,
> +	.maxattr = THERMAL_GENL_ATTR_MAX,
> +};
> +
> +static struct genl_multicast_group thermal_event_mcgrp = {
> +	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> +};
> +
> +int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> +					enum events event)
> +{
> +	struct sk_buff *skb;
> +	struct nlattr *attr;
> +	struct thermal_genl_event *thermal_event;
> +	void *msg_header;
> +	int size;
> +	int result;
> +	static unsigned int thermal_event_seqnum;
> +
> +	if (!tz)
> +		return -EINVAL;
> +
> +	/* allocate memory */
> +	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> +	       nla_total_size(0);
> +
> +	skb = genlmsg_new(size, GFP_ATOMIC);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	/* add the genetlink message header */
> +	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> +				 &thermal_event_genl_family, 0,
> +				 THERMAL_GENL_CMD_EVENT);
> +	if (!msg_header) {
> +		nlmsg_free(skb);
> +		return -ENOMEM;
> +	}
> +
> +	/* fill the data */
> +	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> +			   sizeof(struct thermal_genl_event));
> +
> +	if (!attr) {
> +		nlmsg_free(skb);
> +		return -EINVAL;
> +	}
> +
> +	thermal_event = nla_data(attr);
> +	if (!thermal_event) {
> +		nlmsg_free(skb);
> +		return -EINVAL;
> +	}
> +
> +	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> +
> +	thermal_event->orig = tz->id;
> +	thermal_event->event = event;
> +
> +	/* send multicast genetlink message */
> +	result = genlmsg_end(skb, msg_header);
> +	if (result < 0) {
> +		nlmsg_free(skb);
> +		return result;
> +	}
> +
> +	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
> +	if (result)
> +		dev_err(&tz->device, "Failed to send netlink event:%d", result);
> +
> +	return result;
> +}
> +EXPORT_SYMBOL(thermal_generate_netlink_event);
> +
> +static int genetlink_init(void)
> +{
> +	int result;
> +
> +	result = genl_register_family(&thermal_event_genl_family);
> +	if (result)
> +		return result;
> +
> +	result = genl_register_mc_group(&thermal_event_genl_family,
> +					&thermal_event_mcgrp);
> +	if (result)
> +		genl_unregister_family(&thermal_event_genl_family);
> +	return result;
> +}
> +
> +static void genetlink_exit(void)
> +{
> +	genl_unregister_family(&thermal_event_genl_family);
> +}
> +#else /* !CONFIG_NET */
> +static inline int genetlink_init(void) { return 0; }
> +static inline void genetlink_exit(void) {}
> +#endif /* !CONFIG_NET */
> +
> +static int __init thermal_init(void)
> +{
> +	int result = 0;
> +
> +	result = class_register(&thermal_class);
> +	if (result) {
> +		idr_destroy(&thermal_tz_idr);
> +		idr_destroy(&thermal_cdev_idr);
> +		mutex_destroy(&thermal_idr_lock);
> +		mutex_destroy(&thermal_list_lock);
> +		return result;
> +	}
> +	result = genetlink_init();
> +	return result;
> +}
> +
> +static void __exit thermal_exit(void)
> +{
> +	class_unregister(&thermal_class);
> +	idr_destroy(&thermal_tz_idr);
> +	idr_destroy(&thermal_cdev_idr);
> +	mutex_destroy(&thermal_idr_lock);
> +	mutex_destroy(&thermal_list_lock);
> +	genetlink_exit();
> +}
> +
> +fs_initcall(thermal_init);
> +module_exit(thermal_exit);
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> deleted file mode 100644
> index 5b7863a..0000000
> --- a/drivers/thermal/thermal_sys.c
> +++ /dev/null
> @@ -1,1888 +0,0 @@
> -/*
> - *  thermal.c - Generic Thermal Management Sysfs support.
> - *
> - *  Copyright (C) 2008 Intel Corp
> - *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> - *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> - *
> - *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> - *
> - *  This program is free software; you can redistribute it and/or modify
> - *  it under the terms of the GNU General Public License as published by
> - *  the Free Software Foundation; version 2 of the License.
> - *
> - *  This program is distributed in the hope that it will be useful, but
> - *  WITHOUT ANY WARRANTY; without even the implied warranty of
> - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> - *  General Public License for more details.
> - *
> - *  You should have received a copy of the GNU General Public License along
> - *  with this program; if not, write to the Free Software Foundation, Inc.,
> - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> - *
> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
> -#include <linux/device.h>
> -#include <linux/err.h>
> -#include <linux/slab.h>
> -#include <linux/kdev_t.h>
> -#include <linux/idr.h>
> -#include <linux/thermal.h>
> -#include <linux/reboot.h>
> -#include <net/netlink.h>
> -#include <net/genetlink.h>
> -
> -#include "thermal_core.h"
> -
> -MODULE_AUTHOR("Zhang Rui");
> -MODULE_DESCRIPTION("Generic thermal management sysfs support");
> -MODULE_LICENSE("GPL");
> -
> -static DEFINE_IDR(thermal_tz_idr);
> -static DEFINE_IDR(thermal_cdev_idr);
> -static DEFINE_MUTEX(thermal_idr_lock);
> -
> -static LIST_HEAD(thermal_tz_list);
> -static LIST_HEAD(thermal_cdev_list);
> -static LIST_HEAD(thermal_governor_list);
> -
> -static DEFINE_MUTEX(thermal_list_lock);
> -static DEFINE_MUTEX(thermal_governor_lock);
> -
> -static struct thermal_governor *__find_governor(const char *name)
> -{
> -	struct thermal_governor *pos;
> -
> -	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> -		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> -			return pos;
> -
> -	return NULL;
> -}
> -
> -int thermal_register_governor(struct thermal_governor *governor)
> -{
> -	int err;
> -	const char *name;
> -	struct thermal_zone_device *pos;
> -
> -	if (!governor)
> -		return -EINVAL;
> -
> -	mutex_lock(&thermal_governor_lock);
> -
> -	err = -EBUSY;
> -	if (__find_governor(governor->name) == NULL) {
> -		err = 0;
> -		list_add(&governor->governor_list, &thermal_governor_list);
> -	}
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> -		if (pos->governor)
> -			continue;
> -		if (pos->tzp)
> -			name = pos->tzp->governor_name;
> -		else
> -			name = DEFAULT_THERMAL_GOVERNOR;
> -		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
> -			pos->governor = governor;
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -	mutex_unlock(&thermal_governor_lock);
> -
> -	return err;
> -}
> -EXPORT_SYMBOL_GPL(thermal_register_governor);
> -
> -void thermal_unregister_governor(struct thermal_governor *governor)
> -{
> -	struct thermal_zone_device *pos;
> -
> -	if (!governor)
> -		return;
> -
> -	mutex_lock(&thermal_governor_lock);
> -
> -	if (__find_governor(governor->name) == NULL)
> -		goto exit;
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> -		if (!strnicmp(pos->governor->name, governor->name,
> -						THERMAL_NAME_LENGTH))
> -			pos->governor = NULL;
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -	list_del(&governor->governor_list);
> -exit:
> -	mutex_unlock(&thermal_governor_lock);
> -	return;
> -}
> -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> -
> -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> -{
> -	int ret;
> -
> -	if (lock)
> -		mutex_lock(lock);
> -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> -	if (lock)
> -		mutex_unlock(lock);
> -	if (unlikely(ret < 0))
> -		return ret;
> -	*id = ret;
> -	return 0;
> -}
> -
> -static void release_idr(struct idr *idr, struct mutex *lock, int id)
> -{
> -	if (lock)
> -		mutex_lock(lock);
> -	idr_remove(idr, id);
> -	if (lock)
> -		mutex_unlock(lock);
> -}
> -
> -int get_tz_trend(struct thermal_zone_device *tz, int trip)
> -{
> -	enum thermal_trend trend;
> -
> -	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> -		if (tz->temperature > tz->last_temperature)
> -			trend = THERMAL_TREND_RAISING;
> -		else if (tz->temperature < tz->last_temperature)
> -			trend = THERMAL_TREND_DROPPING;
> -		else
> -			trend = THERMAL_TREND_STABLE;
> -	}
> -
> -	return trend;
> -}
> -EXPORT_SYMBOL(get_tz_trend);
> -
> -struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
> -			struct thermal_cooling_device *cdev, int trip)
> -{
> -	struct thermal_instance *pos = NULL;
> -	struct thermal_instance *target_instance = NULL;
> -
> -	mutex_lock(&tz->lock);
> -	mutex_lock(&cdev->lock);
> -
> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> -			target_instance = pos;
> -			break;
> -		}
> -	}
> -
> -	mutex_unlock(&cdev->lock);
> -	mutex_unlock(&tz->lock);
> -
> -	return target_instance;
> -}
> -EXPORT_SYMBOL(get_thermal_instance);
> -
> -static void print_bind_err_msg(struct thermal_zone_device *tz,
> -			struct thermal_cooling_device *cdev, int ret)
> -{
> -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> -				tz->type, cdev->type, ret);
> -}
> -
> -static void __bind(struct thermal_zone_device *tz, int mask,
> -			struct thermal_cooling_device *cdev)
> -{
> -	int i, ret;
> -
> -	for (i = 0; i < tz->trips; i++) {
> -		if (mask & (1 << i)) {
> -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> -					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
> -			if (ret)
> -				print_bind_err_msg(tz, cdev, ret);
> -		}
> -	}
> -}
> -
> -static void __unbind(struct thermal_zone_device *tz, int mask,
> -			struct thermal_cooling_device *cdev)
> -{
> -	int i;
> -
> -	for (i = 0; i < tz->trips; i++)
> -		if (mask & (1 << i))
> -			thermal_zone_unbind_cooling_device(tz, i, cdev);
> -}
> -
> -static void bind_cdev(struct thermal_cooling_device *cdev)
> -{
> -	int i, ret;
> -	const struct thermal_zone_params *tzp;
> -	struct thermal_zone_device *pos = NULL;
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> -		if (!pos->tzp && !pos->ops->bind)
> -			continue;
> -
> -		if (!pos->tzp && pos->ops->bind) {
> -			ret = pos->ops->bind(pos, cdev);
> -			if (ret)
> -				print_bind_err_msg(pos, cdev, ret);
> -		}
> -
> -		tzp = pos->tzp;
> -		if (!tzp || !tzp->tbp)
> -			continue;
> -
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> -				continue;
> -			if (tzp->tbp[i].match(pos, cdev))
> -				continue;
> -			tzp->tbp[i].cdev = cdev;
> -			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> -		}
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -}
> -
> -static void bind_tz(struct thermal_zone_device *tz)
> -{
> -	int i, ret;
> -	struct thermal_cooling_device *pos = NULL;
> -	const struct thermal_zone_params *tzp = tz->tzp;
> -
> -	if (!tzp && !tz->ops->bind)
> -		return;
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	/* If there is no platform data, try to use ops->bind */
> -	if (!tzp && tz->ops->bind) {
> -		list_for_each_entry(pos, &thermal_cdev_list, node) {
> -			ret = tz->ops->bind(tz, pos);
> -			if (ret)
> -				print_bind_err_msg(tz, pos, ret);
> -		}
> -		goto exit;
> -	}
> -
> -	if (!tzp || !tzp->tbp)
> -		goto exit;
> -
> -	list_for_each_entry(pos, &thermal_cdev_list, node) {
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> -				continue;
> -			if (tzp->tbp[i].match(tz, pos))
> -				continue;
> -			tzp->tbp[i].cdev = pos;
> -			__bind(tz, tzp->tbp[i].trip_mask, pos);
> -		}
> -	}
> -exit:
> -	mutex_unlock(&thermal_list_lock);
> -}
> -
> -static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
> -					    int delay)
> -{
> -	if (delay > 1000)
> -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> -				 round_jiffies(msecs_to_jiffies(delay)));
> -	else if (delay)
> -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> -				 msecs_to_jiffies(delay));
> -	else
> -		cancel_delayed_work(&tz->poll_queue);
> -}
> -
> -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);
> -	else if (tz->polling_delay)
> -		thermal_zone_device_set_polling(tz, tz->polling_delay);
> -	else
> -		thermal_zone_device_set_polling(tz, 0);
> -
> -	mutex_unlock(&tz->lock);
> -}
> -
> -static void handle_non_critical_trips(struct thermal_zone_device *tz,
> -			int trip, enum thermal_trip_type trip_type)
> -{
> -	if (tz->governor)
> -		tz->governor->throttle(tz, trip);
> -}
> -
> -static void handle_critical_trips(struct thermal_zone_device *tz,
> -				int trip, enum thermal_trip_type trip_type)
> -{
> -	long trip_temp;
> -
> -	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> -
> -	/* If we have not crossed the trip_temp, we do not care. */
> -	if (tz->temperature < trip_temp)
> -		return;
> -
> -	if (tz->ops->notify)
> -		tz->ops->notify(tz, trip, trip_type);
> -
> -	if (trip_type == THERMAL_TRIP_CRITICAL) {
> -		dev_emerg(&tz->device,
> -			  "critical temperature reached(%d C),shutting down\n",
> -			  tz->temperature / 1000);
> -		orderly_poweroff(true);
> -	}
> -}
> -
> -static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> -{
> -	enum thermal_trip_type type;
> -
> -	tz->ops->get_trip_type(tz, trip, &type);
> -
> -	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
> -		handle_critical_trips(tz, trip, type);
> -	else
> -		handle_non_critical_trips(tz, trip, type);
> -	/*
> -	 * Alright, we handled this trip successfully.
> -	 * So, start monitoring again.
> -	 */
> -	monitor_thermal_zone(tz);
> -}
> -
> -static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> -				unsigned long *temp)
> -{
> -	int ret = 0;
> -#ifdef CONFIG_THERMAL_EMULATION
> -	int count;
> -	unsigned long crit_temp = -1UL;
> -	enum thermal_trip_type type;
> -#endif
> -
> -	mutex_lock(&tz->lock);
> -
> -	ret = tz->ops->get_temp(tz, temp);
> -#ifdef CONFIG_THERMAL_EMULATION
> -	if (!tz->emul_temperature)
> -		goto skip_emul;
> -
> -	for (count = 0; count < tz->trips; count++) {
> -		ret = tz->ops->get_trip_type(tz, count, &type);
> -		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> -			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> -			break;
> -		}
> -	}
> -
> -	if (ret)
> -		goto skip_emul;
> -
> -	if (*temp < crit_temp)
> -		*temp = tz->emul_temperature;
> -skip_emul:
> -#endif
> -	mutex_unlock(&tz->lock);
> -	return ret;
> -}
> -
> -static void update_temperature(struct thermal_zone_device *tz)
> -{
> -	long temp;
> -	int ret;
> -
> -	ret = thermal_zone_get_temp(tz, &temp);
> -	if (ret) {
> -		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
> -			 tz->id);
> -		return;
> -	}
> -
> -	mutex_lock(&tz->lock);
> -	tz->last_temperature = tz->temperature;
> -	tz->temperature = temp;
> -	mutex_unlock(&tz->lock);
> -}
> -
> -void thermal_zone_device_update(struct thermal_zone_device *tz)
> -{
> -	int count;
> -
> -	update_temperature(tz);
> -
> -	for (count = 0; count < tz->trips; count++)
> -		handle_thermal_trip(tz, count);
> -}
> -EXPORT_SYMBOL(thermal_zone_device_update);
> -
> -static void thermal_zone_device_check(struct work_struct *work)
> -{
> -	struct thermal_zone_device *tz = container_of(work, struct
> -						      thermal_zone_device,
> -						      poll_queue.work);
> -	thermal_zone_device_update(tz);
> -}
> -
> -/* sys I/F for thermal zone */
> -
> -#define to_thermal_zone(_dev) \
> -	container_of(_dev, struct thermal_zone_device, device)
> -
> -static ssize_t
> -type_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -
> -	return sprintf(buf, "%s\n", tz->type);
> -}
> -
> -static ssize_t
> -temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	long temperature;
> -	int ret;
> -
> -	ret = thermal_zone_get_temp(tz, &temperature);
> -
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	enum thermal_device_mode mode;
> -	int result;
> -
> -	if (!tz->ops->get_mode)
> -		return -EPERM;
> -
> -	result = tz->ops->get_mode(tz, &mode);
> -	if (result)
> -		return result;
> -
> -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
> -		       : "disabled");
> -}
> -
> -static ssize_t
> -mode_store(struct device *dev, struct device_attribute *attr,
> -	   const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int result;
> -
> -	if (!tz->ops->set_mode)
> -		return -EPERM;
> -
> -	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);
> -	else
> -		result = -EINVAL;
> -
> -	if (result)
> -		return result;
> -
> -	return count;
> -}
> -
> -static ssize_t
> -trip_point_type_show(struct device *dev, struct device_attribute *attr,
> -		     char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	enum thermal_trip_type type;
> -	int trip, result;
> -
> -	if (!tz->ops->get_trip_type)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> -		return -EINVAL;
> -
> -	result = tz->ops->get_trip_type(tz, trip, &type);
> -	if (result)
> -		return result;
> -
> -	switch (type) {
> -	case THERMAL_TRIP_CRITICAL:
> -		return sprintf(buf, "critical\n");
> -	case THERMAL_TRIP_HOT:
> -		return sprintf(buf, "hot\n");
> -	case THERMAL_TRIP_PASSIVE:
> -		return sprintf(buf, "passive\n");
> -	case THERMAL_TRIP_ACTIVE:
> -		return sprintf(buf, "active\n");
> -	default:
> -		return sprintf(buf, "unknown\n");
> -	}
> -}
> -
> -static ssize_t
> -trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> -		     const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	unsigned long temperature;
> -
> -	if (!tz->ops->set_trip_temp)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> -		return -EINVAL;
> -
> -	if (kstrtoul(buf, 10, &temperature))
> -		return -EINVAL;
> -
> -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> -
> -	return ret ? ret : count;
> -}
> -
> -static ssize_t
> -trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> -		     char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	long temperature;
> -
> -	if (!tz->ops->get_trip_temp)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> -		return -EINVAL;
> -
> -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> -
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> -			const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	unsigned long temperature;
> -
> -	if (!tz->ops->set_trip_hyst)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> -		return -EINVAL;
> -
> -	if (kstrtoul(buf, 10, &temperature))
> -		return -EINVAL;
> -
> -	/*
> -	 * We are not doing any check on the 'temperature' value
> -	 * here. The driver implementing 'set_trip_hyst' has to
> -	 * take care of this.
> -	 */
> -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> -
> -	return ret ? ret : count;
> -}
> -
> -static ssize_t
> -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> -			char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	unsigned long temperature;
> -
> -	if (!tz->ops->get_trip_hyst)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> -		return -EINVAL;
> -
> -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> -
> -	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -passive_store(struct device *dev, struct device_attribute *attr,
> -		    const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	struct thermal_cooling_device *cdev = NULL;
> -	int state;
> -
> -	if (!sscanf(buf, "%d\n", &state))
> -		return -EINVAL;
> -
> -	/* sanity check: values below 1000 millicelcius don't make sense
> -	 * and can cause the system to go into a thermal heart attack
> -	 */
> -	if (state && state < 1000)
> -		return -EINVAL;
> -
> -	if (state && !tz->forced_passive) {
> -		mutex_lock(&thermal_list_lock);
> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> -			if (!strncmp("Processor", cdev->type,
> -				     sizeof("Processor")))
> -				thermal_zone_bind_cooling_device(tz,
> -						THERMAL_TRIPS_NONE, cdev,
> -						THERMAL_NO_LIMIT,
> -						THERMAL_NO_LIMIT);
> -		}
> -		mutex_unlock(&thermal_list_lock);
> -		if (!tz->passive_delay)
> -			tz->passive_delay = 1000;
> -	} else if (!state && tz->forced_passive) {
> -		mutex_lock(&thermal_list_lock);
> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> -			if (!strncmp("Processor", cdev->type,
> -				     sizeof("Processor")))
> -				thermal_zone_unbind_cooling_device(tz,
> -								   THERMAL_TRIPS_NONE,
> -								   cdev);
> -		}
> -		mutex_unlock(&thermal_list_lock);
> -		tz->passive_delay = 0;
> -	}
> -
> -	tz->forced_passive = state;
> -
> -	thermal_zone_device_update(tz);
> -
> -	return count;
> -}
> -
> -static ssize_t
> -passive_show(struct device *dev, struct device_attribute *attr,
> -		   char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -
> -	return sprintf(buf, "%d\n", tz->forced_passive);
> -}
> -
> -static ssize_t
> -policy_store(struct device *dev, struct device_attribute *attr,
> -		    const char *buf, size_t count)
> -{
> -	int ret = -EINVAL;
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	struct thermal_governor *gov;
> -
> -	mutex_lock(&thermal_governor_lock);
> -
> -	gov = __find_governor(buf);
> -	if (!gov)
> -		goto exit;
> -
> -	tz->governor = gov;
> -	ret = count;
> -
> -exit:
> -	mutex_unlock(&thermal_governor_lock);
> -	return ret;
> -}
> -
> -static ssize_t
> -policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -
> -	return sprintf(buf, "%s\n", tz->governor->name);
> -}
> -
> -#ifdef CONFIG_THERMAL_EMULATION
> -static ssize_t
> -emul_temp_store(struct device *dev, struct device_attribute *attr,
> -		     const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int ret = 0;
> -	unsigned long temperature;
> -
> -	if (kstrtoul(buf, 10, &temperature))
> -		return -EINVAL;
> -
> -	if (!tz->ops->set_emul_temp) {
> -		mutex_lock(&tz->lock);
> -		tz->emul_temperature = temperature;
> -		mutex_unlock(&tz->lock);
> -	} else {
> -		ret = tz->ops->set_emul_temp(tz, temperature);
> -	}
> -
> -	return ret ? ret : count;
> -}
> -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> -#endif/*CONFIG_THERMAL_EMULATION*/
> -
> -static DEVICE_ATTR(type, 0444, type_show, NULL);
> -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
> -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
> -
> -/* sys I/F for cooling device */
> -#define to_cooling_device(_dev)	\
> -	container_of(_dev, struct thermal_cooling_device, device)
> -
> -static ssize_t
> -thermal_cooling_device_type_show(struct device *dev,
> -				 struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -
> -	return sprintf(buf, "%s\n", cdev->type);
> -}
> -
> -static ssize_t
> -thermal_cooling_device_max_state_show(struct device *dev,
> -				      struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -	unsigned long state;
> -	int ret;
> -
> -	ret = cdev->ops->get_max_state(cdev, &state);
> -	if (ret)
> -		return ret;
> -	return sprintf(buf, "%ld\n", state);
> -}
> -
> -static ssize_t
> -thermal_cooling_device_cur_state_show(struct device *dev,
> -				      struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -	unsigned long state;
> -	int ret;
> -
> -	ret = cdev->ops->get_cur_state(cdev, &state);
> -	if (ret)
> -		return ret;
> -	return sprintf(buf, "%ld\n", state);
> -}
> -
> -static ssize_t
> -thermal_cooling_device_cur_state_store(struct device *dev,
> -				       struct device_attribute *attr,
> -				       const char *buf, size_t count)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -	unsigned long state;
> -	int result;
> -
> -	if (!sscanf(buf, "%ld\n", &state))
> -		return -EINVAL;
> -
> -	if ((long)state < 0)
> -		return -EINVAL;
> -
> -	result = cdev->ops->set_cur_state(cdev, state);
> -	if (result)
> -		return result;
> -	return count;
> -}
> -
> -static struct device_attribute dev_attr_cdev_type =
> -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> -static DEVICE_ATTR(max_state, 0444,
> -		   thermal_cooling_device_max_state_show, NULL);
> -static DEVICE_ATTR(cur_state, 0644,
> -		   thermal_cooling_device_cur_state_show,
> -		   thermal_cooling_device_cur_state_store);
> -
> -static ssize_t
> -thermal_cooling_device_trip_point_show(struct device *dev,
> -				       struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_instance *instance;
> -
> -	instance =
> -	    container_of(attr, struct thermal_instance, attr);
> -
> -	if (instance->trip == THERMAL_TRIPS_NONE)
> -		return sprintf(buf, "-1\n");
> -	else
> -		return sprintf(buf, "%d\n", instance->trip);
> -}
> -
> -/* Device management */
> -
> -#if defined(CONFIG_THERMAL_HWMON)
> -
> -/* hwmon sys I/F */
> -#include <linux/hwmon.h>
> -
> -/* thermal zone devices with the same type share one hwmon device */
> -struct thermal_hwmon_device {
> -	char type[THERMAL_NAME_LENGTH];
> -	struct device *device;
> -	int count;
> -	struct list_head tz_list;
> -	struct list_head node;
> -};
> -
> -struct thermal_hwmon_attr {
> -	struct device_attribute attr;
> -	char name[16];
> -};
> -
> -/* one temperature input for each thermal zone */
> -struct thermal_hwmon_temp {
> -	struct list_head hwmon_node;
> -	struct thermal_zone_device *tz;
> -	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> -	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> -};
> -
> -static LIST_HEAD(thermal_hwmon_list);
> -
> -static ssize_t
> -name_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> -	return sprintf(buf, "%s\n", hwmon->type);
> -}
> -static DEVICE_ATTR(name, 0444, name_show, NULL);
> -
> -static ssize_t
> -temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	long temperature;
> -	int ret;
> -	struct thermal_hwmon_attr *hwmon_attr
> -			= container_of(attr, struct thermal_hwmon_attr, attr);
> -	struct thermal_hwmon_temp *temp
> -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> -				       temp_input);
> -	struct thermal_zone_device *tz = temp->tz;
> -
> -	ret = thermal_zone_get_temp(tz, &temperature);
> -
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -temp_crit_show(struct device *dev, struct device_attribute *attr,
> -		char *buf)
> -{
> -	struct thermal_hwmon_attr *hwmon_attr
> -			= container_of(attr, struct thermal_hwmon_attr, attr);
> -	struct thermal_hwmon_temp *temp
> -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> -				       temp_crit);
> -	struct thermal_zone_device *tz = temp->tz;
> -	long temperature;
> -	int ret;
> -
> -	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -
> -static struct thermal_hwmon_device *
> -thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_device *hwmon;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> -		if (!strcmp(hwmon->type, tz->type)) {
> -			mutex_unlock(&thermal_list_lock);
> -			return hwmon;
> -		}
> -	mutex_unlock(&thermal_list_lock);
> -
> -	return NULL;
> -}
> -
> -/* Find the temperature input matching a given thermal zone */
> -static struct thermal_hwmon_temp *
> -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
> -			  const struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_temp *temp;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> -		if (temp->tz == tz) {
> -			mutex_unlock(&thermal_list_lock);
> -			return temp;
> -		}
> -	mutex_unlock(&thermal_list_lock);
> -
> -	return NULL;
> -}
> -
> -static int
> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_device *hwmon;
> -	struct thermal_hwmon_temp *temp;
> -	int new_hwmon_device = 1;
> -	int result;
> -
> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> -	if (hwmon) {
> -		new_hwmon_device = 0;
> -		goto register_sys_interface;
> -	}
> -
> -	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
> -	if (!hwmon)
> -		return -ENOMEM;
> -
> -	INIT_LIST_HEAD(&hwmon->tz_list);
> -	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> -	hwmon->device = hwmon_device_register(NULL);
> -	if (IS_ERR(hwmon->device)) {
> -		result = PTR_ERR(hwmon->device);
> -		goto free_mem;
> -	}
> -	dev_set_drvdata(hwmon->device, hwmon);
> -	result = device_create_file(hwmon->device, &dev_attr_name);
> -	if (result)
> -		goto free_mem;
> -
> - register_sys_interface:
> -	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> -	if (!temp) {
> -		result = -ENOMEM;
> -		goto unregister_name;
> -	}
> -
> -	temp->tz = tz;
> -	hwmon->count++;
> -
> -	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
> -		 "temp%d_input", hwmon->count);
> -	temp->temp_input.attr.attr.name = temp->temp_input.name;
> -	temp->temp_input.attr.attr.mode = 0444;
> -	temp->temp_input.attr.show = temp_input_show;
> -	sysfs_attr_init(&temp->temp_input.attr.attr);
> -	result = device_create_file(hwmon->device, &temp->temp_input.attr);
> -	if (result)
> -		goto free_temp_mem;
> -
> -	if (tz->ops->get_crit_temp) {
> -		unsigned long temperature;
> -		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> -			snprintf(temp->temp_crit.name,
> -				 sizeof(temp->temp_crit.name),
> -				"temp%d_crit", hwmon->count);
> -			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
> -			temp->temp_crit.attr.attr.mode = 0444;
> -			temp->temp_crit.attr.show = temp_crit_show;
> -			sysfs_attr_init(&temp->temp_crit.attr.attr);
> -			result = device_create_file(hwmon->device,
> -						    &temp->temp_crit.attr);
> -			if (result)
> -				goto unregister_input;
> -		}
> -	}
> -
> -	mutex_lock(&thermal_list_lock);
> -	if (new_hwmon_device)
> -		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> -	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	return 0;
> -
> - unregister_input:
> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> - free_temp_mem:
> -	kfree(temp);
> - unregister_name:
> -	if (new_hwmon_device) {
> -		device_remove_file(hwmon->device, &dev_attr_name);
> -		hwmon_device_unregister(hwmon->device);
> -	}
> - free_mem:
> -	if (new_hwmon_device)
> -		kfree(hwmon);
> -
> -	return result;
> -}
> -
> -static void
> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_device *hwmon;
> -	struct thermal_hwmon_temp *temp;
> -
> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> -	if (unlikely(!hwmon)) {
> -		/* Should never happen... */
> -		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> -		return;
> -	}
> -
> -	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> -	if (unlikely(!temp)) {
> -		/* Should never happen... */
> -		dev_dbg(&tz->device, "temperature input lookup failed!\n");
> -		return;
> -	}
> -
> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> -	if (tz->ops->get_crit_temp)
> -		device_remove_file(hwmon->device, &temp->temp_crit.attr);
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_del(&temp->hwmon_node);
> -	kfree(temp);
> -	if (!list_empty(&hwmon->tz_list)) {
> -		mutex_unlock(&thermal_list_lock);
> -		return;
> -	}
> -	list_del(&hwmon->node);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	device_remove_file(hwmon->device, &dev_attr_name);
> -	hwmon_device_unregister(hwmon->device);
> -	kfree(hwmon);
> -}
> -#else
> -static int
> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -	return 0;
> -}
> -
> -static void
> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -}
> -#endif
> -
> -/**
> - * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
> - * @tz:		thermal zone device
> - * @trip:	indicates which trip point the cooling devices is
> - *		associated with in this thermal zone.
> - * @cdev:	thermal cooling device
> - *
> - * This function is usually called in the thermal zone device .bind callback.
> - */
> -int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> -				     int trip,
> -				     struct thermal_cooling_device *cdev,
> -				     unsigned long upper, unsigned long lower)
> -{
> -	struct thermal_instance *dev;
> -	struct thermal_instance *pos;
> -	struct thermal_zone_device *pos1;
> -	struct thermal_cooling_device *pos2;
> -	unsigned long max_state;
> -	int result;
> -
> -	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> -		return -EINVAL;
> -
> -	list_for_each_entry(pos1, &thermal_tz_list, node) {
> -		if (pos1 == tz)
> -			break;
> -	}
> -	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> -		if (pos2 == cdev)
> -			break;
> -	}
> -
> -	if (tz != pos1 || cdev != pos2)
> -		return -EINVAL;
> -
> -	cdev->ops->get_max_state(cdev, &max_state);
> -
> -	/* lower default 0, upper default max_state */
> -	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> -	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> -
> -	if (lower > upper || upper > max_state)
> -		return -EINVAL;
> -
> -	dev =
> -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> -	if (!dev)
> -		return -ENOMEM;
> -	dev->tz = tz;
> -	dev->cdev = cdev;
> -	dev->trip = trip;
> -	dev->upper = upper;
> -	dev->lower = lower;
> -	dev->target = THERMAL_NO_TARGET;
> -
> -	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> -	if (result)
> -		goto free_mem;
> -
> -	sprintf(dev->name, "cdev%d", dev->id);
> -	result =
> -	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
> -	if (result)
> -		goto release_idr;
> -
> -	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> -	sysfs_attr_init(&dev->attr.attr);
> -	dev->attr.attr.name = dev->attr_name;
> -	dev->attr.attr.mode = 0444;
> -	dev->attr.show = thermal_cooling_device_trip_point_show;
> -	result = device_create_file(&tz->device, &dev->attr);
> -	if (result)
> -		goto remove_symbol_link;
> -
> -	mutex_lock(&tz->lock);
> -	mutex_lock(&cdev->lock);
> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> -		result = -EEXIST;
> -		break;
> -	}
> -	if (!result) {
> -		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> -		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
> -	}
> -	mutex_unlock(&cdev->lock);
> -	mutex_unlock(&tz->lock);
> -
> -	if (!result)
> -		return 0;
> -
> -	device_remove_file(&tz->device, &dev->attr);
> -remove_symbol_link:
> -	sysfs_remove_link(&tz->device.kobj, dev->name);
> -release_idr:
> -	release_idr(&tz->idr, &tz->lock, dev->id);
> -free_mem:
> -	kfree(dev);
> -	return result;
> -}
> -EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> -
> -/**
> - * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
> - * @tz:		thermal zone device
> - * @trip:	indicates which trip point the cooling devices is
> - *		associated with in this thermal zone.
> - * @cdev:	thermal cooling device
> - *
> - * This function is usually called in the thermal zone device .unbind callback.
> - */
> -int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> -				       int trip,
> -				       struct thermal_cooling_device *cdev)
> -{
> -	struct thermal_instance *pos, *next;
> -
> -	mutex_lock(&tz->lock);
> -	mutex_lock(&cdev->lock);
> -	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> -			list_del(&pos->tz_node);
> -			list_del(&pos->cdev_node);
> -			mutex_unlock(&cdev->lock);
> -			mutex_unlock(&tz->lock);
> -			goto unbind;
> -		}
> -	}
> -	mutex_unlock(&cdev->lock);
> -	mutex_unlock(&tz->lock);
> -
> -	return -ENODEV;
> -
> -unbind:
> -	device_remove_file(&tz->device, &pos->attr);
> -	sysfs_remove_link(&tz->device.kobj, pos->name);
> -	release_idr(&tz->idr, &tz->lock, pos->id);
> -	kfree(pos);
> -	return 0;
> -}
> -EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> -
> -static void thermal_release(struct device *dev)
> -{
> -	struct thermal_zone_device *tz;
> -	struct thermal_cooling_device *cdev;
> -
> -	if (!strncmp(dev_name(dev), "thermal_zone",
> -		     sizeof("thermal_zone") - 1)) {
> -		tz = to_thermal_zone(dev);
> -		kfree(tz);
> -	} else {
> -		cdev = to_cooling_device(dev);
> -		kfree(cdev);
> -	}
> -}
> -
> -static struct class thermal_class = {
> -	.name = "thermal",
> -	.dev_release = thermal_release,
> -};
> -
> -/**
> - * thermal_cooling_device_register - register a new thermal cooling device
> - * @type:	the thermal cooling device type.
> - * @devdata:	device private data.
> - * @ops:		standard thermal cooling devices callbacks.
> - */
> -struct thermal_cooling_device *
> -thermal_cooling_device_register(char *type, void *devdata,
> -				const struct thermal_cooling_device_ops *ops)
> -{
> -	struct thermal_cooling_device *cdev;
> -	int result;
> -
> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> -	    !ops->set_cur_state)
> -		return ERR_PTR(-EINVAL);
> -
> -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> -	if (!cdev)
> -		return ERR_PTR(-ENOMEM);
> -
> -	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> -	if (result) {
> -		kfree(cdev);
> -		return ERR_PTR(result);
> -	}
> -
> -	strcpy(cdev->type, type ? : "");
> -	mutex_init(&cdev->lock);
> -	INIT_LIST_HEAD(&cdev->thermal_instances);
> -	cdev->ops = ops;
> -	cdev->updated = true;
> -	cdev->device.class = &thermal_class;
> -	cdev->devdata = devdata;
> -	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> -	result = device_register(&cdev->device);
> -	if (result) {
> -		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> -		kfree(cdev);
> -		return ERR_PTR(result);
> -	}
> -
> -	/* sys I/F */
> -	if (type) {
> -		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -	result = device_create_file(&cdev->device, &dev_attr_max_state);
> -	if (result)
> -		goto unregister;
> -
> -	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> -	if (result)
> -		goto unregister;
> -
> -	/* Add 'this' new cdev to the global cdev list */
> -	mutex_lock(&thermal_list_lock);
> -	list_add(&cdev->node, &thermal_cdev_list);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	/* Update binding information for 'this' new cdev */
> -	bind_cdev(cdev);
> -
> -	return cdev;
> -
> -unregister:
> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> -	device_unregister(&cdev->device);
> -	return ERR_PTR(result);
> -}
> -EXPORT_SYMBOL(thermal_cooling_device_register);
> -
> -/**
> - * thermal_cooling_device_unregister - removes the registered thermal cooling device
> - * @cdev:	the thermal cooling device to remove.
> - *
> - * thermal_cooling_device_unregister() must be called when the device is no
> - * longer needed.
> - */
> -void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
> -{
> -	int i;
> -	const struct thermal_zone_params *tzp;
> -	struct thermal_zone_device *tz;
> -	struct thermal_cooling_device *pos = NULL;
> -
> -	if (!cdev)
> -		return;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(pos, &thermal_cdev_list, node)
> -	    if (pos == cdev)
> -		break;
> -	if (pos != cdev) {
> -		/* thermal cooling device not found */
> -		mutex_unlock(&thermal_list_lock);
> -		return;
> -	}
> -	list_del(&cdev->node);
> -
> -	/* Unbind all thermal zones associated with 'this' cdev */
> -	list_for_each_entry(tz, &thermal_tz_list, node) {
> -		if (tz->ops->unbind) {
> -			tz->ops->unbind(tz, cdev);
> -			continue;
> -		}
> -
> -		if (!tz->tzp || !tz->tzp->tbp)
> -			continue;
> -
> -		tzp = tz->tzp;
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev == cdev) {
> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> -				tzp->tbp[i].cdev = NULL;
> -			}
> -		}
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -
> -	if (cdev->type[0])
> -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> -	device_remove_file(&cdev->device, &dev_attr_max_state);
> -	device_remove_file(&cdev->device, &dev_attr_cur_state);
> -
> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> -	device_unregister(&cdev->device);
> -	return;
> -}
> -EXPORT_SYMBOL(thermal_cooling_device_unregister);
> -
> -void thermal_cdev_update(struct thermal_cooling_device *cdev)
> -{
> -	struct thermal_instance *instance;
> -	unsigned long target = 0;
> -
> -	/* cooling device is updated*/
> -	if (cdev->updated)
> -		return;
> -
> -	mutex_lock(&cdev->lock);
> -	/* Make sure cdev enters the deepest cooling state */
> -	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
> -		if (instance->target == THERMAL_NO_TARGET)
> -			continue;
> -		if (instance->target > target)
> -			target = instance->target;
> -	}
> -	mutex_unlock(&cdev->lock);
> -	cdev->ops->set_cur_state(cdev, target);
> -	cdev->updated = true;
> -}
> -EXPORT_SYMBOL(thermal_cdev_update);
> -
> -/**
> - * notify_thermal_framework - Sensor drivers use this API to notify framework
> - * @tz:		thermal zone device
> - * @trip:	indicates which trip point has been crossed
> - *
> - * This function handles the trip events from sensor drivers. It starts
> - * throttling the cooling devices according to the policy configured.
> - * For CRITICAL and HOT trip points, this notifies the respective drivers,
> - * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> - * The throttling policy is based on the configured platform data; if no
> - * platform data is provided, this uses the step_wise throttling policy.
> - */
> -void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> -{
> -	handle_thermal_trip(tz, trip);
> -}
> -EXPORT_SYMBOL(notify_thermal_framework);
> -
> -/**
> - * create_trip_attrs - create attributes for trip points
> - * @tz:		the thermal zone device
> - * @mask:	Writeable trip point bitmap.
> - */
> -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> -{
> -	int indx;
> -	int size = sizeof(struct thermal_attr) * tz->trips;
> -
> -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> -	if (!tz->trip_type_attrs)
> -		return -ENOMEM;
> -
> -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> -	if (!tz->trip_temp_attrs) {
> -		kfree(tz->trip_type_attrs);
> -		return -ENOMEM;
> -	}
> -
> -	if (tz->ops->get_trip_hyst) {
> -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> -		if (!tz->trip_hyst_attrs) {
> -			kfree(tz->trip_type_attrs);
> -			kfree(tz->trip_temp_attrs);
> -			return -ENOMEM;
> -		}
> -	}
> -
> -
> -	for (indx = 0; indx < tz->trips; indx++) {
> -		/* create trip type attribute */
> -		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
> -			 "trip_point_%d_type", indx);
> -
> -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> -		tz->trip_type_attrs[indx].attr.attr.name =
> -						tz->trip_type_attrs[indx].name;
> -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> -
> -		device_create_file(&tz->device,
> -				   &tz->trip_type_attrs[indx].attr);
> -
> -		/* create trip temp attribute */
> -		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
> -			 "trip_point_%d_temp", indx);
> -
> -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> -		tz->trip_temp_attrs[indx].attr.attr.name =
> -						tz->trip_temp_attrs[indx].name;
> -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> -		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
> -		if (mask & (1 << indx)) {
> -			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
> -			tz->trip_temp_attrs[indx].attr.store =
> -							trip_point_temp_store;
> -		}
> -
> -		device_create_file(&tz->device,
> -				   &tz->trip_temp_attrs[indx].attr);
> -
> -		/* create Optional trip hyst attribute */
> -		if (!tz->ops->get_trip_hyst)
> -			continue;
> -		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
> -			 "trip_point_%d_hyst", indx);
> -
> -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> -		tz->trip_hyst_attrs[indx].attr.attr.name =
> -					tz->trip_hyst_attrs[indx].name;
> -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> -		if (tz->ops->set_trip_hyst) {
> -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> -			tz->trip_hyst_attrs[indx].attr.store =
> -					trip_point_hyst_store;
> -		}
> -
> -		device_create_file(&tz->device,
> -				   &tz->trip_hyst_attrs[indx].attr);
> -	}
> -	return 0;
> -}
> -
> -static void remove_trip_attrs(struct thermal_zone_device *tz)
> -{
> -	int indx;
> -
> -	for (indx = 0; indx < tz->trips; indx++) {
> -		device_remove_file(&tz->device,
> -				   &tz->trip_type_attrs[indx].attr);
> -		device_remove_file(&tz->device,
> -				   &tz->trip_temp_attrs[indx].attr);
> -		if (tz->ops->get_trip_hyst)
> -			device_remove_file(&tz->device,
> -				  &tz->trip_hyst_attrs[indx].attr);
> -	}
> -	kfree(tz->trip_type_attrs);
> -	kfree(tz->trip_temp_attrs);
> -	kfree(tz->trip_hyst_attrs);
> -}
> -
> -/**
> - * thermal_zone_device_register - register a new thermal zone device
> - * @type:	the thermal zone device type
> - * @trips:	the number of trip points the thermal zone support
> - * @mask:	a bit string indicating the writeablility of trip points
> - * @devdata:	private device data
> - * @ops:	standard thermal zone device callbacks
> - * @tzp:	thermal zone platform parameters
> - * @passive_delay: number of milliseconds to wait between polls when
> - *		   performing passive cooling
> - * @polling_delay: number of milliseconds to wait between polls when checking
> - *		   whether trip points have been crossed (0 for interrupt
> - *		   driven systems)
> - *
> - * thermal_zone_device_unregister() must be called when the device is no
> - * longer needed. The passive cooling depends on the .get_trend() return value.
> - */
> -struct thermal_zone_device *thermal_zone_device_register(const char *type,
> -	int trips, int mask, void *devdata,
> -	const struct thermal_zone_device_ops *ops,
> -	const struct thermal_zone_params *tzp,
> -	int passive_delay, int polling_delay)
> -{
> -	struct thermal_zone_device *tz;
> -	enum thermal_trip_type trip_type;
> -	int result;
> -	int count;
> -	int passive = 0;
> -
> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (!ops || !ops->get_temp)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (trips > 0 && !ops->get_trip_type)
> -		return ERR_PTR(-EINVAL);
> -
> -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> -	if (!tz)
> -		return ERR_PTR(-ENOMEM);
> -
> -	INIT_LIST_HEAD(&tz->thermal_instances);
> -	idr_init(&tz->idr);
> -	mutex_init(&tz->lock);
> -	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> -	if (result) {
> -		kfree(tz);
> -		return ERR_PTR(result);
> -	}
> -
> -	strcpy(tz->type, type ? : "");
> -	tz->ops = ops;
> -	tz->tzp = tzp;
> -	tz->device.class = &thermal_class;
> -	tz->devdata = devdata;
> -	tz->trips = trips;
> -	tz->passive_delay = passive_delay;
> -	tz->polling_delay = polling_delay;
> -
> -	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> -	result = device_register(&tz->device);
> -	if (result) {
> -		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> -		kfree(tz);
> -		return ERR_PTR(result);
> -	}
> -
> -	/* sys I/F */
> -	if (type) {
> -		result = device_create_file(&tz->device, &dev_attr_type);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -	result = device_create_file(&tz->device, &dev_attr_temp);
> -	if (result)
> -		goto unregister;
> -
> -	if (ops->get_mode) {
> -		result = device_create_file(&tz->device, &dev_attr_mode);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -	result = create_trip_attrs(tz, mask);
> -	if (result)
> -		goto unregister;
> -
> -	for (count = 0; count < trips; count++) {
> -		tz->ops->get_trip_type(tz, count, &trip_type);
> -		if (trip_type == THERMAL_TRIP_PASSIVE)
> -			passive = 1;
> -	}
> -
> -	if (!passive) {
> -		result = device_create_file(&tz->device, &dev_attr_passive);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -#ifdef CONFIG_THERMAL_EMULATION
> -	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> -	if (result)
> -		goto unregister;
> -#endif
> -	/* Create policy attribute */
> -	result = device_create_file(&tz->device, &dev_attr_policy);
> -	if (result)
> -		goto unregister;
> -
> -	/* Update 'this' zone's governor information */
> -	mutex_lock(&thermal_governor_lock);
> -
> -	if (tz->tzp)
> -		tz->governor = __find_governor(tz->tzp->governor_name);
> -	else
> -		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
> -
> -	mutex_unlock(&thermal_governor_lock);
> -
> -	result = thermal_add_hwmon_sysfs(tz);
> -	if (result)
> -		goto unregister;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_add_tail(&tz->node, &thermal_tz_list);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	/* Bind cooling devices for this zone */
> -	bind_tz(tz);
> -
> -	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
> -
> -	thermal_zone_device_update(tz);
> -
> -	if (!result)
> -		return tz;
> -
> -unregister:
> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> -	device_unregister(&tz->device);
> -	return ERR_PTR(result);
> -}
> -EXPORT_SYMBOL(thermal_zone_device_register);
> -
> -/**
> - * thermal_device_unregister - removes the registered thermal zone device
> - * @tz: the thermal zone device to remove
> - */
> -void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> -{
> -	int i;
> -	const struct thermal_zone_params *tzp;
> -	struct thermal_cooling_device *cdev;
> -	struct thermal_zone_device *pos = NULL;
> -
> -	if (!tz)
> -		return;
> -
> -	tzp = tz->tzp;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(pos, &thermal_tz_list, node)
> -	    if (pos == tz)
> -		break;
> -	if (pos != tz) {
> -		/* thermal zone device not found */
> -		mutex_unlock(&thermal_list_lock);
> -		return;
> -	}
> -	list_del(&tz->node);
> -
> -	/* Unbind all cdevs associated with 'this' thermal zone */
> -	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> -		if (tz->ops->unbind) {
> -			tz->ops->unbind(tz, cdev);
> -			continue;
> -		}
> -
> -		if (!tzp || !tzp->tbp)
> -			break;
> -
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev == cdev) {
> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> -				tzp->tbp[i].cdev = NULL;
> -			}
> -		}
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -
> -	thermal_zone_device_set_polling(tz, 0);
> -
> -	if (tz->type[0])
> -		device_remove_file(&tz->device, &dev_attr_type);
> -	device_remove_file(&tz->device, &dev_attr_temp);
> -	if (tz->ops->get_mode)
> -		device_remove_file(&tz->device, &dev_attr_mode);
> -	device_remove_file(&tz->device, &dev_attr_policy);
> -	remove_trip_attrs(tz);
> -	tz->governor = NULL;
> -
> -	thermal_remove_hwmon_sysfs(tz);
> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> -	idr_destroy(&tz->idr);
> -	mutex_destroy(&tz->lock);
> -	device_unregister(&tz->device);
> -	return;
> -}
> -EXPORT_SYMBOL(thermal_zone_device_unregister);
> -
> -#ifdef CONFIG_NET
> -static struct genl_family thermal_event_genl_family = {
> -	.id = GENL_ID_GENERATE,
> -	.name = THERMAL_GENL_FAMILY_NAME,
> -	.version = THERMAL_GENL_VERSION,
> -	.maxattr = THERMAL_GENL_ATTR_MAX,
> -};
> -
> -static struct genl_multicast_group thermal_event_mcgrp = {
> -	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> -};
> -
> -int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> -					enum events event)
> -{
> -	struct sk_buff *skb;
> -	struct nlattr *attr;
> -	struct thermal_genl_event *thermal_event;
> -	void *msg_header;
> -	int size;
> -	int result;
> -	static unsigned int thermal_event_seqnum;
> -
> -	if (!tz)
> -		return -EINVAL;
> -
> -	/* allocate memory */
> -	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> -	       nla_total_size(0);
> -
> -	skb = genlmsg_new(size, GFP_ATOMIC);
> -	if (!skb)
> -		return -ENOMEM;
> -
> -	/* add the genetlink message header */
> -	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> -				 &thermal_event_genl_family, 0,
> -				 THERMAL_GENL_CMD_EVENT);
> -	if (!msg_header) {
> -		nlmsg_free(skb);
> -		return -ENOMEM;
> -	}
> -
> -	/* fill the data */
> -	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> -			   sizeof(struct thermal_genl_event));
> -
> -	if (!attr) {
> -		nlmsg_free(skb);
> -		return -EINVAL;
> -	}
> -
> -	thermal_event = nla_data(attr);
> -	if (!thermal_event) {
> -		nlmsg_free(skb);
> -		return -EINVAL;
> -	}
> -
> -	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> -
> -	thermal_event->orig = tz->id;
> -	thermal_event->event = event;
> -
> -	/* send multicast genetlink message */
> -	result = genlmsg_end(skb, msg_header);
> -	if (result < 0) {
> -		nlmsg_free(skb);
> -		return result;
> -	}
> -
> -	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
> -	if (result)
> -		dev_err(&tz->device, "Failed to send netlink event:%d", result);
> -
> -	return result;
> -}
> -EXPORT_SYMBOL(thermal_generate_netlink_event);
> -
> -static int genetlink_init(void)
> -{
> -	int result;
> -
> -	result = genl_register_family(&thermal_event_genl_family);
> -	if (result)
> -		return result;
> -
> -	result = genl_register_mc_group(&thermal_event_genl_family,
> -					&thermal_event_mcgrp);
> -	if (result)
> -		genl_unregister_family(&thermal_event_genl_family);
> -	return result;
> -}
> -
> -static void genetlink_exit(void)
> -{
> -	genl_unregister_family(&thermal_event_genl_family);
> -}
> -#else /* !CONFIG_NET */
> -static inline int genetlink_init(void) { return 0; }
> -static inline void genetlink_exit(void) {}
> -#endif /* !CONFIG_NET */
> -
> -static int __init thermal_init(void)
> -{
> -	int result = 0;
> -
> -	result = class_register(&thermal_class);
> -	if (result) {
> -		idr_destroy(&thermal_tz_idr);
> -		idr_destroy(&thermal_cdev_idr);
> -		mutex_destroy(&thermal_idr_lock);
> -		mutex_destroy(&thermal_list_lock);
> -		return result;
> -	}
> -	result = genetlink_init();
> -	return result;
> -}
> -
> -static void __exit thermal_exit(void)
> -{
> -	class_unregister(&thermal_class);
> -	idr_destroy(&thermal_tz_idr);
> -	idr_destroy(&thermal_cdev_idr);
> -	mutex_destroy(&thermal_idr_lock);
> -	mutex_destroy(&thermal_list_lock);
> -	genetlink_exit();
> -}
> -
> -fs_initcall(thermal_init);
> -module_exit(thermal_exit);
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC,1/5] Thermal: rename thermal_sys.c to thermal_core.c
@ 2013-03-26 22:04     ` Eduardo Valentin
  0 siblings, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-03-26 22:04 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

Hi Rui,

A side note:
I'd really appreciate if you could copy on your patches on 
drivers/thermal/. I had some issues with TI server and got un subscribed 
from linux-pm. Now I will try to catch up any way,

Some comments.

On 26-03-2013 12:26, Zhang Rui wrote:
> No functional change in this patch.
>

Just a better description would also help on code version control.

> Signed-off-by: Zhang Rui <rui.zhang@intel.com>

Apart from minor comments, I agreed with this change. So feel free to 
add my:

Acked-by: Eduardo Valentin <eduardo.valentin@ti.com>

>
> ---
> drivers/thermal/Makefile       |    1 +
>   drivers/thermal/thermal_core.c | 1888 ++++++++++++++++++++++++++++++++++++++++
>   drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------

When sending renames, use git format-patch --find-renames, it makes a 
better summary of what you have done, specially if you have changed 
something in the file while renaming.

>   3 files changed, 1889 insertions(+), 1888 deletions(-)
>   create mode 100644 drivers/thermal/thermal_core.c
>   delete mode 100644 drivers/thermal/thermal_sys.c
>
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index d3a2b38..b2009bd 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -3,6 +3,7 @@
>   #
>
>   obj-$(CONFIG_THERMAL)		+= thermal_sys.o

I know this is for fixing the annoying bug with fan max speed. But while 
still here, do you think 'thermal_sys' is a good name for thermal 
framework driver? Maybe just 'thermal' would suffice?

> +thermal_sys-y			+= thermal_core.o
>
>   # governors
>   obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> new file mode 100644
> index 0000000..5b7863a
> --- /dev/null
> +++ b/drivers/thermal/thermal_core.c
> @@ -0,0 +1,1888 @@
> +/*
> + *  thermal.c - Generic Thermal Management Sysfs support.
> + *
> + *  Copyright (C) 2008 Intel Corp
> + *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> + *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> + *
> + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License as published by
> + *  the Free Software Foundation; version 2 of the License.
> + *
> + *  This program is distributed in the hope that it will be useful, but
> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  General Public License for more details.
> + *
> + *  You should have received a copy of the GNU General Public License along
> + *  with this program; if not, write to the Free Software Foundation, Inc.,
> + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> + *
> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> + */
> +
> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> +
> +#include <linux/module.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/slab.h>
> +#include <linux/kdev_t.h>
> +#include <linux/idr.h>
> +#include <linux/thermal.h>
> +#include <linux/reboot.h>
> +#include <net/netlink.h>
> +#include <net/genetlink.h>
> +
> +#include "thermal_core.h"
> +
> +MODULE_AUTHOR("Zhang Rui");
> +MODULE_DESCRIPTION("Generic thermal management sysfs support");
> +MODULE_LICENSE("GPL");
> +
> +static DEFINE_IDR(thermal_tz_idr);
> +static DEFINE_IDR(thermal_cdev_idr);
> +static DEFINE_MUTEX(thermal_idr_lock);
> +
> +static LIST_HEAD(thermal_tz_list);
> +static LIST_HEAD(thermal_cdev_list);
> +static LIST_HEAD(thermal_governor_list);
> +
> +static DEFINE_MUTEX(thermal_list_lock);
> +static DEFINE_MUTEX(thermal_governor_lock);
> +
> +static struct thermal_governor *__find_governor(const char *name)
> +{
> +	struct thermal_governor *pos;
> +
> +	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> +		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> +			return pos;
> +
> +	return NULL;
> +}
> +
> +int thermal_register_governor(struct thermal_governor *governor)
> +{
> +	int err;
> +	const char *name;
> +	struct thermal_zone_device *pos;
> +
> +	if (!governor)
> +		return -EINVAL;
> +
> +	mutex_lock(&thermal_governor_lock);
> +
> +	err = -EBUSY;
> +	if (__find_governor(governor->name) == NULL) {
> +		err = 0;
> +		list_add(&governor->governor_list, &thermal_governor_list);
> +	}
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> +		if (pos->governor)
> +			continue;
> +		if (pos->tzp)
> +			name = pos->tzp->governor_name;
> +		else
> +			name = DEFAULT_THERMAL_GOVERNOR;
> +		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
> +			pos->governor = governor;
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +	mutex_unlock(&thermal_governor_lock);
> +
> +	return err;
> +}
> +EXPORT_SYMBOL_GPL(thermal_register_governor);
> +
> +void thermal_unregister_governor(struct thermal_governor *governor)
> +{
> +	struct thermal_zone_device *pos;
> +
> +	if (!governor)
> +		return;
> +
> +	mutex_lock(&thermal_governor_lock);
> +
> +	if (__find_governor(governor->name) == NULL)
> +		goto exit;
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> +		if (!strnicmp(pos->governor->name, governor->name,
> +						THERMAL_NAME_LENGTH))
> +			pos->governor = NULL;
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +	list_del(&governor->governor_list);
> +exit:
> +	mutex_unlock(&thermal_governor_lock);
> +	return;
> +}
> +EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> +
> +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> +{
> +	int ret;
> +
> +	if (lock)
> +		mutex_lock(lock);
> +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> +	if (lock)
> +		mutex_unlock(lock);
> +	if (unlikely(ret < 0))
> +		return ret;
> +	*id = ret;
> +	return 0;
> +}
> +
> +static void release_idr(struct idr *idr, struct mutex *lock, int id)
> +{
> +	if (lock)
> +		mutex_lock(lock);
> +	idr_remove(idr, id);
> +	if (lock)
> +		mutex_unlock(lock);
> +}
> +
> +int get_tz_trend(struct thermal_zone_device *tz, int trip)
> +{
> +	enum thermal_trend trend;
> +
> +	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> +		if (tz->temperature > tz->last_temperature)
> +			trend = THERMAL_TREND_RAISING;
> +		else if (tz->temperature < tz->last_temperature)
> +			trend = THERMAL_TREND_DROPPING;
> +		else
> +			trend = THERMAL_TREND_STABLE;
> +	}
> +
> +	return trend;
> +}
> +EXPORT_SYMBOL(get_tz_trend);
> +
> +struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
> +			struct thermal_cooling_device *cdev, int trip)
> +{
> +	struct thermal_instance *pos = NULL;
> +	struct thermal_instance *target_instance = NULL;
> +
> +	mutex_lock(&tz->lock);
> +	mutex_lock(&cdev->lock);
> +
> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> +			target_instance = pos;
> +			break;
> +		}
> +	}
> +
> +	mutex_unlock(&cdev->lock);
> +	mutex_unlock(&tz->lock);
> +
> +	return target_instance;
> +}
> +EXPORT_SYMBOL(get_thermal_instance);
> +
> +static void print_bind_err_msg(struct thermal_zone_device *tz,
> +			struct thermal_cooling_device *cdev, int ret)
> +{
> +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> +				tz->type, cdev->type, ret);
> +}
> +
> +static void __bind(struct thermal_zone_device *tz, int mask,
> +			struct thermal_cooling_device *cdev)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < tz->trips; i++) {
> +		if (mask & (1 << i)) {
> +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> +					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
> +			if (ret)
> +				print_bind_err_msg(tz, cdev, ret);
> +		}
> +	}
> +}
> +
> +static void __unbind(struct thermal_zone_device *tz, int mask,
> +			struct thermal_cooling_device *cdev)
> +{
> +	int i;
> +
> +	for (i = 0; i < tz->trips; i++)
> +		if (mask & (1 << i))
> +			thermal_zone_unbind_cooling_device(tz, i, cdev);
> +}
> +
> +static void bind_cdev(struct thermal_cooling_device *cdev)
> +{
> +	int i, ret;
> +	const struct thermal_zone_params *tzp;
> +	struct thermal_zone_device *pos = NULL;
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> +		if (!pos->tzp && !pos->ops->bind)
> +			continue;
> +
> +		if (!pos->tzp && pos->ops->bind) {
> +			ret = pos->ops->bind(pos, cdev);
> +			if (ret)
> +				print_bind_err_msg(pos, cdev, ret);
> +		}
> +
> +		tzp = pos->tzp;
> +		if (!tzp || !tzp->tbp)
> +			continue;
> +
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> +				continue;
> +			if (tzp->tbp[i].match(pos, cdev))
> +				continue;
> +			tzp->tbp[i].cdev = cdev;
> +			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> +		}
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +}
> +
> +static void bind_tz(struct thermal_zone_device *tz)
> +{
> +	int i, ret;
> +	struct thermal_cooling_device *pos = NULL;
> +	const struct thermal_zone_params *tzp = tz->tzp;
> +
> +	if (!tzp && !tz->ops->bind)
> +		return;
> +
> +	mutex_lock(&thermal_list_lock);
> +
> +	/* If there is no platform data, try to use ops->bind */
> +	if (!tzp && tz->ops->bind) {
> +		list_for_each_entry(pos, &thermal_cdev_list, node) {
> +			ret = tz->ops->bind(tz, pos);
> +			if (ret)
> +				print_bind_err_msg(tz, pos, ret);
> +		}
> +		goto exit;
> +	}
> +
> +	if (!tzp || !tzp->tbp)
> +		goto exit;
> +
> +	list_for_each_entry(pos, &thermal_cdev_list, node) {
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> +				continue;
> +			if (tzp->tbp[i].match(tz, pos))
> +				continue;
> +			tzp->tbp[i].cdev = pos;
> +			__bind(tz, tzp->tbp[i].trip_mask, pos);
> +		}
> +	}
> +exit:
> +	mutex_unlock(&thermal_list_lock);
> +}
> +
> +static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
> +					    int delay)
> +{
> +	if (delay > 1000)
> +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> +				 round_jiffies(msecs_to_jiffies(delay)));
> +	else if (delay)
> +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> +				 msecs_to_jiffies(delay));
> +	else
> +		cancel_delayed_work(&tz->poll_queue);
> +}
> +
> +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);
> +	else if (tz->polling_delay)
> +		thermal_zone_device_set_polling(tz, tz->polling_delay);
> +	else
> +		thermal_zone_device_set_polling(tz, 0);
> +
> +	mutex_unlock(&tz->lock);
> +}
> +
> +static void handle_non_critical_trips(struct thermal_zone_device *tz,
> +			int trip, enum thermal_trip_type trip_type)
> +{
> +	if (tz->governor)
> +		tz->governor->throttle(tz, trip);
> +}
> +
> +static void handle_critical_trips(struct thermal_zone_device *tz,
> +				int trip, enum thermal_trip_type trip_type)
> +{
> +	long trip_temp;
> +
> +	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> +
> +	/* If we have not crossed the trip_temp, we do not care. */
> +	if (tz->temperature < trip_temp)
> +		return;
> +
> +	if (tz->ops->notify)
> +		tz->ops->notify(tz, trip, trip_type);
> +
> +	if (trip_type == THERMAL_TRIP_CRITICAL) {
> +		dev_emerg(&tz->device,
> +			  "critical temperature reached(%d C),shutting down\n",
> +			  tz->temperature / 1000);
> +		orderly_poweroff(true);
> +	}
> +}
> +
> +static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> +{
> +	enum thermal_trip_type type;
> +
> +	tz->ops->get_trip_type(tz, trip, &type);
> +
> +	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
> +		handle_critical_trips(tz, trip, type);
> +	else
> +		handle_non_critical_trips(tz, trip, type);
> +	/*
> +	 * Alright, we handled this trip successfully.
> +	 * So, start monitoring again.
> +	 */
> +	monitor_thermal_zone(tz);
> +}
> +
> +static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> +				unsigned long *temp)
> +{
> +	int ret = 0;
> +#ifdef CONFIG_THERMAL_EMULATION
> +	int count;
> +	unsigned long crit_temp = -1UL;
> +	enum thermal_trip_type type;
> +#endif
> +
> +	mutex_lock(&tz->lock);
> +
> +	ret = tz->ops->get_temp(tz, temp);
> +#ifdef CONFIG_THERMAL_EMULATION
> +	if (!tz->emul_temperature)
> +		goto skip_emul;
> +
> +	for (count = 0; count < tz->trips; count++) {
> +		ret = tz->ops->get_trip_type(tz, count, &type);
> +		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> +			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> +			break;
> +		}
> +	}
> +
> +	if (ret)
> +		goto skip_emul;
> +
> +	if (*temp < crit_temp)
> +		*temp = tz->emul_temperature;
> +skip_emul:
> +#endif
> +	mutex_unlock(&tz->lock);
> +	return ret;
> +}
> +
> +static void update_temperature(struct thermal_zone_device *tz)
> +{
> +	long temp;
> +	int ret;
> +
> +	ret = thermal_zone_get_temp(tz, &temp);
> +	if (ret) {
> +		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
> +			 tz->id);
> +		return;
> +	}
> +
> +	mutex_lock(&tz->lock);
> +	tz->last_temperature = tz->temperature;
> +	tz->temperature = temp;
> +	mutex_unlock(&tz->lock);
> +}
> +
> +void thermal_zone_device_update(struct thermal_zone_device *tz)
> +{
> +	int count;
> +
> +	update_temperature(tz);
> +
> +	for (count = 0; count < tz->trips; count++)
> +		handle_thermal_trip(tz, count);
> +}
> +EXPORT_SYMBOL(thermal_zone_device_update);
> +
> +static void thermal_zone_device_check(struct work_struct *work)
> +{
> +	struct thermal_zone_device *tz = container_of(work, struct
> +						      thermal_zone_device,
> +						      poll_queue.work);
> +	thermal_zone_device_update(tz);
> +}
> +
> +/* sys I/F for thermal zone */
> +
> +#define to_thermal_zone(_dev) \
> +	container_of(_dev, struct thermal_zone_device, device)
> +
> +static ssize_t
> +type_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> +	return sprintf(buf, "%s\n", tz->type);
> +}
> +
> +static ssize_t
> +temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	long temperature;
> +	int ret;
> +
> +	ret = thermal_zone_get_temp(tz, &temperature);
> +
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	enum thermal_device_mode mode;
> +	int result;
> +
> +	if (!tz->ops->get_mode)
> +		return -EPERM;
> +
> +	result = tz->ops->get_mode(tz, &mode);
> +	if (result)
> +		return result;
> +
> +	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
> +		       : "disabled");
> +}
> +
> +static ssize_t
> +mode_store(struct device *dev, struct device_attribute *attr,
> +	   const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int result;
> +
> +	if (!tz->ops->set_mode)
> +		return -EPERM;
> +
> +	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);
> +	else
> +		result = -EINVAL;
> +
> +	if (result)
> +		return result;
> +
> +	return count;
> +}
> +
> +static ssize_t
> +trip_point_type_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	enum thermal_trip_type type;
> +	int trip, result;
> +
> +	if (!tz->ops->get_trip_type)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> +		return -EINVAL;
> +
> +	result = tz->ops->get_trip_type(tz, trip, &type);
> +	if (result)
> +		return result;
> +
> +	switch (type) {
> +	case THERMAL_TRIP_CRITICAL:
> +		return sprintf(buf, "critical\n");
> +	case THERMAL_TRIP_HOT:
> +		return sprintf(buf, "hot\n");
> +	case THERMAL_TRIP_PASSIVE:
> +		return sprintf(buf, "passive\n");
> +	case THERMAL_TRIP_ACTIVE:
> +		return sprintf(buf, "active\n");
> +	default:
> +		return sprintf(buf, "unknown\n");
> +	}
> +}
> +
> +static ssize_t
> +trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> +		     const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	unsigned long temperature;
> +
> +	if (!tz->ops->set_trip_temp)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> +		return -EINVAL;
> +
> +	if (kstrtoul(buf, 10, &temperature))
> +		return -EINVAL;
> +
> +	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> +
> +	return ret ? ret : count;
> +}
> +
> +static ssize_t
> +trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> +		     char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	long temperature;
> +
> +	if (!tz->ops->get_trip_temp)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> +		return -EINVAL;
> +
> +	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> +
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> +			const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	unsigned long temperature;
> +
> +	if (!tz->ops->set_trip_hyst)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> +		return -EINVAL;
> +
> +	if (kstrtoul(buf, 10, &temperature))
> +		return -EINVAL;
> +
> +	/*
> +	 * We are not doing any check on the 'temperature' value
> +	 * here. The driver implementing 'set_trip_hyst' has to
> +	 * take care of this.
> +	 */
> +	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> +
> +	return ret ? ret : count;
> +}
> +
> +static ssize_t
> +trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> +			char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int trip, ret;
> +	unsigned long temperature;
> +
> +	if (!tz->ops->get_trip_hyst)
> +		return -EPERM;
> +
> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> +		return -EINVAL;
> +
> +	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> +
> +	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +passive_store(struct device *dev, struct device_attribute *attr,
> +		    const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	struct thermal_cooling_device *cdev = NULL;
> +	int state;
> +
> +	if (!sscanf(buf, "%d\n", &state))
> +		return -EINVAL;
> +
> +	/* sanity check: values below 1000 millicelcius don't make sense
> +	 * and can cause the system to go into a thermal heart attack
> +	 */
> +	if (state && state < 1000)
> +		return -EINVAL;
> +
> +	if (state && !tz->forced_passive) {
> +		mutex_lock(&thermal_list_lock);
> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> +			if (!strncmp("Processor", cdev->type,
> +				     sizeof("Processor")))
> +				thermal_zone_bind_cooling_device(tz,
> +						THERMAL_TRIPS_NONE, cdev,
> +						THERMAL_NO_LIMIT,
> +						THERMAL_NO_LIMIT);
> +		}
> +		mutex_unlock(&thermal_list_lock);
> +		if (!tz->passive_delay)
> +			tz->passive_delay = 1000;
> +	} else if (!state && tz->forced_passive) {
> +		mutex_lock(&thermal_list_lock);
> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> +			if (!strncmp("Processor", cdev->type,
> +				     sizeof("Processor")))
> +				thermal_zone_unbind_cooling_device(tz,
> +								   THERMAL_TRIPS_NONE,
> +								   cdev);
> +		}
> +		mutex_unlock(&thermal_list_lock);
> +		tz->passive_delay = 0;
> +	}
> +
> +	tz->forced_passive = state;
> +
> +	thermal_zone_device_update(tz);
> +
> +	return count;
> +}
> +
> +static ssize_t
> +passive_show(struct device *dev, struct device_attribute *attr,
> +		   char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> +	return sprintf(buf, "%d\n", tz->forced_passive);
> +}
> +
> +static ssize_t
> +policy_store(struct device *dev, struct device_attribute *attr,
> +		    const char *buf, size_t count)
> +{
> +	int ret = -EINVAL;
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	struct thermal_governor *gov;
> +
> +	mutex_lock(&thermal_governor_lock);
> +
> +	gov = __find_governor(buf);
> +	if (!gov)
> +		goto exit;
> +
> +	tz->governor = gov;
> +	ret = count;
> +
> +exit:
> +	mutex_unlock(&thermal_governor_lock);
> +	return ret;
> +}
> +
> +static ssize_t
> +policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +
> +	return sprintf(buf, "%s\n", tz->governor->name);
> +}
> +
> +#ifdef CONFIG_THERMAL_EMULATION
> +static ssize_t
> +emul_temp_store(struct device *dev, struct device_attribute *attr,
> +		     const char *buf, size_t count)
> +{
> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> +	int ret = 0;
> +	unsigned long temperature;
> +
> +	if (kstrtoul(buf, 10, &temperature))
> +		return -EINVAL;
> +
> +	if (!tz->ops->set_emul_temp) {
> +		mutex_lock(&tz->lock);
> +		tz->emul_temperature = temperature;
> +		mutex_unlock(&tz->lock);
> +	} else {
> +		ret = tz->ops->set_emul_temp(tz, temperature);
> +	}
> +
> +	return ret ? ret : count;
> +}
> +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> +#endif/*CONFIG_THERMAL_EMULATION*/
> +
> +static DEVICE_ATTR(type, 0444, type_show, NULL);
> +static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> +static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
> +static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
> +
> +/* sys I/F for cooling device */
> +#define to_cooling_device(_dev)	\
> +	container_of(_dev, struct thermal_cooling_device, device)
> +
> +static ssize_t
> +thermal_cooling_device_type_show(struct device *dev,
> +				 struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +
> +	return sprintf(buf, "%s\n", cdev->type);
> +}
> +
> +static ssize_t
> +thermal_cooling_device_max_state_show(struct device *dev,
> +				      struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +	unsigned long state;
> +	int ret;
> +
> +	ret = cdev->ops->get_max_state(cdev, &state);
> +	if (ret)
> +		return ret;
> +	return sprintf(buf, "%ld\n", state);
> +}
> +
> +static ssize_t
> +thermal_cooling_device_cur_state_show(struct device *dev,
> +				      struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +	unsigned long state;
> +	int ret;
> +
> +	ret = cdev->ops->get_cur_state(cdev, &state);
> +	if (ret)
> +		return ret;
> +	return sprintf(buf, "%ld\n", state);
> +}
> +
> +static ssize_t
> +thermal_cooling_device_cur_state_store(struct device *dev,
> +				       struct device_attribute *attr,
> +				       const char *buf, size_t count)
> +{
> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> +	unsigned long state;
> +	int result;
> +
> +	if (!sscanf(buf, "%ld\n", &state))
> +		return -EINVAL;
> +
> +	if ((long)state < 0)
> +		return -EINVAL;
> +
> +	result = cdev->ops->set_cur_state(cdev, state);
> +	if (result)
> +		return result;
> +	return count;
> +}
> +
> +static struct device_attribute dev_attr_cdev_type =
> +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> +static DEVICE_ATTR(max_state, 0444,
> +		   thermal_cooling_device_max_state_show, NULL);
> +static DEVICE_ATTR(cur_state, 0644,
> +		   thermal_cooling_device_cur_state_show,
> +		   thermal_cooling_device_cur_state_store);
> +
> +static ssize_t
> +thermal_cooling_device_trip_point_show(struct device *dev,
> +				       struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_instance *instance;
> +
> +	instance =
> +	    container_of(attr, struct thermal_instance, attr);
> +
> +	if (instance->trip == THERMAL_TRIPS_NONE)
> +		return sprintf(buf, "-1\n");
> +	else
> +		return sprintf(buf, "%d\n", instance->trip);
> +}
> +
> +/* Device management */
> +
> +#if defined(CONFIG_THERMAL_HWMON)
> +
> +/* hwmon sys I/F */
> +#include <linux/hwmon.h>
> +
> +/* thermal zone devices with the same type share one hwmon device */
> +struct thermal_hwmon_device {
> +	char type[THERMAL_NAME_LENGTH];
> +	struct device *device;
> +	int count;
> +	struct list_head tz_list;
> +	struct list_head node;
> +};
> +
> +struct thermal_hwmon_attr {
> +	struct device_attribute attr;
> +	char name[16];
> +};
> +
> +/* one temperature input for each thermal zone */
> +struct thermal_hwmon_temp {
> +	struct list_head hwmon_node;
> +	struct thermal_zone_device *tz;
> +	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> +	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> +};
> +
> +static LIST_HEAD(thermal_hwmon_list);
> +
> +static ssize_t
> +name_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> +	return sprintf(buf, "%s\n", hwmon->type);
> +}
> +static DEVICE_ATTR(name, 0444, name_show, NULL);
> +
> +static ssize_t
> +temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
> +{
> +	long temperature;
> +	int ret;
> +	struct thermal_hwmon_attr *hwmon_attr
> +			= container_of(attr, struct thermal_hwmon_attr, attr);
> +	struct thermal_hwmon_temp *temp
> +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> +				       temp_input);
> +	struct thermal_zone_device *tz = temp->tz;
> +
> +	ret = thermal_zone_get_temp(tz, &temperature);
> +
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +static ssize_t
> +temp_crit_show(struct device *dev, struct device_attribute *attr,
> +		char *buf)
> +{
> +	struct thermal_hwmon_attr *hwmon_attr
> +			= container_of(attr, struct thermal_hwmon_attr, attr);
> +	struct thermal_hwmon_temp *temp
> +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> +				       temp_crit);
> +	struct thermal_zone_device *tz = temp->tz;
> +	long temperature;
> +	int ret;
> +
> +	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> +	if (ret)
> +		return ret;
> +
> +	return sprintf(buf, "%ld\n", temperature);
> +}
> +
> +
> +static struct thermal_hwmon_device *
> +thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_device *hwmon;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> +		if (!strcmp(hwmon->type, tz->type)) {
> +			mutex_unlock(&thermal_list_lock);
> +			return hwmon;
> +		}
> +	mutex_unlock(&thermal_list_lock);
> +
> +	return NULL;
> +}
> +
> +/* Find the temperature input matching a given thermal zone */
> +static struct thermal_hwmon_temp *
> +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
> +			  const struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_temp *temp;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> +		if (temp->tz == tz) {
> +			mutex_unlock(&thermal_list_lock);
> +			return temp;
> +		}
> +	mutex_unlock(&thermal_list_lock);
> +
> +	return NULL;
> +}
> +
> +static int
> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_device *hwmon;
> +	struct thermal_hwmon_temp *temp;
> +	int new_hwmon_device = 1;
> +	int result;
> +
> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> +	if (hwmon) {
> +		new_hwmon_device = 0;
> +		goto register_sys_interface;
> +	}
> +
> +	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
> +	if (!hwmon)
> +		return -ENOMEM;
> +
> +	INIT_LIST_HEAD(&hwmon->tz_list);
> +	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> +	hwmon->device = hwmon_device_register(NULL);
> +	if (IS_ERR(hwmon->device)) {
> +		result = PTR_ERR(hwmon->device);
> +		goto free_mem;
> +	}
> +	dev_set_drvdata(hwmon->device, hwmon);
> +	result = device_create_file(hwmon->device, &dev_attr_name);
> +	if (result)
> +		goto free_mem;
> +
> + register_sys_interface:
> +	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> +	if (!temp) {
> +		result = -ENOMEM;
> +		goto unregister_name;
> +	}
> +
> +	temp->tz = tz;
> +	hwmon->count++;
> +
> +	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
> +		 "temp%d_input", hwmon->count);
> +	temp->temp_input.attr.attr.name = temp->temp_input.name;
> +	temp->temp_input.attr.attr.mode = 0444;
> +	temp->temp_input.attr.show = temp_input_show;
> +	sysfs_attr_init(&temp->temp_input.attr.attr);
> +	result = device_create_file(hwmon->device, &temp->temp_input.attr);
> +	if (result)
> +		goto free_temp_mem;
> +
> +	if (tz->ops->get_crit_temp) {
> +		unsigned long temperature;
> +		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> +			snprintf(temp->temp_crit.name,
> +				 sizeof(temp->temp_crit.name),
> +				"temp%d_crit", hwmon->count);
> +			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
> +			temp->temp_crit.attr.attr.mode = 0444;
> +			temp->temp_crit.attr.show = temp_crit_show;
> +			sysfs_attr_init(&temp->temp_crit.attr.attr);
> +			result = device_create_file(hwmon->device,
> +						    &temp->temp_crit.attr);
> +			if (result)
> +				goto unregister_input;
> +		}
> +	}
> +
> +	mutex_lock(&thermal_list_lock);
> +	if (new_hwmon_device)
> +		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> +	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	return 0;
> +
> + unregister_input:
> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> + free_temp_mem:
> +	kfree(temp);
> + unregister_name:
> +	if (new_hwmon_device) {
> +		device_remove_file(hwmon->device, &dev_attr_name);
> +		hwmon_device_unregister(hwmon->device);
> +	}
> + free_mem:
> +	if (new_hwmon_device)
> +		kfree(hwmon);
> +
> +	return result;
> +}
> +
> +static void
> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +	struct thermal_hwmon_device *hwmon;
> +	struct thermal_hwmon_temp *temp;
> +
> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> +	if (unlikely(!hwmon)) {
> +		/* Should never happen... */
> +		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> +		return;
> +	}
> +
> +	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> +	if (unlikely(!temp)) {
> +		/* Should never happen... */
> +		dev_dbg(&tz->device, "temperature input lookup failed!\n");
> +		return;
> +	}
> +
> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> +	if (tz->ops->get_crit_temp)
> +		device_remove_file(hwmon->device, &temp->temp_crit.attr);
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_del(&temp->hwmon_node);
> +	kfree(temp);
> +	if (!list_empty(&hwmon->tz_list)) {
> +		mutex_unlock(&thermal_list_lock);
> +		return;
> +	}
> +	list_del(&hwmon->node);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	device_remove_file(hwmon->device, &dev_attr_name);
> +	hwmon_device_unregister(hwmon->device);
> +	kfree(hwmon);
> +}
> +#else
> +static int
> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +	return 0;
> +}
> +
> +static void
> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> +{
> +}
> +#endif
> +
> +/**
> + * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
> + * @tz:		thermal zone device
> + * @trip:	indicates which trip point the cooling devices is
> + *		associated with in this thermal zone.
> + * @cdev:	thermal cooling device
> + *
> + * This function is usually called in the thermal zone device .bind callback.
> + */
> +int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> +				     int trip,
> +				     struct thermal_cooling_device *cdev,
> +				     unsigned long upper, unsigned long lower)
> +{
> +	struct thermal_instance *dev;
> +	struct thermal_instance *pos;
> +	struct thermal_zone_device *pos1;
> +	struct thermal_cooling_device *pos2;
> +	unsigned long max_state;
> +	int result;
> +
> +	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> +		return -EINVAL;
> +
> +	list_for_each_entry(pos1, &thermal_tz_list, node) {
> +		if (pos1 == tz)
> +			break;
> +	}
> +	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> +		if (pos2 == cdev)
> +			break;
> +	}
> +
> +	if (tz != pos1 || cdev != pos2)
> +		return -EINVAL;
> +
> +	cdev->ops->get_max_state(cdev, &max_state);
> +
> +	/* lower default 0, upper default max_state */
> +	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> +	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> +
> +	if (lower > upper || upper > max_state)
> +		return -EINVAL;
> +
> +	dev =
> +	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> +	if (!dev)
> +		return -ENOMEM;
> +	dev->tz = tz;
> +	dev->cdev = cdev;
> +	dev->trip = trip;
> +	dev->upper = upper;
> +	dev->lower = lower;
> +	dev->target = THERMAL_NO_TARGET;
> +
> +	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> +	if (result)
> +		goto free_mem;
> +
> +	sprintf(dev->name, "cdev%d", dev->id);
> +	result =
> +	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
> +	if (result)
> +		goto release_idr;
> +
> +	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> +	sysfs_attr_init(&dev->attr.attr);
> +	dev->attr.attr.name = dev->attr_name;
> +	dev->attr.attr.mode = 0444;
> +	dev->attr.show = thermal_cooling_device_trip_point_show;
> +	result = device_create_file(&tz->device, &dev->attr);
> +	if (result)
> +		goto remove_symbol_link;
> +
> +	mutex_lock(&tz->lock);
> +	mutex_lock(&cdev->lock);
> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> +	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> +		result = -EEXIST;
> +		break;
> +	}
> +	if (!result) {
> +		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> +		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
> +	}
> +	mutex_unlock(&cdev->lock);
> +	mutex_unlock(&tz->lock);
> +
> +	if (!result)
> +		return 0;
> +
> +	device_remove_file(&tz->device, &dev->attr);
> +remove_symbol_link:
> +	sysfs_remove_link(&tz->device.kobj, dev->name);
> +release_idr:
> +	release_idr(&tz->idr, &tz->lock, dev->id);
> +free_mem:
> +	kfree(dev);
> +	return result;
> +}
> +EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> +
> +/**
> + * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
> + * @tz:		thermal zone device
> + * @trip:	indicates which trip point the cooling devices is
> + *		associated with in this thermal zone.
> + * @cdev:	thermal cooling device
> + *
> + * This function is usually called in the thermal zone device .unbind callback.
> + */
> +int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> +				       int trip,
> +				       struct thermal_cooling_device *cdev)
> +{
> +	struct thermal_instance *pos, *next;
> +
> +	mutex_lock(&tz->lock);
> +	mutex_lock(&cdev->lock);
> +	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> +			list_del(&pos->tz_node);
> +			list_del(&pos->cdev_node);
> +			mutex_unlock(&cdev->lock);
> +			mutex_unlock(&tz->lock);
> +			goto unbind;
> +		}
> +	}
> +	mutex_unlock(&cdev->lock);
> +	mutex_unlock(&tz->lock);
> +
> +	return -ENODEV;
> +
> +unbind:
> +	device_remove_file(&tz->device, &pos->attr);
> +	sysfs_remove_link(&tz->device.kobj, pos->name);
> +	release_idr(&tz->idr, &tz->lock, pos->id);
> +	kfree(pos);
> +	return 0;
> +}
> +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> +
> +static void thermal_release(struct device *dev)
> +{
> +	struct thermal_zone_device *tz;
> +	struct thermal_cooling_device *cdev;
> +
> +	if (!strncmp(dev_name(dev), "thermal_zone",
> +		     sizeof("thermal_zone") - 1)) {
> +		tz = to_thermal_zone(dev);
> +		kfree(tz);
> +	} else {
> +		cdev = to_cooling_device(dev);
> +		kfree(cdev);
> +	}
> +}
> +
> +static struct class thermal_class = {
> +	.name = "thermal",
> +	.dev_release = thermal_release,
> +};
> +
> +/**
> + * thermal_cooling_device_register - register a new thermal cooling device
> + * @type:	the thermal cooling device type.
> + * @devdata:	device private data.
> + * @ops:		standard thermal cooling devices callbacks.
> + */
> +struct thermal_cooling_device *
> +thermal_cooling_device_register(char *type, void *devdata,
> +				const struct thermal_cooling_device_ops *ops)
> +{
> +	struct thermal_cooling_device *cdev;
> +	int result;
> +
> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> +	    !ops->set_cur_state)
> +		return ERR_PTR(-EINVAL);
> +
> +	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> +	if (!cdev)
> +		return ERR_PTR(-ENOMEM);
> +
> +	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> +	if (result) {
> +		kfree(cdev);
> +		return ERR_PTR(result);
> +	}
> +
> +	strcpy(cdev->type, type ? : "");
> +	mutex_init(&cdev->lock);
> +	INIT_LIST_HEAD(&cdev->thermal_instances);
> +	cdev->ops = ops;
> +	cdev->updated = true;
> +	cdev->device.class = &thermal_class;
> +	cdev->devdata = devdata;
> +	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> +	result = device_register(&cdev->device);
> +	if (result) {
> +		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> +		kfree(cdev);
> +		return ERR_PTR(result);
> +	}
> +
> +	/* sys I/F */
> +	if (type) {
> +		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +	result = device_create_file(&cdev->device, &dev_attr_max_state);
> +	if (result)
> +		goto unregister;
> +
> +	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> +	if (result)
> +		goto unregister;
> +
> +	/* Add 'this' new cdev to the global cdev list */
> +	mutex_lock(&thermal_list_lock);
> +	list_add(&cdev->node, &thermal_cdev_list);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	/* Update binding information for 'this' new cdev */
> +	bind_cdev(cdev);
> +
> +	return cdev;
> +
> +unregister:
> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> +	device_unregister(&cdev->device);
> +	return ERR_PTR(result);
> +}
> +EXPORT_SYMBOL(thermal_cooling_device_register);
> +
> +/**
> + * thermal_cooling_device_unregister - removes the registered thermal cooling device
> + * @cdev:	the thermal cooling device to remove.
> + *
> + * thermal_cooling_device_unregister() must be called when the device is no
> + * longer needed.
> + */
> +void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
> +{
> +	int i;
> +	const struct thermal_zone_params *tzp;
> +	struct thermal_zone_device *tz;
> +	struct thermal_cooling_device *pos = NULL;
> +
> +	if (!cdev)
> +		return;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(pos, &thermal_cdev_list, node)
> +	    if (pos == cdev)
> +		break;
> +	if (pos != cdev) {
> +		/* thermal cooling device not found */
> +		mutex_unlock(&thermal_list_lock);
> +		return;
> +	}
> +	list_del(&cdev->node);
> +
> +	/* Unbind all thermal zones associated with 'this' cdev */
> +	list_for_each_entry(tz, &thermal_tz_list, node) {
> +		if (tz->ops->unbind) {
> +			tz->ops->unbind(tz, cdev);
> +			continue;
> +		}
> +
> +		if (!tz->tzp || !tz->tzp->tbp)
> +			continue;
> +
> +		tzp = tz->tzp;
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev == cdev) {
> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> +				tzp->tbp[i].cdev = NULL;
> +			}
> +		}
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +
> +	if (cdev->type[0])
> +		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> +	device_remove_file(&cdev->device, &dev_attr_max_state);
> +	device_remove_file(&cdev->device, &dev_attr_cur_state);
> +
> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> +	device_unregister(&cdev->device);
> +	return;
> +}
> +EXPORT_SYMBOL(thermal_cooling_device_unregister);
> +
> +void thermal_cdev_update(struct thermal_cooling_device *cdev)
> +{
> +	struct thermal_instance *instance;
> +	unsigned long target = 0;
> +
> +	/* cooling device is updated*/
> +	if (cdev->updated)
> +		return;
> +
> +	mutex_lock(&cdev->lock);
> +	/* Make sure cdev enters the deepest cooling state */
> +	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
> +		if (instance->target == THERMAL_NO_TARGET)
> +			continue;
> +		if (instance->target > target)
> +			target = instance->target;
> +	}
> +	mutex_unlock(&cdev->lock);
> +	cdev->ops->set_cur_state(cdev, target);
> +	cdev->updated = true;
> +}
> +EXPORT_SYMBOL(thermal_cdev_update);
> +
> +/**
> + * notify_thermal_framework - Sensor drivers use this API to notify framework
> + * @tz:		thermal zone device
> + * @trip:	indicates which trip point has been crossed
> + *
> + * This function handles the trip events from sensor drivers. It starts
> + * throttling the cooling devices according to the policy configured.
> + * For CRITICAL and HOT trip points, this notifies the respective drivers,
> + * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> + * The throttling policy is based on the configured platform data; if no
> + * platform data is provided, this uses the step_wise throttling policy.
> + */
> +void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> +{
> +	handle_thermal_trip(tz, trip);
> +}
> +EXPORT_SYMBOL(notify_thermal_framework);
> +
> +/**
> + * create_trip_attrs - create attributes for trip points
> + * @tz:		the thermal zone device
> + * @mask:	Writeable trip point bitmap.
> + */
> +static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> +{
> +	int indx;
> +	int size = sizeof(struct thermal_attr) * tz->trips;
> +
> +	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> +	if (!tz->trip_type_attrs)
> +		return -ENOMEM;
> +
> +	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> +	if (!tz->trip_temp_attrs) {
> +		kfree(tz->trip_type_attrs);
> +		return -ENOMEM;
> +	}
> +
> +	if (tz->ops->get_trip_hyst) {
> +		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> +		if (!tz->trip_hyst_attrs) {
> +			kfree(tz->trip_type_attrs);
> +			kfree(tz->trip_temp_attrs);
> +			return -ENOMEM;
> +		}
> +	}
> +
> +
> +	for (indx = 0; indx < tz->trips; indx++) {
> +		/* create trip type attribute */
> +		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
> +			 "trip_point_%d_type", indx);
> +
> +		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> +		tz->trip_type_attrs[indx].attr.attr.name =
> +						tz->trip_type_attrs[indx].name;
> +		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> +		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> +
> +		device_create_file(&tz->device,
> +				   &tz->trip_type_attrs[indx].attr);
> +
> +		/* create trip temp attribute */
> +		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
> +			 "trip_point_%d_temp", indx);
> +
> +		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> +		tz->trip_temp_attrs[indx].attr.attr.name =
> +						tz->trip_temp_attrs[indx].name;
> +		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> +		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
> +		if (mask & (1 << indx)) {
> +			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
> +			tz->trip_temp_attrs[indx].attr.store =
> +							trip_point_temp_store;
> +		}
> +
> +		device_create_file(&tz->device,
> +				   &tz->trip_temp_attrs[indx].attr);
> +
> +		/* create Optional trip hyst attribute */
> +		if (!tz->ops->get_trip_hyst)
> +			continue;
> +		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
> +			 "trip_point_%d_hyst", indx);
> +
> +		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> +		tz->trip_hyst_attrs[indx].attr.attr.name =
> +					tz->trip_hyst_attrs[indx].name;
> +		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> +		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> +		if (tz->ops->set_trip_hyst) {
> +			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> +			tz->trip_hyst_attrs[indx].attr.store =
> +					trip_point_hyst_store;
> +		}
> +
> +		device_create_file(&tz->device,
> +				   &tz->trip_hyst_attrs[indx].attr);
> +	}
> +	return 0;
> +}
> +
> +static void remove_trip_attrs(struct thermal_zone_device *tz)
> +{
> +	int indx;
> +
> +	for (indx = 0; indx < tz->trips; indx++) {
> +		device_remove_file(&tz->device,
> +				   &tz->trip_type_attrs[indx].attr);
> +		device_remove_file(&tz->device,
> +				   &tz->trip_temp_attrs[indx].attr);
> +		if (tz->ops->get_trip_hyst)
> +			device_remove_file(&tz->device,
> +				  &tz->trip_hyst_attrs[indx].attr);
> +	}
> +	kfree(tz->trip_type_attrs);
> +	kfree(tz->trip_temp_attrs);
> +	kfree(tz->trip_hyst_attrs);
> +}
> +
> +/**
> + * thermal_zone_device_register - register a new thermal zone device
> + * @type:	the thermal zone device type
> + * @trips:	the number of trip points the thermal zone support
> + * @mask:	a bit string indicating the writeablility of trip points
> + * @devdata:	private device data
> + * @ops:	standard thermal zone device callbacks
> + * @tzp:	thermal zone platform parameters
> + * @passive_delay: number of milliseconds to wait between polls when
> + *		   performing passive cooling
> + * @polling_delay: number of milliseconds to wait between polls when checking
> + *		   whether trip points have been crossed (0 for interrupt
> + *		   driven systems)
> + *
> + * thermal_zone_device_unregister() must be called when the device is no
> + * longer needed. The passive cooling depends on the .get_trend() return value.
> + */
> +struct thermal_zone_device *thermal_zone_device_register(const char *type,
> +	int trips, int mask, void *devdata,
> +	const struct thermal_zone_device_ops *ops,
> +	const struct thermal_zone_params *tzp,
> +	int passive_delay, int polling_delay)
> +{
> +	struct thermal_zone_device *tz;
> +	enum thermal_trip_type trip_type;
> +	int result;
> +	int count;
> +	int passive = 0;
> +
> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (!ops || !ops->get_temp)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (trips > 0 && !ops->get_trip_type)
> +		return ERR_PTR(-EINVAL);
> +
> +	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> +	if (!tz)
> +		return ERR_PTR(-ENOMEM);
> +
> +	INIT_LIST_HEAD(&tz->thermal_instances);
> +	idr_init(&tz->idr);
> +	mutex_init(&tz->lock);
> +	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> +	if (result) {
> +		kfree(tz);
> +		return ERR_PTR(result);
> +	}
> +
> +	strcpy(tz->type, type ? : "");
> +	tz->ops = ops;
> +	tz->tzp = tzp;
> +	tz->device.class = &thermal_class;
> +	tz->devdata = devdata;
> +	tz->trips = trips;
> +	tz->passive_delay = passive_delay;
> +	tz->polling_delay = polling_delay;
> +
> +	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> +	result = device_register(&tz->device);
> +	if (result) {
> +		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> +		kfree(tz);
> +		return ERR_PTR(result);
> +	}
> +
> +	/* sys I/F */
> +	if (type) {
> +		result = device_create_file(&tz->device, &dev_attr_type);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +	result = device_create_file(&tz->device, &dev_attr_temp);
> +	if (result)
> +		goto unregister;
> +
> +	if (ops->get_mode) {
> +		result = device_create_file(&tz->device, &dev_attr_mode);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +	result = create_trip_attrs(tz, mask);
> +	if (result)
> +		goto unregister;
> +
> +	for (count = 0; count < trips; count++) {
> +		tz->ops->get_trip_type(tz, count, &trip_type);
> +		if (trip_type == THERMAL_TRIP_PASSIVE)
> +			passive = 1;
> +	}
> +
> +	if (!passive) {
> +		result = device_create_file(&tz->device, &dev_attr_passive);
> +		if (result)
> +			goto unregister;
> +	}
> +
> +#ifdef CONFIG_THERMAL_EMULATION
> +	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> +	if (result)
> +		goto unregister;
> +#endif
> +	/* Create policy attribute */
> +	result = device_create_file(&tz->device, &dev_attr_policy);
> +	if (result)
> +		goto unregister;
> +
> +	/* Update 'this' zone's governor information */
> +	mutex_lock(&thermal_governor_lock);
> +
> +	if (tz->tzp)
> +		tz->governor = __find_governor(tz->tzp->governor_name);
> +	else
> +		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
> +
> +	mutex_unlock(&thermal_governor_lock);
> +
> +	result = thermal_add_hwmon_sysfs(tz);
> +	if (result)
> +		goto unregister;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_add_tail(&tz->node, &thermal_tz_list);
> +	mutex_unlock(&thermal_list_lock);
> +
> +	/* Bind cooling devices for this zone */
> +	bind_tz(tz);
> +
> +	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
> +
> +	thermal_zone_device_update(tz);
> +
> +	if (!result)
> +		return tz;
> +
> +unregister:
> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> +	device_unregister(&tz->device);
> +	return ERR_PTR(result);
> +}
> +EXPORT_SYMBOL(thermal_zone_device_register);
> +
> +/**
> + * thermal_device_unregister - removes the registered thermal zone device
> + * @tz: the thermal zone device to remove
> + */
> +void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> +{
> +	int i;
> +	const struct thermal_zone_params *tzp;
> +	struct thermal_cooling_device *cdev;
> +	struct thermal_zone_device *pos = NULL;
> +
> +	if (!tz)
> +		return;
> +
> +	tzp = tz->tzp;
> +
> +	mutex_lock(&thermal_list_lock);
> +	list_for_each_entry(pos, &thermal_tz_list, node)
> +	    if (pos == tz)
> +		break;
> +	if (pos != tz) {
> +		/* thermal zone device not found */
> +		mutex_unlock(&thermal_list_lock);
> +		return;
> +	}
> +	list_del(&tz->node);
> +
> +	/* Unbind all cdevs associated with 'this' thermal zone */
> +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> +		if (tz->ops->unbind) {
> +			tz->ops->unbind(tz, cdev);
> +			continue;
> +		}
> +
> +		if (!tzp || !tzp->tbp)
> +			break;
> +
> +		for (i = 0; i < tzp->num_tbps; i++) {
> +			if (tzp->tbp[i].cdev == cdev) {
> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> +				tzp->tbp[i].cdev = NULL;
> +			}
> +		}
> +	}
> +
> +	mutex_unlock(&thermal_list_lock);
> +
> +	thermal_zone_device_set_polling(tz, 0);
> +
> +	if (tz->type[0])
> +		device_remove_file(&tz->device, &dev_attr_type);
> +	device_remove_file(&tz->device, &dev_attr_temp);
> +	if (tz->ops->get_mode)
> +		device_remove_file(&tz->device, &dev_attr_mode);
> +	device_remove_file(&tz->device, &dev_attr_policy);
> +	remove_trip_attrs(tz);
> +	tz->governor = NULL;
> +
> +	thermal_remove_hwmon_sysfs(tz);
> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> +	idr_destroy(&tz->idr);
> +	mutex_destroy(&tz->lock);
> +	device_unregister(&tz->device);
> +	return;
> +}
> +EXPORT_SYMBOL(thermal_zone_device_unregister);
> +
> +#ifdef CONFIG_NET
> +static struct genl_family thermal_event_genl_family = {
> +	.id = GENL_ID_GENERATE,
> +	.name = THERMAL_GENL_FAMILY_NAME,
> +	.version = THERMAL_GENL_VERSION,
> +	.maxattr = THERMAL_GENL_ATTR_MAX,
> +};
> +
> +static struct genl_multicast_group thermal_event_mcgrp = {
> +	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> +};
> +
> +int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> +					enum events event)
> +{
> +	struct sk_buff *skb;
> +	struct nlattr *attr;
> +	struct thermal_genl_event *thermal_event;
> +	void *msg_header;
> +	int size;
> +	int result;
> +	static unsigned int thermal_event_seqnum;
> +
> +	if (!tz)
> +		return -EINVAL;
> +
> +	/* allocate memory */
> +	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> +	       nla_total_size(0);
> +
> +	skb = genlmsg_new(size, GFP_ATOMIC);
> +	if (!skb)
> +		return -ENOMEM;
> +
> +	/* add the genetlink message header */
> +	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> +				 &thermal_event_genl_family, 0,
> +				 THERMAL_GENL_CMD_EVENT);
> +	if (!msg_header) {
> +		nlmsg_free(skb);
> +		return -ENOMEM;
> +	}
> +
> +	/* fill the data */
> +	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> +			   sizeof(struct thermal_genl_event));
> +
> +	if (!attr) {
> +		nlmsg_free(skb);
> +		return -EINVAL;
> +	}
> +
> +	thermal_event = nla_data(attr);
> +	if (!thermal_event) {
> +		nlmsg_free(skb);
> +		return -EINVAL;
> +	}
> +
> +	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> +
> +	thermal_event->orig = tz->id;
> +	thermal_event->event = event;
> +
> +	/* send multicast genetlink message */
> +	result = genlmsg_end(skb, msg_header);
> +	if (result < 0) {
> +		nlmsg_free(skb);
> +		return result;
> +	}
> +
> +	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
> +	if (result)
> +		dev_err(&tz->device, "Failed to send netlink event:%d", result);
> +
> +	return result;
> +}
> +EXPORT_SYMBOL(thermal_generate_netlink_event);
> +
> +static int genetlink_init(void)
> +{
> +	int result;
> +
> +	result = genl_register_family(&thermal_event_genl_family);
> +	if (result)
> +		return result;
> +
> +	result = genl_register_mc_group(&thermal_event_genl_family,
> +					&thermal_event_mcgrp);
> +	if (result)
> +		genl_unregister_family(&thermal_event_genl_family);
> +	return result;
> +}
> +
> +static void genetlink_exit(void)
> +{
> +	genl_unregister_family(&thermal_event_genl_family);
> +}
> +#else /* !CONFIG_NET */
> +static inline int genetlink_init(void) { return 0; }
> +static inline void genetlink_exit(void) {}
> +#endif /* !CONFIG_NET */
> +
> +static int __init thermal_init(void)
> +{
> +	int result = 0;
> +
> +	result = class_register(&thermal_class);
> +	if (result) {
> +		idr_destroy(&thermal_tz_idr);
> +		idr_destroy(&thermal_cdev_idr);
> +		mutex_destroy(&thermal_idr_lock);
> +		mutex_destroy(&thermal_list_lock);
> +		return result;
> +	}
> +	result = genetlink_init();
> +	return result;
> +}
> +
> +static void __exit thermal_exit(void)
> +{
> +	class_unregister(&thermal_class);
> +	idr_destroy(&thermal_tz_idr);
> +	idr_destroy(&thermal_cdev_idr);
> +	mutex_destroy(&thermal_idr_lock);
> +	mutex_destroy(&thermal_list_lock);
> +	genetlink_exit();
> +}
> +
> +fs_initcall(thermal_init);
> +module_exit(thermal_exit);
> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> deleted file mode 100644
> index 5b7863a..0000000
> --- a/drivers/thermal/thermal_sys.c
> +++ /dev/null
> @@ -1,1888 +0,0 @@
> -/*
> - *  thermal.c - Generic Thermal Management Sysfs support.
> - *
> - *  Copyright (C) 2008 Intel Corp
> - *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> - *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> - *
> - *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> - *
> - *  This program is free software; you can redistribute it and/or modify
> - *  it under the terms of the GNU General Public License as published by
> - *  the Free Software Foundation; version 2 of the License.
> - *
> - *  This program is distributed in the hope that it will be useful, but
> - *  WITHOUT ANY WARRANTY; without even the implied warranty of
> - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> - *  General Public License for more details.
> - *
> - *  You should have received a copy of the GNU General Public License along
> - *  with this program; if not, write to the Free Software Foundation, Inc.,
> - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> - *
> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> - */
> -
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
> -#include <linux/device.h>
> -#include <linux/err.h>
> -#include <linux/slab.h>
> -#include <linux/kdev_t.h>
> -#include <linux/idr.h>
> -#include <linux/thermal.h>
> -#include <linux/reboot.h>
> -#include <net/netlink.h>
> -#include <net/genetlink.h>
> -
> -#include "thermal_core.h"
> -
> -MODULE_AUTHOR("Zhang Rui");
> -MODULE_DESCRIPTION("Generic thermal management sysfs support");
> -MODULE_LICENSE("GPL");
> -
> -static DEFINE_IDR(thermal_tz_idr);
> -static DEFINE_IDR(thermal_cdev_idr);
> -static DEFINE_MUTEX(thermal_idr_lock);
> -
> -static LIST_HEAD(thermal_tz_list);
> -static LIST_HEAD(thermal_cdev_list);
> -static LIST_HEAD(thermal_governor_list);
> -
> -static DEFINE_MUTEX(thermal_list_lock);
> -static DEFINE_MUTEX(thermal_governor_lock);
> -
> -static struct thermal_governor *__find_governor(const char *name)
> -{
> -	struct thermal_governor *pos;
> -
> -	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> -		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> -			return pos;
> -
> -	return NULL;
> -}
> -
> -int thermal_register_governor(struct thermal_governor *governor)
> -{
> -	int err;
> -	const char *name;
> -	struct thermal_zone_device *pos;
> -
> -	if (!governor)
> -		return -EINVAL;
> -
> -	mutex_lock(&thermal_governor_lock);
> -
> -	err = -EBUSY;
> -	if (__find_governor(governor->name) == NULL) {
> -		err = 0;
> -		list_add(&governor->governor_list, &thermal_governor_list);
> -	}
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> -		if (pos->governor)
> -			continue;
> -		if (pos->tzp)
> -			name = pos->tzp->governor_name;
> -		else
> -			name = DEFAULT_THERMAL_GOVERNOR;
> -		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
> -			pos->governor = governor;
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -	mutex_unlock(&thermal_governor_lock);
> -
> -	return err;
> -}
> -EXPORT_SYMBOL_GPL(thermal_register_governor);
> -
> -void thermal_unregister_governor(struct thermal_governor *governor)
> -{
> -	struct thermal_zone_device *pos;
> -
> -	if (!governor)
> -		return;
> -
> -	mutex_lock(&thermal_governor_lock);
> -
> -	if (__find_governor(governor->name) == NULL)
> -		goto exit;
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> -		if (!strnicmp(pos->governor->name, governor->name,
> -						THERMAL_NAME_LENGTH))
> -			pos->governor = NULL;
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -	list_del(&governor->governor_list);
> -exit:
> -	mutex_unlock(&thermal_governor_lock);
> -	return;
> -}
> -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> -
> -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> -{
> -	int ret;
> -
> -	if (lock)
> -		mutex_lock(lock);
> -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> -	if (lock)
> -		mutex_unlock(lock);
> -	if (unlikely(ret < 0))
> -		return ret;
> -	*id = ret;
> -	return 0;
> -}
> -
> -static void release_idr(struct idr *idr, struct mutex *lock, int id)
> -{
> -	if (lock)
> -		mutex_lock(lock);
> -	idr_remove(idr, id);
> -	if (lock)
> -		mutex_unlock(lock);
> -}
> -
> -int get_tz_trend(struct thermal_zone_device *tz, int trip)
> -{
> -	enum thermal_trend trend;
> -
> -	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> -		if (tz->temperature > tz->last_temperature)
> -			trend = THERMAL_TREND_RAISING;
> -		else if (tz->temperature < tz->last_temperature)
> -			trend = THERMAL_TREND_DROPPING;
> -		else
> -			trend = THERMAL_TREND_STABLE;
> -	}
> -
> -	return trend;
> -}
> -EXPORT_SYMBOL(get_tz_trend);
> -
> -struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
> -			struct thermal_cooling_device *cdev, int trip)
> -{
> -	struct thermal_instance *pos = NULL;
> -	struct thermal_instance *target_instance = NULL;
> -
> -	mutex_lock(&tz->lock);
> -	mutex_lock(&cdev->lock);
> -
> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> -			target_instance = pos;
> -			break;
> -		}
> -	}
> -
> -	mutex_unlock(&cdev->lock);
> -	mutex_unlock(&tz->lock);
> -
> -	return target_instance;
> -}
> -EXPORT_SYMBOL(get_thermal_instance);
> -
> -static void print_bind_err_msg(struct thermal_zone_device *tz,
> -			struct thermal_cooling_device *cdev, int ret)
> -{
> -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> -				tz->type, cdev->type, ret);
> -}
> -
> -static void __bind(struct thermal_zone_device *tz, int mask,
> -			struct thermal_cooling_device *cdev)
> -{
> -	int i, ret;
> -
> -	for (i = 0; i < tz->trips; i++) {
> -		if (mask & (1 << i)) {
> -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> -					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
> -			if (ret)
> -				print_bind_err_msg(tz, cdev, ret);
> -		}
> -	}
> -}
> -
> -static void __unbind(struct thermal_zone_device *tz, int mask,
> -			struct thermal_cooling_device *cdev)
> -{
> -	int i;
> -
> -	for (i = 0; i < tz->trips; i++)
> -		if (mask & (1 << i))
> -			thermal_zone_unbind_cooling_device(tz, i, cdev);
> -}
> -
> -static void bind_cdev(struct thermal_cooling_device *cdev)
> -{
> -	int i, ret;
> -	const struct thermal_zone_params *tzp;
> -	struct thermal_zone_device *pos = NULL;
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> -		if (!pos->tzp && !pos->ops->bind)
> -			continue;
> -
> -		if (!pos->tzp && pos->ops->bind) {
> -			ret = pos->ops->bind(pos, cdev);
> -			if (ret)
> -				print_bind_err_msg(pos, cdev, ret);
> -		}
> -
> -		tzp = pos->tzp;
> -		if (!tzp || !tzp->tbp)
> -			continue;
> -
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> -				continue;
> -			if (tzp->tbp[i].match(pos, cdev))
> -				continue;
> -			tzp->tbp[i].cdev = cdev;
> -			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> -		}
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -}
> -
> -static void bind_tz(struct thermal_zone_device *tz)
> -{
> -	int i, ret;
> -	struct thermal_cooling_device *pos = NULL;
> -	const struct thermal_zone_params *tzp = tz->tzp;
> -
> -	if (!tzp && !tz->ops->bind)
> -		return;
> -
> -	mutex_lock(&thermal_list_lock);
> -
> -	/* If there is no platform data, try to use ops->bind */
> -	if (!tzp && tz->ops->bind) {
> -		list_for_each_entry(pos, &thermal_cdev_list, node) {
> -			ret = tz->ops->bind(tz, pos);
> -			if (ret)
> -				print_bind_err_msg(tz, pos, ret);
> -		}
> -		goto exit;
> -	}
> -
> -	if (!tzp || !tzp->tbp)
> -		goto exit;
> -
> -	list_for_each_entry(pos, &thermal_cdev_list, node) {
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> -				continue;
> -			if (tzp->tbp[i].match(tz, pos))
> -				continue;
> -			tzp->tbp[i].cdev = pos;
> -			__bind(tz, tzp->tbp[i].trip_mask, pos);
> -		}
> -	}
> -exit:
> -	mutex_unlock(&thermal_list_lock);
> -}
> -
> -static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
> -					    int delay)
> -{
> -	if (delay > 1000)
> -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> -				 round_jiffies(msecs_to_jiffies(delay)));
> -	else if (delay)
> -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> -				 msecs_to_jiffies(delay));
> -	else
> -		cancel_delayed_work(&tz->poll_queue);
> -}
> -
> -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);
> -	else if (tz->polling_delay)
> -		thermal_zone_device_set_polling(tz, tz->polling_delay);
> -	else
> -		thermal_zone_device_set_polling(tz, 0);
> -
> -	mutex_unlock(&tz->lock);
> -}
> -
> -static void handle_non_critical_trips(struct thermal_zone_device *tz,
> -			int trip, enum thermal_trip_type trip_type)
> -{
> -	if (tz->governor)
> -		tz->governor->throttle(tz, trip);
> -}
> -
> -static void handle_critical_trips(struct thermal_zone_device *tz,
> -				int trip, enum thermal_trip_type trip_type)
> -{
> -	long trip_temp;
> -
> -	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> -
> -	/* If we have not crossed the trip_temp, we do not care. */
> -	if (tz->temperature < trip_temp)
> -		return;
> -
> -	if (tz->ops->notify)
> -		tz->ops->notify(tz, trip, trip_type);
> -
> -	if (trip_type == THERMAL_TRIP_CRITICAL) {
> -		dev_emerg(&tz->device,
> -			  "critical temperature reached(%d C),shutting down\n",
> -			  tz->temperature / 1000);
> -		orderly_poweroff(true);
> -	}
> -}
> -
> -static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> -{
> -	enum thermal_trip_type type;
> -
> -	tz->ops->get_trip_type(tz, trip, &type);
> -
> -	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
> -		handle_critical_trips(tz, trip, type);
> -	else
> -		handle_non_critical_trips(tz, trip, type);
> -	/*
> -	 * Alright, we handled this trip successfully.
> -	 * So, start monitoring again.
> -	 */
> -	monitor_thermal_zone(tz);
> -}
> -
> -static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> -				unsigned long *temp)
> -{
> -	int ret = 0;
> -#ifdef CONFIG_THERMAL_EMULATION
> -	int count;
> -	unsigned long crit_temp = -1UL;
> -	enum thermal_trip_type type;
> -#endif
> -
> -	mutex_lock(&tz->lock);
> -
> -	ret = tz->ops->get_temp(tz, temp);
> -#ifdef CONFIG_THERMAL_EMULATION
> -	if (!tz->emul_temperature)
> -		goto skip_emul;
> -
> -	for (count = 0; count < tz->trips; count++) {
> -		ret = tz->ops->get_trip_type(tz, count, &type);
> -		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> -			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> -			break;
> -		}
> -	}
> -
> -	if (ret)
> -		goto skip_emul;
> -
> -	if (*temp < crit_temp)
> -		*temp = tz->emul_temperature;
> -skip_emul:
> -#endif
> -	mutex_unlock(&tz->lock);
> -	return ret;
> -}
> -
> -static void update_temperature(struct thermal_zone_device *tz)
> -{
> -	long temp;
> -	int ret;
> -
> -	ret = thermal_zone_get_temp(tz, &temp);
> -	if (ret) {
> -		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
> -			 tz->id);
> -		return;
> -	}
> -
> -	mutex_lock(&tz->lock);
> -	tz->last_temperature = tz->temperature;
> -	tz->temperature = temp;
> -	mutex_unlock(&tz->lock);
> -}
> -
> -void thermal_zone_device_update(struct thermal_zone_device *tz)
> -{
> -	int count;
> -
> -	update_temperature(tz);
> -
> -	for (count = 0; count < tz->trips; count++)
> -		handle_thermal_trip(tz, count);
> -}
> -EXPORT_SYMBOL(thermal_zone_device_update);
> -
> -static void thermal_zone_device_check(struct work_struct *work)
> -{
> -	struct thermal_zone_device *tz = container_of(work, struct
> -						      thermal_zone_device,
> -						      poll_queue.work);
> -	thermal_zone_device_update(tz);
> -}
> -
> -/* sys I/F for thermal zone */
> -
> -#define to_thermal_zone(_dev) \
> -	container_of(_dev, struct thermal_zone_device, device)
> -
> -static ssize_t
> -type_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -
> -	return sprintf(buf, "%s\n", tz->type);
> -}
> -
> -static ssize_t
> -temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	long temperature;
> -	int ret;
> -
> -	ret = thermal_zone_get_temp(tz, &temperature);
> -
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	enum thermal_device_mode mode;
> -	int result;
> -
> -	if (!tz->ops->get_mode)
> -		return -EPERM;
> -
> -	result = tz->ops->get_mode(tz, &mode);
> -	if (result)
> -		return result;
> -
> -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
> -		       : "disabled");
> -}
> -
> -static ssize_t
> -mode_store(struct device *dev, struct device_attribute *attr,
> -	   const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int result;
> -
> -	if (!tz->ops->set_mode)
> -		return -EPERM;
> -
> -	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);
> -	else
> -		result = -EINVAL;
> -
> -	if (result)
> -		return result;
> -
> -	return count;
> -}
> -
> -static ssize_t
> -trip_point_type_show(struct device *dev, struct device_attribute *attr,
> -		     char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	enum thermal_trip_type type;
> -	int trip, result;
> -
> -	if (!tz->ops->get_trip_type)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> -		return -EINVAL;
> -
> -	result = tz->ops->get_trip_type(tz, trip, &type);
> -	if (result)
> -		return result;
> -
> -	switch (type) {
> -	case THERMAL_TRIP_CRITICAL:
> -		return sprintf(buf, "critical\n");
> -	case THERMAL_TRIP_HOT:
> -		return sprintf(buf, "hot\n");
> -	case THERMAL_TRIP_PASSIVE:
> -		return sprintf(buf, "passive\n");
> -	case THERMAL_TRIP_ACTIVE:
> -		return sprintf(buf, "active\n");
> -	default:
> -		return sprintf(buf, "unknown\n");
> -	}
> -}
> -
> -static ssize_t
> -trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> -		     const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	unsigned long temperature;
> -
> -	if (!tz->ops->set_trip_temp)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> -		return -EINVAL;
> -
> -	if (kstrtoul(buf, 10, &temperature))
> -		return -EINVAL;
> -
> -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> -
> -	return ret ? ret : count;
> -}
> -
> -static ssize_t
> -trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> -		     char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	long temperature;
> -
> -	if (!tz->ops->get_trip_temp)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> -		return -EINVAL;
> -
> -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> -
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> -			const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	unsigned long temperature;
> -
> -	if (!tz->ops->set_trip_hyst)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> -		return -EINVAL;
> -
> -	if (kstrtoul(buf, 10, &temperature))
> -		return -EINVAL;
> -
> -	/*
> -	 * We are not doing any check on the 'temperature' value
> -	 * here. The driver implementing 'set_trip_hyst' has to
> -	 * take care of this.
> -	 */
> -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> -
> -	return ret ? ret : count;
> -}
> -
> -static ssize_t
> -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> -			char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int trip, ret;
> -	unsigned long temperature;
> -
> -	if (!tz->ops->get_trip_hyst)
> -		return -EPERM;
> -
> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> -		return -EINVAL;
> -
> -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> -
> -	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -passive_store(struct device *dev, struct device_attribute *attr,
> -		    const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	struct thermal_cooling_device *cdev = NULL;
> -	int state;
> -
> -	if (!sscanf(buf, "%d\n", &state))
> -		return -EINVAL;
> -
> -	/* sanity check: values below 1000 millicelcius don't make sense
> -	 * and can cause the system to go into a thermal heart attack
> -	 */
> -	if (state && state < 1000)
> -		return -EINVAL;
> -
> -	if (state && !tz->forced_passive) {
> -		mutex_lock(&thermal_list_lock);
> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> -			if (!strncmp("Processor", cdev->type,
> -				     sizeof("Processor")))
> -				thermal_zone_bind_cooling_device(tz,
> -						THERMAL_TRIPS_NONE, cdev,
> -						THERMAL_NO_LIMIT,
> -						THERMAL_NO_LIMIT);
> -		}
> -		mutex_unlock(&thermal_list_lock);
> -		if (!tz->passive_delay)
> -			tz->passive_delay = 1000;
> -	} else if (!state && tz->forced_passive) {
> -		mutex_lock(&thermal_list_lock);
> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> -			if (!strncmp("Processor", cdev->type,
> -				     sizeof("Processor")))
> -				thermal_zone_unbind_cooling_device(tz,
> -								   THERMAL_TRIPS_NONE,
> -								   cdev);
> -		}
> -		mutex_unlock(&thermal_list_lock);
> -		tz->passive_delay = 0;
> -	}
> -
> -	tz->forced_passive = state;
> -
> -	thermal_zone_device_update(tz);
> -
> -	return count;
> -}
> -
> -static ssize_t
> -passive_show(struct device *dev, struct device_attribute *attr,
> -		   char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -
> -	return sprintf(buf, "%d\n", tz->forced_passive);
> -}
> -
> -static ssize_t
> -policy_store(struct device *dev, struct device_attribute *attr,
> -		    const char *buf, size_t count)
> -{
> -	int ret = -EINVAL;
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	struct thermal_governor *gov;
> -
> -	mutex_lock(&thermal_governor_lock);
> -
> -	gov = __find_governor(buf);
> -	if (!gov)
> -		goto exit;
> -
> -	tz->governor = gov;
> -	ret = count;
> -
> -exit:
> -	mutex_unlock(&thermal_governor_lock);
> -	return ret;
> -}
> -
> -static ssize_t
> -policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -
> -	return sprintf(buf, "%s\n", tz->governor->name);
> -}
> -
> -#ifdef CONFIG_THERMAL_EMULATION
> -static ssize_t
> -emul_temp_store(struct device *dev, struct device_attribute *attr,
> -		     const char *buf, size_t count)
> -{
> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> -	int ret = 0;
> -	unsigned long temperature;
> -
> -	if (kstrtoul(buf, 10, &temperature))
> -		return -EINVAL;
> -
> -	if (!tz->ops->set_emul_temp) {
> -		mutex_lock(&tz->lock);
> -		tz->emul_temperature = temperature;
> -		mutex_unlock(&tz->lock);
> -	} else {
> -		ret = tz->ops->set_emul_temp(tz, temperature);
> -	}
> -
> -	return ret ? ret : count;
> -}
> -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> -#endif/*CONFIG_THERMAL_EMULATION*/
> -
> -static DEVICE_ATTR(type, 0444, type_show, NULL);
> -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
> -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
> -
> -/* sys I/F for cooling device */
> -#define to_cooling_device(_dev)	\
> -	container_of(_dev, struct thermal_cooling_device, device)
> -
> -static ssize_t
> -thermal_cooling_device_type_show(struct device *dev,
> -				 struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -
> -	return sprintf(buf, "%s\n", cdev->type);
> -}
> -
> -static ssize_t
> -thermal_cooling_device_max_state_show(struct device *dev,
> -				      struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -	unsigned long state;
> -	int ret;
> -
> -	ret = cdev->ops->get_max_state(cdev, &state);
> -	if (ret)
> -		return ret;
> -	return sprintf(buf, "%ld\n", state);
> -}
> -
> -static ssize_t
> -thermal_cooling_device_cur_state_show(struct device *dev,
> -				      struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -	unsigned long state;
> -	int ret;
> -
> -	ret = cdev->ops->get_cur_state(cdev, &state);
> -	if (ret)
> -		return ret;
> -	return sprintf(buf, "%ld\n", state);
> -}
> -
> -static ssize_t
> -thermal_cooling_device_cur_state_store(struct device *dev,
> -				       struct device_attribute *attr,
> -				       const char *buf, size_t count)
> -{
> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> -	unsigned long state;
> -	int result;
> -
> -	if (!sscanf(buf, "%ld\n", &state))
> -		return -EINVAL;
> -
> -	if ((long)state < 0)
> -		return -EINVAL;
> -
> -	result = cdev->ops->set_cur_state(cdev, state);
> -	if (result)
> -		return result;
> -	return count;
> -}
> -
> -static struct device_attribute dev_attr_cdev_type =
> -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> -static DEVICE_ATTR(max_state, 0444,
> -		   thermal_cooling_device_max_state_show, NULL);
> -static DEVICE_ATTR(cur_state, 0644,
> -		   thermal_cooling_device_cur_state_show,
> -		   thermal_cooling_device_cur_state_store);
> -
> -static ssize_t
> -thermal_cooling_device_trip_point_show(struct device *dev,
> -				       struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_instance *instance;
> -
> -	instance =
> -	    container_of(attr, struct thermal_instance, attr);
> -
> -	if (instance->trip == THERMAL_TRIPS_NONE)
> -		return sprintf(buf, "-1\n");
> -	else
> -		return sprintf(buf, "%d\n", instance->trip);
> -}
> -
> -/* Device management */
> -
> -#if defined(CONFIG_THERMAL_HWMON)
> -
> -/* hwmon sys I/F */
> -#include <linux/hwmon.h>
> -
> -/* thermal zone devices with the same type share one hwmon device */
> -struct thermal_hwmon_device {
> -	char type[THERMAL_NAME_LENGTH];
> -	struct device *device;
> -	int count;
> -	struct list_head tz_list;
> -	struct list_head node;
> -};
> -
> -struct thermal_hwmon_attr {
> -	struct device_attribute attr;
> -	char name[16];
> -};
> -
> -/* one temperature input for each thermal zone */
> -struct thermal_hwmon_temp {
> -	struct list_head hwmon_node;
> -	struct thermal_zone_device *tz;
> -	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> -	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> -};
> -
> -static LIST_HEAD(thermal_hwmon_list);
> -
> -static ssize_t
> -name_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> -	return sprintf(buf, "%s\n", hwmon->type);
> -}
> -static DEVICE_ATTR(name, 0444, name_show, NULL);
> -
> -static ssize_t
> -temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
> -{
> -	long temperature;
> -	int ret;
> -	struct thermal_hwmon_attr *hwmon_attr
> -			= container_of(attr, struct thermal_hwmon_attr, attr);
> -	struct thermal_hwmon_temp *temp
> -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> -				       temp_input);
> -	struct thermal_zone_device *tz = temp->tz;
> -
> -	ret = thermal_zone_get_temp(tz, &temperature);
> -
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -static ssize_t
> -temp_crit_show(struct device *dev, struct device_attribute *attr,
> -		char *buf)
> -{
> -	struct thermal_hwmon_attr *hwmon_attr
> -			= container_of(attr, struct thermal_hwmon_attr, attr);
> -	struct thermal_hwmon_temp *temp
> -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> -				       temp_crit);
> -	struct thermal_zone_device *tz = temp->tz;
> -	long temperature;
> -	int ret;
> -
> -	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> -	if (ret)
> -		return ret;
> -
> -	return sprintf(buf, "%ld\n", temperature);
> -}
> -
> -
> -static struct thermal_hwmon_device *
> -thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_device *hwmon;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> -		if (!strcmp(hwmon->type, tz->type)) {
> -			mutex_unlock(&thermal_list_lock);
> -			return hwmon;
> -		}
> -	mutex_unlock(&thermal_list_lock);
> -
> -	return NULL;
> -}
> -
> -/* Find the temperature input matching a given thermal zone */
> -static struct thermal_hwmon_temp *
> -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
> -			  const struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_temp *temp;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> -		if (temp->tz == tz) {
> -			mutex_unlock(&thermal_list_lock);
> -			return temp;
> -		}
> -	mutex_unlock(&thermal_list_lock);
> -
> -	return NULL;
> -}
> -
> -static int
> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_device *hwmon;
> -	struct thermal_hwmon_temp *temp;
> -	int new_hwmon_device = 1;
> -	int result;
> -
> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> -	if (hwmon) {
> -		new_hwmon_device = 0;
> -		goto register_sys_interface;
> -	}
> -
> -	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
> -	if (!hwmon)
> -		return -ENOMEM;
> -
> -	INIT_LIST_HEAD(&hwmon->tz_list);
> -	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> -	hwmon->device = hwmon_device_register(NULL);
> -	if (IS_ERR(hwmon->device)) {
> -		result = PTR_ERR(hwmon->device);
> -		goto free_mem;
> -	}
> -	dev_set_drvdata(hwmon->device, hwmon);
> -	result = device_create_file(hwmon->device, &dev_attr_name);
> -	if (result)
> -		goto free_mem;
> -
> - register_sys_interface:
> -	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> -	if (!temp) {
> -		result = -ENOMEM;
> -		goto unregister_name;
> -	}
> -
> -	temp->tz = tz;
> -	hwmon->count++;
> -
> -	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
> -		 "temp%d_input", hwmon->count);
> -	temp->temp_input.attr.attr.name = temp->temp_input.name;
> -	temp->temp_input.attr.attr.mode = 0444;
> -	temp->temp_input.attr.show = temp_input_show;
> -	sysfs_attr_init(&temp->temp_input.attr.attr);
> -	result = device_create_file(hwmon->device, &temp->temp_input.attr);
> -	if (result)
> -		goto free_temp_mem;
> -
> -	if (tz->ops->get_crit_temp) {
> -		unsigned long temperature;
> -		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> -			snprintf(temp->temp_crit.name,
> -				 sizeof(temp->temp_crit.name),
> -				"temp%d_crit", hwmon->count);
> -			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
> -			temp->temp_crit.attr.attr.mode = 0444;
> -			temp->temp_crit.attr.show = temp_crit_show;
> -			sysfs_attr_init(&temp->temp_crit.attr.attr);
> -			result = device_create_file(hwmon->device,
> -						    &temp->temp_crit.attr);
> -			if (result)
> -				goto unregister_input;
> -		}
> -	}
> -
> -	mutex_lock(&thermal_list_lock);
> -	if (new_hwmon_device)
> -		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> -	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	return 0;
> -
> - unregister_input:
> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> - free_temp_mem:
> -	kfree(temp);
> - unregister_name:
> -	if (new_hwmon_device) {
> -		device_remove_file(hwmon->device, &dev_attr_name);
> -		hwmon_device_unregister(hwmon->device);
> -	}
> - free_mem:
> -	if (new_hwmon_device)
> -		kfree(hwmon);
> -
> -	return result;
> -}
> -
> -static void
> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -	struct thermal_hwmon_device *hwmon;
> -	struct thermal_hwmon_temp *temp;
> -
> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> -	if (unlikely(!hwmon)) {
> -		/* Should never happen... */
> -		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> -		return;
> -	}
> -
> -	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> -	if (unlikely(!temp)) {
> -		/* Should never happen... */
> -		dev_dbg(&tz->device, "temperature input lookup failed!\n");
> -		return;
> -	}
> -
> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> -	if (tz->ops->get_crit_temp)
> -		device_remove_file(hwmon->device, &temp->temp_crit.attr);
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_del(&temp->hwmon_node);
> -	kfree(temp);
> -	if (!list_empty(&hwmon->tz_list)) {
> -		mutex_unlock(&thermal_list_lock);
> -		return;
> -	}
> -	list_del(&hwmon->node);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	device_remove_file(hwmon->device, &dev_attr_name);
> -	hwmon_device_unregister(hwmon->device);
> -	kfree(hwmon);
> -}
> -#else
> -static int
> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -	return 0;
> -}
> -
> -static void
> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> -{
> -}
> -#endif
> -
> -/**
> - * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
> - * @tz:		thermal zone device
> - * @trip:	indicates which trip point the cooling devices is
> - *		associated with in this thermal zone.
> - * @cdev:	thermal cooling device
> - *
> - * This function is usually called in the thermal zone device .bind callback.
> - */
> -int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> -				     int trip,
> -				     struct thermal_cooling_device *cdev,
> -				     unsigned long upper, unsigned long lower)
> -{
> -	struct thermal_instance *dev;
> -	struct thermal_instance *pos;
> -	struct thermal_zone_device *pos1;
> -	struct thermal_cooling_device *pos2;
> -	unsigned long max_state;
> -	int result;
> -
> -	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> -		return -EINVAL;
> -
> -	list_for_each_entry(pos1, &thermal_tz_list, node) {
> -		if (pos1 == tz)
> -			break;
> -	}
> -	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> -		if (pos2 == cdev)
> -			break;
> -	}
> -
> -	if (tz != pos1 || cdev != pos2)
> -		return -EINVAL;
> -
> -	cdev->ops->get_max_state(cdev, &max_state);
> -
> -	/* lower default 0, upper default max_state */
> -	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> -	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> -
> -	if (lower > upper || upper > max_state)
> -		return -EINVAL;
> -
> -	dev =
> -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> -	if (!dev)
> -		return -ENOMEM;
> -	dev->tz = tz;
> -	dev->cdev = cdev;
> -	dev->trip = trip;
> -	dev->upper = upper;
> -	dev->lower = lower;
> -	dev->target = THERMAL_NO_TARGET;
> -
> -	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> -	if (result)
> -		goto free_mem;
> -
> -	sprintf(dev->name, "cdev%d", dev->id);
> -	result =
> -	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
> -	if (result)
> -		goto release_idr;
> -
> -	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> -	sysfs_attr_init(&dev->attr.attr);
> -	dev->attr.attr.name = dev->attr_name;
> -	dev->attr.attr.mode = 0444;
> -	dev->attr.show = thermal_cooling_device_trip_point_show;
> -	result = device_create_file(&tz->device, &dev->attr);
> -	if (result)
> -		goto remove_symbol_link;
> -
> -	mutex_lock(&tz->lock);
> -	mutex_lock(&cdev->lock);
> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> -		result = -EEXIST;
> -		break;
> -	}
> -	if (!result) {
> -		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> -		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
> -	}
> -	mutex_unlock(&cdev->lock);
> -	mutex_unlock(&tz->lock);
> -
> -	if (!result)
> -		return 0;
> -
> -	device_remove_file(&tz->device, &dev->attr);
> -remove_symbol_link:
> -	sysfs_remove_link(&tz->device.kobj, dev->name);
> -release_idr:
> -	release_idr(&tz->idr, &tz->lock, dev->id);
> -free_mem:
> -	kfree(dev);
> -	return result;
> -}
> -EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> -
> -/**
> - * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
> - * @tz:		thermal zone device
> - * @trip:	indicates which trip point the cooling devices is
> - *		associated with in this thermal zone.
> - * @cdev:	thermal cooling device
> - *
> - * This function is usually called in the thermal zone device .unbind callback.
> - */
> -int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> -				       int trip,
> -				       struct thermal_cooling_device *cdev)
> -{
> -	struct thermal_instance *pos, *next;
> -
> -	mutex_lock(&tz->lock);
> -	mutex_lock(&cdev->lock);
> -	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> -			list_del(&pos->tz_node);
> -			list_del(&pos->cdev_node);
> -			mutex_unlock(&cdev->lock);
> -			mutex_unlock(&tz->lock);
> -			goto unbind;
> -		}
> -	}
> -	mutex_unlock(&cdev->lock);
> -	mutex_unlock(&tz->lock);
> -
> -	return -ENODEV;
> -
> -unbind:
> -	device_remove_file(&tz->device, &pos->attr);
> -	sysfs_remove_link(&tz->device.kobj, pos->name);
> -	release_idr(&tz->idr, &tz->lock, pos->id);
> -	kfree(pos);
> -	return 0;
> -}
> -EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> -
> -static void thermal_release(struct device *dev)
> -{
> -	struct thermal_zone_device *tz;
> -	struct thermal_cooling_device *cdev;
> -
> -	if (!strncmp(dev_name(dev), "thermal_zone",
> -		     sizeof("thermal_zone") - 1)) {
> -		tz = to_thermal_zone(dev);
> -		kfree(tz);
> -	} else {
> -		cdev = to_cooling_device(dev);
> -		kfree(cdev);
> -	}
> -}
> -
> -static struct class thermal_class = {
> -	.name = "thermal",
> -	.dev_release = thermal_release,
> -};
> -
> -/**
> - * thermal_cooling_device_register - register a new thermal cooling device
> - * @type:	the thermal cooling device type.
> - * @devdata:	device private data.
> - * @ops:		standard thermal cooling devices callbacks.
> - */
> -struct thermal_cooling_device *
> -thermal_cooling_device_register(char *type, void *devdata,
> -				const struct thermal_cooling_device_ops *ops)
> -{
> -	struct thermal_cooling_device *cdev;
> -	int result;
> -
> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> -	    !ops->set_cur_state)
> -		return ERR_PTR(-EINVAL);
> -
> -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> -	if (!cdev)
> -		return ERR_PTR(-ENOMEM);
> -
> -	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> -	if (result) {
> -		kfree(cdev);
> -		return ERR_PTR(result);
> -	}
> -
> -	strcpy(cdev->type, type ? : "");
> -	mutex_init(&cdev->lock);
> -	INIT_LIST_HEAD(&cdev->thermal_instances);
> -	cdev->ops = ops;
> -	cdev->updated = true;
> -	cdev->device.class = &thermal_class;
> -	cdev->devdata = devdata;
> -	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> -	result = device_register(&cdev->device);
> -	if (result) {
> -		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> -		kfree(cdev);
> -		return ERR_PTR(result);
> -	}
> -
> -	/* sys I/F */
> -	if (type) {
> -		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -	result = device_create_file(&cdev->device, &dev_attr_max_state);
> -	if (result)
> -		goto unregister;
> -
> -	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> -	if (result)
> -		goto unregister;
> -
> -	/* Add 'this' new cdev to the global cdev list */
> -	mutex_lock(&thermal_list_lock);
> -	list_add(&cdev->node, &thermal_cdev_list);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	/* Update binding information for 'this' new cdev */
> -	bind_cdev(cdev);
> -
> -	return cdev;
> -
> -unregister:
> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> -	device_unregister(&cdev->device);
> -	return ERR_PTR(result);
> -}
> -EXPORT_SYMBOL(thermal_cooling_device_register);
> -
> -/**
> - * thermal_cooling_device_unregister - removes the registered thermal cooling device
> - * @cdev:	the thermal cooling device to remove.
> - *
> - * thermal_cooling_device_unregister() must be called when the device is no
> - * longer needed.
> - */
> -void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
> -{
> -	int i;
> -	const struct thermal_zone_params *tzp;
> -	struct thermal_zone_device *tz;
> -	struct thermal_cooling_device *pos = NULL;
> -
> -	if (!cdev)
> -		return;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(pos, &thermal_cdev_list, node)
> -	    if (pos == cdev)
> -		break;
> -	if (pos != cdev) {
> -		/* thermal cooling device not found */
> -		mutex_unlock(&thermal_list_lock);
> -		return;
> -	}
> -	list_del(&cdev->node);
> -
> -	/* Unbind all thermal zones associated with 'this' cdev */
> -	list_for_each_entry(tz, &thermal_tz_list, node) {
> -		if (tz->ops->unbind) {
> -			tz->ops->unbind(tz, cdev);
> -			continue;
> -		}
> -
> -		if (!tz->tzp || !tz->tzp->tbp)
> -			continue;
> -
> -		tzp = tz->tzp;
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev == cdev) {
> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> -				tzp->tbp[i].cdev = NULL;
> -			}
> -		}
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -
> -	if (cdev->type[0])
> -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> -	device_remove_file(&cdev->device, &dev_attr_max_state);
> -	device_remove_file(&cdev->device, &dev_attr_cur_state);
> -
> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> -	device_unregister(&cdev->device);
> -	return;
> -}
> -EXPORT_SYMBOL(thermal_cooling_device_unregister);
> -
> -void thermal_cdev_update(struct thermal_cooling_device *cdev)
> -{
> -	struct thermal_instance *instance;
> -	unsigned long target = 0;
> -
> -	/* cooling device is updated*/
> -	if (cdev->updated)
> -		return;
> -
> -	mutex_lock(&cdev->lock);
> -	/* Make sure cdev enters the deepest cooling state */
> -	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
> -		if (instance->target == THERMAL_NO_TARGET)
> -			continue;
> -		if (instance->target > target)
> -			target = instance->target;
> -	}
> -	mutex_unlock(&cdev->lock);
> -	cdev->ops->set_cur_state(cdev, target);
> -	cdev->updated = true;
> -}
> -EXPORT_SYMBOL(thermal_cdev_update);
> -
> -/**
> - * notify_thermal_framework - Sensor drivers use this API to notify framework
> - * @tz:		thermal zone device
> - * @trip:	indicates which trip point has been crossed
> - *
> - * This function handles the trip events from sensor drivers. It starts
> - * throttling the cooling devices according to the policy configured.
> - * For CRITICAL and HOT trip points, this notifies the respective drivers,
> - * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> - * The throttling policy is based on the configured platform data; if no
> - * platform data is provided, this uses the step_wise throttling policy.
> - */
> -void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> -{
> -	handle_thermal_trip(tz, trip);
> -}
> -EXPORT_SYMBOL(notify_thermal_framework);
> -
> -/**
> - * create_trip_attrs - create attributes for trip points
> - * @tz:		the thermal zone device
> - * @mask:	Writeable trip point bitmap.
> - */
> -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> -{
> -	int indx;
> -	int size = sizeof(struct thermal_attr) * tz->trips;
> -
> -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> -	if (!tz->trip_type_attrs)
> -		return -ENOMEM;
> -
> -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> -	if (!tz->trip_temp_attrs) {
> -		kfree(tz->trip_type_attrs);
> -		return -ENOMEM;
> -	}
> -
> -	if (tz->ops->get_trip_hyst) {
> -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> -		if (!tz->trip_hyst_attrs) {
> -			kfree(tz->trip_type_attrs);
> -			kfree(tz->trip_temp_attrs);
> -			return -ENOMEM;
> -		}
> -	}
> -
> -
> -	for (indx = 0; indx < tz->trips; indx++) {
> -		/* create trip type attribute */
> -		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
> -			 "trip_point_%d_type", indx);
> -
> -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> -		tz->trip_type_attrs[indx].attr.attr.name =
> -						tz->trip_type_attrs[indx].name;
> -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> -
> -		device_create_file(&tz->device,
> -				   &tz->trip_type_attrs[indx].attr);
> -
> -		/* create trip temp attribute */
> -		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
> -			 "trip_point_%d_temp", indx);
> -
> -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> -		tz->trip_temp_attrs[indx].attr.attr.name =
> -						tz->trip_temp_attrs[indx].name;
> -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> -		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
> -		if (mask & (1 << indx)) {
> -			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
> -			tz->trip_temp_attrs[indx].attr.store =
> -							trip_point_temp_store;
> -		}
> -
> -		device_create_file(&tz->device,
> -				   &tz->trip_temp_attrs[indx].attr);
> -
> -		/* create Optional trip hyst attribute */
> -		if (!tz->ops->get_trip_hyst)
> -			continue;
> -		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
> -			 "trip_point_%d_hyst", indx);
> -
> -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> -		tz->trip_hyst_attrs[indx].attr.attr.name =
> -					tz->trip_hyst_attrs[indx].name;
> -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> -		if (tz->ops->set_trip_hyst) {
> -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> -			tz->trip_hyst_attrs[indx].attr.store =
> -					trip_point_hyst_store;
> -		}
> -
> -		device_create_file(&tz->device,
> -				   &tz->trip_hyst_attrs[indx].attr);
> -	}
> -	return 0;
> -}
> -
> -static void remove_trip_attrs(struct thermal_zone_device *tz)
> -{
> -	int indx;
> -
> -	for (indx = 0; indx < tz->trips; indx++) {
> -		device_remove_file(&tz->device,
> -				   &tz->trip_type_attrs[indx].attr);
> -		device_remove_file(&tz->device,
> -				   &tz->trip_temp_attrs[indx].attr);
> -		if (tz->ops->get_trip_hyst)
> -			device_remove_file(&tz->device,
> -				  &tz->trip_hyst_attrs[indx].attr);
> -	}
> -	kfree(tz->trip_type_attrs);
> -	kfree(tz->trip_temp_attrs);
> -	kfree(tz->trip_hyst_attrs);
> -}
> -
> -/**
> - * thermal_zone_device_register - register a new thermal zone device
> - * @type:	the thermal zone device type
> - * @trips:	the number of trip points the thermal zone support
> - * @mask:	a bit string indicating the writeablility of trip points
> - * @devdata:	private device data
> - * @ops:	standard thermal zone device callbacks
> - * @tzp:	thermal zone platform parameters
> - * @passive_delay: number of milliseconds to wait between polls when
> - *		   performing passive cooling
> - * @polling_delay: number of milliseconds to wait between polls when checking
> - *		   whether trip points have been crossed (0 for interrupt
> - *		   driven systems)
> - *
> - * thermal_zone_device_unregister() must be called when the device is no
> - * longer needed. The passive cooling depends on the .get_trend() return value.
> - */
> -struct thermal_zone_device *thermal_zone_device_register(const char *type,
> -	int trips, int mask, void *devdata,
> -	const struct thermal_zone_device_ops *ops,
> -	const struct thermal_zone_params *tzp,
> -	int passive_delay, int polling_delay)
> -{
> -	struct thermal_zone_device *tz;
> -	enum thermal_trip_type trip_type;
> -	int result;
> -	int count;
> -	int passive = 0;
> -
> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (!ops || !ops->get_temp)
> -		return ERR_PTR(-EINVAL);
> -
> -	if (trips > 0 && !ops->get_trip_type)
> -		return ERR_PTR(-EINVAL);
> -
> -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> -	if (!tz)
> -		return ERR_PTR(-ENOMEM);
> -
> -	INIT_LIST_HEAD(&tz->thermal_instances);
> -	idr_init(&tz->idr);
> -	mutex_init(&tz->lock);
> -	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> -	if (result) {
> -		kfree(tz);
> -		return ERR_PTR(result);
> -	}
> -
> -	strcpy(tz->type, type ? : "");
> -	tz->ops = ops;
> -	tz->tzp = tzp;
> -	tz->device.class = &thermal_class;
> -	tz->devdata = devdata;
> -	tz->trips = trips;
> -	tz->passive_delay = passive_delay;
> -	tz->polling_delay = polling_delay;
> -
> -	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> -	result = device_register(&tz->device);
> -	if (result) {
> -		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> -		kfree(tz);
> -		return ERR_PTR(result);
> -	}
> -
> -	/* sys I/F */
> -	if (type) {
> -		result = device_create_file(&tz->device, &dev_attr_type);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -	result = device_create_file(&tz->device, &dev_attr_temp);
> -	if (result)
> -		goto unregister;
> -
> -	if (ops->get_mode) {
> -		result = device_create_file(&tz->device, &dev_attr_mode);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -	result = create_trip_attrs(tz, mask);
> -	if (result)
> -		goto unregister;
> -
> -	for (count = 0; count < trips; count++) {
> -		tz->ops->get_trip_type(tz, count, &trip_type);
> -		if (trip_type == THERMAL_TRIP_PASSIVE)
> -			passive = 1;
> -	}
> -
> -	if (!passive) {
> -		result = device_create_file(&tz->device, &dev_attr_passive);
> -		if (result)
> -			goto unregister;
> -	}
> -
> -#ifdef CONFIG_THERMAL_EMULATION
> -	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> -	if (result)
> -		goto unregister;
> -#endif
> -	/* Create policy attribute */
> -	result = device_create_file(&tz->device, &dev_attr_policy);
> -	if (result)
> -		goto unregister;
> -
> -	/* Update 'this' zone's governor information */
> -	mutex_lock(&thermal_governor_lock);
> -
> -	if (tz->tzp)
> -		tz->governor = __find_governor(tz->tzp->governor_name);
> -	else
> -		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
> -
> -	mutex_unlock(&thermal_governor_lock);
> -
> -	result = thermal_add_hwmon_sysfs(tz);
> -	if (result)
> -		goto unregister;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_add_tail(&tz->node, &thermal_tz_list);
> -	mutex_unlock(&thermal_list_lock);
> -
> -	/* Bind cooling devices for this zone */
> -	bind_tz(tz);
> -
> -	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
> -
> -	thermal_zone_device_update(tz);
> -
> -	if (!result)
> -		return tz;
> -
> -unregister:
> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> -	device_unregister(&tz->device);
> -	return ERR_PTR(result);
> -}
> -EXPORT_SYMBOL(thermal_zone_device_register);
> -
> -/**
> - * thermal_device_unregister - removes the registered thermal zone device
> - * @tz: the thermal zone device to remove
> - */
> -void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> -{
> -	int i;
> -	const struct thermal_zone_params *tzp;
> -	struct thermal_cooling_device *cdev;
> -	struct thermal_zone_device *pos = NULL;
> -
> -	if (!tz)
> -		return;
> -
> -	tzp = tz->tzp;
> -
> -	mutex_lock(&thermal_list_lock);
> -	list_for_each_entry(pos, &thermal_tz_list, node)
> -	    if (pos == tz)
> -		break;
> -	if (pos != tz) {
> -		/* thermal zone device not found */
> -		mutex_unlock(&thermal_list_lock);
> -		return;
> -	}
> -	list_del(&tz->node);
> -
> -	/* Unbind all cdevs associated with 'this' thermal zone */
> -	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> -		if (tz->ops->unbind) {
> -			tz->ops->unbind(tz, cdev);
> -			continue;
> -		}
> -
> -		if (!tzp || !tzp->tbp)
> -			break;
> -
> -		for (i = 0; i < tzp->num_tbps; i++) {
> -			if (tzp->tbp[i].cdev == cdev) {
> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> -				tzp->tbp[i].cdev = NULL;
> -			}
> -		}
> -	}
> -
> -	mutex_unlock(&thermal_list_lock);
> -
> -	thermal_zone_device_set_polling(tz, 0);
> -
> -	if (tz->type[0])
> -		device_remove_file(&tz->device, &dev_attr_type);
> -	device_remove_file(&tz->device, &dev_attr_temp);
> -	if (tz->ops->get_mode)
> -		device_remove_file(&tz->device, &dev_attr_mode);
> -	device_remove_file(&tz->device, &dev_attr_policy);
> -	remove_trip_attrs(tz);
> -	tz->governor = NULL;
> -
> -	thermal_remove_hwmon_sysfs(tz);
> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> -	idr_destroy(&tz->idr);
> -	mutex_destroy(&tz->lock);
> -	device_unregister(&tz->device);
> -	return;
> -}
> -EXPORT_SYMBOL(thermal_zone_device_unregister);
> -
> -#ifdef CONFIG_NET
> -static struct genl_family thermal_event_genl_family = {
> -	.id = GENL_ID_GENERATE,
> -	.name = THERMAL_GENL_FAMILY_NAME,
> -	.version = THERMAL_GENL_VERSION,
> -	.maxattr = THERMAL_GENL_ATTR_MAX,
> -};
> -
> -static struct genl_multicast_group thermal_event_mcgrp = {
> -	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> -};
> -
> -int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> -					enum events event)
> -{
> -	struct sk_buff *skb;
> -	struct nlattr *attr;
> -	struct thermal_genl_event *thermal_event;
> -	void *msg_header;
> -	int size;
> -	int result;
> -	static unsigned int thermal_event_seqnum;
> -
> -	if (!tz)
> -		return -EINVAL;
> -
> -	/* allocate memory */
> -	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> -	       nla_total_size(0);
> -
> -	skb = genlmsg_new(size, GFP_ATOMIC);
> -	if (!skb)
> -		return -ENOMEM;
> -
> -	/* add the genetlink message header */
> -	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> -				 &thermal_event_genl_family, 0,
> -				 THERMAL_GENL_CMD_EVENT);
> -	if (!msg_header) {
> -		nlmsg_free(skb);
> -		return -ENOMEM;
> -	}
> -
> -	/* fill the data */
> -	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> -			   sizeof(struct thermal_genl_event));
> -
> -	if (!attr) {
> -		nlmsg_free(skb);
> -		return -EINVAL;
> -	}
> -
> -	thermal_event = nla_data(attr);
> -	if (!thermal_event) {
> -		nlmsg_free(skb);
> -		return -EINVAL;
> -	}
> -
> -	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> -
> -	thermal_event->orig = tz->id;
> -	thermal_event->event = event;
> -
> -	/* send multicast genetlink message */
> -	result = genlmsg_end(skb, msg_header);
> -	if (result < 0) {
> -		nlmsg_free(skb);
> -		return result;
> -	}
> -
> -	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
> -	if (result)
> -		dev_err(&tz->device, "Failed to send netlink event:%d", result);
> -
> -	return result;
> -}
> -EXPORT_SYMBOL(thermal_generate_netlink_event);
> -
> -static int genetlink_init(void)
> -{
> -	int result;
> -
> -	result = genl_register_family(&thermal_event_genl_family);
> -	if (result)
> -		return result;
> -
> -	result = genl_register_mc_group(&thermal_event_genl_family,
> -					&thermal_event_mcgrp);
> -	if (result)
> -		genl_unregister_family(&thermal_event_genl_family);
> -	return result;
> -}
> -
> -static void genetlink_exit(void)
> -{
> -	genl_unregister_family(&thermal_event_genl_family);
> -}
> -#else /* !CONFIG_NET */
> -static inline int genetlink_init(void) { return 0; }
> -static inline void genetlink_exit(void) {}
> -#endif /* !CONFIG_NET */
> -
> -static int __init thermal_init(void)
> -{
> -	int result = 0;
> -
> -	result = class_register(&thermal_class);
> -	if (result) {
> -		idr_destroy(&thermal_tz_idr);
> -		idr_destroy(&thermal_cdev_idr);
> -		mutex_destroy(&thermal_idr_lock);
> -		mutex_destroy(&thermal_list_lock);
> -		return result;
> -	}
> -	result = genetlink_init();
> -	return result;
> -}
> -
> -static void __exit thermal_exit(void)
> -{
> -	class_unregister(&thermal_class);
> -	idr_destroy(&thermal_tz_idr);
> -	idr_destroy(&thermal_cdev_idr);
> -	mutex_destroy(&thermal_idr_lock);
> -	mutex_destroy(&thermal_list_lock);
> -	genetlink_exit();
> -}
> -
> -fs_initcall(thermal_init);
> -module_exit(thermal_exit);
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC, 2/5] Thermal: thermal framework registration failure case cleanup
  2013-03-26 16:26 ` [RFC PATCH 2/5] Thermal: thermal framework registration failure case cleanup Zhang Rui
@ 2013-03-26 22:22     ` Eduardo Valentin
  0 siblings, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-03-26 22:22 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

On 26-03-2013 12:26, Zhang Rui wrote:
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>

Could you please describe why these resource releases are not required 
anymore? Even on thermal_exit.

> ---
> drivers/thermal/thermal_core.c |   12 ++----------
>   1 file changed, 2 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index 5b7863a..845ed6e 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -1863,13 +1863,9 @@ static int __init thermal_init(void)
>   	int result = 0;
>
>   	result = class_register(&thermal_class);
> -	if (result) {
> -		idr_destroy(&thermal_tz_idr);
> -		idr_destroy(&thermal_cdev_idr);
> -		mutex_destroy(&thermal_idr_lock);
> -		mutex_destroy(&thermal_list_lock);
> +	if (result)
>   		return result;
> -	}
> +
>   	result = genetlink_init();
>   	return result;
>   }
> @@ -1877,10 +1873,6 @@ static int __init thermal_init(void)
>   static void __exit thermal_exit(void)
>   {
>   	class_unregister(&thermal_class);
> -	idr_destroy(&thermal_tz_idr);
> -	idr_destroy(&thermal_cdev_idr);
> -	mutex_destroy(&thermal_idr_lock);
> -	mutex_destroy(&thermal_list_lock);
>   	genetlink_exit();
>   }
>
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC, 2/5] Thermal: thermal framework registration failure case cleanup
@ 2013-03-26 22:22     ` Eduardo Valentin
  0 siblings, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-03-26 22:22 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

On 26-03-2013 12:26, Zhang Rui wrote:
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>

Could you please describe why these resource releases are not required 
anymore? Even on thermal_exit.

> ---
> drivers/thermal/thermal_core.c |   12 ++----------
>   1 file changed, 2 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index 5b7863a..845ed6e 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -1863,13 +1863,9 @@ static int __init thermal_init(void)
>   	int result = 0;
>
>   	result = class_register(&thermal_class);
> -	if (result) {
> -		idr_destroy(&thermal_tz_idr);
> -		idr_destroy(&thermal_cdev_idr);
> -		mutex_destroy(&thermal_idr_lock);
> -		mutex_destroy(&thermal_list_lock);
> +	if (result)
>   		return result;
> -	}
> +
>   	result = genetlink_init();
>   	return result;
>   }
> @@ -1877,10 +1873,6 @@ static int __init thermal_init(void)
>   static void __exit thermal_exit(void)
>   {
>   	class_unregister(&thermal_class);
> -	idr_destroy(&thermal_tz_idr);
> -	idr_destroy(&thermal_cdev_idr);
> -	mutex_destroy(&thermal_idr_lock);
> -	mutex_destroy(&thermal_list_lock);
>   	genetlink_exit();
>   }
>
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC,3/5] Thermal: build thermal governors into thermal_sys module
  2013-03-26 16:26 ` [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys module Zhang Rui
@ 2013-03-26 22:31     ` Eduardo Valentin
  2013-03-26 22:31     ` Eduardo Valentin
  1 sibling, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-03-26 22:31 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

Hi Rui,

On 26-03-2013 12:26, Zhang Rui wrote:
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>
> ---
> drivers/thermal/Makefile       |    6 +++---
>   drivers/thermal/fair_share.c   |   15 ++-------------
>   drivers/thermal/step_wise.c    |   16 ++--------------
>   drivers/thermal/thermal_core.c |   36 ++++++++++++++++++++++++++++++++++--
>   drivers/thermal/thermal_core.h |   25 +++++++++++++++++++++++++
>   drivers/thermal/user_space.c   |   15 ++-------------
>   include/linux/thermal.h        |    1 -
>   7 files changed, 68 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index b2009bd..b7fffc7 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -6,9 +6,9 @@ obj-$(CONFIG_THERMAL)		+= thermal_sys.o
>   thermal_sys-y			+= thermal_core.o
>
>   # governors
> -obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> -obj-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
> -obj-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
> +thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> +thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
> +thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
>
>   # cpufreq cooling
>   obj-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
> diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
> index 792479f..944ba2f 100644
> --- a/drivers/thermal/fair_share.c
> +++ b/drivers/thermal/fair_share.c
> @@ -22,9 +22,6 @@
>    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    */
>
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
>   #include <linux/thermal.h>
>
>   #include "thermal_core.h"
> @@ -111,23 +108,15 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
>   static struct thermal_governor thermal_gov_fair_share = {
>   	.name		= "fair_share",
>   	.throttle	= fair_share_throttle,
> -	.owner		= THIS_MODULE,
>   };
>
> -static int __init thermal_gov_fair_share_init(void)
> +int thermal_gov_fair_share_register(void)
>   {
>   	return thermal_register_governor(&thermal_gov_fair_share);
>   }
>
> -static void __exit thermal_gov_fair_share_exit(void)
> +void thermal_gov_fair_share_unregister(void)
>   {
>   	thermal_unregister_governor(&thermal_gov_fair_share);
>   }
>
> -/* This should load after thermal framework */
> -fs_initcall(thermal_gov_fair_share_init);
> -module_exit(thermal_gov_fair_share_exit);
> -
> -MODULE_AUTHOR("Durgadoss R");
> -MODULE_DESCRIPTION("A simple weight based thermal throttling governor");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
> index 407cde3..a6c9666 100644
> --- a/drivers/thermal/step_wise.c
> +++ b/drivers/thermal/step_wise.c
> @@ -22,9 +22,6 @@
>    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    */
>
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
>   #include <linux/thermal.h>
>
>   #include "thermal_core.h"
> @@ -180,23 +177,14 @@ static int step_wise_throttle(struct thermal_zone_device *tz, int trip)
>   static struct thermal_governor thermal_gov_step_wise = {
>   	.name		= "step_wise",
>   	.throttle	= step_wise_throttle,
> -	.owner		= THIS_MODULE,
>   };
>
> -static int __init thermal_gov_step_wise_init(void)
> +int thermal_gov_step_wise_register(void)
>   {
>   	return thermal_register_governor(&thermal_gov_step_wise);
>   }
>
> -static void __exit thermal_gov_step_wise_exit(void)
> +void thermal_gov_step_wise_unregister(void)
>   {
>   	thermal_unregister_governor(&thermal_gov_step_wise);
>   }
> -
> -/* This should load after thermal framework */
> -fs_initcall(thermal_gov_step_wise_init);
> -module_exit(thermal_gov_step_wise_exit);
> -
> -MODULE_AUTHOR("Durgadoss R");
> -MODULE_DESCRIPTION("A step-by-step thermal throttling governor");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index 845ed6e..eac9745 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -1858,22 +1858,54 @@ static inline int genetlink_init(void) { return 0; }
>   static inline void genetlink_exit(void) {}
>   #endif /* !CONFIG_NET */
>
> +static int __init thermal_register_governors(void)
> +{
> +	int result;
> +
> +	result = thermal_gov_step_wise_register();
> +	if (result)
> +		return result;
> +
> +	result = thermal_gov_fair_share_register();
> +	if (result)
> +		return result;
> +
> +	result = thermal_gov_user_space_register();
> +
> +	return result;

Just do a
+	return thermal_gov_user_space_register();

Or better, add err messages in the fail path.

> +}
> +
> +static void __exit thermal_unregister_governors(void)
> +{
> +	thermal_gov_step_wise_unregister();
> +	thermal_gov_fair_share_unregister();
> +	thermal_gov_user_space_unregister();
> +}
> +
>   static int __init thermal_init(void)
>   {
> -	int result = 0;
> +	int result;
> +
> +	result = thermal_register_governors();
> +	if (result)
> +		return result;
>
>   	result = class_register(&thermal_class);
>   	if (result)
>   		return result;
>
>   	result = genetlink_init();
> +	if (result)
> +		class_unregister(&thermal_class);
> +
>   	return result;

ditto.

>   }
>
>   static void __exit thermal_exit(void)
>   {
> -	class_unregister(&thermal_class);
>   	genetlink_exit();
> +	class_unregister(&thermal_class);
> +	thermal_unregister_governors();
>   }
>
>   fs_initcall(thermal_init);
> diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
> index 0d3205a..f84ea0f 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -50,4 +50,29 @@ struct thermal_instance {
>   	struct list_head cdev_node; /* node in cdev->thermal_instances */
>   };
>
> +
> +#ifdef CONFIG_THERMAL_GOV_STEP_WISE
> +extern int thermal_gov_step_wise_register(void);
> +extern void thermal_gov_step_wise_unregister(void);

As you are compiling everything in same binary, I don't think you need 
externs there.

> +#else
> +static inline int thermal_gov_step_wise_register(void) { return 0; }
> +static inline void thermal_gov_step_wise_unregister(void) {}
> +#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
> +
> +#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE
> +extern int thermal_gov_fair_share_register(void);
> +extern void thermal_gov_fair_share_unregister(void);
>

ditto.

  +#else
> +static inline int thermal_gov_fair_share_register(void) { return 0; }
> +static inline void thermal_gov_fair_share_unregister(void) {}
> +#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
> +
> +#ifdef CONFIG_THERMAL_GOV_USER_SPACE
> +extern int thermal_gov_user_space_register(void);
> +extern void thermal_gov_user_space_unregister(void);

ditto.

> +#else
> +static inline int thermal_gov_user_space_register(void) { return 0; }
> +static inline void thermal_gov_user_space_unregister(void) {}
> +#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
> +
>   #endif /* __THERMAL_CORE_H__ */
> diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
> index 6bbb380..10adcdd 100644
> --- a/drivers/thermal/user_space.c
> +++ b/drivers/thermal/user_space.c
> @@ -22,9 +22,6 @@
>    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    */
>
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
>   #include <linux/thermal.h>
>
>   #include "thermal_core.h"
> @@ -46,23 +43,15 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip)
>   static struct thermal_governor thermal_gov_user_space = {
>   	.name		= "user_space",
>   	.throttle	= notify_user_space,
> -	.owner		= THIS_MODULE,
>   };
>
> -static int __init thermal_gov_user_space_init(void)
> +int thermal_gov_user_space_register(void)
>   {
>   	return thermal_register_governor(&thermal_gov_user_space);
>   }
>
> -static void __exit thermal_gov_user_space_exit(void)
> +void thermal_gov_user_space_unregister(void)
>   {
>   	thermal_unregister_governor(&thermal_gov_user_space);
>   }
>
> -/* This should load after thermal framework */
> -fs_initcall(thermal_gov_user_space_init);
> -module_exit(thermal_gov_user_space_exit);
> -
> -MODULE_AUTHOR("Durgadoss R");
> -MODULE_DESCRIPTION("A user space Thermal notifier");
> -MODULE_LICENSE("GPL");
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index f0bd7f9..2eeec01 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -184,7 +184,6 @@ struct thermal_governor {
>   	char name[THERMAL_NAME_LENGTH];
>   	int (*throttle)(struct thermal_zone_device *tz, int trip);
>   	struct list_head	governor_list;
> -	struct module		*owner;
>   };
>
>   /* Structure that holds binding parameters for a zone */
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC,3/5] Thermal: build thermal governors into thermal_sys module
@ 2013-03-26 22:31     ` Eduardo Valentin
  0 siblings, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-03-26 22:31 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

Hi Rui,

On 26-03-2013 12:26, Zhang Rui wrote:
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>
> ---
> drivers/thermal/Makefile       |    6 +++---
>   drivers/thermal/fair_share.c   |   15 ++-------------
>   drivers/thermal/step_wise.c    |   16 ++--------------
>   drivers/thermal/thermal_core.c |   36 ++++++++++++++++++++++++++++++++++--
>   drivers/thermal/thermal_core.h |   25 +++++++++++++++++++++++++
>   drivers/thermal/user_space.c   |   15 ++-------------
>   include/linux/thermal.h        |    1 -
>   7 files changed, 68 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index b2009bd..b7fffc7 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -6,9 +6,9 @@ obj-$(CONFIG_THERMAL)		+= thermal_sys.o
>   thermal_sys-y			+= thermal_core.o
>
>   # governors
> -obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> -obj-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
> -obj-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
> +thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> +thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE)	+= step_wise.o
> +thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
>
>   # cpufreq cooling
>   obj-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
> diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
> index 792479f..944ba2f 100644
> --- a/drivers/thermal/fair_share.c
> +++ b/drivers/thermal/fair_share.c
> @@ -22,9 +22,6 @@
>    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    */
>
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
>   #include <linux/thermal.h>
>
>   #include "thermal_core.h"
> @@ -111,23 +108,15 @@ static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
>   static struct thermal_governor thermal_gov_fair_share = {
>   	.name		= "fair_share",
>   	.throttle	= fair_share_throttle,
> -	.owner		= THIS_MODULE,
>   };
>
> -static int __init thermal_gov_fair_share_init(void)
> +int thermal_gov_fair_share_register(void)
>   {
>   	return thermal_register_governor(&thermal_gov_fair_share);
>   }
>
> -static void __exit thermal_gov_fair_share_exit(void)
> +void thermal_gov_fair_share_unregister(void)
>   {
>   	thermal_unregister_governor(&thermal_gov_fair_share);
>   }
>
> -/* This should load after thermal framework */
> -fs_initcall(thermal_gov_fair_share_init);
> -module_exit(thermal_gov_fair_share_exit);
> -
> -MODULE_AUTHOR("Durgadoss R");
> -MODULE_DESCRIPTION("A simple weight based thermal throttling governor");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
> index 407cde3..a6c9666 100644
> --- a/drivers/thermal/step_wise.c
> +++ b/drivers/thermal/step_wise.c
> @@ -22,9 +22,6 @@
>    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    */
>
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
>   #include <linux/thermal.h>
>
>   #include "thermal_core.h"
> @@ -180,23 +177,14 @@ static int step_wise_throttle(struct thermal_zone_device *tz, int trip)
>   static struct thermal_governor thermal_gov_step_wise = {
>   	.name		= "step_wise",
>   	.throttle	= step_wise_throttle,
> -	.owner		= THIS_MODULE,
>   };
>
> -static int __init thermal_gov_step_wise_init(void)
> +int thermal_gov_step_wise_register(void)
>   {
>   	return thermal_register_governor(&thermal_gov_step_wise);
>   }
>
> -static void __exit thermal_gov_step_wise_exit(void)
> +void thermal_gov_step_wise_unregister(void)
>   {
>   	thermal_unregister_governor(&thermal_gov_step_wise);
>   }
> -
> -/* This should load after thermal framework */
> -fs_initcall(thermal_gov_step_wise_init);
> -module_exit(thermal_gov_step_wise_exit);
> -
> -MODULE_AUTHOR("Durgadoss R");
> -MODULE_DESCRIPTION("A step-by-step thermal throttling governor");
> -MODULE_LICENSE("GPL");
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index 845ed6e..eac9745 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -1858,22 +1858,54 @@ static inline int genetlink_init(void) { return 0; }
>   static inline void genetlink_exit(void) {}
>   #endif /* !CONFIG_NET */
>
> +static int __init thermal_register_governors(void)
> +{
> +	int result;
> +
> +	result = thermal_gov_step_wise_register();
> +	if (result)
> +		return result;
> +
> +	result = thermal_gov_fair_share_register();
> +	if (result)
> +		return result;
> +
> +	result = thermal_gov_user_space_register();
> +
> +	return result;

Just do a
+	return thermal_gov_user_space_register();

Or better, add err messages in the fail path.

> +}
> +
> +static void __exit thermal_unregister_governors(void)
> +{
> +	thermal_gov_step_wise_unregister();
> +	thermal_gov_fair_share_unregister();
> +	thermal_gov_user_space_unregister();
> +}
> +
>   static int __init thermal_init(void)
>   {
> -	int result = 0;
> +	int result;
> +
> +	result = thermal_register_governors();
> +	if (result)
> +		return result;
>
>   	result = class_register(&thermal_class);
>   	if (result)
>   		return result;
>
>   	result = genetlink_init();
> +	if (result)
> +		class_unregister(&thermal_class);
> +
>   	return result;

ditto.

>   }
>
>   static void __exit thermal_exit(void)
>   {
> -	class_unregister(&thermal_class);
>   	genetlink_exit();
> +	class_unregister(&thermal_class);
> +	thermal_unregister_governors();
>   }
>
>   fs_initcall(thermal_init);
> diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
> index 0d3205a..f84ea0f 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -50,4 +50,29 @@ struct thermal_instance {
>   	struct list_head cdev_node; /* node in cdev->thermal_instances */
>   };
>
> +
> +#ifdef CONFIG_THERMAL_GOV_STEP_WISE
> +extern int thermal_gov_step_wise_register(void);
> +extern void thermal_gov_step_wise_unregister(void);

As you are compiling everything in same binary, I don't think you need 
externs there.

> +#else
> +static inline int thermal_gov_step_wise_register(void) { return 0; }
> +static inline void thermal_gov_step_wise_unregister(void) {}
> +#endif /* CONFIG_THERMAL_GOV_STEP_WISE */
> +
> +#ifdef CONFIG_THERMAL_GOV_FAIR_SHARE
> +extern int thermal_gov_fair_share_register(void);
> +extern void thermal_gov_fair_share_unregister(void);
>

ditto.

  +#else
> +static inline int thermal_gov_fair_share_register(void) { return 0; }
> +static inline void thermal_gov_fair_share_unregister(void) {}
> +#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
> +
> +#ifdef CONFIG_THERMAL_GOV_USER_SPACE
> +extern int thermal_gov_user_space_register(void);
> +extern void thermal_gov_user_space_unregister(void);

ditto.

> +#else
> +static inline int thermal_gov_user_space_register(void) { return 0; }
> +static inline void thermal_gov_user_space_unregister(void) {}
> +#endif /* CONFIG_THERMAL_GOV_USER_SPACE */
> +
>   #endif /* __THERMAL_CORE_H__ */
> diff --git a/drivers/thermal/user_space.c b/drivers/thermal/user_space.c
> index 6bbb380..10adcdd 100644
> --- a/drivers/thermal/user_space.c
> +++ b/drivers/thermal/user_space.c
> @@ -22,9 +22,6 @@
>    * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>    */
>
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> -
> -#include <linux/module.h>
>   #include <linux/thermal.h>
>
>   #include "thermal_core.h"
> @@ -46,23 +43,15 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip)
>   static struct thermal_governor thermal_gov_user_space = {
>   	.name		= "user_space",
>   	.throttle	= notify_user_space,
> -	.owner		= THIS_MODULE,
>   };
>
> -static int __init thermal_gov_user_space_init(void)
> +int thermal_gov_user_space_register(void)
>   {
>   	return thermal_register_governor(&thermal_gov_user_space);
>   }
>
> -static void __exit thermal_gov_user_space_exit(void)
> +void thermal_gov_user_space_unregister(void)
>   {
>   	thermal_unregister_governor(&thermal_gov_user_space);
>   }
>
> -/* This should load after thermal framework */
> -fs_initcall(thermal_gov_user_space_init);
> -module_exit(thermal_gov_user_space_exit);
> -
> -MODULE_AUTHOR("Durgadoss R");
> -MODULE_DESCRIPTION("A user space Thermal notifier");
> -MODULE_LICENSE("GPL");
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index f0bd7f9..2eeec01 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -184,7 +184,6 @@ struct thermal_governor {
>   	char name[THERMAL_NAME_LENGTH];
>   	int (*throttle)(struct thermal_zone_device *tz, int trip);
>   	struct list_head	governor_list;
> -	struct module		*owner;
>   };
>
>   /* Structure that holds binding parameters for a zone */
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC,4/5] Thermal: governor API cleanup
  2013-03-26 16:26 ` [RFC PATCH 4/5] Thermal: governor API cleanup Zhang Rui
@ 2013-03-26 22:35     ` Eduardo Valentin
  0 siblings, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-03-26 22:35 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

On 26-03-2013 12:26, Zhang Rui wrote:
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>
> ---
> drivers/thermal/thermal_core.c |    2 --
>   drivers/thermal/thermal_core.h |    2 ++
>   include/linux/thermal.h        |    3 ---

Please also clean Documentation/thermal/sysfs_api.txt

>   3 files changed, 2 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index eac9745..f645757 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -99,7 +99,6 @@ int thermal_register_governor(struct thermal_governor *governor)
>
>   	return err;
>   }
> -EXPORT_SYMBOL_GPL(thermal_register_governor);
>
>   void thermal_unregister_governor(struct thermal_governor *governor)
>   {
> @@ -127,7 +126,6 @@ void thermal_unregister_governor(struct thermal_governor *governor)
>   	mutex_unlock(&thermal_governor_lock);
>   	return;
>   }
> -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
>
>   static int get_idr(struct idr *idr, struct mutex *lock, int *id)
>   {
> diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
> index f84ea0f..a1f8278 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -50,6 +50,8 @@ struct thermal_instance {
>   	struct list_head cdev_node; /* node in cdev->thermal_instances */
>   };
>
> +extern int thermal_register_governor(struct thermal_governor *);
> +extern void thermal_unregister_governor(struct thermal_governor *);

Does this really need to be extern?

>
>   #ifdef CONFIG_THERMAL_GOV_STEP_WISE
>   extern int thermal_gov_step_wise_register(void);
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 2eeec01..af03ea6 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -243,9 +243,6 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
>   void thermal_cdev_update(struct thermal_cooling_device *);
>   void notify_thermal_framework(struct thermal_zone_device *, int);
>
> -int thermal_register_governor(struct thermal_governor *);
> -void thermal_unregister_governor(struct thermal_governor *);
> -
>   #ifdef CONFIG_NET
>   extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>   						enum events event);
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC,4/5] Thermal: governor API cleanup
@ 2013-03-26 22:35     ` Eduardo Valentin
  0 siblings, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-03-26 22:35 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

On 26-03-2013 12:26, Zhang Rui wrote:
> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>
> ---
> drivers/thermal/thermal_core.c |    2 --
>   drivers/thermal/thermal_core.h |    2 ++
>   include/linux/thermal.h        |    3 ---

Please also clean Documentation/thermal/sysfs_api.txt

>   3 files changed, 2 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index eac9745..f645757 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -99,7 +99,6 @@ int thermal_register_governor(struct thermal_governor *governor)
>
>   	return err;
>   }
> -EXPORT_SYMBOL_GPL(thermal_register_governor);
>
>   void thermal_unregister_governor(struct thermal_governor *governor)
>   {
> @@ -127,7 +126,6 @@ void thermal_unregister_governor(struct thermal_governor *governor)
>   	mutex_unlock(&thermal_governor_lock);
>   	return;
>   }
> -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
>
>   static int get_idr(struct idr *idr, struct mutex *lock, int *id)
>   {
> diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
> index f84ea0f..a1f8278 100644
> --- a/drivers/thermal/thermal_core.h
> +++ b/drivers/thermal/thermal_core.h
> @@ -50,6 +50,8 @@ struct thermal_instance {
>   	struct list_head cdev_node; /* node in cdev->thermal_instances */
>   };
>
> +extern int thermal_register_governor(struct thermal_governor *);
> +extern void thermal_unregister_governor(struct thermal_governor *);

Does this really need to be extern?

>
>   #ifdef CONFIG_THERMAL_GOV_STEP_WISE
>   extern int thermal_gov_step_wise_register(void);
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index 2eeec01..af03ea6 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -243,9 +243,6 @@ struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
>   void thermal_cdev_update(struct thermal_cooling_device *);
>   void notify_thermal_framework(struct thermal_zone_device *, int);
>
> -int thermal_register_governor(struct thermal_governor *);
> -void thermal_unregister_governor(struct thermal_governor *);
> -
>   #ifdef CONFIG_NET
>   extern int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>   						enum events event);
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC,1/5] Thermal: rename thermal_sys.c to thermal_core.c
  2013-03-26 22:04     ` Eduardo Valentin
  (?)
@ 2013-03-28  2:40     ` Zhang Rui
  2013-04-01 12:43         ` Eduardo Valentin
  -1 siblings, 1 reply; 23+ messages in thread
From: Zhang Rui @ 2013-03-28  2:40 UTC (permalink / raw)
  To: Eduardo Valentin; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

On Tue, 2013-03-26 at 18:04 -0400, Eduardo Valentin wrote:
> Hi Rui,
> 
> A side note:
> I'd really appreciate if you could copy on your patches on 
> drivers/thermal/. I had some issues with TI server and got un subscribed 
> from linux-pm. Now I will try to catch up any way,
> 
sure.

> Some comments.
> 
> On 26-03-2013 12:26, Zhang Rui wrote:
> > No functional change in this patch.
> >
> 
> Just a better description would also help on code version control.
> 
will add it in V2.

> > Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> 
> Apart from minor comments, I agreed with this change. So feel free to 
> add my:
> 
> Acked-by: Eduardo Valentin <eduardo.valentin@ti.com>
> 
thanks!

> >
> > ---
> > drivers/thermal/Makefile       |    1 +
> >   drivers/thermal/thermal_core.c | 1888 ++++++++++++++++++++++++++++++++++++++++
> >   drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------
> 
> When sending renames, use git format-patch --find-renames, it makes a 
> better summary of what you have done, specially if you have changed 
> something in the file while renaming.
> 
a useful tip. thanks!
> >   3 files changed, 1889 insertions(+), 1888 deletions(-)
> >   create mode 100644 drivers/thermal/thermal_core.c
> >   delete mode 100644 drivers/thermal/thermal_sys.c
> >
> > diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> > index d3a2b38..b2009bd 100644
> > --- a/drivers/thermal/Makefile
> > +++ b/drivers/thermal/Makefile
> > @@ -3,6 +3,7 @@
> >   #
> >
> >   obj-$(CONFIG_THERMAL)		+= thermal_sys.o
> 
> I know this is for fixing the annoying bug with fan max speed. But while 
> still here, do you think 'thermal_sys' is a good name for thermal 
> framework driver? Maybe just 'thermal' would suffice?
> 
as I said, there is already a thermal driver, aka,
driver/acpi/thermal.c.

thanks,
rui
> > +thermal_sys-y			+= thermal_core.o
> >
> >   # governors
> >   obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> > diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> > new file mode 100644
> > index 0000000..5b7863a
> > --- /dev/null
> > +++ b/drivers/thermal/thermal_core.c
> > @@ -0,0 +1,1888 @@
> > +/*
> > + *  thermal.c - Generic Thermal Management Sysfs support.
> > + *
> > + *  Copyright (C) 2008 Intel Corp
> > + *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> > + *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> > + *
> > + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > + *
> > + *  This program is free software; you can redistribute it and/or modify
> > + *  it under the terms of the GNU General Public License as published by
> > + *  the Free Software Foundation; version 2 of the License.
> > + *
> > + *  This program is distributed in the hope that it will be useful, but
> > + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> > + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > + *  General Public License for more details.
> > + *
> > + *  You should have received a copy of the GNU General Public License along
> > + *  with this program; if not, write to the Free Software Foundation, Inc.,
> > + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> > + *
> > + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > + */
> > +
> > +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > +
> > +#include <linux/module.h>
> > +#include <linux/device.h>
> > +#include <linux/err.h>
> > +#include <linux/slab.h>
> > +#include <linux/kdev_t.h>
> > +#include <linux/idr.h>
> > +#include <linux/thermal.h>
> > +#include <linux/reboot.h>
> > +#include <net/netlink.h>
> > +#include <net/genetlink.h>
> > +
> > +#include "thermal_core.h"
> > +
> > +MODULE_AUTHOR("Zhang Rui");
> > +MODULE_DESCRIPTION("Generic thermal management sysfs support");
> > +MODULE_LICENSE("GPL");
> > +
> > +static DEFINE_IDR(thermal_tz_idr);
> > +static DEFINE_IDR(thermal_cdev_idr);
> > +static DEFINE_MUTEX(thermal_idr_lock);
> > +
> > +static LIST_HEAD(thermal_tz_list);
> > +static LIST_HEAD(thermal_cdev_list);
> > +static LIST_HEAD(thermal_governor_list);
> > +
> > +static DEFINE_MUTEX(thermal_list_lock);
> > +static DEFINE_MUTEX(thermal_governor_lock);
> > +
> > +static struct thermal_governor *__find_governor(const char *name)
> > +{
> > +	struct thermal_governor *pos;
> > +
> > +	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> > +		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> > +			return pos;
> > +
> > +	return NULL;
> > +}
> > +
> > +int thermal_register_governor(struct thermal_governor *governor)
> > +{
> > +	int err;
> > +	const char *name;
> > +	struct thermal_zone_device *pos;
> > +
> > +	if (!governor)
> > +		return -EINVAL;
> > +
> > +	mutex_lock(&thermal_governor_lock);
> > +
> > +	err = -EBUSY;
> > +	if (__find_governor(governor->name) == NULL) {
> > +		err = 0;
> > +		list_add(&governor->governor_list, &thermal_governor_list);
> > +	}
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +
> > +	list_for_each_entry(pos, &thermal_tz_list, node) {
> > +		if (pos->governor)
> > +			continue;
> > +		if (pos->tzp)
> > +			name = pos->tzp->governor_name;
> > +		else
> > +			name = DEFAULT_THERMAL_GOVERNOR;
> > +		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
> > +			pos->governor = governor;
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +	mutex_unlock(&thermal_governor_lock);
> > +
> > +	return err;
> > +}
> > +EXPORT_SYMBOL_GPL(thermal_register_governor);
> > +
> > +void thermal_unregister_governor(struct thermal_governor *governor)
> > +{
> > +	struct thermal_zone_device *pos;
> > +
> > +	if (!governor)
> > +		return;
> > +
> > +	mutex_lock(&thermal_governor_lock);
> > +
> > +	if (__find_governor(governor->name) == NULL)
> > +		goto exit;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +
> > +	list_for_each_entry(pos, &thermal_tz_list, node) {
> > +		if (!strnicmp(pos->governor->name, governor->name,
> > +						THERMAL_NAME_LENGTH))
> > +			pos->governor = NULL;
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +	list_del(&governor->governor_list);
> > +exit:
> > +	mutex_unlock(&thermal_governor_lock);
> > +	return;
> > +}
> > +EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> > +
> > +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> > +{
> > +	int ret;
> > +
> > +	if (lock)
> > +		mutex_lock(lock);
> > +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> > +	if (lock)
> > +		mutex_unlock(lock);
> > +	if (unlikely(ret < 0))
> > +		return ret;
> > +	*id = ret;
> > +	return 0;
> > +}
> > +
> > +static void release_idr(struct idr *idr, struct mutex *lock, int id)
> > +{
> > +	if (lock)
> > +		mutex_lock(lock);
> > +	idr_remove(idr, id);
> > +	if (lock)
> > +		mutex_unlock(lock);
> > +}
> > +
> > +int get_tz_trend(struct thermal_zone_device *tz, int trip)
> > +{
> > +	enum thermal_trend trend;
> > +
> > +	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> > +		if (tz->temperature > tz->last_temperature)
> > +			trend = THERMAL_TREND_RAISING;
> > +		else if (tz->temperature < tz->last_temperature)
> > +			trend = THERMAL_TREND_DROPPING;
> > +		else
> > +			trend = THERMAL_TREND_STABLE;
> > +	}
> > +
> > +	return trend;
> > +}
> > +EXPORT_SYMBOL(get_tz_trend);
> > +
> > +struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
> > +			struct thermal_cooling_device *cdev, int trip)
> > +{
> > +	struct thermal_instance *pos = NULL;
> > +	struct thermal_instance *target_instance = NULL;
> > +
> > +	mutex_lock(&tz->lock);
> > +	mutex_lock(&cdev->lock);
> > +
> > +	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> > +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > +			target_instance = pos;
> > +			break;
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&cdev->lock);
> > +	mutex_unlock(&tz->lock);
> > +
> > +	return target_instance;
> > +}
> > +EXPORT_SYMBOL(get_thermal_instance);
> > +
> > +static void print_bind_err_msg(struct thermal_zone_device *tz,
> > +			struct thermal_cooling_device *cdev, int ret)
> > +{
> > +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> > +				tz->type, cdev->type, ret);
> > +}
> > +
> > +static void __bind(struct thermal_zone_device *tz, int mask,
> > +			struct thermal_cooling_device *cdev)
> > +{
> > +	int i, ret;
> > +
> > +	for (i = 0; i < tz->trips; i++) {
> > +		if (mask & (1 << i)) {
> > +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> > +					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
> > +			if (ret)
> > +				print_bind_err_msg(tz, cdev, ret);
> > +		}
> > +	}
> > +}
> > +
> > +static void __unbind(struct thermal_zone_device *tz, int mask,
> > +			struct thermal_cooling_device *cdev)
> > +{
> > +	int i;
> > +
> > +	for (i = 0; i < tz->trips; i++)
> > +		if (mask & (1 << i))
> > +			thermal_zone_unbind_cooling_device(tz, i, cdev);
> > +}
> > +
> > +static void bind_cdev(struct thermal_cooling_device *cdev)
> > +{
> > +	int i, ret;
> > +	const struct thermal_zone_params *tzp;
> > +	struct thermal_zone_device *pos = NULL;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +
> > +	list_for_each_entry(pos, &thermal_tz_list, node) {
> > +		if (!pos->tzp && !pos->ops->bind)
> > +			continue;
> > +
> > +		if (!pos->tzp && pos->ops->bind) {
> > +			ret = pos->ops->bind(pos, cdev);
> > +			if (ret)
> > +				print_bind_err_msg(pos, cdev, ret);
> > +		}
> > +
> > +		tzp = pos->tzp;
> > +		if (!tzp || !tzp->tbp)
> > +			continue;
> > +
> > +		for (i = 0; i < tzp->num_tbps; i++) {
> > +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> > +				continue;
> > +			if (tzp->tbp[i].match(pos, cdev))
> > +				continue;
> > +			tzp->tbp[i].cdev = cdev;
> > +			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +}
> > +
> > +static void bind_tz(struct thermal_zone_device *tz)
> > +{
> > +	int i, ret;
> > +	struct thermal_cooling_device *pos = NULL;
> > +	const struct thermal_zone_params *tzp = tz->tzp;
> > +
> > +	if (!tzp && !tz->ops->bind)
> > +		return;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +
> > +	/* If there is no platform data, try to use ops->bind */
> > +	if (!tzp && tz->ops->bind) {
> > +		list_for_each_entry(pos, &thermal_cdev_list, node) {
> > +			ret = tz->ops->bind(tz, pos);
> > +			if (ret)
> > +				print_bind_err_msg(tz, pos, ret);
> > +		}
> > +		goto exit;
> > +	}
> > +
> > +	if (!tzp || !tzp->tbp)
> > +		goto exit;
> > +
> > +	list_for_each_entry(pos, &thermal_cdev_list, node) {
> > +		for (i = 0; i < tzp->num_tbps; i++) {
> > +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> > +				continue;
> > +			if (tzp->tbp[i].match(tz, pos))
> > +				continue;
> > +			tzp->tbp[i].cdev = pos;
> > +			__bind(tz, tzp->tbp[i].trip_mask, pos);
> > +		}
> > +	}
> > +exit:
> > +	mutex_unlock(&thermal_list_lock);
> > +}
> > +
> > +static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
> > +					    int delay)
> > +{
> > +	if (delay > 1000)
> > +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> > +				 round_jiffies(msecs_to_jiffies(delay)));
> > +	else if (delay)
> > +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> > +				 msecs_to_jiffies(delay));
> > +	else
> > +		cancel_delayed_work(&tz->poll_queue);
> > +}
> > +
> > +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);
> > +	else if (tz->polling_delay)
> > +		thermal_zone_device_set_polling(tz, tz->polling_delay);
> > +	else
> > +		thermal_zone_device_set_polling(tz, 0);
> > +
> > +	mutex_unlock(&tz->lock);
> > +}
> > +
> > +static void handle_non_critical_trips(struct thermal_zone_device *tz,
> > +			int trip, enum thermal_trip_type trip_type)
> > +{
> > +	if (tz->governor)
> > +		tz->governor->throttle(tz, trip);
> > +}
> > +
> > +static void handle_critical_trips(struct thermal_zone_device *tz,
> > +				int trip, enum thermal_trip_type trip_type)
> > +{
> > +	long trip_temp;
> > +
> > +	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> > +
> > +	/* If we have not crossed the trip_temp, we do not care. */
> > +	if (tz->temperature < trip_temp)
> > +		return;
> > +
> > +	if (tz->ops->notify)
> > +		tz->ops->notify(tz, trip, trip_type);
> > +
> > +	if (trip_type == THERMAL_TRIP_CRITICAL) {
> > +		dev_emerg(&tz->device,
> > +			  "critical temperature reached(%d C),shutting down\n",
> > +			  tz->temperature / 1000);
> > +		orderly_poweroff(true);
> > +	}
> > +}
> > +
> > +static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> > +{
> > +	enum thermal_trip_type type;
> > +
> > +	tz->ops->get_trip_type(tz, trip, &type);
> > +
> > +	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
> > +		handle_critical_trips(tz, trip, type);
> > +	else
> > +		handle_non_critical_trips(tz, trip, type);
> > +	/*
> > +	 * Alright, we handled this trip successfully.
> > +	 * So, start monitoring again.
> > +	 */
> > +	monitor_thermal_zone(tz);
> > +}
> > +
> > +static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> > +				unsigned long *temp)
> > +{
> > +	int ret = 0;
> > +#ifdef CONFIG_THERMAL_EMULATION
> > +	int count;
> > +	unsigned long crit_temp = -1UL;
> > +	enum thermal_trip_type type;
> > +#endif
> > +
> > +	mutex_lock(&tz->lock);
> > +
> > +	ret = tz->ops->get_temp(tz, temp);
> > +#ifdef CONFIG_THERMAL_EMULATION
> > +	if (!tz->emul_temperature)
> > +		goto skip_emul;
> > +
> > +	for (count = 0; count < tz->trips; count++) {
> > +		ret = tz->ops->get_trip_type(tz, count, &type);
> > +		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> > +			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> > +			break;
> > +		}
> > +	}
> > +
> > +	if (ret)
> > +		goto skip_emul;
> > +
> > +	if (*temp < crit_temp)
> > +		*temp = tz->emul_temperature;
> > +skip_emul:
> > +#endif
> > +	mutex_unlock(&tz->lock);
> > +	return ret;
> > +}
> > +
> > +static void update_temperature(struct thermal_zone_device *tz)
> > +{
> > +	long temp;
> > +	int ret;
> > +
> > +	ret = thermal_zone_get_temp(tz, &temp);
> > +	if (ret) {
> > +		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
> > +			 tz->id);
> > +		return;
> > +	}
> > +
> > +	mutex_lock(&tz->lock);
> > +	tz->last_temperature = tz->temperature;
> > +	tz->temperature = temp;
> > +	mutex_unlock(&tz->lock);
> > +}
> > +
> > +void thermal_zone_device_update(struct thermal_zone_device *tz)
> > +{
> > +	int count;
> > +
> > +	update_temperature(tz);
> > +
> > +	for (count = 0; count < tz->trips; count++)
> > +		handle_thermal_trip(tz, count);
> > +}
> > +EXPORT_SYMBOL(thermal_zone_device_update);
> > +
> > +static void thermal_zone_device_check(struct work_struct *work)
> > +{
> > +	struct thermal_zone_device *tz = container_of(work, struct
> > +						      thermal_zone_device,
> > +						      poll_queue.work);
> > +	thermal_zone_device_update(tz);
> > +}
> > +
> > +/* sys I/F for thermal zone */
> > +
> > +#define to_thermal_zone(_dev) \
> > +	container_of(_dev, struct thermal_zone_device, device)
> > +
> > +static ssize_t
> > +type_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +
> > +	return sprintf(buf, "%s\n", tz->type);
> > +}
> > +
> > +static ssize_t
> > +temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	long temperature;
> > +	int ret;
> > +
> > +	ret = thermal_zone_get_temp(tz, &temperature);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +static ssize_t
> > +mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	enum thermal_device_mode mode;
> > +	int result;
> > +
> > +	if (!tz->ops->get_mode)
> > +		return -EPERM;
> > +
> > +	result = tz->ops->get_mode(tz, &mode);
> > +	if (result)
> > +		return result;
> > +
> > +	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
> > +		       : "disabled");
> > +}
> > +
> > +static ssize_t
> > +mode_store(struct device *dev, struct device_attribute *attr,
> > +	   const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int result;
> > +
> > +	if (!tz->ops->set_mode)
> > +		return -EPERM;
> > +
> > +	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);
> > +	else
> > +		result = -EINVAL;
> > +
> > +	if (result)
> > +		return result;
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t
> > +trip_point_type_show(struct device *dev, struct device_attribute *attr,
> > +		     char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	enum thermal_trip_type type;
> > +	int trip, result;
> > +
> > +	if (!tz->ops->get_trip_type)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> > +		return -EINVAL;
> > +
> > +	result = tz->ops->get_trip_type(tz, trip, &type);
> > +	if (result)
> > +		return result;
> > +
> > +	switch (type) {
> > +	case THERMAL_TRIP_CRITICAL:
> > +		return sprintf(buf, "critical\n");
> > +	case THERMAL_TRIP_HOT:
> > +		return sprintf(buf, "hot\n");
> > +	case THERMAL_TRIP_PASSIVE:
> > +		return sprintf(buf, "passive\n");
> > +	case THERMAL_TRIP_ACTIVE:
> > +		return sprintf(buf, "active\n");
> > +	default:
> > +		return sprintf(buf, "unknown\n");
> > +	}
> > +}
> > +
> > +static ssize_t
> > +trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> > +		     const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int trip, ret;
> > +	unsigned long temperature;
> > +
> > +	if (!tz->ops->set_trip_temp)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> > +		return -EINVAL;
> > +
> > +	if (kstrtoul(buf, 10, &temperature))
> > +		return -EINVAL;
> > +
> > +	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> > +
> > +	return ret ? ret : count;
> > +}
> > +
> > +static ssize_t
> > +trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> > +		     char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int trip, ret;
> > +	long temperature;
> > +
> > +	if (!tz->ops->get_trip_temp)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> > +		return -EINVAL;
> > +
> > +	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +static ssize_t
> > +trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> > +			const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int trip, ret;
> > +	unsigned long temperature;
> > +
> > +	if (!tz->ops->set_trip_hyst)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> > +		return -EINVAL;
> > +
> > +	if (kstrtoul(buf, 10, &temperature))
> > +		return -EINVAL;
> > +
> > +	/*
> > +	 * We are not doing any check on the 'temperature' value
> > +	 * here. The driver implementing 'set_trip_hyst' has to
> > +	 * take care of this.
> > +	 */
> > +	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> > +
> > +	return ret ? ret : count;
> > +}
> > +
> > +static ssize_t
> > +trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> > +			char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int trip, ret;
> > +	unsigned long temperature;
> > +
> > +	if (!tz->ops->get_trip_hyst)
> > +		return -EPERM;
> > +
> > +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> > +		return -EINVAL;
> > +
> > +	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> > +
> > +	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +static ssize_t
> > +passive_store(struct device *dev, struct device_attribute *attr,
> > +		    const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	struct thermal_cooling_device *cdev = NULL;
> > +	int state;
> > +
> > +	if (!sscanf(buf, "%d\n", &state))
> > +		return -EINVAL;
> > +
> > +	/* sanity check: values below 1000 millicelcius don't make sense
> > +	 * and can cause the system to go into a thermal heart attack
> > +	 */
> > +	if (state && state < 1000)
> > +		return -EINVAL;
> > +
> > +	if (state && !tz->forced_passive) {
> > +		mutex_lock(&thermal_list_lock);
> > +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > +			if (!strncmp("Processor", cdev->type,
> > +				     sizeof("Processor")))
> > +				thermal_zone_bind_cooling_device(tz,
> > +						THERMAL_TRIPS_NONE, cdev,
> > +						THERMAL_NO_LIMIT,
> > +						THERMAL_NO_LIMIT);
> > +		}
> > +		mutex_unlock(&thermal_list_lock);
> > +		if (!tz->passive_delay)
> > +			tz->passive_delay = 1000;
> > +	} else if (!state && tz->forced_passive) {
> > +		mutex_lock(&thermal_list_lock);
> > +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > +			if (!strncmp("Processor", cdev->type,
> > +				     sizeof("Processor")))
> > +				thermal_zone_unbind_cooling_device(tz,
> > +								   THERMAL_TRIPS_NONE,
> > +								   cdev);
> > +		}
> > +		mutex_unlock(&thermal_list_lock);
> > +		tz->passive_delay = 0;
> > +	}
> > +
> > +	tz->forced_passive = state;
> > +
> > +	thermal_zone_device_update(tz);
> > +
> > +	return count;
> > +}
> > +
> > +static ssize_t
> > +passive_show(struct device *dev, struct device_attribute *attr,
> > +		   char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +
> > +	return sprintf(buf, "%d\n", tz->forced_passive);
> > +}
> > +
> > +static ssize_t
> > +policy_store(struct device *dev, struct device_attribute *attr,
> > +		    const char *buf, size_t count)
> > +{
> > +	int ret = -EINVAL;
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	struct thermal_governor *gov;
> > +
> > +	mutex_lock(&thermal_governor_lock);
> > +
> > +	gov = __find_governor(buf);
> > +	if (!gov)
> > +		goto exit;
> > +
> > +	tz->governor = gov;
> > +	ret = count;
> > +
> > +exit:
> > +	mutex_unlock(&thermal_governor_lock);
> > +	return ret;
> > +}
> > +
> > +static ssize_t
> > +policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +
> > +	return sprintf(buf, "%s\n", tz->governor->name);
> > +}
> > +
> > +#ifdef CONFIG_THERMAL_EMULATION
> > +static ssize_t
> > +emul_temp_store(struct device *dev, struct device_attribute *attr,
> > +		     const char *buf, size_t count)
> > +{
> > +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > +	int ret = 0;
> > +	unsigned long temperature;
> > +
> > +	if (kstrtoul(buf, 10, &temperature))
> > +		return -EINVAL;
> > +
> > +	if (!tz->ops->set_emul_temp) {
> > +		mutex_lock(&tz->lock);
> > +		tz->emul_temperature = temperature;
> > +		mutex_unlock(&tz->lock);
> > +	} else {
> > +		ret = tz->ops->set_emul_temp(tz, temperature);
> > +	}
> > +
> > +	return ret ? ret : count;
> > +}
> > +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> > +#endif/*CONFIG_THERMAL_EMULATION*/
> > +
> > +static DEVICE_ATTR(type, 0444, type_show, NULL);
> > +static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> > +static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> > +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
> > +static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
> > +
> > +/* sys I/F for cooling device */
> > +#define to_cooling_device(_dev)	\
> > +	container_of(_dev, struct thermal_cooling_device, device)
> > +
> > +static ssize_t
> > +thermal_cooling_device_type_show(struct device *dev,
> > +				 struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > +
> > +	return sprintf(buf, "%s\n", cdev->type);
> > +}
> > +
> > +static ssize_t
> > +thermal_cooling_device_max_state_show(struct device *dev,
> > +				      struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > +	unsigned long state;
> > +	int ret;
> > +
> > +	ret = cdev->ops->get_max_state(cdev, &state);
> > +	if (ret)
> > +		return ret;
> > +	return sprintf(buf, "%ld\n", state);
> > +}
> > +
> > +static ssize_t
> > +thermal_cooling_device_cur_state_show(struct device *dev,
> > +				      struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > +	unsigned long state;
> > +	int ret;
> > +
> > +	ret = cdev->ops->get_cur_state(cdev, &state);
> > +	if (ret)
> > +		return ret;
> > +	return sprintf(buf, "%ld\n", state);
> > +}
> > +
> > +static ssize_t
> > +thermal_cooling_device_cur_state_store(struct device *dev,
> > +				       struct device_attribute *attr,
> > +				       const char *buf, size_t count)
> > +{
> > +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > +	unsigned long state;
> > +	int result;
> > +
> > +	if (!sscanf(buf, "%ld\n", &state))
> > +		return -EINVAL;
> > +
> > +	if ((long)state < 0)
> > +		return -EINVAL;
> > +
> > +	result = cdev->ops->set_cur_state(cdev, state);
> > +	if (result)
> > +		return result;
> > +	return count;
> > +}
> > +
> > +static struct device_attribute dev_attr_cdev_type =
> > +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> > +static DEVICE_ATTR(max_state, 0444,
> > +		   thermal_cooling_device_max_state_show, NULL);
> > +static DEVICE_ATTR(cur_state, 0644,
> > +		   thermal_cooling_device_cur_state_show,
> > +		   thermal_cooling_device_cur_state_store);
> > +
> > +static ssize_t
> > +thermal_cooling_device_trip_point_show(struct device *dev,
> > +				       struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_instance *instance;
> > +
> > +	instance =
> > +	    container_of(attr, struct thermal_instance, attr);
> > +
> > +	if (instance->trip == THERMAL_TRIPS_NONE)
> > +		return sprintf(buf, "-1\n");
> > +	else
> > +		return sprintf(buf, "%d\n", instance->trip);
> > +}
> > +
> > +/* Device management */
> > +
> > +#if defined(CONFIG_THERMAL_HWMON)
> > +
> > +/* hwmon sys I/F */
> > +#include <linux/hwmon.h>
> > +
> > +/* thermal zone devices with the same type share one hwmon device */
> > +struct thermal_hwmon_device {
> > +	char type[THERMAL_NAME_LENGTH];
> > +	struct device *device;
> > +	int count;
> > +	struct list_head tz_list;
> > +	struct list_head node;
> > +};
> > +
> > +struct thermal_hwmon_attr {
> > +	struct device_attribute attr;
> > +	char name[16];
> > +};
> > +
> > +/* one temperature input for each thermal zone */
> > +struct thermal_hwmon_temp {
> > +	struct list_head hwmon_node;
> > +	struct thermal_zone_device *tz;
> > +	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> > +	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> > +};
> > +
> > +static LIST_HEAD(thermal_hwmon_list);
> > +
> > +static ssize_t
> > +name_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> > +	return sprintf(buf, "%s\n", hwmon->type);
> > +}
> > +static DEVICE_ATTR(name, 0444, name_show, NULL);
> > +
> > +static ssize_t
> > +temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
> > +{
> > +	long temperature;
> > +	int ret;
> > +	struct thermal_hwmon_attr *hwmon_attr
> > +			= container_of(attr, struct thermal_hwmon_attr, attr);
> > +	struct thermal_hwmon_temp *temp
> > +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> > +				       temp_input);
> > +	struct thermal_zone_device *tz = temp->tz;
> > +
> > +	ret = thermal_zone_get_temp(tz, &temperature);
> > +
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +static ssize_t
> > +temp_crit_show(struct device *dev, struct device_attribute *attr,
> > +		char *buf)
> > +{
> > +	struct thermal_hwmon_attr *hwmon_attr
> > +			= container_of(attr, struct thermal_hwmon_attr, attr);
> > +	struct thermal_hwmon_temp *temp
> > +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> > +				       temp_crit);
> > +	struct thermal_zone_device *tz = temp->tz;
> > +	long temperature;
> > +	int ret;
> > +
> > +	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> > +	if (ret)
> > +		return ret;
> > +
> > +	return sprintf(buf, "%ld\n", temperature);
> > +}
> > +
> > +
> > +static struct thermal_hwmon_device *
> > +thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> > +{
> > +	struct thermal_hwmon_device *hwmon;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> > +		if (!strcmp(hwmon->type, tz->type)) {
> > +			mutex_unlock(&thermal_list_lock);
> > +			return hwmon;
> > +		}
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	return NULL;
> > +}
> > +
> > +/* Find the temperature input matching a given thermal zone */
> > +static struct thermal_hwmon_temp *
> > +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
> > +			  const struct thermal_zone_device *tz)
> > +{
> > +	struct thermal_hwmon_temp *temp;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> > +		if (temp->tz == tz) {
> > +			mutex_unlock(&thermal_list_lock);
> > +			return temp;
> > +		}
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	return NULL;
> > +}
> > +
> > +static int
> > +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> > +{
> > +	struct thermal_hwmon_device *hwmon;
> > +	struct thermal_hwmon_temp *temp;
> > +	int new_hwmon_device = 1;
> > +	int result;
> > +
> > +	hwmon = thermal_hwmon_lookup_by_type(tz);
> > +	if (hwmon) {
> > +		new_hwmon_device = 0;
> > +		goto register_sys_interface;
> > +	}
> > +
> > +	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
> > +	if (!hwmon)
> > +		return -ENOMEM;
> > +
> > +	INIT_LIST_HEAD(&hwmon->tz_list);
> > +	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> > +	hwmon->device = hwmon_device_register(NULL);
> > +	if (IS_ERR(hwmon->device)) {
> > +		result = PTR_ERR(hwmon->device);
> > +		goto free_mem;
> > +	}
> > +	dev_set_drvdata(hwmon->device, hwmon);
> > +	result = device_create_file(hwmon->device, &dev_attr_name);
> > +	if (result)
> > +		goto free_mem;
> > +
> > + register_sys_interface:
> > +	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> > +	if (!temp) {
> > +		result = -ENOMEM;
> > +		goto unregister_name;
> > +	}
> > +
> > +	temp->tz = tz;
> > +	hwmon->count++;
> > +
> > +	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
> > +		 "temp%d_input", hwmon->count);
> > +	temp->temp_input.attr.attr.name = temp->temp_input.name;
> > +	temp->temp_input.attr.attr.mode = 0444;
> > +	temp->temp_input.attr.show = temp_input_show;
> > +	sysfs_attr_init(&temp->temp_input.attr.attr);
> > +	result = device_create_file(hwmon->device, &temp->temp_input.attr);
> > +	if (result)
> > +		goto free_temp_mem;
> > +
> > +	if (tz->ops->get_crit_temp) {
> > +		unsigned long temperature;
> > +		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> > +			snprintf(temp->temp_crit.name,
> > +				 sizeof(temp->temp_crit.name),
> > +				"temp%d_crit", hwmon->count);
> > +			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
> > +			temp->temp_crit.attr.attr.mode = 0444;
> > +			temp->temp_crit.attr.show = temp_crit_show;
> > +			sysfs_attr_init(&temp->temp_crit.attr.attr);
> > +			result = device_create_file(hwmon->device,
> > +						    &temp->temp_crit.attr);
> > +			if (result)
> > +				goto unregister_input;
> > +		}
> > +	}
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	if (new_hwmon_device)
> > +		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> > +	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	return 0;
> > +
> > + unregister_input:
> > +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> > + free_temp_mem:
> > +	kfree(temp);
> > + unregister_name:
> > +	if (new_hwmon_device) {
> > +		device_remove_file(hwmon->device, &dev_attr_name);
> > +		hwmon_device_unregister(hwmon->device);
> > +	}
> > + free_mem:
> > +	if (new_hwmon_device)
> > +		kfree(hwmon);
> > +
> > +	return result;
> > +}
> > +
> > +static void
> > +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> > +{
> > +	struct thermal_hwmon_device *hwmon;
> > +	struct thermal_hwmon_temp *temp;
> > +
> > +	hwmon = thermal_hwmon_lookup_by_type(tz);
> > +	if (unlikely(!hwmon)) {
> > +		/* Should never happen... */
> > +		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> > +		return;
> > +	}
> > +
> > +	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> > +	if (unlikely(!temp)) {
> > +		/* Should never happen... */
> > +		dev_dbg(&tz->device, "temperature input lookup failed!\n");
> > +		return;
> > +	}
> > +
> > +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> > +	if (tz->ops->get_crit_temp)
> > +		device_remove_file(hwmon->device, &temp->temp_crit.attr);
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_del(&temp->hwmon_node);
> > +	kfree(temp);
> > +	if (!list_empty(&hwmon->tz_list)) {
> > +		mutex_unlock(&thermal_list_lock);
> > +		return;
> > +	}
> > +	list_del(&hwmon->node);
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	device_remove_file(hwmon->device, &dev_attr_name);
> > +	hwmon_device_unregister(hwmon->device);
> > +	kfree(hwmon);
> > +}
> > +#else
> > +static int
> > +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> > +{
> > +	return 0;
> > +}
> > +
> > +static void
> > +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> > +{
> > +}
> > +#endif
> > +
> > +/**
> > + * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
> > + * @tz:		thermal zone device
> > + * @trip:	indicates which trip point the cooling devices is
> > + *		associated with in this thermal zone.
> > + * @cdev:	thermal cooling device
> > + *
> > + * This function is usually called in the thermal zone device .bind callback.
> > + */
> > +int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> > +				     int trip,
> > +				     struct thermal_cooling_device *cdev,
> > +				     unsigned long upper, unsigned long lower)
> > +{
> > +	struct thermal_instance *dev;
> > +	struct thermal_instance *pos;
> > +	struct thermal_zone_device *pos1;
> > +	struct thermal_cooling_device *pos2;
> > +	unsigned long max_state;
> > +	int result;
> > +
> > +	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> > +		return -EINVAL;
> > +
> > +	list_for_each_entry(pos1, &thermal_tz_list, node) {
> > +		if (pos1 == tz)
> > +			break;
> > +	}
> > +	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> > +		if (pos2 == cdev)
> > +			break;
> > +	}
> > +
> > +	if (tz != pos1 || cdev != pos2)
> > +		return -EINVAL;
> > +
> > +	cdev->ops->get_max_state(cdev, &max_state);
> > +
> > +	/* lower default 0, upper default max_state */
> > +	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> > +	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> > +
> > +	if (lower > upper || upper > max_state)
> > +		return -EINVAL;
> > +
> > +	dev =
> > +	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> > +	if (!dev)
> > +		return -ENOMEM;
> > +	dev->tz = tz;
> > +	dev->cdev = cdev;
> > +	dev->trip = trip;
> > +	dev->upper = upper;
> > +	dev->lower = lower;
> > +	dev->target = THERMAL_NO_TARGET;
> > +
> > +	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> > +	if (result)
> > +		goto free_mem;
> > +
> > +	sprintf(dev->name, "cdev%d", dev->id);
> > +	result =
> > +	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
> > +	if (result)
> > +		goto release_idr;
> > +
> > +	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> > +	sysfs_attr_init(&dev->attr.attr);
> > +	dev->attr.attr.name = dev->attr_name;
> > +	dev->attr.attr.mode = 0444;
> > +	dev->attr.show = thermal_cooling_device_trip_point_show;
> > +	result = device_create_file(&tz->device, &dev->attr);
> > +	if (result)
> > +		goto remove_symbol_link;
> > +
> > +	mutex_lock(&tz->lock);
> > +	mutex_lock(&cdev->lock);
> > +	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> > +	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > +		result = -EEXIST;
> > +		break;
> > +	}
> > +	if (!result) {
> > +		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> > +		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
> > +	}
> > +	mutex_unlock(&cdev->lock);
> > +	mutex_unlock(&tz->lock);
> > +
> > +	if (!result)
> > +		return 0;
> > +
> > +	device_remove_file(&tz->device, &dev->attr);
> > +remove_symbol_link:
> > +	sysfs_remove_link(&tz->device.kobj, dev->name);
> > +release_idr:
> > +	release_idr(&tz->idr, &tz->lock, dev->id);
> > +free_mem:
> > +	kfree(dev);
> > +	return result;
> > +}
> > +EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> > +
> > +/**
> > + * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
> > + * @tz:		thermal zone device
> > + * @trip:	indicates which trip point the cooling devices is
> > + *		associated with in this thermal zone.
> > + * @cdev:	thermal cooling device
> > + *
> > + * This function is usually called in the thermal zone device .unbind callback.
> > + */
> > +int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> > +				       int trip,
> > +				       struct thermal_cooling_device *cdev)
> > +{
> > +	struct thermal_instance *pos, *next;
> > +
> > +	mutex_lock(&tz->lock);
> > +	mutex_lock(&cdev->lock);
> > +	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
> > +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > +			list_del(&pos->tz_node);
> > +			list_del(&pos->cdev_node);
> > +			mutex_unlock(&cdev->lock);
> > +			mutex_unlock(&tz->lock);
> > +			goto unbind;
> > +		}
> > +	}
> > +	mutex_unlock(&cdev->lock);
> > +	mutex_unlock(&tz->lock);
> > +
> > +	return -ENODEV;
> > +
> > +unbind:
> > +	device_remove_file(&tz->device, &pos->attr);
> > +	sysfs_remove_link(&tz->device.kobj, pos->name);
> > +	release_idr(&tz->idr, &tz->lock, pos->id);
> > +	kfree(pos);
> > +	return 0;
> > +}
> > +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> > +
> > +static void thermal_release(struct device *dev)
> > +{
> > +	struct thermal_zone_device *tz;
> > +	struct thermal_cooling_device *cdev;
> > +
> > +	if (!strncmp(dev_name(dev), "thermal_zone",
> > +		     sizeof("thermal_zone") - 1)) {
> > +		tz = to_thermal_zone(dev);
> > +		kfree(tz);
> > +	} else {
> > +		cdev = to_cooling_device(dev);
> > +		kfree(cdev);
> > +	}
> > +}
> > +
> > +static struct class thermal_class = {
> > +	.name = "thermal",
> > +	.dev_release = thermal_release,
> > +};
> > +
> > +/**
> > + * thermal_cooling_device_register - register a new thermal cooling device
> > + * @type:	the thermal cooling device type.
> > + * @devdata:	device private data.
> > + * @ops:		standard thermal cooling devices callbacks.
> > + */
> > +struct thermal_cooling_device *
> > +thermal_cooling_device_register(char *type, void *devdata,
> > +				const struct thermal_cooling_device_ops *ops)
> > +{
> > +	struct thermal_cooling_device *cdev;
> > +	int result;
> > +
> > +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> > +	    !ops->set_cur_state)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> > +	if (!cdev)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> > +	if (result) {
> > +		kfree(cdev);
> > +		return ERR_PTR(result);
> > +	}
> > +
> > +	strcpy(cdev->type, type ? : "");
> > +	mutex_init(&cdev->lock);
> > +	INIT_LIST_HEAD(&cdev->thermal_instances);
> > +	cdev->ops = ops;
> > +	cdev->updated = true;
> > +	cdev->device.class = &thermal_class;
> > +	cdev->devdata = devdata;
> > +	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> > +	result = device_register(&cdev->device);
> > +	if (result) {
> > +		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > +		kfree(cdev);
> > +		return ERR_PTR(result);
> > +	}
> > +
> > +	/* sys I/F */
> > +	if (type) {
> > +		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
> > +		if (result)
> > +			goto unregister;
> > +	}
> > +
> > +	result = device_create_file(&cdev->device, &dev_attr_max_state);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	/* Add 'this' new cdev to the global cdev list */
> > +	mutex_lock(&thermal_list_lock);
> > +	list_add(&cdev->node, &thermal_cdev_list);
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	/* Update binding information for 'this' new cdev */
> > +	bind_cdev(cdev);
> > +
> > +	return cdev;
> > +
> > +unregister:
> > +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > +	device_unregister(&cdev->device);
> > +	return ERR_PTR(result);
> > +}
> > +EXPORT_SYMBOL(thermal_cooling_device_register);
> > +
> > +/**
> > + * thermal_cooling_device_unregister - removes the registered thermal cooling device
> > + * @cdev:	the thermal cooling device to remove.
> > + *
> > + * thermal_cooling_device_unregister() must be called when the device is no
> > + * longer needed.
> > + */
> > +void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
> > +{
> > +	int i;
> > +	const struct thermal_zone_params *tzp;
> > +	struct thermal_zone_device *tz;
> > +	struct thermal_cooling_device *pos = NULL;
> > +
> > +	if (!cdev)
> > +		return;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_for_each_entry(pos, &thermal_cdev_list, node)
> > +	    if (pos == cdev)
> > +		break;
> > +	if (pos != cdev) {
> > +		/* thermal cooling device not found */
> > +		mutex_unlock(&thermal_list_lock);
> > +		return;
> > +	}
> > +	list_del(&cdev->node);
> > +
> > +	/* Unbind all thermal zones associated with 'this' cdev */
> > +	list_for_each_entry(tz, &thermal_tz_list, node) {
> > +		if (tz->ops->unbind) {
> > +			tz->ops->unbind(tz, cdev);
> > +			continue;
> > +		}
> > +
> > +		if (!tz->tzp || !tz->tzp->tbp)
> > +			continue;
> > +
> > +		tzp = tz->tzp;
> > +		for (i = 0; i < tzp->num_tbps; i++) {
> > +			if (tzp->tbp[i].cdev == cdev) {
> > +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> > +				tzp->tbp[i].cdev = NULL;
> > +			}
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	if (cdev->type[0])
> > +		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> > +	device_remove_file(&cdev->device, &dev_attr_max_state);
> > +	device_remove_file(&cdev->device, &dev_attr_cur_state);
> > +
> > +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > +	device_unregister(&cdev->device);
> > +	return;
> > +}
> > +EXPORT_SYMBOL(thermal_cooling_device_unregister);
> > +
> > +void thermal_cdev_update(struct thermal_cooling_device *cdev)
> > +{
> > +	struct thermal_instance *instance;
> > +	unsigned long target = 0;
> > +
> > +	/* cooling device is updated*/
> > +	if (cdev->updated)
> > +		return;
> > +
> > +	mutex_lock(&cdev->lock);
> > +	/* Make sure cdev enters the deepest cooling state */
> > +	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
> > +		if (instance->target == THERMAL_NO_TARGET)
> > +			continue;
> > +		if (instance->target > target)
> > +			target = instance->target;
> > +	}
> > +	mutex_unlock(&cdev->lock);
> > +	cdev->ops->set_cur_state(cdev, target);
> > +	cdev->updated = true;
> > +}
> > +EXPORT_SYMBOL(thermal_cdev_update);
> > +
> > +/**
> > + * notify_thermal_framework - Sensor drivers use this API to notify framework
> > + * @tz:		thermal zone device
> > + * @trip:	indicates which trip point has been crossed
> > + *
> > + * This function handles the trip events from sensor drivers. It starts
> > + * throttling the cooling devices according to the policy configured.
> > + * For CRITICAL and HOT trip points, this notifies the respective drivers,
> > + * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> > + * The throttling policy is based on the configured platform data; if no
> > + * platform data is provided, this uses the step_wise throttling policy.
> > + */
> > +void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> > +{
> > +	handle_thermal_trip(tz, trip);
> > +}
> > +EXPORT_SYMBOL(notify_thermal_framework);
> > +
> > +/**
> > + * create_trip_attrs - create attributes for trip points
> > + * @tz:		the thermal zone device
> > + * @mask:	Writeable trip point bitmap.
> > + */
> > +static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> > +{
> > +	int indx;
> > +	int size = sizeof(struct thermal_attr) * tz->trips;
> > +
> > +	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> > +	if (!tz->trip_type_attrs)
> > +		return -ENOMEM;
> > +
> > +	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> > +	if (!tz->trip_temp_attrs) {
> > +		kfree(tz->trip_type_attrs);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	if (tz->ops->get_trip_hyst) {
> > +		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> > +		if (!tz->trip_hyst_attrs) {
> > +			kfree(tz->trip_type_attrs);
> > +			kfree(tz->trip_temp_attrs);
> > +			return -ENOMEM;
> > +		}
> > +	}
> > +
> > +
> > +	for (indx = 0; indx < tz->trips; indx++) {
> > +		/* create trip type attribute */
> > +		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
> > +			 "trip_point_%d_type", indx);
> > +
> > +		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> > +		tz->trip_type_attrs[indx].attr.attr.name =
> > +						tz->trip_type_attrs[indx].name;
> > +		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> > +		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> > +
> > +		device_create_file(&tz->device,
> > +				   &tz->trip_type_attrs[indx].attr);
> > +
> > +		/* create trip temp attribute */
> > +		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
> > +			 "trip_point_%d_temp", indx);
> > +
> > +		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> > +		tz->trip_temp_attrs[indx].attr.attr.name =
> > +						tz->trip_temp_attrs[indx].name;
> > +		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> > +		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
> > +		if (mask & (1 << indx)) {
> > +			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
> > +			tz->trip_temp_attrs[indx].attr.store =
> > +							trip_point_temp_store;
> > +		}
> > +
> > +		device_create_file(&tz->device,
> > +				   &tz->trip_temp_attrs[indx].attr);
> > +
> > +		/* create Optional trip hyst attribute */
> > +		if (!tz->ops->get_trip_hyst)
> > +			continue;
> > +		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
> > +			 "trip_point_%d_hyst", indx);
> > +
> > +		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> > +		tz->trip_hyst_attrs[indx].attr.attr.name =
> > +					tz->trip_hyst_attrs[indx].name;
> > +		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> > +		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> > +		if (tz->ops->set_trip_hyst) {
> > +			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> > +			tz->trip_hyst_attrs[indx].attr.store =
> > +					trip_point_hyst_store;
> > +		}
> > +
> > +		device_create_file(&tz->device,
> > +				   &tz->trip_hyst_attrs[indx].attr);
> > +	}
> > +	return 0;
> > +}
> > +
> > +static void remove_trip_attrs(struct thermal_zone_device *tz)
> > +{
> > +	int indx;
> > +
> > +	for (indx = 0; indx < tz->trips; indx++) {
> > +		device_remove_file(&tz->device,
> > +				   &tz->trip_type_attrs[indx].attr);
> > +		device_remove_file(&tz->device,
> > +				   &tz->trip_temp_attrs[indx].attr);
> > +		if (tz->ops->get_trip_hyst)
> > +			device_remove_file(&tz->device,
> > +				  &tz->trip_hyst_attrs[indx].attr);
> > +	}
> > +	kfree(tz->trip_type_attrs);
> > +	kfree(tz->trip_temp_attrs);
> > +	kfree(tz->trip_hyst_attrs);
> > +}
> > +
> > +/**
> > + * thermal_zone_device_register - register a new thermal zone device
> > + * @type:	the thermal zone device type
> > + * @trips:	the number of trip points the thermal zone support
> > + * @mask:	a bit string indicating the writeablility of trip points
> > + * @devdata:	private device data
> > + * @ops:	standard thermal zone device callbacks
> > + * @tzp:	thermal zone platform parameters
> > + * @passive_delay: number of milliseconds to wait between polls when
> > + *		   performing passive cooling
> > + * @polling_delay: number of milliseconds to wait between polls when checking
> > + *		   whether trip points have been crossed (0 for interrupt
> > + *		   driven systems)
> > + *
> > + * thermal_zone_device_unregister() must be called when the device is no
> > + * longer needed. The passive cooling depends on the .get_trend() return value.
> > + */
> > +struct thermal_zone_device *thermal_zone_device_register(const char *type,
> > +	int trips, int mask, void *devdata,
> > +	const struct thermal_zone_device_ops *ops,
> > +	const struct thermal_zone_params *tzp,
> > +	int passive_delay, int polling_delay)
> > +{
> > +	struct thermal_zone_device *tz;
> > +	enum thermal_trip_type trip_type;
> > +	int result;
> > +	int count;
> > +	int passive = 0;
> > +
> > +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	if (!ops || !ops->get_temp)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	if (trips > 0 && !ops->get_trip_type)
> > +		return ERR_PTR(-EINVAL);
> > +
> > +	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> > +	if (!tz)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	INIT_LIST_HEAD(&tz->thermal_instances);
> > +	idr_init(&tz->idr);
> > +	mutex_init(&tz->lock);
> > +	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> > +	if (result) {
> > +		kfree(tz);
> > +		return ERR_PTR(result);
> > +	}
> > +
> > +	strcpy(tz->type, type ? : "");
> > +	tz->ops = ops;
> > +	tz->tzp = tzp;
> > +	tz->device.class = &thermal_class;
> > +	tz->devdata = devdata;
> > +	tz->trips = trips;
> > +	tz->passive_delay = passive_delay;
> > +	tz->polling_delay = polling_delay;
> > +
> > +	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> > +	result = device_register(&tz->device);
> > +	if (result) {
> > +		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > +		kfree(tz);
> > +		return ERR_PTR(result);
> > +	}
> > +
> > +	/* sys I/F */
> > +	if (type) {
> > +		result = device_create_file(&tz->device, &dev_attr_type);
> > +		if (result)
> > +			goto unregister;
> > +	}
> > +
> > +	result = device_create_file(&tz->device, &dev_attr_temp);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	if (ops->get_mode) {
> > +		result = device_create_file(&tz->device, &dev_attr_mode);
> > +		if (result)
> > +			goto unregister;
> > +	}
> > +
> > +	result = create_trip_attrs(tz, mask);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	for (count = 0; count < trips; count++) {
> > +		tz->ops->get_trip_type(tz, count, &trip_type);
> > +		if (trip_type == THERMAL_TRIP_PASSIVE)
> > +			passive = 1;
> > +	}
> > +
> > +	if (!passive) {
> > +		result = device_create_file(&tz->device, &dev_attr_passive);
> > +		if (result)
> > +			goto unregister;
> > +	}
> > +
> > +#ifdef CONFIG_THERMAL_EMULATION
> > +	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> > +	if (result)
> > +		goto unregister;
> > +#endif
> > +	/* Create policy attribute */
> > +	result = device_create_file(&tz->device, &dev_attr_policy);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	/* Update 'this' zone's governor information */
> > +	mutex_lock(&thermal_governor_lock);
> > +
> > +	if (tz->tzp)
> > +		tz->governor = __find_governor(tz->tzp->governor_name);
> > +	else
> > +		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
> > +
> > +	mutex_unlock(&thermal_governor_lock);
> > +
> > +	result = thermal_add_hwmon_sysfs(tz);
> > +	if (result)
> > +		goto unregister;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_add_tail(&tz->node, &thermal_tz_list);
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	/* Bind cooling devices for this zone */
> > +	bind_tz(tz);
> > +
> > +	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
> > +
> > +	thermal_zone_device_update(tz);
> > +
> > +	if (!result)
> > +		return tz;
> > +
> > +unregister:
> > +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > +	device_unregister(&tz->device);
> > +	return ERR_PTR(result);
> > +}
> > +EXPORT_SYMBOL(thermal_zone_device_register);
> > +
> > +/**
> > + * thermal_device_unregister - removes the registered thermal zone device
> > + * @tz: the thermal zone device to remove
> > + */
> > +void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> > +{
> > +	int i;
> > +	const struct thermal_zone_params *tzp;
> > +	struct thermal_cooling_device *cdev;
> > +	struct thermal_zone_device *pos = NULL;
> > +
> > +	if (!tz)
> > +		return;
> > +
> > +	tzp = tz->tzp;
> > +
> > +	mutex_lock(&thermal_list_lock);
> > +	list_for_each_entry(pos, &thermal_tz_list, node)
> > +	    if (pos == tz)
> > +		break;
> > +	if (pos != tz) {
> > +		/* thermal zone device not found */
> > +		mutex_unlock(&thermal_list_lock);
> > +		return;
> > +	}
> > +	list_del(&tz->node);
> > +
> > +	/* Unbind all cdevs associated with 'this' thermal zone */
> > +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > +		if (tz->ops->unbind) {
> > +			tz->ops->unbind(tz, cdev);
> > +			continue;
> > +		}
> > +
> > +		if (!tzp || !tzp->tbp)
> > +			break;
> > +
> > +		for (i = 0; i < tzp->num_tbps; i++) {
> > +			if (tzp->tbp[i].cdev == cdev) {
> > +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> > +				tzp->tbp[i].cdev = NULL;
> > +			}
> > +		}
> > +	}
> > +
> > +	mutex_unlock(&thermal_list_lock);
> > +
> > +	thermal_zone_device_set_polling(tz, 0);
> > +
> > +	if (tz->type[0])
> > +		device_remove_file(&tz->device, &dev_attr_type);
> > +	device_remove_file(&tz->device, &dev_attr_temp);
> > +	if (tz->ops->get_mode)
> > +		device_remove_file(&tz->device, &dev_attr_mode);
> > +	device_remove_file(&tz->device, &dev_attr_policy);
> > +	remove_trip_attrs(tz);
> > +	tz->governor = NULL;
> > +
> > +	thermal_remove_hwmon_sysfs(tz);
> > +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > +	idr_destroy(&tz->idr);
> > +	mutex_destroy(&tz->lock);
> > +	device_unregister(&tz->device);
> > +	return;
> > +}
> > +EXPORT_SYMBOL(thermal_zone_device_unregister);
> > +
> > +#ifdef CONFIG_NET
> > +static struct genl_family thermal_event_genl_family = {
> > +	.id = GENL_ID_GENERATE,
> > +	.name = THERMAL_GENL_FAMILY_NAME,
> > +	.version = THERMAL_GENL_VERSION,
> > +	.maxattr = THERMAL_GENL_ATTR_MAX,
> > +};
> > +
> > +static struct genl_multicast_group thermal_event_mcgrp = {
> > +	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> > +};
> > +
> > +int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> > +					enum events event)
> > +{
> > +	struct sk_buff *skb;
> > +	struct nlattr *attr;
> > +	struct thermal_genl_event *thermal_event;
> > +	void *msg_header;
> > +	int size;
> > +	int result;
> > +	static unsigned int thermal_event_seqnum;
> > +
> > +	if (!tz)
> > +		return -EINVAL;
> > +
> > +	/* allocate memory */
> > +	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> > +	       nla_total_size(0);
> > +
> > +	skb = genlmsg_new(size, GFP_ATOMIC);
> > +	if (!skb)
> > +		return -ENOMEM;
> > +
> > +	/* add the genetlink message header */
> > +	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> > +				 &thermal_event_genl_family, 0,
> > +				 THERMAL_GENL_CMD_EVENT);
> > +	if (!msg_header) {
> > +		nlmsg_free(skb);
> > +		return -ENOMEM;
> > +	}
> > +
> > +	/* fill the data */
> > +	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> > +			   sizeof(struct thermal_genl_event));
> > +
> > +	if (!attr) {
> > +		nlmsg_free(skb);
> > +		return -EINVAL;
> > +	}
> > +
> > +	thermal_event = nla_data(attr);
> > +	if (!thermal_event) {
> > +		nlmsg_free(skb);
> > +		return -EINVAL;
> > +	}
> > +
> > +	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> > +
> > +	thermal_event->orig = tz->id;
> > +	thermal_event->event = event;
> > +
> > +	/* send multicast genetlink message */
> > +	result = genlmsg_end(skb, msg_header);
> > +	if (result < 0) {
> > +		nlmsg_free(skb);
> > +		return result;
> > +	}
> > +
> > +	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
> > +	if (result)
> > +		dev_err(&tz->device, "Failed to send netlink event:%d", result);
> > +
> > +	return result;
> > +}
> > +EXPORT_SYMBOL(thermal_generate_netlink_event);
> > +
> > +static int genetlink_init(void)
> > +{
> > +	int result;
> > +
> > +	result = genl_register_family(&thermal_event_genl_family);
> > +	if (result)
> > +		return result;
> > +
> > +	result = genl_register_mc_group(&thermal_event_genl_family,
> > +					&thermal_event_mcgrp);
> > +	if (result)
> > +		genl_unregister_family(&thermal_event_genl_family);
> > +	return result;
> > +}
> > +
> > +static void genetlink_exit(void)
> > +{
> > +	genl_unregister_family(&thermal_event_genl_family);
> > +}
> > +#else /* !CONFIG_NET */
> > +static inline int genetlink_init(void) { return 0; }
> > +static inline void genetlink_exit(void) {}
> > +#endif /* !CONFIG_NET */
> > +
> > +static int __init thermal_init(void)
> > +{
> > +	int result = 0;
> > +
> > +	result = class_register(&thermal_class);
> > +	if (result) {
> > +		idr_destroy(&thermal_tz_idr);
> > +		idr_destroy(&thermal_cdev_idr);
> > +		mutex_destroy(&thermal_idr_lock);
> > +		mutex_destroy(&thermal_list_lock);
> > +		return result;
> > +	}
> > +	result = genetlink_init();
> > +	return result;
> > +}
> > +
> > +static void __exit thermal_exit(void)
> > +{
> > +	class_unregister(&thermal_class);
> > +	idr_destroy(&thermal_tz_idr);
> > +	idr_destroy(&thermal_cdev_idr);
> > +	mutex_destroy(&thermal_idr_lock);
> > +	mutex_destroy(&thermal_list_lock);
> > +	genetlink_exit();
> > +}
> > +
> > +fs_initcall(thermal_init);
> > +module_exit(thermal_exit);
> > diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
> > deleted file mode 100644
> > index 5b7863a..0000000
> > --- a/drivers/thermal/thermal_sys.c
> > +++ /dev/null
> > @@ -1,1888 +0,0 @@
> > -/*
> > - *  thermal.c - Generic Thermal Management Sysfs support.
> > - *
> > - *  Copyright (C) 2008 Intel Corp
> > - *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> > - *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> > - *
> > - *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > - *
> > - *  This program is free software; you can redistribute it and/or modify
> > - *  it under the terms of the GNU General Public License as published by
> > - *  the Free Software Foundation; version 2 of the License.
> > - *
> > - *  This program is distributed in the hope that it will be useful, but
> > - *  WITHOUT ANY WARRANTY; without even the implied warranty of
> > - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > - *  General Public License for more details.
> > - *
> > - *  You should have received a copy of the GNU General Public License along
> > - *  with this program; if not, write to the Free Software Foundation, Inc.,
> > - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> > - *
> > - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > - */
> > -
> > -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> > -
> > -#include <linux/module.h>
> > -#include <linux/device.h>
> > -#include <linux/err.h>
> > -#include <linux/slab.h>
> > -#include <linux/kdev_t.h>
> > -#include <linux/idr.h>
> > -#include <linux/thermal.h>
> > -#include <linux/reboot.h>
> > -#include <net/netlink.h>
> > -#include <net/genetlink.h>
> > -
> > -#include "thermal_core.h"
> > -
> > -MODULE_AUTHOR("Zhang Rui");
> > -MODULE_DESCRIPTION("Generic thermal management sysfs support");
> > -MODULE_LICENSE("GPL");
> > -
> > -static DEFINE_IDR(thermal_tz_idr);
> > -static DEFINE_IDR(thermal_cdev_idr);
> > -static DEFINE_MUTEX(thermal_idr_lock);
> > -
> > -static LIST_HEAD(thermal_tz_list);
> > -static LIST_HEAD(thermal_cdev_list);
> > -static LIST_HEAD(thermal_governor_list);
> > -
> > -static DEFINE_MUTEX(thermal_list_lock);
> > -static DEFINE_MUTEX(thermal_governor_lock);
> > -
> > -static struct thermal_governor *__find_governor(const char *name)
> > -{
> > -	struct thermal_governor *pos;
> > -
> > -	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> > -		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> > -			return pos;
> > -
> > -	return NULL;
> > -}
> > -
> > -int thermal_register_governor(struct thermal_governor *governor)
> > -{
> > -	int err;
> > -	const char *name;
> > -	struct thermal_zone_device *pos;
> > -
> > -	if (!governor)
> > -		return -EINVAL;
> > -
> > -	mutex_lock(&thermal_governor_lock);
> > -
> > -	err = -EBUSY;
> > -	if (__find_governor(governor->name) == NULL) {
> > -		err = 0;
> > -		list_add(&governor->governor_list, &thermal_governor_list);
> > -	}
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -
> > -	list_for_each_entry(pos, &thermal_tz_list, node) {
> > -		if (pos->governor)
> > -			continue;
> > -		if (pos->tzp)
> > -			name = pos->tzp->governor_name;
> > -		else
> > -			name = DEFAULT_THERMAL_GOVERNOR;
> > -		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
> > -			pos->governor = governor;
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -	mutex_unlock(&thermal_governor_lock);
> > -
> > -	return err;
> > -}
> > -EXPORT_SYMBOL_GPL(thermal_register_governor);
> > -
> > -void thermal_unregister_governor(struct thermal_governor *governor)
> > -{
> > -	struct thermal_zone_device *pos;
> > -
> > -	if (!governor)
> > -		return;
> > -
> > -	mutex_lock(&thermal_governor_lock);
> > -
> > -	if (__find_governor(governor->name) == NULL)
> > -		goto exit;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -
> > -	list_for_each_entry(pos, &thermal_tz_list, node) {
> > -		if (!strnicmp(pos->governor->name, governor->name,
> > -						THERMAL_NAME_LENGTH))
> > -			pos->governor = NULL;
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -	list_del(&governor->governor_list);
> > -exit:
> > -	mutex_unlock(&thermal_governor_lock);
> > -	return;
> > -}
> > -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> > -
> > -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> > -{
> > -	int ret;
> > -
> > -	if (lock)
> > -		mutex_lock(lock);
> > -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> > -	if (lock)
> > -		mutex_unlock(lock);
> > -	if (unlikely(ret < 0))
> > -		return ret;
> > -	*id = ret;
> > -	return 0;
> > -}
> > -
> > -static void release_idr(struct idr *idr, struct mutex *lock, int id)
> > -{
> > -	if (lock)
> > -		mutex_lock(lock);
> > -	idr_remove(idr, id);
> > -	if (lock)
> > -		mutex_unlock(lock);
> > -}
> > -
> > -int get_tz_trend(struct thermal_zone_device *tz, int trip)
> > -{
> > -	enum thermal_trend trend;
> > -
> > -	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> > -		if (tz->temperature > tz->last_temperature)
> > -			trend = THERMAL_TREND_RAISING;
> > -		else if (tz->temperature < tz->last_temperature)
> > -			trend = THERMAL_TREND_DROPPING;
> > -		else
> > -			trend = THERMAL_TREND_STABLE;
> > -	}
> > -
> > -	return trend;
> > -}
> > -EXPORT_SYMBOL(get_tz_trend);
> > -
> > -struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
> > -			struct thermal_cooling_device *cdev, int trip)
> > -{
> > -	struct thermal_instance *pos = NULL;
> > -	struct thermal_instance *target_instance = NULL;
> > -
> > -	mutex_lock(&tz->lock);
> > -	mutex_lock(&cdev->lock);
> > -
> > -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> > -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > -			target_instance = pos;
> > -			break;
> > -		}
> > -	}
> > -
> > -	mutex_unlock(&cdev->lock);
> > -	mutex_unlock(&tz->lock);
> > -
> > -	return target_instance;
> > -}
> > -EXPORT_SYMBOL(get_thermal_instance);
> > -
> > -static void print_bind_err_msg(struct thermal_zone_device *tz,
> > -			struct thermal_cooling_device *cdev, int ret)
> > -{
> > -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> > -				tz->type, cdev->type, ret);
> > -}
> > -
> > -static void __bind(struct thermal_zone_device *tz, int mask,
> > -			struct thermal_cooling_device *cdev)
> > -{
> > -	int i, ret;
> > -
> > -	for (i = 0; i < tz->trips; i++) {
> > -		if (mask & (1 << i)) {
> > -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> > -					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
> > -			if (ret)
> > -				print_bind_err_msg(tz, cdev, ret);
> > -		}
> > -	}
> > -}
> > -
> > -static void __unbind(struct thermal_zone_device *tz, int mask,
> > -			struct thermal_cooling_device *cdev)
> > -{
> > -	int i;
> > -
> > -	for (i = 0; i < tz->trips; i++)
> > -		if (mask & (1 << i))
> > -			thermal_zone_unbind_cooling_device(tz, i, cdev);
> > -}
> > -
> > -static void bind_cdev(struct thermal_cooling_device *cdev)
> > -{
> > -	int i, ret;
> > -	const struct thermal_zone_params *tzp;
> > -	struct thermal_zone_device *pos = NULL;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -
> > -	list_for_each_entry(pos, &thermal_tz_list, node) {
> > -		if (!pos->tzp && !pos->ops->bind)
> > -			continue;
> > -
> > -		if (!pos->tzp && pos->ops->bind) {
> > -			ret = pos->ops->bind(pos, cdev);
> > -			if (ret)
> > -				print_bind_err_msg(pos, cdev, ret);
> > -		}
> > -
> > -		tzp = pos->tzp;
> > -		if (!tzp || !tzp->tbp)
> > -			continue;
> > -
> > -		for (i = 0; i < tzp->num_tbps; i++) {
> > -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> > -				continue;
> > -			if (tzp->tbp[i].match(pos, cdev))
> > -				continue;
> > -			tzp->tbp[i].cdev = cdev;
> > -			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> > -		}
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -}
> > -
> > -static void bind_tz(struct thermal_zone_device *tz)
> > -{
> > -	int i, ret;
> > -	struct thermal_cooling_device *pos = NULL;
> > -	const struct thermal_zone_params *tzp = tz->tzp;
> > -
> > -	if (!tzp && !tz->ops->bind)
> > -		return;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -
> > -	/* If there is no platform data, try to use ops->bind */
> > -	if (!tzp && tz->ops->bind) {
> > -		list_for_each_entry(pos, &thermal_cdev_list, node) {
> > -			ret = tz->ops->bind(tz, pos);
> > -			if (ret)
> > -				print_bind_err_msg(tz, pos, ret);
> > -		}
> > -		goto exit;
> > -	}
> > -
> > -	if (!tzp || !tzp->tbp)
> > -		goto exit;
> > -
> > -	list_for_each_entry(pos, &thermal_cdev_list, node) {
> > -		for (i = 0; i < tzp->num_tbps; i++) {
> > -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> > -				continue;
> > -			if (tzp->tbp[i].match(tz, pos))
> > -				continue;
> > -			tzp->tbp[i].cdev = pos;
> > -			__bind(tz, tzp->tbp[i].trip_mask, pos);
> > -		}
> > -	}
> > -exit:
> > -	mutex_unlock(&thermal_list_lock);
> > -}
> > -
> > -static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
> > -					    int delay)
> > -{
> > -	if (delay > 1000)
> > -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> > -				 round_jiffies(msecs_to_jiffies(delay)));
> > -	else if (delay)
> > -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
> > -				 msecs_to_jiffies(delay));
> > -	else
> > -		cancel_delayed_work(&tz->poll_queue);
> > -}
> > -
> > -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);
> > -	else if (tz->polling_delay)
> > -		thermal_zone_device_set_polling(tz, tz->polling_delay);
> > -	else
> > -		thermal_zone_device_set_polling(tz, 0);
> > -
> > -	mutex_unlock(&tz->lock);
> > -}
> > -
> > -static void handle_non_critical_trips(struct thermal_zone_device *tz,
> > -			int trip, enum thermal_trip_type trip_type)
> > -{
> > -	if (tz->governor)
> > -		tz->governor->throttle(tz, trip);
> > -}
> > -
> > -static void handle_critical_trips(struct thermal_zone_device *tz,
> > -				int trip, enum thermal_trip_type trip_type)
> > -{
> > -	long trip_temp;
> > -
> > -	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> > -
> > -	/* If we have not crossed the trip_temp, we do not care. */
> > -	if (tz->temperature < trip_temp)
> > -		return;
> > -
> > -	if (tz->ops->notify)
> > -		tz->ops->notify(tz, trip, trip_type);
> > -
> > -	if (trip_type == THERMAL_TRIP_CRITICAL) {
> > -		dev_emerg(&tz->device,
> > -			  "critical temperature reached(%d C),shutting down\n",
> > -			  tz->temperature / 1000);
> > -		orderly_poweroff(true);
> > -	}
> > -}
> > -
> > -static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
> > -{
> > -	enum thermal_trip_type type;
> > -
> > -	tz->ops->get_trip_type(tz, trip, &type);
> > -
> > -	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
> > -		handle_critical_trips(tz, trip, type);
> > -	else
> > -		handle_non_critical_trips(tz, trip, type);
> > -	/*
> > -	 * Alright, we handled this trip successfully.
> > -	 * So, start monitoring again.
> > -	 */
> > -	monitor_thermal_zone(tz);
> > -}
> > -
> > -static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> > -				unsigned long *temp)
> > -{
> > -	int ret = 0;
> > -#ifdef CONFIG_THERMAL_EMULATION
> > -	int count;
> > -	unsigned long crit_temp = -1UL;
> > -	enum thermal_trip_type type;
> > -#endif
> > -
> > -	mutex_lock(&tz->lock);
> > -
> > -	ret = tz->ops->get_temp(tz, temp);
> > -#ifdef CONFIG_THERMAL_EMULATION
> > -	if (!tz->emul_temperature)
> > -		goto skip_emul;
> > -
> > -	for (count = 0; count < tz->trips; count++) {
> > -		ret = tz->ops->get_trip_type(tz, count, &type);
> > -		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> > -			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> > -			break;
> > -		}
> > -	}
> > -
> > -	if (ret)
> > -		goto skip_emul;
> > -
> > -	if (*temp < crit_temp)
> > -		*temp = tz->emul_temperature;
> > -skip_emul:
> > -#endif
> > -	mutex_unlock(&tz->lock);
> > -	return ret;
> > -}
> > -
> > -static void update_temperature(struct thermal_zone_device *tz)
> > -{
> > -	long temp;
> > -	int ret;
> > -
> > -	ret = thermal_zone_get_temp(tz, &temp);
> > -	if (ret) {
> > -		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
> > -			 tz->id);
> > -		return;
> > -	}
> > -
> > -	mutex_lock(&tz->lock);
> > -	tz->last_temperature = tz->temperature;
> > -	tz->temperature = temp;
> > -	mutex_unlock(&tz->lock);
> > -}
> > -
> > -void thermal_zone_device_update(struct thermal_zone_device *tz)
> > -{
> > -	int count;
> > -
> > -	update_temperature(tz);
> > -
> > -	for (count = 0; count < tz->trips; count++)
> > -		handle_thermal_trip(tz, count);
> > -}
> > -EXPORT_SYMBOL(thermal_zone_device_update);
> > -
> > -static void thermal_zone_device_check(struct work_struct *work)
> > -{
> > -	struct thermal_zone_device *tz = container_of(work, struct
> > -						      thermal_zone_device,
> > -						      poll_queue.work);
> > -	thermal_zone_device_update(tz);
> > -}
> > -
> > -/* sys I/F for thermal zone */
> > -
> > -#define to_thermal_zone(_dev) \
> > -	container_of(_dev, struct thermal_zone_device, device)
> > -
> > -static ssize_t
> > -type_show(struct device *dev, struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -
> > -	return sprintf(buf, "%s\n", tz->type);
> > -}
> > -
> > -static ssize_t
> > -temp_show(struct device *dev, struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	long temperature;
> > -	int ret;
> > -
> > -	ret = thermal_zone_get_temp(tz, &temperature);
> > -
> > -	if (ret)
> > -		return ret;
> > -
> > -	return sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -static ssize_t
> > -mode_show(struct device *dev, struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	enum thermal_device_mode mode;
> > -	int result;
> > -
> > -	if (!tz->ops->get_mode)
> > -		return -EPERM;
> > -
> > -	result = tz->ops->get_mode(tz, &mode);
> > -	if (result)
> > -		return result;
> > -
> > -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
> > -		       : "disabled");
> > -}
> > -
> > -static ssize_t
> > -mode_store(struct device *dev, struct device_attribute *attr,
> > -	   const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int result;
> > -
> > -	if (!tz->ops->set_mode)
> > -		return -EPERM;
> > -
> > -	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);
> > -	else
> > -		result = -EINVAL;
> > -
> > -	if (result)
> > -		return result;
> > -
> > -	return count;
> > -}
> > -
> > -static ssize_t
> > -trip_point_type_show(struct device *dev, struct device_attribute *attr,
> > -		     char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	enum thermal_trip_type type;
> > -	int trip, result;
> > -
> > -	if (!tz->ops->get_trip_type)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> > -		return -EINVAL;
> > -
> > -	result = tz->ops->get_trip_type(tz, trip, &type);
> > -	if (result)
> > -		return result;
> > -
> > -	switch (type) {
> > -	case THERMAL_TRIP_CRITICAL:
> > -		return sprintf(buf, "critical\n");
> > -	case THERMAL_TRIP_HOT:
> > -		return sprintf(buf, "hot\n");
> > -	case THERMAL_TRIP_PASSIVE:
> > -		return sprintf(buf, "passive\n");
> > -	case THERMAL_TRIP_ACTIVE:
> > -		return sprintf(buf, "active\n");
> > -	default:
> > -		return sprintf(buf, "unknown\n");
> > -	}
> > -}
> > -
> > -static ssize_t
> > -trip_point_temp_store(struct device *dev, struct device_attribute *attr,
> > -		     const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int trip, ret;
> > -	unsigned long temperature;
> > -
> > -	if (!tz->ops->set_trip_temp)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> > -		return -EINVAL;
> > -
> > -	if (kstrtoul(buf, 10, &temperature))
> > -		return -EINVAL;
> > -
> > -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> > -
> > -	return ret ? ret : count;
> > -}
> > -
> > -static ssize_t
> > -trip_point_temp_show(struct device *dev, struct device_attribute *attr,
> > -		     char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int trip, ret;
> > -	long temperature;
> > -
> > -	if (!tz->ops->get_trip_temp)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> > -		return -EINVAL;
> > -
> > -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> > -
> > -	if (ret)
> > -		return ret;
> > -
> > -	return sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -static ssize_t
> > -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> > -			const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int trip, ret;
> > -	unsigned long temperature;
> > -
> > -	if (!tz->ops->set_trip_hyst)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> > -		return -EINVAL;
> > -
> > -	if (kstrtoul(buf, 10, &temperature))
> > -		return -EINVAL;
> > -
> > -	/*
> > -	 * We are not doing any check on the 'temperature' value
> > -	 * here. The driver implementing 'set_trip_hyst' has to
> > -	 * take care of this.
> > -	 */
> > -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> > -
> > -	return ret ? ret : count;
> > -}
> > -
> > -static ssize_t
> > -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> > -			char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int trip, ret;
> > -	unsigned long temperature;
> > -
> > -	if (!tz->ops->get_trip_hyst)
> > -		return -EPERM;
> > -
> > -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> > -		return -EINVAL;
> > -
> > -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> > -
> > -	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -static ssize_t
> > -passive_store(struct device *dev, struct device_attribute *attr,
> > -		    const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	struct thermal_cooling_device *cdev = NULL;
> > -	int state;
> > -
> > -	if (!sscanf(buf, "%d\n", &state))
> > -		return -EINVAL;
> > -
> > -	/* sanity check: values below 1000 millicelcius don't make sense
> > -	 * and can cause the system to go into a thermal heart attack
> > -	 */
> > -	if (state && state < 1000)
> > -		return -EINVAL;
> > -
> > -	if (state && !tz->forced_passive) {
> > -		mutex_lock(&thermal_list_lock);
> > -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > -			if (!strncmp("Processor", cdev->type,
> > -				     sizeof("Processor")))
> > -				thermal_zone_bind_cooling_device(tz,
> > -						THERMAL_TRIPS_NONE, cdev,
> > -						THERMAL_NO_LIMIT,
> > -						THERMAL_NO_LIMIT);
> > -		}
> > -		mutex_unlock(&thermal_list_lock);
> > -		if (!tz->passive_delay)
> > -			tz->passive_delay = 1000;
> > -	} else if (!state && tz->forced_passive) {
> > -		mutex_lock(&thermal_list_lock);
> > -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > -			if (!strncmp("Processor", cdev->type,
> > -				     sizeof("Processor")))
> > -				thermal_zone_unbind_cooling_device(tz,
> > -								   THERMAL_TRIPS_NONE,
> > -								   cdev);
> > -		}
> > -		mutex_unlock(&thermal_list_lock);
> > -		tz->passive_delay = 0;
> > -	}
> > -
> > -	tz->forced_passive = state;
> > -
> > -	thermal_zone_device_update(tz);
> > -
> > -	return count;
> > -}
> > -
> > -static ssize_t
> > -passive_show(struct device *dev, struct device_attribute *attr,
> > -		   char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -
> > -	return sprintf(buf, "%d\n", tz->forced_passive);
> > -}
> > -
> > -static ssize_t
> > -policy_store(struct device *dev, struct device_attribute *attr,
> > -		    const char *buf, size_t count)
> > -{
> > -	int ret = -EINVAL;
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	struct thermal_governor *gov;
> > -
> > -	mutex_lock(&thermal_governor_lock);
> > -
> > -	gov = __find_governor(buf);
> > -	if (!gov)
> > -		goto exit;
> > -
> > -	tz->governor = gov;
> > -	ret = count;
> > -
> > -exit:
> > -	mutex_unlock(&thermal_governor_lock);
> > -	return ret;
> > -}
> > -
> > -static ssize_t
> > -policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -
> > -	return sprintf(buf, "%s\n", tz->governor->name);
> > -}
> > -
> > -#ifdef CONFIG_THERMAL_EMULATION
> > -static ssize_t
> > -emul_temp_store(struct device *dev, struct device_attribute *attr,
> > -		     const char *buf, size_t count)
> > -{
> > -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> > -	int ret = 0;
> > -	unsigned long temperature;
> > -
> > -	if (kstrtoul(buf, 10, &temperature))
> > -		return -EINVAL;
> > -
> > -	if (!tz->ops->set_emul_temp) {
> > -		mutex_lock(&tz->lock);
> > -		tz->emul_temperature = temperature;
> > -		mutex_unlock(&tz->lock);
> > -	} else {
> > -		ret = tz->ops->set_emul_temp(tz, temperature);
> > -	}
> > -
> > -	return ret ? ret : count;
> > -}
> > -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> > -#endif/*CONFIG_THERMAL_EMULATION*/
> > -
> > -static DEVICE_ATTR(type, 0444, type_show, NULL);
> > -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> > -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> > -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
> > -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
> > -
> > -/* sys I/F for cooling device */
> > -#define to_cooling_device(_dev)	\
> > -	container_of(_dev, struct thermal_cooling_device, device)
> > -
> > -static ssize_t
> > -thermal_cooling_device_type_show(struct device *dev,
> > -				 struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > -
> > -	return sprintf(buf, "%s\n", cdev->type);
> > -}
> > -
> > -static ssize_t
> > -thermal_cooling_device_max_state_show(struct device *dev,
> > -				      struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > -	unsigned long state;
> > -	int ret;
> > -
> > -	ret = cdev->ops->get_max_state(cdev, &state);
> > -	if (ret)
> > -		return ret;
> > -	return sprintf(buf, "%ld\n", state);
> > -}
> > -
> > -static ssize_t
> > -thermal_cooling_device_cur_state_show(struct device *dev,
> > -				      struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > -	unsigned long state;
> > -	int ret;
> > -
> > -	ret = cdev->ops->get_cur_state(cdev, &state);
> > -	if (ret)
> > -		return ret;
> > -	return sprintf(buf, "%ld\n", state);
> > -}
> > -
> > -static ssize_t
> > -thermal_cooling_device_cur_state_store(struct device *dev,
> > -				       struct device_attribute *attr,
> > -				       const char *buf, size_t count)
> > -{
> > -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> > -	unsigned long state;
> > -	int result;
> > -
> > -	if (!sscanf(buf, "%ld\n", &state))
> > -		return -EINVAL;
> > -
> > -	if ((long)state < 0)
> > -		return -EINVAL;
> > -
> > -	result = cdev->ops->set_cur_state(cdev, state);
> > -	if (result)
> > -		return result;
> > -	return count;
> > -}
> > -
> > -static struct device_attribute dev_attr_cdev_type =
> > -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> > -static DEVICE_ATTR(max_state, 0444,
> > -		   thermal_cooling_device_max_state_show, NULL);
> > -static DEVICE_ATTR(cur_state, 0644,
> > -		   thermal_cooling_device_cur_state_show,
> > -		   thermal_cooling_device_cur_state_store);
> > -
> > -static ssize_t
> > -thermal_cooling_device_trip_point_show(struct device *dev,
> > -				       struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_instance *instance;
> > -
> > -	instance =
> > -	    container_of(attr, struct thermal_instance, attr);
> > -
> > -	if (instance->trip == THERMAL_TRIPS_NONE)
> > -		return sprintf(buf, "-1\n");
> > -	else
> > -		return sprintf(buf, "%d\n", instance->trip);
> > -}
> > -
> > -/* Device management */
> > -
> > -#if defined(CONFIG_THERMAL_HWMON)
> > -
> > -/* hwmon sys I/F */
> > -#include <linux/hwmon.h>
> > -
> > -/* thermal zone devices with the same type share one hwmon device */
> > -struct thermal_hwmon_device {
> > -	char type[THERMAL_NAME_LENGTH];
> > -	struct device *device;
> > -	int count;
> > -	struct list_head tz_list;
> > -	struct list_head node;
> > -};
> > -
> > -struct thermal_hwmon_attr {
> > -	struct device_attribute attr;
> > -	char name[16];
> > -};
> > -
> > -/* one temperature input for each thermal zone */
> > -struct thermal_hwmon_temp {
> > -	struct list_head hwmon_node;
> > -	struct thermal_zone_device *tz;
> > -	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> > -	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> > -};
> > -
> > -static LIST_HEAD(thermal_hwmon_list);
> > -
> > -static ssize_t
> > -name_show(struct device *dev, struct device_attribute *attr, char *buf)
> > -{
> > -	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> > -	return sprintf(buf, "%s\n", hwmon->type);
> > -}
> > -static DEVICE_ATTR(name, 0444, name_show, NULL);
> > -
> > -static ssize_t
> > -temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
> > -{
> > -	long temperature;
> > -	int ret;
> > -	struct thermal_hwmon_attr *hwmon_attr
> > -			= container_of(attr, struct thermal_hwmon_attr, attr);
> > -	struct thermal_hwmon_temp *temp
> > -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> > -				       temp_input);
> > -	struct thermal_zone_device *tz = temp->tz;
> > -
> > -	ret = thermal_zone_get_temp(tz, &temperature);
> > -
> > -	if (ret)
> > -		return ret;
> > -
> > -	return sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -static ssize_t
> > -temp_crit_show(struct device *dev, struct device_attribute *attr,
> > -		char *buf)
> > -{
> > -	struct thermal_hwmon_attr *hwmon_attr
> > -			= container_of(attr, struct thermal_hwmon_attr, attr);
> > -	struct thermal_hwmon_temp *temp
> > -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
> > -				       temp_crit);
> > -	struct thermal_zone_device *tz = temp->tz;
> > -	long temperature;
> > -	int ret;
> > -
> > -	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> > -	if (ret)
> > -		return ret;
> > -
> > -	return sprintf(buf, "%ld\n", temperature);
> > -}
> > -
> > -
> > -static struct thermal_hwmon_device *
> > -thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
> > -{
> > -	struct thermal_hwmon_device *hwmon;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> > -		if (!strcmp(hwmon->type, tz->type)) {
> > -			mutex_unlock(&thermal_list_lock);
> > -			return hwmon;
> > -		}
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	return NULL;
> > -}
> > -
> > -/* Find the temperature input matching a given thermal zone */
> > -static struct thermal_hwmon_temp *
> > -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
> > -			  const struct thermal_zone_device *tz)
> > -{
> > -	struct thermal_hwmon_temp *temp;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> > -		if (temp->tz == tz) {
> > -			mutex_unlock(&thermal_list_lock);
> > -			return temp;
> > -		}
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	return NULL;
> > -}
> > -
> > -static int
> > -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> > -{
> > -	struct thermal_hwmon_device *hwmon;
> > -	struct thermal_hwmon_temp *temp;
> > -	int new_hwmon_device = 1;
> > -	int result;
> > -
> > -	hwmon = thermal_hwmon_lookup_by_type(tz);
> > -	if (hwmon) {
> > -		new_hwmon_device = 0;
> > -		goto register_sys_interface;
> > -	}
> > -
> > -	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
> > -	if (!hwmon)
> > -		return -ENOMEM;
> > -
> > -	INIT_LIST_HEAD(&hwmon->tz_list);
> > -	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> > -	hwmon->device = hwmon_device_register(NULL);
> > -	if (IS_ERR(hwmon->device)) {
> > -		result = PTR_ERR(hwmon->device);
> > -		goto free_mem;
> > -	}
> > -	dev_set_drvdata(hwmon->device, hwmon);
> > -	result = device_create_file(hwmon->device, &dev_attr_name);
> > -	if (result)
> > -		goto free_mem;
> > -
> > - register_sys_interface:
> > -	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> > -	if (!temp) {
> > -		result = -ENOMEM;
> > -		goto unregister_name;
> > -	}
> > -
> > -	temp->tz = tz;
> > -	hwmon->count++;
> > -
> > -	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
> > -		 "temp%d_input", hwmon->count);
> > -	temp->temp_input.attr.attr.name = temp->temp_input.name;
> > -	temp->temp_input.attr.attr.mode = 0444;
> > -	temp->temp_input.attr.show = temp_input_show;
> > -	sysfs_attr_init(&temp->temp_input.attr.attr);
> > -	result = device_create_file(hwmon->device, &temp->temp_input.attr);
> > -	if (result)
> > -		goto free_temp_mem;
> > -
> > -	if (tz->ops->get_crit_temp) {
> > -		unsigned long temperature;
> > -		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> > -			snprintf(temp->temp_crit.name,
> > -				 sizeof(temp->temp_crit.name),
> > -				"temp%d_crit", hwmon->count);
> > -			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
> > -			temp->temp_crit.attr.attr.mode = 0444;
> > -			temp->temp_crit.attr.show = temp_crit_show;
> > -			sysfs_attr_init(&temp->temp_crit.attr.attr);
> > -			result = device_create_file(hwmon->device,
> > -						    &temp->temp_crit.attr);
> > -			if (result)
> > -				goto unregister_input;
> > -		}
> > -	}
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	if (new_hwmon_device)
> > -		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> > -	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	return 0;
> > -
> > - unregister_input:
> > -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> > - free_temp_mem:
> > -	kfree(temp);
> > - unregister_name:
> > -	if (new_hwmon_device) {
> > -		device_remove_file(hwmon->device, &dev_attr_name);
> > -		hwmon_device_unregister(hwmon->device);
> > -	}
> > - free_mem:
> > -	if (new_hwmon_device)
> > -		kfree(hwmon);
> > -
> > -	return result;
> > -}
> > -
> > -static void
> > -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> > -{
> > -	struct thermal_hwmon_device *hwmon;
> > -	struct thermal_hwmon_temp *temp;
> > -
> > -	hwmon = thermal_hwmon_lookup_by_type(tz);
> > -	if (unlikely(!hwmon)) {
> > -		/* Should never happen... */
> > -		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> > -		return;
> > -	}
> > -
> > -	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> > -	if (unlikely(!temp)) {
> > -		/* Should never happen... */
> > -		dev_dbg(&tz->device, "temperature input lookup failed!\n");
> > -		return;
> > -	}
> > -
> > -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> > -	if (tz->ops->get_crit_temp)
> > -		device_remove_file(hwmon->device, &temp->temp_crit.attr);
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_del(&temp->hwmon_node);
> > -	kfree(temp);
> > -	if (!list_empty(&hwmon->tz_list)) {
> > -		mutex_unlock(&thermal_list_lock);
> > -		return;
> > -	}
> > -	list_del(&hwmon->node);
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	device_remove_file(hwmon->device, &dev_attr_name);
> > -	hwmon_device_unregister(hwmon->device);
> > -	kfree(hwmon);
> > -}
> > -#else
> > -static int
> > -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> > -{
> > -	return 0;
> > -}
> > -
> > -static void
> > -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> > -{
> > -}
> > -#endif
> > -
> > -/**
> > - * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
> > - * @tz:		thermal zone device
> > - * @trip:	indicates which trip point the cooling devices is
> > - *		associated with in this thermal zone.
> > - * @cdev:	thermal cooling device
> > - *
> > - * This function is usually called in the thermal zone device .bind callback.
> > - */
> > -int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
> > -				     int trip,
> > -				     struct thermal_cooling_device *cdev,
> > -				     unsigned long upper, unsigned long lower)
> > -{
> > -	struct thermal_instance *dev;
> > -	struct thermal_instance *pos;
> > -	struct thermal_zone_device *pos1;
> > -	struct thermal_cooling_device *pos2;
> > -	unsigned long max_state;
> > -	int result;
> > -
> > -	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> > -		return -EINVAL;
> > -
> > -	list_for_each_entry(pos1, &thermal_tz_list, node) {
> > -		if (pos1 == tz)
> > -			break;
> > -	}
> > -	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> > -		if (pos2 == cdev)
> > -			break;
> > -	}
> > -
> > -	if (tz != pos1 || cdev != pos2)
> > -		return -EINVAL;
> > -
> > -	cdev->ops->get_max_state(cdev, &max_state);
> > -
> > -	/* lower default 0, upper default max_state */
> > -	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> > -	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> > -
> > -	if (lower > upper || upper > max_state)
> > -		return -EINVAL;
> > -
> > -	dev =
> > -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> > -	if (!dev)
> > -		return -ENOMEM;
> > -	dev->tz = tz;
> > -	dev->cdev = cdev;
> > -	dev->trip = trip;
> > -	dev->upper = upper;
> > -	dev->lower = lower;
> > -	dev->target = THERMAL_NO_TARGET;
> > -
> > -	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> > -	if (result)
> > -		goto free_mem;
> > -
> > -	sprintf(dev->name, "cdev%d", dev->id);
> > -	result =
> > -	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
> > -	if (result)
> > -		goto release_idr;
> > -
> > -	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> > -	sysfs_attr_init(&dev->attr.attr);
> > -	dev->attr.attr.name = dev->attr_name;
> > -	dev->attr.attr.mode = 0444;
> > -	dev->attr.show = thermal_cooling_device_trip_point_show;
> > -	result = device_create_file(&tz->device, &dev->attr);
> > -	if (result)
> > -		goto remove_symbol_link;
> > -
> > -	mutex_lock(&tz->lock);
> > -	mutex_lock(&cdev->lock);
> > -	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> > -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > -		result = -EEXIST;
> > -		break;
> > -	}
> > -	if (!result) {
> > -		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> > -		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
> > -	}
> > -	mutex_unlock(&cdev->lock);
> > -	mutex_unlock(&tz->lock);
> > -
> > -	if (!result)
> > -		return 0;
> > -
> > -	device_remove_file(&tz->device, &dev->attr);
> > -remove_symbol_link:
> > -	sysfs_remove_link(&tz->device.kobj, dev->name);
> > -release_idr:
> > -	release_idr(&tz->idr, &tz->lock, dev->id);
> > -free_mem:
> > -	kfree(dev);
> > -	return result;
> > -}
> > -EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> > -
> > -/**
> > - * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
> > - * @tz:		thermal zone device
> > - * @trip:	indicates which trip point the cooling devices is
> > - *		associated with in this thermal zone.
> > - * @cdev:	thermal cooling device
> > - *
> > - * This function is usually called in the thermal zone device .unbind callback.
> > - */
> > -int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
> > -				       int trip,
> > -				       struct thermal_cooling_device *cdev)
> > -{
> > -	struct thermal_instance *pos, *next;
> > -
> > -	mutex_lock(&tz->lock);
> > -	mutex_lock(&cdev->lock);
> > -	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
> > -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> > -			list_del(&pos->tz_node);
> > -			list_del(&pos->cdev_node);
> > -			mutex_unlock(&cdev->lock);
> > -			mutex_unlock(&tz->lock);
> > -			goto unbind;
> > -		}
> > -	}
> > -	mutex_unlock(&cdev->lock);
> > -	mutex_unlock(&tz->lock);
> > -
> > -	return -ENODEV;
> > -
> > -unbind:
> > -	device_remove_file(&tz->device, &pos->attr);
> > -	sysfs_remove_link(&tz->device.kobj, pos->name);
> > -	release_idr(&tz->idr, &tz->lock, pos->id);
> > -	kfree(pos);
> > -	return 0;
> > -}
> > -EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> > -
> > -static void thermal_release(struct device *dev)
> > -{
> > -	struct thermal_zone_device *tz;
> > -	struct thermal_cooling_device *cdev;
> > -
> > -	if (!strncmp(dev_name(dev), "thermal_zone",
> > -		     sizeof("thermal_zone") - 1)) {
> > -		tz = to_thermal_zone(dev);
> > -		kfree(tz);
> > -	} else {
> > -		cdev = to_cooling_device(dev);
> > -		kfree(cdev);
> > -	}
> > -}
> > -
> > -static struct class thermal_class = {
> > -	.name = "thermal",
> > -	.dev_release = thermal_release,
> > -};
> > -
> > -/**
> > - * thermal_cooling_device_register - register a new thermal cooling device
> > - * @type:	the thermal cooling device type.
> > - * @devdata:	device private data.
> > - * @ops:		standard thermal cooling devices callbacks.
> > - */
> > -struct thermal_cooling_device *
> > -thermal_cooling_device_register(char *type, void *devdata,
> > -				const struct thermal_cooling_device_ops *ops)
> > -{
> > -	struct thermal_cooling_device *cdev;
> > -	int result;
> > -
> > -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> > -	    !ops->set_cur_state)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> > -	if (!cdev)
> > -		return ERR_PTR(-ENOMEM);
> > -
> > -	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> > -	if (result) {
> > -		kfree(cdev);
> > -		return ERR_PTR(result);
> > -	}
> > -
> > -	strcpy(cdev->type, type ? : "");
> > -	mutex_init(&cdev->lock);
> > -	INIT_LIST_HEAD(&cdev->thermal_instances);
> > -	cdev->ops = ops;
> > -	cdev->updated = true;
> > -	cdev->device.class = &thermal_class;
> > -	cdev->devdata = devdata;
> > -	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> > -	result = device_register(&cdev->device);
> > -	if (result) {
> > -		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > -		kfree(cdev);
> > -		return ERR_PTR(result);
> > -	}
> > -
> > -	/* sys I/F */
> > -	if (type) {
> > -		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
> > -		if (result)
> > -			goto unregister;
> > -	}
> > -
> > -	result = device_create_file(&cdev->device, &dev_attr_max_state);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	/* Add 'this' new cdev to the global cdev list */
> > -	mutex_lock(&thermal_list_lock);
> > -	list_add(&cdev->node, &thermal_cdev_list);
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	/* Update binding information for 'this' new cdev */
> > -	bind_cdev(cdev);
> > -
> > -	return cdev;
> > -
> > -unregister:
> > -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > -	device_unregister(&cdev->device);
> > -	return ERR_PTR(result);
> > -}
> > -EXPORT_SYMBOL(thermal_cooling_device_register);
> > -
> > -/**
> > - * thermal_cooling_device_unregister - removes the registered thermal cooling device
> > - * @cdev:	the thermal cooling device to remove.
> > - *
> > - * thermal_cooling_device_unregister() must be called when the device is no
> > - * longer needed.
> > - */
> > -void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
> > -{
> > -	int i;
> > -	const struct thermal_zone_params *tzp;
> > -	struct thermal_zone_device *tz;
> > -	struct thermal_cooling_device *pos = NULL;
> > -
> > -	if (!cdev)
> > -		return;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_for_each_entry(pos, &thermal_cdev_list, node)
> > -	    if (pos == cdev)
> > -		break;
> > -	if (pos != cdev) {
> > -		/* thermal cooling device not found */
> > -		mutex_unlock(&thermal_list_lock);
> > -		return;
> > -	}
> > -	list_del(&cdev->node);
> > -
> > -	/* Unbind all thermal zones associated with 'this' cdev */
> > -	list_for_each_entry(tz, &thermal_tz_list, node) {
> > -		if (tz->ops->unbind) {
> > -			tz->ops->unbind(tz, cdev);
> > -			continue;
> > -		}
> > -
> > -		if (!tz->tzp || !tz->tzp->tbp)
> > -			continue;
> > -
> > -		tzp = tz->tzp;
> > -		for (i = 0; i < tzp->num_tbps; i++) {
> > -			if (tzp->tbp[i].cdev == cdev) {
> > -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> > -				tzp->tbp[i].cdev = NULL;
> > -			}
> > -		}
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	if (cdev->type[0])
> > -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> > -	device_remove_file(&cdev->device, &dev_attr_max_state);
> > -	device_remove_file(&cdev->device, &dev_attr_cur_state);
> > -
> > -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> > -	device_unregister(&cdev->device);
> > -	return;
> > -}
> > -EXPORT_SYMBOL(thermal_cooling_device_unregister);
> > -
> > -void thermal_cdev_update(struct thermal_cooling_device *cdev)
> > -{
> > -	struct thermal_instance *instance;
> > -	unsigned long target = 0;
> > -
> > -	/* cooling device is updated*/
> > -	if (cdev->updated)
> > -		return;
> > -
> > -	mutex_lock(&cdev->lock);
> > -	/* Make sure cdev enters the deepest cooling state */
> > -	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
> > -		if (instance->target == THERMAL_NO_TARGET)
> > -			continue;
> > -		if (instance->target > target)
> > -			target = instance->target;
> > -	}
> > -	mutex_unlock(&cdev->lock);
> > -	cdev->ops->set_cur_state(cdev, target);
> > -	cdev->updated = true;
> > -}
> > -EXPORT_SYMBOL(thermal_cdev_update);
> > -
> > -/**
> > - * notify_thermal_framework - Sensor drivers use this API to notify framework
> > - * @tz:		thermal zone device
> > - * @trip:	indicates which trip point has been crossed
> > - *
> > - * This function handles the trip events from sensor drivers. It starts
> > - * throttling the cooling devices according to the policy configured.
> > - * For CRITICAL and HOT trip points, this notifies the respective drivers,
> > - * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
> > - * The throttling policy is based on the configured platform data; if no
> > - * platform data is provided, this uses the step_wise throttling policy.
> > - */
> > -void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
> > -{
> > -	handle_thermal_trip(tz, trip);
> > -}
> > -EXPORT_SYMBOL(notify_thermal_framework);
> > -
> > -/**
> > - * create_trip_attrs - create attributes for trip points
> > - * @tz:		the thermal zone device
> > - * @mask:	Writeable trip point bitmap.
> > - */
> > -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> > -{
> > -	int indx;
> > -	int size = sizeof(struct thermal_attr) * tz->trips;
> > -
> > -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> > -	if (!tz->trip_type_attrs)
> > -		return -ENOMEM;
> > -
> > -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> > -	if (!tz->trip_temp_attrs) {
> > -		kfree(tz->trip_type_attrs);
> > -		return -ENOMEM;
> > -	}
> > -
> > -	if (tz->ops->get_trip_hyst) {
> > -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> > -		if (!tz->trip_hyst_attrs) {
> > -			kfree(tz->trip_type_attrs);
> > -			kfree(tz->trip_temp_attrs);
> > -			return -ENOMEM;
> > -		}
> > -	}
> > -
> > -
> > -	for (indx = 0; indx < tz->trips; indx++) {
> > -		/* create trip type attribute */
> > -		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
> > -			 "trip_point_%d_type", indx);
> > -
> > -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> > -		tz->trip_type_attrs[indx].attr.attr.name =
> > -						tz->trip_type_attrs[indx].name;
> > -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> > -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> > -
> > -		device_create_file(&tz->device,
> > -				   &tz->trip_type_attrs[indx].attr);
> > -
> > -		/* create trip temp attribute */
> > -		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
> > -			 "trip_point_%d_temp", indx);
> > -
> > -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> > -		tz->trip_temp_attrs[indx].attr.attr.name =
> > -						tz->trip_temp_attrs[indx].name;
> > -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> > -		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
> > -		if (mask & (1 << indx)) {
> > -			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
> > -			tz->trip_temp_attrs[indx].attr.store =
> > -							trip_point_temp_store;
> > -		}
> > -
> > -		device_create_file(&tz->device,
> > -				   &tz->trip_temp_attrs[indx].attr);
> > -
> > -		/* create Optional trip hyst attribute */
> > -		if (!tz->ops->get_trip_hyst)
> > -			continue;
> > -		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
> > -			 "trip_point_%d_hyst", indx);
> > -
> > -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> > -		tz->trip_hyst_attrs[indx].attr.attr.name =
> > -					tz->trip_hyst_attrs[indx].name;
> > -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> > -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> > -		if (tz->ops->set_trip_hyst) {
> > -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> > -			tz->trip_hyst_attrs[indx].attr.store =
> > -					trip_point_hyst_store;
> > -		}
> > -
> > -		device_create_file(&tz->device,
> > -				   &tz->trip_hyst_attrs[indx].attr);
> > -	}
> > -	return 0;
> > -}
> > -
> > -static void remove_trip_attrs(struct thermal_zone_device *tz)
> > -{
> > -	int indx;
> > -
> > -	for (indx = 0; indx < tz->trips; indx++) {
> > -		device_remove_file(&tz->device,
> > -				   &tz->trip_type_attrs[indx].attr);
> > -		device_remove_file(&tz->device,
> > -				   &tz->trip_temp_attrs[indx].attr);
> > -		if (tz->ops->get_trip_hyst)
> > -			device_remove_file(&tz->device,
> > -				  &tz->trip_hyst_attrs[indx].attr);
> > -	}
> > -	kfree(tz->trip_type_attrs);
> > -	kfree(tz->trip_temp_attrs);
> > -	kfree(tz->trip_hyst_attrs);
> > -}
> > -
> > -/**
> > - * thermal_zone_device_register - register a new thermal zone device
> > - * @type:	the thermal zone device type
> > - * @trips:	the number of trip points the thermal zone support
> > - * @mask:	a bit string indicating the writeablility of trip points
> > - * @devdata:	private device data
> > - * @ops:	standard thermal zone device callbacks
> > - * @tzp:	thermal zone platform parameters
> > - * @passive_delay: number of milliseconds to wait between polls when
> > - *		   performing passive cooling
> > - * @polling_delay: number of milliseconds to wait between polls when checking
> > - *		   whether trip points have been crossed (0 for interrupt
> > - *		   driven systems)
> > - *
> > - * thermal_zone_device_unregister() must be called when the device is no
> > - * longer needed. The passive cooling depends on the .get_trend() return value.
> > - */
> > -struct thermal_zone_device *thermal_zone_device_register(const char *type,
> > -	int trips, int mask, void *devdata,
> > -	const struct thermal_zone_device_ops *ops,
> > -	const struct thermal_zone_params *tzp,
> > -	int passive_delay, int polling_delay)
> > -{
> > -	struct thermal_zone_device *tz;
> > -	enum thermal_trip_type trip_type;
> > -	int result;
> > -	int count;
> > -	int passive = 0;
> > -
> > -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	if (!ops || !ops->get_temp)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	if (trips > 0 && !ops->get_trip_type)
> > -		return ERR_PTR(-EINVAL);
> > -
> > -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> > -	if (!tz)
> > -		return ERR_PTR(-ENOMEM);
> > -
> > -	INIT_LIST_HEAD(&tz->thermal_instances);
> > -	idr_init(&tz->idr);
> > -	mutex_init(&tz->lock);
> > -	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> > -	if (result) {
> > -		kfree(tz);
> > -		return ERR_PTR(result);
> > -	}
> > -
> > -	strcpy(tz->type, type ? : "");
> > -	tz->ops = ops;
> > -	tz->tzp = tzp;
> > -	tz->device.class = &thermal_class;
> > -	tz->devdata = devdata;
> > -	tz->trips = trips;
> > -	tz->passive_delay = passive_delay;
> > -	tz->polling_delay = polling_delay;
> > -
> > -	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> > -	result = device_register(&tz->device);
> > -	if (result) {
> > -		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > -		kfree(tz);
> > -		return ERR_PTR(result);
> > -	}
> > -
> > -	/* sys I/F */
> > -	if (type) {
> > -		result = device_create_file(&tz->device, &dev_attr_type);
> > -		if (result)
> > -			goto unregister;
> > -	}
> > -
> > -	result = device_create_file(&tz->device, &dev_attr_temp);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	if (ops->get_mode) {
> > -		result = device_create_file(&tz->device, &dev_attr_mode);
> > -		if (result)
> > -			goto unregister;
> > -	}
> > -
> > -	result = create_trip_attrs(tz, mask);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	for (count = 0; count < trips; count++) {
> > -		tz->ops->get_trip_type(tz, count, &trip_type);
> > -		if (trip_type == THERMAL_TRIP_PASSIVE)
> > -			passive = 1;
> > -	}
> > -
> > -	if (!passive) {
> > -		result = device_create_file(&tz->device, &dev_attr_passive);
> > -		if (result)
> > -			goto unregister;
> > -	}
> > -
> > -#ifdef CONFIG_THERMAL_EMULATION
> > -	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> > -	if (result)
> > -		goto unregister;
> > -#endif
> > -	/* Create policy attribute */
> > -	result = device_create_file(&tz->device, &dev_attr_policy);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	/* Update 'this' zone's governor information */
> > -	mutex_lock(&thermal_governor_lock);
> > -
> > -	if (tz->tzp)
> > -		tz->governor = __find_governor(tz->tzp->governor_name);
> > -	else
> > -		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
> > -
> > -	mutex_unlock(&thermal_governor_lock);
> > -
> > -	result = thermal_add_hwmon_sysfs(tz);
> > -	if (result)
> > -		goto unregister;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_add_tail(&tz->node, &thermal_tz_list);
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	/* Bind cooling devices for this zone */
> > -	bind_tz(tz);
> > -
> > -	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
> > -
> > -	thermal_zone_device_update(tz);
> > -
> > -	if (!result)
> > -		return tz;
> > -
> > -unregister:
> > -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > -	device_unregister(&tz->device);
> > -	return ERR_PTR(result);
> > -}
> > -EXPORT_SYMBOL(thermal_zone_device_register);
> > -
> > -/**
> > - * thermal_device_unregister - removes the registered thermal zone device
> > - * @tz: the thermal zone device to remove
> > - */
> > -void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> > -{
> > -	int i;
> > -	const struct thermal_zone_params *tzp;
> > -	struct thermal_cooling_device *cdev;
> > -	struct thermal_zone_device *pos = NULL;
> > -
> > -	if (!tz)
> > -		return;
> > -
> > -	tzp = tz->tzp;
> > -
> > -	mutex_lock(&thermal_list_lock);
> > -	list_for_each_entry(pos, &thermal_tz_list, node)
> > -	    if (pos == tz)
> > -		break;
> > -	if (pos != tz) {
> > -		/* thermal zone device not found */
> > -		mutex_unlock(&thermal_list_lock);
> > -		return;
> > -	}
> > -	list_del(&tz->node);
> > -
> > -	/* Unbind all cdevs associated with 'this' thermal zone */
> > -	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> > -		if (tz->ops->unbind) {
> > -			tz->ops->unbind(tz, cdev);
> > -			continue;
> > -		}
> > -
> > -		if (!tzp || !tzp->tbp)
> > -			break;
> > -
> > -		for (i = 0; i < tzp->num_tbps; i++) {
> > -			if (tzp->tbp[i].cdev == cdev) {
> > -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> > -				tzp->tbp[i].cdev = NULL;
> > -			}
> > -		}
> > -	}
> > -
> > -	mutex_unlock(&thermal_list_lock);
> > -
> > -	thermal_zone_device_set_polling(tz, 0);
> > -
> > -	if (tz->type[0])
> > -		device_remove_file(&tz->device, &dev_attr_type);
> > -	device_remove_file(&tz->device, &dev_attr_temp);
> > -	if (tz->ops->get_mode)
> > -		device_remove_file(&tz->device, &dev_attr_mode);
> > -	device_remove_file(&tz->device, &dev_attr_policy);
> > -	remove_trip_attrs(tz);
> > -	tz->governor = NULL;
> > -
> > -	thermal_remove_hwmon_sysfs(tz);
> > -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> > -	idr_destroy(&tz->idr);
> > -	mutex_destroy(&tz->lock);
> > -	device_unregister(&tz->device);
> > -	return;
> > -}
> > -EXPORT_SYMBOL(thermal_zone_device_unregister);
> > -
> > -#ifdef CONFIG_NET
> > -static struct genl_family thermal_event_genl_family = {
> > -	.id = GENL_ID_GENERATE,
> > -	.name = THERMAL_GENL_FAMILY_NAME,
> > -	.version = THERMAL_GENL_VERSION,
> > -	.maxattr = THERMAL_GENL_ATTR_MAX,
> > -};
> > -
> > -static struct genl_multicast_group thermal_event_mcgrp = {
> > -	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> > -};
> > -
> > -int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> > -					enum events event)
> > -{
> > -	struct sk_buff *skb;
> > -	struct nlattr *attr;
> > -	struct thermal_genl_event *thermal_event;
> > -	void *msg_header;
> > -	int size;
> > -	int result;
> > -	static unsigned int thermal_event_seqnum;
> > -
> > -	if (!tz)
> > -		return -EINVAL;
> > -
> > -	/* allocate memory */
> > -	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> > -	       nla_total_size(0);
> > -
> > -	skb = genlmsg_new(size, GFP_ATOMIC);
> > -	if (!skb)
> > -		return -ENOMEM;
> > -
> > -	/* add the genetlink message header */
> > -	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> > -				 &thermal_event_genl_family, 0,
> > -				 THERMAL_GENL_CMD_EVENT);
> > -	if (!msg_header) {
> > -		nlmsg_free(skb);
> > -		return -ENOMEM;
> > -	}
> > -
> > -	/* fill the data */
> > -	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> > -			   sizeof(struct thermal_genl_event));
> > -
> > -	if (!attr) {
> > -		nlmsg_free(skb);
> > -		return -EINVAL;
> > -	}
> > -
> > -	thermal_event = nla_data(attr);
> > -	if (!thermal_event) {
> > -		nlmsg_free(skb);
> > -		return -EINVAL;
> > -	}
> > -
> > -	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> > -
> > -	thermal_event->orig = tz->id;
> > -	thermal_event->event = event;
> > -
> > -	/* send multicast genetlink message */
> > -	result = genlmsg_end(skb, msg_header);
> > -	if (result < 0) {
> > -		nlmsg_free(skb);
> > -		return result;
> > -	}
> > -
> > -	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
> > -	if (result)
> > -		dev_err(&tz->device, "Failed to send netlink event:%d", result);
> > -
> > -	return result;
> > -}
> > -EXPORT_SYMBOL(thermal_generate_netlink_event);
> > -
> > -static int genetlink_init(void)
> > -{
> > -	int result;
> > -
> > -	result = genl_register_family(&thermal_event_genl_family);
> > -	if (result)
> > -		return result;
> > -
> > -	result = genl_register_mc_group(&thermal_event_genl_family,
> > -					&thermal_event_mcgrp);
> > -	if (result)
> > -		genl_unregister_family(&thermal_event_genl_family);
> > -	return result;
> > -}
> > -
> > -static void genetlink_exit(void)
> > -{
> > -	genl_unregister_family(&thermal_event_genl_family);
> > -}
> > -#else /* !CONFIG_NET */
> > -static inline int genetlink_init(void) { return 0; }
> > -static inline void genetlink_exit(void) {}
> > -#endif /* !CONFIG_NET */
> > -
> > -static int __init thermal_init(void)
> > -{
> > -	int result = 0;
> > -
> > -	result = class_register(&thermal_class);
> > -	if (result) {
> > -		idr_destroy(&thermal_tz_idr);
> > -		idr_destroy(&thermal_cdev_idr);
> > -		mutex_destroy(&thermal_idr_lock);
> > -		mutex_destroy(&thermal_list_lock);
> > -		return result;
> > -	}
> > -	result = genetlink_init();
> > -	return result;
> > -}
> > -
> > -static void __exit thermal_exit(void)
> > -{
> > -	class_unregister(&thermal_class);
> > -	idr_destroy(&thermal_tz_idr);
> > -	idr_destroy(&thermal_cdev_idr);
> > -	mutex_destroy(&thermal_idr_lock);
> > -	mutex_destroy(&thermal_list_lock);
> > -	genetlink_exit();
> > -}
> > -
> > -fs_initcall(thermal_init);
> > -module_exit(thermal_exit);
> >
> 



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC,1/5] Thermal: rename thermal_sys.c to thermal_core.c
  2013-03-28  2:40     ` Zhang Rui
@ 2013-04-01 12:43         ` Eduardo Valentin
  0 siblings, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-04-01 12:43 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

Hey Rui,

On 27-03-2013 22:40, Zhang Rui wrote:
> On Tue, 2013-03-26 at 18:04 -0400, Eduardo Valentin wrote:
>> Hi Rui,
>>
>> A side note:
>> I'd really appreciate if you could copy on your patches on
>> drivers/thermal/. I had some issues with TI server and got un subscribed
>> from linux-pm. Now I will try to catch up any way,
>>
> sure.
>
>> Some comments.
>>
>> On 26-03-2013 12:26, Zhang Rui wrote:
>>> No functional change in this patch.
>>>
>>
>> Just a better description would also help on code version control.
>>
> will add it in V2.
>
>>> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>>
>> Apart from minor comments, I agreed with this change. So feel free to
>> add my:
>>
>> Acked-by: Eduardo Valentin <eduardo.valentin@ti.com>
>>
> thanks!
>
>>>
>>> ---
>>> drivers/thermal/Makefile       |    1 +
>>>    drivers/thermal/thermal_core.c | 1888 ++++++++++++++++++++++++++++++++++++++++
>>>    drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------
>>
>> When sending renames, use git format-patch --find-renames, it makes a
>> better summary of what you have done, specially if you have changed
>> something in the file while renaming.
>>
> a useful tip. thanks!
>>>    3 files changed, 1889 insertions(+), 1888 deletions(-)
>>>    create mode 100644 drivers/thermal/thermal_core.c
>>>    delete mode 100644 drivers/thermal/thermal_sys.c
>>>
>>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>>> index d3a2b38..b2009bd 100644
>>> --- a/drivers/thermal/Makefile
>>> +++ b/drivers/thermal/Makefile
>>> @@ -3,6 +3,7 @@
>>>    #
>>>
>>>    obj-$(CONFIG_THERMAL)		+= thermal_sys.o
>>
>> I know this is for fixing the annoying bug with fan max speed. But while
>> still here, do you think 'thermal_sys' is a good name for thermal
>> framework driver? Maybe just 'thermal' would suffice?
>>
> as I said, there is already a thermal driver, aka,
> driver/acpi/thermal.c.
>

In fact there is. On the other hand, it does not imply that this naming 
convention is correct, right?

Unless you have a strong requirement to name these drivers the way it 
is, I'd suggest to take the opportunity to rename them. 
drivers/acpi/thermal.c could be named 'thermal-acpi.ko', if this does 
not violate any ACPI requirements. While this driver, 
drivers/thermal/thermal_sys.c, would be named only 'thermal.ko'.


> thanks,

Regards,

Ed

> rui
>>> +thermal_sys-y			+= thermal_core.o
>>>
>>>    # governors
>>>    obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
>>> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
>>> new file mode 100644
>>> index 0000000..5b7863a
>>> --- /dev/null
>>> +++ b/drivers/thermal/thermal_core.c
>>> @@ -0,0 +1,1888 @@
>>> +/*
>>> + *  thermal.c - Generic Thermal Management Sysfs support.
>>> + *
>>> + *  Copyright (C) 2008 Intel Corp
>>> + *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
>>> + *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
>>> + *
>>> + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> + *
>>> + *  This program is free software; you can redistribute it and/or modify
>>> + *  it under the terms of the GNU General Public License as published by
>>> + *  the Free Software Foundation; version 2 of the License.
>>> + *
>>> + *  This program is distributed in the hope that it will be useful, but
>>> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + *  General Public License for more details.
>>> + *
>>> + *  You should have received a copy of the GNU General Public License along
>>> + *  with this program; if not, write to the Free Software Foundation, Inc.,
>>> + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
>>> + *
>>> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> + */
>>> +
>>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>> +
>>> +#include <linux/module.h>
>>> +#include <linux/device.h>
>>> +#include <linux/err.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/kdev_t.h>
>>> +#include <linux/idr.h>
>>> +#include <linux/thermal.h>
>>> +#include <linux/reboot.h>
>>> +#include <net/netlink.h>
>>> +#include <net/genetlink.h>
>>> +
>>> +#include "thermal_core.h"
>>> +
>>> +MODULE_AUTHOR("Zhang Rui");
>>> +MODULE_DESCRIPTION("Generic thermal management sysfs support");
>>> +MODULE_LICENSE("GPL");
>>> +
>>> +static DEFINE_IDR(thermal_tz_idr);
>>> +static DEFINE_IDR(thermal_cdev_idr);
>>> +static DEFINE_MUTEX(thermal_idr_lock);
>>> +
>>> +static LIST_HEAD(thermal_tz_list);
>>> +static LIST_HEAD(thermal_cdev_list);
>>> +static LIST_HEAD(thermal_governor_list);
>>> +
>>> +static DEFINE_MUTEX(thermal_list_lock);
>>> +static DEFINE_MUTEX(thermal_governor_lock);
>>> +
>>> +static struct thermal_governor *__find_governor(const char *name)
>>> +{
>>> +	struct thermal_governor *pos;
>>> +
>>> +	list_for_each_entry(pos, &thermal_governor_list, governor_list)
>>> +		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
>>> +			return pos;
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +int thermal_register_governor(struct thermal_governor *governor)
>>> +{
>>> +	int err;
>>> +	const char *name;
>>> +	struct thermal_zone_device *pos;
>>> +
>>> +	if (!governor)
>>> +		return -EINVAL;
>>> +
>>> +	mutex_lock(&thermal_governor_lock);
>>> +
>>> +	err = -EBUSY;
>>> +	if (__find_governor(governor->name) == NULL) {
>>> +		err = 0;
>>> +		list_add(&governor->governor_list, &thermal_governor_list);
>>> +	}
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +
>>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> +		if (pos->governor)
>>> +			continue;
>>> +		if (pos->tzp)
>>> +			name = pos->tzp->governor_name;
>>> +		else
>>> +			name = DEFAULT_THERMAL_GOVERNOR;
>>> +		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
>>> +			pos->governor = governor;
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +	mutex_unlock(&thermal_governor_lock);
>>> +
>>> +	return err;
>>> +}
>>> +EXPORT_SYMBOL_GPL(thermal_register_governor);
>>> +
>>> +void thermal_unregister_governor(struct thermal_governor *governor)
>>> +{
>>> +	struct thermal_zone_device *pos;
>>> +
>>> +	if (!governor)
>>> +		return;
>>> +
>>> +	mutex_lock(&thermal_governor_lock);
>>> +
>>> +	if (__find_governor(governor->name) == NULL)
>>> +		goto exit;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +
>>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> +		if (!strnicmp(pos->governor->name, governor->name,
>>> +						THERMAL_NAME_LENGTH))
>>> +			pos->governor = NULL;
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +	list_del(&governor->governor_list);
>>> +exit:
>>> +	mutex_unlock(&thermal_governor_lock);
>>> +	return;
>>> +}
>>> +EXPORT_SYMBOL_GPL(thermal_unregister_governor);
>>> +
>>> +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
>>> +{
>>> +	int ret;
>>> +
>>> +	if (lock)
>>> +		mutex_lock(lock);
>>> +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
>>> +	if (lock)
>>> +		mutex_unlock(lock);
>>> +	if (unlikely(ret < 0))
>>> +		return ret;
>>> +	*id = ret;
>>> +	return 0;
>>> +}
>>> +
>>> +static void release_idr(struct idr *idr, struct mutex *lock, int id)
>>> +{
>>> +	if (lock)
>>> +		mutex_lock(lock);
>>> +	idr_remove(idr, id);
>>> +	if (lock)
>>> +		mutex_unlock(lock);
>>> +}
>>> +
>>> +int get_tz_trend(struct thermal_zone_device *tz, int trip)
>>> +{
>>> +	enum thermal_trend trend;
>>> +
>>> +	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
>>> +		if (tz->temperature > tz->last_temperature)
>>> +			trend = THERMAL_TREND_RAISING;
>>> +		else if (tz->temperature < tz->last_temperature)
>>> +			trend = THERMAL_TREND_DROPPING;
>>> +		else
>>> +			trend = THERMAL_TREND_STABLE;
>>> +	}
>>> +
>>> +	return trend;
>>> +}
>>> +EXPORT_SYMBOL(get_tz_trend);
>>> +
>>> +struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
>>> +			struct thermal_cooling_device *cdev, int trip)
>>> +{
>>> +	struct thermal_instance *pos = NULL;
>>> +	struct thermal_instance *target_instance = NULL;
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +	mutex_lock(&cdev->lock);
>>> +
>>> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
>>> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> +			target_instance = pos;
>>> +			break;
>>> +		}
>>> +	}
>>> +
>>> +	mutex_unlock(&cdev->lock);
>>> +	mutex_unlock(&tz->lock);
>>> +
>>> +	return target_instance;
>>> +}
>>> +EXPORT_SYMBOL(get_thermal_instance);
>>> +
>>> +static void print_bind_err_msg(struct thermal_zone_device *tz,
>>> +			struct thermal_cooling_device *cdev, int ret)
>>> +{
>>> +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>>> +				tz->type, cdev->type, ret);
>>> +}
>>> +
>>> +static void __bind(struct thermal_zone_device *tz, int mask,
>>> +			struct thermal_cooling_device *cdev)
>>> +{
>>> +	int i, ret;
>>> +
>>> +	for (i = 0; i < tz->trips; i++) {
>>> +		if (mask & (1 << i)) {
>>> +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
>>> +					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
>>> +			if (ret)
>>> +				print_bind_err_msg(tz, cdev, ret);
>>> +		}
>>> +	}
>>> +}
>>> +
>>> +static void __unbind(struct thermal_zone_device *tz, int mask,
>>> +			struct thermal_cooling_device *cdev)
>>> +{
>>> +	int i;
>>> +
>>> +	for (i = 0; i < tz->trips; i++)
>>> +		if (mask & (1 << i))
>>> +			thermal_zone_unbind_cooling_device(tz, i, cdev);
>>> +}
>>> +
>>> +static void bind_cdev(struct thermal_cooling_device *cdev)
>>> +{
>>> +	int i, ret;
>>> +	const struct thermal_zone_params *tzp;
>>> +	struct thermal_zone_device *pos = NULL;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +
>>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> +		if (!pos->tzp && !pos->ops->bind)
>>> +			continue;
>>> +
>>> +		if (!pos->tzp && pos->ops->bind) {
>>> +			ret = pos->ops->bind(pos, cdev);
>>> +			if (ret)
>>> +				print_bind_err_msg(pos, cdev, ret);
>>> +		}
>>> +
>>> +		tzp = pos->tzp;
>>> +		if (!tzp || !tzp->tbp)
>>> +			continue;
>>> +
>>> +		for (i = 0; i < tzp->num_tbps; i++) {
>>> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
>>> +				continue;
>>> +			if (tzp->tbp[i].match(pos, cdev))
>>> +				continue;
>>> +			tzp->tbp[i].cdev = cdev;
>>> +			__bind(pos, tzp->tbp[i].trip_mask, cdev);
>>> +		}
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +}
>>> +
>>> +static void bind_tz(struct thermal_zone_device *tz)
>>> +{
>>> +	int i, ret;
>>> +	struct thermal_cooling_device *pos = NULL;
>>> +	const struct thermal_zone_params *tzp = tz->tzp;
>>> +
>>> +	if (!tzp && !tz->ops->bind)
>>> +		return;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +
>>> +	/* If there is no platform data, try to use ops->bind */
>>> +	if (!tzp && tz->ops->bind) {
>>> +		list_for_each_entry(pos, &thermal_cdev_list, node) {
>>> +			ret = tz->ops->bind(tz, pos);
>>> +			if (ret)
>>> +				print_bind_err_msg(tz, pos, ret);
>>> +		}
>>> +		goto exit;
>>> +	}
>>> +
>>> +	if (!tzp || !tzp->tbp)
>>> +		goto exit;
>>> +
>>> +	list_for_each_entry(pos, &thermal_cdev_list, node) {
>>> +		for (i = 0; i < tzp->num_tbps; i++) {
>>> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
>>> +				continue;
>>> +			if (tzp->tbp[i].match(tz, pos))
>>> +				continue;
>>> +			tzp->tbp[i].cdev = pos;
>>> +			__bind(tz, tzp->tbp[i].trip_mask, pos);
>>> +		}
>>> +	}
>>> +exit:
>>> +	mutex_unlock(&thermal_list_lock);
>>> +}
>>> +
>>> +static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
>>> +					    int delay)
>>> +{
>>> +	if (delay > 1000)
>>> +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
>>> +				 round_jiffies(msecs_to_jiffies(delay)));
>>> +	else if (delay)
>>> +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
>>> +				 msecs_to_jiffies(delay));
>>> +	else
>>> +		cancel_delayed_work(&tz->poll_queue);
>>> +}
>>> +
>>> +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);
>>> +	else if (tz->polling_delay)
>>> +		thermal_zone_device_set_polling(tz, tz->polling_delay);
>>> +	else
>>> +		thermal_zone_device_set_polling(tz, 0);
>>> +
>>> +	mutex_unlock(&tz->lock);
>>> +}
>>> +
>>> +static void handle_non_critical_trips(struct thermal_zone_device *tz,
>>> +			int trip, enum thermal_trip_type trip_type)
>>> +{
>>> +	if (tz->governor)
>>> +		tz->governor->throttle(tz, trip);
>>> +}
>>> +
>>> +static void handle_critical_trips(struct thermal_zone_device *tz,
>>> +				int trip, enum thermal_trip_type trip_type)
>>> +{
>>> +	long trip_temp;
>>> +
>>> +	tz->ops->get_trip_temp(tz, trip, &trip_temp);
>>> +
>>> +	/* If we have not crossed the trip_temp, we do not care. */
>>> +	if (tz->temperature < trip_temp)
>>> +		return;
>>> +
>>> +	if (tz->ops->notify)
>>> +		tz->ops->notify(tz, trip, trip_type);
>>> +
>>> +	if (trip_type == THERMAL_TRIP_CRITICAL) {
>>> +		dev_emerg(&tz->device,
>>> +			  "critical temperature reached(%d C),shutting down\n",
>>> +			  tz->temperature / 1000);
>>> +		orderly_poweroff(true);
>>> +	}
>>> +}
>>> +
>>> +static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
>>> +{
>>> +	enum thermal_trip_type type;
>>> +
>>> +	tz->ops->get_trip_type(tz, trip, &type);
>>> +
>>> +	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
>>> +		handle_critical_trips(tz, trip, type);
>>> +	else
>>> +		handle_non_critical_trips(tz, trip, type);
>>> +	/*
>>> +	 * Alright, we handled this trip successfully.
>>> +	 * So, start monitoring again.
>>> +	 */
>>> +	monitor_thermal_zone(tz);
>>> +}
>>> +
>>> +static int thermal_zone_get_temp(struct thermal_zone_device *tz,
>>> +				unsigned long *temp)
>>> +{
>>> +	int ret = 0;
>>> +#ifdef CONFIG_THERMAL_EMULATION
>>> +	int count;
>>> +	unsigned long crit_temp = -1UL;
>>> +	enum thermal_trip_type type;
>>> +#endif
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +
>>> +	ret = tz->ops->get_temp(tz, temp);
>>> +#ifdef CONFIG_THERMAL_EMULATION
>>> +	if (!tz->emul_temperature)
>>> +		goto skip_emul;
>>> +
>>> +	for (count = 0; count < tz->trips; count++) {
>>> +		ret = tz->ops->get_trip_type(tz, count, &type);
>>> +		if (!ret && type == THERMAL_TRIP_CRITICAL) {
>>> +			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
>>> +			break;
>>> +		}
>>> +	}
>>> +
>>> +	if (ret)
>>> +		goto skip_emul;
>>> +
>>> +	if (*temp < crit_temp)
>>> +		*temp = tz->emul_temperature;
>>> +skip_emul:
>>> +#endif
>>> +	mutex_unlock(&tz->lock);
>>> +	return ret;
>>> +}
>>> +
>>> +static void update_temperature(struct thermal_zone_device *tz)
>>> +{
>>> +	long temp;
>>> +	int ret;
>>> +
>>> +	ret = thermal_zone_get_temp(tz, &temp);
>>> +	if (ret) {
>>> +		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
>>> +			 tz->id);
>>> +		return;
>>> +	}
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +	tz->last_temperature = tz->temperature;
>>> +	tz->temperature = temp;
>>> +	mutex_unlock(&tz->lock);
>>> +}
>>> +
>>> +void thermal_zone_device_update(struct thermal_zone_device *tz)
>>> +{
>>> +	int count;
>>> +
>>> +	update_temperature(tz);
>>> +
>>> +	for (count = 0; count < tz->trips; count++)
>>> +		handle_thermal_trip(tz, count);
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_device_update);
>>> +
>>> +static void thermal_zone_device_check(struct work_struct *work)
>>> +{
>>> +	struct thermal_zone_device *tz = container_of(work, struct
>>> +						      thermal_zone_device,
>>> +						      poll_queue.work);
>>> +	thermal_zone_device_update(tz);
>>> +}
>>> +
>>> +/* sys I/F for thermal zone */
>>> +
>>> +#define to_thermal_zone(_dev) \
>>> +	container_of(_dev, struct thermal_zone_device, device)
>>> +
>>> +static ssize_t
>>> +type_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +
>>> +	return sprintf(buf, "%s\n", tz->type);
>>> +}
>>> +
>>> +static ssize_t
>>> +temp_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	long temperature;
>>> +	int ret;
>>> +
>>> +	ret = thermal_zone_get_temp(tz, &temperature);
>>> +
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +static ssize_t
>>> +mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	enum thermal_device_mode mode;
>>> +	int result;
>>> +
>>> +	if (!tz->ops->get_mode)
>>> +		return -EPERM;
>>> +
>>> +	result = tz->ops->get_mode(tz, &mode);
>>> +	if (result)
>>> +		return result;
>>> +
>>> +	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
>>> +		       : "disabled");
>>> +}
>>> +
>>> +static ssize_t
>>> +mode_store(struct device *dev, struct device_attribute *attr,
>>> +	   const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int result;
>>> +
>>> +	if (!tz->ops->set_mode)
>>> +		return -EPERM;
>>> +
>>> +	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);
>>> +	else
>>> +		result = -EINVAL;
>>> +
>>> +	if (result)
>>> +		return result;
>>> +
>>> +	return count;
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_type_show(struct device *dev, struct device_attribute *attr,
>>> +		     char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	enum thermal_trip_type type;
>>> +	int trip, result;
>>> +
>>> +	if (!tz->ops->get_trip_type)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	result = tz->ops->get_trip_type(tz, trip, &type);
>>> +	if (result)
>>> +		return result;
>>> +
>>> +	switch (type) {
>>> +	case THERMAL_TRIP_CRITICAL:
>>> +		return sprintf(buf, "critical\n");
>>> +	case THERMAL_TRIP_HOT:
>>> +		return sprintf(buf, "hot\n");
>>> +	case THERMAL_TRIP_PASSIVE:
>>> +		return sprintf(buf, "passive\n");
>>> +	case THERMAL_TRIP_ACTIVE:
>>> +		return sprintf(buf, "active\n");
>>> +	default:
>>> +		return sprintf(buf, "unknown\n");
>>> +	}
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_temp_store(struct device *dev, struct device_attribute *attr,
>>> +		     const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int trip, ret;
>>> +	unsigned long temperature;
>>> +
>>> +	if (!tz->ops->set_trip_temp)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	if (kstrtoul(buf, 10, &temperature))
>>> +		return -EINVAL;
>>> +
>>> +	ret = tz->ops->set_trip_temp(tz, trip, temperature);
>>> +
>>> +	return ret ? ret : count;
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_temp_show(struct device *dev, struct device_attribute *attr,
>>> +		     char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int trip, ret;
>>> +	long temperature;
>>> +
>>> +	if (!tz->ops->get_trip_temp)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
>>> +
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
>>> +			const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int trip, ret;
>>> +	unsigned long temperature;
>>> +
>>> +	if (!tz->ops->set_trip_hyst)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	if (kstrtoul(buf, 10, &temperature))
>>> +		return -EINVAL;
>>> +
>>> +	/*
>>> +	 * We are not doing any check on the 'temperature' value
>>> +	 * here. The driver implementing 'set_trip_hyst' has to
>>> +	 * take care of this.
>>> +	 */
>>> +	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
>>> +
>>> +	return ret ? ret : count;
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
>>> +			char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int trip, ret;
>>> +	unsigned long temperature;
>>> +
>>> +	if (!tz->ops->get_trip_hyst)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
>>> +
>>> +	return ret ? ret : sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +static ssize_t
>>> +passive_store(struct device *dev, struct device_attribute *attr,
>>> +		    const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	struct thermal_cooling_device *cdev = NULL;
>>> +	int state;
>>> +
>>> +	if (!sscanf(buf, "%d\n", &state))
>>> +		return -EINVAL;
>>> +
>>> +	/* sanity check: values below 1000 millicelcius don't make sense
>>> +	 * and can cause the system to go into a thermal heart attack
>>> +	 */
>>> +	if (state && state < 1000)
>>> +		return -EINVAL;
>>> +
>>> +	if (state && !tz->forced_passive) {
>>> +		mutex_lock(&thermal_list_lock);
>>> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> +			if (!strncmp("Processor", cdev->type,
>>> +				     sizeof("Processor")))
>>> +				thermal_zone_bind_cooling_device(tz,
>>> +						THERMAL_TRIPS_NONE, cdev,
>>> +						THERMAL_NO_LIMIT,
>>> +						THERMAL_NO_LIMIT);
>>> +		}
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		if (!tz->passive_delay)
>>> +			tz->passive_delay = 1000;
>>> +	} else if (!state && tz->forced_passive) {
>>> +		mutex_lock(&thermal_list_lock);
>>> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> +			if (!strncmp("Processor", cdev->type,
>>> +				     sizeof("Processor")))
>>> +				thermal_zone_unbind_cooling_device(tz,
>>> +								   THERMAL_TRIPS_NONE,
>>> +								   cdev);
>>> +		}
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		tz->passive_delay = 0;
>>> +	}
>>> +
>>> +	tz->forced_passive = state;
>>> +
>>> +	thermal_zone_device_update(tz);
>>> +
>>> +	return count;
>>> +}
>>> +
>>> +static ssize_t
>>> +passive_show(struct device *dev, struct device_attribute *attr,
>>> +		   char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +
>>> +	return sprintf(buf, "%d\n", tz->forced_passive);
>>> +}
>>> +
>>> +static ssize_t
>>> +policy_store(struct device *dev, struct device_attribute *attr,
>>> +		    const char *buf, size_t count)
>>> +{
>>> +	int ret = -EINVAL;
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	struct thermal_governor *gov;
>>> +
>>> +	mutex_lock(&thermal_governor_lock);
>>> +
>>> +	gov = __find_governor(buf);
>>> +	if (!gov)
>>> +		goto exit;
>>> +
>>> +	tz->governor = gov;
>>> +	ret = count;
>>> +
>>> +exit:
>>> +	mutex_unlock(&thermal_governor_lock);
>>> +	return ret;
>>> +}
>>> +
>>> +static ssize_t
>>> +policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +
>>> +	return sprintf(buf, "%s\n", tz->governor->name);
>>> +}
>>> +
>>> +#ifdef CONFIG_THERMAL_EMULATION
>>> +static ssize_t
>>> +emul_temp_store(struct device *dev, struct device_attribute *attr,
>>> +		     const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int ret = 0;
>>> +	unsigned long temperature;
>>> +
>>> +	if (kstrtoul(buf, 10, &temperature))
>>> +		return -EINVAL;
>>> +
>>> +	if (!tz->ops->set_emul_temp) {
>>> +		mutex_lock(&tz->lock);
>>> +		tz->emul_temperature = temperature;
>>> +		mutex_unlock(&tz->lock);
>>> +	} else {
>>> +		ret = tz->ops->set_emul_temp(tz, temperature);
>>> +	}
>>> +
>>> +	return ret ? ret : count;
>>> +}
>>> +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
>>> +#endif/*CONFIG_THERMAL_EMULATION*/
>>> +
>>> +static DEVICE_ATTR(type, 0444, type_show, NULL);
>>> +static DEVICE_ATTR(temp, 0444, temp_show, NULL);
>>> +static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
>>> +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
>>> +static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
>>> +
>>> +/* sys I/F for cooling device */
>>> +#define to_cooling_device(_dev)	\
>>> +	container_of(_dev, struct thermal_cooling_device, device)
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_type_show(struct device *dev,
>>> +				 struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> +
>>> +	return sprintf(buf, "%s\n", cdev->type);
>>> +}
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_max_state_show(struct device *dev,
>>> +				      struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> +	unsigned long state;
>>> +	int ret;
>>> +
>>> +	ret = cdev->ops->get_max_state(cdev, &state);
>>> +	if (ret)
>>> +		return ret;
>>> +	return sprintf(buf, "%ld\n", state);
>>> +}
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_cur_state_show(struct device *dev,
>>> +				      struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> +	unsigned long state;
>>> +	int ret;
>>> +
>>> +	ret = cdev->ops->get_cur_state(cdev, &state);
>>> +	if (ret)
>>> +		return ret;
>>> +	return sprintf(buf, "%ld\n", state);
>>> +}
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_cur_state_store(struct device *dev,
>>> +				       struct device_attribute *attr,
>>> +				       const char *buf, size_t count)
>>> +{
>>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> +	unsigned long state;
>>> +	int result;
>>> +
>>> +	if (!sscanf(buf, "%ld\n", &state))
>>> +		return -EINVAL;
>>> +
>>> +	if ((long)state < 0)
>>> +		return -EINVAL;
>>> +
>>> +	result = cdev->ops->set_cur_state(cdev, state);
>>> +	if (result)
>>> +		return result;
>>> +	return count;
>>> +}
>>> +
>>> +static struct device_attribute dev_attr_cdev_type =
>>> +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
>>> +static DEVICE_ATTR(max_state, 0444,
>>> +		   thermal_cooling_device_max_state_show, NULL);
>>> +static DEVICE_ATTR(cur_state, 0644,
>>> +		   thermal_cooling_device_cur_state_show,
>>> +		   thermal_cooling_device_cur_state_store);
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_trip_point_show(struct device *dev,
>>> +				       struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_instance *instance;
>>> +
>>> +	instance =
>>> +	    container_of(attr, struct thermal_instance, attr);
>>> +
>>> +	if (instance->trip == THERMAL_TRIPS_NONE)
>>> +		return sprintf(buf, "-1\n");
>>> +	else
>>> +		return sprintf(buf, "%d\n", instance->trip);
>>> +}
>>> +
>>> +/* Device management */
>>> +
>>> +#if defined(CONFIG_THERMAL_HWMON)
>>> +
>>> +/* hwmon sys I/F */
>>> +#include <linux/hwmon.h>
>>> +
>>> +/* thermal zone devices with the same type share one hwmon device */
>>> +struct thermal_hwmon_device {
>>> +	char type[THERMAL_NAME_LENGTH];
>>> +	struct device *device;
>>> +	int count;
>>> +	struct list_head tz_list;
>>> +	struct list_head node;
>>> +};
>>> +
>>> +struct thermal_hwmon_attr {
>>> +	struct device_attribute attr;
>>> +	char name[16];
>>> +};
>>> +
>>> +/* one temperature input for each thermal zone */
>>> +struct thermal_hwmon_temp {
>>> +	struct list_head hwmon_node;
>>> +	struct thermal_zone_device *tz;
>>> +	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
>>> +	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
>>> +};
>>> +
>>> +static LIST_HEAD(thermal_hwmon_list);
>>> +
>>> +static ssize_t
>>> +name_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
>>> +	return sprintf(buf, "%s\n", hwmon->type);
>>> +}
>>> +static DEVICE_ATTR(name, 0444, name_show, NULL);
>>> +
>>> +static ssize_t
>>> +temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	long temperature;
>>> +	int ret;
>>> +	struct thermal_hwmon_attr *hwmon_attr
>>> +			= container_of(attr, struct thermal_hwmon_attr, attr);
>>> +	struct thermal_hwmon_temp *temp
>>> +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
>>> +				       temp_input);
>>> +	struct thermal_zone_device *tz = temp->tz;
>>> +
>>> +	ret = thermal_zone_get_temp(tz, &temperature);
>>> +
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +static ssize_t
>>> +temp_crit_show(struct device *dev, struct device_attribute *attr,
>>> +		char *buf)
>>> +{
>>> +	struct thermal_hwmon_attr *hwmon_attr
>>> +			= container_of(attr, struct thermal_hwmon_attr, attr);
>>> +	struct thermal_hwmon_temp *temp
>>> +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
>>> +				       temp_crit);
>>> +	struct thermal_zone_device *tz = temp->tz;
>>> +	long temperature;
>>> +	int ret;
>>> +
>>> +	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +
>>> +static struct thermal_hwmon_device *
>>> +thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
>>> +{
>>> +	struct thermal_hwmon_device *hwmon;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
>>> +		if (!strcmp(hwmon->type, tz->type)) {
>>> +			mutex_unlock(&thermal_list_lock);
>>> +			return hwmon;
>>> +		}
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +/* Find the temperature input matching a given thermal zone */
>>> +static struct thermal_hwmon_temp *
>>> +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
>>> +			  const struct thermal_zone_device *tz)
>>> +{
>>> +	struct thermal_hwmon_temp *temp;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
>>> +		if (temp->tz == tz) {
>>> +			mutex_unlock(&thermal_list_lock);
>>> +			return temp;
>>> +		}
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +static int
>>> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
>>> +{
>>> +	struct thermal_hwmon_device *hwmon;
>>> +	struct thermal_hwmon_temp *temp;
>>> +	int new_hwmon_device = 1;
>>> +	int result;
>>> +
>>> +	hwmon = thermal_hwmon_lookup_by_type(tz);
>>> +	if (hwmon) {
>>> +		new_hwmon_device = 0;
>>> +		goto register_sys_interface;
>>> +	}
>>> +
>>> +	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
>>> +	if (!hwmon)
>>> +		return -ENOMEM;
>>> +
>>> +	INIT_LIST_HEAD(&hwmon->tz_list);
>>> +	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
>>> +	hwmon->device = hwmon_device_register(NULL);
>>> +	if (IS_ERR(hwmon->device)) {
>>> +		result = PTR_ERR(hwmon->device);
>>> +		goto free_mem;
>>> +	}
>>> +	dev_set_drvdata(hwmon->device, hwmon);
>>> +	result = device_create_file(hwmon->device, &dev_attr_name);
>>> +	if (result)
>>> +		goto free_mem;
>>> +
>>> + register_sys_interface:
>>> +	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
>>> +	if (!temp) {
>>> +		result = -ENOMEM;
>>> +		goto unregister_name;
>>> +	}
>>> +
>>> +	temp->tz = tz;
>>> +	hwmon->count++;
>>> +
>>> +	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
>>> +		 "temp%d_input", hwmon->count);
>>> +	temp->temp_input.attr.attr.name = temp->temp_input.name;
>>> +	temp->temp_input.attr.attr.mode = 0444;
>>> +	temp->temp_input.attr.show = temp_input_show;
>>> +	sysfs_attr_init(&temp->temp_input.attr.attr);
>>> +	result = device_create_file(hwmon->device, &temp->temp_input.attr);
>>> +	if (result)
>>> +		goto free_temp_mem;
>>> +
>>> +	if (tz->ops->get_crit_temp) {
>>> +		unsigned long temperature;
>>> +		if (!tz->ops->get_crit_temp(tz, &temperature)) {
>>> +			snprintf(temp->temp_crit.name,
>>> +				 sizeof(temp->temp_crit.name),
>>> +				"temp%d_crit", hwmon->count);
>>> +			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
>>> +			temp->temp_crit.attr.attr.mode = 0444;
>>> +			temp->temp_crit.attr.show = temp_crit_show;
>>> +			sysfs_attr_init(&temp->temp_crit.attr.attr);
>>> +			result = device_create_file(hwmon->device,
>>> +						    &temp->temp_crit.attr);
>>> +			if (result)
>>> +				goto unregister_input;
>>> +		}
>>> +	}
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	if (new_hwmon_device)
>>> +		list_add_tail(&hwmon->node, &thermal_hwmon_list);
>>> +	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	return 0;
>>> +
>>> + unregister_input:
>>> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
>>> + free_temp_mem:
>>> +	kfree(temp);
>>> + unregister_name:
>>> +	if (new_hwmon_device) {
>>> +		device_remove_file(hwmon->device, &dev_attr_name);
>>> +		hwmon_device_unregister(hwmon->device);
>>> +	}
>>> + free_mem:
>>> +	if (new_hwmon_device)
>>> +		kfree(hwmon);
>>> +
>>> +	return result;
>>> +}
>>> +
>>> +static void
>>> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
>>> +{
>>> +	struct thermal_hwmon_device *hwmon;
>>> +	struct thermal_hwmon_temp *temp;
>>> +
>>> +	hwmon = thermal_hwmon_lookup_by_type(tz);
>>> +	if (unlikely(!hwmon)) {
>>> +		/* Should never happen... */
>>> +		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
>>> +		return;
>>> +	}
>>> +
>>> +	temp = thermal_hwmon_lookup_temp(hwmon, tz);
>>> +	if (unlikely(!temp)) {
>>> +		/* Should never happen... */
>>> +		dev_dbg(&tz->device, "temperature input lookup failed!\n");
>>> +		return;
>>> +	}
>>> +
>>> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
>>> +	if (tz->ops->get_crit_temp)
>>> +		device_remove_file(hwmon->device, &temp->temp_crit.attr);
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_del(&temp->hwmon_node);
>>> +	kfree(temp);
>>> +	if (!list_empty(&hwmon->tz_list)) {
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		return;
>>> +	}
>>> +	list_del(&hwmon->node);
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	device_remove_file(hwmon->device, &dev_attr_name);
>>> +	hwmon_device_unregister(hwmon->device);
>>> +	kfree(hwmon);
>>> +}
>>> +#else
>>> +static int
>>> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static void
>>> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
>>> +{
>>> +}
>>> +#endif
>>> +
>>> +/**
>>> + * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
>>> + * @tz:		thermal zone device
>>> + * @trip:	indicates which trip point the cooling devices is
>>> + *		associated with in this thermal zone.
>>> + * @cdev:	thermal cooling device
>>> + *
>>> + * This function is usually called in the thermal zone device .bind callback.
>>> + */
>>> +int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
>>> +				     int trip,
>>> +				     struct thermal_cooling_device *cdev,
>>> +				     unsigned long upper, unsigned long lower)
>>> +{
>>> +	struct thermal_instance *dev;
>>> +	struct thermal_instance *pos;
>>> +	struct thermal_zone_device *pos1;
>>> +	struct thermal_cooling_device *pos2;
>>> +	unsigned long max_state;
>>> +	int result;
>>> +
>>> +	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
>>> +		return -EINVAL;
>>> +
>>> +	list_for_each_entry(pos1, &thermal_tz_list, node) {
>>> +		if (pos1 == tz)
>>> +			break;
>>> +	}
>>> +	list_for_each_entry(pos2, &thermal_cdev_list, node) {
>>> +		if (pos2 == cdev)
>>> +			break;
>>> +	}
>>> +
>>> +	if (tz != pos1 || cdev != pos2)
>>> +		return -EINVAL;
>>> +
>>> +	cdev->ops->get_max_state(cdev, &max_state);
>>> +
>>> +	/* lower default 0, upper default max_state */
>>> +	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
>>> +	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
>>> +
>>> +	if (lower > upper || upper > max_state)
>>> +		return -EINVAL;
>>> +
>>> +	dev =
>>> +	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
>>> +	if (!dev)
>>> +		return -ENOMEM;
>>> +	dev->tz = tz;
>>> +	dev->cdev = cdev;
>>> +	dev->trip = trip;
>>> +	dev->upper = upper;
>>> +	dev->lower = lower;
>>> +	dev->target = THERMAL_NO_TARGET;
>>> +
>>> +	result = get_idr(&tz->idr, &tz->lock, &dev->id);
>>> +	if (result)
>>> +		goto free_mem;
>>> +
>>> +	sprintf(dev->name, "cdev%d", dev->id);
>>> +	result =
>>> +	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
>>> +	if (result)
>>> +		goto release_idr;
>>> +
>>> +	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
>>> +	sysfs_attr_init(&dev->attr.attr);
>>> +	dev->attr.attr.name = dev->attr_name;
>>> +	dev->attr.attr.mode = 0444;
>>> +	dev->attr.show = thermal_cooling_device_trip_point_show;
>>> +	result = device_create_file(&tz->device, &dev->attr);
>>> +	if (result)
>>> +		goto remove_symbol_link;
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +	mutex_lock(&cdev->lock);
>>> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
>>> +	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> +		result = -EEXIST;
>>> +		break;
>>> +	}
>>> +	if (!result) {
>>> +		list_add_tail(&dev->tz_node, &tz->thermal_instances);
>>> +		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
>>> +	}
>>> +	mutex_unlock(&cdev->lock);
>>> +	mutex_unlock(&tz->lock);
>>> +
>>> +	if (!result)
>>> +		return 0;
>>> +
>>> +	device_remove_file(&tz->device, &dev->attr);
>>> +remove_symbol_link:
>>> +	sysfs_remove_link(&tz->device.kobj, dev->name);
>>> +release_idr:
>>> +	release_idr(&tz->idr, &tz->lock, dev->id);
>>> +free_mem:
>>> +	kfree(dev);
>>> +	return result;
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
>>> +
>>> +/**
>>> + * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
>>> + * @tz:		thermal zone device
>>> + * @trip:	indicates which trip point the cooling devices is
>>> + *		associated with in this thermal zone.
>>> + * @cdev:	thermal cooling device
>>> + *
>>> + * This function is usually called in the thermal zone device .unbind callback.
>>> + */
>>> +int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
>>> +				       int trip,
>>> +				       struct thermal_cooling_device *cdev)
>>> +{
>>> +	struct thermal_instance *pos, *next;
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +	mutex_lock(&cdev->lock);
>>> +	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
>>> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> +			list_del(&pos->tz_node);
>>> +			list_del(&pos->cdev_node);
>>> +			mutex_unlock(&cdev->lock);
>>> +			mutex_unlock(&tz->lock);
>>> +			goto unbind;
>>> +		}
>>> +	}
>>> +	mutex_unlock(&cdev->lock);
>>> +	mutex_unlock(&tz->lock);
>>> +
>>> +	return -ENODEV;
>>> +
>>> +unbind:
>>> +	device_remove_file(&tz->device, &pos->attr);
>>> +	sysfs_remove_link(&tz->device.kobj, pos->name);
>>> +	release_idr(&tz->idr, &tz->lock, pos->id);
>>> +	kfree(pos);
>>> +	return 0;
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
>>> +
>>> +static void thermal_release(struct device *dev)
>>> +{
>>> +	struct thermal_zone_device *tz;
>>> +	struct thermal_cooling_device *cdev;
>>> +
>>> +	if (!strncmp(dev_name(dev), "thermal_zone",
>>> +		     sizeof("thermal_zone") - 1)) {
>>> +		tz = to_thermal_zone(dev);
>>> +		kfree(tz);
>>> +	} else {
>>> +		cdev = to_cooling_device(dev);
>>> +		kfree(cdev);
>>> +	}
>>> +}
>>> +
>>> +static struct class thermal_class = {
>>> +	.name = "thermal",
>>> +	.dev_release = thermal_release,
>>> +};
>>> +
>>> +/**
>>> + * thermal_cooling_device_register - register a new thermal cooling device
>>> + * @type:	the thermal cooling device type.
>>> + * @devdata:	device private data.
>>> + * @ops:		standard thermal cooling devices callbacks.
>>> + */
>>> +struct thermal_cooling_device *
>>> +thermal_cooling_device_register(char *type, void *devdata,
>>> +				const struct thermal_cooling_device_ops *ops)
>>> +{
>>> +	struct thermal_cooling_device *cdev;
>>> +	int result;
>>> +
>>> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
>>> +	    !ops->set_cur_state)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
>>> +	if (!cdev)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
>>> +	if (result) {
>>> +		kfree(cdev);
>>> +		return ERR_PTR(result);
>>> +	}
>>> +
>>> +	strcpy(cdev->type, type ? : "");
>>> +	mutex_init(&cdev->lock);
>>> +	INIT_LIST_HEAD(&cdev->thermal_instances);
>>> +	cdev->ops = ops;
>>> +	cdev->updated = true;
>>> +	cdev->device.class = &thermal_class;
>>> +	cdev->devdata = devdata;
>>> +	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
>>> +	result = device_register(&cdev->device);
>>> +	if (result) {
>>> +		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> +		kfree(cdev);
>>> +		return ERR_PTR(result);
>>> +	}
>>> +
>>> +	/* sys I/F */
>>> +	if (type) {
>>> +		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
>>> +		if (result)
>>> +			goto unregister;
>>> +	}
>>> +
>>> +	result = device_create_file(&cdev->device, &dev_attr_max_state);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	result = device_create_file(&cdev->device, &dev_attr_cur_state);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	/* Add 'this' new cdev to the global cdev list */
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_add(&cdev->node, &thermal_cdev_list);
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	/* Update binding information for 'this' new cdev */
>>> +	bind_cdev(cdev);
>>> +
>>> +	return cdev;
>>> +
>>> +unregister:
>>> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> +	device_unregister(&cdev->device);
>>> +	return ERR_PTR(result);
>>> +}
>>> +EXPORT_SYMBOL(thermal_cooling_device_register);
>>> +
>>> +/**
>>> + * thermal_cooling_device_unregister - removes the registered thermal cooling device
>>> + * @cdev:	the thermal cooling device to remove.
>>> + *
>>> + * thermal_cooling_device_unregister() must be called when the device is no
>>> + * longer needed.
>>> + */
>>> +void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
>>> +{
>>> +	int i;
>>> +	const struct thermal_zone_params *tzp;
>>> +	struct thermal_zone_device *tz;
>>> +	struct thermal_cooling_device *pos = NULL;
>>> +
>>> +	if (!cdev)
>>> +		return;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_for_each_entry(pos, &thermal_cdev_list, node)
>>> +	    if (pos == cdev)
>>> +		break;
>>> +	if (pos != cdev) {
>>> +		/* thermal cooling device not found */
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		return;
>>> +	}
>>> +	list_del(&cdev->node);
>>> +
>>> +	/* Unbind all thermal zones associated with 'this' cdev */
>>> +	list_for_each_entry(tz, &thermal_tz_list, node) {
>>> +		if (tz->ops->unbind) {
>>> +			tz->ops->unbind(tz, cdev);
>>> +			continue;
>>> +		}
>>> +
>>> +		if (!tz->tzp || !tz->tzp->tbp)
>>> +			continue;
>>> +
>>> +		tzp = tz->tzp;
>>> +		for (i = 0; i < tzp->num_tbps; i++) {
>>> +			if (tzp->tbp[i].cdev == cdev) {
>>> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
>>> +				tzp->tbp[i].cdev = NULL;
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	if (cdev->type[0])
>>> +		device_remove_file(&cdev->device, &dev_attr_cdev_type);
>>> +	device_remove_file(&cdev->device, &dev_attr_max_state);
>>> +	device_remove_file(&cdev->device, &dev_attr_cur_state);
>>> +
>>> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> +	device_unregister(&cdev->device);
>>> +	return;
>>> +}
>>> +EXPORT_SYMBOL(thermal_cooling_device_unregister);
>>> +
>>> +void thermal_cdev_update(struct thermal_cooling_device *cdev)
>>> +{
>>> +	struct thermal_instance *instance;
>>> +	unsigned long target = 0;
>>> +
>>> +	/* cooling device is updated*/
>>> +	if (cdev->updated)
>>> +		return;
>>> +
>>> +	mutex_lock(&cdev->lock);
>>> +	/* Make sure cdev enters the deepest cooling state */
>>> +	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
>>> +		if (instance->target == THERMAL_NO_TARGET)
>>> +			continue;
>>> +		if (instance->target > target)
>>> +			target = instance->target;
>>> +	}
>>> +	mutex_unlock(&cdev->lock);
>>> +	cdev->ops->set_cur_state(cdev, target);
>>> +	cdev->updated = true;
>>> +}
>>> +EXPORT_SYMBOL(thermal_cdev_update);
>>> +
>>> +/**
>>> + * notify_thermal_framework - Sensor drivers use this API to notify framework
>>> + * @tz:		thermal zone device
>>> + * @trip:	indicates which trip point has been crossed
>>> + *
>>> + * This function handles the trip events from sensor drivers. It starts
>>> + * throttling the cooling devices according to the policy configured.
>>> + * For CRITICAL and HOT trip points, this notifies the respective drivers,
>>> + * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
>>> + * The throttling policy is based on the configured platform data; if no
>>> + * platform data is provided, this uses the step_wise throttling policy.
>>> + */
>>> +void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
>>> +{
>>> +	handle_thermal_trip(tz, trip);
>>> +}
>>> +EXPORT_SYMBOL(notify_thermal_framework);
>>> +
>>> +/**
>>> + * create_trip_attrs - create attributes for trip points
>>> + * @tz:		the thermal zone device
>>> + * @mask:	Writeable trip point bitmap.
>>> + */
>>> +static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
>>> +{
>>> +	int indx;
>>> +	int size = sizeof(struct thermal_attr) * tz->trips;
>>> +
>>> +	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
>>> +	if (!tz->trip_type_attrs)
>>> +		return -ENOMEM;
>>> +
>>> +	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
>>> +	if (!tz->trip_temp_attrs) {
>>> +		kfree(tz->trip_type_attrs);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	if (tz->ops->get_trip_hyst) {
>>> +		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
>>> +		if (!tz->trip_hyst_attrs) {
>>> +			kfree(tz->trip_type_attrs);
>>> +			kfree(tz->trip_temp_attrs);
>>> +			return -ENOMEM;
>>> +		}
>>> +	}
>>> +
>>> +
>>> +	for (indx = 0; indx < tz->trips; indx++) {
>>> +		/* create trip type attribute */
>>> +		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> +			 "trip_point_%d_type", indx);
>>> +
>>> +		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
>>> +		tz->trip_type_attrs[indx].attr.attr.name =
>>> +						tz->trip_type_attrs[indx].name;
>>> +		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
>>> +		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
>>> +
>>> +		device_create_file(&tz->device,
>>> +				   &tz->trip_type_attrs[indx].attr);
>>> +
>>> +		/* create trip temp attribute */
>>> +		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> +			 "trip_point_%d_temp", indx);
>>> +
>>> +		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
>>> +		tz->trip_temp_attrs[indx].attr.attr.name =
>>> +						tz->trip_temp_attrs[indx].name;
>>> +		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
>>> +		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
>>> +		if (mask & (1 << indx)) {
>>> +			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
>>> +			tz->trip_temp_attrs[indx].attr.store =
>>> +							trip_point_temp_store;
>>> +		}
>>> +
>>> +		device_create_file(&tz->device,
>>> +				   &tz->trip_temp_attrs[indx].attr);
>>> +
>>> +		/* create Optional trip hyst attribute */
>>> +		if (!tz->ops->get_trip_hyst)
>>> +			continue;
>>> +		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> +			 "trip_point_%d_hyst", indx);
>>> +
>>> +		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
>>> +		tz->trip_hyst_attrs[indx].attr.attr.name =
>>> +					tz->trip_hyst_attrs[indx].name;
>>> +		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
>>> +		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
>>> +		if (tz->ops->set_trip_hyst) {
>>> +			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
>>> +			tz->trip_hyst_attrs[indx].attr.store =
>>> +					trip_point_hyst_store;
>>> +		}
>>> +
>>> +		device_create_file(&tz->device,
>>> +				   &tz->trip_hyst_attrs[indx].attr);
>>> +	}
>>> +	return 0;
>>> +}
>>> +
>>> +static void remove_trip_attrs(struct thermal_zone_device *tz)
>>> +{
>>> +	int indx;
>>> +
>>> +	for (indx = 0; indx < tz->trips; indx++) {
>>> +		device_remove_file(&tz->device,
>>> +				   &tz->trip_type_attrs[indx].attr);
>>> +		device_remove_file(&tz->device,
>>> +				   &tz->trip_temp_attrs[indx].attr);
>>> +		if (tz->ops->get_trip_hyst)
>>> +			device_remove_file(&tz->device,
>>> +				  &tz->trip_hyst_attrs[indx].attr);
>>> +	}
>>> +	kfree(tz->trip_type_attrs);
>>> +	kfree(tz->trip_temp_attrs);
>>> +	kfree(tz->trip_hyst_attrs);
>>> +}
>>> +
>>> +/**
>>> + * thermal_zone_device_register - register a new thermal zone device
>>> + * @type:	the thermal zone device type
>>> + * @trips:	the number of trip points the thermal zone support
>>> + * @mask:	a bit string indicating the writeablility of trip points
>>> + * @devdata:	private device data
>>> + * @ops:	standard thermal zone device callbacks
>>> + * @tzp:	thermal zone platform parameters
>>> + * @passive_delay: number of milliseconds to wait between polls when
>>> + *		   performing passive cooling
>>> + * @polling_delay: number of milliseconds to wait between polls when checking
>>> + *		   whether trip points have been crossed (0 for interrupt
>>> + *		   driven systems)
>>> + *
>>> + * thermal_zone_device_unregister() must be called when the device is no
>>> + * longer needed. The passive cooling depends on the .get_trend() return value.
>>> + */
>>> +struct thermal_zone_device *thermal_zone_device_register(const char *type,
>>> +	int trips, int mask, void *devdata,
>>> +	const struct thermal_zone_device_ops *ops,
>>> +	const struct thermal_zone_params *tzp,
>>> +	int passive_delay, int polling_delay)
>>> +{
>>> +	struct thermal_zone_device *tz;
>>> +	enum thermal_trip_type trip_type;
>>> +	int result;
>>> +	int count;
>>> +	int passive = 0;
>>> +
>>> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	if (!ops || !ops->get_temp)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	if (trips > 0 && !ops->get_trip_type)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
>>> +	if (!tz)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	INIT_LIST_HEAD(&tz->thermal_instances);
>>> +	idr_init(&tz->idr);
>>> +	mutex_init(&tz->lock);
>>> +	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
>>> +	if (result) {
>>> +		kfree(tz);
>>> +		return ERR_PTR(result);
>>> +	}
>>> +
>>> +	strcpy(tz->type, type ? : "");
>>> +	tz->ops = ops;
>>> +	tz->tzp = tzp;
>>> +	tz->device.class = &thermal_class;
>>> +	tz->devdata = devdata;
>>> +	tz->trips = trips;
>>> +	tz->passive_delay = passive_delay;
>>> +	tz->polling_delay = polling_delay;
>>> +
>>> +	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
>>> +	result = device_register(&tz->device);
>>> +	if (result) {
>>> +		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> +		kfree(tz);
>>> +		return ERR_PTR(result);
>>> +	}
>>> +
>>> +	/* sys I/F */
>>> +	if (type) {
>>> +		result = device_create_file(&tz->device, &dev_attr_type);
>>> +		if (result)
>>> +			goto unregister;
>>> +	}
>>> +
>>> +	result = device_create_file(&tz->device, &dev_attr_temp);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	if (ops->get_mode) {
>>> +		result = device_create_file(&tz->device, &dev_attr_mode);
>>> +		if (result)
>>> +			goto unregister;
>>> +	}
>>> +
>>> +	result = create_trip_attrs(tz, mask);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	for (count = 0; count < trips; count++) {
>>> +		tz->ops->get_trip_type(tz, count, &trip_type);
>>> +		if (trip_type == THERMAL_TRIP_PASSIVE)
>>> +			passive = 1;
>>> +	}
>>> +
>>> +	if (!passive) {
>>> +		result = device_create_file(&tz->device, &dev_attr_passive);
>>> +		if (result)
>>> +			goto unregister;
>>> +	}
>>> +
>>> +#ifdef CONFIG_THERMAL_EMULATION
>>> +	result = device_create_file(&tz->device, &dev_attr_emul_temp);
>>> +	if (result)
>>> +		goto unregister;
>>> +#endif
>>> +	/* Create policy attribute */
>>> +	result = device_create_file(&tz->device, &dev_attr_policy);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	/* Update 'this' zone's governor information */
>>> +	mutex_lock(&thermal_governor_lock);
>>> +
>>> +	if (tz->tzp)
>>> +		tz->governor = __find_governor(tz->tzp->governor_name);
>>> +	else
>>> +		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
>>> +
>>> +	mutex_unlock(&thermal_governor_lock);
>>> +
>>> +	result = thermal_add_hwmon_sysfs(tz);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_add_tail(&tz->node, &thermal_tz_list);
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	/* Bind cooling devices for this zone */
>>> +	bind_tz(tz);
>>> +
>>> +	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
>>> +
>>> +	thermal_zone_device_update(tz);
>>> +
>>> +	if (!result)
>>> +		return tz;
>>> +
>>> +unregister:
>>> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> +	device_unregister(&tz->device);
>>> +	return ERR_PTR(result);
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_device_register);
>>> +
>>> +/**
>>> + * thermal_device_unregister - removes the registered thermal zone device
>>> + * @tz: the thermal zone device to remove
>>> + */
>>> +void thermal_zone_device_unregister(struct thermal_zone_device *tz)
>>> +{
>>> +	int i;
>>> +	const struct thermal_zone_params *tzp;
>>> +	struct thermal_cooling_device *cdev;
>>> +	struct thermal_zone_device *pos = NULL;
>>> +
>>> +	if (!tz)
>>> +		return;
>>> +
>>> +	tzp = tz->tzp;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_for_each_entry(pos, &thermal_tz_list, node)
>>> +	    if (pos == tz)
>>> +		break;
>>> +	if (pos != tz) {
>>> +		/* thermal zone device not found */
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		return;
>>> +	}
>>> +	list_del(&tz->node);
>>> +
>>> +	/* Unbind all cdevs associated with 'this' thermal zone */
>>> +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> +		if (tz->ops->unbind) {
>>> +			tz->ops->unbind(tz, cdev);
>>> +			continue;
>>> +		}
>>> +
>>> +		if (!tzp || !tzp->tbp)
>>> +			break;
>>> +
>>> +		for (i = 0; i < tzp->num_tbps; i++) {
>>> +			if (tzp->tbp[i].cdev == cdev) {
>>> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
>>> +				tzp->tbp[i].cdev = NULL;
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	thermal_zone_device_set_polling(tz, 0);
>>> +
>>> +	if (tz->type[0])
>>> +		device_remove_file(&tz->device, &dev_attr_type);
>>> +	device_remove_file(&tz->device, &dev_attr_temp);
>>> +	if (tz->ops->get_mode)
>>> +		device_remove_file(&tz->device, &dev_attr_mode);
>>> +	device_remove_file(&tz->device, &dev_attr_policy);
>>> +	remove_trip_attrs(tz);
>>> +	tz->governor = NULL;
>>> +
>>> +	thermal_remove_hwmon_sysfs(tz);
>>> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> +	idr_destroy(&tz->idr);
>>> +	mutex_destroy(&tz->lock);
>>> +	device_unregister(&tz->device);
>>> +	return;
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_device_unregister);
>>> +
>>> +#ifdef CONFIG_NET
>>> +static struct genl_family thermal_event_genl_family = {
>>> +	.id = GENL_ID_GENERATE,
>>> +	.name = THERMAL_GENL_FAMILY_NAME,
>>> +	.version = THERMAL_GENL_VERSION,
>>> +	.maxattr = THERMAL_GENL_ATTR_MAX,
>>> +};
>>> +
>>> +static struct genl_multicast_group thermal_event_mcgrp = {
>>> +	.name = THERMAL_GENL_MCAST_GROUP_NAME,
>>> +};
>>> +
>>> +int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>>> +					enum events event)
>>> +{
>>> +	struct sk_buff *skb;
>>> +	struct nlattr *attr;
>>> +	struct thermal_genl_event *thermal_event;
>>> +	void *msg_header;
>>> +	int size;
>>> +	int result;
>>> +	static unsigned int thermal_event_seqnum;
>>> +
>>> +	if (!tz)
>>> +		return -EINVAL;
>>> +
>>> +	/* allocate memory */
>>> +	size = nla_total_size(sizeof(struct thermal_genl_event)) +
>>> +	       nla_total_size(0);
>>> +
>>> +	skb = genlmsg_new(size, GFP_ATOMIC);
>>> +	if (!skb)
>>> +		return -ENOMEM;
>>> +
>>> +	/* add the genetlink message header */
>>> +	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
>>> +				 &thermal_event_genl_family, 0,
>>> +				 THERMAL_GENL_CMD_EVENT);
>>> +	if (!msg_header) {
>>> +		nlmsg_free(skb);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	/* fill the data */
>>> +	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
>>> +			   sizeof(struct thermal_genl_event));
>>> +
>>> +	if (!attr) {
>>> +		nlmsg_free(skb);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	thermal_event = nla_data(attr);
>>> +	if (!thermal_event) {
>>> +		nlmsg_free(skb);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
>>> +
>>> +	thermal_event->orig = tz->id;
>>> +	thermal_event->event = event;
>>> +
>>> +	/* send multicast genetlink message */
>>> +	result = genlmsg_end(skb, msg_header);
>>> +	if (result < 0) {
>>> +		nlmsg_free(skb);
>>> +		return result;
>>> +	}
>>> +
>>> +	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
>>> +	if (result)
>>> +		dev_err(&tz->device, "Failed to send netlink event:%d", result);
>>> +
>>> +	return result;
>>> +}
>>> +EXPORT_SYMBOL(thermal_generate_netlink_event);
>>> +
>>> +static int genetlink_init(void)
>>> +{
>>> +	int result;
>>> +
>>> +	result = genl_register_family(&thermal_event_genl_family);
>>> +	if (result)
>>> +		return result;
>>> +
>>> +	result = genl_register_mc_group(&thermal_event_genl_family,
>>> +					&thermal_event_mcgrp);
>>> +	if (result)
>>> +		genl_unregister_family(&thermal_event_genl_family);
>>> +	return result;
>>> +}
>>> +
>>> +static void genetlink_exit(void)
>>> +{
>>> +	genl_unregister_family(&thermal_event_genl_family);
>>> +}
>>> +#else /* !CONFIG_NET */
>>> +static inline int genetlink_init(void) { return 0; }
>>> +static inline void genetlink_exit(void) {}
>>> +#endif /* !CONFIG_NET */
>>> +
>>> +static int __init thermal_init(void)
>>> +{
>>> +	int result = 0;
>>> +
>>> +	result = class_register(&thermal_class);
>>> +	if (result) {
>>> +		idr_destroy(&thermal_tz_idr);
>>> +		idr_destroy(&thermal_cdev_idr);
>>> +		mutex_destroy(&thermal_idr_lock);
>>> +		mutex_destroy(&thermal_list_lock);
>>> +		return result;
>>> +	}
>>> +	result = genetlink_init();
>>> +	return result;
>>> +}
>>> +
>>> +static void __exit thermal_exit(void)
>>> +{
>>> +	class_unregister(&thermal_class);
>>> +	idr_destroy(&thermal_tz_idr);
>>> +	idr_destroy(&thermal_cdev_idr);
>>> +	mutex_destroy(&thermal_idr_lock);
>>> +	mutex_destroy(&thermal_list_lock);
>>> +	genetlink_exit();
>>> +}
>>> +
>>> +fs_initcall(thermal_init);
>>> +module_exit(thermal_exit);
>>> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
>>> deleted file mode 100644
>>> index 5b7863a..0000000
>>> --- a/drivers/thermal/thermal_sys.c
>>> +++ /dev/null
>>> @@ -1,1888 +0,0 @@
>>> -/*
>>> - *  thermal.c - Generic Thermal Management Sysfs support.
>>> - *
>>> - *  Copyright (C) 2008 Intel Corp
>>> - *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
>>> - *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
>>> - *
>>> - *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> - *
>>> - *  This program is free software; you can redistribute it and/or modify
>>> - *  it under the terms of the GNU General Public License as published by
>>> - *  the Free Software Foundation; version 2 of the License.
>>> - *
>>> - *  This program is distributed in the hope that it will be useful, but
>>> - *  WITHOUT ANY WARRANTY; without even the implied warranty of
>>> - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> - *  General Public License for more details.
>>> - *
>>> - *  You should have received a copy of the GNU General Public License along
>>> - *  with this program; if not, write to the Free Software Foundation, Inc.,
>>> - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
>>> - *
>>> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> - */
>>> -
>>> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>> -
>>> -#include <linux/module.h>
>>> -#include <linux/device.h>
>>> -#include <linux/err.h>
>>> -#include <linux/slab.h>
>>> -#include <linux/kdev_t.h>
>>> -#include <linux/idr.h>
>>> -#include <linux/thermal.h>
>>> -#include <linux/reboot.h>
>>> -#include <net/netlink.h>
>>> -#include <net/genetlink.h>
>>> -
>>> -#include "thermal_core.h"
>>> -
>>> -MODULE_AUTHOR("Zhang Rui");
>>> -MODULE_DESCRIPTION("Generic thermal management sysfs support");
>>> -MODULE_LICENSE("GPL");
>>> -
>>> -static DEFINE_IDR(thermal_tz_idr);
>>> -static DEFINE_IDR(thermal_cdev_idr);
>>> -static DEFINE_MUTEX(thermal_idr_lock);
>>> -
>>> -static LIST_HEAD(thermal_tz_list);
>>> -static LIST_HEAD(thermal_cdev_list);
>>> -static LIST_HEAD(thermal_governor_list);
>>> -
>>> -static DEFINE_MUTEX(thermal_list_lock);
>>> -static DEFINE_MUTEX(thermal_governor_lock);
>>> -
>>> -static struct thermal_governor *__find_governor(const char *name)
>>> -{
>>> -	struct thermal_governor *pos;
>>> -
>>> -	list_for_each_entry(pos, &thermal_governor_list, governor_list)
>>> -		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
>>> -			return pos;
>>> -
>>> -	return NULL;
>>> -}
>>> -
>>> -int thermal_register_governor(struct thermal_governor *governor)
>>> -{
>>> -	int err;
>>> -	const char *name;
>>> -	struct thermal_zone_device *pos;
>>> -
>>> -	if (!governor)
>>> -		return -EINVAL;
>>> -
>>> -	mutex_lock(&thermal_governor_lock);
>>> -
>>> -	err = -EBUSY;
>>> -	if (__find_governor(governor->name) == NULL) {
>>> -		err = 0;
>>> -		list_add(&governor->governor_list, &thermal_governor_list);
>>> -	}
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -
>>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> -		if (pos->governor)
>>> -			continue;
>>> -		if (pos->tzp)
>>> -			name = pos->tzp->governor_name;
>>> -		else
>>> -			name = DEFAULT_THERMAL_GOVERNOR;
>>> -		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
>>> -			pos->governor = governor;
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -	mutex_unlock(&thermal_governor_lock);
>>> -
>>> -	return err;
>>> -}
>>> -EXPORT_SYMBOL_GPL(thermal_register_governor);
>>> -
>>> -void thermal_unregister_governor(struct thermal_governor *governor)
>>> -{
>>> -	struct thermal_zone_device *pos;
>>> -
>>> -	if (!governor)
>>> -		return;
>>> -
>>> -	mutex_lock(&thermal_governor_lock);
>>> -
>>> -	if (__find_governor(governor->name) == NULL)
>>> -		goto exit;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -
>>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> -		if (!strnicmp(pos->governor->name, governor->name,
>>> -						THERMAL_NAME_LENGTH))
>>> -			pos->governor = NULL;
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -	list_del(&governor->governor_list);
>>> -exit:
>>> -	mutex_unlock(&thermal_governor_lock);
>>> -	return;
>>> -}
>>> -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
>>> -
>>> -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
>>> -{
>>> -	int ret;
>>> -
>>> -	if (lock)
>>> -		mutex_lock(lock);
>>> -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
>>> -	if (lock)
>>> -		mutex_unlock(lock);
>>> -	if (unlikely(ret < 0))
>>> -		return ret;
>>> -	*id = ret;
>>> -	return 0;
>>> -}
>>> -
>>> -static void release_idr(struct idr *idr, struct mutex *lock, int id)
>>> -{
>>> -	if (lock)
>>> -		mutex_lock(lock);
>>> -	idr_remove(idr, id);
>>> -	if (lock)
>>> -		mutex_unlock(lock);
>>> -}
>>> -
>>> -int get_tz_trend(struct thermal_zone_device *tz, int trip)
>>> -{
>>> -	enum thermal_trend trend;
>>> -
>>> -	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
>>> -		if (tz->temperature > tz->last_temperature)
>>> -			trend = THERMAL_TREND_RAISING;
>>> -		else if (tz->temperature < tz->last_temperature)
>>> -			trend = THERMAL_TREND_DROPPING;
>>> -		else
>>> -			trend = THERMAL_TREND_STABLE;
>>> -	}
>>> -
>>> -	return trend;
>>> -}
>>> -EXPORT_SYMBOL(get_tz_trend);
>>> -
>>> -struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
>>> -			struct thermal_cooling_device *cdev, int trip)
>>> -{
>>> -	struct thermal_instance *pos = NULL;
>>> -	struct thermal_instance *target_instance = NULL;
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -	mutex_lock(&cdev->lock);
>>> -
>>> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
>>> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> -			target_instance = pos;
>>> -			break;
>>> -		}
>>> -	}
>>> -
>>> -	mutex_unlock(&cdev->lock);
>>> -	mutex_unlock(&tz->lock);
>>> -
>>> -	return target_instance;
>>> -}
>>> -EXPORT_SYMBOL(get_thermal_instance);
>>> -
>>> -static void print_bind_err_msg(struct thermal_zone_device *tz,
>>> -			struct thermal_cooling_device *cdev, int ret)
>>> -{
>>> -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>>> -				tz->type, cdev->type, ret);
>>> -}
>>> -
>>> -static void __bind(struct thermal_zone_device *tz, int mask,
>>> -			struct thermal_cooling_device *cdev)
>>> -{
>>> -	int i, ret;
>>> -
>>> -	for (i = 0; i < tz->trips; i++) {
>>> -		if (mask & (1 << i)) {
>>> -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
>>> -					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
>>> -			if (ret)
>>> -				print_bind_err_msg(tz, cdev, ret);
>>> -		}
>>> -	}
>>> -}
>>> -
>>> -static void __unbind(struct thermal_zone_device *tz, int mask,
>>> -			struct thermal_cooling_device *cdev)
>>> -{
>>> -	int i;
>>> -
>>> -	for (i = 0; i < tz->trips; i++)
>>> -		if (mask & (1 << i))
>>> -			thermal_zone_unbind_cooling_device(tz, i, cdev);
>>> -}
>>> -
>>> -static void bind_cdev(struct thermal_cooling_device *cdev)
>>> -{
>>> -	int i, ret;
>>> -	const struct thermal_zone_params *tzp;
>>> -	struct thermal_zone_device *pos = NULL;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -
>>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> -		if (!pos->tzp && !pos->ops->bind)
>>> -			continue;
>>> -
>>> -		if (!pos->tzp && pos->ops->bind) {
>>> -			ret = pos->ops->bind(pos, cdev);
>>> -			if (ret)
>>> -				print_bind_err_msg(pos, cdev, ret);
>>> -		}
>>> -
>>> -		tzp = pos->tzp;
>>> -		if (!tzp || !tzp->tbp)
>>> -			continue;
>>> -
>>> -		for (i = 0; i < tzp->num_tbps; i++) {
>>> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
>>> -				continue;
>>> -			if (tzp->tbp[i].match(pos, cdev))
>>> -				continue;
>>> -			tzp->tbp[i].cdev = cdev;
>>> -			__bind(pos, tzp->tbp[i].trip_mask, cdev);
>>> -		}
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -}
>>> -
>>> -static void bind_tz(struct thermal_zone_device *tz)
>>> -{
>>> -	int i, ret;
>>> -	struct thermal_cooling_device *pos = NULL;
>>> -	const struct thermal_zone_params *tzp = tz->tzp;
>>> -
>>> -	if (!tzp && !tz->ops->bind)
>>> -		return;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -
>>> -	/* If there is no platform data, try to use ops->bind */
>>> -	if (!tzp && tz->ops->bind) {
>>> -		list_for_each_entry(pos, &thermal_cdev_list, node) {
>>> -			ret = tz->ops->bind(tz, pos);
>>> -			if (ret)
>>> -				print_bind_err_msg(tz, pos, ret);
>>> -		}
>>> -		goto exit;
>>> -	}
>>> -
>>> -	if (!tzp || !tzp->tbp)
>>> -		goto exit;
>>> -
>>> -	list_for_each_entry(pos, &thermal_cdev_list, node) {
>>> -		for (i = 0; i < tzp->num_tbps; i++) {
>>> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
>>> -				continue;
>>> -			if (tzp->tbp[i].match(tz, pos))
>>> -				continue;
>>> -			tzp->tbp[i].cdev = pos;
>>> -			__bind(tz, tzp->tbp[i].trip_mask, pos);
>>> -		}
>>> -	}
>>> -exit:
>>> -	mutex_unlock(&thermal_list_lock);
>>> -}
>>> -
>>> -static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
>>> -					    int delay)
>>> -{
>>> -	if (delay > 1000)
>>> -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
>>> -				 round_jiffies(msecs_to_jiffies(delay)));
>>> -	else if (delay)
>>> -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
>>> -				 msecs_to_jiffies(delay));
>>> -	else
>>> -		cancel_delayed_work(&tz->poll_queue);
>>> -}
>>> -
>>> -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);
>>> -	else if (tz->polling_delay)
>>> -		thermal_zone_device_set_polling(tz, tz->polling_delay);
>>> -	else
>>> -		thermal_zone_device_set_polling(tz, 0);
>>> -
>>> -	mutex_unlock(&tz->lock);
>>> -}
>>> -
>>> -static void handle_non_critical_trips(struct thermal_zone_device *tz,
>>> -			int trip, enum thermal_trip_type trip_type)
>>> -{
>>> -	if (tz->governor)
>>> -		tz->governor->throttle(tz, trip);
>>> -}
>>> -
>>> -static void handle_critical_trips(struct thermal_zone_device *tz,
>>> -				int trip, enum thermal_trip_type trip_type)
>>> -{
>>> -	long trip_temp;
>>> -
>>> -	tz->ops->get_trip_temp(tz, trip, &trip_temp);
>>> -
>>> -	/* If we have not crossed the trip_temp, we do not care. */
>>> -	if (tz->temperature < trip_temp)
>>> -		return;
>>> -
>>> -	if (tz->ops->notify)
>>> -		tz->ops->notify(tz, trip, trip_type);
>>> -
>>> -	if (trip_type == THERMAL_TRIP_CRITICAL) {
>>> -		dev_emerg(&tz->device,
>>> -			  "critical temperature reached(%d C),shutting down\n",
>>> -			  tz->temperature / 1000);
>>> -		orderly_poweroff(true);
>>> -	}
>>> -}
>>> -
>>> -static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
>>> -{
>>> -	enum thermal_trip_type type;
>>> -
>>> -	tz->ops->get_trip_type(tz, trip, &type);
>>> -
>>> -	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
>>> -		handle_critical_trips(tz, trip, type);
>>> -	else
>>> -		handle_non_critical_trips(tz, trip, type);
>>> -	/*
>>> -	 * Alright, we handled this trip successfully.
>>> -	 * So, start monitoring again.
>>> -	 */
>>> -	monitor_thermal_zone(tz);
>>> -}
>>> -
>>> -static int thermal_zone_get_temp(struct thermal_zone_device *tz,
>>> -				unsigned long *temp)
>>> -{
>>> -	int ret = 0;
>>> -#ifdef CONFIG_THERMAL_EMULATION
>>> -	int count;
>>> -	unsigned long crit_temp = -1UL;
>>> -	enum thermal_trip_type type;
>>> -#endif
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -
>>> -	ret = tz->ops->get_temp(tz, temp);
>>> -#ifdef CONFIG_THERMAL_EMULATION
>>> -	if (!tz->emul_temperature)
>>> -		goto skip_emul;
>>> -
>>> -	for (count = 0; count < tz->trips; count++) {
>>> -		ret = tz->ops->get_trip_type(tz, count, &type);
>>> -		if (!ret && type == THERMAL_TRIP_CRITICAL) {
>>> -			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
>>> -			break;
>>> -		}
>>> -	}
>>> -
>>> -	if (ret)
>>> -		goto skip_emul;
>>> -
>>> -	if (*temp < crit_temp)
>>> -		*temp = tz->emul_temperature;
>>> -skip_emul:
>>> -#endif
>>> -	mutex_unlock(&tz->lock);
>>> -	return ret;
>>> -}
>>> -
>>> -static void update_temperature(struct thermal_zone_device *tz)
>>> -{
>>> -	long temp;
>>> -	int ret;
>>> -
>>> -	ret = thermal_zone_get_temp(tz, &temp);
>>> -	if (ret) {
>>> -		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
>>> -			 tz->id);
>>> -		return;
>>> -	}
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -	tz->last_temperature = tz->temperature;
>>> -	tz->temperature = temp;
>>> -	mutex_unlock(&tz->lock);
>>> -}
>>> -
>>> -void thermal_zone_device_update(struct thermal_zone_device *tz)
>>> -{
>>> -	int count;
>>> -
>>> -	update_temperature(tz);
>>> -
>>> -	for (count = 0; count < tz->trips; count++)
>>> -		handle_thermal_trip(tz, count);
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_device_update);
>>> -
>>> -static void thermal_zone_device_check(struct work_struct *work)
>>> -{
>>> -	struct thermal_zone_device *tz = container_of(work, struct
>>> -						      thermal_zone_device,
>>> -						      poll_queue.work);
>>> -	thermal_zone_device_update(tz);
>>> -}
>>> -
>>> -/* sys I/F for thermal zone */
>>> -
>>> -#define to_thermal_zone(_dev) \
>>> -	container_of(_dev, struct thermal_zone_device, device)
>>> -
>>> -static ssize_t
>>> -type_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -
>>> -	return sprintf(buf, "%s\n", tz->type);
>>> -}
>>> -
>>> -static ssize_t
>>> -temp_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	long temperature;
>>> -	int ret;
>>> -
>>> -	ret = thermal_zone_get_temp(tz, &temperature);
>>> -
>>> -	if (ret)
>>> -		return ret;
>>> -
>>> -	return sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -static ssize_t
>>> -mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	enum thermal_device_mode mode;
>>> -	int result;
>>> -
>>> -	if (!tz->ops->get_mode)
>>> -		return -EPERM;
>>> -
>>> -	result = tz->ops->get_mode(tz, &mode);
>>> -	if (result)
>>> -		return result;
>>> -
>>> -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
>>> -		       : "disabled");
>>> -}
>>> -
>>> -static ssize_t
>>> -mode_store(struct device *dev, struct device_attribute *attr,
>>> -	   const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int result;
>>> -
>>> -	if (!tz->ops->set_mode)
>>> -		return -EPERM;
>>> -
>>> -	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);
>>> -	else
>>> -		result = -EINVAL;
>>> -
>>> -	if (result)
>>> -		return result;
>>> -
>>> -	return count;
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_type_show(struct device *dev, struct device_attribute *attr,
>>> -		     char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	enum thermal_trip_type type;
>>> -	int trip, result;
>>> -
>>> -	if (!tz->ops->get_trip_type)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	result = tz->ops->get_trip_type(tz, trip, &type);
>>> -	if (result)
>>> -		return result;
>>> -
>>> -	switch (type) {
>>> -	case THERMAL_TRIP_CRITICAL:
>>> -		return sprintf(buf, "critical\n");
>>> -	case THERMAL_TRIP_HOT:
>>> -		return sprintf(buf, "hot\n");
>>> -	case THERMAL_TRIP_PASSIVE:
>>> -		return sprintf(buf, "passive\n");
>>> -	case THERMAL_TRIP_ACTIVE:
>>> -		return sprintf(buf, "active\n");
>>> -	default:
>>> -		return sprintf(buf, "unknown\n");
>>> -	}
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_temp_store(struct device *dev, struct device_attribute *attr,
>>> -		     const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int trip, ret;
>>> -	unsigned long temperature;
>>> -
>>> -	if (!tz->ops->set_trip_temp)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	if (kstrtoul(buf, 10, &temperature))
>>> -		return -EINVAL;
>>> -
>>> -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
>>> -
>>> -	return ret ? ret : count;
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_temp_show(struct device *dev, struct device_attribute *attr,
>>> -		     char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int trip, ret;
>>> -	long temperature;
>>> -
>>> -	if (!tz->ops->get_trip_temp)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
>>> -
>>> -	if (ret)
>>> -		return ret;
>>> -
>>> -	return sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
>>> -			const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int trip, ret;
>>> -	unsigned long temperature;
>>> -
>>> -	if (!tz->ops->set_trip_hyst)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	if (kstrtoul(buf, 10, &temperature))
>>> -		return -EINVAL;
>>> -
>>> -	/*
>>> -	 * We are not doing any check on the 'temperature' value
>>> -	 * here. The driver implementing 'set_trip_hyst' has to
>>> -	 * take care of this.
>>> -	 */
>>> -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
>>> -
>>> -	return ret ? ret : count;
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
>>> -			char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int trip, ret;
>>> -	unsigned long temperature;
>>> -
>>> -	if (!tz->ops->get_trip_hyst)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
>>> -
>>> -	return ret ? ret : sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -static ssize_t
>>> -passive_store(struct device *dev, struct device_attribute *attr,
>>> -		    const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	struct thermal_cooling_device *cdev = NULL;
>>> -	int state;
>>> -
>>> -	if (!sscanf(buf, "%d\n", &state))
>>> -		return -EINVAL;
>>> -
>>> -	/* sanity check: values below 1000 millicelcius don't make sense
>>> -	 * and can cause the system to go into a thermal heart attack
>>> -	 */
>>> -	if (state && state < 1000)
>>> -		return -EINVAL;
>>> -
>>> -	if (state && !tz->forced_passive) {
>>> -		mutex_lock(&thermal_list_lock);
>>> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> -			if (!strncmp("Processor", cdev->type,
>>> -				     sizeof("Processor")))
>>> -				thermal_zone_bind_cooling_device(tz,
>>> -						THERMAL_TRIPS_NONE, cdev,
>>> -						THERMAL_NO_LIMIT,
>>> -						THERMAL_NO_LIMIT);
>>> -		}
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		if (!tz->passive_delay)
>>> -			tz->passive_delay = 1000;
>>> -	} else if (!state && tz->forced_passive) {
>>> -		mutex_lock(&thermal_list_lock);
>>> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> -			if (!strncmp("Processor", cdev->type,
>>> -				     sizeof("Processor")))
>>> -				thermal_zone_unbind_cooling_device(tz,
>>> -								   THERMAL_TRIPS_NONE,
>>> -								   cdev);
>>> -		}
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		tz->passive_delay = 0;
>>> -	}
>>> -
>>> -	tz->forced_passive = state;
>>> -
>>> -	thermal_zone_device_update(tz);
>>> -
>>> -	return count;
>>> -}
>>> -
>>> -static ssize_t
>>> -passive_show(struct device *dev, struct device_attribute *attr,
>>> -		   char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -
>>> -	return sprintf(buf, "%d\n", tz->forced_passive);
>>> -}
>>> -
>>> -static ssize_t
>>> -policy_store(struct device *dev, struct device_attribute *attr,
>>> -		    const char *buf, size_t count)
>>> -{
>>> -	int ret = -EINVAL;
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	struct thermal_governor *gov;
>>> -
>>> -	mutex_lock(&thermal_governor_lock);
>>> -
>>> -	gov = __find_governor(buf);
>>> -	if (!gov)
>>> -		goto exit;
>>> -
>>> -	tz->governor = gov;
>>> -	ret = count;
>>> -
>>> -exit:
>>> -	mutex_unlock(&thermal_governor_lock);
>>> -	return ret;
>>> -}
>>> -
>>> -static ssize_t
>>> -policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -
>>> -	return sprintf(buf, "%s\n", tz->governor->name);
>>> -}
>>> -
>>> -#ifdef CONFIG_THERMAL_EMULATION
>>> -static ssize_t
>>> -emul_temp_store(struct device *dev, struct device_attribute *attr,
>>> -		     const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int ret = 0;
>>> -	unsigned long temperature;
>>> -
>>> -	if (kstrtoul(buf, 10, &temperature))
>>> -		return -EINVAL;
>>> -
>>> -	if (!tz->ops->set_emul_temp) {
>>> -		mutex_lock(&tz->lock);
>>> -		tz->emul_temperature = temperature;
>>> -		mutex_unlock(&tz->lock);
>>> -	} else {
>>> -		ret = tz->ops->set_emul_temp(tz, temperature);
>>> -	}
>>> -
>>> -	return ret ? ret : count;
>>> -}
>>> -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
>>> -#endif/*CONFIG_THERMAL_EMULATION*/
>>> -
>>> -static DEVICE_ATTR(type, 0444, type_show, NULL);
>>> -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
>>> -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
>>> -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
>>> -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
>>> -
>>> -/* sys I/F for cooling device */
>>> -#define to_cooling_device(_dev)	\
>>> -	container_of(_dev, struct thermal_cooling_device, device)
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_type_show(struct device *dev,
>>> -				 struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> -
>>> -	return sprintf(buf, "%s\n", cdev->type);
>>> -}
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_max_state_show(struct device *dev,
>>> -				      struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> -	unsigned long state;
>>> -	int ret;
>>> -
>>> -	ret = cdev->ops->get_max_state(cdev, &state);
>>> -	if (ret)
>>> -		return ret;
>>> -	return sprintf(buf, "%ld\n", state);
>>> -}
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_cur_state_show(struct device *dev,
>>> -				      struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> -	unsigned long state;
>>> -	int ret;
>>> -
>>> -	ret = cdev->ops->get_cur_state(cdev, &state);
>>> -	if (ret)
>>> -		return ret;
>>> -	return sprintf(buf, "%ld\n", state);
>>> -}
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_cur_state_store(struct device *dev,
>>> -				       struct device_attribute *attr,
>>> -				       const char *buf, size_t count)
>>> -{
>>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> -	unsigned long state;
>>> -	int result;
>>> -
>>> -	if (!sscanf(buf, "%ld\n", &state))
>>> -		return -EINVAL;
>>> -
>>> -	if ((long)state < 0)
>>> -		return -EINVAL;
>>> -
>>> -	result = cdev->ops->set_cur_state(cdev, state);
>>> -	if (result)
>>> -		return result;
>>> -	return count;
>>> -}
>>> -
>>> -static struct device_attribute dev_attr_cdev_type =
>>> -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
>>> -static DEVICE_ATTR(max_state, 0444,
>>> -		   thermal_cooling_device_max_state_show, NULL);
>>> -static DEVICE_ATTR(cur_state, 0644,
>>> -		   thermal_cooling_device_cur_state_show,
>>> -		   thermal_cooling_device_cur_state_store);
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_trip_point_show(struct device *dev,
>>> -				       struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_instance *instance;
>>> -
>>> -	instance =
>>> -	    container_of(attr, struct thermal_instance, attr);
>>> -
>>> -	if (instance->trip == THERMAL_TRIPS_NONE)
>>> -		return sprintf(buf, "-1\n");
>>> -	else
>>> -		return sprintf(buf, "%d\n", instance->trip);
>>> -}
>>> -
>>> -/* Device management */
>>> -
>>> -#if defined(CONFIG_THERMAL_HWMON)
>>> -
>>> -/* hwmon sys I/F */
>>> -#include <linux/hwmon.h>
>>> -
>>> -/* thermal zone devices with the same type share one hwmon device */
>>> -struct thermal_hwmon_device {
>>> -	char type[THERMAL_NAME_LENGTH];
>>> -	struct device *device;
>>> -	int count;
>>> -	struct list_head tz_list;
>>> -	struct list_head node;
>>> -};
>>> -
>>> -struct thermal_hwmon_attr {
>>> -	struct device_attribute attr;
>>> -	char name[16];
>>> -};
>>> -
>>> -/* one temperature input for each thermal zone */
>>> -struct thermal_hwmon_temp {
>>> -	struct list_head hwmon_node;
>>> -	struct thermal_zone_device *tz;
>>> -	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
>>> -	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
>>> -};
>>> -
>>> -static LIST_HEAD(thermal_hwmon_list);
>>> -
>>> -static ssize_t
>>> -name_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
>>> -	return sprintf(buf, "%s\n", hwmon->type);
>>> -}
>>> -static DEVICE_ATTR(name, 0444, name_show, NULL);
>>> -
>>> -static ssize_t
>>> -temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	long temperature;
>>> -	int ret;
>>> -	struct thermal_hwmon_attr *hwmon_attr
>>> -			= container_of(attr, struct thermal_hwmon_attr, attr);
>>> -	struct thermal_hwmon_temp *temp
>>> -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
>>> -				       temp_input);
>>> -	struct thermal_zone_device *tz = temp->tz;
>>> -
>>> -	ret = thermal_zone_get_temp(tz, &temperature);
>>> -
>>> -	if (ret)
>>> -		return ret;
>>> -
>>> -	return sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -static ssize_t
>>> -temp_crit_show(struct device *dev, struct device_attribute *attr,
>>> -		char *buf)
>>> -{
>>> -	struct thermal_hwmon_attr *hwmon_attr
>>> -			= container_of(attr, struct thermal_hwmon_attr, attr);
>>> -	struct thermal_hwmon_temp *temp
>>> -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
>>> -				       temp_crit);
>>> -	struct thermal_zone_device *tz = temp->tz;
>>> -	long temperature;
>>> -	int ret;
>>> -
>>> -	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
>>> -	if (ret)
>>> -		return ret;
>>> -
>>> -	return sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -
>>> -static struct thermal_hwmon_device *
>>> -thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
>>> -{
>>> -	struct thermal_hwmon_device *hwmon;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
>>> -		if (!strcmp(hwmon->type, tz->type)) {
>>> -			mutex_unlock(&thermal_list_lock);
>>> -			return hwmon;
>>> -		}
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	return NULL;
>>> -}
>>> -
>>> -/* Find the temperature input matching a given thermal zone */
>>> -static struct thermal_hwmon_temp *
>>> -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
>>> -			  const struct thermal_zone_device *tz)
>>> -{
>>> -	struct thermal_hwmon_temp *temp;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
>>> -		if (temp->tz == tz) {
>>> -			mutex_unlock(&thermal_list_lock);
>>> -			return temp;
>>> -		}
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	return NULL;
>>> -}
>>> -
>>> -static int
>>> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
>>> -{
>>> -	struct thermal_hwmon_device *hwmon;
>>> -	struct thermal_hwmon_temp *temp;
>>> -	int new_hwmon_device = 1;
>>> -	int result;
>>> -
>>> -	hwmon = thermal_hwmon_lookup_by_type(tz);
>>> -	if (hwmon) {
>>> -		new_hwmon_device = 0;
>>> -		goto register_sys_interface;
>>> -	}
>>> -
>>> -	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
>>> -	if (!hwmon)
>>> -		return -ENOMEM;
>>> -
>>> -	INIT_LIST_HEAD(&hwmon->tz_list);
>>> -	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
>>> -	hwmon->device = hwmon_device_register(NULL);
>>> -	if (IS_ERR(hwmon->device)) {
>>> -		result = PTR_ERR(hwmon->device);
>>> -		goto free_mem;
>>> -	}
>>> -	dev_set_drvdata(hwmon->device, hwmon);
>>> -	result = device_create_file(hwmon->device, &dev_attr_name);
>>> -	if (result)
>>> -		goto free_mem;
>>> -
>>> - register_sys_interface:
>>> -	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
>>> -	if (!temp) {
>>> -		result = -ENOMEM;
>>> -		goto unregister_name;
>>> -	}
>>> -
>>> -	temp->tz = tz;
>>> -	hwmon->count++;
>>> -
>>> -	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
>>> -		 "temp%d_input", hwmon->count);
>>> -	temp->temp_input.attr.attr.name = temp->temp_input.name;
>>> -	temp->temp_input.attr.attr.mode = 0444;
>>> -	temp->temp_input.attr.show = temp_input_show;
>>> -	sysfs_attr_init(&temp->temp_input.attr.attr);
>>> -	result = device_create_file(hwmon->device, &temp->temp_input.attr);
>>> -	if (result)
>>> -		goto free_temp_mem;
>>> -
>>> -	if (tz->ops->get_crit_temp) {
>>> -		unsigned long temperature;
>>> -		if (!tz->ops->get_crit_temp(tz, &temperature)) {
>>> -			snprintf(temp->temp_crit.name,
>>> -				 sizeof(temp->temp_crit.name),
>>> -				"temp%d_crit", hwmon->count);
>>> -			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
>>> -			temp->temp_crit.attr.attr.mode = 0444;
>>> -			temp->temp_crit.attr.show = temp_crit_show;
>>> -			sysfs_attr_init(&temp->temp_crit.attr.attr);
>>> -			result = device_create_file(hwmon->device,
>>> -						    &temp->temp_crit.attr);
>>> -			if (result)
>>> -				goto unregister_input;
>>> -		}
>>> -	}
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	if (new_hwmon_device)
>>> -		list_add_tail(&hwmon->node, &thermal_hwmon_list);
>>> -	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	return 0;
>>> -
>>> - unregister_input:
>>> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
>>> - free_temp_mem:
>>> -	kfree(temp);
>>> - unregister_name:
>>> -	if (new_hwmon_device) {
>>> -		device_remove_file(hwmon->device, &dev_attr_name);
>>> -		hwmon_device_unregister(hwmon->device);
>>> -	}
>>> - free_mem:
>>> -	if (new_hwmon_device)
>>> -		kfree(hwmon);
>>> -
>>> -	return result;
>>> -}
>>> -
>>> -static void
>>> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
>>> -{
>>> -	struct thermal_hwmon_device *hwmon;
>>> -	struct thermal_hwmon_temp *temp;
>>> -
>>> -	hwmon = thermal_hwmon_lookup_by_type(tz);
>>> -	if (unlikely(!hwmon)) {
>>> -		/* Should never happen... */
>>> -		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
>>> -		return;
>>> -	}
>>> -
>>> -	temp = thermal_hwmon_lookup_temp(hwmon, tz);
>>> -	if (unlikely(!temp)) {
>>> -		/* Should never happen... */
>>> -		dev_dbg(&tz->device, "temperature input lookup failed!\n");
>>> -		return;
>>> -	}
>>> -
>>> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
>>> -	if (tz->ops->get_crit_temp)
>>> -		device_remove_file(hwmon->device, &temp->temp_crit.attr);
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_del(&temp->hwmon_node);
>>> -	kfree(temp);
>>> -	if (!list_empty(&hwmon->tz_list)) {
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		return;
>>> -	}
>>> -	list_del(&hwmon->node);
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	device_remove_file(hwmon->device, &dev_attr_name);
>>> -	hwmon_device_unregister(hwmon->device);
>>> -	kfree(hwmon);
>>> -}
>>> -#else
>>> -static int
>>> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>> -static void
>>> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
>>> -{
>>> -}
>>> -#endif
>>> -
>>> -/**
>>> - * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
>>> - * @tz:		thermal zone device
>>> - * @trip:	indicates which trip point the cooling devices is
>>> - *		associated with in this thermal zone.
>>> - * @cdev:	thermal cooling device
>>> - *
>>> - * This function is usually called in the thermal zone device .bind callback.
>>> - */
>>> -int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
>>> -				     int trip,
>>> -				     struct thermal_cooling_device *cdev,
>>> -				     unsigned long upper, unsigned long lower)
>>> -{
>>> -	struct thermal_instance *dev;
>>> -	struct thermal_instance *pos;
>>> -	struct thermal_zone_device *pos1;
>>> -	struct thermal_cooling_device *pos2;
>>> -	unsigned long max_state;
>>> -	int result;
>>> -
>>> -	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
>>> -		return -EINVAL;
>>> -
>>> -	list_for_each_entry(pos1, &thermal_tz_list, node) {
>>> -		if (pos1 == tz)
>>> -			break;
>>> -	}
>>> -	list_for_each_entry(pos2, &thermal_cdev_list, node) {
>>> -		if (pos2 == cdev)
>>> -			break;
>>> -	}
>>> -
>>> -	if (tz != pos1 || cdev != pos2)
>>> -		return -EINVAL;
>>> -
>>> -	cdev->ops->get_max_state(cdev, &max_state);
>>> -
>>> -	/* lower default 0, upper default max_state */
>>> -	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
>>> -	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
>>> -
>>> -	if (lower > upper || upper > max_state)
>>> -		return -EINVAL;
>>> -
>>> -	dev =
>>> -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
>>> -	if (!dev)
>>> -		return -ENOMEM;
>>> -	dev->tz = tz;
>>> -	dev->cdev = cdev;
>>> -	dev->trip = trip;
>>> -	dev->upper = upper;
>>> -	dev->lower = lower;
>>> -	dev->target = THERMAL_NO_TARGET;
>>> -
>>> -	result = get_idr(&tz->idr, &tz->lock, &dev->id);
>>> -	if (result)
>>> -		goto free_mem;
>>> -
>>> -	sprintf(dev->name, "cdev%d", dev->id);
>>> -	result =
>>> -	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
>>> -	if (result)
>>> -		goto release_idr;
>>> -
>>> -	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
>>> -	sysfs_attr_init(&dev->attr.attr);
>>> -	dev->attr.attr.name = dev->attr_name;
>>> -	dev->attr.attr.mode = 0444;
>>> -	dev->attr.show = thermal_cooling_device_trip_point_show;
>>> -	result = device_create_file(&tz->device, &dev->attr);
>>> -	if (result)
>>> -		goto remove_symbol_link;
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -	mutex_lock(&cdev->lock);
>>> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
>>> -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> -		result = -EEXIST;
>>> -		break;
>>> -	}
>>> -	if (!result) {
>>> -		list_add_tail(&dev->tz_node, &tz->thermal_instances);
>>> -		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
>>> -	}
>>> -	mutex_unlock(&cdev->lock);
>>> -	mutex_unlock(&tz->lock);
>>> -
>>> -	if (!result)
>>> -		return 0;
>>> -
>>> -	device_remove_file(&tz->device, &dev->attr);
>>> -remove_symbol_link:
>>> -	sysfs_remove_link(&tz->device.kobj, dev->name);
>>> -release_idr:
>>> -	release_idr(&tz->idr, &tz->lock, dev->id);
>>> -free_mem:
>>> -	kfree(dev);
>>> -	return result;
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
>>> -
>>> -/**
>>> - * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
>>> - * @tz:		thermal zone device
>>> - * @trip:	indicates which trip point the cooling devices is
>>> - *		associated with in this thermal zone.
>>> - * @cdev:	thermal cooling device
>>> - *
>>> - * This function is usually called in the thermal zone device .unbind callback.
>>> - */
>>> -int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
>>> -				       int trip,
>>> -				       struct thermal_cooling_device *cdev)
>>> -{
>>> -	struct thermal_instance *pos, *next;
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -	mutex_lock(&cdev->lock);
>>> -	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
>>> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> -			list_del(&pos->tz_node);
>>> -			list_del(&pos->cdev_node);
>>> -			mutex_unlock(&cdev->lock);
>>> -			mutex_unlock(&tz->lock);
>>> -			goto unbind;
>>> -		}
>>> -	}
>>> -	mutex_unlock(&cdev->lock);
>>> -	mutex_unlock(&tz->lock);
>>> -
>>> -	return -ENODEV;
>>> -
>>> -unbind:
>>> -	device_remove_file(&tz->device, &pos->attr);
>>> -	sysfs_remove_link(&tz->device.kobj, pos->name);
>>> -	release_idr(&tz->idr, &tz->lock, pos->id);
>>> -	kfree(pos);
>>> -	return 0;
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
>>> -
>>> -static void thermal_release(struct device *dev)
>>> -{
>>> -	struct thermal_zone_device *tz;
>>> -	struct thermal_cooling_device *cdev;
>>> -
>>> -	if (!strncmp(dev_name(dev), "thermal_zone",
>>> -		     sizeof("thermal_zone") - 1)) {
>>> -		tz = to_thermal_zone(dev);
>>> -		kfree(tz);
>>> -	} else {
>>> -		cdev = to_cooling_device(dev);
>>> -		kfree(cdev);
>>> -	}
>>> -}
>>> -
>>> -static struct class thermal_class = {
>>> -	.name = "thermal",
>>> -	.dev_release = thermal_release,
>>> -};
>>> -
>>> -/**
>>> - * thermal_cooling_device_register - register a new thermal cooling device
>>> - * @type:	the thermal cooling device type.
>>> - * @devdata:	device private data.
>>> - * @ops:		standard thermal cooling devices callbacks.
>>> - */
>>> -struct thermal_cooling_device *
>>> -thermal_cooling_device_register(char *type, void *devdata,
>>> -				const struct thermal_cooling_device_ops *ops)
>>> -{
>>> -	struct thermal_cooling_device *cdev;
>>> -	int result;
>>> -
>>> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
>>> -	    !ops->set_cur_state)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
>>> -	if (!cdev)
>>> -		return ERR_PTR(-ENOMEM);
>>> -
>>> -	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
>>> -	if (result) {
>>> -		kfree(cdev);
>>> -		return ERR_PTR(result);
>>> -	}
>>> -
>>> -	strcpy(cdev->type, type ? : "");
>>> -	mutex_init(&cdev->lock);
>>> -	INIT_LIST_HEAD(&cdev->thermal_instances);
>>> -	cdev->ops = ops;
>>> -	cdev->updated = true;
>>> -	cdev->device.class = &thermal_class;
>>> -	cdev->devdata = devdata;
>>> -	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
>>> -	result = device_register(&cdev->device);
>>> -	if (result) {
>>> -		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> -		kfree(cdev);
>>> -		return ERR_PTR(result);
>>> -	}
>>> -
>>> -	/* sys I/F */
>>> -	if (type) {
>>> -		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
>>> -		if (result)
>>> -			goto unregister;
>>> -	}
>>> -
>>> -	result = device_create_file(&cdev->device, &dev_attr_max_state);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	result = device_create_file(&cdev->device, &dev_attr_cur_state);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	/* Add 'this' new cdev to the global cdev list */
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_add(&cdev->node, &thermal_cdev_list);
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	/* Update binding information for 'this' new cdev */
>>> -	bind_cdev(cdev);
>>> -
>>> -	return cdev;
>>> -
>>> -unregister:
>>> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> -	device_unregister(&cdev->device);
>>> -	return ERR_PTR(result);
>>> -}
>>> -EXPORT_SYMBOL(thermal_cooling_device_register);
>>> -
>>> -/**
>>> - * thermal_cooling_device_unregister - removes the registered thermal cooling device
>>> - * @cdev:	the thermal cooling device to remove.
>>> - *
>>> - * thermal_cooling_device_unregister() must be called when the device is no
>>> - * longer needed.
>>> - */
>>> -void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
>>> -{
>>> -	int i;
>>> -	const struct thermal_zone_params *tzp;
>>> -	struct thermal_zone_device *tz;
>>> -	struct thermal_cooling_device *pos = NULL;
>>> -
>>> -	if (!cdev)
>>> -		return;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_for_each_entry(pos, &thermal_cdev_list, node)
>>> -	    if (pos == cdev)
>>> -		break;
>>> -	if (pos != cdev) {
>>> -		/* thermal cooling device not found */
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		return;
>>> -	}
>>> -	list_del(&cdev->node);
>>> -
>>> -	/* Unbind all thermal zones associated with 'this' cdev */
>>> -	list_for_each_entry(tz, &thermal_tz_list, node) {
>>> -		if (tz->ops->unbind) {
>>> -			tz->ops->unbind(tz, cdev);
>>> -			continue;
>>> -		}
>>> -
>>> -		if (!tz->tzp || !tz->tzp->tbp)
>>> -			continue;
>>> -
>>> -		tzp = tz->tzp;
>>> -		for (i = 0; i < tzp->num_tbps; i++) {
>>> -			if (tzp->tbp[i].cdev == cdev) {
>>> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
>>> -				tzp->tbp[i].cdev = NULL;
>>> -			}
>>> -		}
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	if (cdev->type[0])
>>> -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
>>> -	device_remove_file(&cdev->device, &dev_attr_max_state);
>>> -	device_remove_file(&cdev->device, &dev_attr_cur_state);
>>> -
>>> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> -	device_unregister(&cdev->device);
>>> -	return;
>>> -}
>>> -EXPORT_SYMBOL(thermal_cooling_device_unregister);
>>> -
>>> -void thermal_cdev_update(struct thermal_cooling_device *cdev)
>>> -{
>>> -	struct thermal_instance *instance;
>>> -	unsigned long target = 0;
>>> -
>>> -	/* cooling device is updated*/
>>> -	if (cdev->updated)
>>> -		return;
>>> -
>>> -	mutex_lock(&cdev->lock);
>>> -	/* Make sure cdev enters the deepest cooling state */
>>> -	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
>>> -		if (instance->target == THERMAL_NO_TARGET)
>>> -			continue;
>>> -		if (instance->target > target)
>>> -			target = instance->target;
>>> -	}
>>> -	mutex_unlock(&cdev->lock);
>>> -	cdev->ops->set_cur_state(cdev, target);
>>> -	cdev->updated = true;
>>> -}
>>> -EXPORT_SYMBOL(thermal_cdev_update);
>>> -
>>> -/**
>>> - * notify_thermal_framework - Sensor drivers use this API to notify framework
>>> - * @tz:		thermal zone device
>>> - * @trip:	indicates which trip point has been crossed
>>> - *
>>> - * This function handles the trip events from sensor drivers. It starts
>>> - * throttling the cooling devices according to the policy configured.
>>> - * For CRITICAL and HOT trip points, this notifies the respective drivers,
>>> - * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
>>> - * The throttling policy is based on the configured platform data; if no
>>> - * platform data is provided, this uses the step_wise throttling policy.
>>> - */
>>> -void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
>>> -{
>>> -	handle_thermal_trip(tz, trip);
>>> -}
>>> -EXPORT_SYMBOL(notify_thermal_framework);
>>> -
>>> -/**
>>> - * create_trip_attrs - create attributes for trip points
>>> - * @tz:		the thermal zone device
>>> - * @mask:	Writeable trip point bitmap.
>>> - */
>>> -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
>>> -{
>>> -	int indx;
>>> -	int size = sizeof(struct thermal_attr) * tz->trips;
>>> -
>>> -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
>>> -	if (!tz->trip_type_attrs)
>>> -		return -ENOMEM;
>>> -
>>> -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
>>> -	if (!tz->trip_temp_attrs) {
>>> -		kfree(tz->trip_type_attrs);
>>> -		return -ENOMEM;
>>> -	}
>>> -
>>> -	if (tz->ops->get_trip_hyst) {
>>> -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
>>> -		if (!tz->trip_hyst_attrs) {
>>> -			kfree(tz->trip_type_attrs);
>>> -			kfree(tz->trip_temp_attrs);
>>> -			return -ENOMEM;
>>> -		}
>>> -	}
>>> -
>>> -
>>> -	for (indx = 0; indx < tz->trips; indx++) {
>>> -		/* create trip type attribute */
>>> -		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> -			 "trip_point_%d_type", indx);
>>> -
>>> -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
>>> -		tz->trip_type_attrs[indx].attr.attr.name =
>>> -						tz->trip_type_attrs[indx].name;
>>> -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
>>> -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
>>> -
>>> -		device_create_file(&tz->device,
>>> -				   &tz->trip_type_attrs[indx].attr);
>>> -
>>> -		/* create trip temp attribute */
>>> -		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> -			 "trip_point_%d_temp", indx);
>>> -
>>> -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
>>> -		tz->trip_temp_attrs[indx].attr.attr.name =
>>> -						tz->trip_temp_attrs[indx].name;
>>> -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
>>> -		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
>>> -		if (mask & (1 << indx)) {
>>> -			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
>>> -			tz->trip_temp_attrs[indx].attr.store =
>>> -							trip_point_temp_store;
>>> -		}
>>> -
>>> -		device_create_file(&tz->device,
>>> -				   &tz->trip_temp_attrs[indx].attr);
>>> -
>>> -		/* create Optional trip hyst attribute */
>>> -		if (!tz->ops->get_trip_hyst)
>>> -			continue;
>>> -		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> -			 "trip_point_%d_hyst", indx);
>>> -
>>> -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
>>> -		tz->trip_hyst_attrs[indx].attr.attr.name =
>>> -					tz->trip_hyst_attrs[indx].name;
>>> -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
>>> -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
>>> -		if (tz->ops->set_trip_hyst) {
>>> -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
>>> -			tz->trip_hyst_attrs[indx].attr.store =
>>> -					trip_point_hyst_store;
>>> -		}
>>> -
>>> -		device_create_file(&tz->device,
>>> -				   &tz->trip_hyst_attrs[indx].attr);
>>> -	}
>>> -	return 0;
>>> -}
>>> -
>>> -static void remove_trip_attrs(struct thermal_zone_device *tz)
>>> -{
>>> -	int indx;
>>> -
>>> -	for (indx = 0; indx < tz->trips; indx++) {
>>> -		device_remove_file(&tz->device,
>>> -				   &tz->trip_type_attrs[indx].attr);
>>> -		device_remove_file(&tz->device,
>>> -				   &tz->trip_temp_attrs[indx].attr);
>>> -		if (tz->ops->get_trip_hyst)
>>> -			device_remove_file(&tz->device,
>>> -				  &tz->trip_hyst_attrs[indx].attr);
>>> -	}
>>> -	kfree(tz->trip_type_attrs);
>>> -	kfree(tz->trip_temp_attrs);
>>> -	kfree(tz->trip_hyst_attrs);
>>> -}
>>> -
>>> -/**
>>> - * thermal_zone_device_register - register a new thermal zone device
>>> - * @type:	the thermal zone device type
>>> - * @trips:	the number of trip points the thermal zone support
>>> - * @mask:	a bit string indicating the writeablility of trip points
>>> - * @devdata:	private device data
>>> - * @ops:	standard thermal zone device callbacks
>>> - * @tzp:	thermal zone platform parameters
>>> - * @passive_delay: number of milliseconds to wait between polls when
>>> - *		   performing passive cooling
>>> - * @polling_delay: number of milliseconds to wait between polls when checking
>>> - *		   whether trip points have been crossed (0 for interrupt
>>> - *		   driven systems)
>>> - *
>>> - * thermal_zone_device_unregister() must be called when the device is no
>>> - * longer needed. The passive cooling depends on the .get_trend() return value.
>>> - */
>>> -struct thermal_zone_device *thermal_zone_device_register(const char *type,
>>> -	int trips, int mask, void *devdata,
>>> -	const struct thermal_zone_device_ops *ops,
>>> -	const struct thermal_zone_params *tzp,
>>> -	int passive_delay, int polling_delay)
>>> -{
>>> -	struct thermal_zone_device *tz;
>>> -	enum thermal_trip_type trip_type;
>>> -	int result;
>>> -	int count;
>>> -	int passive = 0;
>>> -
>>> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	if (!ops || !ops->get_temp)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	if (trips > 0 && !ops->get_trip_type)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
>>> -	if (!tz)
>>> -		return ERR_PTR(-ENOMEM);
>>> -
>>> -	INIT_LIST_HEAD(&tz->thermal_instances);
>>> -	idr_init(&tz->idr);
>>> -	mutex_init(&tz->lock);
>>> -	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
>>> -	if (result) {
>>> -		kfree(tz);
>>> -		return ERR_PTR(result);
>>> -	}
>>> -
>>> -	strcpy(tz->type, type ? : "");
>>> -	tz->ops = ops;
>>> -	tz->tzp = tzp;
>>> -	tz->device.class = &thermal_class;
>>> -	tz->devdata = devdata;
>>> -	tz->trips = trips;
>>> -	tz->passive_delay = passive_delay;
>>> -	tz->polling_delay = polling_delay;
>>> -
>>> -	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
>>> -	result = device_register(&tz->device);
>>> -	if (result) {
>>> -		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> -		kfree(tz);
>>> -		return ERR_PTR(result);
>>> -	}
>>> -
>>> -	/* sys I/F */
>>> -	if (type) {
>>> -		result = device_create_file(&tz->device, &dev_attr_type);
>>> -		if (result)
>>> -			goto unregister;
>>> -	}
>>> -
>>> -	result = device_create_file(&tz->device, &dev_attr_temp);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	if (ops->get_mode) {
>>> -		result = device_create_file(&tz->device, &dev_attr_mode);
>>> -		if (result)
>>> -			goto unregister;
>>> -	}
>>> -
>>> -	result = create_trip_attrs(tz, mask);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	for (count = 0; count < trips; count++) {
>>> -		tz->ops->get_trip_type(tz, count, &trip_type);
>>> -		if (trip_type == THERMAL_TRIP_PASSIVE)
>>> -			passive = 1;
>>> -	}
>>> -
>>> -	if (!passive) {
>>> -		result = device_create_file(&tz->device, &dev_attr_passive);
>>> -		if (result)
>>> -			goto unregister;
>>> -	}
>>> -
>>> -#ifdef CONFIG_THERMAL_EMULATION
>>> -	result = device_create_file(&tz->device, &dev_attr_emul_temp);
>>> -	if (result)
>>> -		goto unregister;
>>> -#endif
>>> -	/* Create policy attribute */
>>> -	result = device_create_file(&tz->device, &dev_attr_policy);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	/* Update 'this' zone's governor information */
>>> -	mutex_lock(&thermal_governor_lock);
>>> -
>>> -	if (tz->tzp)
>>> -		tz->governor = __find_governor(tz->tzp->governor_name);
>>> -	else
>>> -		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
>>> -
>>> -	mutex_unlock(&thermal_governor_lock);
>>> -
>>> -	result = thermal_add_hwmon_sysfs(tz);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_add_tail(&tz->node, &thermal_tz_list);
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	/* Bind cooling devices for this zone */
>>> -	bind_tz(tz);
>>> -
>>> -	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
>>> -
>>> -	thermal_zone_device_update(tz);
>>> -
>>> -	if (!result)
>>> -		return tz;
>>> -
>>> -unregister:
>>> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> -	device_unregister(&tz->device);
>>> -	return ERR_PTR(result);
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_device_register);
>>> -
>>> -/**
>>> - * thermal_device_unregister - removes the registered thermal zone device
>>> - * @tz: the thermal zone device to remove
>>> - */
>>> -void thermal_zone_device_unregister(struct thermal_zone_device *tz)
>>> -{
>>> -	int i;
>>> -	const struct thermal_zone_params *tzp;
>>> -	struct thermal_cooling_device *cdev;
>>> -	struct thermal_zone_device *pos = NULL;
>>> -
>>> -	if (!tz)
>>> -		return;
>>> -
>>> -	tzp = tz->tzp;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_for_each_entry(pos, &thermal_tz_list, node)
>>> -	    if (pos == tz)
>>> -		break;
>>> -	if (pos != tz) {
>>> -		/* thermal zone device not found */
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		return;
>>> -	}
>>> -	list_del(&tz->node);
>>> -
>>> -	/* Unbind all cdevs associated with 'this' thermal zone */
>>> -	list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> -		if (tz->ops->unbind) {
>>> -			tz->ops->unbind(tz, cdev);
>>> -			continue;
>>> -		}
>>> -
>>> -		if (!tzp || !tzp->tbp)
>>> -			break;
>>> -
>>> -		for (i = 0; i < tzp->num_tbps; i++) {
>>> -			if (tzp->tbp[i].cdev == cdev) {
>>> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
>>> -				tzp->tbp[i].cdev = NULL;
>>> -			}
>>> -		}
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	thermal_zone_device_set_polling(tz, 0);
>>> -
>>> -	if (tz->type[0])
>>> -		device_remove_file(&tz->device, &dev_attr_type);
>>> -	device_remove_file(&tz->device, &dev_attr_temp);
>>> -	if (tz->ops->get_mode)
>>> -		device_remove_file(&tz->device, &dev_attr_mode);
>>> -	device_remove_file(&tz->device, &dev_attr_policy);
>>> -	remove_trip_attrs(tz);
>>> -	tz->governor = NULL;
>>> -
>>> -	thermal_remove_hwmon_sysfs(tz);
>>> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> -	idr_destroy(&tz->idr);
>>> -	mutex_destroy(&tz->lock);
>>> -	device_unregister(&tz->device);
>>> -	return;
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_device_unregister);
>>> -
>>> -#ifdef CONFIG_NET
>>> -static struct genl_family thermal_event_genl_family = {
>>> -	.id = GENL_ID_GENERATE,
>>> -	.name = THERMAL_GENL_FAMILY_NAME,
>>> -	.version = THERMAL_GENL_VERSION,
>>> -	.maxattr = THERMAL_GENL_ATTR_MAX,
>>> -};
>>> -
>>> -static struct genl_multicast_group thermal_event_mcgrp = {
>>> -	.name = THERMAL_GENL_MCAST_GROUP_NAME,
>>> -};
>>> -
>>> -int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>>> -					enum events event)
>>> -{
>>> -	struct sk_buff *skb;
>>> -	struct nlattr *attr;
>>> -	struct thermal_genl_event *thermal_event;
>>> -	void *msg_header;
>>> -	int size;
>>> -	int result;
>>> -	static unsigned int thermal_event_seqnum;
>>> -
>>> -	if (!tz)
>>> -		return -EINVAL;
>>> -
>>> -	/* allocate memory */
>>> -	size = nla_total_size(sizeof(struct thermal_genl_event)) +
>>> -	       nla_total_size(0);
>>> -
>>> -	skb = genlmsg_new(size, GFP_ATOMIC);
>>> -	if (!skb)
>>> -		return -ENOMEM;
>>> -
>>> -	/* add the genetlink message header */
>>> -	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
>>> -				 &thermal_event_genl_family, 0,
>>> -				 THERMAL_GENL_CMD_EVENT);
>>> -	if (!msg_header) {
>>> -		nlmsg_free(skb);
>>> -		return -ENOMEM;
>>> -	}
>>> -
>>> -	/* fill the data */
>>> -	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
>>> -			   sizeof(struct thermal_genl_event));
>>> -
>>> -	if (!attr) {
>>> -		nlmsg_free(skb);
>>> -		return -EINVAL;
>>> -	}
>>> -
>>> -	thermal_event = nla_data(attr);
>>> -	if (!thermal_event) {
>>> -		nlmsg_free(skb);
>>> -		return -EINVAL;
>>> -	}
>>> -
>>> -	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
>>> -
>>> -	thermal_event->orig = tz->id;
>>> -	thermal_event->event = event;
>>> -
>>> -	/* send multicast genetlink message */
>>> -	result = genlmsg_end(skb, msg_header);
>>> -	if (result < 0) {
>>> -		nlmsg_free(skb);
>>> -		return result;
>>> -	}
>>> -
>>> -	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
>>> -	if (result)
>>> -		dev_err(&tz->device, "Failed to send netlink event:%d", result);
>>> -
>>> -	return result;
>>> -}
>>> -EXPORT_SYMBOL(thermal_generate_netlink_event);
>>> -
>>> -static int genetlink_init(void)
>>> -{
>>> -	int result;
>>> -
>>> -	result = genl_register_family(&thermal_event_genl_family);
>>> -	if (result)
>>> -		return result;
>>> -
>>> -	result = genl_register_mc_group(&thermal_event_genl_family,
>>> -					&thermal_event_mcgrp);
>>> -	if (result)
>>> -		genl_unregister_family(&thermal_event_genl_family);
>>> -	return result;
>>> -}
>>> -
>>> -static void genetlink_exit(void)
>>> -{
>>> -	genl_unregister_family(&thermal_event_genl_family);
>>> -}
>>> -#else /* !CONFIG_NET */
>>> -static inline int genetlink_init(void) { return 0; }
>>> -static inline void genetlink_exit(void) {}
>>> -#endif /* !CONFIG_NET */
>>> -
>>> -static int __init thermal_init(void)
>>> -{
>>> -	int result = 0;
>>> -
>>> -	result = class_register(&thermal_class);
>>> -	if (result) {
>>> -		idr_destroy(&thermal_tz_idr);
>>> -		idr_destroy(&thermal_cdev_idr);
>>> -		mutex_destroy(&thermal_idr_lock);
>>> -		mutex_destroy(&thermal_list_lock);
>>> -		return result;
>>> -	}
>>> -	result = genetlink_init();
>>> -	return result;
>>> -}
>>> -
>>> -static void __exit thermal_exit(void)
>>> -{
>>> -	class_unregister(&thermal_class);
>>> -	idr_destroy(&thermal_tz_idr);
>>> -	idr_destroy(&thermal_cdev_idr);
>>> -	mutex_destroy(&thermal_idr_lock);
>>> -	mutex_destroy(&thermal_list_lock);
>>> -	genetlink_exit();
>>> -}
>>> -
>>> -fs_initcall(thermal_init);
>>> -module_exit(thermal_exit);
>>>
>>
>
>
>
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFC,1/5] Thermal: rename thermal_sys.c to thermal_core.c
@ 2013-04-01 12:43         ` Eduardo Valentin
  0 siblings, 0 replies; 23+ messages in thread
From: Eduardo Valentin @ 2013-04-01 12:43 UTC (permalink / raw)
  To: Zhang Rui; +Cc: linux-pm, linux-kernel, amit.daniel, durgadoss.r, andi

Hey Rui,

On 27-03-2013 22:40, Zhang Rui wrote:
> On Tue, 2013-03-26 at 18:04 -0400, Eduardo Valentin wrote:
>> Hi Rui,
>>
>> A side note:
>> I'd really appreciate if you could copy on your patches on
>> drivers/thermal/. I had some issues with TI server and got un subscribed
>> from linux-pm. Now I will try to catch up any way,
>>
> sure.
>
>> Some comments.
>>
>> On 26-03-2013 12:26, Zhang Rui wrote:
>>> No functional change in this patch.
>>>
>>
>> Just a better description would also help on code version control.
>>
> will add it in V2.
>
>>> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
>>
>> Apart from minor comments, I agreed with this change. So feel free to
>> add my:
>>
>> Acked-by: Eduardo Valentin <eduardo.valentin@ti.com>
>>
> thanks!
>
>>>
>>> ---
>>> drivers/thermal/Makefile       |    1 +
>>>    drivers/thermal/thermal_core.c | 1888 ++++++++++++++++++++++++++++++++++++++++
>>>    drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------
>>
>> When sending renames, use git format-patch --find-renames, it makes a
>> better summary of what you have done, specially if you have changed
>> something in the file while renaming.
>>
> a useful tip. thanks!
>>>    3 files changed, 1889 insertions(+), 1888 deletions(-)
>>>    create mode 100644 drivers/thermal/thermal_core.c
>>>    delete mode 100644 drivers/thermal/thermal_sys.c
>>>
>>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
>>> index d3a2b38..b2009bd 100644
>>> --- a/drivers/thermal/Makefile
>>> +++ b/drivers/thermal/Makefile
>>> @@ -3,6 +3,7 @@
>>>    #
>>>
>>>    obj-$(CONFIG_THERMAL)		+= thermal_sys.o
>>
>> I know this is for fixing the annoying bug with fan max speed. But while
>> still here, do you think 'thermal_sys' is a good name for thermal
>> framework driver? Maybe just 'thermal' would suffice?
>>
> as I said, there is already a thermal driver, aka,
> driver/acpi/thermal.c.
>

In fact there is. On the other hand, it does not imply that this naming 
convention is correct, right?

Unless you have a strong requirement to name these drivers the way it 
is, I'd suggest to take the opportunity to rename them. 
drivers/acpi/thermal.c could be named 'thermal-acpi.ko', if this does 
not violate any ACPI requirements. While this driver, 
drivers/thermal/thermal_sys.c, would be named only 'thermal.ko'.


> thanks,

Regards,

Ed

> rui
>>> +thermal_sys-y			+= thermal_core.o
>>>
>>>    # governors
>>>    obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
>>> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
>>> new file mode 100644
>>> index 0000000..5b7863a
>>> --- /dev/null
>>> +++ b/drivers/thermal/thermal_core.c
>>> @@ -0,0 +1,1888 @@
>>> +/*
>>> + *  thermal.c - Generic Thermal Management Sysfs support.
>>> + *
>>> + *  Copyright (C) 2008 Intel Corp
>>> + *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
>>> + *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
>>> + *
>>> + *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> + *
>>> + *  This program is free software; you can redistribute it and/or modify
>>> + *  it under the terms of the GNU General Public License as published by
>>> + *  the Free Software Foundation; version 2 of the License.
>>> + *
>>> + *  This program is distributed in the hope that it will be useful, but
>>> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
>>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> + *  General Public License for more details.
>>> + *
>>> + *  You should have received a copy of the GNU General Public License along
>>> + *  with this program; if not, write to the Free Software Foundation, Inc.,
>>> + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
>>> + *
>>> + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> + */
>>> +
>>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>> +
>>> +#include <linux/module.h>
>>> +#include <linux/device.h>
>>> +#include <linux/err.h>
>>> +#include <linux/slab.h>
>>> +#include <linux/kdev_t.h>
>>> +#include <linux/idr.h>
>>> +#include <linux/thermal.h>
>>> +#include <linux/reboot.h>
>>> +#include <net/netlink.h>
>>> +#include <net/genetlink.h>
>>> +
>>> +#include "thermal_core.h"
>>> +
>>> +MODULE_AUTHOR("Zhang Rui");
>>> +MODULE_DESCRIPTION("Generic thermal management sysfs support");
>>> +MODULE_LICENSE("GPL");
>>> +
>>> +static DEFINE_IDR(thermal_tz_idr);
>>> +static DEFINE_IDR(thermal_cdev_idr);
>>> +static DEFINE_MUTEX(thermal_idr_lock);
>>> +
>>> +static LIST_HEAD(thermal_tz_list);
>>> +static LIST_HEAD(thermal_cdev_list);
>>> +static LIST_HEAD(thermal_governor_list);
>>> +
>>> +static DEFINE_MUTEX(thermal_list_lock);
>>> +static DEFINE_MUTEX(thermal_governor_lock);
>>> +
>>> +static struct thermal_governor *__find_governor(const char *name)
>>> +{
>>> +	struct thermal_governor *pos;
>>> +
>>> +	list_for_each_entry(pos, &thermal_governor_list, governor_list)
>>> +		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
>>> +			return pos;
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +int thermal_register_governor(struct thermal_governor *governor)
>>> +{
>>> +	int err;
>>> +	const char *name;
>>> +	struct thermal_zone_device *pos;
>>> +
>>> +	if (!governor)
>>> +		return -EINVAL;
>>> +
>>> +	mutex_lock(&thermal_governor_lock);
>>> +
>>> +	err = -EBUSY;
>>> +	if (__find_governor(governor->name) == NULL) {
>>> +		err = 0;
>>> +		list_add(&governor->governor_list, &thermal_governor_list);
>>> +	}
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +
>>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> +		if (pos->governor)
>>> +			continue;
>>> +		if (pos->tzp)
>>> +			name = pos->tzp->governor_name;
>>> +		else
>>> +			name = DEFAULT_THERMAL_GOVERNOR;
>>> +		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
>>> +			pos->governor = governor;
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +	mutex_unlock(&thermal_governor_lock);
>>> +
>>> +	return err;
>>> +}
>>> +EXPORT_SYMBOL_GPL(thermal_register_governor);
>>> +
>>> +void thermal_unregister_governor(struct thermal_governor *governor)
>>> +{
>>> +	struct thermal_zone_device *pos;
>>> +
>>> +	if (!governor)
>>> +		return;
>>> +
>>> +	mutex_lock(&thermal_governor_lock);
>>> +
>>> +	if (__find_governor(governor->name) == NULL)
>>> +		goto exit;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +
>>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> +		if (!strnicmp(pos->governor->name, governor->name,
>>> +						THERMAL_NAME_LENGTH))
>>> +			pos->governor = NULL;
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +	list_del(&governor->governor_list);
>>> +exit:
>>> +	mutex_unlock(&thermal_governor_lock);
>>> +	return;
>>> +}
>>> +EXPORT_SYMBOL_GPL(thermal_unregister_governor);
>>> +
>>> +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
>>> +{
>>> +	int ret;
>>> +
>>> +	if (lock)
>>> +		mutex_lock(lock);
>>> +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
>>> +	if (lock)
>>> +		mutex_unlock(lock);
>>> +	if (unlikely(ret < 0))
>>> +		return ret;
>>> +	*id = ret;
>>> +	return 0;
>>> +}
>>> +
>>> +static void release_idr(struct idr *idr, struct mutex *lock, int id)
>>> +{
>>> +	if (lock)
>>> +		mutex_lock(lock);
>>> +	idr_remove(idr, id);
>>> +	if (lock)
>>> +		mutex_unlock(lock);
>>> +}
>>> +
>>> +int get_tz_trend(struct thermal_zone_device *tz, int trip)
>>> +{
>>> +	enum thermal_trend trend;
>>> +
>>> +	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
>>> +		if (tz->temperature > tz->last_temperature)
>>> +			trend = THERMAL_TREND_RAISING;
>>> +		else if (tz->temperature < tz->last_temperature)
>>> +			trend = THERMAL_TREND_DROPPING;
>>> +		else
>>> +			trend = THERMAL_TREND_STABLE;
>>> +	}
>>> +
>>> +	return trend;
>>> +}
>>> +EXPORT_SYMBOL(get_tz_trend);
>>> +
>>> +struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
>>> +			struct thermal_cooling_device *cdev, int trip)
>>> +{
>>> +	struct thermal_instance *pos = NULL;
>>> +	struct thermal_instance *target_instance = NULL;
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +	mutex_lock(&cdev->lock);
>>> +
>>> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
>>> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> +			target_instance = pos;
>>> +			break;
>>> +		}
>>> +	}
>>> +
>>> +	mutex_unlock(&cdev->lock);
>>> +	mutex_unlock(&tz->lock);
>>> +
>>> +	return target_instance;
>>> +}
>>> +EXPORT_SYMBOL(get_thermal_instance);
>>> +
>>> +static void print_bind_err_msg(struct thermal_zone_device *tz,
>>> +			struct thermal_cooling_device *cdev, int ret)
>>> +{
>>> +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>>> +				tz->type, cdev->type, ret);
>>> +}
>>> +
>>> +static void __bind(struct thermal_zone_device *tz, int mask,
>>> +			struct thermal_cooling_device *cdev)
>>> +{
>>> +	int i, ret;
>>> +
>>> +	for (i = 0; i < tz->trips; i++) {
>>> +		if (mask & (1 << i)) {
>>> +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
>>> +					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
>>> +			if (ret)
>>> +				print_bind_err_msg(tz, cdev, ret);
>>> +		}
>>> +	}
>>> +}
>>> +
>>> +static void __unbind(struct thermal_zone_device *tz, int mask,
>>> +			struct thermal_cooling_device *cdev)
>>> +{
>>> +	int i;
>>> +
>>> +	for (i = 0; i < tz->trips; i++)
>>> +		if (mask & (1 << i))
>>> +			thermal_zone_unbind_cooling_device(tz, i, cdev);
>>> +}
>>> +
>>> +static void bind_cdev(struct thermal_cooling_device *cdev)
>>> +{
>>> +	int i, ret;
>>> +	const struct thermal_zone_params *tzp;
>>> +	struct thermal_zone_device *pos = NULL;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +
>>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> +		if (!pos->tzp && !pos->ops->bind)
>>> +			continue;
>>> +
>>> +		if (!pos->tzp && pos->ops->bind) {
>>> +			ret = pos->ops->bind(pos, cdev);
>>> +			if (ret)
>>> +				print_bind_err_msg(pos, cdev, ret);
>>> +		}
>>> +
>>> +		tzp = pos->tzp;
>>> +		if (!tzp || !tzp->tbp)
>>> +			continue;
>>> +
>>> +		for (i = 0; i < tzp->num_tbps; i++) {
>>> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
>>> +				continue;
>>> +			if (tzp->tbp[i].match(pos, cdev))
>>> +				continue;
>>> +			tzp->tbp[i].cdev = cdev;
>>> +			__bind(pos, tzp->tbp[i].trip_mask, cdev);
>>> +		}
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +}
>>> +
>>> +static void bind_tz(struct thermal_zone_device *tz)
>>> +{
>>> +	int i, ret;
>>> +	struct thermal_cooling_device *pos = NULL;
>>> +	const struct thermal_zone_params *tzp = tz->tzp;
>>> +
>>> +	if (!tzp && !tz->ops->bind)
>>> +		return;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +
>>> +	/* If there is no platform data, try to use ops->bind */
>>> +	if (!tzp && tz->ops->bind) {
>>> +		list_for_each_entry(pos, &thermal_cdev_list, node) {
>>> +			ret = tz->ops->bind(tz, pos);
>>> +			if (ret)
>>> +				print_bind_err_msg(tz, pos, ret);
>>> +		}
>>> +		goto exit;
>>> +	}
>>> +
>>> +	if (!tzp || !tzp->tbp)
>>> +		goto exit;
>>> +
>>> +	list_for_each_entry(pos, &thermal_cdev_list, node) {
>>> +		for (i = 0; i < tzp->num_tbps; i++) {
>>> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
>>> +				continue;
>>> +			if (tzp->tbp[i].match(tz, pos))
>>> +				continue;
>>> +			tzp->tbp[i].cdev = pos;
>>> +			__bind(tz, tzp->tbp[i].trip_mask, pos);
>>> +		}
>>> +	}
>>> +exit:
>>> +	mutex_unlock(&thermal_list_lock);
>>> +}
>>> +
>>> +static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
>>> +					    int delay)
>>> +{
>>> +	if (delay > 1000)
>>> +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
>>> +				 round_jiffies(msecs_to_jiffies(delay)));
>>> +	else if (delay)
>>> +		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
>>> +				 msecs_to_jiffies(delay));
>>> +	else
>>> +		cancel_delayed_work(&tz->poll_queue);
>>> +}
>>> +
>>> +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);
>>> +	else if (tz->polling_delay)
>>> +		thermal_zone_device_set_polling(tz, tz->polling_delay);
>>> +	else
>>> +		thermal_zone_device_set_polling(tz, 0);
>>> +
>>> +	mutex_unlock(&tz->lock);
>>> +}
>>> +
>>> +static void handle_non_critical_trips(struct thermal_zone_device *tz,
>>> +			int trip, enum thermal_trip_type trip_type)
>>> +{
>>> +	if (tz->governor)
>>> +		tz->governor->throttle(tz, trip);
>>> +}
>>> +
>>> +static void handle_critical_trips(struct thermal_zone_device *tz,
>>> +				int trip, enum thermal_trip_type trip_type)
>>> +{
>>> +	long trip_temp;
>>> +
>>> +	tz->ops->get_trip_temp(tz, trip, &trip_temp);
>>> +
>>> +	/* If we have not crossed the trip_temp, we do not care. */
>>> +	if (tz->temperature < trip_temp)
>>> +		return;
>>> +
>>> +	if (tz->ops->notify)
>>> +		tz->ops->notify(tz, trip, trip_type);
>>> +
>>> +	if (trip_type == THERMAL_TRIP_CRITICAL) {
>>> +		dev_emerg(&tz->device,
>>> +			  "critical temperature reached(%d C),shutting down\n",
>>> +			  tz->temperature / 1000);
>>> +		orderly_poweroff(true);
>>> +	}
>>> +}
>>> +
>>> +static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
>>> +{
>>> +	enum thermal_trip_type type;
>>> +
>>> +	tz->ops->get_trip_type(tz, trip, &type);
>>> +
>>> +	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
>>> +		handle_critical_trips(tz, trip, type);
>>> +	else
>>> +		handle_non_critical_trips(tz, trip, type);
>>> +	/*
>>> +	 * Alright, we handled this trip successfully.
>>> +	 * So, start monitoring again.
>>> +	 */
>>> +	monitor_thermal_zone(tz);
>>> +}
>>> +
>>> +static int thermal_zone_get_temp(struct thermal_zone_device *tz,
>>> +				unsigned long *temp)
>>> +{
>>> +	int ret = 0;
>>> +#ifdef CONFIG_THERMAL_EMULATION
>>> +	int count;
>>> +	unsigned long crit_temp = -1UL;
>>> +	enum thermal_trip_type type;
>>> +#endif
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +
>>> +	ret = tz->ops->get_temp(tz, temp);
>>> +#ifdef CONFIG_THERMAL_EMULATION
>>> +	if (!tz->emul_temperature)
>>> +		goto skip_emul;
>>> +
>>> +	for (count = 0; count < tz->trips; count++) {
>>> +		ret = tz->ops->get_trip_type(tz, count, &type);
>>> +		if (!ret && type == THERMAL_TRIP_CRITICAL) {
>>> +			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
>>> +			break;
>>> +		}
>>> +	}
>>> +
>>> +	if (ret)
>>> +		goto skip_emul;
>>> +
>>> +	if (*temp < crit_temp)
>>> +		*temp = tz->emul_temperature;
>>> +skip_emul:
>>> +#endif
>>> +	mutex_unlock(&tz->lock);
>>> +	return ret;
>>> +}
>>> +
>>> +static void update_temperature(struct thermal_zone_device *tz)
>>> +{
>>> +	long temp;
>>> +	int ret;
>>> +
>>> +	ret = thermal_zone_get_temp(tz, &temp);
>>> +	if (ret) {
>>> +		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
>>> +			 tz->id);
>>> +		return;
>>> +	}
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +	tz->last_temperature = tz->temperature;
>>> +	tz->temperature = temp;
>>> +	mutex_unlock(&tz->lock);
>>> +}
>>> +
>>> +void thermal_zone_device_update(struct thermal_zone_device *tz)
>>> +{
>>> +	int count;
>>> +
>>> +	update_temperature(tz);
>>> +
>>> +	for (count = 0; count < tz->trips; count++)
>>> +		handle_thermal_trip(tz, count);
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_device_update);
>>> +
>>> +static void thermal_zone_device_check(struct work_struct *work)
>>> +{
>>> +	struct thermal_zone_device *tz = container_of(work, struct
>>> +						      thermal_zone_device,
>>> +						      poll_queue.work);
>>> +	thermal_zone_device_update(tz);
>>> +}
>>> +
>>> +/* sys I/F for thermal zone */
>>> +
>>> +#define to_thermal_zone(_dev) \
>>> +	container_of(_dev, struct thermal_zone_device, device)
>>> +
>>> +static ssize_t
>>> +type_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +
>>> +	return sprintf(buf, "%s\n", tz->type);
>>> +}
>>> +
>>> +static ssize_t
>>> +temp_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	long temperature;
>>> +	int ret;
>>> +
>>> +	ret = thermal_zone_get_temp(tz, &temperature);
>>> +
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +static ssize_t
>>> +mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	enum thermal_device_mode mode;
>>> +	int result;
>>> +
>>> +	if (!tz->ops->get_mode)
>>> +		return -EPERM;
>>> +
>>> +	result = tz->ops->get_mode(tz, &mode);
>>> +	if (result)
>>> +		return result;
>>> +
>>> +	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
>>> +		       : "disabled");
>>> +}
>>> +
>>> +static ssize_t
>>> +mode_store(struct device *dev, struct device_attribute *attr,
>>> +	   const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int result;
>>> +
>>> +	if (!tz->ops->set_mode)
>>> +		return -EPERM;
>>> +
>>> +	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);
>>> +	else
>>> +		result = -EINVAL;
>>> +
>>> +	if (result)
>>> +		return result;
>>> +
>>> +	return count;
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_type_show(struct device *dev, struct device_attribute *attr,
>>> +		     char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	enum thermal_trip_type type;
>>> +	int trip, result;
>>> +
>>> +	if (!tz->ops->get_trip_type)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	result = tz->ops->get_trip_type(tz, trip, &type);
>>> +	if (result)
>>> +		return result;
>>> +
>>> +	switch (type) {
>>> +	case THERMAL_TRIP_CRITICAL:
>>> +		return sprintf(buf, "critical\n");
>>> +	case THERMAL_TRIP_HOT:
>>> +		return sprintf(buf, "hot\n");
>>> +	case THERMAL_TRIP_PASSIVE:
>>> +		return sprintf(buf, "passive\n");
>>> +	case THERMAL_TRIP_ACTIVE:
>>> +		return sprintf(buf, "active\n");
>>> +	default:
>>> +		return sprintf(buf, "unknown\n");
>>> +	}
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_temp_store(struct device *dev, struct device_attribute *attr,
>>> +		     const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int trip, ret;
>>> +	unsigned long temperature;
>>> +
>>> +	if (!tz->ops->set_trip_temp)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	if (kstrtoul(buf, 10, &temperature))
>>> +		return -EINVAL;
>>> +
>>> +	ret = tz->ops->set_trip_temp(tz, trip, temperature);
>>> +
>>> +	return ret ? ret : count;
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_temp_show(struct device *dev, struct device_attribute *attr,
>>> +		     char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int trip, ret;
>>> +	long temperature;
>>> +
>>> +	if (!tz->ops->get_trip_temp)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
>>> +
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
>>> +			const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int trip, ret;
>>> +	unsigned long temperature;
>>> +
>>> +	if (!tz->ops->set_trip_hyst)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	if (kstrtoul(buf, 10, &temperature))
>>> +		return -EINVAL;
>>> +
>>> +	/*
>>> +	 * We are not doing any check on the 'temperature' value
>>> +	 * here. The driver implementing 'set_trip_hyst' has to
>>> +	 * take care of this.
>>> +	 */
>>> +	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
>>> +
>>> +	return ret ? ret : count;
>>> +}
>>> +
>>> +static ssize_t
>>> +trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
>>> +			char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int trip, ret;
>>> +	unsigned long temperature;
>>> +
>>> +	if (!tz->ops->get_trip_hyst)
>>> +		return -EPERM;
>>> +
>>> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
>>> +		return -EINVAL;
>>> +
>>> +	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
>>> +
>>> +	return ret ? ret : sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +static ssize_t
>>> +passive_store(struct device *dev, struct device_attribute *attr,
>>> +		    const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	struct thermal_cooling_device *cdev = NULL;
>>> +	int state;
>>> +
>>> +	if (!sscanf(buf, "%d\n", &state))
>>> +		return -EINVAL;
>>> +
>>> +	/* sanity check: values below 1000 millicelcius don't make sense
>>> +	 * and can cause the system to go into a thermal heart attack
>>> +	 */
>>> +	if (state && state < 1000)
>>> +		return -EINVAL;
>>> +
>>> +	if (state && !tz->forced_passive) {
>>> +		mutex_lock(&thermal_list_lock);
>>> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> +			if (!strncmp("Processor", cdev->type,
>>> +				     sizeof("Processor")))
>>> +				thermal_zone_bind_cooling_device(tz,
>>> +						THERMAL_TRIPS_NONE, cdev,
>>> +						THERMAL_NO_LIMIT,
>>> +						THERMAL_NO_LIMIT);
>>> +		}
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		if (!tz->passive_delay)
>>> +			tz->passive_delay = 1000;
>>> +	} else if (!state && tz->forced_passive) {
>>> +		mutex_lock(&thermal_list_lock);
>>> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> +			if (!strncmp("Processor", cdev->type,
>>> +				     sizeof("Processor")))
>>> +				thermal_zone_unbind_cooling_device(tz,
>>> +								   THERMAL_TRIPS_NONE,
>>> +								   cdev);
>>> +		}
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		tz->passive_delay = 0;
>>> +	}
>>> +
>>> +	tz->forced_passive = state;
>>> +
>>> +	thermal_zone_device_update(tz);
>>> +
>>> +	return count;
>>> +}
>>> +
>>> +static ssize_t
>>> +passive_show(struct device *dev, struct device_attribute *attr,
>>> +		   char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +
>>> +	return sprintf(buf, "%d\n", tz->forced_passive);
>>> +}
>>> +
>>> +static ssize_t
>>> +policy_store(struct device *dev, struct device_attribute *attr,
>>> +		    const char *buf, size_t count)
>>> +{
>>> +	int ret = -EINVAL;
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	struct thermal_governor *gov;
>>> +
>>> +	mutex_lock(&thermal_governor_lock);
>>> +
>>> +	gov = __find_governor(buf);
>>> +	if (!gov)
>>> +		goto exit;
>>> +
>>> +	tz->governor = gov;
>>> +	ret = count;
>>> +
>>> +exit:
>>> +	mutex_unlock(&thermal_governor_lock);
>>> +	return ret;
>>> +}
>>> +
>>> +static ssize_t
>>> +policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +
>>> +	return sprintf(buf, "%s\n", tz->governor->name);
>>> +}
>>> +
>>> +#ifdef CONFIG_THERMAL_EMULATION
>>> +static ssize_t
>>> +emul_temp_store(struct device *dev, struct device_attribute *attr,
>>> +		     const char *buf, size_t count)
>>> +{
>>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> +	int ret = 0;
>>> +	unsigned long temperature;
>>> +
>>> +	if (kstrtoul(buf, 10, &temperature))
>>> +		return -EINVAL;
>>> +
>>> +	if (!tz->ops->set_emul_temp) {
>>> +		mutex_lock(&tz->lock);
>>> +		tz->emul_temperature = temperature;
>>> +		mutex_unlock(&tz->lock);
>>> +	} else {
>>> +		ret = tz->ops->set_emul_temp(tz, temperature);
>>> +	}
>>> +
>>> +	return ret ? ret : count;
>>> +}
>>> +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
>>> +#endif/*CONFIG_THERMAL_EMULATION*/
>>> +
>>> +static DEVICE_ATTR(type, 0444, type_show, NULL);
>>> +static DEVICE_ATTR(temp, 0444, temp_show, NULL);
>>> +static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
>>> +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
>>> +static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
>>> +
>>> +/* sys I/F for cooling device */
>>> +#define to_cooling_device(_dev)	\
>>> +	container_of(_dev, struct thermal_cooling_device, device)
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_type_show(struct device *dev,
>>> +				 struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> +
>>> +	return sprintf(buf, "%s\n", cdev->type);
>>> +}
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_max_state_show(struct device *dev,
>>> +				      struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> +	unsigned long state;
>>> +	int ret;
>>> +
>>> +	ret = cdev->ops->get_max_state(cdev, &state);
>>> +	if (ret)
>>> +		return ret;
>>> +	return sprintf(buf, "%ld\n", state);
>>> +}
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_cur_state_show(struct device *dev,
>>> +				      struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> +	unsigned long state;
>>> +	int ret;
>>> +
>>> +	ret = cdev->ops->get_cur_state(cdev, &state);
>>> +	if (ret)
>>> +		return ret;
>>> +	return sprintf(buf, "%ld\n", state);
>>> +}
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_cur_state_store(struct device *dev,
>>> +				       struct device_attribute *attr,
>>> +				       const char *buf, size_t count)
>>> +{
>>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> +	unsigned long state;
>>> +	int result;
>>> +
>>> +	if (!sscanf(buf, "%ld\n", &state))
>>> +		return -EINVAL;
>>> +
>>> +	if ((long)state < 0)
>>> +		return -EINVAL;
>>> +
>>> +	result = cdev->ops->set_cur_state(cdev, state);
>>> +	if (result)
>>> +		return result;
>>> +	return count;
>>> +}
>>> +
>>> +static struct device_attribute dev_attr_cdev_type =
>>> +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
>>> +static DEVICE_ATTR(max_state, 0444,
>>> +		   thermal_cooling_device_max_state_show, NULL);
>>> +static DEVICE_ATTR(cur_state, 0644,
>>> +		   thermal_cooling_device_cur_state_show,
>>> +		   thermal_cooling_device_cur_state_store);
>>> +
>>> +static ssize_t
>>> +thermal_cooling_device_trip_point_show(struct device *dev,
>>> +				       struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_instance *instance;
>>> +
>>> +	instance =
>>> +	    container_of(attr, struct thermal_instance, attr);
>>> +
>>> +	if (instance->trip == THERMAL_TRIPS_NONE)
>>> +		return sprintf(buf, "-1\n");
>>> +	else
>>> +		return sprintf(buf, "%d\n", instance->trip);
>>> +}
>>> +
>>> +/* Device management */
>>> +
>>> +#if defined(CONFIG_THERMAL_HWMON)
>>> +
>>> +/* hwmon sys I/F */
>>> +#include <linux/hwmon.h>
>>> +
>>> +/* thermal zone devices with the same type share one hwmon device */
>>> +struct thermal_hwmon_device {
>>> +	char type[THERMAL_NAME_LENGTH];
>>> +	struct device *device;
>>> +	int count;
>>> +	struct list_head tz_list;
>>> +	struct list_head node;
>>> +};
>>> +
>>> +struct thermal_hwmon_attr {
>>> +	struct device_attribute attr;
>>> +	char name[16];
>>> +};
>>> +
>>> +/* one temperature input for each thermal zone */
>>> +struct thermal_hwmon_temp {
>>> +	struct list_head hwmon_node;
>>> +	struct thermal_zone_device *tz;
>>> +	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
>>> +	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
>>> +};
>>> +
>>> +static LIST_HEAD(thermal_hwmon_list);
>>> +
>>> +static ssize_t
>>> +name_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
>>> +	return sprintf(buf, "%s\n", hwmon->type);
>>> +}
>>> +static DEVICE_ATTR(name, 0444, name_show, NULL);
>>> +
>>> +static ssize_t
>>> +temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> +{
>>> +	long temperature;
>>> +	int ret;
>>> +	struct thermal_hwmon_attr *hwmon_attr
>>> +			= container_of(attr, struct thermal_hwmon_attr, attr);
>>> +	struct thermal_hwmon_temp *temp
>>> +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
>>> +				       temp_input);
>>> +	struct thermal_zone_device *tz = temp->tz;
>>> +
>>> +	ret = thermal_zone_get_temp(tz, &temperature);
>>> +
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +static ssize_t
>>> +temp_crit_show(struct device *dev, struct device_attribute *attr,
>>> +		char *buf)
>>> +{
>>> +	struct thermal_hwmon_attr *hwmon_attr
>>> +			= container_of(attr, struct thermal_hwmon_attr, attr);
>>> +	struct thermal_hwmon_temp *temp
>>> +			= container_of(hwmon_attr, struct thermal_hwmon_temp,
>>> +				       temp_crit);
>>> +	struct thermal_zone_device *tz = temp->tz;
>>> +	long temperature;
>>> +	int ret;
>>> +
>>> +	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
>>> +	if (ret)
>>> +		return ret;
>>> +
>>> +	return sprintf(buf, "%ld\n", temperature);
>>> +}
>>> +
>>> +
>>> +static struct thermal_hwmon_device *
>>> +thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
>>> +{
>>> +	struct thermal_hwmon_device *hwmon;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
>>> +		if (!strcmp(hwmon->type, tz->type)) {
>>> +			mutex_unlock(&thermal_list_lock);
>>> +			return hwmon;
>>> +		}
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +/* Find the temperature input matching a given thermal zone */
>>> +static struct thermal_hwmon_temp *
>>> +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
>>> +			  const struct thermal_zone_device *tz)
>>> +{
>>> +	struct thermal_hwmon_temp *temp;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
>>> +		if (temp->tz == tz) {
>>> +			mutex_unlock(&thermal_list_lock);
>>> +			return temp;
>>> +		}
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +static int
>>> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
>>> +{
>>> +	struct thermal_hwmon_device *hwmon;
>>> +	struct thermal_hwmon_temp *temp;
>>> +	int new_hwmon_device = 1;
>>> +	int result;
>>> +
>>> +	hwmon = thermal_hwmon_lookup_by_type(tz);
>>> +	if (hwmon) {
>>> +		new_hwmon_device = 0;
>>> +		goto register_sys_interface;
>>> +	}
>>> +
>>> +	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
>>> +	if (!hwmon)
>>> +		return -ENOMEM;
>>> +
>>> +	INIT_LIST_HEAD(&hwmon->tz_list);
>>> +	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
>>> +	hwmon->device = hwmon_device_register(NULL);
>>> +	if (IS_ERR(hwmon->device)) {
>>> +		result = PTR_ERR(hwmon->device);
>>> +		goto free_mem;
>>> +	}
>>> +	dev_set_drvdata(hwmon->device, hwmon);
>>> +	result = device_create_file(hwmon->device, &dev_attr_name);
>>> +	if (result)
>>> +		goto free_mem;
>>> +
>>> + register_sys_interface:
>>> +	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
>>> +	if (!temp) {
>>> +		result = -ENOMEM;
>>> +		goto unregister_name;
>>> +	}
>>> +
>>> +	temp->tz = tz;
>>> +	hwmon->count++;
>>> +
>>> +	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
>>> +		 "temp%d_input", hwmon->count);
>>> +	temp->temp_input.attr.attr.name = temp->temp_input.name;
>>> +	temp->temp_input.attr.attr.mode = 0444;
>>> +	temp->temp_input.attr.show = temp_input_show;
>>> +	sysfs_attr_init(&temp->temp_input.attr.attr);
>>> +	result = device_create_file(hwmon->device, &temp->temp_input.attr);
>>> +	if (result)
>>> +		goto free_temp_mem;
>>> +
>>> +	if (tz->ops->get_crit_temp) {
>>> +		unsigned long temperature;
>>> +		if (!tz->ops->get_crit_temp(tz, &temperature)) {
>>> +			snprintf(temp->temp_crit.name,
>>> +				 sizeof(temp->temp_crit.name),
>>> +				"temp%d_crit", hwmon->count);
>>> +			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
>>> +			temp->temp_crit.attr.attr.mode = 0444;
>>> +			temp->temp_crit.attr.show = temp_crit_show;
>>> +			sysfs_attr_init(&temp->temp_crit.attr.attr);
>>> +			result = device_create_file(hwmon->device,
>>> +						    &temp->temp_crit.attr);
>>> +			if (result)
>>> +				goto unregister_input;
>>> +		}
>>> +	}
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	if (new_hwmon_device)
>>> +		list_add_tail(&hwmon->node, &thermal_hwmon_list);
>>> +	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	return 0;
>>> +
>>> + unregister_input:
>>> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
>>> + free_temp_mem:
>>> +	kfree(temp);
>>> + unregister_name:
>>> +	if (new_hwmon_device) {
>>> +		device_remove_file(hwmon->device, &dev_attr_name);
>>> +		hwmon_device_unregister(hwmon->device);
>>> +	}
>>> + free_mem:
>>> +	if (new_hwmon_device)
>>> +		kfree(hwmon);
>>> +
>>> +	return result;
>>> +}
>>> +
>>> +static void
>>> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
>>> +{
>>> +	struct thermal_hwmon_device *hwmon;
>>> +	struct thermal_hwmon_temp *temp;
>>> +
>>> +	hwmon = thermal_hwmon_lookup_by_type(tz);
>>> +	if (unlikely(!hwmon)) {
>>> +		/* Should never happen... */
>>> +		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
>>> +		return;
>>> +	}
>>> +
>>> +	temp = thermal_hwmon_lookup_temp(hwmon, tz);
>>> +	if (unlikely(!temp)) {
>>> +		/* Should never happen... */
>>> +		dev_dbg(&tz->device, "temperature input lookup failed!\n");
>>> +		return;
>>> +	}
>>> +
>>> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
>>> +	if (tz->ops->get_crit_temp)
>>> +		device_remove_file(hwmon->device, &temp->temp_crit.attr);
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_del(&temp->hwmon_node);
>>> +	kfree(temp);
>>> +	if (!list_empty(&hwmon->tz_list)) {
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		return;
>>> +	}
>>> +	list_del(&hwmon->node);
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	device_remove_file(hwmon->device, &dev_attr_name);
>>> +	hwmon_device_unregister(hwmon->device);
>>> +	kfree(hwmon);
>>> +}
>>> +#else
>>> +static int
>>> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
>>> +{
>>> +	return 0;
>>> +}
>>> +
>>> +static void
>>> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
>>> +{
>>> +}
>>> +#endif
>>> +
>>> +/**
>>> + * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
>>> + * @tz:		thermal zone device
>>> + * @trip:	indicates which trip point the cooling devices is
>>> + *		associated with in this thermal zone.
>>> + * @cdev:	thermal cooling device
>>> + *
>>> + * This function is usually called in the thermal zone device .bind callback.
>>> + */
>>> +int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
>>> +				     int trip,
>>> +				     struct thermal_cooling_device *cdev,
>>> +				     unsigned long upper, unsigned long lower)
>>> +{
>>> +	struct thermal_instance *dev;
>>> +	struct thermal_instance *pos;
>>> +	struct thermal_zone_device *pos1;
>>> +	struct thermal_cooling_device *pos2;
>>> +	unsigned long max_state;
>>> +	int result;
>>> +
>>> +	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
>>> +		return -EINVAL;
>>> +
>>> +	list_for_each_entry(pos1, &thermal_tz_list, node) {
>>> +		if (pos1 == tz)
>>> +			break;
>>> +	}
>>> +	list_for_each_entry(pos2, &thermal_cdev_list, node) {
>>> +		if (pos2 == cdev)
>>> +			break;
>>> +	}
>>> +
>>> +	if (tz != pos1 || cdev != pos2)
>>> +		return -EINVAL;
>>> +
>>> +	cdev->ops->get_max_state(cdev, &max_state);
>>> +
>>> +	/* lower default 0, upper default max_state */
>>> +	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
>>> +	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
>>> +
>>> +	if (lower > upper || upper > max_state)
>>> +		return -EINVAL;
>>> +
>>> +	dev =
>>> +	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
>>> +	if (!dev)
>>> +		return -ENOMEM;
>>> +	dev->tz = tz;
>>> +	dev->cdev = cdev;
>>> +	dev->trip = trip;
>>> +	dev->upper = upper;
>>> +	dev->lower = lower;
>>> +	dev->target = THERMAL_NO_TARGET;
>>> +
>>> +	result = get_idr(&tz->idr, &tz->lock, &dev->id);
>>> +	if (result)
>>> +		goto free_mem;
>>> +
>>> +	sprintf(dev->name, "cdev%d", dev->id);
>>> +	result =
>>> +	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
>>> +	if (result)
>>> +		goto release_idr;
>>> +
>>> +	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
>>> +	sysfs_attr_init(&dev->attr.attr);
>>> +	dev->attr.attr.name = dev->attr_name;
>>> +	dev->attr.attr.mode = 0444;
>>> +	dev->attr.show = thermal_cooling_device_trip_point_show;
>>> +	result = device_create_file(&tz->device, &dev->attr);
>>> +	if (result)
>>> +		goto remove_symbol_link;
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +	mutex_lock(&cdev->lock);
>>> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
>>> +	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> +		result = -EEXIST;
>>> +		break;
>>> +	}
>>> +	if (!result) {
>>> +		list_add_tail(&dev->tz_node, &tz->thermal_instances);
>>> +		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
>>> +	}
>>> +	mutex_unlock(&cdev->lock);
>>> +	mutex_unlock(&tz->lock);
>>> +
>>> +	if (!result)
>>> +		return 0;
>>> +
>>> +	device_remove_file(&tz->device, &dev->attr);
>>> +remove_symbol_link:
>>> +	sysfs_remove_link(&tz->device.kobj, dev->name);
>>> +release_idr:
>>> +	release_idr(&tz->idr, &tz->lock, dev->id);
>>> +free_mem:
>>> +	kfree(dev);
>>> +	return result;
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
>>> +
>>> +/**
>>> + * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
>>> + * @tz:		thermal zone device
>>> + * @trip:	indicates which trip point the cooling devices is
>>> + *		associated with in this thermal zone.
>>> + * @cdev:	thermal cooling device
>>> + *
>>> + * This function is usually called in the thermal zone device .unbind callback.
>>> + */
>>> +int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
>>> +				       int trip,
>>> +				       struct thermal_cooling_device *cdev)
>>> +{
>>> +	struct thermal_instance *pos, *next;
>>> +
>>> +	mutex_lock(&tz->lock);
>>> +	mutex_lock(&cdev->lock);
>>> +	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
>>> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> +			list_del(&pos->tz_node);
>>> +			list_del(&pos->cdev_node);
>>> +			mutex_unlock(&cdev->lock);
>>> +			mutex_unlock(&tz->lock);
>>> +			goto unbind;
>>> +		}
>>> +	}
>>> +	mutex_unlock(&cdev->lock);
>>> +	mutex_unlock(&tz->lock);
>>> +
>>> +	return -ENODEV;
>>> +
>>> +unbind:
>>> +	device_remove_file(&tz->device, &pos->attr);
>>> +	sysfs_remove_link(&tz->device.kobj, pos->name);
>>> +	release_idr(&tz->idr, &tz->lock, pos->id);
>>> +	kfree(pos);
>>> +	return 0;
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
>>> +
>>> +static void thermal_release(struct device *dev)
>>> +{
>>> +	struct thermal_zone_device *tz;
>>> +	struct thermal_cooling_device *cdev;
>>> +
>>> +	if (!strncmp(dev_name(dev), "thermal_zone",
>>> +		     sizeof("thermal_zone") - 1)) {
>>> +		tz = to_thermal_zone(dev);
>>> +		kfree(tz);
>>> +	} else {
>>> +		cdev = to_cooling_device(dev);
>>> +		kfree(cdev);
>>> +	}
>>> +}
>>> +
>>> +static struct class thermal_class = {
>>> +	.name = "thermal",
>>> +	.dev_release = thermal_release,
>>> +};
>>> +
>>> +/**
>>> + * thermal_cooling_device_register - register a new thermal cooling device
>>> + * @type:	the thermal cooling device type.
>>> + * @devdata:	device private data.
>>> + * @ops:		standard thermal cooling devices callbacks.
>>> + */
>>> +struct thermal_cooling_device *
>>> +thermal_cooling_device_register(char *type, void *devdata,
>>> +				const struct thermal_cooling_device_ops *ops)
>>> +{
>>> +	struct thermal_cooling_device *cdev;
>>> +	int result;
>>> +
>>> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
>>> +	    !ops->set_cur_state)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
>>> +	if (!cdev)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
>>> +	if (result) {
>>> +		kfree(cdev);
>>> +		return ERR_PTR(result);
>>> +	}
>>> +
>>> +	strcpy(cdev->type, type ? : "");
>>> +	mutex_init(&cdev->lock);
>>> +	INIT_LIST_HEAD(&cdev->thermal_instances);
>>> +	cdev->ops = ops;
>>> +	cdev->updated = true;
>>> +	cdev->device.class = &thermal_class;
>>> +	cdev->devdata = devdata;
>>> +	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
>>> +	result = device_register(&cdev->device);
>>> +	if (result) {
>>> +		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> +		kfree(cdev);
>>> +		return ERR_PTR(result);
>>> +	}
>>> +
>>> +	/* sys I/F */
>>> +	if (type) {
>>> +		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
>>> +		if (result)
>>> +			goto unregister;
>>> +	}
>>> +
>>> +	result = device_create_file(&cdev->device, &dev_attr_max_state);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	result = device_create_file(&cdev->device, &dev_attr_cur_state);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	/* Add 'this' new cdev to the global cdev list */
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_add(&cdev->node, &thermal_cdev_list);
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	/* Update binding information for 'this' new cdev */
>>> +	bind_cdev(cdev);
>>> +
>>> +	return cdev;
>>> +
>>> +unregister:
>>> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> +	device_unregister(&cdev->device);
>>> +	return ERR_PTR(result);
>>> +}
>>> +EXPORT_SYMBOL(thermal_cooling_device_register);
>>> +
>>> +/**
>>> + * thermal_cooling_device_unregister - removes the registered thermal cooling device
>>> + * @cdev:	the thermal cooling device to remove.
>>> + *
>>> + * thermal_cooling_device_unregister() must be called when the device is no
>>> + * longer needed.
>>> + */
>>> +void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
>>> +{
>>> +	int i;
>>> +	const struct thermal_zone_params *tzp;
>>> +	struct thermal_zone_device *tz;
>>> +	struct thermal_cooling_device *pos = NULL;
>>> +
>>> +	if (!cdev)
>>> +		return;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_for_each_entry(pos, &thermal_cdev_list, node)
>>> +	    if (pos == cdev)
>>> +		break;
>>> +	if (pos != cdev) {
>>> +		/* thermal cooling device not found */
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		return;
>>> +	}
>>> +	list_del(&cdev->node);
>>> +
>>> +	/* Unbind all thermal zones associated with 'this' cdev */
>>> +	list_for_each_entry(tz, &thermal_tz_list, node) {
>>> +		if (tz->ops->unbind) {
>>> +			tz->ops->unbind(tz, cdev);
>>> +			continue;
>>> +		}
>>> +
>>> +		if (!tz->tzp || !tz->tzp->tbp)
>>> +			continue;
>>> +
>>> +		tzp = tz->tzp;
>>> +		for (i = 0; i < tzp->num_tbps; i++) {
>>> +			if (tzp->tbp[i].cdev == cdev) {
>>> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
>>> +				tzp->tbp[i].cdev = NULL;
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	if (cdev->type[0])
>>> +		device_remove_file(&cdev->device, &dev_attr_cdev_type);
>>> +	device_remove_file(&cdev->device, &dev_attr_max_state);
>>> +	device_remove_file(&cdev->device, &dev_attr_cur_state);
>>> +
>>> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> +	device_unregister(&cdev->device);
>>> +	return;
>>> +}
>>> +EXPORT_SYMBOL(thermal_cooling_device_unregister);
>>> +
>>> +void thermal_cdev_update(struct thermal_cooling_device *cdev)
>>> +{
>>> +	struct thermal_instance *instance;
>>> +	unsigned long target = 0;
>>> +
>>> +	/* cooling device is updated*/
>>> +	if (cdev->updated)
>>> +		return;
>>> +
>>> +	mutex_lock(&cdev->lock);
>>> +	/* Make sure cdev enters the deepest cooling state */
>>> +	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
>>> +		if (instance->target == THERMAL_NO_TARGET)
>>> +			continue;
>>> +		if (instance->target > target)
>>> +			target = instance->target;
>>> +	}
>>> +	mutex_unlock(&cdev->lock);
>>> +	cdev->ops->set_cur_state(cdev, target);
>>> +	cdev->updated = true;
>>> +}
>>> +EXPORT_SYMBOL(thermal_cdev_update);
>>> +
>>> +/**
>>> + * notify_thermal_framework - Sensor drivers use this API to notify framework
>>> + * @tz:		thermal zone device
>>> + * @trip:	indicates which trip point has been crossed
>>> + *
>>> + * This function handles the trip events from sensor drivers. It starts
>>> + * throttling the cooling devices according to the policy configured.
>>> + * For CRITICAL and HOT trip points, this notifies the respective drivers,
>>> + * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
>>> + * The throttling policy is based on the configured platform data; if no
>>> + * platform data is provided, this uses the step_wise throttling policy.
>>> + */
>>> +void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
>>> +{
>>> +	handle_thermal_trip(tz, trip);
>>> +}
>>> +EXPORT_SYMBOL(notify_thermal_framework);
>>> +
>>> +/**
>>> + * create_trip_attrs - create attributes for trip points
>>> + * @tz:		the thermal zone device
>>> + * @mask:	Writeable trip point bitmap.
>>> + */
>>> +static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
>>> +{
>>> +	int indx;
>>> +	int size = sizeof(struct thermal_attr) * tz->trips;
>>> +
>>> +	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
>>> +	if (!tz->trip_type_attrs)
>>> +		return -ENOMEM;
>>> +
>>> +	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
>>> +	if (!tz->trip_temp_attrs) {
>>> +		kfree(tz->trip_type_attrs);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	if (tz->ops->get_trip_hyst) {
>>> +		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
>>> +		if (!tz->trip_hyst_attrs) {
>>> +			kfree(tz->trip_type_attrs);
>>> +			kfree(tz->trip_temp_attrs);
>>> +			return -ENOMEM;
>>> +		}
>>> +	}
>>> +
>>> +
>>> +	for (indx = 0; indx < tz->trips; indx++) {
>>> +		/* create trip type attribute */
>>> +		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> +			 "trip_point_%d_type", indx);
>>> +
>>> +		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
>>> +		tz->trip_type_attrs[indx].attr.attr.name =
>>> +						tz->trip_type_attrs[indx].name;
>>> +		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
>>> +		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
>>> +
>>> +		device_create_file(&tz->device,
>>> +				   &tz->trip_type_attrs[indx].attr);
>>> +
>>> +		/* create trip temp attribute */
>>> +		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> +			 "trip_point_%d_temp", indx);
>>> +
>>> +		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
>>> +		tz->trip_temp_attrs[indx].attr.attr.name =
>>> +						tz->trip_temp_attrs[indx].name;
>>> +		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
>>> +		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
>>> +		if (mask & (1 << indx)) {
>>> +			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
>>> +			tz->trip_temp_attrs[indx].attr.store =
>>> +							trip_point_temp_store;
>>> +		}
>>> +
>>> +		device_create_file(&tz->device,
>>> +				   &tz->trip_temp_attrs[indx].attr);
>>> +
>>> +		/* create Optional trip hyst attribute */
>>> +		if (!tz->ops->get_trip_hyst)
>>> +			continue;
>>> +		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> +			 "trip_point_%d_hyst", indx);
>>> +
>>> +		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
>>> +		tz->trip_hyst_attrs[indx].attr.attr.name =
>>> +					tz->trip_hyst_attrs[indx].name;
>>> +		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
>>> +		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
>>> +		if (tz->ops->set_trip_hyst) {
>>> +			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
>>> +			tz->trip_hyst_attrs[indx].attr.store =
>>> +					trip_point_hyst_store;
>>> +		}
>>> +
>>> +		device_create_file(&tz->device,
>>> +				   &tz->trip_hyst_attrs[indx].attr);
>>> +	}
>>> +	return 0;
>>> +}
>>> +
>>> +static void remove_trip_attrs(struct thermal_zone_device *tz)
>>> +{
>>> +	int indx;
>>> +
>>> +	for (indx = 0; indx < tz->trips; indx++) {
>>> +		device_remove_file(&tz->device,
>>> +				   &tz->trip_type_attrs[indx].attr);
>>> +		device_remove_file(&tz->device,
>>> +				   &tz->trip_temp_attrs[indx].attr);
>>> +		if (tz->ops->get_trip_hyst)
>>> +			device_remove_file(&tz->device,
>>> +				  &tz->trip_hyst_attrs[indx].attr);
>>> +	}
>>> +	kfree(tz->trip_type_attrs);
>>> +	kfree(tz->trip_temp_attrs);
>>> +	kfree(tz->trip_hyst_attrs);
>>> +}
>>> +
>>> +/**
>>> + * thermal_zone_device_register - register a new thermal zone device
>>> + * @type:	the thermal zone device type
>>> + * @trips:	the number of trip points the thermal zone support
>>> + * @mask:	a bit string indicating the writeablility of trip points
>>> + * @devdata:	private device data
>>> + * @ops:	standard thermal zone device callbacks
>>> + * @tzp:	thermal zone platform parameters
>>> + * @passive_delay: number of milliseconds to wait between polls when
>>> + *		   performing passive cooling
>>> + * @polling_delay: number of milliseconds to wait between polls when checking
>>> + *		   whether trip points have been crossed (0 for interrupt
>>> + *		   driven systems)
>>> + *
>>> + * thermal_zone_device_unregister() must be called when the device is no
>>> + * longer needed. The passive cooling depends on the .get_trend() return value.
>>> + */
>>> +struct thermal_zone_device *thermal_zone_device_register(const char *type,
>>> +	int trips, int mask, void *devdata,
>>> +	const struct thermal_zone_device_ops *ops,
>>> +	const struct thermal_zone_params *tzp,
>>> +	int passive_delay, int polling_delay)
>>> +{
>>> +	struct thermal_zone_device *tz;
>>> +	enum thermal_trip_type trip_type;
>>> +	int result;
>>> +	int count;
>>> +	int passive = 0;
>>> +
>>> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	if (!ops || !ops->get_temp)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	if (trips > 0 && !ops->get_trip_type)
>>> +		return ERR_PTR(-EINVAL);
>>> +
>>> +	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
>>> +	if (!tz)
>>> +		return ERR_PTR(-ENOMEM);
>>> +
>>> +	INIT_LIST_HEAD(&tz->thermal_instances);
>>> +	idr_init(&tz->idr);
>>> +	mutex_init(&tz->lock);
>>> +	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
>>> +	if (result) {
>>> +		kfree(tz);
>>> +		return ERR_PTR(result);
>>> +	}
>>> +
>>> +	strcpy(tz->type, type ? : "");
>>> +	tz->ops = ops;
>>> +	tz->tzp = tzp;
>>> +	tz->device.class = &thermal_class;
>>> +	tz->devdata = devdata;
>>> +	tz->trips = trips;
>>> +	tz->passive_delay = passive_delay;
>>> +	tz->polling_delay = polling_delay;
>>> +
>>> +	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
>>> +	result = device_register(&tz->device);
>>> +	if (result) {
>>> +		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> +		kfree(tz);
>>> +		return ERR_PTR(result);
>>> +	}
>>> +
>>> +	/* sys I/F */
>>> +	if (type) {
>>> +		result = device_create_file(&tz->device, &dev_attr_type);
>>> +		if (result)
>>> +			goto unregister;
>>> +	}
>>> +
>>> +	result = device_create_file(&tz->device, &dev_attr_temp);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	if (ops->get_mode) {
>>> +		result = device_create_file(&tz->device, &dev_attr_mode);
>>> +		if (result)
>>> +			goto unregister;
>>> +	}
>>> +
>>> +	result = create_trip_attrs(tz, mask);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	for (count = 0; count < trips; count++) {
>>> +		tz->ops->get_trip_type(tz, count, &trip_type);
>>> +		if (trip_type == THERMAL_TRIP_PASSIVE)
>>> +			passive = 1;
>>> +	}
>>> +
>>> +	if (!passive) {
>>> +		result = device_create_file(&tz->device, &dev_attr_passive);
>>> +		if (result)
>>> +			goto unregister;
>>> +	}
>>> +
>>> +#ifdef CONFIG_THERMAL_EMULATION
>>> +	result = device_create_file(&tz->device, &dev_attr_emul_temp);
>>> +	if (result)
>>> +		goto unregister;
>>> +#endif
>>> +	/* Create policy attribute */
>>> +	result = device_create_file(&tz->device, &dev_attr_policy);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	/* Update 'this' zone's governor information */
>>> +	mutex_lock(&thermal_governor_lock);
>>> +
>>> +	if (tz->tzp)
>>> +		tz->governor = __find_governor(tz->tzp->governor_name);
>>> +	else
>>> +		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
>>> +
>>> +	mutex_unlock(&thermal_governor_lock);
>>> +
>>> +	result = thermal_add_hwmon_sysfs(tz);
>>> +	if (result)
>>> +		goto unregister;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_add_tail(&tz->node, &thermal_tz_list);
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	/* Bind cooling devices for this zone */
>>> +	bind_tz(tz);
>>> +
>>> +	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
>>> +
>>> +	thermal_zone_device_update(tz);
>>> +
>>> +	if (!result)
>>> +		return tz;
>>> +
>>> +unregister:
>>> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> +	device_unregister(&tz->device);
>>> +	return ERR_PTR(result);
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_device_register);
>>> +
>>> +/**
>>> + * thermal_device_unregister - removes the registered thermal zone device
>>> + * @tz: the thermal zone device to remove
>>> + */
>>> +void thermal_zone_device_unregister(struct thermal_zone_device *tz)
>>> +{
>>> +	int i;
>>> +	const struct thermal_zone_params *tzp;
>>> +	struct thermal_cooling_device *cdev;
>>> +	struct thermal_zone_device *pos = NULL;
>>> +
>>> +	if (!tz)
>>> +		return;
>>> +
>>> +	tzp = tz->tzp;
>>> +
>>> +	mutex_lock(&thermal_list_lock);
>>> +	list_for_each_entry(pos, &thermal_tz_list, node)
>>> +	    if (pos == tz)
>>> +		break;
>>> +	if (pos != tz) {
>>> +		/* thermal zone device not found */
>>> +		mutex_unlock(&thermal_list_lock);
>>> +		return;
>>> +	}
>>> +	list_del(&tz->node);
>>> +
>>> +	/* Unbind all cdevs associated with 'this' thermal zone */
>>> +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> +		if (tz->ops->unbind) {
>>> +			tz->ops->unbind(tz, cdev);
>>> +			continue;
>>> +		}
>>> +
>>> +		if (!tzp || !tzp->tbp)
>>> +			break;
>>> +
>>> +		for (i = 0; i < tzp->num_tbps; i++) {
>>> +			if (tzp->tbp[i].cdev == cdev) {
>>> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
>>> +				tzp->tbp[i].cdev = NULL;
>>> +			}
>>> +		}
>>> +	}
>>> +
>>> +	mutex_unlock(&thermal_list_lock);
>>> +
>>> +	thermal_zone_device_set_polling(tz, 0);
>>> +
>>> +	if (tz->type[0])
>>> +		device_remove_file(&tz->device, &dev_attr_type);
>>> +	device_remove_file(&tz->device, &dev_attr_temp);
>>> +	if (tz->ops->get_mode)
>>> +		device_remove_file(&tz->device, &dev_attr_mode);
>>> +	device_remove_file(&tz->device, &dev_attr_policy);
>>> +	remove_trip_attrs(tz);
>>> +	tz->governor = NULL;
>>> +
>>> +	thermal_remove_hwmon_sysfs(tz);
>>> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> +	idr_destroy(&tz->idr);
>>> +	mutex_destroy(&tz->lock);
>>> +	device_unregister(&tz->device);
>>> +	return;
>>> +}
>>> +EXPORT_SYMBOL(thermal_zone_device_unregister);
>>> +
>>> +#ifdef CONFIG_NET
>>> +static struct genl_family thermal_event_genl_family = {
>>> +	.id = GENL_ID_GENERATE,
>>> +	.name = THERMAL_GENL_FAMILY_NAME,
>>> +	.version = THERMAL_GENL_VERSION,
>>> +	.maxattr = THERMAL_GENL_ATTR_MAX,
>>> +};
>>> +
>>> +static struct genl_multicast_group thermal_event_mcgrp = {
>>> +	.name = THERMAL_GENL_MCAST_GROUP_NAME,
>>> +};
>>> +
>>> +int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>>> +					enum events event)
>>> +{
>>> +	struct sk_buff *skb;
>>> +	struct nlattr *attr;
>>> +	struct thermal_genl_event *thermal_event;
>>> +	void *msg_header;
>>> +	int size;
>>> +	int result;
>>> +	static unsigned int thermal_event_seqnum;
>>> +
>>> +	if (!tz)
>>> +		return -EINVAL;
>>> +
>>> +	/* allocate memory */
>>> +	size = nla_total_size(sizeof(struct thermal_genl_event)) +
>>> +	       nla_total_size(0);
>>> +
>>> +	skb = genlmsg_new(size, GFP_ATOMIC);
>>> +	if (!skb)
>>> +		return -ENOMEM;
>>> +
>>> +	/* add the genetlink message header */
>>> +	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
>>> +				 &thermal_event_genl_family, 0,
>>> +				 THERMAL_GENL_CMD_EVENT);
>>> +	if (!msg_header) {
>>> +		nlmsg_free(skb);
>>> +		return -ENOMEM;
>>> +	}
>>> +
>>> +	/* fill the data */
>>> +	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
>>> +			   sizeof(struct thermal_genl_event));
>>> +
>>> +	if (!attr) {
>>> +		nlmsg_free(skb);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	thermal_event = nla_data(attr);
>>> +	if (!thermal_event) {
>>> +		nlmsg_free(skb);
>>> +		return -EINVAL;
>>> +	}
>>> +
>>> +	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
>>> +
>>> +	thermal_event->orig = tz->id;
>>> +	thermal_event->event = event;
>>> +
>>> +	/* send multicast genetlink message */
>>> +	result = genlmsg_end(skb, msg_header);
>>> +	if (result < 0) {
>>> +		nlmsg_free(skb);
>>> +		return result;
>>> +	}
>>> +
>>> +	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
>>> +	if (result)
>>> +		dev_err(&tz->device, "Failed to send netlink event:%d", result);
>>> +
>>> +	return result;
>>> +}
>>> +EXPORT_SYMBOL(thermal_generate_netlink_event);
>>> +
>>> +static int genetlink_init(void)
>>> +{
>>> +	int result;
>>> +
>>> +	result = genl_register_family(&thermal_event_genl_family);
>>> +	if (result)
>>> +		return result;
>>> +
>>> +	result = genl_register_mc_group(&thermal_event_genl_family,
>>> +					&thermal_event_mcgrp);
>>> +	if (result)
>>> +		genl_unregister_family(&thermal_event_genl_family);
>>> +	return result;
>>> +}
>>> +
>>> +static void genetlink_exit(void)
>>> +{
>>> +	genl_unregister_family(&thermal_event_genl_family);
>>> +}
>>> +#else /* !CONFIG_NET */
>>> +static inline int genetlink_init(void) { return 0; }
>>> +static inline void genetlink_exit(void) {}
>>> +#endif /* !CONFIG_NET */
>>> +
>>> +static int __init thermal_init(void)
>>> +{
>>> +	int result = 0;
>>> +
>>> +	result = class_register(&thermal_class);
>>> +	if (result) {
>>> +		idr_destroy(&thermal_tz_idr);
>>> +		idr_destroy(&thermal_cdev_idr);
>>> +		mutex_destroy(&thermal_idr_lock);
>>> +		mutex_destroy(&thermal_list_lock);
>>> +		return result;
>>> +	}
>>> +	result = genetlink_init();
>>> +	return result;
>>> +}
>>> +
>>> +static void __exit thermal_exit(void)
>>> +{
>>> +	class_unregister(&thermal_class);
>>> +	idr_destroy(&thermal_tz_idr);
>>> +	idr_destroy(&thermal_cdev_idr);
>>> +	mutex_destroy(&thermal_idr_lock);
>>> +	mutex_destroy(&thermal_list_lock);
>>> +	genetlink_exit();
>>> +}
>>> +
>>> +fs_initcall(thermal_init);
>>> +module_exit(thermal_exit);
>>> diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c
>>> deleted file mode 100644
>>> index 5b7863a..0000000
>>> --- a/drivers/thermal/thermal_sys.c
>>> +++ /dev/null
>>> @@ -1,1888 +0,0 @@
>>> -/*
>>> - *  thermal.c - Generic Thermal Management Sysfs support.
>>> - *
>>> - *  Copyright (C) 2008 Intel Corp
>>> - *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
>>> - *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
>>> - *
>>> - *  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> - *
>>> - *  This program is free software; you can redistribute it and/or modify
>>> - *  it under the terms of the GNU General Public License as published by
>>> - *  the Free Software Foundation; version 2 of the License.
>>> - *
>>> - *  This program is distributed in the hope that it will be useful, but
>>> - *  WITHOUT ANY WARRANTY; without even the implied warranty of
>>> - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>>> - *  General Public License for more details.
>>> - *
>>> - *  You should have received a copy of the GNU General Public License along
>>> - *  with this program; if not, write to the Free Software Foundation, Inc.,
>>> - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
>>> - *
>>> - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>> - */
>>> -
>>> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
>>> -
>>> -#include <linux/module.h>
>>> -#include <linux/device.h>
>>> -#include <linux/err.h>
>>> -#include <linux/slab.h>
>>> -#include <linux/kdev_t.h>
>>> -#include <linux/idr.h>
>>> -#include <linux/thermal.h>
>>> -#include <linux/reboot.h>
>>> -#include <net/netlink.h>
>>> -#include <net/genetlink.h>
>>> -
>>> -#include "thermal_core.h"
>>> -
>>> -MODULE_AUTHOR("Zhang Rui");
>>> -MODULE_DESCRIPTION("Generic thermal management sysfs support");
>>> -MODULE_LICENSE("GPL");
>>> -
>>> -static DEFINE_IDR(thermal_tz_idr);
>>> -static DEFINE_IDR(thermal_cdev_idr);
>>> -static DEFINE_MUTEX(thermal_idr_lock);
>>> -
>>> -static LIST_HEAD(thermal_tz_list);
>>> -static LIST_HEAD(thermal_cdev_list);
>>> -static LIST_HEAD(thermal_governor_list);
>>> -
>>> -static DEFINE_MUTEX(thermal_list_lock);
>>> -static DEFINE_MUTEX(thermal_governor_lock);
>>> -
>>> -static struct thermal_governor *__find_governor(const char *name)
>>> -{
>>> -	struct thermal_governor *pos;
>>> -
>>> -	list_for_each_entry(pos, &thermal_governor_list, governor_list)
>>> -		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
>>> -			return pos;
>>> -
>>> -	return NULL;
>>> -}
>>> -
>>> -int thermal_register_governor(struct thermal_governor *governor)
>>> -{
>>> -	int err;
>>> -	const char *name;
>>> -	struct thermal_zone_device *pos;
>>> -
>>> -	if (!governor)
>>> -		return -EINVAL;
>>> -
>>> -	mutex_lock(&thermal_governor_lock);
>>> -
>>> -	err = -EBUSY;
>>> -	if (__find_governor(governor->name) == NULL) {
>>> -		err = 0;
>>> -		list_add(&governor->governor_list, &thermal_governor_list);
>>> -	}
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -
>>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> -		if (pos->governor)
>>> -			continue;
>>> -		if (pos->tzp)
>>> -			name = pos->tzp->governor_name;
>>> -		else
>>> -			name = DEFAULT_THERMAL_GOVERNOR;
>>> -		if (!strnicmp(name, governor->name, THERMAL_NAME_LENGTH))
>>> -			pos->governor = governor;
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -	mutex_unlock(&thermal_governor_lock);
>>> -
>>> -	return err;
>>> -}
>>> -EXPORT_SYMBOL_GPL(thermal_register_governor);
>>> -
>>> -void thermal_unregister_governor(struct thermal_governor *governor)
>>> -{
>>> -	struct thermal_zone_device *pos;
>>> -
>>> -	if (!governor)
>>> -		return;
>>> -
>>> -	mutex_lock(&thermal_governor_lock);
>>> -
>>> -	if (__find_governor(governor->name) == NULL)
>>> -		goto exit;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -
>>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> -		if (!strnicmp(pos->governor->name, governor->name,
>>> -						THERMAL_NAME_LENGTH))
>>> -			pos->governor = NULL;
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -	list_del(&governor->governor_list);
>>> -exit:
>>> -	mutex_unlock(&thermal_governor_lock);
>>> -	return;
>>> -}
>>> -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
>>> -
>>> -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
>>> -{
>>> -	int ret;
>>> -
>>> -	if (lock)
>>> -		mutex_lock(lock);
>>> -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
>>> -	if (lock)
>>> -		mutex_unlock(lock);
>>> -	if (unlikely(ret < 0))
>>> -		return ret;
>>> -	*id = ret;
>>> -	return 0;
>>> -}
>>> -
>>> -static void release_idr(struct idr *idr, struct mutex *lock, int id)
>>> -{
>>> -	if (lock)
>>> -		mutex_lock(lock);
>>> -	idr_remove(idr, id);
>>> -	if (lock)
>>> -		mutex_unlock(lock);
>>> -}
>>> -
>>> -int get_tz_trend(struct thermal_zone_device *tz, int trip)
>>> -{
>>> -	enum thermal_trend trend;
>>> -
>>> -	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
>>> -		if (tz->temperature > tz->last_temperature)
>>> -			trend = THERMAL_TREND_RAISING;
>>> -		else if (tz->temperature < tz->last_temperature)
>>> -			trend = THERMAL_TREND_DROPPING;
>>> -		else
>>> -			trend = THERMAL_TREND_STABLE;
>>> -	}
>>> -
>>> -	return trend;
>>> -}
>>> -EXPORT_SYMBOL(get_tz_trend);
>>> -
>>> -struct thermal_instance *get_thermal_instance(struct thermal_zone_device *tz,
>>> -			struct thermal_cooling_device *cdev, int trip)
>>> -{
>>> -	struct thermal_instance *pos = NULL;
>>> -	struct thermal_instance *target_instance = NULL;
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -	mutex_lock(&cdev->lock);
>>> -
>>> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
>>> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> -			target_instance = pos;
>>> -			break;
>>> -		}
>>> -	}
>>> -
>>> -	mutex_unlock(&cdev->lock);
>>> -	mutex_unlock(&tz->lock);
>>> -
>>> -	return target_instance;
>>> -}
>>> -EXPORT_SYMBOL(get_thermal_instance);
>>> -
>>> -static void print_bind_err_msg(struct thermal_zone_device *tz,
>>> -			struct thermal_cooling_device *cdev, int ret)
>>> -{
>>> -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
>>> -				tz->type, cdev->type, ret);
>>> -}
>>> -
>>> -static void __bind(struct thermal_zone_device *tz, int mask,
>>> -			struct thermal_cooling_device *cdev)
>>> -{
>>> -	int i, ret;
>>> -
>>> -	for (i = 0; i < tz->trips; i++) {
>>> -		if (mask & (1 << i)) {
>>> -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
>>> -					THERMAL_NO_LIMIT, THERMAL_NO_LIMIT);
>>> -			if (ret)
>>> -				print_bind_err_msg(tz, cdev, ret);
>>> -		}
>>> -	}
>>> -}
>>> -
>>> -static void __unbind(struct thermal_zone_device *tz, int mask,
>>> -			struct thermal_cooling_device *cdev)
>>> -{
>>> -	int i;
>>> -
>>> -	for (i = 0; i < tz->trips; i++)
>>> -		if (mask & (1 << i))
>>> -			thermal_zone_unbind_cooling_device(tz, i, cdev);
>>> -}
>>> -
>>> -static void bind_cdev(struct thermal_cooling_device *cdev)
>>> -{
>>> -	int i, ret;
>>> -	const struct thermal_zone_params *tzp;
>>> -	struct thermal_zone_device *pos = NULL;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -
>>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
>>> -		if (!pos->tzp && !pos->ops->bind)
>>> -			continue;
>>> -
>>> -		if (!pos->tzp && pos->ops->bind) {
>>> -			ret = pos->ops->bind(pos, cdev);
>>> -			if (ret)
>>> -				print_bind_err_msg(pos, cdev, ret);
>>> -		}
>>> -
>>> -		tzp = pos->tzp;
>>> -		if (!tzp || !tzp->tbp)
>>> -			continue;
>>> -
>>> -		for (i = 0; i < tzp->num_tbps; i++) {
>>> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
>>> -				continue;
>>> -			if (tzp->tbp[i].match(pos, cdev))
>>> -				continue;
>>> -			tzp->tbp[i].cdev = cdev;
>>> -			__bind(pos, tzp->tbp[i].trip_mask, cdev);
>>> -		}
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -}
>>> -
>>> -static void bind_tz(struct thermal_zone_device *tz)
>>> -{
>>> -	int i, ret;
>>> -	struct thermal_cooling_device *pos = NULL;
>>> -	const struct thermal_zone_params *tzp = tz->tzp;
>>> -
>>> -	if (!tzp && !tz->ops->bind)
>>> -		return;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -
>>> -	/* If there is no platform data, try to use ops->bind */
>>> -	if (!tzp && tz->ops->bind) {
>>> -		list_for_each_entry(pos, &thermal_cdev_list, node) {
>>> -			ret = tz->ops->bind(tz, pos);
>>> -			if (ret)
>>> -				print_bind_err_msg(tz, pos, ret);
>>> -		}
>>> -		goto exit;
>>> -	}
>>> -
>>> -	if (!tzp || !tzp->tbp)
>>> -		goto exit;
>>> -
>>> -	list_for_each_entry(pos, &thermal_cdev_list, node) {
>>> -		for (i = 0; i < tzp->num_tbps; i++) {
>>> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
>>> -				continue;
>>> -			if (tzp->tbp[i].match(tz, pos))
>>> -				continue;
>>> -			tzp->tbp[i].cdev = pos;
>>> -			__bind(tz, tzp->tbp[i].trip_mask, pos);
>>> -		}
>>> -	}
>>> -exit:
>>> -	mutex_unlock(&thermal_list_lock);
>>> -}
>>> -
>>> -static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
>>> -					    int delay)
>>> -{
>>> -	if (delay > 1000)
>>> -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
>>> -				 round_jiffies(msecs_to_jiffies(delay)));
>>> -	else if (delay)
>>> -		mod_delayed_work(system_freezable_wq, &tz->poll_queue,
>>> -				 msecs_to_jiffies(delay));
>>> -	else
>>> -		cancel_delayed_work(&tz->poll_queue);
>>> -}
>>> -
>>> -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);
>>> -	else if (tz->polling_delay)
>>> -		thermal_zone_device_set_polling(tz, tz->polling_delay);
>>> -	else
>>> -		thermal_zone_device_set_polling(tz, 0);
>>> -
>>> -	mutex_unlock(&tz->lock);
>>> -}
>>> -
>>> -static void handle_non_critical_trips(struct thermal_zone_device *tz,
>>> -			int trip, enum thermal_trip_type trip_type)
>>> -{
>>> -	if (tz->governor)
>>> -		tz->governor->throttle(tz, trip);
>>> -}
>>> -
>>> -static void handle_critical_trips(struct thermal_zone_device *tz,
>>> -				int trip, enum thermal_trip_type trip_type)
>>> -{
>>> -	long trip_temp;
>>> -
>>> -	tz->ops->get_trip_temp(tz, trip, &trip_temp);
>>> -
>>> -	/* If we have not crossed the trip_temp, we do not care. */
>>> -	if (tz->temperature < trip_temp)
>>> -		return;
>>> -
>>> -	if (tz->ops->notify)
>>> -		tz->ops->notify(tz, trip, trip_type);
>>> -
>>> -	if (trip_type == THERMAL_TRIP_CRITICAL) {
>>> -		dev_emerg(&tz->device,
>>> -			  "critical temperature reached(%d C),shutting down\n",
>>> -			  tz->temperature / 1000);
>>> -		orderly_poweroff(true);
>>> -	}
>>> -}
>>> -
>>> -static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
>>> -{
>>> -	enum thermal_trip_type type;
>>> -
>>> -	tz->ops->get_trip_type(tz, trip, &type);
>>> -
>>> -	if (type == THERMAL_TRIP_CRITICAL || type == THERMAL_TRIP_HOT)
>>> -		handle_critical_trips(tz, trip, type);
>>> -	else
>>> -		handle_non_critical_trips(tz, trip, type);
>>> -	/*
>>> -	 * Alright, we handled this trip successfully.
>>> -	 * So, start monitoring again.
>>> -	 */
>>> -	monitor_thermal_zone(tz);
>>> -}
>>> -
>>> -static int thermal_zone_get_temp(struct thermal_zone_device *tz,
>>> -				unsigned long *temp)
>>> -{
>>> -	int ret = 0;
>>> -#ifdef CONFIG_THERMAL_EMULATION
>>> -	int count;
>>> -	unsigned long crit_temp = -1UL;
>>> -	enum thermal_trip_type type;
>>> -#endif
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -
>>> -	ret = tz->ops->get_temp(tz, temp);
>>> -#ifdef CONFIG_THERMAL_EMULATION
>>> -	if (!tz->emul_temperature)
>>> -		goto skip_emul;
>>> -
>>> -	for (count = 0; count < tz->trips; count++) {
>>> -		ret = tz->ops->get_trip_type(tz, count, &type);
>>> -		if (!ret && type == THERMAL_TRIP_CRITICAL) {
>>> -			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
>>> -			break;
>>> -		}
>>> -	}
>>> -
>>> -	if (ret)
>>> -		goto skip_emul;
>>> -
>>> -	if (*temp < crit_temp)
>>> -		*temp = tz->emul_temperature;
>>> -skip_emul:
>>> -#endif
>>> -	mutex_unlock(&tz->lock);
>>> -	return ret;
>>> -}
>>> -
>>> -static void update_temperature(struct thermal_zone_device *tz)
>>> -{
>>> -	long temp;
>>> -	int ret;
>>> -
>>> -	ret = thermal_zone_get_temp(tz, &temp);
>>> -	if (ret) {
>>> -		dev_warn(&tz->device, "failed to read out thermal zone %d\n",
>>> -			 tz->id);
>>> -		return;
>>> -	}
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -	tz->last_temperature = tz->temperature;
>>> -	tz->temperature = temp;
>>> -	mutex_unlock(&tz->lock);
>>> -}
>>> -
>>> -void thermal_zone_device_update(struct thermal_zone_device *tz)
>>> -{
>>> -	int count;
>>> -
>>> -	update_temperature(tz);
>>> -
>>> -	for (count = 0; count < tz->trips; count++)
>>> -		handle_thermal_trip(tz, count);
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_device_update);
>>> -
>>> -static void thermal_zone_device_check(struct work_struct *work)
>>> -{
>>> -	struct thermal_zone_device *tz = container_of(work, struct
>>> -						      thermal_zone_device,
>>> -						      poll_queue.work);
>>> -	thermal_zone_device_update(tz);
>>> -}
>>> -
>>> -/* sys I/F for thermal zone */
>>> -
>>> -#define to_thermal_zone(_dev) \
>>> -	container_of(_dev, struct thermal_zone_device, device)
>>> -
>>> -static ssize_t
>>> -type_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -
>>> -	return sprintf(buf, "%s\n", tz->type);
>>> -}
>>> -
>>> -static ssize_t
>>> -temp_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	long temperature;
>>> -	int ret;
>>> -
>>> -	ret = thermal_zone_get_temp(tz, &temperature);
>>> -
>>> -	if (ret)
>>> -		return ret;
>>> -
>>> -	return sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -static ssize_t
>>> -mode_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	enum thermal_device_mode mode;
>>> -	int result;
>>> -
>>> -	if (!tz->ops->get_mode)
>>> -		return -EPERM;
>>> -
>>> -	result = tz->ops->get_mode(tz, &mode);
>>> -	if (result)
>>> -		return result;
>>> -
>>> -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ? "enabled"
>>> -		       : "disabled");
>>> -}
>>> -
>>> -static ssize_t
>>> -mode_store(struct device *dev, struct device_attribute *attr,
>>> -	   const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int result;
>>> -
>>> -	if (!tz->ops->set_mode)
>>> -		return -EPERM;
>>> -
>>> -	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);
>>> -	else
>>> -		result = -EINVAL;
>>> -
>>> -	if (result)
>>> -		return result;
>>> -
>>> -	return count;
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_type_show(struct device *dev, struct device_attribute *attr,
>>> -		     char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	enum thermal_trip_type type;
>>> -	int trip, result;
>>> -
>>> -	if (!tz->ops->get_trip_type)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	result = tz->ops->get_trip_type(tz, trip, &type);
>>> -	if (result)
>>> -		return result;
>>> -
>>> -	switch (type) {
>>> -	case THERMAL_TRIP_CRITICAL:
>>> -		return sprintf(buf, "critical\n");
>>> -	case THERMAL_TRIP_HOT:
>>> -		return sprintf(buf, "hot\n");
>>> -	case THERMAL_TRIP_PASSIVE:
>>> -		return sprintf(buf, "passive\n");
>>> -	case THERMAL_TRIP_ACTIVE:
>>> -		return sprintf(buf, "active\n");
>>> -	default:
>>> -		return sprintf(buf, "unknown\n");
>>> -	}
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_temp_store(struct device *dev, struct device_attribute *attr,
>>> -		     const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int trip, ret;
>>> -	unsigned long temperature;
>>> -
>>> -	if (!tz->ops->set_trip_temp)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	if (kstrtoul(buf, 10, &temperature))
>>> -		return -EINVAL;
>>> -
>>> -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
>>> -
>>> -	return ret ? ret : count;
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_temp_show(struct device *dev, struct device_attribute *attr,
>>> -		     char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int trip, ret;
>>> -	long temperature;
>>> -
>>> -	if (!tz->ops->get_trip_temp)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
>>> -
>>> -	if (ret)
>>> -		return ret;
>>> -
>>> -	return sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
>>> -			const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int trip, ret;
>>> -	unsigned long temperature;
>>> -
>>> -	if (!tz->ops->set_trip_hyst)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	if (kstrtoul(buf, 10, &temperature))
>>> -		return -EINVAL;
>>> -
>>> -	/*
>>> -	 * We are not doing any check on the 'temperature' value
>>> -	 * here. The driver implementing 'set_trip_hyst' has to
>>> -	 * take care of this.
>>> -	 */
>>> -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
>>> -
>>> -	return ret ? ret : count;
>>> -}
>>> -
>>> -static ssize_t
>>> -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
>>> -			char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int trip, ret;
>>> -	unsigned long temperature;
>>> -
>>> -	if (!tz->ops->get_trip_hyst)
>>> -		return -EPERM;
>>> -
>>> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
>>> -		return -EINVAL;
>>> -
>>> -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
>>> -
>>> -	return ret ? ret : sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -static ssize_t
>>> -passive_store(struct device *dev, struct device_attribute *attr,
>>> -		    const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	struct thermal_cooling_device *cdev = NULL;
>>> -	int state;
>>> -
>>> -	if (!sscanf(buf, "%d\n", &state))
>>> -		return -EINVAL;
>>> -
>>> -	/* sanity check: values below 1000 millicelcius don't make sense
>>> -	 * and can cause the system to go into a thermal heart attack
>>> -	 */
>>> -	if (state && state < 1000)
>>> -		return -EINVAL;
>>> -
>>> -	if (state && !tz->forced_passive) {
>>> -		mutex_lock(&thermal_list_lock);
>>> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> -			if (!strncmp("Processor", cdev->type,
>>> -				     sizeof("Processor")))
>>> -				thermal_zone_bind_cooling_device(tz,
>>> -						THERMAL_TRIPS_NONE, cdev,
>>> -						THERMAL_NO_LIMIT,
>>> -						THERMAL_NO_LIMIT);
>>> -		}
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		if (!tz->passive_delay)
>>> -			tz->passive_delay = 1000;
>>> -	} else if (!state && tz->forced_passive) {
>>> -		mutex_lock(&thermal_list_lock);
>>> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> -			if (!strncmp("Processor", cdev->type,
>>> -				     sizeof("Processor")))
>>> -				thermal_zone_unbind_cooling_device(tz,
>>> -								   THERMAL_TRIPS_NONE,
>>> -								   cdev);
>>> -		}
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		tz->passive_delay = 0;
>>> -	}
>>> -
>>> -	tz->forced_passive = state;
>>> -
>>> -	thermal_zone_device_update(tz);
>>> -
>>> -	return count;
>>> -}
>>> -
>>> -static ssize_t
>>> -passive_show(struct device *dev, struct device_attribute *attr,
>>> -		   char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -
>>> -	return sprintf(buf, "%d\n", tz->forced_passive);
>>> -}
>>> -
>>> -static ssize_t
>>> -policy_store(struct device *dev, struct device_attribute *attr,
>>> -		    const char *buf, size_t count)
>>> -{
>>> -	int ret = -EINVAL;
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	struct thermal_governor *gov;
>>> -
>>> -	mutex_lock(&thermal_governor_lock);
>>> -
>>> -	gov = __find_governor(buf);
>>> -	if (!gov)
>>> -		goto exit;
>>> -
>>> -	tz->governor = gov;
>>> -	ret = count;
>>> -
>>> -exit:
>>> -	mutex_unlock(&thermal_governor_lock);
>>> -	return ret;
>>> -}
>>> -
>>> -static ssize_t
>>> -policy_show(struct device *dev, struct device_attribute *devattr, char *buf)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -
>>> -	return sprintf(buf, "%s\n", tz->governor->name);
>>> -}
>>> -
>>> -#ifdef CONFIG_THERMAL_EMULATION
>>> -static ssize_t
>>> -emul_temp_store(struct device *dev, struct device_attribute *attr,
>>> -		     const char *buf, size_t count)
>>> -{
>>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
>>> -	int ret = 0;
>>> -	unsigned long temperature;
>>> -
>>> -	if (kstrtoul(buf, 10, &temperature))
>>> -		return -EINVAL;
>>> -
>>> -	if (!tz->ops->set_emul_temp) {
>>> -		mutex_lock(&tz->lock);
>>> -		tz->emul_temperature = temperature;
>>> -		mutex_unlock(&tz->lock);
>>> -	} else {
>>> -		ret = tz->ops->set_emul_temp(tz, temperature);
>>> -	}
>>> -
>>> -	return ret ? ret : count;
>>> -}
>>> -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
>>> -#endif/*CONFIG_THERMAL_EMULATION*/
>>> -
>>> -static DEVICE_ATTR(type, 0444, type_show, NULL);
>>> -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
>>> -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
>>> -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show, passive_store);
>>> -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show, policy_store);
>>> -
>>> -/* sys I/F for cooling device */
>>> -#define to_cooling_device(_dev)	\
>>> -	container_of(_dev, struct thermal_cooling_device, device)
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_type_show(struct device *dev,
>>> -				 struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> -
>>> -	return sprintf(buf, "%s\n", cdev->type);
>>> -}
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_max_state_show(struct device *dev,
>>> -				      struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> -	unsigned long state;
>>> -	int ret;
>>> -
>>> -	ret = cdev->ops->get_max_state(cdev, &state);
>>> -	if (ret)
>>> -		return ret;
>>> -	return sprintf(buf, "%ld\n", state);
>>> -}
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_cur_state_show(struct device *dev,
>>> -				      struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> -	unsigned long state;
>>> -	int ret;
>>> -
>>> -	ret = cdev->ops->get_cur_state(cdev, &state);
>>> -	if (ret)
>>> -		return ret;
>>> -	return sprintf(buf, "%ld\n", state);
>>> -}
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_cur_state_store(struct device *dev,
>>> -				       struct device_attribute *attr,
>>> -				       const char *buf, size_t count)
>>> -{
>>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
>>> -	unsigned long state;
>>> -	int result;
>>> -
>>> -	if (!sscanf(buf, "%ld\n", &state))
>>> -		return -EINVAL;
>>> -
>>> -	if ((long)state < 0)
>>> -		return -EINVAL;
>>> -
>>> -	result = cdev->ops->set_cur_state(cdev, state);
>>> -	if (result)
>>> -		return result;
>>> -	return count;
>>> -}
>>> -
>>> -static struct device_attribute dev_attr_cdev_type =
>>> -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
>>> -static DEVICE_ATTR(max_state, 0444,
>>> -		   thermal_cooling_device_max_state_show, NULL);
>>> -static DEVICE_ATTR(cur_state, 0644,
>>> -		   thermal_cooling_device_cur_state_show,
>>> -		   thermal_cooling_device_cur_state_store);
>>> -
>>> -static ssize_t
>>> -thermal_cooling_device_trip_point_show(struct device *dev,
>>> -				       struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_instance *instance;
>>> -
>>> -	instance =
>>> -	    container_of(attr, struct thermal_instance, attr);
>>> -
>>> -	if (instance->trip == THERMAL_TRIPS_NONE)
>>> -		return sprintf(buf, "-1\n");
>>> -	else
>>> -		return sprintf(buf, "%d\n", instance->trip);
>>> -}
>>> -
>>> -/* Device management */
>>> -
>>> -#if defined(CONFIG_THERMAL_HWMON)
>>> -
>>> -/* hwmon sys I/F */
>>> -#include <linux/hwmon.h>
>>> -
>>> -/* thermal zone devices with the same type share one hwmon device */
>>> -struct thermal_hwmon_device {
>>> -	char type[THERMAL_NAME_LENGTH];
>>> -	struct device *device;
>>> -	int count;
>>> -	struct list_head tz_list;
>>> -	struct list_head node;
>>> -};
>>> -
>>> -struct thermal_hwmon_attr {
>>> -	struct device_attribute attr;
>>> -	char name[16];
>>> -};
>>> -
>>> -/* one temperature input for each thermal zone */
>>> -struct thermal_hwmon_temp {
>>> -	struct list_head hwmon_node;
>>> -	struct thermal_zone_device *tz;
>>> -	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
>>> -	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
>>> -};
>>> -
>>> -static LIST_HEAD(thermal_hwmon_list);
>>> -
>>> -static ssize_t
>>> -name_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
>>> -	return sprintf(buf, "%s\n", hwmon->type);
>>> -}
>>> -static DEVICE_ATTR(name, 0444, name_show, NULL);
>>> -
>>> -static ssize_t
>>> -temp_input_show(struct device *dev, struct device_attribute *attr, char *buf)
>>> -{
>>> -	long temperature;
>>> -	int ret;
>>> -	struct thermal_hwmon_attr *hwmon_attr
>>> -			= container_of(attr, struct thermal_hwmon_attr, attr);
>>> -	struct thermal_hwmon_temp *temp
>>> -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
>>> -				       temp_input);
>>> -	struct thermal_zone_device *tz = temp->tz;
>>> -
>>> -	ret = thermal_zone_get_temp(tz, &temperature);
>>> -
>>> -	if (ret)
>>> -		return ret;
>>> -
>>> -	return sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -static ssize_t
>>> -temp_crit_show(struct device *dev, struct device_attribute *attr,
>>> -		char *buf)
>>> -{
>>> -	struct thermal_hwmon_attr *hwmon_attr
>>> -			= container_of(attr, struct thermal_hwmon_attr, attr);
>>> -	struct thermal_hwmon_temp *temp
>>> -			= container_of(hwmon_attr, struct thermal_hwmon_temp,
>>> -				       temp_crit);
>>> -	struct thermal_zone_device *tz = temp->tz;
>>> -	long temperature;
>>> -	int ret;
>>> -
>>> -	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
>>> -	if (ret)
>>> -		return ret;
>>> -
>>> -	return sprintf(buf, "%ld\n", temperature);
>>> -}
>>> -
>>> -
>>> -static struct thermal_hwmon_device *
>>> -thermal_hwmon_lookup_by_type(const struct thermal_zone_device *tz)
>>> -{
>>> -	struct thermal_hwmon_device *hwmon;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
>>> -		if (!strcmp(hwmon->type, tz->type)) {
>>> -			mutex_unlock(&thermal_list_lock);
>>> -			return hwmon;
>>> -		}
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	return NULL;
>>> -}
>>> -
>>> -/* Find the temperature input matching a given thermal zone */
>>> -static struct thermal_hwmon_temp *
>>> -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device *hwmon,
>>> -			  const struct thermal_zone_device *tz)
>>> -{
>>> -	struct thermal_hwmon_temp *temp;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
>>> -		if (temp->tz == tz) {
>>> -			mutex_unlock(&thermal_list_lock);
>>> -			return temp;
>>> -		}
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	return NULL;
>>> -}
>>> -
>>> -static int
>>> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
>>> -{
>>> -	struct thermal_hwmon_device *hwmon;
>>> -	struct thermal_hwmon_temp *temp;
>>> -	int new_hwmon_device = 1;
>>> -	int result;
>>> -
>>> -	hwmon = thermal_hwmon_lookup_by_type(tz);
>>> -	if (hwmon) {
>>> -		new_hwmon_device = 0;
>>> -		goto register_sys_interface;
>>> -	}
>>> -
>>> -	hwmon = kzalloc(sizeof(struct thermal_hwmon_device), GFP_KERNEL);
>>> -	if (!hwmon)
>>> -		return -ENOMEM;
>>> -
>>> -	INIT_LIST_HEAD(&hwmon->tz_list);
>>> -	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
>>> -	hwmon->device = hwmon_device_register(NULL);
>>> -	if (IS_ERR(hwmon->device)) {
>>> -		result = PTR_ERR(hwmon->device);
>>> -		goto free_mem;
>>> -	}
>>> -	dev_set_drvdata(hwmon->device, hwmon);
>>> -	result = device_create_file(hwmon->device, &dev_attr_name);
>>> -	if (result)
>>> -		goto free_mem;
>>> -
>>> - register_sys_interface:
>>> -	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
>>> -	if (!temp) {
>>> -		result = -ENOMEM;
>>> -		goto unregister_name;
>>> -	}
>>> -
>>> -	temp->tz = tz;
>>> -	hwmon->count++;
>>> -
>>> -	snprintf(temp->temp_input.name, sizeof(temp->temp_input.name),
>>> -		 "temp%d_input", hwmon->count);
>>> -	temp->temp_input.attr.attr.name = temp->temp_input.name;
>>> -	temp->temp_input.attr.attr.mode = 0444;
>>> -	temp->temp_input.attr.show = temp_input_show;
>>> -	sysfs_attr_init(&temp->temp_input.attr.attr);
>>> -	result = device_create_file(hwmon->device, &temp->temp_input.attr);
>>> -	if (result)
>>> -		goto free_temp_mem;
>>> -
>>> -	if (tz->ops->get_crit_temp) {
>>> -		unsigned long temperature;
>>> -		if (!tz->ops->get_crit_temp(tz, &temperature)) {
>>> -			snprintf(temp->temp_crit.name,
>>> -				 sizeof(temp->temp_crit.name),
>>> -				"temp%d_crit", hwmon->count);
>>> -			temp->temp_crit.attr.attr.name = temp->temp_crit.name;
>>> -			temp->temp_crit.attr.attr.mode = 0444;
>>> -			temp->temp_crit.attr.show = temp_crit_show;
>>> -			sysfs_attr_init(&temp->temp_crit.attr.attr);
>>> -			result = device_create_file(hwmon->device,
>>> -						    &temp->temp_crit.attr);
>>> -			if (result)
>>> -				goto unregister_input;
>>> -		}
>>> -	}
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	if (new_hwmon_device)
>>> -		list_add_tail(&hwmon->node, &thermal_hwmon_list);
>>> -	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	return 0;
>>> -
>>> - unregister_input:
>>> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
>>> - free_temp_mem:
>>> -	kfree(temp);
>>> - unregister_name:
>>> -	if (new_hwmon_device) {
>>> -		device_remove_file(hwmon->device, &dev_attr_name);
>>> -		hwmon_device_unregister(hwmon->device);
>>> -	}
>>> - free_mem:
>>> -	if (new_hwmon_device)
>>> -		kfree(hwmon);
>>> -
>>> -	return result;
>>> -}
>>> -
>>> -static void
>>> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
>>> -{
>>> -	struct thermal_hwmon_device *hwmon;
>>> -	struct thermal_hwmon_temp *temp;
>>> -
>>> -	hwmon = thermal_hwmon_lookup_by_type(tz);
>>> -	if (unlikely(!hwmon)) {
>>> -		/* Should never happen... */
>>> -		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
>>> -		return;
>>> -	}
>>> -
>>> -	temp = thermal_hwmon_lookup_temp(hwmon, tz);
>>> -	if (unlikely(!temp)) {
>>> -		/* Should never happen... */
>>> -		dev_dbg(&tz->device, "temperature input lookup failed!\n");
>>> -		return;
>>> -	}
>>> -
>>> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
>>> -	if (tz->ops->get_crit_temp)
>>> -		device_remove_file(hwmon->device, &temp->temp_crit.attr);
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_del(&temp->hwmon_node);
>>> -	kfree(temp);
>>> -	if (!list_empty(&hwmon->tz_list)) {
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		return;
>>> -	}
>>> -	list_del(&hwmon->node);
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	device_remove_file(hwmon->device, &dev_attr_name);
>>> -	hwmon_device_unregister(hwmon->device);
>>> -	kfree(hwmon);
>>> -}
>>> -#else
>>> -static int
>>> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
>>> -{
>>> -	return 0;
>>> -}
>>> -
>>> -static void
>>> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
>>> -{
>>> -}
>>> -#endif
>>> -
>>> -/**
>>> - * thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
>>> - * @tz:		thermal zone device
>>> - * @trip:	indicates which trip point the cooling devices is
>>> - *		associated with in this thermal zone.
>>> - * @cdev:	thermal cooling device
>>> - *
>>> - * This function is usually called in the thermal zone device .bind callback.
>>> - */
>>> -int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
>>> -				     int trip,
>>> -				     struct thermal_cooling_device *cdev,
>>> -				     unsigned long upper, unsigned long lower)
>>> -{
>>> -	struct thermal_instance *dev;
>>> -	struct thermal_instance *pos;
>>> -	struct thermal_zone_device *pos1;
>>> -	struct thermal_cooling_device *pos2;
>>> -	unsigned long max_state;
>>> -	int result;
>>> -
>>> -	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
>>> -		return -EINVAL;
>>> -
>>> -	list_for_each_entry(pos1, &thermal_tz_list, node) {
>>> -		if (pos1 == tz)
>>> -			break;
>>> -	}
>>> -	list_for_each_entry(pos2, &thermal_cdev_list, node) {
>>> -		if (pos2 == cdev)
>>> -			break;
>>> -	}
>>> -
>>> -	if (tz != pos1 || cdev != pos2)
>>> -		return -EINVAL;
>>> -
>>> -	cdev->ops->get_max_state(cdev, &max_state);
>>> -
>>> -	/* lower default 0, upper default max_state */
>>> -	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
>>> -	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
>>> -
>>> -	if (lower > upper || upper > max_state)
>>> -		return -EINVAL;
>>> -
>>> -	dev =
>>> -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
>>> -	if (!dev)
>>> -		return -ENOMEM;
>>> -	dev->tz = tz;
>>> -	dev->cdev = cdev;
>>> -	dev->trip = trip;
>>> -	dev->upper = upper;
>>> -	dev->lower = lower;
>>> -	dev->target = THERMAL_NO_TARGET;
>>> -
>>> -	result = get_idr(&tz->idr, &tz->lock, &dev->id);
>>> -	if (result)
>>> -		goto free_mem;
>>> -
>>> -	sprintf(dev->name, "cdev%d", dev->id);
>>> -	result =
>>> -	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
>>> -	if (result)
>>> -		goto release_idr;
>>> -
>>> -	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
>>> -	sysfs_attr_init(&dev->attr.attr);
>>> -	dev->attr.attr.name = dev->attr_name;
>>> -	dev->attr.attr.mode = 0444;
>>> -	dev->attr.show = thermal_cooling_device_trip_point_show;
>>> -	result = device_create_file(&tz->device, &dev->attr);
>>> -	if (result)
>>> -		goto remove_symbol_link;
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -	mutex_lock(&cdev->lock);
>>> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
>>> -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> -		result = -EEXIST;
>>> -		break;
>>> -	}
>>> -	if (!result) {
>>> -		list_add_tail(&dev->tz_node, &tz->thermal_instances);
>>> -		list_add_tail(&dev->cdev_node, &cdev->thermal_instances);
>>> -	}
>>> -	mutex_unlock(&cdev->lock);
>>> -	mutex_unlock(&tz->lock);
>>> -
>>> -	if (!result)
>>> -		return 0;
>>> -
>>> -	device_remove_file(&tz->device, &dev->attr);
>>> -remove_symbol_link:
>>> -	sysfs_remove_link(&tz->device.kobj, dev->name);
>>> -release_idr:
>>> -	release_idr(&tz->idr, &tz->lock, dev->id);
>>> -free_mem:
>>> -	kfree(dev);
>>> -	return result;
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
>>> -
>>> -/**
>>> - * thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
>>> - * @tz:		thermal zone device
>>> - * @trip:	indicates which trip point the cooling devices is
>>> - *		associated with in this thermal zone.
>>> - * @cdev:	thermal cooling device
>>> - *
>>> - * This function is usually called in the thermal zone device .unbind callback.
>>> - */
>>> -int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
>>> -				       int trip,
>>> -				       struct thermal_cooling_device *cdev)
>>> -{
>>> -	struct thermal_instance *pos, *next;
>>> -
>>> -	mutex_lock(&tz->lock);
>>> -	mutex_lock(&cdev->lock);
>>> -	list_for_each_entry_safe(pos, next, &tz->thermal_instances, tz_node) {
>>> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
>>> -			list_del(&pos->tz_node);
>>> -			list_del(&pos->cdev_node);
>>> -			mutex_unlock(&cdev->lock);
>>> -			mutex_unlock(&tz->lock);
>>> -			goto unbind;
>>> -		}
>>> -	}
>>> -	mutex_unlock(&cdev->lock);
>>> -	mutex_unlock(&tz->lock);
>>> -
>>> -	return -ENODEV;
>>> -
>>> -unbind:
>>> -	device_remove_file(&tz->device, &pos->attr);
>>> -	sysfs_remove_link(&tz->device.kobj, pos->name);
>>> -	release_idr(&tz->idr, &tz->lock, pos->id);
>>> -	kfree(pos);
>>> -	return 0;
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
>>> -
>>> -static void thermal_release(struct device *dev)
>>> -{
>>> -	struct thermal_zone_device *tz;
>>> -	struct thermal_cooling_device *cdev;
>>> -
>>> -	if (!strncmp(dev_name(dev), "thermal_zone",
>>> -		     sizeof("thermal_zone") - 1)) {
>>> -		tz = to_thermal_zone(dev);
>>> -		kfree(tz);
>>> -	} else {
>>> -		cdev = to_cooling_device(dev);
>>> -		kfree(cdev);
>>> -	}
>>> -}
>>> -
>>> -static struct class thermal_class = {
>>> -	.name = "thermal",
>>> -	.dev_release = thermal_release,
>>> -};
>>> -
>>> -/**
>>> - * thermal_cooling_device_register - register a new thermal cooling device
>>> - * @type:	the thermal cooling device type.
>>> - * @devdata:	device private data.
>>> - * @ops:		standard thermal cooling devices callbacks.
>>> - */
>>> -struct thermal_cooling_device *
>>> -thermal_cooling_device_register(char *type, void *devdata,
>>> -				const struct thermal_cooling_device_ops *ops)
>>> -{
>>> -	struct thermal_cooling_device *cdev;
>>> -	int result;
>>> -
>>> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
>>> -	    !ops->set_cur_state)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
>>> -	if (!cdev)
>>> -		return ERR_PTR(-ENOMEM);
>>> -
>>> -	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
>>> -	if (result) {
>>> -		kfree(cdev);
>>> -		return ERR_PTR(result);
>>> -	}
>>> -
>>> -	strcpy(cdev->type, type ? : "");
>>> -	mutex_init(&cdev->lock);
>>> -	INIT_LIST_HEAD(&cdev->thermal_instances);
>>> -	cdev->ops = ops;
>>> -	cdev->updated = true;
>>> -	cdev->device.class = &thermal_class;
>>> -	cdev->devdata = devdata;
>>> -	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
>>> -	result = device_register(&cdev->device);
>>> -	if (result) {
>>> -		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> -		kfree(cdev);
>>> -		return ERR_PTR(result);
>>> -	}
>>> -
>>> -	/* sys I/F */
>>> -	if (type) {
>>> -		result = device_create_file(&cdev->device, &dev_attr_cdev_type);
>>> -		if (result)
>>> -			goto unregister;
>>> -	}
>>> -
>>> -	result = device_create_file(&cdev->device, &dev_attr_max_state);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	result = device_create_file(&cdev->device, &dev_attr_cur_state);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	/* Add 'this' new cdev to the global cdev list */
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_add(&cdev->node, &thermal_cdev_list);
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	/* Update binding information for 'this' new cdev */
>>> -	bind_cdev(cdev);
>>> -
>>> -	return cdev;
>>> -
>>> -unregister:
>>> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> -	device_unregister(&cdev->device);
>>> -	return ERR_PTR(result);
>>> -}
>>> -EXPORT_SYMBOL(thermal_cooling_device_register);
>>> -
>>> -/**
>>> - * thermal_cooling_device_unregister - removes the registered thermal cooling device
>>> - * @cdev:	the thermal cooling device to remove.
>>> - *
>>> - * thermal_cooling_device_unregister() must be called when the device is no
>>> - * longer needed.
>>> - */
>>> -void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
>>> -{
>>> -	int i;
>>> -	const struct thermal_zone_params *tzp;
>>> -	struct thermal_zone_device *tz;
>>> -	struct thermal_cooling_device *pos = NULL;
>>> -
>>> -	if (!cdev)
>>> -		return;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_for_each_entry(pos, &thermal_cdev_list, node)
>>> -	    if (pos == cdev)
>>> -		break;
>>> -	if (pos != cdev) {
>>> -		/* thermal cooling device not found */
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		return;
>>> -	}
>>> -	list_del(&cdev->node);
>>> -
>>> -	/* Unbind all thermal zones associated with 'this' cdev */
>>> -	list_for_each_entry(tz, &thermal_tz_list, node) {
>>> -		if (tz->ops->unbind) {
>>> -			tz->ops->unbind(tz, cdev);
>>> -			continue;
>>> -		}
>>> -
>>> -		if (!tz->tzp || !tz->tzp->tbp)
>>> -			continue;
>>> -
>>> -		tzp = tz->tzp;
>>> -		for (i = 0; i < tzp->num_tbps; i++) {
>>> -			if (tzp->tbp[i].cdev == cdev) {
>>> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
>>> -				tzp->tbp[i].cdev = NULL;
>>> -			}
>>> -		}
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	if (cdev->type[0])
>>> -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
>>> -	device_remove_file(&cdev->device, &dev_attr_max_state);
>>> -	device_remove_file(&cdev->device, &dev_attr_cur_state);
>>> -
>>> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
>>> -	device_unregister(&cdev->device);
>>> -	return;
>>> -}
>>> -EXPORT_SYMBOL(thermal_cooling_device_unregister);
>>> -
>>> -void thermal_cdev_update(struct thermal_cooling_device *cdev)
>>> -{
>>> -	struct thermal_instance *instance;
>>> -	unsigned long target = 0;
>>> -
>>> -	/* cooling device is updated*/
>>> -	if (cdev->updated)
>>> -		return;
>>> -
>>> -	mutex_lock(&cdev->lock);
>>> -	/* Make sure cdev enters the deepest cooling state */
>>> -	list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) {
>>> -		if (instance->target == THERMAL_NO_TARGET)
>>> -			continue;
>>> -		if (instance->target > target)
>>> -			target = instance->target;
>>> -	}
>>> -	mutex_unlock(&cdev->lock);
>>> -	cdev->ops->set_cur_state(cdev, target);
>>> -	cdev->updated = true;
>>> -}
>>> -EXPORT_SYMBOL(thermal_cdev_update);
>>> -
>>> -/**
>>> - * notify_thermal_framework - Sensor drivers use this API to notify framework
>>> - * @tz:		thermal zone device
>>> - * @trip:	indicates which trip point has been crossed
>>> - *
>>> - * This function handles the trip events from sensor drivers. It starts
>>> - * throttling the cooling devices according to the policy configured.
>>> - * For CRITICAL and HOT trip points, this notifies the respective drivers,
>>> - * and does actual throttling for other trip points i.e ACTIVE and PASSIVE.
>>> - * The throttling policy is based on the configured platform data; if no
>>> - * platform data is provided, this uses the step_wise throttling policy.
>>> - */
>>> -void notify_thermal_framework(struct thermal_zone_device *tz, int trip)
>>> -{
>>> -	handle_thermal_trip(tz, trip);
>>> -}
>>> -EXPORT_SYMBOL(notify_thermal_framework);
>>> -
>>> -/**
>>> - * create_trip_attrs - create attributes for trip points
>>> - * @tz:		the thermal zone device
>>> - * @mask:	Writeable trip point bitmap.
>>> - */
>>> -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
>>> -{
>>> -	int indx;
>>> -	int size = sizeof(struct thermal_attr) * tz->trips;
>>> -
>>> -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
>>> -	if (!tz->trip_type_attrs)
>>> -		return -ENOMEM;
>>> -
>>> -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
>>> -	if (!tz->trip_temp_attrs) {
>>> -		kfree(tz->trip_type_attrs);
>>> -		return -ENOMEM;
>>> -	}
>>> -
>>> -	if (tz->ops->get_trip_hyst) {
>>> -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
>>> -		if (!tz->trip_hyst_attrs) {
>>> -			kfree(tz->trip_type_attrs);
>>> -			kfree(tz->trip_temp_attrs);
>>> -			return -ENOMEM;
>>> -		}
>>> -	}
>>> -
>>> -
>>> -	for (indx = 0; indx < tz->trips; indx++) {
>>> -		/* create trip type attribute */
>>> -		snprintf(tz->trip_type_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> -			 "trip_point_%d_type", indx);
>>> -
>>> -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
>>> -		tz->trip_type_attrs[indx].attr.attr.name =
>>> -						tz->trip_type_attrs[indx].name;
>>> -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
>>> -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
>>> -
>>> -		device_create_file(&tz->device,
>>> -				   &tz->trip_type_attrs[indx].attr);
>>> -
>>> -		/* create trip temp attribute */
>>> -		snprintf(tz->trip_temp_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> -			 "trip_point_%d_temp", indx);
>>> -
>>> -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
>>> -		tz->trip_temp_attrs[indx].attr.attr.name =
>>> -						tz->trip_temp_attrs[indx].name;
>>> -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
>>> -		tz->trip_temp_attrs[indx].attr.show = trip_point_temp_show;
>>> -		if (mask & (1 << indx)) {
>>> -			tz->trip_temp_attrs[indx].attr.attr.mode |= S_IWUSR;
>>> -			tz->trip_temp_attrs[indx].attr.store =
>>> -							trip_point_temp_store;
>>> -		}
>>> -
>>> -		device_create_file(&tz->device,
>>> -				   &tz->trip_temp_attrs[indx].attr);
>>> -
>>> -		/* create Optional trip hyst attribute */
>>> -		if (!tz->ops->get_trip_hyst)
>>> -			continue;
>>> -		snprintf(tz->trip_hyst_attrs[indx].name, THERMAL_NAME_LENGTH,
>>> -			 "trip_point_%d_hyst", indx);
>>> -
>>> -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
>>> -		tz->trip_hyst_attrs[indx].attr.attr.name =
>>> -					tz->trip_hyst_attrs[indx].name;
>>> -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
>>> -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
>>> -		if (tz->ops->set_trip_hyst) {
>>> -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
>>> -			tz->trip_hyst_attrs[indx].attr.store =
>>> -					trip_point_hyst_store;
>>> -		}
>>> -
>>> -		device_create_file(&tz->device,
>>> -				   &tz->trip_hyst_attrs[indx].attr);
>>> -	}
>>> -	return 0;
>>> -}
>>> -
>>> -static void remove_trip_attrs(struct thermal_zone_device *tz)
>>> -{
>>> -	int indx;
>>> -
>>> -	for (indx = 0; indx < tz->trips; indx++) {
>>> -		device_remove_file(&tz->device,
>>> -				   &tz->trip_type_attrs[indx].attr);
>>> -		device_remove_file(&tz->device,
>>> -				   &tz->trip_temp_attrs[indx].attr);
>>> -		if (tz->ops->get_trip_hyst)
>>> -			device_remove_file(&tz->device,
>>> -				  &tz->trip_hyst_attrs[indx].attr);
>>> -	}
>>> -	kfree(tz->trip_type_attrs);
>>> -	kfree(tz->trip_temp_attrs);
>>> -	kfree(tz->trip_hyst_attrs);
>>> -}
>>> -
>>> -/**
>>> - * thermal_zone_device_register - register a new thermal zone device
>>> - * @type:	the thermal zone device type
>>> - * @trips:	the number of trip points the thermal zone support
>>> - * @mask:	a bit string indicating the writeablility of trip points
>>> - * @devdata:	private device data
>>> - * @ops:	standard thermal zone device callbacks
>>> - * @tzp:	thermal zone platform parameters
>>> - * @passive_delay: number of milliseconds to wait between polls when
>>> - *		   performing passive cooling
>>> - * @polling_delay: number of milliseconds to wait between polls when checking
>>> - *		   whether trip points have been crossed (0 for interrupt
>>> - *		   driven systems)
>>> - *
>>> - * thermal_zone_device_unregister() must be called when the device is no
>>> - * longer needed. The passive cooling depends on the .get_trend() return value.
>>> - */
>>> -struct thermal_zone_device *thermal_zone_device_register(const char *type,
>>> -	int trips, int mask, void *devdata,
>>> -	const struct thermal_zone_device_ops *ops,
>>> -	const struct thermal_zone_params *tzp,
>>> -	int passive_delay, int polling_delay)
>>> -{
>>> -	struct thermal_zone_device *tz;
>>> -	enum thermal_trip_type trip_type;
>>> -	int result;
>>> -	int count;
>>> -	int passive = 0;
>>> -
>>> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	if (!ops || !ops->get_temp)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	if (trips > 0 && !ops->get_trip_type)
>>> -		return ERR_PTR(-EINVAL);
>>> -
>>> -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
>>> -	if (!tz)
>>> -		return ERR_PTR(-ENOMEM);
>>> -
>>> -	INIT_LIST_HEAD(&tz->thermal_instances);
>>> -	idr_init(&tz->idr);
>>> -	mutex_init(&tz->lock);
>>> -	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
>>> -	if (result) {
>>> -		kfree(tz);
>>> -		return ERR_PTR(result);
>>> -	}
>>> -
>>> -	strcpy(tz->type, type ? : "");
>>> -	tz->ops = ops;
>>> -	tz->tzp = tzp;
>>> -	tz->device.class = &thermal_class;
>>> -	tz->devdata = devdata;
>>> -	tz->trips = trips;
>>> -	tz->passive_delay = passive_delay;
>>> -	tz->polling_delay = polling_delay;
>>> -
>>> -	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
>>> -	result = device_register(&tz->device);
>>> -	if (result) {
>>> -		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> -		kfree(tz);
>>> -		return ERR_PTR(result);
>>> -	}
>>> -
>>> -	/* sys I/F */
>>> -	if (type) {
>>> -		result = device_create_file(&tz->device, &dev_attr_type);
>>> -		if (result)
>>> -			goto unregister;
>>> -	}
>>> -
>>> -	result = device_create_file(&tz->device, &dev_attr_temp);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	if (ops->get_mode) {
>>> -		result = device_create_file(&tz->device, &dev_attr_mode);
>>> -		if (result)
>>> -			goto unregister;
>>> -	}
>>> -
>>> -	result = create_trip_attrs(tz, mask);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	for (count = 0; count < trips; count++) {
>>> -		tz->ops->get_trip_type(tz, count, &trip_type);
>>> -		if (trip_type == THERMAL_TRIP_PASSIVE)
>>> -			passive = 1;
>>> -	}
>>> -
>>> -	if (!passive) {
>>> -		result = device_create_file(&tz->device, &dev_attr_passive);
>>> -		if (result)
>>> -			goto unregister;
>>> -	}
>>> -
>>> -#ifdef CONFIG_THERMAL_EMULATION
>>> -	result = device_create_file(&tz->device, &dev_attr_emul_temp);
>>> -	if (result)
>>> -		goto unregister;
>>> -#endif
>>> -	/* Create policy attribute */
>>> -	result = device_create_file(&tz->device, &dev_attr_policy);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	/* Update 'this' zone's governor information */
>>> -	mutex_lock(&thermal_governor_lock);
>>> -
>>> -	if (tz->tzp)
>>> -		tz->governor = __find_governor(tz->tzp->governor_name);
>>> -	else
>>> -		tz->governor = __find_governor(DEFAULT_THERMAL_GOVERNOR);
>>> -
>>> -	mutex_unlock(&thermal_governor_lock);
>>> -
>>> -	result = thermal_add_hwmon_sysfs(tz);
>>> -	if (result)
>>> -		goto unregister;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_add_tail(&tz->node, &thermal_tz_list);
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	/* Bind cooling devices for this zone */
>>> -	bind_tz(tz);
>>> -
>>> -	INIT_DELAYED_WORK(&(tz->poll_queue), thermal_zone_device_check);
>>> -
>>> -	thermal_zone_device_update(tz);
>>> -
>>> -	if (!result)
>>> -		return tz;
>>> -
>>> -unregister:
>>> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> -	device_unregister(&tz->device);
>>> -	return ERR_PTR(result);
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_device_register);
>>> -
>>> -/**
>>> - * thermal_device_unregister - removes the registered thermal zone device
>>> - * @tz: the thermal zone device to remove
>>> - */
>>> -void thermal_zone_device_unregister(struct thermal_zone_device *tz)
>>> -{
>>> -	int i;
>>> -	const struct thermal_zone_params *tzp;
>>> -	struct thermal_cooling_device *cdev;
>>> -	struct thermal_zone_device *pos = NULL;
>>> -
>>> -	if (!tz)
>>> -		return;
>>> -
>>> -	tzp = tz->tzp;
>>> -
>>> -	mutex_lock(&thermal_list_lock);
>>> -	list_for_each_entry(pos, &thermal_tz_list, node)
>>> -	    if (pos == tz)
>>> -		break;
>>> -	if (pos != tz) {
>>> -		/* thermal zone device not found */
>>> -		mutex_unlock(&thermal_list_lock);
>>> -		return;
>>> -	}
>>> -	list_del(&tz->node);
>>> -
>>> -	/* Unbind all cdevs associated with 'this' thermal zone */
>>> -	list_for_each_entry(cdev, &thermal_cdev_list, node) {
>>> -		if (tz->ops->unbind) {
>>> -			tz->ops->unbind(tz, cdev);
>>> -			continue;
>>> -		}
>>> -
>>> -		if (!tzp || !tzp->tbp)
>>> -			break;
>>> -
>>> -		for (i = 0; i < tzp->num_tbps; i++) {
>>> -			if (tzp->tbp[i].cdev == cdev) {
>>> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
>>> -				tzp->tbp[i].cdev = NULL;
>>> -			}
>>> -		}
>>> -	}
>>> -
>>> -	mutex_unlock(&thermal_list_lock);
>>> -
>>> -	thermal_zone_device_set_polling(tz, 0);
>>> -
>>> -	if (tz->type[0])
>>> -		device_remove_file(&tz->device, &dev_attr_type);
>>> -	device_remove_file(&tz->device, &dev_attr_temp);
>>> -	if (tz->ops->get_mode)
>>> -		device_remove_file(&tz->device, &dev_attr_mode);
>>> -	device_remove_file(&tz->device, &dev_attr_policy);
>>> -	remove_trip_attrs(tz);
>>> -	tz->governor = NULL;
>>> -
>>> -	thermal_remove_hwmon_sysfs(tz);
>>> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
>>> -	idr_destroy(&tz->idr);
>>> -	mutex_destroy(&tz->lock);
>>> -	device_unregister(&tz->device);
>>> -	return;
>>> -}
>>> -EXPORT_SYMBOL(thermal_zone_device_unregister);
>>> -
>>> -#ifdef CONFIG_NET
>>> -static struct genl_family thermal_event_genl_family = {
>>> -	.id = GENL_ID_GENERATE,
>>> -	.name = THERMAL_GENL_FAMILY_NAME,
>>> -	.version = THERMAL_GENL_VERSION,
>>> -	.maxattr = THERMAL_GENL_ATTR_MAX,
>>> -};
>>> -
>>> -static struct genl_multicast_group thermal_event_mcgrp = {
>>> -	.name = THERMAL_GENL_MCAST_GROUP_NAME,
>>> -};
>>> -
>>> -int thermal_generate_netlink_event(struct thermal_zone_device *tz,
>>> -					enum events event)
>>> -{
>>> -	struct sk_buff *skb;
>>> -	struct nlattr *attr;
>>> -	struct thermal_genl_event *thermal_event;
>>> -	void *msg_header;
>>> -	int size;
>>> -	int result;
>>> -	static unsigned int thermal_event_seqnum;
>>> -
>>> -	if (!tz)
>>> -		return -EINVAL;
>>> -
>>> -	/* allocate memory */
>>> -	size = nla_total_size(sizeof(struct thermal_genl_event)) +
>>> -	       nla_total_size(0);
>>> -
>>> -	skb = genlmsg_new(size, GFP_ATOMIC);
>>> -	if (!skb)
>>> -		return -ENOMEM;
>>> -
>>> -	/* add the genetlink message header */
>>> -	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
>>> -				 &thermal_event_genl_family, 0,
>>> -				 THERMAL_GENL_CMD_EVENT);
>>> -	if (!msg_header) {
>>> -		nlmsg_free(skb);
>>> -		return -ENOMEM;
>>> -	}
>>> -
>>> -	/* fill the data */
>>> -	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
>>> -			   sizeof(struct thermal_genl_event));
>>> -
>>> -	if (!attr) {
>>> -		nlmsg_free(skb);
>>> -		return -EINVAL;
>>> -	}
>>> -
>>> -	thermal_event = nla_data(attr);
>>> -	if (!thermal_event) {
>>> -		nlmsg_free(skb);
>>> -		return -EINVAL;
>>> -	}
>>> -
>>> -	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
>>> -
>>> -	thermal_event->orig = tz->id;
>>> -	thermal_event->event = event;
>>> -
>>> -	/* send multicast genetlink message */
>>> -	result = genlmsg_end(skb, msg_header);
>>> -	if (result < 0) {
>>> -		nlmsg_free(skb);
>>> -		return result;
>>> -	}
>>> -
>>> -	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id, GFP_ATOMIC);
>>> -	if (result)
>>> -		dev_err(&tz->device, "Failed to send netlink event:%d", result);
>>> -
>>> -	return result;
>>> -}
>>> -EXPORT_SYMBOL(thermal_generate_netlink_event);
>>> -
>>> -static int genetlink_init(void)
>>> -{
>>> -	int result;
>>> -
>>> -	result = genl_register_family(&thermal_event_genl_family);
>>> -	if (result)
>>> -		return result;
>>> -
>>> -	result = genl_register_mc_group(&thermal_event_genl_family,
>>> -					&thermal_event_mcgrp);
>>> -	if (result)
>>> -		genl_unregister_family(&thermal_event_genl_family);
>>> -	return result;
>>> -}
>>> -
>>> -static void genetlink_exit(void)
>>> -{
>>> -	genl_unregister_family(&thermal_event_genl_family);
>>> -}
>>> -#else /* !CONFIG_NET */
>>> -static inline int genetlink_init(void) { return 0; }
>>> -static inline void genetlink_exit(void) {}
>>> -#endif /* !CONFIG_NET */
>>> -
>>> -static int __init thermal_init(void)
>>> -{
>>> -	int result = 0;
>>> -
>>> -	result = class_register(&thermal_class);
>>> -	if (result) {
>>> -		idr_destroy(&thermal_tz_idr);
>>> -		idr_destroy(&thermal_cdev_idr);
>>> -		mutex_destroy(&thermal_idr_lock);
>>> -		mutex_destroy(&thermal_list_lock);
>>> -		return result;
>>> -	}
>>> -	result = genetlink_init();
>>> -	return result;
>>> -}
>>> -
>>> -static void __exit thermal_exit(void)
>>> -{
>>> -	class_unregister(&thermal_class);
>>> -	idr_destroy(&thermal_tz_idr);
>>> -	idr_destroy(&thermal_cdev_idr);
>>> -	mutex_destroy(&thermal_idr_lock);
>>> -	mutex_destroy(&thermal_list_lock);
>>> -	genetlink_exit();
>>> -}
>>> -
>>> -fs_initcall(thermal_init);
>>> -module_exit(thermal_exit);
>>>
>>
>
>
>
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [RFC,1/5] Thermal: rename thermal_sys.c to thermal_core.c
  2013-04-01 12:43         ` Eduardo Valentin
@ 2013-04-01 13:09           ` R, Durgadoss
  -1 siblings, 0 replies; 23+ messages in thread
From: R, Durgadoss @ 2013-04-01 13:09 UTC (permalink / raw)
  To: Eduardo Valentin, Zhang, Rui; +Cc: linux-pm, linux-kernel, amit.daniel, andi

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset="utf-8", Size: 124815 bytes --]

> -----Original Message-----
> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
> Sent: Monday, April 01, 2013 6:14 PM
> To: Zhang, Rui
> Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> amit.daniel@samsung.com; R, Durgadoss; andi@lisas.de
> Subject: Re: [RFC,1/5] Thermal: rename thermal_sys.c to thermal_core.c
> 
> Hey Rui,
> 
> On 27-03-2013 22:40, Zhang Rui wrote:
> > On Tue, 2013-03-26 at 18:04 -0400, Eduardo Valentin wrote:
> >> Hi Rui,
> >>
> >> A side note:
> >> I'd really appreciate if you could copy on your patches on
> >> drivers/thermal/. I had some issues with TI server and got un subscribed
> >> from linux-pm. Now I will try to catch up any way,
> >>
> > sure.
> >
> >> Some comments.
> >>
> >> On 26-03-2013 12:26, Zhang Rui wrote:
> >>> No functional change in this patch.
> >>>
> >>
> >> Just a better description would also help on code version control.
> >>
> > will add it in V2.
> >
> >>> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> >>
> >> Apart from minor comments, I agreed with this change. So feel free to
> >> add my:
> >>
> >> Acked-by: Eduardo Valentin <eduardo.valentin@ti.com>
> >>
> > thanks!
> >
> >>>
> >>> ---
> >>> drivers/thermal/Makefile       |    1 +
> >>>    drivers/thermal/thermal_core.c | 1888
> ++++++++++++++++++++++++++++++++++++++++
> >>>    drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------
> >>
> >> When sending renames, use git format-patch --find-renames, it makes a
> >> better summary of what you have done, specially if you have changed
> >> something in the file while renaming.
> >>
> > a useful tip. thanks!
> >>>    3 files changed, 1889 insertions(+), 1888 deletions(-)
> >>>    create mode 100644 drivers/thermal/thermal_core.c
> >>>    delete mode 100644 drivers/thermal/thermal_sys.c
> >>>
> >>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> >>> index d3a2b38..b2009bd 100644
> >>> --- a/drivers/thermal/Makefile
> >>> +++ b/drivers/thermal/Makefile
> >>> @@ -3,6 +3,7 @@
> >>>    #
> >>>
> >>>    obj-$(CONFIG_THERMAL)		+= thermal_sys.o
> >>
> >> I know this is for fixing the annoying bug with fan max speed. But while
> >> still here, do you think 'thermal_sys' is a good name for thermal
> >> framework driver? Maybe just 'thermal' would suffice?
> >>
> > as I said, there is already a thermal driver, aka,
> > driver/acpi/thermal.c.
> >
> 
> In fact there is. On the other hand, it does not imply that this naming
> convention is correct, right?
> 
> Unless you have a strong requirement to name these drivers the way it
> is, I'd suggest to take the opportunity to rename them.
> drivers/acpi/thermal.c could be named 'thermal-acpi.ko', if this does
> not violate any ACPI requirements. While this driver,
> drivers/thermal/thermal_sys.c, would be named only 'thermal.ko'.

Yes, I was also thinking of the same thing.
Can we do this Rui ?

Thanks,
Durga

> 
> 
> > thanks,
> 
> Regards,
> 
> Ed
> 
> > rui
> >>> +thermal_sys-y			+= thermal_core.o
> >>>
> >>>    # governors
> >>>    obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> >>> diff --git a/drivers/thermal/thermal_core.c
> b/drivers/thermal/thermal_core.c
> >>> new file mode 100644
> >>> index 0000000..5b7863a
> >>> --- /dev/null
> >>> +++ b/drivers/thermal/thermal_core.c
> >>> @@ -0,0 +1,1888 @@
> >>> +/*
> >>> + *  thermal.c - Generic Thermal Management Sysfs support.
> >>> + *
> >>> + *  Copyright (C) 2008 Intel Corp
> >>> + *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> >>> + *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> >>> + *
> >>> + *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> >>> + *
> >>> + *  This program is free software; you can redistribute it and/or modify
> >>> + *  it under the terms of the GNU General Public License as published
> by
> >>> + *  the Free Software Foundation; version 2 of the License.
> >>> + *
> >>> + *  This program is distributed in the hope that it will be useful, but
> >>> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> >>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> the GNU
> >>> + *  General Public License for more details.
> >>> + *
> >>> + *  You should have received a copy of the GNU General Public License
> along
> >>> + *  with this program; if not, write to the Free Software Foundation,
> Inc.,
> >>> + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> >>> + *
> >>> + *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> >>> + */
> >>> +
> >>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> >>> +
> >>> +#include <linux/module.h>
> >>> +#include <linux/device.h>
> >>> +#include <linux/err.h>
> >>> +#include <linux/slab.h>
> >>> +#include <linux/kdev_t.h>
> >>> +#include <linux/idr.h>
> >>> +#include <linux/thermal.h>
> >>> +#include <linux/reboot.h>
> >>> +#include <net/netlink.h>
> >>> +#include <net/genetlink.h>
> >>> +
> >>> +#include "thermal_core.h"
> >>> +
> >>> +MODULE_AUTHOR("Zhang Rui");
> >>> +MODULE_DESCRIPTION("Generic thermal management sysfs
> support");
> >>> +MODULE_LICENSE("GPL");
> >>> +
> >>> +static DEFINE_IDR(thermal_tz_idr);
> >>> +static DEFINE_IDR(thermal_cdev_idr);
> >>> +static DEFINE_MUTEX(thermal_idr_lock);
> >>> +
> >>> +static LIST_HEAD(thermal_tz_list);
> >>> +static LIST_HEAD(thermal_cdev_list);
> >>> +static LIST_HEAD(thermal_governor_list);
> >>> +
> >>> +static DEFINE_MUTEX(thermal_list_lock);
> >>> +static DEFINE_MUTEX(thermal_governor_lock);
> >>> +
> >>> +static struct thermal_governor *__find_governor(const char *name)
> >>> +{
> >>> +	struct thermal_governor *pos;
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> >>> +		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> >>> +			return pos;
> >>> +
> >>> +	return NULL;
> >>> +}
> >>> +
> >>> +int thermal_register_governor(struct thermal_governor *governor)
> >>> +{
> >>> +	int err;
> >>> +	const char *name;
> >>> +	struct thermal_zone_device *pos;
> >>> +
> >>> +	if (!governor)
> >>> +		return -EINVAL;
> >>> +
> >>> +	mutex_lock(&thermal_governor_lock);
> >>> +
> >>> +	err = -EBUSY;
> >>> +	if (__find_governor(governor->name) == NULL) {
> >>> +		err = 0;
> >>> +		list_add(&governor->governor_list,
> &thermal_governor_list);
> >>> +	}
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> +		if (pos->governor)
> >>> +			continue;
> >>> +		if (pos->tzp)
> >>> +			name = pos->tzp->governor_name;
> >>> +		else
> >>> +			name = DEFAULT_THERMAL_GOVERNOR;
> >>> +		if (!strnicmp(name, governor->name,
> THERMAL_NAME_LENGTH))
> >>> +			pos->governor = governor;
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +	mutex_unlock(&thermal_governor_lock);
> >>> +
> >>> +	return err;
> >>> +}
> >>> +EXPORT_SYMBOL_GPL(thermal_register_governor);
> >>> +
> >>> +void thermal_unregister_governor(struct thermal_governor
> *governor)
> >>> +{
> >>> +	struct thermal_zone_device *pos;
> >>> +
> >>> +	if (!governor)
> >>> +		return;
> >>> +
> >>> +	mutex_lock(&thermal_governor_lock);
> >>> +
> >>> +	if (__find_governor(governor->name) == NULL)
> >>> +		goto exit;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> +		if (!strnicmp(pos->governor->name, governor->name,
> >>> +						THERMAL_NAME_LENGTH))
> >>> +			pos->governor = NULL;
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +	list_del(&governor->governor_list);
> >>> +exit:
> >>> +	mutex_unlock(&thermal_governor_lock);
> >>> +	return;
> >>> +}
> >>> +EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> >>> +
> >>> +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> >>> +{
> >>> +	int ret;
> >>> +
> >>> +	if (lock)
> >>> +		mutex_lock(lock);
> >>> +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> >>> +	if (lock)
> >>> +		mutex_unlock(lock);
> >>> +	if (unlikely(ret < 0))
> >>> +		return ret;
> >>> +	*id = ret;
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static void release_idr(struct idr *idr, struct mutex *lock, int id)
> >>> +{
> >>> +	if (lock)
> >>> +		mutex_lock(lock);
> >>> +	idr_remove(idr, id);
> >>> +	if (lock)
> >>> +		mutex_unlock(lock);
> >>> +}
> >>> +
> >>> +int get_tz_trend(struct thermal_zone_device *tz, int trip)
> >>> +{
> >>> +	enum thermal_trend trend;
> >>> +
> >>> +	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> >>> +		if (tz->temperature > tz->last_temperature)
> >>> +			trend = THERMAL_TREND_RAISING;
> >>> +		else if (tz->temperature < tz->last_temperature)
> >>> +			trend = THERMAL_TREND_DROPPING;
> >>> +		else
> >>> +			trend = THERMAL_TREND_STABLE;
> >>> +	}
> >>> +
> >>> +	return trend;
> >>> +}
> >>> +EXPORT_SYMBOL(get_tz_trend);
> >>> +
> >>> +struct thermal_instance *get_thermal_instance(struct
> thermal_zone_device *tz,
> >>> +			struct thermal_cooling_device *cdev, int trip)
> >>> +{
> >>> +	struct thermal_instance *pos = NULL;
> >>> +	struct thermal_instance *target_instance = NULL;
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +	mutex_lock(&cdev->lock);
> >>> +
> >>> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> >>> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> +			target_instance = pos;
> >>> +			break;
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&cdev->lock);
> >>> +	mutex_unlock(&tz->lock);
> >>> +
> >>> +	return target_instance;
> >>> +}
> >>> +EXPORT_SYMBOL(get_thermal_instance);
> >>> +
> >>> +static void print_bind_err_msg(struct thermal_zone_device *tz,
> >>> +			struct thermal_cooling_device *cdev, int ret)
> >>> +{
> >>> +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> >>> +				tz->type, cdev->type, ret);
> >>> +}
> >>> +
> >>> +static void __bind(struct thermal_zone_device *tz, int mask,
> >>> +			struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	int i, ret;
> >>> +
> >>> +	for (i = 0; i < tz->trips; i++) {
> >>> +		if (mask & (1 << i)) {
> >>> +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> >>> +					THERMAL_NO_LIMIT,
> THERMAL_NO_LIMIT);
> >>> +			if (ret)
> >>> +				print_bind_err_msg(tz, cdev, ret);
> >>> +		}
> >>> +	}
> >>> +}
> >>> +
> >>> +static void __unbind(struct thermal_zone_device *tz, int mask,
> >>> +			struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	int i;
> >>> +
> >>> +	for (i = 0; i < tz->trips; i++)
> >>> +		if (mask & (1 << i))
> >>> +			thermal_zone_unbind_cooling_device(tz, i, cdev);
> >>> +}
> >>> +
> >>> +static void bind_cdev(struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	int i, ret;
> >>> +	const struct thermal_zone_params *tzp;
> >>> +	struct thermal_zone_device *pos = NULL;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> +		if (!pos->tzp && !pos->ops->bind)
> >>> +			continue;
> >>> +
> >>> +		if (!pos->tzp && pos->ops->bind) {
> >>> +			ret = pos->ops->bind(pos, cdev);
> >>> +			if (ret)
> >>> +				print_bind_err_msg(pos, cdev, ret);
> >>> +		}
> >>> +
> >>> +		tzp = pos->tzp;
> >>> +		if (!tzp || !tzp->tbp)
> >>> +			continue;
> >>> +
> >>> +		for (i = 0; i < tzp->num_tbps; i++) {
> >>> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> >>> +				continue;
> >>> +			if (tzp->tbp[i].match(pos, cdev))
> >>> +				continue;
> >>> +			tzp->tbp[i].cdev = cdev;
> >>> +			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +}
> >>> +
> >>> +static void bind_tz(struct thermal_zone_device *tz)
> >>> +{
> >>> +	int i, ret;
> >>> +	struct thermal_cooling_device *pos = NULL;
> >>> +	const struct thermal_zone_params *tzp = tz->tzp;
> >>> +
> >>> +	if (!tzp && !tz->ops->bind)
> >>> +		return;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +
> >>> +	/* If there is no platform data, try to use ops->bind */
> >>> +	if (!tzp && tz->ops->bind) {
> >>> +		list_for_each_entry(pos, &thermal_cdev_list, node) {
> >>> +			ret = tz->ops->bind(tz, pos);
> >>> +			if (ret)
> >>> +				print_bind_err_msg(tz, pos, ret);
> >>> +		}
> >>> +		goto exit;
> >>> +	}
> >>> +
> >>> +	if (!tzp || !tzp->tbp)
> >>> +		goto exit;
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_cdev_list, node) {
> >>> +		for (i = 0; i < tzp->num_tbps; i++) {
> >>> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> >>> +				continue;
> >>> +			if (tzp->tbp[i].match(tz, pos))
> >>> +				continue;
> >>> +			tzp->tbp[i].cdev = pos;
> >>> +			__bind(tz, tzp->tbp[i].trip_mask, pos);
> >>> +		}
> >>> +	}
> >>> +exit:
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +}
> >>> +
> >>> +static void thermal_zone_device_set_polling(struct
> thermal_zone_device *tz,
> >>> +					    int delay)
> >>> +{
> >>> +	if (delay > 1000)
> >>> +		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> >>> +				 round_jiffies(msecs_to_jiffies(delay)));
> >>> +	else if (delay)
> >>> +		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> >>> +				 msecs_to_jiffies(delay));
> >>> +	else
> >>> +		cancel_delayed_work(&tz->poll_queue);
> >>> +}
> >>> +
> >>> +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);
> >>> +	else if (tz->polling_delay)
> >>> +		thermal_zone_device_set_polling(tz, tz->polling_delay);
> >>> +	else
> >>> +		thermal_zone_device_set_polling(tz, 0);
> >>> +
> >>> +	mutex_unlock(&tz->lock);
> >>> +}
> >>> +
> >>> +static void handle_non_critical_trips(struct thermal_zone_device *tz,
> >>> +			int trip, enum thermal_trip_type trip_type)
> >>> +{
> >>> +	if (tz->governor)
> >>> +		tz->governor->throttle(tz, trip);
> >>> +}
> >>> +
> >>> +static void handle_critical_trips(struct thermal_zone_device *tz,
> >>> +				int trip, enum thermal_trip_type trip_type)
> >>> +{
> >>> +	long trip_temp;
> >>> +
> >>> +	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> >>> +
> >>> +	/* If we have not crossed the trip_temp, we do not care. */
> >>> +	if (tz->temperature < trip_temp)
> >>> +		return;
> >>> +
> >>> +	if (tz->ops->notify)
> >>> +		tz->ops->notify(tz, trip, trip_type);
> >>> +
> >>> +	if (trip_type == THERMAL_TRIP_CRITICAL) {
> >>> +		dev_emerg(&tz->device,
> >>> +			  "critical temperature reached(%d C),shutting
> down\n",
> >>> +			  tz->temperature / 1000);
> >>> +		orderly_poweroff(true);
> >>> +	}
> >>> +}
> >>> +
> >>> +static void handle_thermal_trip(struct thermal_zone_device *tz, int
> trip)
> >>> +{
> >>> +	enum thermal_trip_type type;
> >>> +
> >>> +	tz->ops->get_trip_type(tz, trip, &type);
> >>> +
> >>> +	if (type == THERMAL_TRIP_CRITICAL || type ==
> THERMAL_TRIP_HOT)
> >>> +		handle_critical_trips(tz, trip, type);
> >>> +	else
> >>> +		handle_non_critical_trips(tz, trip, type);
> >>> +	/*
> >>> +	 * Alright, we handled this trip successfully.
> >>> +	 * So, start monitoring again.
> >>> +	 */
> >>> +	monitor_thermal_zone(tz);
> >>> +}
> >>> +
> >>> +static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> >>> +				unsigned long *temp)
> >>> +{
> >>> +	int ret = 0;
> >>> +#ifdef CONFIG_THERMAL_EMULATION
> >>> +	int count;
> >>> +	unsigned long crit_temp = -1UL;
> >>> +	enum thermal_trip_type type;
> >>> +#endif
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +
> >>> +	ret = tz->ops->get_temp(tz, temp);
> >>> +#ifdef CONFIG_THERMAL_EMULATION
> >>> +	if (!tz->emul_temperature)
> >>> +		goto skip_emul;
> >>> +
> >>> +	for (count = 0; count < tz->trips; count++) {
> >>> +		ret = tz->ops->get_trip_type(tz, count, &type);
> >>> +		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> >>> +			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> >>> +			break;
> >>> +		}
> >>> +	}
> >>> +
> >>> +	if (ret)
> >>> +		goto skip_emul;
> >>> +
> >>> +	if (*temp < crit_temp)
> >>> +		*temp = tz->emul_temperature;
> >>> +skip_emul:
> >>> +#endif
> >>> +	mutex_unlock(&tz->lock);
> >>> +	return ret;
> >>> +}
> >>> +
> >>> +static void update_temperature(struct thermal_zone_device *tz)
> >>> +{
> >>> +	long temp;
> >>> +	int ret;
> >>> +
> >>> +	ret = thermal_zone_get_temp(tz, &temp);
> >>> +	if (ret) {
> >>> +		dev_warn(&tz->device, "failed to read out thermal zone
> %d\n",
> >>> +			 tz->id);
> >>> +		return;
> >>> +	}
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +	tz->last_temperature = tz->temperature;
> >>> +	tz->temperature = temp;
> >>> +	mutex_unlock(&tz->lock);
> >>> +}
> >>> +
> >>> +void thermal_zone_device_update(struct thermal_zone_device *tz)
> >>> +{
> >>> +	int count;
> >>> +
> >>> +	update_temperature(tz);
> >>> +
> >>> +	for (count = 0; count < tz->trips; count++)
> >>> +		handle_thermal_trip(tz, count);
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_device_update);
> >>> +
> >>> +static void thermal_zone_device_check(struct work_struct *work)
> >>> +{
> >>> +	struct thermal_zone_device *tz = container_of(work, struct
> >>> +						      thermal_zone_device,
> >>> +						      poll_queue.work);
> >>> +	thermal_zone_device_update(tz);
> >>> +}
> >>> +
> >>> +/* sys I/F for thermal zone */
> >>> +
> >>> +#define to_thermal_zone(_dev) \
> >>> +	container_of(_dev, struct thermal_zone_device, device)
> >>> +
> >>> +static ssize_t
> >>> +type_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +
> >>> +	return sprintf(buf, "%s\n", tz->type);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +temp_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	long temperature;
> >>> +	int ret;
> >>> +
> >>> +	ret = thermal_zone_get_temp(tz, &temperature);
> >>> +
> >>> +	if (ret)
> >>> +		return ret;
> >>> +
> >>> +	return sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +mode_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	enum thermal_device_mode mode;
> >>> +	int result;
> >>> +
> >>> +	if (!tz->ops->get_mode)
> >>> +		return -EPERM;
> >>> +
> >>> +	result = tz->ops->get_mode(tz, &mode);
> >>> +	if (result)
> >>> +		return result;
> >>> +
> >>> +	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ?
> "enabled"
> >>> +		       : "disabled");
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +mode_store(struct device *dev, struct device_attribute *attr,
> >>> +	   const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int result;
> >>> +
> >>> +	if (!tz->ops->set_mode)
> >>> +		return -EPERM;
> >>> +
> >>> +	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);
> >>> +	else
> >>> +		result = -EINVAL;
> >>> +
> >>> +	if (result)
> >>> +		return result;
> >>> +
> >>> +	return count;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_type_show(struct device *dev, struct device_attribute
> *attr,
> >>> +		     char *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	enum thermal_trip_type type;
> >>> +	int trip, result;
> >>> +
> >>> +	if (!tz->ops->get_trip_type)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	result = tz->ops->get_trip_type(tz, trip, &type);
> >>> +	if (result)
> >>> +		return result;
> >>> +
> >>> +	switch (type) {
> >>> +	case THERMAL_TRIP_CRITICAL:
> >>> +		return sprintf(buf, "critical\n");
> >>> +	case THERMAL_TRIP_HOT:
> >>> +		return sprintf(buf, "hot\n");
> >>> +	case THERMAL_TRIP_PASSIVE:
> >>> +		return sprintf(buf, "passive\n");
> >>> +	case THERMAL_TRIP_ACTIVE:
> >>> +		return sprintf(buf, "active\n");
> >>> +	default:
> >>> +		return sprintf(buf, "unknown\n");
> >>> +	}
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_temp_store(struct device *dev, struct device_attribute
> *attr,
> >>> +		     const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int trip, ret;
> >>> +	unsigned long temperature;
> >>> +
> >>> +	if (!tz->ops->set_trip_temp)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	if (kstrtoul(buf, 10, &temperature))
> >>> +		return -EINVAL;
> >>> +
> >>> +	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> >>> +
> >>> +	return ret ? ret : count;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_temp_show(struct device *dev, struct device_attribute
> *attr,
> >>> +		     char *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int trip, ret;
> >>> +	long temperature;
> >>> +
> >>> +	if (!tz->ops->get_trip_temp)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> >>> +
> >>> +	if (ret)
> >>> +		return ret;
> >>> +
> >>> +	return sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_hyst_store(struct device *dev, struct device_attribute
> *attr,
> >>> +			const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int trip, ret;
> >>> +	unsigned long temperature;
> >>> +
> >>> +	if (!tz->ops->set_trip_hyst)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	if (kstrtoul(buf, 10, &temperature))
> >>> +		return -EINVAL;
> >>> +
> >>> +	/*
> >>> +	 * We are not doing any check on the 'temperature' value
> >>> +	 * here. The driver implementing 'set_trip_hyst' has to
> >>> +	 * take care of this.
> >>> +	 */
> >>> +	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> >>> +
> >>> +	return ret ? ret : count;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_hyst_show(struct device *dev, struct device_attribute
> *attr,
> >>> +			char *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int trip, ret;
> >>> +	unsigned long temperature;
> >>> +
> >>> +	if (!tz->ops->get_trip_hyst)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> >>> +
> >>> +	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +passive_store(struct device *dev, struct device_attribute *attr,
> >>> +		    const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	struct thermal_cooling_device *cdev = NULL;
> >>> +	int state;
> >>> +
> >>> +	if (!sscanf(buf, "%d\n", &state))
> >>> +		return -EINVAL;
> >>> +
> >>> +	/* sanity check: values below 1000 millicelcius don't make sense
> >>> +	 * and can cause the system to go into a thermal heart attack
> >>> +	 */
> >>> +	if (state && state < 1000)
> >>> +		return -EINVAL;
> >>> +
> >>> +	if (state && !tz->forced_passive) {
> >>> +		mutex_lock(&thermal_list_lock);
> >>> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> +			if (!strncmp("Processor", cdev->type,
> >>> +				     sizeof("Processor")))
> >>> +				thermal_zone_bind_cooling_device(tz,
> >>> +						THERMAL_TRIPS_NONE,
> cdev,
> >>> +						THERMAL_NO_LIMIT,
> >>> +						THERMAL_NO_LIMIT);
> >>> +		}
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		if (!tz->passive_delay)
> >>> +			tz->passive_delay = 1000;
> >>> +	} else if (!state && tz->forced_passive) {
> >>> +		mutex_lock(&thermal_list_lock);
> >>> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> +			if (!strncmp("Processor", cdev->type,
> >>> +				     sizeof("Processor")))
> >>> +				thermal_zone_unbind_cooling_device(tz,
> >>> +
> THERMAL_TRIPS_NONE,
> >>> +								   cdev);
> >>> +		}
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		tz->passive_delay = 0;
> >>> +	}
> >>> +
> >>> +	tz->forced_passive = state;
> >>> +
> >>> +	thermal_zone_device_update(tz);
> >>> +
> >>> +	return count;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +passive_show(struct device *dev, struct device_attribute *attr,
> >>> +		   char *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +
> >>> +	return sprintf(buf, "%d\n", tz->forced_passive);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +policy_store(struct device *dev, struct device_attribute *attr,
> >>> +		    const char *buf, size_t count)
> >>> +{
> >>> +	int ret = -EINVAL;
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	struct thermal_governor *gov;
> >>> +
> >>> +	mutex_lock(&thermal_governor_lock);
> >>> +
> >>> +	gov = __find_governor(buf);
> >>> +	if (!gov)
> >>> +		goto exit;
> >>> +
> >>> +	tz->governor = gov;
> >>> +	ret = count;
> >>> +
> >>> +exit:
> >>> +	mutex_unlock(&thermal_governor_lock);
> >>> +	return ret;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +policy_show(struct device *dev, struct device_attribute *devattr, char
> *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +
> >>> +	return sprintf(buf, "%s\n", tz->governor->name);
> >>> +}
> >>> +
> >>> +#ifdef CONFIG_THERMAL_EMULATION
> >>> +static ssize_t
> >>> +emul_temp_store(struct device *dev, struct device_attribute *attr,
> >>> +		     const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int ret = 0;
> >>> +	unsigned long temperature;
> >>> +
> >>> +	if (kstrtoul(buf, 10, &temperature))
> >>> +		return -EINVAL;
> >>> +
> >>> +	if (!tz->ops->set_emul_temp) {
> >>> +		mutex_lock(&tz->lock);
> >>> +		tz->emul_temperature = temperature;
> >>> +		mutex_unlock(&tz->lock);
> >>> +	} else {
> >>> +		ret = tz->ops->set_emul_temp(tz, temperature);
> >>> +	}
> >>> +
> >>> +	return ret ? ret : count;
> >>> +}
> >>> +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> >>> +#endif/*CONFIG_THERMAL_EMULATION*/
> >>> +
> >>> +static DEVICE_ATTR(type, 0444, type_show, NULL);
> >>> +static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> >>> +static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> >>> +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show,
> passive_store);
> >>> +static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show,
> policy_store);
> >>> +
> >>> +/* sys I/F for cooling device */
> >>> +#define to_cooling_device(_dev)	\
> >>> +	container_of(_dev, struct thermal_cooling_device, device)
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_type_show(struct device *dev,
> >>> +				 struct device_attribute *attr, char *buf)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> +
> >>> +	return sprintf(buf, "%s\n", cdev->type);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_max_state_show(struct device *dev,
> >>> +				      struct device_attribute *attr, char *buf)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> +	unsigned long state;
> >>> +	int ret;
> >>> +
> >>> +	ret = cdev->ops->get_max_state(cdev, &state);
> >>> +	if (ret)
> >>> +		return ret;
> >>> +	return sprintf(buf, "%ld\n", state);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_cur_state_show(struct device *dev,
> >>> +				      struct device_attribute *attr, char *buf)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> +	unsigned long state;
> >>> +	int ret;
> >>> +
> >>> +	ret = cdev->ops->get_cur_state(cdev, &state);
> >>> +	if (ret)
> >>> +		return ret;
> >>> +	return sprintf(buf, "%ld\n", state);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_cur_state_store(struct device *dev,
> >>> +				       struct device_attribute *attr,
> >>> +				       const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> +	unsigned long state;
> >>> +	int result;
> >>> +
> >>> +	if (!sscanf(buf, "%ld\n", &state))
> >>> +		return -EINVAL;
> >>> +
> >>> +	if ((long)state < 0)
> >>> +		return -EINVAL;
> >>> +
> >>> +	result = cdev->ops->set_cur_state(cdev, state);
> >>> +	if (result)
> >>> +		return result;
> >>> +	return count;
> >>> +}
> >>> +
> >>> +static struct device_attribute dev_attr_cdev_type =
> >>> +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> >>> +static DEVICE_ATTR(max_state, 0444,
> >>> +		   thermal_cooling_device_max_state_show, NULL);
> >>> +static DEVICE_ATTR(cur_state, 0644,
> >>> +		   thermal_cooling_device_cur_state_show,
> >>> +		   thermal_cooling_device_cur_state_store);
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_trip_point_show(struct device *dev,
> >>> +				       struct device_attribute *attr, char *buf)
> >>> +{
> >>> +	struct thermal_instance *instance;
> >>> +
> >>> +	instance =
> >>> +	    container_of(attr, struct thermal_instance, attr);
> >>> +
> >>> +	if (instance->trip == THERMAL_TRIPS_NONE)
> >>> +		return sprintf(buf, "-1\n");
> >>> +	else
> >>> +		return sprintf(buf, "%d\n", instance->trip);
> >>> +}
> >>> +
> >>> +/* Device management */
> >>> +
> >>> +#if defined(CONFIG_THERMAL_HWMON)
> >>> +
> >>> +/* hwmon sys I/F */
> >>> +#include <linux/hwmon.h>
> >>> +
> >>> +/* thermal zone devices with the same type share one hwmon device
> */
> >>> +struct thermal_hwmon_device {
> >>> +	char type[THERMAL_NAME_LENGTH];
> >>> +	struct device *device;
> >>> +	int count;
> >>> +	struct list_head tz_list;
> >>> +	struct list_head node;
> >>> +};
> >>> +
> >>> +struct thermal_hwmon_attr {
> >>> +	struct device_attribute attr;
> >>> +	char name[16];
> >>> +};
> >>> +
> >>> +/* one temperature input for each thermal zone */
> >>> +struct thermal_hwmon_temp {
> >>> +	struct list_head hwmon_node;
> >>> +	struct thermal_zone_device *tz;
> >>> +	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> >>> +	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> >>> +};
> >>> +
> >>> +static LIST_HEAD(thermal_hwmon_list);
> >>> +
> >>> +static ssize_t
> >>> +name_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> +{
> >>> +	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> >>> +	return sprintf(buf, "%s\n", hwmon->type);
> >>> +}
> >>> +static DEVICE_ATTR(name, 0444, name_show, NULL);
> >>> +
> >>> +static ssize_t
> >>> +temp_input_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> >>> +{
> >>> +	long temperature;
> >>> +	int ret;
> >>> +	struct thermal_hwmon_attr *hwmon_attr
> >>> +			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> >>> +	struct thermal_hwmon_temp *temp
> >>> +			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> >>> +				       temp_input);
> >>> +	struct thermal_zone_device *tz = temp->tz;
> >>> +
> >>> +	ret = thermal_zone_get_temp(tz, &temperature);
> >>> +
> >>> +	if (ret)
> >>> +		return ret;
> >>> +
> >>> +	return sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +temp_crit_show(struct device *dev, struct device_attribute *attr,
> >>> +		char *buf)
> >>> +{
> >>> +	struct thermal_hwmon_attr *hwmon_attr
> >>> +			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> >>> +	struct thermal_hwmon_temp *temp
> >>> +			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> >>> +				       temp_crit);
> >>> +	struct thermal_zone_device *tz = temp->tz;
> >>> +	long temperature;
> >>> +	int ret;
> >>> +
> >>> +	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> >>> +	if (ret)
> >>> +		return ret;
> >>> +
> >>> +	return sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +
> >>> +static struct thermal_hwmon_device *
> >>> +thermal_hwmon_lookup_by_type(const struct thermal_zone_device
> *tz)
> >>> +{
> >>> +	struct thermal_hwmon_device *hwmon;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> >>> +		if (!strcmp(hwmon->type, tz->type)) {
> >>> +			mutex_unlock(&thermal_list_lock);
> >>> +			return hwmon;
> >>> +		}
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	return NULL;
> >>> +}
> >>> +
> >>> +/* Find the temperature input matching a given thermal zone */
> >>> +static struct thermal_hwmon_temp *
> >>> +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device
> *hwmon,
> >>> +			  const struct thermal_zone_device *tz)
> >>> +{
> >>> +	struct thermal_hwmon_temp *temp;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> >>> +		if (temp->tz == tz) {
> >>> +			mutex_unlock(&thermal_list_lock);
> >>> +			return temp;
> >>> +		}
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	return NULL;
> >>> +}
> >>> +
> >>> +static int
> >>> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> +{
> >>> +	struct thermal_hwmon_device *hwmon;
> >>> +	struct thermal_hwmon_temp *temp;
> >>> +	int new_hwmon_device = 1;
> >>> +	int result;
> >>> +
> >>> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> >>> +	if (hwmon) {
> >>> +		new_hwmon_device = 0;
> >>> +		goto register_sys_interface;
> >>> +	}
> >>> +
> >>> +	hwmon = kzalloc(sizeof(struct thermal_hwmon_device),
> GFP_KERNEL);
> >>> +	if (!hwmon)
> >>> +		return -ENOMEM;
> >>> +
> >>> +	INIT_LIST_HEAD(&hwmon->tz_list);
> >>> +	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> >>> +	hwmon->device = hwmon_device_register(NULL);
> >>> +	if (IS_ERR(hwmon->device)) {
> >>> +		result = PTR_ERR(hwmon->device);
> >>> +		goto free_mem;
> >>> +	}
> >>> +	dev_set_drvdata(hwmon->device, hwmon);
> >>> +	result = device_create_file(hwmon->device, &dev_attr_name);
> >>> +	if (result)
> >>> +		goto free_mem;
> >>> +
> >>> + register_sys_interface:
> >>> +	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> >>> +	if (!temp) {
> >>> +		result = -ENOMEM;
> >>> +		goto unregister_name;
> >>> +	}
> >>> +
> >>> +	temp->tz = tz;
> >>> +	hwmon->count++;
> >>> +
> >>> +	snprintf(temp->temp_input.name, sizeof(temp-
> >temp_input.name),
> >>> +		 "temp%d_input", hwmon->count);
> >>> +	temp->temp_input.attr.attr.name = temp->temp_input.name;
> >>> +	temp->temp_input.attr.attr.mode = 0444;
> >>> +	temp->temp_input.attr.show = temp_input_show;
> >>> +	sysfs_attr_init(&temp->temp_input.attr.attr);
> >>> +	result = device_create_file(hwmon->device, &temp-
> >temp_input.attr);
> >>> +	if (result)
> >>> +		goto free_temp_mem;
> >>> +
> >>> +	if (tz->ops->get_crit_temp) {
> >>> +		unsigned long temperature;
> >>> +		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> >>> +			snprintf(temp->temp_crit.name,
> >>> +				 sizeof(temp->temp_crit.name),
> >>> +				"temp%d_crit", hwmon->count);
> >>> +			temp->temp_crit.attr.attr.name = temp-
> >temp_crit.name;
> >>> +			temp->temp_crit.attr.attr.mode = 0444;
> >>> +			temp->temp_crit.attr.show = temp_crit_show;
> >>> +			sysfs_attr_init(&temp->temp_crit.attr.attr);
> >>> +			result = device_create_file(hwmon->device,
> >>> +						    &temp->temp_crit.attr);
> >>> +			if (result)
> >>> +				goto unregister_input;
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	if (new_hwmon_device)
> >>> +		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> >>> +	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	return 0;
> >>> +
> >>> + unregister_input:
> >>> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> >>> + free_temp_mem:
> >>> +	kfree(temp);
> >>> + unregister_name:
> >>> +	if (new_hwmon_device) {
> >>> +		device_remove_file(hwmon->device, &dev_attr_name);
> >>> +		hwmon_device_unregister(hwmon->device);
> >>> +	}
> >>> + free_mem:
> >>> +	if (new_hwmon_device)
> >>> +		kfree(hwmon);
> >>> +
> >>> +	return result;
> >>> +}
> >>> +
> >>> +static void
> >>> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> +{
> >>> +	struct thermal_hwmon_device *hwmon;
> >>> +	struct thermal_hwmon_temp *temp;
> >>> +
> >>> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> >>> +	if (unlikely(!hwmon)) {
> >>> +		/* Should never happen... */
> >>> +		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> >>> +		return;
> >>> +	}
> >>> +
> >>> +	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> >>> +	if (unlikely(!temp)) {
> >>> +		/* Should never happen... */
> >>> +		dev_dbg(&tz->device, "temperature input lookup
> failed!\n");
> >>> +		return;
> >>> +	}
> >>> +
> >>> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> >>> +	if (tz->ops->get_crit_temp)
> >>> +		device_remove_file(hwmon->device, &temp-
> >temp_crit.attr);
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_del(&temp->hwmon_node);
> >>> +	kfree(temp);
> >>> +	if (!list_empty(&hwmon->tz_list)) {
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		return;
> >>> +	}
> >>> +	list_del(&hwmon->node);
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	device_remove_file(hwmon->device, &dev_attr_name);
> >>> +	hwmon_device_unregister(hwmon->device);
> >>> +	kfree(hwmon);
> >>> +}
> >>> +#else
> >>> +static int
> >>> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> +{
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static void
> >>> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> +{
> >>> +}
> >>> +#endif
> >>> +
> >>> +/**
> >>> + * thermal_zone_bind_cooling_device - bind a cooling device to a
> thermal zone
> >>> + * @tz:		thermal zone device
> >>> + * @trip:	indicates which trip point the cooling devices is
> >>> + *		associated with in this thermal zone.
> >>> + * @cdev:	thermal cooling device
> >>> + *
> >>> + * This function is usually called in the thermal zone device .bind
> callback.
> >>> + */
> >>> +int thermal_zone_bind_cooling_device(struct thermal_zone_device
> *tz,
> >>> +				     int trip,
> >>> +				     struct thermal_cooling_device *cdev,
> >>> +				     unsigned long upper, unsigned long lower)
> >>> +{
> >>> +	struct thermal_instance *dev;
> >>> +	struct thermal_instance *pos;
> >>> +	struct thermal_zone_device *pos1;
> >>> +	struct thermal_cooling_device *pos2;
> >>> +	unsigned long max_state;
> >>> +	int result;
> >>> +
> >>> +	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> >>> +		return -EINVAL;
> >>> +
> >>> +	list_for_each_entry(pos1, &thermal_tz_list, node) {
> >>> +		if (pos1 == tz)
> >>> +			break;
> >>> +	}
> >>> +	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> >>> +		if (pos2 == cdev)
> >>> +			break;
> >>> +	}
> >>> +
> >>> +	if (tz != pos1 || cdev != pos2)
> >>> +		return -EINVAL;
> >>> +
> >>> +	cdev->ops->get_max_state(cdev, &max_state);
> >>> +
> >>> +	/* lower default 0, upper default max_state */
> >>> +	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> >>> +	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> >>> +
> >>> +	if (lower > upper || upper > max_state)
> >>> +		return -EINVAL;
> >>> +
> >>> +	dev =
> >>> +	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> >>> +	if (!dev)
> >>> +		return -ENOMEM;
> >>> +	dev->tz = tz;
> >>> +	dev->cdev = cdev;
> >>> +	dev->trip = trip;
> >>> +	dev->upper = upper;
> >>> +	dev->lower = lower;
> >>> +	dev->target = THERMAL_NO_TARGET;
> >>> +
> >>> +	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> >>> +	if (result)
> >>> +		goto free_mem;
> >>> +
> >>> +	sprintf(dev->name, "cdev%d", dev->id);
> >>> +	result =
> >>> +	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev-
> >name);
> >>> +	if (result)
> >>> +		goto release_idr;
> >>> +
> >>> +	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> >>> +	sysfs_attr_init(&dev->attr.attr);
> >>> +	dev->attr.attr.name = dev->attr_name;
> >>> +	dev->attr.attr.mode = 0444;
> >>> +	dev->attr.show = thermal_cooling_device_trip_point_show;
> >>> +	result = device_create_file(&tz->device, &dev->attr);
> >>> +	if (result)
> >>> +		goto remove_symbol_link;
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +	mutex_lock(&cdev->lock);
> >>> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> >>> +	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> +		result = -EEXIST;
> >>> +		break;
> >>> +	}
> >>> +	if (!result) {
> >>> +		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> >>> +		list_add_tail(&dev->cdev_node, &cdev-
> >thermal_instances);
> >>> +	}
> >>> +	mutex_unlock(&cdev->lock);
> >>> +	mutex_unlock(&tz->lock);
> >>> +
> >>> +	if (!result)
> >>> +		return 0;
> >>> +
> >>> +	device_remove_file(&tz->device, &dev->attr);
> >>> +remove_symbol_link:
> >>> +	sysfs_remove_link(&tz->device.kobj, dev->name);
> >>> +release_idr:
> >>> +	release_idr(&tz->idr, &tz->lock, dev->id);
> >>> +free_mem:
> >>> +	kfree(dev);
> >>> +	return result;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> >>> +
> >>> +/**
> >>> + * thermal_zone_unbind_cooling_device - unbind a cooling device
> from a thermal zone
> >>> + * @tz:		thermal zone device
> >>> + * @trip:	indicates which trip point the cooling devices is
> >>> + *		associated with in this thermal zone.
> >>> + * @cdev:	thermal cooling device
> >>> + *
> >>> + * This function is usually called in the thermal zone device .unbind
> callback.
> >>> + */
> >>> +int thermal_zone_unbind_cooling_device(struct thermal_zone_device
> *tz,
> >>> +				       int trip,
> >>> +				       struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	struct thermal_instance *pos, *next;
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +	mutex_lock(&cdev->lock);
> >>> +	list_for_each_entry_safe(pos, next, &tz->thermal_instances,
> tz_node) {
> >>> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> +			list_del(&pos->tz_node);
> >>> +			list_del(&pos->cdev_node);
> >>> +			mutex_unlock(&cdev->lock);
> >>> +			mutex_unlock(&tz->lock);
> >>> +			goto unbind;
> >>> +		}
> >>> +	}
> >>> +	mutex_unlock(&cdev->lock);
> >>> +	mutex_unlock(&tz->lock);
> >>> +
> >>> +	return -ENODEV;
> >>> +
> >>> +unbind:
> >>> +	device_remove_file(&tz->device, &pos->attr);
> >>> +	sysfs_remove_link(&tz->device.kobj, pos->name);
> >>> +	release_idr(&tz->idr, &tz->lock, pos->id);
> >>> +	kfree(pos);
> >>> +	return 0;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> >>> +
> >>> +static void thermal_release(struct device *dev)
> >>> +{
> >>> +	struct thermal_zone_device *tz;
> >>> +	struct thermal_cooling_device *cdev;
> >>> +
> >>> +	if (!strncmp(dev_name(dev), "thermal_zone",
> >>> +		     sizeof("thermal_zone") - 1)) {
> >>> +		tz = to_thermal_zone(dev);
> >>> +		kfree(tz);
> >>> +	} else {
> >>> +		cdev = to_cooling_device(dev);
> >>> +		kfree(cdev);
> >>> +	}
> >>> +}
> >>> +
> >>> +static struct class thermal_class = {
> >>> +	.name = "thermal",
> >>> +	.dev_release = thermal_release,
> >>> +};
> >>> +
> >>> +/**
> >>> + * thermal_cooling_device_register - register a new thermal cooling
> device
> >>> + * @type:	the thermal cooling device type.
> >>> + * @devdata:	device private data.
> >>> + * @ops:		standard thermal cooling devices callbacks.
> >>> + */
> >>> +struct thermal_cooling_device *
> >>> +thermal_cooling_device_register(char *type, void *devdata,
> >>> +				const struct thermal_cooling_device_ops
> *ops)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev;
> >>> +	int result;
> >>> +
> >>> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> >>> +	    !ops->set_cur_state)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> >>> +	if (!cdev)
> >>> +		return ERR_PTR(-ENOMEM);
> >>> +
> >>> +	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> >>> +	if (result) {
> >>> +		kfree(cdev);
> >>> +		return ERR_PTR(result);
> >>> +	}
> >>> +
> >>> +	strcpy(cdev->type, type ? : "");
> >>> +	mutex_init(&cdev->lock);
> >>> +	INIT_LIST_HEAD(&cdev->thermal_instances);
> >>> +	cdev->ops = ops;
> >>> +	cdev->updated = true;
> >>> +	cdev->device.class = &thermal_class;
> >>> +	cdev->devdata = devdata;
> >>> +	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> >>> +	result = device_register(&cdev->device);
> >>> +	if (result) {
> >>> +		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev-
> >id);
> >>> +		kfree(cdev);
> >>> +		return ERR_PTR(result);
> >>> +	}
> >>> +
> >>> +	/* sys I/F */
> >>> +	if (type) {
> >>> +		result = device_create_file(&cdev->device,
> &dev_attr_cdev_type);
> >>> +		if (result)
> >>> +			goto unregister;
> >>> +	}
> >>> +
> >>> +	result = device_create_file(&cdev->device, &dev_attr_max_state);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	/* Add 'this' new cdev to the global cdev list */
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_add(&cdev->node, &thermal_cdev_list);
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	/* Update binding information for 'this' new cdev */
> >>> +	bind_cdev(cdev);
> >>> +
> >>> +	return cdev;
> >>> +
> >>> +unregister:
> >>> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> >>> +	device_unregister(&cdev->device);
> >>> +	return ERR_PTR(result);
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_cooling_device_register);
> >>> +
> >>> +/**
> >>> + * thermal_cooling_device_unregister - removes the registered
> thermal cooling device
> >>> + * @cdev:	the thermal cooling device to remove.
> >>> + *
> >>> + * thermal_cooling_device_unregister() must be called when the
> device is no
> >>> + * longer needed.
> >>> + */
> >>> +void thermal_cooling_device_unregister(struct
> thermal_cooling_device *cdev)
> >>> +{
> >>> +	int i;
> >>> +	const struct thermal_zone_params *tzp;
> >>> +	struct thermal_zone_device *tz;
> >>> +	struct thermal_cooling_device *pos = NULL;
> >>> +
> >>> +	if (!cdev)
> >>> +		return;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_for_each_entry(pos, &thermal_cdev_list, node)
> >>> +	    if (pos == cdev)
> >>> +		break;
> >>> +	if (pos != cdev) {
> >>> +		/* thermal cooling device not found */
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		return;
> >>> +	}
> >>> +	list_del(&cdev->node);
> >>> +
> >>> +	/* Unbind all thermal zones associated with 'this' cdev */
> >>> +	list_for_each_entry(tz, &thermal_tz_list, node) {
> >>> +		if (tz->ops->unbind) {
> >>> +			tz->ops->unbind(tz, cdev);
> >>> +			continue;
> >>> +		}
> >>> +
> >>> +		if (!tz->tzp || !tz->tzp->tbp)
> >>> +			continue;
> >>> +
> >>> +		tzp = tz->tzp;
> >>> +		for (i = 0; i < tzp->num_tbps; i++) {
> >>> +			if (tzp->tbp[i].cdev == cdev) {
> >>> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> >>> +				tzp->tbp[i].cdev = NULL;
> >>> +			}
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	if (cdev->type[0])
> >>> +		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> >>> +	device_remove_file(&cdev->device, &dev_attr_max_state);
> >>> +	device_remove_file(&cdev->device, &dev_attr_cur_state);
> >>> +
> >>> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> >>> +	device_unregister(&cdev->device);
> >>> +	return;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_cooling_device_unregister);
> >>> +
> >>> +void thermal_cdev_update(struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	struct thermal_instance *instance;
> >>> +	unsigned long target = 0;
> >>> +
> >>> +	/* cooling device is updated*/
> >>> +	if (cdev->updated)
> >>> +		return;
> >>> +
> >>> +	mutex_lock(&cdev->lock);
> >>> +	/* Make sure cdev enters the deepest cooling state */
> >>> +	list_for_each_entry(instance, &cdev->thermal_instances,
> cdev_node) {
> >>> +		if (instance->target == THERMAL_NO_TARGET)
> >>> +			continue;
> >>> +		if (instance->target > target)
> >>> +			target = instance->target;
> >>> +	}
> >>> +	mutex_unlock(&cdev->lock);
> >>> +	cdev->ops->set_cur_state(cdev, target);
> >>> +	cdev->updated = true;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_cdev_update);
> >>> +
> >>> +/**
> >>> + * notify_thermal_framework - Sensor drivers use this API to notify
> framework
> >>> + * @tz:		thermal zone device
> >>> + * @trip:	indicates which trip point has been crossed
> >>> + *
> >>> + * This function handles the trip events from sensor drivers. It starts
> >>> + * throttling the cooling devices according to the policy configured.
> >>> + * For CRITICAL and HOT trip points, this notifies the respective drivers,
> >>> + * and does actual throttling for other trip points i.e ACTIVE and
> PASSIVE.
> >>> + * The throttling policy is based on the configured platform data; if no
> >>> + * platform data is provided, this uses the step_wise throttling policy.
> >>> + */
> >>> +void notify_thermal_framework(struct thermal_zone_device *tz, int
> trip)
> >>> +{
> >>> +	handle_thermal_trip(tz, trip);
> >>> +}
> >>> +EXPORT_SYMBOL(notify_thermal_framework);
> >>> +
> >>> +/**
> >>> + * create_trip_attrs - create attributes for trip points
> >>> + * @tz:		the thermal zone device
> >>> + * @mask:	Writeable trip point bitmap.
> >>> + */
> >>> +static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> >>> +{
> >>> +	int indx;
> >>> +	int size = sizeof(struct thermal_attr) * tz->trips;
> >>> +
> >>> +	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> >>> +	if (!tz->trip_type_attrs)
> >>> +		return -ENOMEM;
> >>> +
> >>> +	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> >>> +	if (!tz->trip_temp_attrs) {
> >>> +		kfree(tz->trip_type_attrs);
> >>> +		return -ENOMEM;
> >>> +	}
> >>> +
> >>> +	if (tz->ops->get_trip_hyst) {
> >>> +		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> >>> +		if (!tz->trip_hyst_attrs) {
> >>> +			kfree(tz->trip_type_attrs);
> >>> +			kfree(tz->trip_temp_attrs);
> >>> +			return -ENOMEM;
> >>> +		}
> >>> +	}
> >>> +
> >>> +
> >>> +	for (indx = 0; indx < tz->trips; indx++) {
> >>> +		/* create trip type attribute */
> >>> +		snprintf(tz->trip_type_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> +			 "trip_point_%d_type", indx);
> >>> +
> >>> +		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> >>> +		tz->trip_type_attrs[indx].attr.attr.name =
> >>> +						tz-
> >trip_type_attrs[indx].name;
> >>> +		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> +		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> >>> +
> >>> +		device_create_file(&tz->device,
> >>> +				   &tz->trip_type_attrs[indx].attr);
> >>> +
> >>> +		/* create trip temp attribute */
> >>> +		snprintf(tz->trip_temp_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> +			 "trip_point_%d_temp", indx);
> >>> +
> >>> +		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> >>> +		tz->trip_temp_attrs[indx].attr.attr.name =
> >>> +						tz-
> >trip_temp_attrs[indx].name;
> >>> +		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> +		tz->trip_temp_attrs[indx].attr.show =
> trip_point_temp_show;
> >>> +		if (mask & (1 << indx)) {
> >>> +			tz->trip_temp_attrs[indx].attr.attr.mode |=
> S_IWUSR;
> >>> +			tz->trip_temp_attrs[indx].attr.store =
> >>> +
> 	trip_point_temp_store;
> >>> +		}
> >>> +
> >>> +		device_create_file(&tz->device,
> >>> +				   &tz->trip_temp_attrs[indx].attr);
> >>> +
> >>> +		/* create Optional trip hyst attribute */
> >>> +		if (!tz->ops->get_trip_hyst)
> >>> +			continue;
> >>> +		snprintf(tz->trip_hyst_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> +			 "trip_point_%d_hyst", indx);
> >>> +
> >>> +		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> >>> +		tz->trip_hyst_attrs[indx].attr.attr.name =
> >>> +					tz->trip_hyst_attrs[indx].name;
> >>> +		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> +		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> >>> +		if (tz->ops->set_trip_hyst) {
> >>> +			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> >>> +			tz->trip_hyst_attrs[indx].attr.store =
> >>> +					trip_point_hyst_store;
> >>> +		}
> >>> +
> >>> +		device_create_file(&tz->device,
> >>> +				   &tz->trip_hyst_attrs[indx].attr);
> >>> +	}
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static void remove_trip_attrs(struct thermal_zone_device *tz)
> >>> +{
> >>> +	int indx;
> >>> +
> >>> +	for (indx = 0; indx < tz->trips; indx++) {
> >>> +		device_remove_file(&tz->device,
> >>> +				   &tz->trip_type_attrs[indx].attr);
> >>> +		device_remove_file(&tz->device,
> >>> +				   &tz->trip_temp_attrs[indx].attr);
> >>> +		if (tz->ops->get_trip_hyst)
> >>> +			device_remove_file(&tz->device,
> >>> +				  &tz->trip_hyst_attrs[indx].attr);
> >>> +	}
> >>> +	kfree(tz->trip_type_attrs);
> >>> +	kfree(tz->trip_temp_attrs);
> >>> +	kfree(tz->trip_hyst_attrs);
> >>> +}
> >>> +
> >>> +/**
> >>> + * thermal_zone_device_register - register a new thermal zone device
> >>> + * @type:	the thermal zone device type
> >>> + * @trips:	the number of trip points the thermal zone support
> >>> + * @mask:	a bit string indicating the writeablility of trip points
> >>> + * @devdata:	private device data
> >>> + * @ops:	standard thermal zone device callbacks
> >>> + * @tzp:	thermal zone platform parameters
> >>> + * @passive_delay: number of milliseconds to wait between polls when
> >>> + *		   performing passive cooling
> >>> + * @polling_delay: number of milliseconds to wait between polls when
> checking
> >>> + *		   whether trip points have been crossed (0 for interrupt
> >>> + *		   driven systems)
> >>> + *
> >>> + * thermal_zone_device_unregister() must be called when the device
> is no
> >>> + * longer needed. The passive cooling depends on the .get_trend()
> return value.
> >>> + */
> >>> +struct thermal_zone_device *thermal_zone_device_register(const
> char *type,
> >>> +	int trips, int mask, void *devdata,
> >>> +	const struct thermal_zone_device_ops *ops,
> >>> +	const struct thermal_zone_params *tzp,
> >>> +	int passive_delay, int polling_delay)
> >>> +{
> >>> +	struct thermal_zone_device *tz;
> >>> +	enum thermal_trip_type trip_type;
> >>> +	int result;
> >>> +	int count;
> >>> +	int passive = 0;
> >>> +
> >>> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	if (!ops || !ops->get_temp)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	if (trips > 0 && !ops->get_trip_type)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> >>> +	if (!tz)
> >>> +		return ERR_PTR(-ENOMEM);
> >>> +
> >>> +	INIT_LIST_HEAD(&tz->thermal_instances);
> >>> +	idr_init(&tz->idr);
> >>> +	mutex_init(&tz->lock);
> >>> +	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> >>> +	if (result) {
> >>> +		kfree(tz);
> >>> +		return ERR_PTR(result);
> >>> +	}
> >>> +
> >>> +	strcpy(tz->type, type ? : "");
> >>> +	tz->ops = ops;
> >>> +	tz->tzp = tzp;
> >>> +	tz->device.class = &thermal_class;
> >>> +	tz->devdata = devdata;
> >>> +	tz->trips = trips;
> >>> +	tz->passive_delay = passive_delay;
> >>> +	tz->polling_delay = polling_delay;
> >>> +
> >>> +	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> >>> +	result = device_register(&tz->device);
> >>> +	if (result) {
> >>> +		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> +		kfree(tz);
> >>> +		return ERR_PTR(result);
> >>> +	}
> >>> +
> >>> +	/* sys I/F */
> >>> +	if (type) {
> >>> +		result = device_create_file(&tz->device, &dev_attr_type);
> >>> +		if (result)
> >>> +			goto unregister;
> >>> +	}
> >>> +
> >>> +	result = device_create_file(&tz->device, &dev_attr_temp);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	if (ops->get_mode) {
> >>> +		result = device_create_file(&tz->device, &dev_attr_mode);
> >>> +		if (result)
> >>> +			goto unregister;
> >>> +	}
> >>> +
> >>> +	result = create_trip_attrs(tz, mask);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	for (count = 0; count < trips; count++) {
> >>> +		tz->ops->get_trip_type(tz, count, &trip_type);
> >>> +		if (trip_type == THERMAL_TRIP_PASSIVE)
> >>> +			passive = 1;
> >>> +	}
> >>> +
> >>> +	if (!passive) {
> >>> +		result = device_create_file(&tz->device, &dev_attr_passive);
> >>> +		if (result)
> >>> +			goto unregister;
> >>> +	}
> >>> +
> >>> +#ifdef CONFIG_THERMAL_EMULATION
> >>> +	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +#endif
> >>> +	/* Create policy attribute */
> >>> +	result = device_create_file(&tz->device, &dev_attr_policy);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	/* Update 'this' zone's governor information */
> >>> +	mutex_lock(&thermal_governor_lock);
> >>> +
> >>> +	if (tz->tzp)
> >>> +		tz->governor = __find_governor(tz->tzp->governor_name);
> >>> +	else
> >>> +		tz->governor =
> __find_governor(DEFAULT_THERMAL_GOVERNOR);
> >>> +
> >>> +	mutex_unlock(&thermal_governor_lock);
> >>> +
> >>> +	result = thermal_add_hwmon_sysfs(tz);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_add_tail(&tz->node, &thermal_tz_list);
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	/* Bind cooling devices for this zone */
> >>> +	bind_tz(tz);
> >>> +
> >>> +	INIT_DELAYED_WORK(&(tz->poll_queue),
> thermal_zone_device_check);
> >>> +
> >>> +	thermal_zone_device_update(tz);
> >>> +
> >>> +	if (!result)
> >>> +		return tz;
> >>> +
> >>> +unregister:
> >>> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> +	device_unregister(&tz->device);
> >>> +	return ERR_PTR(result);
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_device_register);
> >>> +
> >>> +/**
> >>> + * thermal_device_unregister - removes the registered thermal zone
> device
> >>> + * @tz: the thermal zone device to remove
> >>> + */
> >>> +void thermal_zone_device_unregister(struct thermal_zone_device
> *tz)
> >>> +{
> >>> +	int i;
> >>> +	const struct thermal_zone_params *tzp;
> >>> +	struct thermal_cooling_device *cdev;
> >>> +	struct thermal_zone_device *pos = NULL;
> >>> +
> >>> +	if (!tz)
> >>> +		return;
> >>> +
> >>> +	tzp = tz->tzp;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_for_each_entry(pos, &thermal_tz_list, node)
> >>> +	    if (pos == tz)
> >>> +		break;
> >>> +	if (pos != tz) {
> >>> +		/* thermal zone device not found */
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		return;
> >>> +	}
> >>> +	list_del(&tz->node);
> >>> +
> >>> +	/* Unbind all cdevs associated with 'this' thermal zone */
> >>> +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> +		if (tz->ops->unbind) {
> >>> +			tz->ops->unbind(tz, cdev);
> >>> +			continue;
> >>> +		}
> >>> +
> >>> +		if (!tzp || !tzp->tbp)
> >>> +			break;
> >>> +
> >>> +		for (i = 0; i < tzp->num_tbps; i++) {
> >>> +			if (tzp->tbp[i].cdev == cdev) {
> >>> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> >>> +				tzp->tbp[i].cdev = NULL;
> >>> +			}
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	thermal_zone_device_set_polling(tz, 0);
> >>> +
> >>> +	if (tz->type[0])
> >>> +		device_remove_file(&tz->device, &dev_attr_type);
> >>> +	device_remove_file(&tz->device, &dev_attr_temp);
> >>> +	if (tz->ops->get_mode)
> >>> +		device_remove_file(&tz->device, &dev_attr_mode);
> >>> +	device_remove_file(&tz->device, &dev_attr_policy);
> >>> +	remove_trip_attrs(tz);
> >>> +	tz->governor = NULL;
> >>> +
> >>> +	thermal_remove_hwmon_sysfs(tz);
> >>> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> +	idr_destroy(&tz->idr);
> >>> +	mutex_destroy(&tz->lock);
> >>> +	device_unregister(&tz->device);
> >>> +	return;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_device_unregister);
> >>> +
> >>> +#ifdef CONFIG_NET
> >>> +static struct genl_family thermal_event_genl_family = {
> >>> +	.id = GENL_ID_GENERATE,
> >>> +	.name = THERMAL_GENL_FAMILY_NAME,
> >>> +	.version = THERMAL_GENL_VERSION,
> >>> +	.maxattr = THERMAL_GENL_ATTR_MAX,
> >>> +};
> >>> +
> >>> +static struct genl_multicast_group thermal_event_mcgrp = {
> >>> +	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> >>> +};
> >>> +
> >>> +int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> >>> +					enum events event)
> >>> +{
> >>> +	struct sk_buff *skb;
> >>> +	struct nlattr *attr;
> >>> +	struct thermal_genl_event *thermal_event;
> >>> +	void *msg_header;
> >>> +	int size;
> >>> +	int result;
> >>> +	static unsigned int thermal_event_seqnum;
> >>> +
> >>> +	if (!tz)
> >>> +		return -EINVAL;
> >>> +
> >>> +	/* allocate memory */
> >>> +	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> >>> +	       nla_total_size(0);
> >>> +
> >>> +	skb = genlmsg_new(size, GFP_ATOMIC);
> >>> +	if (!skb)
> >>> +		return -ENOMEM;
> >>> +
> >>> +	/* add the genetlink message header */
> >>> +	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> >>> +				 &thermal_event_genl_family, 0,
> >>> +				 THERMAL_GENL_CMD_EVENT);
> >>> +	if (!msg_header) {
> >>> +		nlmsg_free(skb);
> >>> +		return -ENOMEM;
> >>> +	}
> >>> +
> >>> +	/* fill the data */
> >>> +	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> >>> +			   sizeof(struct thermal_genl_event));
> >>> +
> >>> +	if (!attr) {
> >>> +		nlmsg_free(skb);
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>> +	thermal_event = nla_data(attr);
> >>> +	if (!thermal_event) {
> >>> +		nlmsg_free(skb);
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>> +	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> >>> +
> >>> +	thermal_event->orig = tz->id;
> >>> +	thermal_event->event = event;
> >>> +
> >>> +	/* send multicast genetlink message */
> >>> +	result = genlmsg_end(skb, msg_header);
> >>> +	if (result < 0) {
> >>> +		nlmsg_free(skb);
> >>> +		return result;
> >>> +	}
> >>> +
> >>> +	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id,
> GFP_ATOMIC);
> >>> +	if (result)
> >>> +		dev_err(&tz->device, "Failed to send netlink event:%d",
> result);
> >>> +
> >>> +	return result;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_generate_netlink_event);
> >>> +
> >>> +static int genetlink_init(void)
> >>> +{
> >>> +	int result;
> >>> +
> >>> +	result = genl_register_family(&thermal_event_genl_family);
> >>> +	if (result)
> >>> +		return result;
> >>> +
> >>> +	result = genl_register_mc_group(&thermal_event_genl_family,
> >>> +					&thermal_event_mcgrp);
> >>> +	if (result)
> >>> +		genl_unregister_family(&thermal_event_genl_family);
> >>> +	return result;
> >>> +}
> >>> +
> >>> +static void genetlink_exit(void)
> >>> +{
> >>> +	genl_unregister_family(&thermal_event_genl_family);
> >>> +}
> >>> +#else /* !CONFIG_NET */
> >>> +static inline int genetlink_init(void) { return 0; }
> >>> +static inline void genetlink_exit(void) {}
> >>> +#endif /* !CONFIG_NET */
> >>> +
> >>> +static int __init thermal_init(void)
> >>> +{
> >>> +	int result = 0;
> >>> +
> >>> +	result = class_register(&thermal_class);
> >>> +	if (result) {
> >>> +		idr_destroy(&thermal_tz_idr);
> >>> +		idr_destroy(&thermal_cdev_idr);
> >>> +		mutex_destroy(&thermal_idr_lock);
> >>> +		mutex_destroy(&thermal_list_lock);
> >>> +		return result;
> >>> +	}
> >>> +	result = genetlink_init();
> >>> +	return result;
> >>> +}
> >>> +
> >>> +static void __exit thermal_exit(void)
> >>> +{
> >>> +	class_unregister(&thermal_class);
> >>> +	idr_destroy(&thermal_tz_idr);
> >>> +	idr_destroy(&thermal_cdev_idr);
> >>> +	mutex_destroy(&thermal_idr_lock);
> >>> +	mutex_destroy(&thermal_list_lock);
> >>> +	genetlink_exit();
> >>> +}
> >>> +
> >>> +fs_initcall(thermal_init);
> >>> +module_exit(thermal_exit);
> >>> diff --git a/drivers/thermal/thermal_sys.c
> b/drivers/thermal/thermal_sys.c
> >>> deleted file mode 100644
> >>> index 5b7863a..0000000
> >>> --- a/drivers/thermal/thermal_sys.c
> >>> +++ /dev/null
> >>> @@ -1,1888 +0,0 @@
> >>> -/*
> >>> - *  thermal.c - Generic Thermal Management Sysfs support.
> >>> - *
> >>> - *  Copyright (C) 2008 Intel Corp
> >>> - *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> >>> - *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> >>> - *
> >>> - *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> >>> - *
> >>> - *  This program is free software; you can redistribute it and/or modify
> >>> - *  it under the terms of the GNU General Public License as published by
> >>> - *  the Free Software Foundation; version 2 of the License.
> >>> - *
> >>> - *  This program is distributed in the hope that it will be useful, but
> >>> - *  WITHOUT ANY WARRANTY; without even the implied warranty of
> >>> - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> the GNU
> >>> - *  General Public License for more details.
> >>> - *
> >>> - *  You should have received a copy of the GNU General Public License
> along
> >>> - *  with this program; if not, write to the Free Software Foundation, Inc.,
> >>> - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> >>> - *
> >>> - *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> >>> - */
> >>> -
> >>> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> >>> -
> >>> -#include <linux/module.h>
> >>> -#include <linux/device.h>
> >>> -#include <linux/err.h>
> >>> -#include <linux/slab.h>
> >>> -#include <linux/kdev_t.h>
> >>> -#include <linux/idr.h>
> >>> -#include <linux/thermal.h>
> >>> -#include <linux/reboot.h>
> >>> -#include <net/netlink.h>
> >>> -#include <net/genetlink.h>
> >>> -
> >>> -#include "thermal_core.h"
> >>> -
> >>> -MODULE_AUTHOR("Zhang Rui");
> >>> -MODULE_DESCRIPTION("Generic thermal management sysfs
> support");
> >>> -MODULE_LICENSE("GPL");
> >>> -
> >>> -static DEFINE_IDR(thermal_tz_idr);
> >>> -static DEFINE_IDR(thermal_cdev_idr);
> >>> -static DEFINE_MUTEX(thermal_idr_lock);
> >>> -
> >>> -static LIST_HEAD(thermal_tz_list);
> >>> -static LIST_HEAD(thermal_cdev_list);
> >>> -static LIST_HEAD(thermal_governor_list);
> >>> -
> >>> -static DEFINE_MUTEX(thermal_list_lock);
> >>> -static DEFINE_MUTEX(thermal_governor_lock);
> >>> -
> >>> -static struct thermal_governor *__find_governor(const char *name)
> >>> -{
> >>> -	struct thermal_governor *pos;
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> >>> -		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> >>> -			return pos;
> >>> -
> >>> -	return NULL;
> >>> -}
> >>> -
> >>> -int thermal_register_governor(struct thermal_governor *governor)
> >>> -{
> >>> -	int err;
> >>> -	const char *name;
> >>> -	struct thermal_zone_device *pos;
> >>> -
> >>> -	if (!governor)
> >>> -		return -EINVAL;
> >>> -
> >>> -	mutex_lock(&thermal_governor_lock);
> >>> -
> >>> -	err = -EBUSY;
> >>> -	if (__find_governor(governor->name) == NULL) {
> >>> -		err = 0;
> >>> -		list_add(&governor->governor_list,
> &thermal_governor_list);
> >>> -	}
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> -		if (pos->governor)
> >>> -			continue;
> >>> -		if (pos->tzp)
> >>> -			name = pos->tzp->governor_name;
> >>> -		else
> >>> -			name = DEFAULT_THERMAL_GOVERNOR;
> >>> -		if (!strnicmp(name, governor->name,
> THERMAL_NAME_LENGTH))
> >>> -			pos->governor = governor;
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -	mutex_unlock(&thermal_governor_lock);
> >>> -
> >>> -	return err;
> >>> -}
> >>> -EXPORT_SYMBOL_GPL(thermal_register_governor);
> >>> -
> >>> -void thermal_unregister_governor(struct thermal_governor
> *governor)
> >>> -{
> >>> -	struct thermal_zone_device *pos;
> >>> -
> >>> -	if (!governor)
> >>> -		return;
> >>> -
> >>> -	mutex_lock(&thermal_governor_lock);
> >>> -
> >>> -	if (__find_governor(governor->name) == NULL)
> >>> -		goto exit;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> -		if (!strnicmp(pos->governor->name, governor->name,
> >>> -						THERMAL_NAME_LENGTH))
> >>> -			pos->governor = NULL;
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -	list_del(&governor->governor_list);
> >>> -exit:
> >>> -	mutex_unlock(&thermal_governor_lock);
> >>> -	return;
> >>> -}
> >>> -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> >>> -
> >>> -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> >>> -{
> >>> -	int ret;
> >>> -
> >>> -	if (lock)
> >>> -		mutex_lock(lock);
> >>> -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> >>> -	if (lock)
> >>> -		mutex_unlock(lock);
> >>> -	if (unlikely(ret < 0))
> >>> -		return ret;
> >>> -	*id = ret;
> >>> -	return 0;
> >>> -}
> >>> -
> >>> -static void release_idr(struct idr *idr, struct mutex *lock, int id)
> >>> -{
> >>> -	if (lock)
> >>> -		mutex_lock(lock);
> >>> -	idr_remove(idr, id);
> >>> -	if (lock)
> >>> -		mutex_unlock(lock);
> >>> -}
> >>> -
> >>> -int get_tz_trend(struct thermal_zone_device *tz, int trip)
> >>> -{
> >>> -	enum thermal_trend trend;
> >>> -
> >>> -	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> >>> -		if (tz->temperature > tz->last_temperature)
> >>> -			trend = THERMAL_TREND_RAISING;
> >>> -		else if (tz->temperature < tz->last_temperature)
> >>> -			trend = THERMAL_TREND_DROPPING;
> >>> -		else
> >>> -			trend = THERMAL_TREND_STABLE;
> >>> -	}
> >>> -
> >>> -	return trend;
> >>> -}
> >>> -EXPORT_SYMBOL(get_tz_trend);
> >>> -
> >>> -struct thermal_instance *get_thermal_instance(struct
> thermal_zone_device *tz,
> >>> -			struct thermal_cooling_device *cdev, int trip)
> >>> -{
> >>> -	struct thermal_instance *pos = NULL;
> >>> -	struct thermal_instance *target_instance = NULL;
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -	mutex_lock(&cdev->lock);
> >>> -
> >>> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> >>> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> -			target_instance = pos;
> >>> -			break;
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&cdev->lock);
> >>> -	mutex_unlock(&tz->lock);
> >>> -
> >>> -	return target_instance;
> >>> -}
> >>> -EXPORT_SYMBOL(get_thermal_instance);
> >>> -
> >>> -static void print_bind_err_msg(struct thermal_zone_device *tz,
> >>> -			struct thermal_cooling_device *cdev, int ret)
> >>> -{
> >>> -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> >>> -				tz->type, cdev->type, ret);
> >>> -}
> >>> -
> >>> -static void __bind(struct thermal_zone_device *tz, int mask,
> >>> -			struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	int i, ret;
> >>> -
> >>> -	for (i = 0; i < tz->trips; i++) {
> >>> -		if (mask & (1 << i)) {
> >>> -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> >>> -					THERMAL_NO_LIMIT,
> THERMAL_NO_LIMIT);
> >>> -			if (ret)
> >>> -				print_bind_err_msg(tz, cdev, ret);
> >>> -		}
> >>> -	}
> >>> -}
> >>> -
> >>> -static void __unbind(struct thermal_zone_device *tz, int mask,
> >>> -			struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	int i;
> >>> -
> >>> -	for (i = 0; i < tz->trips; i++)
> >>> -		if (mask & (1 << i))
> >>> -			thermal_zone_unbind_cooling_device(tz, i, cdev);
> >>> -}
> >>> -
> >>> -static void bind_cdev(struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	int i, ret;
> >>> -	const struct thermal_zone_params *tzp;
> >>> -	struct thermal_zone_device *pos = NULL;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> -		if (!pos->tzp && !pos->ops->bind)
> >>> -			continue;
> >>> -
> >>> -		if (!pos->tzp && pos->ops->bind) {
> >>> -			ret = pos->ops->bind(pos, cdev);
> >>> -			if (ret)
> >>> -				print_bind_err_msg(pos, cdev, ret);
> >>> -		}
> >>> -
> >>> -		tzp = pos->tzp;
> >>> -		if (!tzp || !tzp->tbp)
> >>> -			continue;
> >>> -
> >>> -		for (i = 0; i < tzp->num_tbps; i++) {
> >>> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> >>> -				continue;
> >>> -			if (tzp->tbp[i].match(pos, cdev))
> >>> -				continue;
> >>> -			tzp->tbp[i].cdev = cdev;
> >>> -			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -}
> >>> -
> >>> -static void bind_tz(struct thermal_zone_device *tz)
> >>> -{
> >>> -	int i, ret;
> >>> -	struct thermal_cooling_device *pos = NULL;
> >>> -	const struct thermal_zone_params *tzp = tz->tzp;
> >>> -
> >>> -	if (!tzp && !tz->ops->bind)
> >>> -		return;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -
> >>> -	/* If there is no platform data, try to use ops->bind */
> >>> -	if (!tzp && tz->ops->bind) {
> >>> -		list_for_each_entry(pos, &thermal_cdev_list, node) {
> >>> -			ret = tz->ops->bind(tz, pos);
> >>> -			if (ret)
> >>> -				print_bind_err_msg(tz, pos, ret);
> >>> -		}
> >>> -		goto exit;
> >>> -	}
> >>> -
> >>> -	if (!tzp || !tzp->tbp)
> >>> -		goto exit;
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_cdev_list, node) {
> >>> -		for (i = 0; i < tzp->num_tbps; i++) {
> >>> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> >>> -				continue;
> >>> -			if (tzp->tbp[i].match(tz, pos))
> >>> -				continue;
> >>> -			tzp->tbp[i].cdev = pos;
> >>> -			__bind(tz, tzp->tbp[i].trip_mask, pos);
> >>> -		}
> >>> -	}
> >>> -exit:
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -}
> >>> -
> >>> -static void thermal_zone_device_set_polling(struct
> thermal_zone_device *tz,
> >>> -					    int delay)
> >>> -{
> >>> -	if (delay > 1000)
> >>> -		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> >>> -				 round_jiffies(msecs_to_jiffies(delay)));
> >>> -	else if (delay)
> >>> -		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> >>> -				 msecs_to_jiffies(delay));
> >>> -	else
> >>> -		cancel_delayed_work(&tz->poll_queue);
> >>> -}
> >>> -
> >>> -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);
> >>> -	else if (tz->polling_delay)
> >>> -		thermal_zone_device_set_polling(tz, tz->polling_delay);
> >>> -	else
> >>> -		thermal_zone_device_set_polling(tz, 0);
> >>> -
> >>> -	mutex_unlock(&tz->lock);
> >>> -}
> >>> -
> >>> -static void handle_non_critical_trips(struct thermal_zone_device *tz,
> >>> -			int trip, enum thermal_trip_type trip_type)
> >>> -{
> >>> -	if (tz->governor)
> >>> -		tz->governor->throttle(tz, trip);
> >>> -}
> >>> -
> >>> -static void handle_critical_trips(struct thermal_zone_device *tz,
> >>> -				int trip, enum thermal_trip_type trip_type)
> >>> -{
> >>> -	long trip_temp;
> >>> -
> >>> -	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> >>> -
> >>> -	/* If we have not crossed the trip_temp, we do not care. */
> >>> -	if (tz->temperature < trip_temp)
> >>> -		return;
> >>> -
> >>> -	if (tz->ops->notify)
> >>> -		tz->ops->notify(tz, trip, trip_type);
> >>> -
> >>> -	if (trip_type == THERMAL_TRIP_CRITICAL) {
> >>> -		dev_emerg(&tz->device,
> >>> -			  "critical temperature reached(%d C),shutting
> down\n",
> >>> -			  tz->temperature / 1000);
> >>> -		orderly_poweroff(true);
> >>> -	}
> >>> -}
> >>> -
> >>> -static void handle_thermal_trip(struct thermal_zone_device *tz, int
> trip)
> >>> -{
> >>> -	enum thermal_trip_type type;
> >>> -
> >>> -	tz->ops->get_trip_type(tz, trip, &type);
> >>> -
> >>> -	if (type == THERMAL_TRIP_CRITICAL || type ==
> THERMAL_TRIP_HOT)
> >>> -		handle_critical_trips(tz, trip, type);
> >>> -	else
> >>> -		handle_non_critical_trips(tz, trip, type);
> >>> -	/*
> >>> -	 * Alright, we handled this trip successfully.
> >>> -	 * So, start monitoring again.
> >>> -	 */
> >>> -	monitor_thermal_zone(tz);
> >>> -}
> >>> -
> >>> -static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> >>> -				unsigned long *temp)
> >>> -{
> >>> -	int ret = 0;
> >>> -#ifdef CONFIG_THERMAL_EMULATION
> >>> -	int count;
> >>> -	unsigned long crit_temp = -1UL;
> >>> -	enum thermal_trip_type type;
> >>> -#endif
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -
> >>> -	ret = tz->ops->get_temp(tz, temp);
> >>> -#ifdef CONFIG_THERMAL_EMULATION
> >>> -	if (!tz->emul_temperature)
> >>> -		goto skip_emul;
> >>> -
> >>> -	for (count = 0; count < tz->trips; count++) {
> >>> -		ret = tz->ops->get_trip_type(tz, count, &type);
> >>> -		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> >>> -			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> >>> -			break;
> >>> -		}
> >>> -	}
> >>> -
> >>> -	if (ret)
> >>> -		goto skip_emul;
> >>> -
> >>> -	if (*temp < crit_temp)
> >>> -		*temp = tz->emul_temperature;
> >>> -skip_emul:
> >>> -#endif
> >>> -	mutex_unlock(&tz->lock);
> >>> -	return ret;
> >>> -}
> >>> -
> >>> -static void update_temperature(struct thermal_zone_device *tz)
> >>> -{
> >>> -	long temp;
> >>> -	int ret;
> >>> -
> >>> -	ret = thermal_zone_get_temp(tz, &temp);
> >>> -	if (ret) {
> >>> -		dev_warn(&tz->device, "failed to read out thermal zone
> %d\n",
> >>> -			 tz->id);
> >>> -		return;
> >>> -	}
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -	tz->last_temperature = tz->temperature;
> >>> -	tz->temperature = temp;
> >>> -	mutex_unlock(&tz->lock);
> >>> -}
> >>> -
> >>> -void thermal_zone_device_update(struct thermal_zone_device *tz)
> >>> -{
> >>> -	int count;
> >>> -
> >>> -	update_temperature(tz);
> >>> -
> >>> -	for (count = 0; count < tz->trips; count++)
> >>> -		handle_thermal_trip(tz, count);
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_device_update);
> >>> -
> >>> -static void thermal_zone_device_check(struct work_struct *work)
> >>> -{
> >>> -	struct thermal_zone_device *tz = container_of(work, struct
> >>> -						      thermal_zone_device,
> >>> -						      poll_queue.work);
> >>> -	thermal_zone_device_update(tz);
> >>> -}
> >>> -
> >>> -/* sys I/F for thermal zone */
> >>> -
> >>> -#define to_thermal_zone(_dev) \
> >>> -	container_of(_dev, struct thermal_zone_device, device)
> >>> -
> >>> -static ssize_t
> >>> -type_show(struct device *dev, struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -
> >>> -	return sprintf(buf, "%s\n", tz->type);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -temp_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	long temperature;
> >>> -	int ret;
> >>> -
> >>> -	ret = thermal_zone_get_temp(tz, &temperature);
> >>> -
> >>> -	if (ret)
> >>> -		return ret;
> >>> -
> >>> -	return sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -mode_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	enum thermal_device_mode mode;
> >>> -	int result;
> >>> -
> >>> -	if (!tz->ops->get_mode)
> >>> -		return -EPERM;
> >>> -
> >>> -	result = tz->ops->get_mode(tz, &mode);
> >>> -	if (result)
> >>> -		return result;
> >>> -
> >>> -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ?
> "enabled"
> >>> -		       : "disabled");
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -mode_store(struct device *dev, struct device_attribute *attr,
> >>> -	   const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int result;
> >>> -
> >>> -	if (!tz->ops->set_mode)
> >>> -		return -EPERM;
> >>> -
> >>> -	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);
> >>> -	else
> >>> -		result = -EINVAL;
> >>> -
> >>> -	if (result)
> >>> -		return result;
> >>> -
> >>> -	return count;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_type_show(struct device *dev, struct device_attribute
> *attr,
> >>> -		     char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	enum thermal_trip_type type;
> >>> -	int trip, result;
> >>> -
> >>> -	if (!tz->ops->get_trip_type)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	result = tz->ops->get_trip_type(tz, trip, &type);
> >>> -	if (result)
> >>> -		return result;
> >>> -
> >>> -	switch (type) {
> >>> -	case THERMAL_TRIP_CRITICAL:
> >>> -		return sprintf(buf, "critical\n");
> >>> -	case THERMAL_TRIP_HOT:
> >>> -		return sprintf(buf, "hot\n");
> >>> -	case THERMAL_TRIP_PASSIVE:
> >>> -		return sprintf(buf, "passive\n");
> >>> -	case THERMAL_TRIP_ACTIVE:
> >>> -		return sprintf(buf, "active\n");
> >>> -	default:
> >>> -		return sprintf(buf, "unknown\n");
> >>> -	}
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_temp_store(struct device *dev, struct device_attribute
> *attr,
> >>> -		     const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int trip, ret;
> >>> -	unsigned long temperature;
> >>> -
> >>> -	if (!tz->ops->set_trip_temp)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	if (kstrtoul(buf, 10, &temperature))
> >>> -		return -EINVAL;
> >>> -
> >>> -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> >>> -
> >>> -	return ret ? ret : count;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_temp_show(struct device *dev, struct device_attribute
> *attr,
> >>> -		     char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int trip, ret;
> >>> -	long temperature;
> >>> -
> >>> -	if (!tz->ops->get_trip_temp)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> >>> -
> >>> -	if (ret)
> >>> -		return ret;
> >>> -
> >>> -	return sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> >>> -			const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int trip, ret;
> >>> -	unsigned long temperature;
> >>> -
> >>> -	if (!tz->ops->set_trip_hyst)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	if (kstrtoul(buf, 10, &temperature))
> >>> -		return -EINVAL;
> >>> -
> >>> -	/*
> >>> -	 * We are not doing any check on the 'temperature' value
> >>> -	 * here. The driver implementing 'set_trip_hyst' has to
> >>> -	 * take care of this.
> >>> -	 */
> >>> -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> >>> -
> >>> -	return ret ? ret : count;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> >>> -			char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int trip, ret;
> >>> -	unsigned long temperature;
> >>> -
> >>> -	if (!tz->ops->get_trip_hyst)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> >>> -
> >>> -	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -passive_store(struct device *dev, struct device_attribute *attr,
> >>> -		    const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	struct thermal_cooling_device *cdev = NULL;
> >>> -	int state;
> >>> -
> >>> -	if (!sscanf(buf, "%d\n", &state))
> >>> -		return -EINVAL;
> >>> -
> >>> -	/* sanity check: values below 1000 millicelcius don't make sense
> >>> -	 * and can cause the system to go into a thermal heart attack
> >>> -	 */
> >>> -	if (state && state < 1000)
> >>> -		return -EINVAL;
> >>> -
> >>> -	if (state && !tz->forced_passive) {
> >>> -		mutex_lock(&thermal_list_lock);
> >>> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> -			if (!strncmp("Processor", cdev->type,
> >>> -				     sizeof("Processor")))
> >>> -				thermal_zone_bind_cooling_device(tz,
> >>> -						THERMAL_TRIPS_NONE,
> cdev,
> >>> -						THERMAL_NO_LIMIT,
> >>> -						THERMAL_NO_LIMIT);
> >>> -		}
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		if (!tz->passive_delay)
> >>> -			tz->passive_delay = 1000;
> >>> -	} else if (!state && tz->forced_passive) {
> >>> -		mutex_lock(&thermal_list_lock);
> >>> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> -			if (!strncmp("Processor", cdev->type,
> >>> -				     sizeof("Processor")))
> >>> -				thermal_zone_unbind_cooling_device(tz,
> >>> -
> THERMAL_TRIPS_NONE,
> >>> -								   cdev);
> >>> -		}
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		tz->passive_delay = 0;
> >>> -	}
> >>> -
> >>> -	tz->forced_passive = state;
> >>> -
> >>> -	thermal_zone_device_update(tz);
> >>> -
> >>> -	return count;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -passive_show(struct device *dev, struct device_attribute *attr,
> >>> -		   char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -
> >>> -	return sprintf(buf, "%d\n", tz->forced_passive);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -policy_store(struct device *dev, struct device_attribute *attr,
> >>> -		    const char *buf, size_t count)
> >>> -{
> >>> -	int ret = -EINVAL;
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	struct thermal_governor *gov;
> >>> -
> >>> -	mutex_lock(&thermal_governor_lock);
> >>> -
> >>> -	gov = __find_governor(buf);
> >>> -	if (!gov)
> >>> -		goto exit;
> >>> -
> >>> -	tz->governor = gov;
> >>> -	ret = count;
> >>> -
> >>> -exit:
> >>> -	mutex_unlock(&thermal_governor_lock);
> >>> -	return ret;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -policy_show(struct device *dev, struct device_attribute *devattr, char
> *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -
> >>> -	return sprintf(buf, "%s\n", tz->governor->name);
> >>> -}
> >>> -
> >>> -#ifdef CONFIG_THERMAL_EMULATION
> >>> -static ssize_t
> >>> -emul_temp_store(struct device *dev, struct device_attribute *attr,
> >>> -		     const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int ret = 0;
> >>> -	unsigned long temperature;
> >>> -
> >>> -	if (kstrtoul(buf, 10, &temperature))
> >>> -		return -EINVAL;
> >>> -
> >>> -	if (!tz->ops->set_emul_temp) {
> >>> -		mutex_lock(&tz->lock);
> >>> -		tz->emul_temperature = temperature;
> >>> -		mutex_unlock(&tz->lock);
> >>> -	} else {
> >>> -		ret = tz->ops->set_emul_temp(tz, temperature);
> >>> -	}
> >>> -
> >>> -	return ret ? ret : count;
> >>> -}
> >>> -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> >>> -#endif/*CONFIG_THERMAL_EMULATION*/
> >>> -
> >>> -static DEVICE_ATTR(type, 0444, type_show, NULL);
> >>> -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> >>> -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> >>> -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show,
> passive_store);
> >>> -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show,
> policy_store);
> >>> -
> >>> -/* sys I/F for cooling device */
> >>> -#define to_cooling_device(_dev)	\
> >>> -	container_of(_dev, struct thermal_cooling_device, device)
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_type_show(struct device *dev,
> >>> -				 struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> -
> >>> -	return sprintf(buf, "%s\n", cdev->type);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_max_state_show(struct device *dev,
> >>> -				      struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> -	unsigned long state;
> >>> -	int ret;
> >>> -
> >>> -	ret = cdev->ops->get_max_state(cdev, &state);
> >>> -	if (ret)
> >>> -		return ret;
> >>> -	return sprintf(buf, "%ld\n", state);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_cur_state_show(struct device *dev,
> >>> -				      struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> -	unsigned long state;
> >>> -	int ret;
> >>> -
> >>> -	ret = cdev->ops->get_cur_state(cdev, &state);
> >>> -	if (ret)
> >>> -		return ret;
> >>> -	return sprintf(buf, "%ld\n", state);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_cur_state_store(struct device *dev,
> >>> -				       struct device_attribute *attr,
> >>> -				       const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> -	unsigned long state;
> >>> -	int result;
> >>> -
> >>> -	if (!sscanf(buf, "%ld\n", &state))
> >>> -		return -EINVAL;
> >>> -
> >>> -	if ((long)state < 0)
> >>> -		return -EINVAL;
> >>> -
> >>> -	result = cdev->ops->set_cur_state(cdev, state);
> >>> -	if (result)
> >>> -		return result;
> >>> -	return count;
> >>> -}
> >>> -
> >>> -static struct device_attribute dev_attr_cdev_type =
> >>> -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> >>> -static DEVICE_ATTR(max_state, 0444,
> >>> -		   thermal_cooling_device_max_state_show, NULL);
> >>> -static DEVICE_ATTR(cur_state, 0644,
> >>> -		   thermal_cooling_device_cur_state_show,
> >>> -		   thermal_cooling_device_cur_state_store);
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_trip_point_show(struct device *dev,
> >>> -				       struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_instance *instance;
> >>> -
> >>> -	instance =
> >>> -	    container_of(attr, struct thermal_instance, attr);
> >>> -
> >>> -	if (instance->trip == THERMAL_TRIPS_NONE)
> >>> -		return sprintf(buf, "-1\n");
> >>> -	else
> >>> -		return sprintf(buf, "%d\n", instance->trip);
> >>> -}
> >>> -
> >>> -/* Device management */
> >>> -
> >>> -#if defined(CONFIG_THERMAL_HWMON)
> >>> -
> >>> -/* hwmon sys I/F */
> >>> -#include <linux/hwmon.h>
> >>> -
> >>> -/* thermal zone devices with the same type share one hwmon device
> */
> >>> -struct thermal_hwmon_device {
> >>> -	char type[THERMAL_NAME_LENGTH];
> >>> -	struct device *device;
> >>> -	int count;
> >>> -	struct list_head tz_list;
> >>> -	struct list_head node;
> >>> -};
> >>> -
> >>> -struct thermal_hwmon_attr {
> >>> -	struct device_attribute attr;
> >>> -	char name[16];
> >>> -};
> >>> -
> >>> -/* one temperature input for each thermal zone */
> >>> -struct thermal_hwmon_temp {
> >>> -	struct list_head hwmon_node;
> >>> -	struct thermal_zone_device *tz;
> >>> -	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> >>> -	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> >>> -};
> >>> -
> >>> -static LIST_HEAD(thermal_hwmon_list);
> >>> -
> >>> -static ssize_t
> >>> -name_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> -{
> >>> -	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> >>> -	return sprintf(buf, "%s\n", hwmon->type);
> >>> -}
> >>> -static DEVICE_ATTR(name, 0444, name_show, NULL);
> >>> -
> >>> -static ssize_t
> >>> -temp_input_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> >>> -{
> >>> -	long temperature;
> >>> -	int ret;
> >>> -	struct thermal_hwmon_attr *hwmon_attr
> >>> -			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> >>> -	struct thermal_hwmon_temp *temp
> >>> -			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> >>> -				       temp_input);
> >>> -	struct thermal_zone_device *tz = temp->tz;
> >>> -
> >>> -	ret = thermal_zone_get_temp(tz, &temperature);
> >>> -
> >>> -	if (ret)
> >>> -		return ret;
> >>> -
> >>> -	return sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -temp_crit_show(struct device *dev, struct device_attribute *attr,
> >>> -		char *buf)
> >>> -{
> >>> -	struct thermal_hwmon_attr *hwmon_attr
> >>> -			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> >>> -	struct thermal_hwmon_temp *temp
> >>> -			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> >>> -				       temp_crit);
> >>> -	struct thermal_zone_device *tz = temp->tz;
> >>> -	long temperature;
> >>> -	int ret;
> >>> -
> >>> -	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> >>> -	if (ret)
> >>> -		return ret;
> >>> -
> >>> -	return sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -
> >>> -static struct thermal_hwmon_device *
> >>> -thermal_hwmon_lookup_by_type(const struct thermal_zone_device
> *tz)
> >>> -{
> >>> -	struct thermal_hwmon_device *hwmon;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> >>> -		if (!strcmp(hwmon->type, tz->type)) {
> >>> -			mutex_unlock(&thermal_list_lock);
> >>> -			return hwmon;
> >>> -		}
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	return NULL;
> >>> -}
> >>> -
> >>> -/* Find the temperature input matching a given thermal zone */
> >>> -static struct thermal_hwmon_temp *
> >>> -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device
> *hwmon,
> >>> -			  const struct thermal_zone_device *tz)
> >>> -{
> >>> -	struct thermal_hwmon_temp *temp;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> >>> -		if (temp->tz == tz) {
> >>> -			mutex_unlock(&thermal_list_lock);
> >>> -			return temp;
> >>> -		}
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	return NULL;
> >>> -}
> >>> -
> >>> -static int
> >>> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> -{
> >>> -	struct thermal_hwmon_device *hwmon;
> >>> -	struct thermal_hwmon_temp *temp;
> >>> -	int new_hwmon_device = 1;
> >>> -	int result;
> >>> -
> >>> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> >>> -	if (hwmon) {
> >>> -		new_hwmon_device = 0;
> >>> -		goto register_sys_interface;
> >>> -	}
> >>> -
> >>> -	hwmon = kzalloc(sizeof(struct thermal_hwmon_device),
> GFP_KERNEL);
> >>> -	if (!hwmon)
> >>> -		return -ENOMEM;
> >>> -
> >>> -	INIT_LIST_HEAD(&hwmon->tz_list);
> >>> -	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> >>> -	hwmon->device = hwmon_device_register(NULL);
> >>> -	if (IS_ERR(hwmon->device)) {
> >>> -		result = PTR_ERR(hwmon->device);
> >>> -		goto free_mem;
> >>> -	}
> >>> -	dev_set_drvdata(hwmon->device, hwmon);
> >>> -	result = device_create_file(hwmon->device, &dev_attr_name);
> >>> -	if (result)
> >>> -		goto free_mem;
> >>> -
> >>> - register_sys_interface:
> >>> -	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> >>> -	if (!temp) {
> >>> -		result = -ENOMEM;
> >>> -		goto unregister_name;
> >>> -	}
> >>> -
> >>> -	temp->tz = tz;
> >>> -	hwmon->count++;
> >>> -
> >>> -	snprintf(temp->temp_input.name, sizeof(temp-
> >temp_input.name),
> >>> -		 "temp%d_input", hwmon->count);
> >>> -	temp->temp_input.attr.attr.name = temp->temp_input.name;
> >>> -	temp->temp_input.attr.attr.mode = 0444;
> >>> -	temp->temp_input.attr.show = temp_input_show;
> >>> -	sysfs_attr_init(&temp->temp_input.attr.attr);
> >>> -	result = device_create_file(hwmon->device, &temp-
> >temp_input.attr);
> >>> -	if (result)
> >>> -		goto free_temp_mem;
> >>> -
> >>> -	if (tz->ops->get_crit_temp) {
> >>> -		unsigned long temperature;
> >>> -		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> >>> -			snprintf(temp->temp_crit.name,
> >>> -				 sizeof(temp->temp_crit.name),
> >>> -				"temp%d_crit", hwmon->count);
> >>> -			temp->temp_crit.attr.attr.name = temp-
> >temp_crit.name;
> >>> -			temp->temp_crit.attr.attr.mode = 0444;
> >>> -			temp->temp_crit.attr.show = temp_crit_show;
> >>> -			sysfs_attr_init(&temp->temp_crit.attr.attr);
> >>> -			result = device_create_file(hwmon->device,
> >>> -						    &temp->temp_crit.attr);
> >>> -			if (result)
> >>> -				goto unregister_input;
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	if (new_hwmon_device)
> >>> -		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> >>> -	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	return 0;
> >>> -
> >>> - unregister_input:
> >>> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> >>> - free_temp_mem:
> >>> -	kfree(temp);
> >>> - unregister_name:
> >>> -	if (new_hwmon_device) {
> >>> -		device_remove_file(hwmon->device, &dev_attr_name);
> >>> -		hwmon_device_unregister(hwmon->device);
> >>> -	}
> >>> - free_mem:
> >>> -	if (new_hwmon_device)
> >>> -		kfree(hwmon);
> >>> -
> >>> -	return result;
> >>> -}
> >>> -
> >>> -static void
> >>> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> -{
> >>> -	struct thermal_hwmon_device *hwmon;
> >>> -	struct thermal_hwmon_temp *temp;
> >>> -
> >>> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> >>> -	if (unlikely(!hwmon)) {
> >>> -		/* Should never happen... */
> >>> -		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> >>> -		return;
> >>> -	}
> >>> -
> >>> -	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> >>> -	if (unlikely(!temp)) {
> >>> -		/* Should never happen... */
> >>> -		dev_dbg(&tz->device, "temperature input lookup
> failed!\n");
> >>> -		return;
> >>> -	}
> >>> -
> >>> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> >>> -	if (tz->ops->get_crit_temp)
> >>> -		device_remove_file(hwmon->device, &temp-
> >temp_crit.attr);
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_del(&temp->hwmon_node);
> >>> -	kfree(temp);
> >>> -	if (!list_empty(&hwmon->tz_list)) {
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		return;
> >>> -	}
> >>> -	list_del(&hwmon->node);
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	device_remove_file(hwmon->device, &dev_attr_name);
> >>> -	hwmon_device_unregister(hwmon->device);
> >>> -	kfree(hwmon);
> >>> -}
> >>> -#else
> >>> -static int
> >>> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> -{
> >>> -	return 0;
> >>> -}
> >>> -
> >>> -static void
> >>> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> -{
> >>> -}
> >>> -#endif
> >>> -
> >>> -/**
> >>> - * thermal_zone_bind_cooling_device - bind a cooling device to a
> thermal zone
> >>> - * @tz:		thermal zone device
> >>> - * @trip:	indicates which trip point the cooling devices is
> >>> - *		associated with in this thermal zone.
> >>> - * @cdev:	thermal cooling device
> >>> - *
> >>> - * This function is usually called in the thermal zone device .bind
> callback.
> >>> - */
> >>> -int thermal_zone_bind_cooling_device(struct thermal_zone_device
> *tz,
> >>> -				     int trip,
> >>> -				     struct thermal_cooling_device *cdev,
> >>> -				     unsigned long upper, unsigned long lower)
> >>> -{
> >>> -	struct thermal_instance *dev;
> >>> -	struct thermal_instance *pos;
> >>> -	struct thermal_zone_device *pos1;
> >>> -	struct thermal_cooling_device *pos2;
> >>> -	unsigned long max_state;
> >>> -	int result;
> >>> -
> >>> -	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> >>> -		return -EINVAL;
> >>> -
> >>> -	list_for_each_entry(pos1, &thermal_tz_list, node) {
> >>> -		if (pos1 == tz)
> >>> -			break;
> >>> -	}
> >>> -	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> >>> -		if (pos2 == cdev)
> >>> -			break;
> >>> -	}
> >>> -
> >>> -	if (tz != pos1 || cdev != pos2)
> >>> -		return -EINVAL;
> >>> -
> >>> -	cdev->ops->get_max_state(cdev, &max_state);
> >>> -
> >>> -	/* lower default 0, upper default max_state */
> >>> -	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> >>> -	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> >>> -
> >>> -	if (lower > upper || upper > max_state)
> >>> -		return -EINVAL;
> >>> -
> >>> -	dev =
> >>> -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> >>> -	if (!dev)
> >>> -		return -ENOMEM;
> >>> -	dev->tz = tz;
> >>> -	dev->cdev = cdev;
> >>> -	dev->trip = trip;
> >>> -	dev->upper = upper;
> >>> -	dev->lower = lower;
> >>> -	dev->target = THERMAL_NO_TARGET;
> >>> -
> >>> -	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> >>> -	if (result)
> >>> -		goto free_mem;
> >>> -
> >>> -	sprintf(dev->name, "cdev%d", dev->id);
> >>> -	result =
> >>> -	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev-
> >name);
> >>> -	if (result)
> >>> -		goto release_idr;
> >>> -
> >>> -	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> >>> -	sysfs_attr_init(&dev->attr.attr);
> >>> -	dev->attr.attr.name = dev->attr_name;
> >>> -	dev->attr.attr.mode = 0444;
> >>> -	dev->attr.show = thermal_cooling_device_trip_point_show;
> >>> -	result = device_create_file(&tz->device, &dev->attr);
> >>> -	if (result)
> >>> -		goto remove_symbol_link;
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -	mutex_lock(&cdev->lock);
> >>> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> >>> -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> -		result = -EEXIST;
> >>> -		break;
> >>> -	}
> >>> -	if (!result) {
> >>> -		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> >>> -		list_add_tail(&dev->cdev_node, &cdev-
> >thermal_instances);
> >>> -	}
> >>> -	mutex_unlock(&cdev->lock);
> >>> -	mutex_unlock(&tz->lock);
> >>> -
> >>> -	if (!result)
> >>> -		return 0;
> >>> -
> >>> -	device_remove_file(&tz->device, &dev->attr);
> >>> -remove_symbol_link:
> >>> -	sysfs_remove_link(&tz->device.kobj, dev->name);
> >>> -release_idr:
> >>> -	release_idr(&tz->idr, &tz->lock, dev->id);
> >>> -free_mem:
> >>> -	kfree(dev);
> >>> -	return result;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> >>> -
> >>> -/**
> >>> - * thermal_zone_unbind_cooling_device - unbind a cooling device from
> a thermal zone
> >>> - * @tz:		thermal zone device
> >>> - * @trip:	indicates which trip point the cooling devices is
> >>> - *		associated with in this thermal zone.
> >>> - * @cdev:	thermal cooling device
> >>> - *
> >>> - * This function is usually called in the thermal zone device .unbind
> callback.
> >>> - */
> >>> -int thermal_zone_unbind_cooling_device(struct thermal_zone_device
> *tz,
> >>> -				       int trip,
> >>> -				       struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	struct thermal_instance *pos, *next;
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -	mutex_lock(&cdev->lock);
> >>> -	list_for_each_entry_safe(pos, next, &tz->thermal_instances,
> tz_node) {
> >>> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> -			list_del(&pos->tz_node);
> >>> -			list_del(&pos->cdev_node);
> >>> -			mutex_unlock(&cdev->lock);
> >>> -			mutex_unlock(&tz->lock);
> >>> -			goto unbind;
> >>> -		}
> >>> -	}
> >>> -	mutex_unlock(&cdev->lock);
> >>> -	mutex_unlock(&tz->lock);
> >>> -
> >>> -	return -ENODEV;
> >>> -
> >>> -unbind:
> >>> -	device_remove_file(&tz->device, &pos->attr);
> >>> -	sysfs_remove_link(&tz->device.kobj, pos->name);
> >>> -	release_idr(&tz->idr, &tz->lock, pos->id);
> >>> -	kfree(pos);
> >>> -	return 0;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> >>> -
> >>> -static void thermal_release(struct device *dev)
> >>> -{
> >>> -	struct thermal_zone_device *tz;
> >>> -	struct thermal_cooling_device *cdev;
> >>> -
> >>> -	if (!strncmp(dev_name(dev), "thermal_zone",
> >>> -		     sizeof("thermal_zone") - 1)) {
> >>> -		tz = to_thermal_zone(dev);
> >>> -		kfree(tz);
> >>> -	} else {
> >>> -		cdev = to_cooling_device(dev);
> >>> -		kfree(cdev);
> >>> -	}
> >>> -}
> >>> -
> >>> -static struct class thermal_class = {
> >>> -	.name = "thermal",
> >>> -	.dev_release = thermal_release,
> >>> -};
> >>> -
> >>> -/**
> >>> - * thermal_cooling_device_register - register a new thermal cooling
> device
> >>> - * @type:	the thermal cooling device type.
> >>> - * @devdata:	device private data.
> >>> - * @ops:		standard thermal cooling devices callbacks.
> >>> - */
> >>> -struct thermal_cooling_device *
> >>> -thermal_cooling_device_register(char *type, void *devdata,
> >>> -				const struct thermal_cooling_device_ops
> *ops)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev;
> >>> -	int result;
> >>> -
> >>> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> >>> -	    !ops->set_cur_state)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> >>> -	if (!cdev)
> >>> -		return ERR_PTR(-ENOMEM);
> >>> -
> >>> -	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> >>> -	if (result) {
> >>> -		kfree(cdev);
> >>> -		return ERR_PTR(result);
> >>> -	}
> >>> -
> >>> -	strcpy(cdev->type, type ? : "");
> >>> -	mutex_init(&cdev->lock);
> >>> -	INIT_LIST_HEAD(&cdev->thermal_instances);
> >>> -	cdev->ops = ops;
> >>> -	cdev->updated = true;
> >>> -	cdev->device.class = &thermal_class;
> >>> -	cdev->devdata = devdata;
> >>> -	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> >>> -	result = device_register(&cdev->device);
> >>> -	if (result) {
> >>> -		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev-
> >id);
> >>> -		kfree(cdev);
> >>> -		return ERR_PTR(result);
> >>> -	}
> >>> -
> >>> -	/* sys I/F */
> >>> -	if (type) {
> >>> -		result = device_create_file(&cdev->device,
> &dev_attr_cdev_type);
> >>> -		if (result)
> >>> -			goto unregister;
> >>> -	}
> >>> -
> >>> -	result = device_create_file(&cdev->device, &dev_attr_max_state);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	/* Add 'this' new cdev to the global cdev list */
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_add(&cdev->node, &thermal_cdev_list);
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	/* Update binding information for 'this' new cdev */
> >>> -	bind_cdev(cdev);
> >>> -
> >>> -	return cdev;
> >>> -
> >>> -unregister:
> >>> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> >>> -	device_unregister(&cdev->device);
> >>> -	return ERR_PTR(result);
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_cooling_device_register);
> >>> -
> >>> -/**
> >>> - * thermal_cooling_device_unregister - removes the registered thermal
> cooling device
> >>> - * @cdev:	the thermal cooling device to remove.
> >>> - *
> >>> - * thermal_cooling_device_unregister() must be called when the device
> is no
> >>> - * longer needed.
> >>> - */
> >>> -void thermal_cooling_device_unregister(struct thermal_cooling_device
> *cdev)
> >>> -{
> >>> -	int i;
> >>> -	const struct thermal_zone_params *tzp;
> >>> -	struct thermal_zone_device *tz;
> >>> -	struct thermal_cooling_device *pos = NULL;
> >>> -
> >>> -	if (!cdev)
> >>> -		return;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_for_each_entry(pos, &thermal_cdev_list, node)
> >>> -	    if (pos == cdev)
> >>> -		break;
> >>> -	if (pos != cdev) {
> >>> -		/* thermal cooling device not found */
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		return;
> >>> -	}
> >>> -	list_del(&cdev->node);
> >>> -
> >>> -	/* Unbind all thermal zones associated with 'this' cdev */
> >>> -	list_for_each_entry(tz, &thermal_tz_list, node) {
> >>> -		if (tz->ops->unbind) {
> >>> -			tz->ops->unbind(tz, cdev);
> >>> -			continue;
> >>> -		}
> >>> -
> >>> -		if (!tz->tzp || !tz->tzp->tbp)
> >>> -			continue;
> >>> -
> >>> -		tzp = tz->tzp;
> >>> -		for (i = 0; i < tzp->num_tbps; i++) {
> >>> -			if (tzp->tbp[i].cdev == cdev) {
> >>> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> >>> -				tzp->tbp[i].cdev = NULL;
> >>> -			}
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	if (cdev->type[0])
> >>> -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> >>> -	device_remove_file(&cdev->device, &dev_attr_max_state);
> >>> -	device_remove_file(&cdev->device, &dev_attr_cur_state);
> >>> -
> >>> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> >>> -	device_unregister(&cdev->device);
> >>> -	return;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_cooling_device_unregister);
> >>> -
> >>> -void thermal_cdev_update(struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	struct thermal_instance *instance;
> >>> -	unsigned long target = 0;
> >>> -
> >>> -	/* cooling device is updated*/
> >>> -	if (cdev->updated)
> >>> -		return;
> >>> -
> >>> -	mutex_lock(&cdev->lock);
> >>> -	/* Make sure cdev enters the deepest cooling state */
> >>> -	list_for_each_entry(instance, &cdev->thermal_instances,
> cdev_node) {
> >>> -		if (instance->target == THERMAL_NO_TARGET)
> >>> -			continue;
> >>> -		if (instance->target > target)
> >>> -			target = instance->target;
> >>> -	}
> >>> -	mutex_unlock(&cdev->lock);
> >>> -	cdev->ops->set_cur_state(cdev, target);
> >>> -	cdev->updated = true;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_cdev_update);
> >>> -
> >>> -/**
> >>> - * notify_thermal_framework - Sensor drivers use this API to notify
> framework
> >>> - * @tz:		thermal zone device
> >>> - * @trip:	indicates which trip point has been crossed
> >>> - *
> >>> - * This function handles the trip events from sensor drivers. It starts
> >>> - * throttling the cooling devices according to the policy configured.
> >>> - * For CRITICAL and HOT trip points, this notifies the respective drivers,
> >>> - * and does actual throttling for other trip points i.e ACTIVE and
> PASSIVE.
> >>> - * The throttling policy is based on the configured platform data; if no
> >>> - * platform data is provided, this uses the step_wise throttling policy.
> >>> - */
> >>> -void notify_thermal_framework(struct thermal_zone_device *tz, int
> trip)
> >>> -{
> >>> -	handle_thermal_trip(tz, trip);
> >>> -}
> >>> -EXPORT_SYMBOL(notify_thermal_framework);
> >>> -
> >>> -/**
> >>> - * create_trip_attrs - create attributes for trip points
> >>> - * @tz:		the thermal zone device
> >>> - * @mask:	Writeable trip point bitmap.
> >>> - */
> >>> -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> >>> -{
> >>> -	int indx;
> >>> -	int size = sizeof(struct thermal_attr) * tz->trips;
> >>> -
> >>> -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> >>> -	if (!tz->trip_type_attrs)
> >>> -		return -ENOMEM;
> >>> -
> >>> -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> >>> -	if (!tz->trip_temp_attrs) {
> >>> -		kfree(tz->trip_type_attrs);
> >>> -		return -ENOMEM;
> >>> -	}
> >>> -
> >>> -	if (tz->ops->get_trip_hyst) {
> >>> -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> >>> -		if (!tz->trip_hyst_attrs) {
> >>> -			kfree(tz->trip_type_attrs);
> >>> -			kfree(tz->trip_temp_attrs);
> >>> -			return -ENOMEM;
> >>> -		}
> >>> -	}
> >>> -
> >>> -
> >>> -	for (indx = 0; indx < tz->trips; indx++) {
> >>> -		/* create trip type attribute */
> >>> -		snprintf(tz->trip_type_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> -			 "trip_point_%d_type", indx);
> >>> -
> >>> -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> >>> -		tz->trip_type_attrs[indx].attr.attr.name =
> >>> -						tz-
> >trip_type_attrs[indx].name;
> >>> -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> >>> -
> >>> -		device_create_file(&tz->device,
> >>> -				   &tz->trip_type_attrs[indx].attr);
> >>> -
> >>> -		/* create trip temp attribute */
> >>> -		snprintf(tz->trip_temp_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> -			 "trip_point_%d_temp", indx);
> >>> -
> >>> -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> >>> -		tz->trip_temp_attrs[indx].attr.attr.name =
> >>> -						tz-
> >trip_temp_attrs[indx].name;
> >>> -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> -		tz->trip_temp_attrs[indx].attr.show =
> trip_point_temp_show;
> >>> -		if (mask & (1 << indx)) {
> >>> -			tz->trip_temp_attrs[indx].attr.attr.mode |=
> S_IWUSR;
> >>> -			tz->trip_temp_attrs[indx].attr.store =
> >>> -
> 	trip_point_temp_store;
> >>> -		}
> >>> -
> >>> -		device_create_file(&tz->device,
> >>> -				   &tz->trip_temp_attrs[indx].attr);
> >>> -
> >>> -		/* create Optional trip hyst attribute */
> >>> -		if (!tz->ops->get_trip_hyst)
> >>> -			continue;
> >>> -		snprintf(tz->trip_hyst_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> -			 "trip_point_%d_hyst", indx);
> >>> -
> >>> -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> >>> -		tz->trip_hyst_attrs[indx].attr.attr.name =
> >>> -					tz->trip_hyst_attrs[indx].name;
> >>> -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> >>> -		if (tz->ops->set_trip_hyst) {
> >>> -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> >>> -			tz->trip_hyst_attrs[indx].attr.store =
> >>> -					trip_point_hyst_store;
> >>> -		}
> >>> -
> >>> -		device_create_file(&tz->device,
> >>> -				   &tz->trip_hyst_attrs[indx].attr);
> >>> -	}
> >>> -	return 0;
> >>> -}
> >>> -
> >>> -static void remove_trip_attrs(struct thermal_zone_device *tz)
> >>> -{
> >>> -	int indx;
> >>> -
> >>> -	for (indx = 0; indx < tz->trips; indx++) {
> >>> -		device_remove_file(&tz->device,
> >>> -				   &tz->trip_type_attrs[indx].attr);
> >>> -		device_remove_file(&tz->device,
> >>> -				   &tz->trip_temp_attrs[indx].attr);
> >>> -		if (tz->ops->get_trip_hyst)
> >>> -			device_remove_file(&tz->device,
> >>> -				  &tz->trip_hyst_attrs[indx].attr);
> >>> -	}
> >>> -	kfree(tz->trip_type_attrs);
> >>> -	kfree(tz->trip_temp_attrs);
> >>> -	kfree(tz->trip_hyst_attrs);
> >>> -}
> >>> -
> >>> -/**
> >>> - * thermal_zone_device_register - register a new thermal zone device
> >>> - * @type:	the thermal zone device type
> >>> - * @trips:	the number of trip points the thermal zone support
> >>> - * @mask:	a bit string indicating the writeablility of trip points
> >>> - * @devdata:	private device data
> >>> - * @ops:	standard thermal zone device callbacks
> >>> - * @tzp:	thermal zone platform parameters
> >>> - * @passive_delay: number of milliseconds to wait between polls when
> >>> - *		   performing passive cooling
> >>> - * @polling_delay: number of milliseconds to wait between polls when
> checking
> >>> - *		   whether trip points have been crossed (0 for interrupt
> >>> - *		   driven systems)
> >>> - *
> >>> - * thermal_zone_device_unregister() must be called when the device is
> no
> >>> - * longer needed. The passive cooling depends on the .get_trend()
> return value.
> >>> - */
> >>> -struct thermal_zone_device *thermal_zone_device_register(const
> char *type,
> >>> -	int trips, int mask, void *devdata,
> >>> -	const struct thermal_zone_device_ops *ops,
> >>> -	const struct thermal_zone_params *tzp,
> >>> -	int passive_delay, int polling_delay)
> >>> -{
> >>> -	struct thermal_zone_device *tz;
> >>> -	enum thermal_trip_type trip_type;
> >>> -	int result;
> >>> -	int count;
> >>> -	int passive = 0;
> >>> -
> >>> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	if (!ops || !ops->get_temp)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	if (trips > 0 && !ops->get_trip_type)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> >>> -	if (!tz)
> >>> -		return ERR_PTR(-ENOMEM);
> >>> -
> >>> -	INIT_LIST_HEAD(&tz->thermal_instances);
> >>> -	idr_init(&tz->idr);
> >>> -	mutex_init(&tz->lock);
> >>> -	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> >>> -	if (result) {
> >>> -		kfree(tz);
> >>> -		return ERR_PTR(result);
> >>> -	}
> >>> -
> >>> -	strcpy(tz->type, type ? : "");
> >>> -	tz->ops = ops;
> >>> -	tz->tzp = tzp;
> >>> -	tz->device.class = &thermal_class;
> >>> -	tz->devdata = devdata;
> >>> -	tz->trips = trips;
> >>> -	tz->passive_delay = passive_delay;
> >>> -	tz->polling_delay = polling_delay;
> >>> -
> >>> -	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> >>> -	result = device_register(&tz->device);
> >>> -	if (result) {
> >>> -		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> -		kfree(tz);
> >>> -		return ERR_PTR(result);
> >>> -	}
> >>> -
> >>> -	/* sys I/F */
> >>> -	if (type) {
> >>> -		result = device_create_file(&tz->device, &dev_attr_type);
> >>> -		if (result)
> >>> -			goto unregister;
> >>> -	}
> >>> -
> >>> -	result = device_create_file(&tz->device, &dev_attr_temp);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	if (ops->get_mode) {
> >>> -		result = device_create_file(&tz->device, &dev_attr_mode);
> >>> -		if (result)
> >>> -			goto unregister;
> >>> -	}
> >>> -
> >>> -	result = create_trip_attrs(tz, mask);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	for (count = 0; count < trips; count++) {
> >>> -		tz->ops->get_trip_type(tz, count, &trip_type);
> >>> -		if (trip_type == THERMAL_TRIP_PASSIVE)
> >>> -			passive = 1;
> >>> -	}
> >>> -
> >>> -	if (!passive) {
> >>> -		result = device_create_file(&tz->device, &dev_attr_passive);
> >>> -		if (result)
> >>> -			goto unregister;
> >>> -	}
> >>> -
> >>> -#ifdef CONFIG_THERMAL_EMULATION
> >>> -	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -#endif
> >>> -	/* Create policy attribute */
> >>> -	result = device_create_file(&tz->device, &dev_attr_policy);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	/* Update 'this' zone's governor information */
> >>> -	mutex_lock(&thermal_governor_lock);
> >>> -
> >>> -	if (tz->tzp)
> >>> -		tz->governor = __find_governor(tz->tzp->governor_name);
> >>> -	else
> >>> -		tz->governor =
> __find_governor(DEFAULT_THERMAL_GOVERNOR);
> >>> -
> >>> -	mutex_unlock(&thermal_governor_lock);
> >>> -
> >>> -	result = thermal_add_hwmon_sysfs(tz);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_add_tail(&tz->node, &thermal_tz_list);
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	/* Bind cooling devices for this zone */
> >>> -	bind_tz(tz);
> >>> -
> >>> -	INIT_DELAYED_WORK(&(tz->poll_queue),
> thermal_zone_device_check);
> >>> -
> >>> -	thermal_zone_device_update(tz);
> >>> -
> >>> -	if (!result)
> >>> -		return tz;
> >>> -
> >>> -unregister:
> >>> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> -	device_unregister(&tz->device);
> >>> -	return ERR_PTR(result);
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_device_register);
> >>> -
> >>> -/**
> >>> - * thermal_device_unregister - removes the registered thermal zone
> device
> >>> - * @tz: the thermal zone device to remove
> >>> - */
> >>> -void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> >>> -{
> >>> -	int i;
> >>> -	const struct thermal_zone_params *tzp;
> >>> -	struct thermal_cooling_device *cdev;
> >>> -	struct thermal_zone_device *pos = NULL;
> >>> -
> >>> -	if (!tz)
> >>> -		return;
> >>> -
> >>> -	tzp = tz->tzp;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_for_each_entry(pos, &thermal_tz_list, node)
> >>> -	    if (pos == tz)
> >>> -		break;
> >>> -	if (pos != tz) {
> >>> -		/* thermal zone device not found */
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		return;
> >>> -	}
> >>> -	list_del(&tz->node);
> >>> -
> >>> -	/* Unbind all cdevs associated with 'this' thermal zone */
> >>> -	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> -		if (tz->ops->unbind) {
> >>> -			tz->ops->unbind(tz, cdev);
> >>> -			continue;
> >>> -		}
> >>> -
> >>> -		if (!tzp || !tzp->tbp)
> >>> -			break;
> >>> -
> >>> -		for (i = 0; i < tzp->num_tbps; i++) {
> >>> -			if (tzp->tbp[i].cdev == cdev) {
> >>> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> >>> -				tzp->tbp[i].cdev = NULL;
> >>> -			}
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	thermal_zone_device_set_polling(tz, 0);
> >>> -
> >>> -	if (tz->type[0])
> >>> -		device_remove_file(&tz->device, &dev_attr_type);
> >>> -	device_remove_file(&tz->device, &dev_attr_temp);
> >>> -	if (tz->ops->get_mode)
> >>> -		device_remove_file(&tz->device, &dev_attr_mode);
> >>> -	device_remove_file(&tz->device, &dev_attr_policy);
> >>> -	remove_trip_attrs(tz);
> >>> -	tz->governor = NULL;
> >>> -
> >>> -	thermal_remove_hwmon_sysfs(tz);
> >>> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> -	idr_destroy(&tz->idr);
> >>> -	mutex_destroy(&tz->lock);
> >>> -	device_unregister(&tz->device);
> >>> -	return;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_device_unregister);
> >>> -
> >>> -#ifdef CONFIG_NET
> >>> -static struct genl_family thermal_event_genl_family = {
> >>> -	.id = GENL_ID_GENERATE,
> >>> -	.name = THERMAL_GENL_FAMILY_NAME,
> >>> -	.version = THERMAL_GENL_VERSION,
> >>> -	.maxattr = THERMAL_GENL_ATTR_MAX,
> >>> -};
> >>> -
> >>> -static struct genl_multicast_group thermal_event_mcgrp = {
> >>> -	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> >>> -};
> >>> -
> >>> -int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> >>> -					enum events event)
> >>> -{
> >>> -	struct sk_buff *skb;
> >>> -	struct nlattr *attr;
> >>> -	struct thermal_genl_event *thermal_event;
> >>> -	void *msg_header;
> >>> -	int size;
> >>> -	int result;
> >>> -	static unsigned int thermal_event_seqnum;
> >>> -
> >>> -	if (!tz)
> >>> -		return -EINVAL;
> >>> -
> >>> -	/* allocate memory */
> >>> -	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> >>> -	       nla_total_size(0);
> >>> -
> >>> -	skb = genlmsg_new(size, GFP_ATOMIC);
> >>> -	if (!skb)
> >>> -		return -ENOMEM;
> >>> -
> >>> -	/* add the genetlink message header */
> >>> -	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> >>> -				 &thermal_event_genl_family, 0,
> >>> -				 THERMAL_GENL_CMD_EVENT);
> >>> -	if (!msg_header) {
> >>> -		nlmsg_free(skb);
> >>> -		return -ENOMEM;
> >>> -	}
> >>> -
> >>> -	/* fill the data */
> >>> -	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> >>> -			   sizeof(struct thermal_genl_event));
> >>> -
> >>> -	if (!attr) {
> >>> -		nlmsg_free(skb);
> >>> -		return -EINVAL;
> >>> -	}
> >>> -
> >>> -	thermal_event = nla_data(attr);
> >>> -	if (!thermal_event) {
> >>> -		nlmsg_free(skb);
> >>> -		return -EINVAL;
> >>> -	}
> >>> -
> >>> -	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> >>> -
> >>> -	thermal_event->orig = tz->id;
> >>> -	thermal_event->event = event;
> >>> -
> >>> -	/* send multicast genetlink message */
> >>> -	result = genlmsg_end(skb, msg_header);
> >>> -	if (result < 0) {
> >>> -		nlmsg_free(skb);
> >>> -		return result;
> >>> -	}
> >>> -
> >>> -	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id,
> GFP_ATOMIC);
> >>> -	if (result)
> >>> -		dev_err(&tz->device, "Failed to send netlink event:%d",
> result);
> >>> -
> >>> -	return result;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_generate_netlink_event);
> >>> -
> >>> -static int genetlink_init(void)
> >>> -{
> >>> -	int result;
> >>> -
> >>> -	result = genl_register_family(&thermal_event_genl_family);
> >>> -	if (result)
> >>> -		return result;
> >>> -
> >>> -	result = genl_register_mc_group(&thermal_event_genl_family,
> >>> -					&thermal_event_mcgrp);
> >>> -	if (result)
> >>> -		genl_unregister_family(&thermal_event_genl_family);
> >>> -	return result;
> >>> -}
> >>> -
> >>> -static void genetlink_exit(void)
> >>> -{
> >>> -	genl_unregister_family(&thermal_event_genl_family);
> >>> -}
> >>> -#else /* !CONFIG_NET */
> >>> -static inline int genetlink_init(void) { return 0; }
> >>> -static inline void genetlink_exit(void) {}
> >>> -#endif /* !CONFIG_NET */
> >>> -
> >>> -static int __init thermal_init(void)
> >>> -{
> >>> -	int result = 0;
> >>> -
> >>> -	result = class_register(&thermal_class);
> >>> -	if (result) {
> >>> -		idr_destroy(&thermal_tz_idr);
> >>> -		idr_destroy(&thermal_cdev_idr);
> >>> -		mutex_destroy(&thermal_idr_lock);
> >>> -		mutex_destroy(&thermal_list_lock);
> >>> -		return result;
> >>> -	}
> >>> -	result = genetlink_init();
> >>> -	return result;
> >>> -}
> >>> -
> >>> -static void __exit thermal_exit(void)
> >>> -{
> >>> -	class_unregister(&thermal_class);
> >>> -	idr_destroy(&thermal_tz_idr);
> >>> -	idr_destroy(&thermal_cdev_idr);
> >>> -	mutex_destroy(&thermal_idr_lock);
> >>> -	mutex_destroy(&thermal_list_lock);
> >>> -	genetlink_exit();
> >>> -}
> >>> -
> >>> -fs_initcall(thermal_init);
> >>> -module_exit(thermal_exit);
> >>>
> >>
> >
> >
> >
> >

ÿôèº{.nÇ+‰·Ÿ®‰­†+%ŠËÿ±éݶ\x17¥Šwÿº{.nÇ+‰·¥Š{±þG«éÿŠ{ayº\x1dʇڙë,j\a­¢f£¢·hšïêÿ‘êçz_è®\x03(­éšŽŠÝ¢j"ú\x1a¶^[m§ÿÿ¾\a«þG«éÿ¢¸?™¨è­Ú&£ø§~á¶iO•æ¬z·švØ^\x14\x04\x1a¶^[m§ÿÿÃ\fÿ¶ìÿ¢¸?–I¥

^ permalink raw reply	[flat|nested] 23+ messages in thread

* RE: [RFC,1/5] Thermal: rename thermal_sys.c to thermal_core.c
@ 2013-04-01 13:09           ` R, Durgadoss
  0 siblings, 0 replies; 23+ messages in thread
From: R, Durgadoss @ 2013-04-01 13:09 UTC (permalink / raw)
  To: Eduardo Valentin, Zhang, Rui; +Cc: linux-pm, linux-kernel, amit.daniel, andi

> -----Original Message-----
> From: Eduardo Valentin [mailto:eduardo.valentin@ti.com]
> Sent: Monday, April 01, 2013 6:14 PM
> To: Zhang, Rui
> Cc: linux-pm@vger.kernel.org; linux-kernel@vger.kernel.org;
> amit.daniel@samsung.com; R, Durgadoss; andi@lisas.de
> Subject: Re: [RFC,1/5] Thermal: rename thermal_sys.c to thermal_core.c
> 
> Hey Rui,
> 
> On 27-03-2013 22:40, Zhang Rui wrote:
> > On Tue, 2013-03-26 at 18:04 -0400, Eduardo Valentin wrote:
> >> Hi Rui,
> >>
> >> A side note:
> >> I'd really appreciate if you could copy on your patches on
> >> drivers/thermal/. I had some issues with TI server and got un subscribed
> >> from linux-pm. Now I will try to catch up any way,
> >>
> > sure.
> >
> >> Some comments.
> >>
> >> On 26-03-2013 12:26, Zhang Rui wrote:
> >>> No functional change in this patch.
> >>>
> >>
> >> Just a better description would also help on code version control.
> >>
> > will add it in V2.
> >
> >>> Signed-off-by: Zhang Rui <rui.zhang@intel.com>
> >>
> >> Apart from minor comments, I agreed with this change. So feel free to
> >> add my:
> >>
> >> Acked-by: Eduardo Valentin <eduardo.valentin@ti.com>
> >>
> > thanks!
> >
> >>>
> >>> ---
> >>> drivers/thermal/Makefile       |    1 +
> >>>    drivers/thermal/thermal_core.c | 1888
> ++++++++++++++++++++++++++++++++++++++++
> >>>    drivers/thermal/thermal_sys.c  | 1888 ----------------------------------------
> >>
> >> When sending renames, use git format-patch --find-renames, it makes a
> >> better summary of what you have done, specially if you have changed
> >> something in the file while renaming.
> >>
> > a useful tip. thanks!
> >>>    3 files changed, 1889 insertions(+), 1888 deletions(-)
> >>>    create mode 100644 drivers/thermal/thermal_core.c
> >>>    delete mode 100644 drivers/thermal/thermal_sys.c
> >>>
> >>> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> >>> index d3a2b38..b2009bd 100644
> >>> --- a/drivers/thermal/Makefile
> >>> +++ b/drivers/thermal/Makefile
> >>> @@ -3,6 +3,7 @@
> >>>    #
> >>>
> >>>    obj-$(CONFIG_THERMAL)		+= thermal_sys.o
> >>
> >> I know this is for fixing the annoying bug with fan max speed. But while
> >> still here, do you think 'thermal_sys' is a good name for thermal
> >> framework driver? Maybe just 'thermal' would suffice?
> >>
> > as I said, there is already a thermal driver, aka,
> > driver/acpi/thermal.c.
> >
> 
> In fact there is. On the other hand, it does not imply that this naming
> convention is correct, right?
> 
> Unless you have a strong requirement to name these drivers the way it
> is, I'd suggest to take the opportunity to rename them.
> drivers/acpi/thermal.c could be named 'thermal-acpi.ko', if this does
> not violate any ACPI requirements. While this driver,
> drivers/thermal/thermal_sys.c, would be named only 'thermal.ko'.

Yes, I was also thinking of the same thing.
Can we do this Rui ?

Thanks,
Durga

> 
> 
> > thanks,
> 
> Regards,
> 
> Ed
> 
> > rui
> >>> +thermal_sys-y			+= thermal_core.o
> >>>
> >>>    # governors
> >>>    obj-$(CONFIG_THERMAL_GOV_FAIR_SHARE)	+= fair_share.o
> >>> diff --git a/drivers/thermal/thermal_core.c
> b/drivers/thermal/thermal_core.c
> >>> new file mode 100644
> >>> index 0000000..5b7863a
> >>> --- /dev/null
> >>> +++ b/drivers/thermal/thermal_core.c
> >>> @@ -0,0 +1,1888 @@
> >>> +/*
> >>> + *  thermal.c - Generic Thermal Management Sysfs support.
> >>> + *
> >>> + *  Copyright (C) 2008 Intel Corp
> >>> + *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> >>> + *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> >>> + *
> >>> + *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> >>> + *
> >>> + *  This program is free software; you can redistribute it and/or modify
> >>> + *  it under the terms of the GNU General Public License as published
> by
> >>> + *  the Free Software Foundation; version 2 of the License.
> >>> + *
> >>> + *  This program is distributed in the hope that it will be useful, but
> >>> + *  WITHOUT ANY WARRANTY; without even the implied warranty of
> >>> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> the GNU
> >>> + *  General Public License for more details.
> >>> + *
> >>> + *  You should have received a copy of the GNU General Public License
> along
> >>> + *  with this program; if not, write to the Free Software Foundation,
> Inc.,
> >>> + *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> >>> + *
> >>> + *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> >>> + */
> >>> +
> >>> +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> >>> +
> >>> +#include <linux/module.h>
> >>> +#include <linux/device.h>
> >>> +#include <linux/err.h>
> >>> +#include <linux/slab.h>
> >>> +#include <linux/kdev_t.h>
> >>> +#include <linux/idr.h>
> >>> +#include <linux/thermal.h>
> >>> +#include <linux/reboot.h>
> >>> +#include <net/netlink.h>
> >>> +#include <net/genetlink.h>
> >>> +
> >>> +#include "thermal_core.h"
> >>> +
> >>> +MODULE_AUTHOR("Zhang Rui");
> >>> +MODULE_DESCRIPTION("Generic thermal management sysfs
> support");
> >>> +MODULE_LICENSE("GPL");
> >>> +
> >>> +static DEFINE_IDR(thermal_tz_idr);
> >>> +static DEFINE_IDR(thermal_cdev_idr);
> >>> +static DEFINE_MUTEX(thermal_idr_lock);
> >>> +
> >>> +static LIST_HEAD(thermal_tz_list);
> >>> +static LIST_HEAD(thermal_cdev_list);
> >>> +static LIST_HEAD(thermal_governor_list);
> >>> +
> >>> +static DEFINE_MUTEX(thermal_list_lock);
> >>> +static DEFINE_MUTEX(thermal_governor_lock);
> >>> +
> >>> +static struct thermal_governor *__find_governor(const char *name)
> >>> +{
> >>> +	struct thermal_governor *pos;
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> >>> +		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> >>> +			return pos;
> >>> +
> >>> +	return NULL;
> >>> +}
> >>> +
> >>> +int thermal_register_governor(struct thermal_governor *governor)
> >>> +{
> >>> +	int err;
> >>> +	const char *name;
> >>> +	struct thermal_zone_device *pos;
> >>> +
> >>> +	if (!governor)
> >>> +		return -EINVAL;
> >>> +
> >>> +	mutex_lock(&thermal_governor_lock);
> >>> +
> >>> +	err = -EBUSY;
> >>> +	if (__find_governor(governor->name) == NULL) {
> >>> +		err = 0;
> >>> +		list_add(&governor->governor_list,
> &thermal_governor_list);
> >>> +	}
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> +		if (pos->governor)
> >>> +			continue;
> >>> +		if (pos->tzp)
> >>> +			name = pos->tzp->governor_name;
> >>> +		else
> >>> +			name = DEFAULT_THERMAL_GOVERNOR;
> >>> +		if (!strnicmp(name, governor->name,
> THERMAL_NAME_LENGTH))
> >>> +			pos->governor = governor;
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +	mutex_unlock(&thermal_governor_lock);
> >>> +
> >>> +	return err;
> >>> +}
> >>> +EXPORT_SYMBOL_GPL(thermal_register_governor);
> >>> +
> >>> +void thermal_unregister_governor(struct thermal_governor
> *governor)
> >>> +{
> >>> +	struct thermal_zone_device *pos;
> >>> +
> >>> +	if (!governor)
> >>> +		return;
> >>> +
> >>> +	mutex_lock(&thermal_governor_lock);
> >>> +
> >>> +	if (__find_governor(governor->name) == NULL)
> >>> +		goto exit;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> +		if (!strnicmp(pos->governor->name, governor->name,
> >>> +						THERMAL_NAME_LENGTH))
> >>> +			pos->governor = NULL;
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +	list_del(&governor->governor_list);
> >>> +exit:
> >>> +	mutex_unlock(&thermal_governor_lock);
> >>> +	return;
> >>> +}
> >>> +EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> >>> +
> >>> +static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> >>> +{
> >>> +	int ret;
> >>> +
> >>> +	if (lock)
> >>> +		mutex_lock(lock);
> >>> +	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> >>> +	if (lock)
> >>> +		mutex_unlock(lock);
> >>> +	if (unlikely(ret < 0))
> >>> +		return ret;
> >>> +	*id = ret;
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static void release_idr(struct idr *idr, struct mutex *lock, int id)
> >>> +{
> >>> +	if (lock)
> >>> +		mutex_lock(lock);
> >>> +	idr_remove(idr, id);
> >>> +	if (lock)
> >>> +		mutex_unlock(lock);
> >>> +}
> >>> +
> >>> +int get_tz_trend(struct thermal_zone_device *tz, int trip)
> >>> +{
> >>> +	enum thermal_trend trend;
> >>> +
> >>> +	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> >>> +		if (tz->temperature > tz->last_temperature)
> >>> +			trend = THERMAL_TREND_RAISING;
> >>> +		else if (tz->temperature < tz->last_temperature)
> >>> +			trend = THERMAL_TREND_DROPPING;
> >>> +		else
> >>> +			trend = THERMAL_TREND_STABLE;
> >>> +	}
> >>> +
> >>> +	return trend;
> >>> +}
> >>> +EXPORT_SYMBOL(get_tz_trend);
> >>> +
> >>> +struct thermal_instance *get_thermal_instance(struct
> thermal_zone_device *tz,
> >>> +			struct thermal_cooling_device *cdev, int trip)
> >>> +{
> >>> +	struct thermal_instance *pos = NULL;
> >>> +	struct thermal_instance *target_instance = NULL;
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +	mutex_lock(&cdev->lock);
> >>> +
> >>> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> >>> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> +			target_instance = pos;
> >>> +			break;
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&cdev->lock);
> >>> +	mutex_unlock(&tz->lock);
> >>> +
> >>> +	return target_instance;
> >>> +}
> >>> +EXPORT_SYMBOL(get_thermal_instance);
> >>> +
> >>> +static void print_bind_err_msg(struct thermal_zone_device *tz,
> >>> +			struct thermal_cooling_device *cdev, int ret)
> >>> +{
> >>> +	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> >>> +				tz->type, cdev->type, ret);
> >>> +}
> >>> +
> >>> +static void __bind(struct thermal_zone_device *tz, int mask,
> >>> +			struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	int i, ret;
> >>> +
> >>> +	for (i = 0; i < tz->trips; i++) {
> >>> +		if (mask & (1 << i)) {
> >>> +			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> >>> +					THERMAL_NO_LIMIT,
> THERMAL_NO_LIMIT);
> >>> +			if (ret)
> >>> +				print_bind_err_msg(tz, cdev, ret);
> >>> +		}
> >>> +	}
> >>> +}
> >>> +
> >>> +static void __unbind(struct thermal_zone_device *tz, int mask,
> >>> +			struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	int i;
> >>> +
> >>> +	for (i = 0; i < tz->trips; i++)
> >>> +		if (mask & (1 << i))
> >>> +			thermal_zone_unbind_cooling_device(tz, i, cdev);
> >>> +}
> >>> +
> >>> +static void bind_cdev(struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	int i, ret;
> >>> +	const struct thermal_zone_params *tzp;
> >>> +	struct thermal_zone_device *pos = NULL;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> +		if (!pos->tzp && !pos->ops->bind)
> >>> +			continue;
> >>> +
> >>> +		if (!pos->tzp && pos->ops->bind) {
> >>> +			ret = pos->ops->bind(pos, cdev);
> >>> +			if (ret)
> >>> +				print_bind_err_msg(pos, cdev, ret);
> >>> +		}
> >>> +
> >>> +		tzp = pos->tzp;
> >>> +		if (!tzp || !tzp->tbp)
> >>> +			continue;
> >>> +
> >>> +		for (i = 0; i < tzp->num_tbps; i++) {
> >>> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> >>> +				continue;
> >>> +			if (tzp->tbp[i].match(pos, cdev))
> >>> +				continue;
> >>> +			tzp->tbp[i].cdev = cdev;
> >>> +			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +}
> >>> +
> >>> +static void bind_tz(struct thermal_zone_device *tz)
> >>> +{
> >>> +	int i, ret;
> >>> +	struct thermal_cooling_device *pos = NULL;
> >>> +	const struct thermal_zone_params *tzp = tz->tzp;
> >>> +
> >>> +	if (!tzp && !tz->ops->bind)
> >>> +		return;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +
> >>> +	/* If there is no platform data, try to use ops->bind */
> >>> +	if (!tzp && tz->ops->bind) {
> >>> +		list_for_each_entry(pos, &thermal_cdev_list, node) {
> >>> +			ret = tz->ops->bind(tz, pos);
> >>> +			if (ret)
> >>> +				print_bind_err_msg(tz, pos, ret);
> >>> +		}
> >>> +		goto exit;
> >>> +	}
> >>> +
> >>> +	if (!tzp || !tzp->tbp)
> >>> +		goto exit;
> >>> +
> >>> +	list_for_each_entry(pos, &thermal_cdev_list, node) {
> >>> +		for (i = 0; i < tzp->num_tbps; i++) {
> >>> +			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> >>> +				continue;
> >>> +			if (tzp->tbp[i].match(tz, pos))
> >>> +				continue;
> >>> +			tzp->tbp[i].cdev = pos;
> >>> +			__bind(tz, tzp->tbp[i].trip_mask, pos);
> >>> +		}
> >>> +	}
> >>> +exit:
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +}
> >>> +
> >>> +static void thermal_zone_device_set_polling(struct
> thermal_zone_device *tz,
> >>> +					    int delay)
> >>> +{
> >>> +	if (delay > 1000)
> >>> +		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> >>> +				 round_jiffies(msecs_to_jiffies(delay)));
> >>> +	else if (delay)
> >>> +		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> >>> +				 msecs_to_jiffies(delay));
> >>> +	else
> >>> +		cancel_delayed_work(&tz->poll_queue);
> >>> +}
> >>> +
> >>> +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);
> >>> +	else if (tz->polling_delay)
> >>> +		thermal_zone_device_set_polling(tz, tz->polling_delay);
> >>> +	else
> >>> +		thermal_zone_device_set_polling(tz, 0);
> >>> +
> >>> +	mutex_unlock(&tz->lock);
> >>> +}
> >>> +
> >>> +static void handle_non_critical_trips(struct thermal_zone_device *tz,
> >>> +			int trip, enum thermal_trip_type trip_type)
> >>> +{
> >>> +	if (tz->governor)
> >>> +		tz->governor->throttle(tz, trip);
> >>> +}
> >>> +
> >>> +static void handle_critical_trips(struct thermal_zone_device *tz,
> >>> +				int trip, enum thermal_trip_type trip_type)
> >>> +{
> >>> +	long trip_temp;
> >>> +
> >>> +	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> >>> +
> >>> +	/* If we have not crossed the trip_temp, we do not care. */
> >>> +	if (tz->temperature < trip_temp)
> >>> +		return;
> >>> +
> >>> +	if (tz->ops->notify)
> >>> +		tz->ops->notify(tz, trip, trip_type);
> >>> +
> >>> +	if (trip_type == THERMAL_TRIP_CRITICAL) {
> >>> +		dev_emerg(&tz->device,
> >>> +			  "critical temperature reached(%d C),shutting
> down\n",
> >>> +			  tz->temperature / 1000);
> >>> +		orderly_poweroff(true);
> >>> +	}
> >>> +}
> >>> +
> >>> +static void handle_thermal_trip(struct thermal_zone_device *tz, int
> trip)
> >>> +{
> >>> +	enum thermal_trip_type type;
> >>> +
> >>> +	tz->ops->get_trip_type(tz, trip, &type);
> >>> +
> >>> +	if (type == THERMAL_TRIP_CRITICAL || type ==
> THERMAL_TRIP_HOT)
> >>> +		handle_critical_trips(tz, trip, type);
> >>> +	else
> >>> +		handle_non_critical_trips(tz, trip, type);
> >>> +	/*
> >>> +	 * Alright, we handled this trip successfully.
> >>> +	 * So, start monitoring again.
> >>> +	 */
> >>> +	monitor_thermal_zone(tz);
> >>> +}
> >>> +
> >>> +static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> >>> +				unsigned long *temp)
> >>> +{
> >>> +	int ret = 0;
> >>> +#ifdef CONFIG_THERMAL_EMULATION
> >>> +	int count;
> >>> +	unsigned long crit_temp = -1UL;
> >>> +	enum thermal_trip_type type;
> >>> +#endif
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +
> >>> +	ret = tz->ops->get_temp(tz, temp);
> >>> +#ifdef CONFIG_THERMAL_EMULATION
> >>> +	if (!tz->emul_temperature)
> >>> +		goto skip_emul;
> >>> +
> >>> +	for (count = 0; count < tz->trips; count++) {
> >>> +		ret = tz->ops->get_trip_type(tz, count, &type);
> >>> +		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> >>> +			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> >>> +			break;
> >>> +		}
> >>> +	}
> >>> +
> >>> +	if (ret)
> >>> +		goto skip_emul;
> >>> +
> >>> +	if (*temp < crit_temp)
> >>> +		*temp = tz->emul_temperature;
> >>> +skip_emul:
> >>> +#endif
> >>> +	mutex_unlock(&tz->lock);
> >>> +	return ret;
> >>> +}
> >>> +
> >>> +static void update_temperature(struct thermal_zone_device *tz)
> >>> +{
> >>> +	long temp;
> >>> +	int ret;
> >>> +
> >>> +	ret = thermal_zone_get_temp(tz, &temp);
> >>> +	if (ret) {
> >>> +		dev_warn(&tz->device, "failed to read out thermal zone
> %d\n",
> >>> +			 tz->id);
> >>> +		return;
> >>> +	}
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +	tz->last_temperature = tz->temperature;
> >>> +	tz->temperature = temp;
> >>> +	mutex_unlock(&tz->lock);
> >>> +}
> >>> +
> >>> +void thermal_zone_device_update(struct thermal_zone_device *tz)
> >>> +{
> >>> +	int count;
> >>> +
> >>> +	update_temperature(tz);
> >>> +
> >>> +	for (count = 0; count < tz->trips; count++)
> >>> +		handle_thermal_trip(tz, count);
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_device_update);
> >>> +
> >>> +static void thermal_zone_device_check(struct work_struct *work)
> >>> +{
> >>> +	struct thermal_zone_device *tz = container_of(work, struct
> >>> +						      thermal_zone_device,
> >>> +						      poll_queue.work);
> >>> +	thermal_zone_device_update(tz);
> >>> +}
> >>> +
> >>> +/* sys I/F for thermal zone */
> >>> +
> >>> +#define to_thermal_zone(_dev) \
> >>> +	container_of(_dev, struct thermal_zone_device, device)
> >>> +
> >>> +static ssize_t
> >>> +type_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +
> >>> +	return sprintf(buf, "%s\n", tz->type);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +temp_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	long temperature;
> >>> +	int ret;
> >>> +
> >>> +	ret = thermal_zone_get_temp(tz, &temperature);
> >>> +
> >>> +	if (ret)
> >>> +		return ret;
> >>> +
> >>> +	return sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +mode_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	enum thermal_device_mode mode;
> >>> +	int result;
> >>> +
> >>> +	if (!tz->ops->get_mode)
> >>> +		return -EPERM;
> >>> +
> >>> +	result = tz->ops->get_mode(tz, &mode);
> >>> +	if (result)
> >>> +		return result;
> >>> +
> >>> +	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ?
> "enabled"
> >>> +		       : "disabled");
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +mode_store(struct device *dev, struct device_attribute *attr,
> >>> +	   const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int result;
> >>> +
> >>> +	if (!tz->ops->set_mode)
> >>> +		return -EPERM;
> >>> +
> >>> +	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);
> >>> +	else
> >>> +		result = -EINVAL;
> >>> +
> >>> +	if (result)
> >>> +		return result;
> >>> +
> >>> +	return count;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_type_show(struct device *dev, struct device_attribute
> *attr,
> >>> +		     char *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	enum thermal_trip_type type;
> >>> +	int trip, result;
> >>> +
> >>> +	if (!tz->ops->get_trip_type)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	result = tz->ops->get_trip_type(tz, trip, &type);
> >>> +	if (result)
> >>> +		return result;
> >>> +
> >>> +	switch (type) {
> >>> +	case THERMAL_TRIP_CRITICAL:
> >>> +		return sprintf(buf, "critical\n");
> >>> +	case THERMAL_TRIP_HOT:
> >>> +		return sprintf(buf, "hot\n");
> >>> +	case THERMAL_TRIP_PASSIVE:
> >>> +		return sprintf(buf, "passive\n");
> >>> +	case THERMAL_TRIP_ACTIVE:
> >>> +		return sprintf(buf, "active\n");
> >>> +	default:
> >>> +		return sprintf(buf, "unknown\n");
> >>> +	}
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_temp_store(struct device *dev, struct device_attribute
> *attr,
> >>> +		     const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int trip, ret;
> >>> +	unsigned long temperature;
> >>> +
> >>> +	if (!tz->ops->set_trip_temp)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	if (kstrtoul(buf, 10, &temperature))
> >>> +		return -EINVAL;
> >>> +
> >>> +	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> >>> +
> >>> +	return ret ? ret : count;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_temp_show(struct device *dev, struct device_attribute
> *attr,
> >>> +		     char *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int trip, ret;
> >>> +	long temperature;
> >>> +
> >>> +	if (!tz->ops->get_trip_temp)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> >>> +
> >>> +	if (ret)
> >>> +		return ret;
> >>> +
> >>> +	return sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_hyst_store(struct device *dev, struct device_attribute
> *attr,
> >>> +			const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int trip, ret;
> >>> +	unsigned long temperature;
> >>> +
> >>> +	if (!tz->ops->set_trip_hyst)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	if (kstrtoul(buf, 10, &temperature))
> >>> +		return -EINVAL;
> >>> +
> >>> +	/*
> >>> +	 * We are not doing any check on the 'temperature' value
> >>> +	 * here. The driver implementing 'set_trip_hyst' has to
> >>> +	 * take care of this.
> >>> +	 */
> >>> +	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> >>> +
> >>> +	return ret ? ret : count;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +trip_point_hyst_show(struct device *dev, struct device_attribute
> *attr,
> >>> +			char *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int trip, ret;
> >>> +	unsigned long temperature;
> >>> +
> >>> +	if (!tz->ops->get_trip_hyst)
> >>> +		return -EPERM;
> >>> +
> >>> +	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> >>> +		return -EINVAL;
> >>> +
> >>> +	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> >>> +
> >>> +	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +passive_store(struct device *dev, struct device_attribute *attr,
> >>> +		    const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	struct thermal_cooling_device *cdev = NULL;
> >>> +	int state;
> >>> +
> >>> +	if (!sscanf(buf, "%d\n", &state))
> >>> +		return -EINVAL;
> >>> +
> >>> +	/* sanity check: values below 1000 millicelcius don't make sense
> >>> +	 * and can cause the system to go into a thermal heart attack
> >>> +	 */
> >>> +	if (state && state < 1000)
> >>> +		return -EINVAL;
> >>> +
> >>> +	if (state && !tz->forced_passive) {
> >>> +		mutex_lock(&thermal_list_lock);
> >>> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> +			if (!strncmp("Processor", cdev->type,
> >>> +				     sizeof("Processor")))
> >>> +				thermal_zone_bind_cooling_device(tz,
> >>> +						THERMAL_TRIPS_NONE,
> cdev,
> >>> +						THERMAL_NO_LIMIT,
> >>> +						THERMAL_NO_LIMIT);
> >>> +		}
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		if (!tz->passive_delay)
> >>> +			tz->passive_delay = 1000;
> >>> +	} else if (!state && tz->forced_passive) {
> >>> +		mutex_lock(&thermal_list_lock);
> >>> +		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> +			if (!strncmp("Processor", cdev->type,
> >>> +				     sizeof("Processor")))
> >>> +				thermal_zone_unbind_cooling_device(tz,
> >>> +
> THERMAL_TRIPS_NONE,
> >>> +								   cdev);
> >>> +		}
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		tz->passive_delay = 0;
> >>> +	}
> >>> +
> >>> +	tz->forced_passive = state;
> >>> +
> >>> +	thermal_zone_device_update(tz);
> >>> +
> >>> +	return count;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +passive_show(struct device *dev, struct device_attribute *attr,
> >>> +		   char *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +
> >>> +	return sprintf(buf, "%d\n", tz->forced_passive);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +policy_store(struct device *dev, struct device_attribute *attr,
> >>> +		    const char *buf, size_t count)
> >>> +{
> >>> +	int ret = -EINVAL;
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	struct thermal_governor *gov;
> >>> +
> >>> +	mutex_lock(&thermal_governor_lock);
> >>> +
> >>> +	gov = __find_governor(buf);
> >>> +	if (!gov)
> >>> +		goto exit;
> >>> +
> >>> +	tz->governor = gov;
> >>> +	ret = count;
> >>> +
> >>> +exit:
> >>> +	mutex_unlock(&thermal_governor_lock);
> >>> +	return ret;
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +policy_show(struct device *dev, struct device_attribute *devattr, char
> *buf)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +
> >>> +	return sprintf(buf, "%s\n", tz->governor->name);
> >>> +}
> >>> +
> >>> +#ifdef CONFIG_THERMAL_EMULATION
> >>> +static ssize_t
> >>> +emul_temp_store(struct device *dev, struct device_attribute *attr,
> >>> +		     const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> +	int ret = 0;
> >>> +	unsigned long temperature;
> >>> +
> >>> +	if (kstrtoul(buf, 10, &temperature))
> >>> +		return -EINVAL;
> >>> +
> >>> +	if (!tz->ops->set_emul_temp) {
> >>> +		mutex_lock(&tz->lock);
> >>> +		tz->emul_temperature = temperature;
> >>> +		mutex_unlock(&tz->lock);
> >>> +	} else {
> >>> +		ret = tz->ops->set_emul_temp(tz, temperature);
> >>> +	}
> >>> +
> >>> +	return ret ? ret : count;
> >>> +}
> >>> +static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> >>> +#endif/*CONFIG_THERMAL_EMULATION*/
> >>> +
> >>> +static DEVICE_ATTR(type, 0444, type_show, NULL);
> >>> +static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> >>> +static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> >>> +static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show,
> passive_store);
> >>> +static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show,
> policy_store);
> >>> +
> >>> +/* sys I/F for cooling device */
> >>> +#define to_cooling_device(_dev)	\
> >>> +	container_of(_dev, struct thermal_cooling_device, device)
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_type_show(struct device *dev,
> >>> +				 struct device_attribute *attr, char *buf)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> +
> >>> +	return sprintf(buf, "%s\n", cdev->type);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_max_state_show(struct device *dev,
> >>> +				      struct device_attribute *attr, char *buf)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> +	unsigned long state;
> >>> +	int ret;
> >>> +
> >>> +	ret = cdev->ops->get_max_state(cdev, &state);
> >>> +	if (ret)
> >>> +		return ret;
> >>> +	return sprintf(buf, "%ld\n", state);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_cur_state_show(struct device *dev,
> >>> +				      struct device_attribute *attr, char *buf)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> +	unsigned long state;
> >>> +	int ret;
> >>> +
> >>> +	ret = cdev->ops->get_cur_state(cdev, &state);
> >>> +	if (ret)
> >>> +		return ret;
> >>> +	return sprintf(buf, "%ld\n", state);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_cur_state_store(struct device *dev,
> >>> +				       struct device_attribute *attr,
> >>> +				       const char *buf, size_t count)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> +	unsigned long state;
> >>> +	int result;
> >>> +
> >>> +	if (!sscanf(buf, "%ld\n", &state))
> >>> +		return -EINVAL;
> >>> +
> >>> +	if ((long)state < 0)
> >>> +		return -EINVAL;
> >>> +
> >>> +	result = cdev->ops->set_cur_state(cdev, state);
> >>> +	if (result)
> >>> +		return result;
> >>> +	return count;
> >>> +}
> >>> +
> >>> +static struct device_attribute dev_attr_cdev_type =
> >>> +__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> >>> +static DEVICE_ATTR(max_state, 0444,
> >>> +		   thermal_cooling_device_max_state_show, NULL);
> >>> +static DEVICE_ATTR(cur_state, 0644,
> >>> +		   thermal_cooling_device_cur_state_show,
> >>> +		   thermal_cooling_device_cur_state_store);
> >>> +
> >>> +static ssize_t
> >>> +thermal_cooling_device_trip_point_show(struct device *dev,
> >>> +				       struct device_attribute *attr, char *buf)
> >>> +{
> >>> +	struct thermal_instance *instance;
> >>> +
> >>> +	instance =
> >>> +	    container_of(attr, struct thermal_instance, attr);
> >>> +
> >>> +	if (instance->trip == THERMAL_TRIPS_NONE)
> >>> +		return sprintf(buf, "-1\n");
> >>> +	else
> >>> +		return sprintf(buf, "%d\n", instance->trip);
> >>> +}
> >>> +
> >>> +/* Device management */
> >>> +
> >>> +#if defined(CONFIG_THERMAL_HWMON)
> >>> +
> >>> +/* hwmon sys I/F */
> >>> +#include <linux/hwmon.h>
> >>> +
> >>> +/* thermal zone devices with the same type share one hwmon device
> */
> >>> +struct thermal_hwmon_device {
> >>> +	char type[THERMAL_NAME_LENGTH];
> >>> +	struct device *device;
> >>> +	int count;
> >>> +	struct list_head tz_list;
> >>> +	struct list_head node;
> >>> +};
> >>> +
> >>> +struct thermal_hwmon_attr {
> >>> +	struct device_attribute attr;
> >>> +	char name[16];
> >>> +};
> >>> +
> >>> +/* one temperature input for each thermal zone */
> >>> +struct thermal_hwmon_temp {
> >>> +	struct list_head hwmon_node;
> >>> +	struct thermal_zone_device *tz;
> >>> +	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> >>> +	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> >>> +};
> >>> +
> >>> +static LIST_HEAD(thermal_hwmon_list);
> >>> +
> >>> +static ssize_t
> >>> +name_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> +{
> >>> +	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> >>> +	return sprintf(buf, "%s\n", hwmon->type);
> >>> +}
> >>> +static DEVICE_ATTR(name, 0444, name_show, NULL);
> >>> +
> >>> +static ssize_t
> >>> +temp_input_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> >>> +{
> >>> +	long temperature;
> >>> +	int ret;
> >>> +	struct thermal_hwmon_attr *hwmon_attr
> >>> +			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> >>> +	struct thermal_hwmon_temp *temp
> >>> +			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> >>> +				       temp_input);
> >>> +	struct thermal_zone_device *tz = temp->tz;
> >>> +
> >>> +	ret = thermal_zone_get_temp(tz, &temperature);
> >>> +
> >>> +	if (ret)
> >>> +		return ret;
> >>> +
> >>> +	return sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +static ssize_t
> >>> +temp_crit_show(struct device *dev, struct device_attribute *attr,
> >>> +		char *buf)
> >>> +{
> >>> +	struct thermal_hwmon_attr *hwmon_attr
> >>> +			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> >>> +	struct thermal_hwmon_temp *temp
> >>> +			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> >>> +				       temp_crit);
> >>> +	struct thermal_zone_device *tz = temp->tz;
> >>> +	long temperature;
> >>> +	int ret;
> >>> +
> >>> +	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> >>> +	if (ret)
> >>> +		return ret;
> >>> +
> >>> +	return sprintf(buf, "%ld\n", temperature);
> >>> +}
> >>> +
> >>> +
> >>> +static struct thermal_hwmon_device *
> >>> +thermal_hwmon_lookup_by_type(const struct thermal_zone_device
> *tz)
> >>> +{
> >>> +	struct thermal_hwmon_device *hwmon;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> >>> +		if (!strcmp(hwmon->type, tz->type)) {
> >>> +			mutex_unlock(&thermal_list_lock);
> >>> +			return hwmon;
> >>> +		}
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	return NULL;
> >>> +}
> >>> +
> >>> +/* Find the temperature input matching a given thermal zone */
> >>> +static struct thermal_hwmon_temp *
> >>> +thermal_hwmon_lookup_temp(const struct thermal_hwmon_device
> *hwmon,
> >>> +			  const struct thermal_zone_device *tz)
> >>> +{
> >>> +	struct thermal_hwmon_temp *temp;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> >>> +		if (temp->tz == tz) {
> >>> +			mutex_unlock(&thermal_list_lock);
> >>> +			return temp;
> >>> +		}
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	return NULL;
> >>> +}
> >>> +
> >>> +static int
> >>> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> +{
> >>> +	struct thermal_hwmon_device *hwmon;
> >>> +	struct thermal_hwmon_temp *temp;
> >>> +	int new_hwmon_device = 1;
> >>> +	int result;
> >>> +
> >>> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> >>> +	if (hwmon) {
> >>> +		new_hwmon_device = 0;
> >>> +		goto register_sys_interface;
> >>> +	}
> >>> +
> >>> +	hwmon = kzalloc(sizeof(struct thermal_hwmon_device),
> GFP_KERNEL);
> >>> +	if (!hwmon)
> >>> +		return -ENOMEM;
> >>> +
> >>> +	INIT_LIST_HEAD(&hwmon->tz_list);
> >>> +	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> >>> +	hwmon->device = hwmon_device_register(NULL);
> >>> +	if (IS_ERR(hwmon->device)) {
> >>> +		result = PTR_ERR(hwmon->device);
> >>> +		goto free_mem;
> >>> +	}
> >>> +	dev_set_drvdata(hwmon->device, hwmon);
> >>> +	result = device_create_file(hwmon->device, &dev_attr_name);
> >>> +	if (result)
> >>> +		goto free_mem;
> >>> +
> >>> + register_sys_interface:
> >>> +	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> >>> +	if (!temp) {
> >>> +		result = -ENOMEM;
> >>> +		goto unregister_name;
> >>> +	}
> >>> +
> >>> +	temp->tz = tz;
> >>> +	hwmon->count++;
> >>> +
> >>> +	snprintf(temp->temp_input.name, sizeof(temp-
> >temp_input.name),
> >>> +		 "temp%d_input", hwmon->count);
> >>> +	temp->temp_input.attr.attr.name = temp->temp_input.name;
> >>> +	temp->temp_input.attr.attr.mode = 0444;
> >>> +	temp->temp_input.attr.show = temp_input_show;
> >>> +	sysfs_attr_init(&temp->temp_input.attr.attr);
> >>> +	result = device_create_file(hwmon->device, &temp-
> >temp_input.attr);
> >>> +	if (result)
> >>> +		goto free_temp_mem;
> >>> +
> >>> +	if (tz->ops->get_crit_temp) {
> >>> +		unsigned long temperature;
> >>> +		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> >>> +			snprintf(temp->temp_crit.name,
> >>> +				 sizeof(temp->temp_crit.name),
> >>> +				"temp%d_crit", hwmon->count);
> >>> +			temp->temp_crit.attr.attr.name = temp-
> >temp_crit.name;
> >>> +			temp->temp_crit.attr.attr.mode = 0444;
> >>> +			temp->temp_crit.attr.show = temp_crit_show;
> >>> +			sysfs_attr_init(&temp->temp_crit.attr.attr);
> >>> +			result = device_create_file(hwmon->device,
> >>> +						    &temp->temp_crit.attr);
> >>> +			if (result)
> >>> +				goto unregister_input;
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	if (new_hwmon_device)
> >>> +		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> >>> +	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	return 0;
> >>> +
> >>> + unregister_input:
> >>> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> >>> + free_temp_mem:
> >>> +	kfree(temp);
> >>> + unregister_name:
> >>> +	if (new_hwmon_device) {
> >>> +		device_remove_file(hwmon->device, &dev_attr_name);
> >>> +		hwmon_device_unregister(hwmon->device);
> >>> +	}
> >>> + free_mem:
> >>> +	if (new_hwmon_device)
> >>> +		kfree(hwmon);
> >>> +
> >>> +	return result;
> >>> +}
> >>> +
> >>> +static void
> >>> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> +{
> >>> +	struct thermal_hwmon_device *hwmon;
> >>> +	struct thermal_hwmon_temp *temp;
> >>> +
> >>> +	hwmon = thermal_hwmon_lookup_by_type(tz);
> >>> +	if (unlikely(!hwmon)) {
> >>> +		/* Should never happen... */
> >>> +		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> >>> +		return;
> >>> +	}
> >>> +
> >>> +	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> >>> +	if (unlikely(!temp)) {
> >>> +		/* Should never happen... */
> >>> +		dev_dbg(&tz->device, "temperature input lookup
> failed!\n");
> >>> +		return;
> >>> +	}
> >>> +
> >>> +	device_remove_file(hwmon->device, &temp->temp_input.attr);
> >>> +	if (tz->ops->get_crit_temp)
> >>> +		device_remove_file(hwmon->device, &temp-
> >temp_crit.attr);
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_del(&temp->hwmon_node);
> >>> +	kfree(temp);
> >>> +	if (!list_empty(&hwmon->tz_list)) {
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		return;
> >>> +	}
> >>> +	list_del(&hwmon->node);
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	device_remove_file(hwmon->device, &dev_attr_name);
> >>> +	hwmon_device_unregister(hwmon->device);
> >>> +	kfree(hwmon);
> >>> +}
> >>> +#else
> >>> +static int
> >>> +thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> +{
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static void
> >>> +thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> +{
> >>> +}
> >>> +#endif
> >>> +
> >>> +/**
> >>> + * thermal_zone_bind_cooling_device - bind a cooling device to a
> thermal zone
> >>> + * @tz:		thermal zone device
> >>> + * @trip:	indicates which trip point the cooling devices is
> >>> + *		associated with in this thermal zone.
> >>> + * @cdev:	thermal cooling device
> >>> + *
> >>> + * This function is usually called in the thermal zone device .bind
> callback.
> >>> + */
> >>> +int thermal_zone_bind_cooling_device(struct thermal_zone_device
> *tz,
> >>> +				     int trip,
> >>> +				     struct thermal_cooling_device *cdev,
> >>> +				     unsigned long upper, unsigned long lower)
> >>> +{
> >>> +	struct thermal_instance *dev;
> >>> +	struct thermal_instance *pos;
> >>> +	struct thermal_zone_device *pos1;
> >>> +	struct thermal_cooling_device *pos2;
> >>> +	unsigned long max_state;
> >>> +	int result;
> >>> +
> >>> +	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> >>> +		return -EINVAL;
> >>> +
> >>> +	list_for_each_entry(pos1, &thermal_tz_list, node) {
> >>> +		if (pos1 == tz)
> >>> +			break;
> >>> +	}
> >>> +	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> >>> +		if (pos2 == cdev)
> >>> +			break;
> >>> +	}
> >>> +
> >>> +	if (tz != pos1 || cdev != pos2)
> >>> +		return -EINVAL;
> >>> +
> >>> +	cdev->ops->get_max_state(cdev, &max_state);
> >>> +
> >>> +	/* lower default 0, upper default max_state */
> >>> +	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> >>> +	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> >>> +
> >>> +	if (lower > upper || upper > max_state)
> >>> +		return -EINVAL;
> >>> +
> >>> +	dev =
> >>> +	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> >>> +	if (!dev)
> >>> +		return -ENOMEM;
> >>> +	dev->tz = tz;
> >>> +	dev->cdev = cdev;
> >>> +	dev->trip = trip;
> >>> +	dev->upper = upper;
> >>> +	dev->lower = lower;
> >>> +	dev->target = THERMAL_NO_TARGET;
> >>> +
> >>> +	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> >>> +	if (result)
> >>> +		goto free_mem;
> >>> +
> >>> +	sprintf(dev->name, "cdev%d", dev->id);
> >>> +	result =
> >>> +	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev-
> >name);
> >>> +	if (result)
> >>> +		goto release_idr;
> >>> +
> >>> +	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> >>> +	sysfs_attr_init(&dev->attr.attr);
> >>> +	dev->attr.attr.name = dev->attr_name;
> >>> +	dev->attr.attr.mode = 0444;
> >>> +	dev->attr.show = thermal_cooling_device_trip_point_show;
> >>> +	result = device_create_file(&tz->device, &dev->attr);
> >>> +	if (result)
> >>> +		goto remove_symbol_link;
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +	mutex_lock(&cdev->lock);
> >>> +	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> >>> +	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> +		result = -EEXIST;
> >>> +		break;
> >>> +	}
> >>> +	if (!result) {
> >>> +		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> >>> +		list_add_tail(&dev->cdev_node, &cdev-
> >thermal_instances);
> >>> +	}
> >>> +	mutex_unlock(&cdev->lock);
> >>> +	mutex_unlock(&tz->lock);
> >>> +
> >>> +	if (!result)
> >>> +		return 0;
> >>> +
> >>> +	device_remove_file(&tz->device, &dev->attr);
> >>> +remove_symbol_link:
> >>> +	sysfs_remove_link(&tz->device.kobj, dev->name);
> >>> +release_idr:
> >>> +	release_idr(&tz->idr, &tz->lock, dev->id);
> >>> +free_mem:
> >>> +	kfree(dev);
> >>> +	return result;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> >>> +
> >>> +/**
> >>> + * thermal_zone_unbind_cooling_device - unbind a cooling device
> from a thermal zone
> >>> + * @tz:		thermal zone device
> >>> + * @trip:	indicates which trip point the cooling devices is
> >>> + *		associated with in this thermal zone.
> >>> + * @cdev:	thermal cooling device
> >>> + *
> >>> + * This function is usually called in the thermal zone device .unbind
> callback.
> >>> + */
> >>> +int thermal_zone_unbind_cooling_device(struct thermal_zone_device
> *tz,
> >>> +				       int trip,
> >>> +				       struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	struct thermal_instance *pos, *next;
> >>> +
> >>> +	mutex_lock(&tz->lock);
> >>> +	mutex_lock(&cdev->lock);
> >>> +	list_for_each_entry_safe(pos, next, &tz->thermal_instances,
> tz_node) {
> >>> +		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> +			list_del(&pos->tz_node);
> >>> +			list_del(&pos->cdev_node);
> >>> +			mutex_unlock(&cdev->lock);
> >>> +			mutex_unlock(&tz->lock);
> >>> +			goto unbind;
> >>> +		}
> >>> +	}
> >>> +	mutex_unlock(&cdev->lock);
> >>> +	mutex_unlock(&tz->lock);
> >>> +
> >>> +	return -ENODEV;
> >>> +
> >>> +unbind:
> >>> +	device_remove_file(&tz->device, &pos->attr);
> >>> +	sysfs_remove_link(&tz->device.kobj, pos->name);
> >>> +	release_idr(&tz->idr, &tz->lock, pos->id);
> >>> +	kfree(pos);
> >>> +	return 0;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> >>> +
> >>> +static void thermal_release(struct device *dev)
> >>> +{
> >>> +	struct thermal_zone_device *tz;
> >>> +	struct thermal_cooling_device *cdev;
> >>> +
> >>> +	if (!strncmp(dev_name(dev), "thermal_zone",
> >>> +		     sizeof("thermal_zone") - 1)) {
> >>> +		tz = to_thermal_zone(dev);
> >>> +		kfree(tz);
> >>> +	} else {
> >>> +		cdev = to_cooling_device(dev);
> >>> +		kfree(cdev);
> >>> +	}
> >>> +}
> >>> +
> >>> +static struct class thermal_class = {
> >>> +	.name = "thermal",
> >>> +	.dev_release = thermal_release,
> >>> +};
> >>> +
> >>> +/**
> >>> + * thermal_cooling_device_register - register a new thermal cooling
> device
> >>> + * @type:	the thermal cooling device type.
> >>> + * @devdata:	device private data.
> >>> + * @ops:		standard thermal cooling devices callbacks.
> >>> + */
> >>> +struct thermal_cooling_device *
> >>> +thermal_cooling_device_register(char *type, void *devdata,
> >>> +				const struct thermal_cooling_device_ops
> *ops)
> >>> +{
> >>> +	struct thermal_cooling_device *cdev;
> >>> +	int result;
> >>> +
> >>> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> >>> +	    !ops->set_cur_state)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> >>> +	if (!cdev)
> >>> +		return ERR_PTR(-ENOMEM);
> >>> +
> >>> +	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> >>> +	if (result) {
> >>> +		kfree(cdev);
> >>> +		return ERR_PTR(result);
> >>> +	}
> >>> +
> >>> +	strcpy(cdev->type, type ? : "");
> >>> +	mutex_init(&cdev->lock);
> >>> +	INIT_LIST_HEAD(&cdev->thermal_instances);
> >>> +	cdev->ops = ops;
> >>> +	cdev->updated = true;
> >>> +	cdev->device.class = &thermal_class;
> >>> +	cdev->devdata = devdata;
> >>> +	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> >>> +	result = device_register(&cdev->device);
> >>> +	if (result) {
> >>> +		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev-
> >id);
> >>> +		kfree(cdev);
> >>> +		return ERR_PTR(result);
> >>> +	}
> >>> +
> >>> +	/* sys I/F */
> >>> +	if (type) {
> >>> +		result = device_create_file(&cdev->device,
> &dev_attr_cdev_type);
> >>> +		if (result)
> >>> +			goto unregister;
> >>> +	}
> >>> +
> >>> +	result = device_create_file(&cdev->device, &dev_attr_max_state);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	/* Add 'this' new cdev to the global cdev list */
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_add(&cdev->node, &thermal_cdev_list);
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	/* Update binding information for 'this' new cdev */
> >>> +	bind_cdev(cdev);
> >>> +
> >>> +	return cdev;
> >>> +
> >>> +unregister:
> >>> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> >>> +	device_unregister(&cdev->device);
> >>> +	return ERR_PTR(result);
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_cooling_device_register);
> >>> +
> >>> +/**
> >>> + * thermal_cooling_device_unregister - removes the registered
> thermal cooling device
> >>> + * @cdev:	the thermal cooling device to remove.
> >>> + *
> >>> + * thermal_cooling_device_unregister() must be called when the
> device is no
> >>> + * longer needed.
> >>> + */
> >>> +void thermal_cooling_device_unregister(struct
> thermal_cooling_device *cdev)
> >>> +{
> >>> +	int i;
> >>> +	const struct thermal_zone_params *tzp;
> >>> +	struct thermal_zone_device *tz;
> >>> +	struct thermal_cooling_device *pos = NULL;
> >>> +
> >>> +	if (!cdev)
> >>> +		return;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_for_each_entry(pos, &thermal_cdev_list, node)
> >>> +	    if (pos == cdev)
> >>> +		break;
> >>> +	if (pos != cdev) {
> >>> +		/* thermal cooling device not found */
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		return;
> >>> +	}
> >>> +	list_del(&cdev->node);
> >>> +
> >>> +	/* Unbind all thermal zones associated with 'this' cdev */
> >>> +	list_for_each_entry(tz, &thermal_tz_list, node) {
> >>> +		if (tz->ops->unbind) {
> >>> +			tz->ops->unbind(tz, cdev);
> >>> +			continue;
> >>> +		}
> >>> +
> >>> +		if (!tz->tzp || !tz->tzp->tbp)
> >>> +			continue;
> >>> +
> >>> +		tzp = tz->tzp;
> >>> +		for (i = 0; i < tzp->num_tbps; i++) {
> >>> +			if (tzp->tbp[i].cdev == cdev) {
> >>> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> >>> +				tzp->tbp[i].cdev = NULL;
> >>> +			}
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	if (cdev->type[0])
> >>> +		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> >>> +	device_remove_file(&cdev->device, &dev_attr_max_state);
> >>> +	device_remove_file(&cdev->device, &dev_attr_cur_state);
> >>> +
> >>> +	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> >>> +	device_unregister(&cdev->device);
> >>> +	return;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_cooling_device_unregister);
> >>> +
> >>> +void thermal_cdev_update(struct thermal_cooling_device *cdev)
> >>> +{
> >>> +	struct thermal_instance *instance;
> >>> +	unsigned long target = 0;
> >>> +
> >>> +	/* cooling device is updated*/
> >>> +	if (cdev->updated)
> >>> +		return;
> >>> +
> >>> +	mutex_lock(&cdev->lock);
> >>> +	/* Make sure cdev enters the deepest cooling state */
> >>> +	list_for_each_entry(instance, &cdev->thermal_instances,
> cdev_node) {
> >>> +		if (instance->target == THERMAL_NO_TARGET)
> >>> +			continue;
> >>> +		if (instance->target > target)
> >>> +			target = instance->target;
> >>> +	}
> >>> +	mutex_unlock(&cdev->lock);
> >>> +	cdev->ops->set_cur_state(cdev, target);
> >>> +	cdev->updated = true;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_cdev_update);
> >>> +
> >>> +/**
> >>> + * notify_thermal_framework - Sensor drivers use this API to notify
> framework
> >>> + * @tz:		thermal zone device
> >>> + * @trip:	indicates which trip point has been crossed
> >>> + *
> >>> + * This function handles the trip events from sensor drivers. It starts
> >>> + * throttling the cooling devices according to the policy configured.
> >>> + * For CRITICAL and HOT trip points, this notifies the respective drivers,
> >>> + * and does actual throttling for other trip points i.e ACTIVE and
> PASSIVE.
> >>> + * The throttling policy is based on the configured platform data; if no
> >>> + * platform data is provided, this uses the step_wise throttling policy.
> >>> + */
> >>> +void notify_thermal_framework(struct thermal_zone_device *tz, int
> trip)
> >>> +{
> >>> +	handle_thermal_trip(tz, trip);
> >>> +}
> >>> +EXPORT_SYMBOL(notify_thermal_framework);
> >>> +
> >>> +/**
> >>> + * create_trip_attrs - create attributes for trip points
> >>> + * @tz:		the thermal zone device
> >>> + * @mask:	Writeable trip point bitmap.
> >>> + */
> >>> +static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> >>> +{
> >>> +	int indx;
> >>> +	int size = sizeof(struct thermal_attr) * tz->trips;
> >>> +
> >>> +	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> >>> +	if (!tz->trip_type_attrs)
> >>> +		return -ENOMEM;
> >>> +
> >>> +	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> >>> +	if (!tz->trip_temp_attrs) {
> >>> +		kfree(tz->trip_type_attrs);
> >>> +		return -ENOMEM;
> >>> +	}
> >>> +
> >>> +	if (tz->ops->get_trip_hyst) {
> >>> +		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> >>> +		if (!tz->trip_hyst_attrs) {
> >>> +			kfree(tz->trip_type_attrs);
> >>> +			kfree(tz->trip_temp_attrs);
> >>> +			return -ENOMEM;
> >>> +		}
> >>> +	}
> >>> +
> >>> +
> >>> +	for (indx = 0; indx < tz->trips; indx++) {
> >>> +		/* create trip type attribute */
> >>> +		snprintf(tz->trip_type_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> +			 "trip_point_%d_type", indx);
> >>> +
> >>> +		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> >>> +		tz->trip_type_attrs[indx].attr.attr.name =
> >>> +						tz-
> >trip_type_attrs[indx].name;
> >>> +		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> +		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> >>> +
> >>> +		device_create_file(&tz->device,
> >>> +				   &tz->trip_type_attrs[indx].attr);
> >>> +
> >>> +		/* create trip temp attribute */
> >>> +		snprintf(tz->trip_temp_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> +			 "trip_point_%d_temp", indx);
> >>> +
> >>> +		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> >>> +		tz->trip_temp_attrs[indx].attr.attr.name =
> >>> +						tz-
> >trip_temp_attrs[indx].name;
> >>> +		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> +		tz->trip_temp_attrs[indx].attr.show =
> trip_point_temp_show;
> >>> +		if (mask & (1 << indx)) {
> >>> +			tz->trip_temp_attrs[indx].attr.attr.mode |=
> S_IWUSR;
> >>> +			tz->trip_temp_attrs[indx].attr.store =
> >>> +
> 	trip_point_temp_store;
> >>> +		}
> >>> +
> >>> +		device_create_file(&tz->device,
> >>> +				   &tz->trip_temp_attrs[indx].attr);
> >>> +
> >>> +		/* create Optional trip hyst attribute */
> >>> +		if (!tz->ops->get_trip_hyst)
> >>> +			continue;
> >>> +		snprintf(tz->trip_hyst_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> +			 "trip_point_%d_hyst", indx);
> >>> +
> >>> +		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> >>> +		tz->trip_hyst_attrs[indx].attr.attr.name =
> >>> +					tz->trip_hyst_attrs[indx].name;
> >>> +		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> +		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> >>> +		if (tz->ops->set_trip_hyst) {
> >>> +			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> >>> +			tz->trip_hyst_attrs[indx].attr.store =
> >>> +					trip_point_hyst_store;
> >>> +		}
> >>> +
> >>> +		device_create_file(&tz->device,
> >>> +				   &tz->trip_hyst_attrs[indx].attr);
> >>> +	}
> >>> +	return 0;
> >>> +}
> >>> +
> >>> +static void remove_trip_attrs(struct thermal_zone_device *tz)
> >>> +{
> >>> +	int indx;
> >>> +
> >>> +	for (indx = 0; indx < tz->trips; indx++) {
> >>> +		device_remove_file(&tz->device,
> >>> +				   &tz->trip_type_attrs[indx].attr);
> >>> +		device_remove_file(&tz->device,
> >>> +				   &tz->trip_temp_attrs[indx].attr);
> >>> +		if (tz->ops->get_trip_hyst)
> >>> +			device_remove_file(&tz->device,
> >>> +				  &tz->trip_hyst_attrs[indx].attr);
> >>> +	}
> >>> +	kfree(tz->trip_type_attrs);
> >>> +	kfree(tz->trip_temp_attrs);
> >>> +	kfree(tz->trip_hyst_attrs);
> >>> +}
> >>> +
> >>> +/**
> >>> + * thermal_zone_device_register - register a new thermal zone device
> >>> + * @type:	the thermal zone device type
> >>> + * @trips:	the number of trip points the thermal zone support
> >>> + * @mask:	a bit string indicating the writeablility of trip points
> >>> + * @devdata:	private device data
> >>> + * @ops:	standard thermal zone device callbacks
> >>> + * @tzp:	thermal zone platform parameters
> >>> + * @passive_delay: number of milliseconds to wait between polls when
> >>> + *		   performing passive cooling
> >>> + * @polling_delay: number of milliseconds to wait between polls when
> checking
> >>> + *		   whether trip points have been crossed (0 for interrupt
> >>> + *		   driven systems)
> >>> + *
> >>> + * thermal_zone_device_unregister() must be called when the device
> is no
> >>> + * longer needed. The passive cooling depends on the .get_trend()
> return value.
> >>> + */
> >>> +struct thermal_zone_device *thermal_zone_device_register(const
> char *type,
> >>> +	int trips, int mask, void *devdata,
> >>> +	const struct thermal_zone_device_ops *ops,
> >>> +	const struct thermal_zone_params *tzp,
> >>> +	int passive_delay, int polling_delay)
> >>> +{
> >>> +	struct thermal_zone_device *tz;
> >>> +	enum thermal_trip_type trip_type;
> >>> +	int result;
> >>> +	int count;
> >>> +	int passive = 0;
> >>> +
> >>> +	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	if (!ops || !ops->get_temp)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	if (trips > 0 && !ops->get_trip_type)
> >>> +		return ERR_PTR(-EINVAL);
> >>> +
> >>> +	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> >>> +	if (!tz)
> >>> +		return ERR_PTR(-ENOMEM);
> >>> +
> >>> +	INIT_LIST_HEAD(&tz->thermal_instances);
> >>> +	idr_init(&tz->idr);
> >>> +	mutex_init(&tz->lock);
> >>> +	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> >>> +	if (result) {
> >>> +		kfree(tz);
> >>> +		return ERR_PTR(result);
> >>> +	}
> >>> +
> >>> +	strcpy(tz->type, type ? : "");
> >>> +	tz->ops = ops;
> >>> +	tz->tzp = tzp;
> >>> +	tz->device.class = &thermal_class;
> >>> +	tz->devdata = devdata;
> >>> +	tz->trips = trips;
> >>> +	tz->passive_delay = passive_delay;
> >>> +	tz->polling_delay = polling_delay;
> >>> +
> >>> +	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> >>> +	result = device_register(&tz->device);
> >>> +	if (result) {
> >>> +		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> +		kfree(tz);
> >>> +		return ERR_PTR(result);
> >>> +	}
> >>> +
> >>> +	/* sys I/F */
> >>> +	if (type) {
> >>> +		result = device_create_file(&tz->device, &dev_attr_type);
> >>> +		if (result)
> >>> +			goto unregister;
> >>> +	}
> >>> +
> >>> +	result = device_create_file(&tz->device, &dev_attr_temp);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	if (ops->get_mode) {
> >>> +		result = device_create_file(&tz->device, &dev_attr_mode);
> >>> +		if (result)
> >>> +			goto unregister;
> >>> +	}
> >>> +
> >>> +	result = create_trip_attrs(tz, mask);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	for (count = 0; count < trips; count++) {
> >>> +		tz->ops->get_trip_type(tz, count, &trip_type);
> >>> +		if (trip_type == THERMAL_TRIP_PASSIVE)
> >>> +			passive = 1;
> >>> +	}
> >>> +
> >>> +	if (!passive) {
> >>> +		result = device_create_file(&tz->device, &dev_attr_passive);
> >>> +		if (result)
> >>> +			goto unregister;
> >>> +	}
> >>> +
> >>> +#ifdef CONFIG_THERMAL_EMULATION
> >>> +	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +#endif
> >>> +	/* Create policy attribute */
> >>> +	result = device_create_file(&tz->device, &dev_attr_policy);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	/* Update 'this' zone's governor information */
> >>> +	mutex_lock(&thermal_governor_lock);
> >>> +
> >>> +	if (tz->tzp)
> >>> +		tz->governor = __find_governor(tz->tzp->governor_name);
> >>> +	else
> >>> +		tz->governor =
> __find_governor(DEFAULT_THERMAL_GOVERNOR);
> >>> +
> >>> +	mutex_unlock(&thermal_governor_lock);
> >>> +
> >>> +	result = thermal_add_hwmon_sysfs(tz);
> >>> +	if (result)
> >>> +		goto unregister;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_add_tail(&tz->node, &thermal_tz_list);
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	/* Bind cooling devices for this zone */
> >>> +	bind_tz(tz);
> >>> +
> >>> +	INIT_DELAYED_WORK(&(tz->poll_queue),
> thermal_zone_device_check);
> >>> +
> >>> +	thermal_zone_device_update(tz);
> >>> +
> >>> +	if (!result)
> >>> +		return tz;
> >>> +
> >>> +unregister:
> >>> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> +	device_unregister(&tz->device);
> >>> +	return ERR_PTR(result);
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_device_register);
> >>> +
> >>> +/**
> >>> + * thermal_device_unregister - removes the registered thermal zone
> device
> >>> + * @tz: the thermal zone device to remove
> >>> + */
> >>> +void thermal_zone_device_unregister(struct thermal_zone_device
> *tz)
> >>> +{
> >>> +	int i;
> >>> +	const struct thermal_zone_params *tzp;
> >>> +	struct thermal_cooling_device *cdev;
> >>> +	struct thermal_zone_device *pos = NULL;
> >>> +
> >>> +	if (!tz)
> >>> +		return;
> >>> +
> >>> +	tzp = tz->tzp;
> >>> +
> >>> +	mutex_lock(&thermal_list_lock);
> >>> +	list_for_each_entry(pos, &thermal_tz_list, node)
> >>> +	    if (pos == tz)
> >>> +		break;
> >>> +	if (pos != tz) {
> >>> +		/* thermal zone device not found */
> >>> +		mutex_unlock(&thermal_list_lock);
> >>> +		return;
> >>> +	}
> >>> +	list_del(&tz->node);
> >>> +
> >>> +	/* Unbind all cdevs associated with 'this' thermal zone */
> >>> +	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> +		if (tz->ops->unbind) {
> >>> +			tz->ops->unbind(tz, cdev);
> >>> +			continue;
> >>> +		}
> >>> +
> >>> +		if (!tzp || !tzp->tbp)
> >>> +			break;
> >>> +
> >>> +		for (i = 0; i < tzp->num_tbps; i++) {
> >>> +			if (tzp->tbp[i].cdev == cdev) {
> >>> +				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> >>> +				tzp->tbp[i].cdev = NULL;
> >>> +			}
> >>> +		}
> >>> +	}
> >>> +
> >>> +	mutex_unlock(&thermal_list_lock);
> >>> +
> >>> +	thermal_zone_device_set_polling(tz, 0);
> >>> +
> >>> +	if (tz->type[0])
> >>> +		device_remove_file(&tz->device, &dev_attr_type);
> >>> +	device_remove_file(&tz->device, &dev_attr_temp);
> >>> +	if (tz->ops->get_mode)
> >>> +		device_remove_file(&tz->device, &dev_attr_mode);
> >>> +	device_remove_file(&tz->device, &dev_attr_policy);
> >>> +	remove_trip_attrs(tz);
> >>> +	tz->governor = NULL;
> >>> +
> >>> +	thermal_remove_hwmon_sysfs(tz);
> >>> +	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> +	idr_destroy(&tz->idr);
> >>> +	mutex_destroy(&tz->lock);
> >>> +	device_unregister(&tz->device);
> >>> +	return;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_zone_device_unregister);
> >>> +
> >>> +#ifdef CONFIG_NET
> >>> +static struct genl_family thermal_event_genl_family = {
> >>> +	.id = GENL_ID_GENERATE,
> >>> +	.name = THERMAL_GENL_FAMILY_NAME,
> >>> +	.version = THERMAL_GENL_VERSION,
> >>> +	.maxattr = THERMAL_GENL_ATTR_MAX,
> >>> +};
> >>> +
> >>> +static struct genl_multicast_group thermal_event_mcgrp = {
> >>> +	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> >>> +};
> >>> +
> >>> +int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> >>> +					enum events event)
> >>> +{
> >>> +	struct sk_buff *skb;
> >>> +	struct nlattr *attr;
> >>> +	struct thermal_genl_event *thermal_event;
> >>> +	void *msg_header;
> >>> +	int size;
> >>> +	int result;
> >>> +	static unsigned int thermal_event_seqnum;
> >>> +
> >>> +	if (!tz)
> >>> +		return -EINVAL;
> >>> +
> >>> +	/* allocate memory */
> >>> +	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> >>> +	       nla_total_size(0);
> >>> +
> >>> +	skb = genlmsg_new(size, GFP_ATOMIC);
> >>> +	if (!skb)
> >>> +		return -ENOMEM;
> >>> +
> >>> +	/* add the genetlink message header */
> >>> +	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> >>> +				 &thermal_event_genl_family, 0,
> >>> +				 THERMAL_GENL_CMD_EVENT);
> >>> +	if (!msg_header) {
> >>> +		nlmsg_free(skb);
> >>> +		return -ENOMEM;
> >>> +	}
> >>> +
> >>> +	/* fill the data */
> >>> +	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> >>> +			   sizeof(struct thermal_genl_event));
> >>> +
> >>> +	if (!attr) {
> >>> +		nlmsg_free(skb);
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>> +	thermal_event = nla_data(attr);
> >>> +	if (!thermal_event) {
> >>> +		nlmsg_free(skb);
> >>> +		return -EINVAL;
> >>> +	}
> >>> +
> >>> +	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> >>> +
> >>> +	thermal_event->orig = tz->id;
> >>> +	thermal_event->event = event;
> >>> +
> >>> +	/* send multicast genetlink message */
> >>> +	result = genlmsg_end(skb, msg_header);
> >>> +	if (result < 0) {
> >>> +		nlmsg_free(skb);
> >>> +		return result;
> >>> +	}
> >>> +
> >>> +	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id,
> GFP_ATOMIC);
> >>> +	if (result)
> >>> +		dev_err(&tz->device, "Failed to send netlink event:%d",
> result);
> >>> +
> >>> +	return result;
> >>> +}
> >>> +EXPORT_SYMBOL(thermal_generate_netlink_event);
> >>> +
> >>> +static int genetlink_init(void)
> >>> +{
> >>> +	int result;
> >>> +
> >>> +	result = genl_register_family(&thermal_event_genl_family);
> >>> +	if (result)
> >>> +		return result;
> >>> +
> >>> +	result = genl_register_mc_group(&thermal_event_genl_family,
> >>> +					&thermal_event_mcgrp);
> >>> +	if (result)
> >>> +		genl_unregister_family(&thermal_event_genl_family);
> >>> +	return result;
> >>> +}
> >>> +
> >>> +static void genetlink_exit(void)
> >>> +{
> >>> +	genl_unregister_family(&thermal_event_genl_family);
> >>> +}
> >>> +#else /* !CONFIG_NET */
> >>> +static inline int genetlink_init(void) { return 0; }
> >>> +static inline void genetlink_exit(void) {}
> >>> +#endif /* !CONFIG_NET */
> >>> +
> >>> +static int __init thermal_init(void)
> >>> +{
> >>> +	int result = 0;
> >>> +
> >>> +	result = class_register(&thermal_class);
> >>> +	if (result) {
> >>> +		idr_destroy(&thermal_tz_idr);
> >>> +		idr_destroy(&thermal_cdev_idr);
> >>> +		mutex_destroy(&thermal_idr_lock);
> >>> +		mutex_destroy(&thermal_list_lock);
> >>> +		return result;
> >>> +	}
> >>> +	result = genetlink_init();
> >>> +	return result;
> >>> +}
> >>> +
> >>> +static void __exit thermal_exit(void)
> >>> +{
> >>> +	class_unregister(&thermal_class);
> >>> +	idr_destroy(&thermal_tz_idr);
> >>> +	idr_destroy(&thermal_cdev_idr);
> >>> +	mutex_destroy(&thermal_idr_lock);
> >>> +	mutex_destroy(&thermal_list_lock);
> >>> +	genetlink_exit();
> >>> +}
> >>> +
> >>> +fs_initcall(thermal_init);
> >>> +module_exit(thermal_exit);
> >>> diff --git a/drivers/thermal/thermal_sys.c
> b/drivers/thermal/thermal_sys.c
> >>> deleted file mode 100644
> >>> index 5b7863a..0000000
> >>> --- a/drivers/thermal/thermal_sys.c
> >>> +++ /dev/null
> >>> @@ -1,1888 +0,0 @@
> >>> -/*
> >>> - *  thermal.c - Generic Thermal Management Sysfs support.
> >>> - *
> >>> - *  Copyright (C) 2008 Intel Corp
> >>> - *  Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
> >>> - *  Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
> >>> - *
> >>> - *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> >>> - *
> >>> - *  This program is free software; you can redistribute it and/or modify
> >>> - *  it under the terms of the GNU General Public License as published by
> >>> - *  the Free Software Foundation; version 2 of the License.
> >>> - *
> >>> - *  This program is distributed in the hope that it will be useful, but
> >>> - *  WITHOUT ANY WARRANTY; without even the implied warranty of
> >>> - *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
> the GNU
> >>> - *  General Public License for more details.
> >>> - *
> >>> - *  You should have received a copy of the GNU General Public License
> along
> >>> - *  with this program; if not, write to the Free Software Foundation, Inc.,
> >>> - *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
> >>> - *
> >>> - *
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> ~~~~~~~~~~~~~~~~
> >>> - */
> >>> -
> >>> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
> >>> -
> >>> -#include <linux/module.h>
> >>> -#include <linux/device.h>
> >>> -#include <linux/err.h>
> >>> -#include <linux/slab.h>
> >>> -#include <linux/kdev_t.h>
> >>> -#include <linux/idr.h>
> >>> -#include <linux/thermal.h>
> >>> -#include <linux/reboot.h>
> >>> -#include <net/netlink.h>
> >>> -#include <net/genetlink.h>
> >>> -
> >>> -#include "thermal_core.h"
> >>> -
> >>> -MODULE_AUTHOR("Zhang Rui");
> >>> -MODULE_DESCRIPTION("Generic thermal management sysfs
> support");
> >>> -MODULE_LICENSE("GPL");
> >>> -
> >>> -static DEFINE_IDR(thermal_tz_idr);
> >>> -static DEFINE_IDR(thermal_cdev_idr);
> >>> -static DEFINE_MUTEX(thermal_idr_lock);
> >>> -
> >>> -static LIST_HEAD(thermal_tz_list);
> >>> -static LIST_HEAD(thermal_cdev_list);
> >>> -static LIST_HEAD(thermal_governor_list);
> >>> -
> >>> -static DEFINE_MUTEX(thermal_list_lock);
> >>> -static DEFINE_MUTEX(thermal_governor_lock);
> >>> -
> >>> -static struct thermal_governor *__find_governor(const char *name)
> >>> -{
> >>> -	struct thermal_governor *pos;
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_governor_list, governor_list)
> >>> -		if (!strnicmp(name, pos->name, THERMAL_NAME_LENGTH))
> >>> -			return pos;
> >>> -
> >>> -	return NULL;
> >>> -}
> >>> -
> >>> -int thermal_register_governor(struct thermal_governor *governor)
> >>> -{
> >>> -	int err;
> >>> -	const char *name;
> >>> -	struct thermal_zone_device *pos;
> >>> -
> >>> -	if (!governor)
> >>> -		return -EINVAL;
> >>> -
> >>> -	mutex_lock(&thermal_governor_lock);
> >>> -
> >>> -	err = -EBUSY;
> >>> -	if (__find_governor(governor->name) == NULL) {
> >>> -		err = 0;
> >>> -		list_add(&governor->governor_list,
> &thermal_governor_list);
> >>> -	}
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> -		if (pos->governor)
> >>> -			continue;
> >>> -		if (pos->tzp)
> >>> -			name = pos->tzp->governor_name;
> >>> -		else
> >>> -			name = DEFAULT_THERMAL_GOVERNOR;
> >>> -		if (!strnicmp(name, governor->name,
> THERMAL_NAME_LENGTH))
> >>> -			pos->governor = governor;
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -	mutex_unlock(&thermal_governor_lock);
> >>> -
> >>> -	return err;
> >>> -}
> >>> -EXPORT_SYMBOL_GPL(thermal_register_governor);
> >>> -
> >>> -void thermal_unregister_governor(struct thermal_governor
> *governor)
> >>> -{
> >>> -	struct thermal_zone_device *pos;
> >>> -
> >>> -	if (!governor)
> >>> -		return;
> >>> -
> >>> -	mutex_lock(&thermal_governor_lock);
> >>> -
> >>> -	if (__find_governor(governor->name) == NULL)
> >>> -		goto exit;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> -		if (!strnicmp(pos->governor->name, governor->name,
> >>> -						THERMAL_NAME_LENGTH))
> >>> -			pos->governor = NULL;
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -	list_del(&governor->governor_list);
> >>> -exit:
> >>> -	mutex_unlock(&thermal_governor_lock);
> >>> -	return;
> >>> -}
> >>> -EXPORT_SYMBOL_GPL(thermal_unregister_governor);
> >>> -
> >>> -static int get_idr(struct idr *idr, struct mutex *lock, int *id)
> >>> -{
> >>> -	int ret;
> >>> -
> >>> -	if (lock)
> >>> -		mutex_lock(lock);
> >>> -	ret = idr_alloc(idr, NULL, 0, 0, GFP_KERNEL);
> >>> -	if (lock)
> >>> -		mutex_unlock(lock);
> >>> -	if (unlikely(ret < 0))
> >>> -		return ret;
> >>> -	*id = ret;
> >>> -	return 0;
> >>> -}
> >>> -
> >>> -static void release_idr(struct idr *idr, struct mutex *lock, int id)
> >>> -{
> >>> -	if (lock)
> >>> -		mutex_lock(lock);
> >>> -	idr_remove(idr, id);
> >>> -	if (lock)
> >>> -		mutex_unlock(lock);
> >>> -}
> >>> -
> >>> -int get_tz_trend(struct thermal_zone_device *tz, int trip)
> >>> -{
> >>> -	enum thermal_trend trend;
> >>> -
> >>> -	if (!tz->ops->get_trend || tz->ops->get_trend(tz, trip, &trend)) {
> >>> -		if (tz->temperature > tz->last_temperature)
> >>> -			trend = THERMAL_TREND_RAISING;
> >>> -		else if (tz->temperature < tz->last_temperature)
> >>> -			trend = THERMAL_TREND_DROPPING;
> >>> -		else
> >>> -			trend = THERMAL_TREND_STABLE;
> >>> -	}
> >>> -
> >>> -	return trend;
> >>> -}
> >>> -EXPORT_SYMBOL(get_tz_trend);
> >>> -
> >>> -struct thermal_instance *get_thermal_instance(struct
> thermal_zone_device *tz,
> >>> -			struct thermal_cooling_device *cdev, int trip)
> >>> -{
> >>> -	struct thermal_instance *pos = NULL;
> >>> -	struct thermal_instance *target_instance = NULL;
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -	mutex_lock(&cdev->lock);
> >>> -
> >>> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
> >>> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> -			target_instance = pos;
> >>> -			break;
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&cdev->lock);
> >>> -	mutex_unlock(&tz->lock);
> >>> -
> >>> -	return target_instance;
> >>> -}
> >>> -EXPORT_SYMBOL(get_thermal_instance);
> >>> -
> >>> -static void print_bind_err_msg(struct thermal_zone_device *tz,
> >>> -			struct thermal_cooling_device *cdev, int ret)
> >>> -{
> >>> -	dev_err(&tz->device, "binding zone %s with cdev %s failed:%d\n",
> >>> -				tz->type, cdev->type, ret);
> >>> -}
> >>> -
> >>> -static void __bind(struct thermal_zone_device *tz, int mask,
> >>> -			struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	int i, ret;
> >>> -
> >>> -	for (i = 0; i < tz->trips; i++) {
> >>> -		if (mask & (1 << i)) {
> >>> -			ret = thermal_zone_bind_cooling_device(tz, i, cdev,
> >>> -					THERMAL_NO_LIMIT,
> THERMAL_NO_LIMIT);
> >>> -			if (ret)
> >>> -				print_bind_err_msg(tz, cdev, ret);
> >>> -		}
> >>> -	}
> >>> -}
> >>> -
> >>> -static void __unbind(struct thermal_zone_device *tz, int mask,
> >>> -			struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	int i;
> >>> -
> >>> -	for (i = 0; i < tz->trips; i++)
> >>> -		if (mask & (1 << i))
> >>> -			thermal_zone_unbind_cooling_device(tz, i, cdev);
> >>> -}
> >>> -
> >>> -static void bind_cdev(struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	int i, ret;
> >>> -	const struct thermal_zone_params *tzp;
> >>> -	struct thermal_zone_device *pos = NULL;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_tz_list, node) {
> >>> -		if (!pos->tzp && !pos->ops->bind)
> >>> -			continue;
> >>> -
> >>> -		if (!pos->tzp && pos->ops->bind) {
> >>> -			ret = pos->ops->bind(pos, cdev);
> >>> -			if (ret)
> >>> -				print_bind_err_msg(pos, cdev, ret);
> >>> -		}
> >>> -
> >>> -		tzp = pos->tzp;
> >>> -		if (!tzp || !tzp->tbp)
> >>> -			continue;
> >>> -
> >>> -		for (i = 0; i < tzp->num_tbps; i++) {
> >>> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> >>> -				continue;
> >>> -			if (tzp->tbp[i].match(pos, cdev))
> >>> -				continue;
> >>> -			tzp->tbp[i].cdev = cdev;
> >>> -			__bind(pos, tzp->tbp[i].trip_mask, cdev);
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -}
> >>> -
> >>> -static void bind_tz(struct thermal_zone_device *tz)
> >>> -{
> >>> -	int i, ret;
> >>> -	struct thermal_cooling_device *pos = NULL;
> >>> -	const struct thermal_zone_params *tzp = tz->tzp;
> >>> -
> >>> -	if (!tzp && !tz->ops->bind)
> >>> -		return;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -
> >>> -	/* If there is no platform data, try to use ops->bind */
> >>> -	if (!tzp && tz->ops->bind) {
> >>> -		list_for_each_entry(pos, &thermal_cdev_list, node) {
> >>> -			ret = tz->ops->bind(tz, pos);
> >>> -			if (ret)
> >>> -				print_bind_err_msg(tz, pos, ret);
> >>> -		}
> >>> -		goto exit;
> >>> -	}
> >>> -
> >>> -	if (!tzp || !tzp->tbp)
> >>> -		goto exit;
> >>> -
> >>> -	list_for_each_entry(pos, &thermal_cdev_list, node) {
> >>> -		for (i = 0; i < tzp->num_tbps; i++) {
> >>> -			if (tzp->tbp[i].cdev || !tzp->tbp[i].match)
> >>> -				continue;
> >>> -			if (tzp->tbp[i].match(tz, pos))
> >>> -				continue;
> >>> -			tzp->tbp[i].cdev = pos;
> >>> -			__bind(tz, tzp->tbp[i].trip_mask, pos);
> >>> -		}
> >>> -	}
> >>> -exit:
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -}
> >>> -
> >>> -static void thermal_zone_device_set_polling(struct
> thermal_zone_device *tz,
> >>> -					    int delay)
> >>> -{
> >>> -	if (delay > 1000)
> >>> -		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> >>> -				 round_jiffies(msecs_to_jiffies(delay)));
> >>> -	else if (delay)
> >>> -		mod_delayed_work(system_freezable_wq, &tz-
> >poll_queue,
> >>> -				 msecs_to_jiffies(delay));
> >>> -	else
> >>> -		cancel_delayed_work(&tz->poll_queue);
> >>> -}
> >>> -
> >>> -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);
> >>> -	else if (tz->polling_delay)
> >>> -		thermal_zone_device_set_polling(tz, tz->polling_delay);
> >>> -	else
> >>> -		thermal_zone_device_set_polling(tz, 0);
> >>> -
> >>> -	mutex_unlock(&tz->lock);
> >>> -}
> >>> -
> >>> -static void handle_non_critical_trips(struct thermal_zone_device *tz,
> >>> -			int trip, enum thermal_trip_type trip_type)
> >>> -{
> >>> -	if (tz->governor)
> >>> -		tz->governor->throttle(tz, trip);
> >>> -}
> >>> -
> >>> -static void handle_critical_trips(struct thermal_zone_device *tz,
> >>> -				int trip, enum thermal_trip_type trip_type)
> >>> -{
> >>> -	long trip_temp;
> >>> -
> >>> -	tz->ops->get_trip_temp(tz, trip, &trip_temp);
> >>> -
> >>> -	/* If we have not crossed the trip_temp, we do not care. */
> >>> -	if (tz->temperature < trip_temp)
> >>> -		return;
> >>> -
> >>> -	if (tz->ops->notify)
> >>> -		tz->ops->notify(tz, trip, trip_type);
> >>> -
> >>> -	if (trip_type == THERMAL_TRIP_CRITICAL) {
> >>> -		dev_emerg(&tz->device,
> >>> -			  "critical temperature reached(%d C),shutting
> down\n",
> >>> -			  tz->temperature / 1000);
> >>> -		orderly_poweroff(true);
> >>> -	}
> >>> -}
> >>> -
> >>> -static void handle_thermal_trip(struct thermal_zone_device *tz, int
> trip)
> >>> -{
> >>> -	enum thermal_trip_type type;
> >>> -
> >>> -	tz->ops->get_trip_type(tz, trip, &type);
> >>> -
> >>> -	if (type == THERMAL_TRIP_CRITICAL || type ==
> THERMAL_TRIP_HOT)
> >>> -		handle_critical_trips(tz, trip, type);
> >>> -	else
> >>> -		handle_non_critical_trips(tz, trip, type);
> >>> -	/*
> >>> -	 * Alright, we handled this trip successfully.
> >>> -	 * So, start monitoring again.
> >>> -	 */
> >>> -	monitor_thermal_zone(tz);
> >>> -}
> >>> -
> >>> -static int thermal_zone_get_temp(struct thermal_zone_device *tz,
> >>> -				unsigned long *temp)
> >>> -{
> >>> -	int ret = 0;
> >>> -#ifdef CONFIG_THERMAL_EMULATION
> >>> -	int count;
> >>> -	unsigned long crit_temp = -1UL;
> >>> -	enum thermal_trip_type type;
> >>> -#endif
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -
> >>> -	ret = tz->ops->get_temp(tz, temp);
> >>> -#ifdef CONFIG_THERMAL_EMULATION
> >>> -	if (!tz->emul_temperature)
> >>> -		goto skip_emul;
> >>> -
> >>> -	for (count = 0; count < tz->trips; count++) {
> >>> -		ret = tz->ops->get_trip_type(tz, count, &type);
> >>> -		if (!ret && type == THERMAL_TRIP_CRITICAL) {
> >>> -			ret = tz->ops->get_trip_temp(tz, count, &crit_temp);
> >>> -			break;
> >>> -		}
> >>> -	}
> >>> -
> >>> -	if (ret)
> >>> -		goto skip_emul;
> >>> -
> >>> -	if (*temp < crit_temp)
> >>> -		*temp = tz->emul_temperature;
> >>> -skip_emul:
> >>> -#endif
> >>> -	mutex_unlock(&tz->lock);
> >>> -	return ret;
> >>> -}
> >>> -
> >>> -static void update_temperature(struct thermal_zone_device *tz)
> >>> -{
> >>> -	long temp;
> >>> -	int ret;
> >>> -
> >>> -	ret = thermal_zone_get_temp(tz, &temp);
> >>> -	if (ret) {
> >>> -		dev_warn(&tz->device, "failed to read out thermal zone
> %d\n",
> >>> -			 tz->id);
> >>> -		return;
> >>> -	}
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -	tz->last_temperature = tz->temperature;
> >>> -	tz->temperature = temp;
> >>> -	mutex_unlock(&tz->lock);
> >>> -}
> >>> -
> >>> -void thermal_zone_device_update(struct thermal_zone_device *tz)
> >>> -{
> >>> -	int count;
> >>> -
> >>> -	update_temperature(tz);
> >>> -
> >>> -	for (count = 0; count < tz->trips; count++)
> >>> -		handle_thermal_trip(tz, count);
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_device_update);
> >>> -
> >>> -static void thermal_zone_device_check(struct work_struct *work)
> >>> -{
> >>> -	struct thermal_zone_device *tz = container_of(work, struct
> >>> -						      thermal_zone_device,
> >>> -						      poll_queue.work);
> >>> -	thermal_zone_device_update(tz);
> >>> -}
> >>> -
> >>> -/* sys I/F for thermal zone */
> >>> -
> >>> -#define to_thermal_zone(_dev) \
> >>> -	container_of(_dev, struct thermal_zone_device, device)
> >>> -
> >>> -static ssize_t
> >>> -type_show(struct device *dev, struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -
> >>> -	return sprintf(buf, "%s\n", tz->type);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -temp_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	long temperature;
> >>> -	int ret;
> >>> -
> >>> -	ret = thermal_zone_get_temp(tz, &temperature);
> >>> -
> >>> -	if (ret)
> >>> -		return ret;
> >>> -
> >>> -	return sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -mode_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	enum thermal_device_mode mode;
> >>> -	int result;
> >>> -
> >>> -	if (!tz->ops->get_mode)
> >>> -		return -EPERM;
> >>> -
> >>> -	result = tz->ops->get_mode(tz, &mode);
> >>> -	if (result)
> >>> -		return result;
> >>> -
> >>> -	return sprintf(buf, "%s\n", mode == THERMAL_DEVICE_ENABLED ?
> "enabled"
> >>> -		       : "disabled");
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -mode_store(struct device *dev, struct device_attribute *attr,
> >>> -	   const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int result;
> >>> -
> >>> -	if (!tz->ops->set_mode)
> >>> -		return -EPERM;
> >>> -
> >>> -	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);
> >>> -	else
> >>> -		result = -EINVAL;
> >>> -
> >>> -	if (result)
> >>> -		return result;
> >>> -
> >>> -	return count;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_type_show(struct device *dev, struct device_attribute
> *attr,
> >>> -		     char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	enum thermal_trip_type type;
> >>> -	int trip, result;
> >>> -
> >>> -	if (!tz->ops->get_trip_type)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	result = tz->ops->get_trip_type(tz, trip, &type);
> >>> -	if (result)
> >>> -		return result;
> >>> -
> >>> -	switch (type) {
> >>> -	case THERMAL_TRIP_CRITICAL:
> >>> -		return sprintf(buf, "critical\n");
> >>> -	case THERMAL_TRIP_HOT:
> >>> -		return sprintf(buf, "hot\n");
> >>> -	case THERMAL_TRIP_PASSIVE:
> >>> -		return sprintf(buf, "passive\n");
> >>> -	case THERMAL_TRIP_ACTIVE:
> >>> -		return sprintf(buf, "active\n");
> >>> -	default:
> >>> -		return sprintf(buf, "unknown\n");
> >>> -	}
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_temp_store(struct device *dev, struct device_attribute
> *attr,
> >>> -		     const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int trip, ret;
> >>> -	unsigned long temperature;
> >>> -
> >>> -	if (!tz->ops->set_trip_temp)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	if (kstrtoul(buf, 10, &temperature))
> >>> -		return -EINVAL;
> >>> -
> >>> -	ret = tz->ops->set_trip_temp(tz, trip, temperature);
> >>> -
> >>> -	return ret ? ret : count;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_temp_show(struct device *dev, struct device_attribute
> *attr,
> >>> -		     char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int trip, ret;
> >>> -	long temperature;
> >>> -
> >>> -	if (!tz->ops->get_trip_temp)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	ret = tz->ops->get_trip_temp(tz, trip, &temperature);
> >>> -
> >>> -	if (ret)
> >>> -		return ret;
> >>> -
> >>> -	return sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> >>> -			const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int trip, ret;
> >>> -	unsigned long temperature;
> >>> -
> >>> -	if (!tz->ops->set_trip_hyst)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	if (kstrtoul(buf, 10, &temperature))
> >>> -		return -EINVAL;
> >>> -
> >>> -	/*
> >>> -	 * We are not doing any check on the 'temperature' value
> >>> -	 * here. The driver implementing 'set_trip_hyst' has to
> >>> -	 * take care of this.
> >>> -	 */
> >>> -	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> >>> -
> >>> -	return ret ? ret : count;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -trip_point_hyst_show(struct device *dev, struct device_attribute *attr,
> >>> -			char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int trip, ret;
> >>> -	unsigned long temperature;
> >>> -
> >>> -	if (!tz->ops->get_trip_hyst)
> >>> -		return -EPERM;
> >>> -
> >>> -	if (!sscanf(attr->attr.name, "trip_point_%d_hyst", &trip))
> >>> -		return -EINVAL;
> >>> -
> >>> -	ret = tz->ops->get_trip_hyst(tz, trip, &temperature);
> >>> -
> >>> -	return ret ? ret : sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -passive_store(struct device *dev, struct device_attribute *attr,
> >>> -		    const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	struct thermal_cooling_device *cdev = NULL;
> >>> -	int state;
> >>> -
> >>> -	if (!sscanf(buf, "%d\n", &state))
> >>> -		return -EINVAL;
> >>> -
> >>> -	/* sanity check: values below 1000 millicelcius don't make sense
> >>> -	 * and can cause the system to go into a thermal heart attack
> >>> -	 */
> >>> -	if (state && state < 1000)
> >>> -		return -EINVAL;
> >>> -
> >>> -	if (state && !tz->forced_passive) {
> >>> -		mutex_lock(&thermal_list_lock);
> >>> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> -			if (!strncmp("Processor", cdev->type,
> >>> -				     sizeof("Processor")))
> >>> -				thermal_zone_bind_cooling_device(tz,
> >>> -						THERMAL_TRIPS_NONE,
> cdev,
> >>> -						THERMAL_NO_LIMIT,
> >>> -						THERMAL_NO_LIMIT);
> >>> -		}
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		if (!tz->passive_delay)
> >>> -			tz->passive_delay = 1000;
> >>> -	} else if (!state && tz->forced_passive) {
> >>> -		mutex_lock(&thermal_list_lock);
> >>> -		list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> -			if (!strncmp("Processor", cdev->type,
> >>> -				     sizeof("Processor")))
> >>> -				thermal_zone_unbind_cooling_device(tz,
> >>> -
> THERMAL_TRIPS_NONE,
> >>> -								   cdev);
> >>> -		}
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		tz->passive_delay = 0;
> >>> -	}
> >>> -
> >>> -	tz->forced_passive = state;
> >>> -
> >>> -	thermal_zone_device_update(tz);
> >>> -
> >>> -	return count;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -passive_show(struct device *dev, struct device_attribute *attr,
> >>> -		   char *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -
> >>> -	return sprintf(buf, "%d\n", tz->forced_passive);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -policy_store(struct device *dev, struct device_attribute *attr,
> >>> -		    const char *buf, size_t count)
> >>> -{
> >>> -	int ret = -EINVAL;
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	struct thermal_governor *gov;
> >>> -
> >>> -	mutex_lock(&thermal_governor_lock);
> >>> -
> >>> -	gov = __find_governor(buf);
> >>> -	if (!gov)
> >>> -		goto exit;
> >>> -
> >>> -	tz->governor = gov;
> >>> -	ret = count;
> >>> -
> >>> -exit:
> >>> -	mutex_unlock(&thermal_governor_lock);
> >>> -	return ret;
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -policy_show(struct device *dev, struct device_attribute *devattr, char
> *buf)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -
> >>> -	return sprintf(buf, "%s\n", tz->governor->name);
> >>> -}
> >>> -
> >>> -#ifdef CONFIG_THERMAL_EMULATION
> >>> -static ssize_t
> >>> -emul_temp_store(struct device *dev, struct device_attribute *attr,
> >>> -		     const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_zone_device *tz = to_thermal_zone(dev);
> >>> -	int ret = 0;
> >>> -	unsigned long temperature;
> >>> -
> >>> -	if (kstrtoul(buf, 10, &temperature))
> >>> -		return -EINVAL;
> >>> -
> >>> -	if (!tz->ops->set_emul_temp) {
> >>> -		mutex_lock(&tz->lock);
> >>> -		tz->emul_temperature = temperature;
> >>> -		mutex_unlock(&tz->lock);
> >>> -	} else {
> >>> -		ret = tz->ops->set_emul_temp(tz, temperature);
> >>> -	}
> >>> -
> >>> -	return ret ? ret : count;
> >>> -}
> >>> -static DEVICE_ATTR(emul_temp, S_IWUSR, NULL, emul_temp_store);
> >>> -#endif/*CONFIG_THERMAL_EMULATION*/
> >>> -
> >>> -static DEVICE_ATTR(type, 0444, type_show, NULL);
> >>> -static DEVICE_ATTR(temp, 0444, temp_show, NULL);
> >>> -static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
> >>> -static DEVICE_ATTR(passive, S_IRUGO | S_IWUSR, passive_show,
> passive_store);
> >>> -static DEVICE_ATTR(policy, S_IRUGO | S_IWUSR, policy_show,
> policy_store);
> >>> -
> >>> -/* sys I/F for cooling device */
> >>> -#define to_cooling_device(_dev)	\
> >>> -	container_of(_dev, struct thermal_cooling_device, device)
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_type_show(struct device *dev,
> >>> -				 struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> -
> >>> -	return sprintf(buf, "%s\n", cdev->type);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_max_state_show(struct device *dev,
> >>> -				      struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> -	unsigned long state;
> >>> -	int ret;
> >>> -
> >>> -	ret = cdev->ops->get_max_state(cdev, &state);
> >>> -	if (ret)
> >>> -		return ret;
> >>> -	return sprintf(buf, "%ld\n", state);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_cur_state_show(struct device *dev,
> >>> -				      struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> -	unsigned long state;
> >>> -	int ret;
> >>> -
> >>> -	ret = cdev->ops->get_cur_state(cdev, &state);
> >>> -	if (ret)
> >>> -		return ret;
> >>> -	return sprintf(buf, "%ld\n", state);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_cur_state_store(struct device *dev,
> >>> -				       struct device_attribute *attr,
> >>> -				       const char *buf, size_t count)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev = to_cooling_device(dev);
> >>> -	unsigned long state;
> >>> -	int result;
> >>> -
> >>> -	if (!sscanf(buf, "%ld\n", &state))
> >>> -		return -EINVAL;
> >>> -
> >>> -	if ((long)state < 0)
> >>> -		return -EINVAL;
> >>> -
> >>> -	result = cdev->ops->set_cur_state(cdev, state);
> >>> -	if (result)
> >>> -		return result;
> >>> -	return count;
> >>> -}
> >>> -
> >>> -static struct device_attribute dev_attr_cdev_type =
> >>> -__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
> >>> -static DEVICE_ATTR(max_state, 0444,
> >>> -		   thermal_cooling_device_max_state_show, NULL);
> >>> -static DEVICE_ATTR(cur_state, 0644,
> >>> -		   thermal_cooling_device_cur_state_show,
> >>> -		   thermal_cooling_device_cur_state_store);
> >>> -
> >>> -static ssize_t
> >>> -thermal_cooling_device_trip_point_show(struct device *dev,
> >>> -				       struct device_attribute *attr, char *buf)
> >>> -{
> >>> -	struct thermal_instance *instance;
> >>> -
> >>> -	instance =
> >>> -	    container_of(attr, struct thermal_instance, attr);
> >>> -
> >>> -	if (instance->trip == THERMAL_TRIPS_NONE)
> >>> -		return sprintf(buf, "-1\n");
> >>> -	else
> >>> -		return sprintf(buf, "%d\n", instance->trip);
> >>> -}
> >>> -
> >>> -/* Device management */
> >>> -
> >>> -#if defined(CONFIG_THERMAL_HWMON)
> >>> -
> >>> -/* hwmon sys I/F */
> >>> -#include <linux/hwmon.h>
> >>> -
> >>> -/* thermal zone devices with the same type share one hwmon device
> */
> >>> -struct thermal_hwmon_device {
> >>> -	char type[THERMAL_NAME_LENGTH];
> >>> -	struct device *device;
> >>> -	int count;
> >>> -	struct list_head tz_list;
> >>> -	struct list_head node;
> >>> -};
> >>> -
> >>> -struct thermal_hwmon_attr {
> >>> -	struct device_attribute attr;
> >>> -	char name[16];
> >>> -};
> >>> -
> >>> -/* one temperature input for each thermal zone */
> >>> -struct thermal_hwmon_temp {
> >>> -	struct list_head hwmon_node;
> >>> -	struct thermal_zone_device *tz;
> >>> -	struct thermal_hwmon_attr temp_input;	/* hwmon sys attr */
> >>> -	struct thermal_hwmon_attr temp_crit;	/* hwmon sys attr */
> >>> -};
> >>> -
> >>> -static LIST_HEAD(thermal_hwmon_list);
> >>> -
> >>> -static ssize_t
> >>> -name_show(struct device *dev, struct device_attribute *attr, char
> *buf)
> >>> -{
> >>> -	struct thermal_hwmon_device *hwmon = dev_get_drvdata(dev);
> >>> -	return sprintf(buf, "%s\n", hwmon->type);
> >>> -}
> >>> -static DEVICE_ATTR(name, 0444, name_show, NULL);
> >>> -
> >>> -static ssize_t
> >>> -temp_input_show(struct device *dev, struct device_attribute *attr,
> char *buf)
> >>> -{
> >>> -	long temperature;
> >>> -	int ret;
> >>> -	struct thermal_hwmon_attr *hwmon_attr
> >>> -			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> >>> -	struct thermal_hwmon_temp *temp
> >>> -			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> >>> -				       temp_input);
> >>> -	struct thermal_zone_device *tz = temp->tz;
> >>> -
> >>> -	ret = thermal_zone_get_temp(tz, &temperature);
> >>> -
> >>> -	if (ret)
> >>> -		return ret;
> >>> -
> >>> -	return sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -static ssize_t
> >>> -temp_crit_show(struct device *dev, struct device_attribute *attr,
> >>> -		char *buf)
> >>> -{
> >>> -	struct thermal_hwmon_attr *hwmon_attr
> >>> -			= container_of(attr, struct thermal_hwmon_attr,
> attr);
> >>> -	struct thermal_hwmon_temp *temp
> >>> -			= container_of(hwmon_attr, struct
> thermal_hwmon_temp,
> >>> -				       temp_crit);
> >>> -	struct thermal_zone_device *tz = temp->tz;
> >>> -	long temperature;
> >>> -	int ret;
> >>> -
> >>> -	ret = tz->ops->get_trip_temp(tz, 0, &temperature);
> >>> -	if (ret)
> >>> -		return ret;
> >>> -
> >>> -	return sprintf(buf, "%ld\n", temperature);
> >>> -}
> >>> -
> >>> -
> >>> -static struct thermal_hwmon_device *
> >>> -thermal_hwmon_lookup_by_type(const struct thermal_zone_device
> *tz)
> >>> -{
> >>> -	struct thermal_hwmon_device *hwmon;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_for_each_entry(hwmon, &thermal_hwmon_list, node)
> >>> -		if (!strcmp(hwmon->type, tz->type)) {
> >>> -			mutex_unlock(&thermal_list_lock);
> >>> -			return hwmon;
> >>> -		}
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	return NULL;
> >>> -}
> >>> -
> >>> -/* Find the temperature input matching a given thermal zone */
> >>> -static struct thermal_hwmon_temp *
> >>> -thermal_hwmon_lookup_temp(const struct thermal_hwmon_device
> *hwmon,
> >>> -			  const struct thermal_zone_device *tz)
> >>> -{
> >>> -	struct thermal_hwmon_temp *temp;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_for_each_entry(temp, &hwmon->tz_list, hwmon_node)
> >>> -		if (temp->tz == tz) {
> >>> -			mutex_unlock(&thermal_list_lock);
> >>> -			return temp;
> >>> -		}
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	return NULL;
> >>> -}
> >>> -
> >>> -static int
> >>> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> -{
> >>> -	struct thermal_hwmon_device *hwmon;
> >>> -	struct thermal_hwmon_temp *temp;
> >>> -	int new_hwmon_device = 1;
> >>> -	int result;
> >>> -
> >>> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> >>> -	if (hwmon) {
> >>> -		new_hwmon_device = 0;
> >>> -		goto register_sys_interface;
> >>> -	}
> >>> -
> >>> -	hwmon = kzalloc(sizeof(struct thermal_hwmon_device),
> GFP_KERNEL);
> >>> -	if (!hwmon)
> >>> -		return -ENOMEM;
> >>> -
> >>> -	INIT_LIST_HEAD(&hwmon->tz_list);
> >>> -	strlcpy(hwmon->type, tz->type, THERMAL_NAME_LENGTH);
> >>> -	hwmon->device = hwmon_device_register(NULL);
> >>> -	if (IS_ERR(hwmon->device)) {
> >>> -		result = PTR_ERR(hwmon->device);
> >>> -		goto free_mem;
> >>> -	}
> >>> -	dev_set_drvdata(hwmon->device, hwmon);
> >>> -	result = device_create_file(hwmon->device, &dev_attr_name);
> >>> -	if (result)
> >>> -		goto free_mem;
> >>> -
> >>> - register_sys_interface:
> >>> -	temp = kzalloc(sizeof(struct thermal_hwmon_temp), GFP_KERNEL);
> >>> -	if (!temp) {
> >>> -		result = -ENOMEM;
> >>> -		goto unregister_name;
> >>> -	}
> >>> -
> >>> -	temp->tz = tz;
> >>> -	hwmon->count++;
> >>> -
> >>> -	snprintf(temp->temp_input.name, sizeof(temp-
> >temp_input.name),
> >>> -		 "temp%d_input", hwmon->count);
> >>> -	temp->temp_input.attr.attr.name = temp->temp_input.name;
> >>> -	temp->temp_input.attr.attr.mode = 0444;
> >>> -	temp->temp_input.attr.show = temp_input_show;
> >>> -	sysfs_attr_init(&temp->temp_input.attr.attr);
> >>> -	result = device_create_file(hwmon->device, &temp-
> >temp_input.attr);
> >>> -	if (result)
> >>> -		goto free_temp_mem;
> >>> -
> >>> -	if (tz->ops->get_crit_temp) {
> >>> -		unsigned long temperature;
> >>> -		if (!tz->ops->get_crit_temp(tz, &temperature)) {
> >>> -			snprintf(temp->temp_crit.name,
> >>> -				 sizeof(temp->temp_crit.name),
> >>> -				"temp%d_crit", hwmon->count);
> >>> -			temp->temp_crit.attr.attr.name = temp-
> >temp_crit.name;
> >>> -			temp->temp_crit.attr.attr.mode = 0444;
> >>> -			temp->temp_crit.attr.show = temp_crit_show;
> >>> -			sysfs_attr_init(&temp->temp_crit.attr.attr);
> >>> -			result = device_create_file(hwmon->device,
> >>> -						    &temp->temp_crit.attr);
> >>> -			if (result)
> >>> -				goto unregister_input;
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	if (new_hwmon_device)
> >>> -		list_add_tail(&hwmon->node, &thermal_hwmon_list);
> >>> -	list_add_tail(&temp->hwmon_node, &hwmon->tz_list);
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	return 0;
> >>> -
> >>> - unregister_input:
> >>> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> >>> - free_temp_mem:
> >>> -	kfree(temp);
> >>> - unregister_name:
> >>> -	if (new_hwmon_device) {
> >>> -		device_remove_file(hwmon->device, &dev_attr_name);
> >>> -		hwmon_device_unregister(hwmon->device);
> >>> -	}
> >>> - free_mem:
> >>> -	if (new_hwmon_device)
> >>> -		kfree(hwmon);
> >>> -
> >>> -	return result;
> >>> -}
> >>> -
> >>> -static void
> >>> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> -{
> >>> -	struct thermal_hwmon_device *hwmon;
> >>> -	struct thermal_hwmon_temp *temp;
> >>> -
> >>> -	hwmon = thermal_hwmon_lookup_by_type(tz);
> >>> -	if (unlikely(!hwmon)) {
> >>> -		/* Should never happen... */
> >>> -		dev_dbg(&tz->device, "hwmon device lookup failed!\n");
> >>> -		return;
> >>> -	}
> >>> -
> >>> -	temp = thermal_hwmon_lookup_temp(hwmon, tz);
> >>> -	if (unlikely(!temp)) {
> >>> -		/* Should never happen... */
> >>> -		dev_dbg(&tz->device, "temperature input lookup
> failed!\n");
> >>> -		return;
> >>> -	}
> >>> -
> >>> -	device_remove_file(hwmon->device, &temp->temp_input.attr);
> >>> -	if (tz->ops->get_crit_temp)
> >>> -		device_remove_file(hwmon->device, &temp-
> >temp_crit.attr);
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_del(&temp->hwmon_node);
> >>> -	kfree(temp);
> >>> -	if (!list_empty(&hwmon->tz_list)) {
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		return;
> >>> -	}
> >>> -	list_del(&hwmon->node);
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	device_remove_file(hwmon->device, &dev_attr_name);
> >>> -	hwmon_device_unregister(hwmon->device);
> >>> -	kfree(hwmon);
> >>> -}
> >>> -#else
> >>> -static int
> >>> -thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> -{
> >>> -	return 0;
> >>> -}
> >>> -
> >>> -static void
> >>> -thermal_remove_hwmon_sysfs(struct thermal_zone_device *tz)
> >>> -{
> >>> -}
> >>> -#endif
> >>> -
> >>> -/**
> >>> - * thermal_zone_bind_cooling_device - bind a cooling device to a
> thermal zone
> >>> - * @tz:		thermal zone device
> >>> - * @trip:	indicates which trip point the cooling devices is
> >>> - *		associated with in this thermal zone.
> >>> - * @cdev:	thermal cooling device
> >>> - *
> >>> - * This function is usually called in the thermal zone device .bind
> callback.
> >>> - */
> >>> -int thermal_zone_bind_cooling_device(struct thermal_zone_device
> *tz,
> >>> -				     int trip,
> >>> -				     struct thermal_cooling_device *cdev,
> >>> -				     unsigned long upper, unsigned long lower)
> >>> -{
> >>> -	struct thermal_instance *dev;
> >>> -	struct thermal_instance *pos;
> >>> -	struct thermal_zone_device *pos1;
> >>> -	struct thermal_cooling_device *pos2;
> >>> -	unsigned long max_state;
> >>> -	int result;
> >>> -
> >>> -	if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
> >>> -		return -EINVAL;
> >>> -
> >>> -	list_for_each_entry(pos1, &thermal_tz_list, node) {
> >>> -		if (pos1 == tz)
> >>> -			break;
> >>> -	}
> >>> -	list_for_each_entry(pos2, &thermal_cdev_list, node) {
> >>> -		if (pos2 == cdev)
> >>> -			break;
> >>> -	}
> >>> -
> >>> -	if (tz != pos1 || cdev != pos2)
> >>> -		return -EINVAL;
> >>> -
> >>> -	cdev->ops->get_max_state(cdev, &max_state);
> >>> -
> >>> -	/* lower default 0, upper default max_state */
> >>> -	lower = lower == THERMAL_NO_LIMIT ? 0 : lower;
> >>> -	upper = upper == THERMAL_NO_LIMIT ? max_state : upper;
> >>> -
> >>> -	if (lower > upper || upper > max_state)
> >>> -		return -EINVAL;
> >>> -
> >>> -	dev =
> >>> -	    kzalloc(sizeof(struct thermal_instance), GFP_KERNEL);
> >>> -	if (!dev)
> >>> -		return -ENOMEM;
> >>> -	dev->tz = tz;
> >>> -	dev->cdev = cdev;
> >>> -	dev->trip = trip;
> >>> -	dev->upper = upper;
> >>> -	dev->lower = lower;
> >>> -	dev->target = THERMAL_NO_TARGET;
> >>> -
> >>> -	result = get_idr(&tz->idr, &tz->lock, &dev->id);
> >>> -	if (result)
> >>> -		goto free_mem;
> >>> -
> >>> -	sprintf(dev->name, "cdev%d", dev->id);
> >>> -	result =
> >>> -	    sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev-
> >name);
> >>> -	if (result)
> >>> -		goto release_idr;
> >>> -
> >>> -	sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
> >>> -	sysfs_attr_init(&dev->attr.attr);
> >>> -	dev->attr.attr.name = dev->attr_name;
> >>> -	dev->attr.attr.mode = 0444;
> >>> -	dev->attr.show = thermal_cooling_device_trip_point_show;
> >>> -	result = device_create_file(&tz->device, &dev->attr);
> >>> -	if (result)
> >>> -		goto remove_symbol_link;
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -	mutex_lock(&cdev->lock);
> >>> -	list_for_each_entry(pos, &tz->thermal_instances, tz_node)
> >>> -	    if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> -		result = -EEXIST;
> >>> -		break;
> >>> -	}
> >>> -	if (!result) {
> >>> -		list_add_tail(&dev->tz_node, &tz->thermal_instances);
> >>> -		list_add_tail(&dev->cdev_node, &cdev-
> >thermal_instances);
> >>> -	}
> >>> -	mutex_unlock(&cdev->lock);
> >>> -	mutex_unlock(&tz->lock);
> >>> -
> >>> -	if (!result)
> >>> -		return 0;
> >>> -
> >>> -	device_remove_file(&tz->device, &dev->attr);
> >>> -remove_symbol_link:
> >>> -	sysfs_remove_link(&tz->device.kobj, dev->name);
> >>> -release_idr:
> >>> -	release_idr(&tz->idr, &tz->lock, dev->id);
> >>> -free_mem:
> >>> -	kfree(dev);
> >>> -	return result;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
> >>> -
> >>> -/**
> >>> - * thermal_zone_unbind_cooling_device - unbind a cooling device from
> a thermal zone
> >>> - * @tz:		thermal zone device
> >>> - * @trip:	indicates which trip point the cooling devices is
> >>> - *		associated with in this thermal zone.
> >>> - * @cdev:	thermal cooling device
> >>> - *
> >>> - * This function is usually called in the thermal zone device .unbind
> callback.
> >>> - */
> >>> -int thermal_zone_unbind_cooling_device(struct thermal_zone_device
> *tz,
> >>> -				       int trip,
> >>> -				       struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	struct thermal_instance *pos, *next;
> >>> -
> >>> -	mutex_lock(&tz->lock);
> >>> -	mutex_lock(&cdev->lock);
> >>> -	list_for_each_entry_safe(pos, next, &tz->thermal_instances,
> tz_node) {
> >>> -		if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
> >>> -			list_del(&pos->tz_node);
> >>> -			list_del(&pos->cdev_node);
> >>> -			mutex_unlock(&cdev->lock);
> >>> -			mutex_unlock(&tz->lock);
> >>> -			goto unbind;
> >>> -		}
> >>> -	}
> >>> -	mutex_unlock(&cdev->lock);
> >>> -	mutex_unlock(&tz->lock);
> >>> -
> >>> -	return -ENODEV;
> >>> -
> >>> -unbind:
> >>> -	device_remove_file(&tz->device, &pos->attr);
> >>> -	sysfs_remove_link(&tz->device.kobj, pos->name);
> >>> -	release_idr(&tz->idr, &tz->lock, pos->id);
> >>> -	kfree(pos);
> >>> -	return 0;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
> >>> -
> >>> -static void thermal_release(struct device *dev)
> >>> -{
> >>> -	struct thermal_zone_device *tz;
> >>> -	struct thermal_cooling_device *cdev;
> >>> -
> >>> -	if (!strncmp(dev_name(dev), "thermal_zone",
> >>> -		     sizeof("thermal_zone") - 1)) {
> >>> -		tz = to_thermal_zone(dev);
> >>> -		kfree(tz);
> >>> -	} else {
> >>> -		cdev = to_cooling_device(dev);
> >>> -		kfree(cdev);
> >>> -	}
> >>> -}
> >>> -
> >>> -static struct class thermal_class = {
> >>> -	.name = "thermal",
> >>> -	.dev_release = thermal_release,
> >>> -};
> >>> -
> >>> -/**
> >>> - * thermal_cooling_device_register - register a new thermal cooling
> device
> >>> - * @type:	the thermal cooling device type.
> >>> - * @devdata:	device private data.
> >>> - * @ops:		standard thermal cooling devices callbacks.
> >>> - */
> >>> -struct thermal_cooling_device *
> >>> -thermal_cooling_device_register(char *type, void *devdata,
> >>> -				const struct thermal_cooling_device_ops
> *ops)
> >>> -{
> >>> -	struct thermal_cooling_device *cdev;
> >>> -	int result;
> >>> -
> >>> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	if (!ops || !ops->get_max_state || !ops->get_cur_state ||
> >>> -	    !ops->set_cur_state)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
> >>> -	if (!cdev)
> >>> -		return ERR_PTR(-ENOMEM);
> >>> -
> >>> -	result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
> >>> -	if (result) {
> >>> -		kfree(cdev);
> >>> -		return ERR_PTR(result);
> >>> -	}
> >>> -
> >>> -	strcpy(cdev->type, type ? : "");
> >>> -	mutex_init(&cdev->lock);
> >>> -	INIT_LIST_HEAD(&cdev->thermal_instances);
> >>> -	cdev->ops = ops;
> >>> -	cdev->updated = true;
> >>> -	cdev->device.class = &thermal_class;
> >>> -	cdev->devdata = devdata;
> >>> -	dev_set_name(&cdev->device, "cooling_device%d", cdev->id);
> >>> -	result = device_register(&cdev->device);
> >>> -	if (result) {
> >>> -		release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev-
> >id);
> >>> -		kfree(cdev);
> >>> -		return ERR_PTR(result);
> >>> -	}
> >>> -
> >>> -	/* sys I/F */
> >>> -	if (type) {
> >>> -		result = device_create_file(&cdev->device,
> &dev_attr_cdev_type);
> >>> -		if (result)
> >>> -			goto unregister;
> >>> -	}
> >>> -
> >>> -	result = device_create_file(&cdev->device, &dev_attr_max_state);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	result = device_create_file(&cdev->device, &dev_attr_cur_state);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	/* Add 'this' new cdev to the global cdev list */
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_add(&cdev->node, &thermal_cdev_list);
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	/* Update binding information for 'this' new cdev */
> >>> -	bind_cdev(cdev);
> >>> -
> >>> -	return cdev;
> >>> -
> >>> -unregister:
> >>> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> >>> -	device_unregister(&cdev->device);
> >>> -	return ERR_PTR(result);
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_cooling_device_register);
> >>> -
> >>> -/**
> >>> - * thermal_cooling_device_unregister - removes the registered thermal
> cooling device
> >>> - * @cdev:	the thermal cooling device to remove.
> >>> - *
> >>> - * thermal_cooling_device_unregister() must be called when the device
> is no
> >>> - * longer needed.
> >>> - */
> >>> -void thermal_cooling_device_unregister(struct thermal_cooling_device
> *cdev)
> >>> -{
> >>> -	int i;
> >>> -	const struct thermal_zone_params *tzp;
> >>> -	struct thermal_zone_device *tz;
> >>> -	struct thermal_cooling_device *pos = NULL;
> >>> -
> >>> -	if (!cdev)
> >>> -		return;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_for_each_entry(pos, &thermal_cdev_list, node)
> >>> -	    if (pos == cdev)
> >>> -		break;
> >>> -	if (pos != cdev) {
> >>> -		/* thermal cooling device not found */
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		return;
> >>> -	}
> >>> -	list_del(&cdev->node);
> >>> -
> >>> -	/* Unbind all thermal zones associated with 'this' cdev */
> >>> -	list_for_each_entry(tz, &thermal_tz_list, node) {
> >>> -		if (tz->ops->unbind) {
> >>> -			tz->ops->unbind(tz, cdev);
> >>> -			continue;
> >>> -		}
> >>> -
> >>> -		if (!tz->tzp || !tz->tzp->tbp)
> >>> -			continue;
> >>> -
> >>> -		tzp = tz->tzp;
> >>> -		for (i = 0; i < tzp->num_tbps; i++) {
> >>> -			if (tzp->tbp[i].cdev == cdev) {
> >>> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> >>> -				tzp->tbp[i].cdev = NULL;
> >>> -			}
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	if (cdev->type[0])
> >>> -		device_remove_file(&cdev->device, &dev_attr_cdev_type);
> >>> -	device_remove_file(&cdev->device, &dev_attr_max_state);
> >>> -	device_remove_file(&cdev->device, &dev_attr_cur_state);
> >>> -
> >>> -	release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
> >>> -	device_unregister(&cdev->device);
> >>> -	return;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_cooling_device_unregister);
> >>> -
> >>> -void thermal_cdev_update(struct thermal_cooling_device *cdev)
> >>> -{
> >>> -	struct thermal_instance *instance;
> >>> -	unsigned long target = 0;
> >>> -
> >>> -	/* cooling device is updated*/
> >>> -	if (cdev->updated)
> >>> -		return;
> >>> -
> >>> -	mutex_lock(&cdev->lock);
> >>> -	/* Make sure cdev enters the deepest cooling state */
> >>> -	list_for_each_entry(instance, &cdev->thermal_instances,
> cdev_node) {
> >>> -		if (instance->target == THERMAL_NO_TARGET)
> >>> -			continue;
> >>> -		if (instance->target > target)
> >>> -			target = instance->target;
> >>> -	}
> >>> -	mutex_unlock(&cdev->lock);
> >>> -	cdev->ops->set_cur_state(cdev, target);
> >>> -	cdev->updated = true;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_cdev_update);
> >>> -
> >>> -/**
> >>> - * notify_thermal_framework - Sensor drivers use this API to notify
> framework
> >>> - * @tz:		thermal zone device
> >>> - * @trip:	indicates which trip point has been crossed
> >>> - *
> >>> - * This function handles the trip events from sensor drivers. It starts
> >>> - * throttling the cooling devices according to the policy configured.
> >>> - * For CRITICAL and HOT trip points, this notifies the respective drivers,
> >>> - * and does actual throttling for other trip points i.e ACTIVE and
> PASSIVE.
> >>> - * The throttling policy is based on the configured platform data; if no
> >>> - * platform data is provided, this uses the step_wise throttling policy.
> >>> - */
> >>> -void notify_thermal_framework(struct thermal_zone_device *tz, int
> trip)
> >>> -{
> >>> -	handle_thermal_trip(tz, trip);
> >>> -}
> >>> -EXPORT_SYMBOL(notify_thermal_framework);
> >>> -
> >>> -/**
> >>> - * create_trip_attrs - create attributes for trip points
> >>> - * @tz:		the thermal zone device
> >>> - * @mask:	Writeable trip point bitmap.
> >>> - */
> >>> -static int create_trip_attrs(struct thermal_zone_device *tz, int mask)
> >>> -{
> >>> -	int indx;
> >>> -	int size = sizeof(struct thermal_attr) * tz->trips;
> >>> -
> >>> -	tz->trip_type_attrs = kzalloc(size, GFP_KERNEL);
> >>> -	if (!tz->trip_type_attrs)
> >>> -		return -ENOMEM;
> >>> -
> >>> -	tz->trip_temp_attrs = kzalloc(size, GFP_KERNEL);
> >>> -	if (!tz->trip_temp_attrs) {
> >>> -		kfree(tz->trip_type_attrs);
> >>> -		return -ENOMEM;
> >>> -	}
> >>> -
> >>> -	if (tz->ops->get_trip_hyst) {
> >>> -		tz->trip_hyst_attrs = kzalloc(size, GFP_KERNEL);
> >>> -		if (!tz->trip_hyst_attrs) {
> >>> -			kfree(tz->trip_type_attrs);
> >>> -			kfree(tz->trip_temp_attrs);
> >>> -			return -ENOMEM;
> >>> -		}
> >>> -	}
> >>> -
> >>> -
> >>> -	for (indx = 0; indx < tz->trips; indx++) {
> >>> -		/* create trip type attribute */
> >>> -		snprintf(tz->trip_type_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> -			 "trip_point_%d_type", indx);
> >>> -
> >>> -		sysfs_attr_init(&tz->trip_type_attrs[indx].attr.attr);
> >>> -		tz->trip_type_attrs[indx].attr.attr.name =
> >>> -						tz-
> >trip_type_attrs[indx].name;
> >>> -		tz->trip_type_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> -		tz->trip_type_attrs[indx].attr.show = trip_point_type_show;
> >>> -
> >>> -		device_create_file(&tz->device,
> >>> -				   &tz->trip_type_attrs[indx].attr);
> >>> -
> >>> -		/* create trip temp attribute */
> >>> -		snprintf(tz->trip_temp_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> -			 "trip_point_%d_temp", indx);
> >>> -
> >>> -		sysfs_attr_init(&tz->trip_temp_attrs[indx].attr.attr);
> >>> -		tz->trip_temp_attrs[indx].attr.attr.name =
> >>> -						tz-
> >trip_temp_attrs[indx].name;
> >>> -		tz->trip_temp_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> -		tz->trip_temp_attrs[indx].attr.show =
> trip_point_temp_show;
> >>> -		if (mask & (1 << indx)) {
> >>> -			tz->trip_temp_attrs[indx].attr.attr.mode |=
> S_IWUSR;
> >>> -			tz->trip_temp_attrs[indx].attr.store =
> >>> -
> 	trip_point_temp_store;
> >>> -		}
> >>> -
> >>> -		device_create_file(&tz->device,
> >>> -				   &tz->trip_temp_attrs[indx].attr);
> >>> -
> >>> -		/* create Optional trip hyst attribute */
> >>> -		if (!tz->ops->get_trip_hyst)
> >>> -			continue;
> >>> -		snprintf(tz->trip_hyst_attrs[indx].name,
> THERMAL_NAME_LENGTH,
> >>> -			 "trip_point_%d_hyst", indx);
> >>> -
> >>> -		sysfs_attr_init(&tz->trip_hyst_attrs[indx].attr.attr);
> >>> -		tz->trip_hyst_attrs[indx].attr.attr.name =
> >>> -					tz->trip_hyst_attrs[indx].name;
> >>> -		tz->trip_hyst_attrs[indx].attr.attr.mode = S_IRUGO;
> >>> -		tz->trip_hyst_attrs[indx].attr.show = trip_point_hyst_show;
> >>> -		if (tz->ops->set_trip_hyst) {
> >>> -			tz->trip_hyst_attrs[indx].attr.attr.mode |= S_IWUSR;
> >>> -			tz->trip_hyst_attrs[indx].attr.store =
> >>> -					trip_point_hyst_store;
> >>> -		}
> >>> -
> >>> -		device_create_file(&tz->device,
> >>> -				   &tz->trip_hyst_attrs[indx].attr);
> >>> -	}
> >>> -	return 0;
> >>> -}
> >>> -
> >>> -static void remove_trip_attrs(struct thermal_zone_device *tz)
> >>> -{
> >>> -	int indx;
> >>> -
> >>> -	for (indx = 0; indx < tz->trips; indx++) {
> >>> -		device_remove_file(&tz->device,
> >>> -				   &tz->trip_type_attrs[indx].attr);
> >>> -		device_remove_file(&tz->device,
> >>> -				   &tz->trip_temp_attrs[indx].attr);
> >>> -		if (tz->ops->get_trip_hyst)
> >>> -			device_remove_file(&tz->device,
> >>> -				  &tz->trip_hyst_attrs[indx].attr);
> >>> -	}
> >>> -	kfree(tz->trip_type_attrs);
> >>> -	kfree(tz->trip_temp_attrs);
> >>> -	kfree(tz->trip_hyst_attrs);
> >>> -}
> >>> -
> >>> -/**
> >>> - * thermal_zone_device_register - register a new thermal zone device
> >>> - * @type:	the thermal zone device type
> >>> - * @trips:	the number of trip points the thermal zone support
> >>> - * @mask:	a bit string indicating the writeablility of trip points
> >>> - * @devdata:	private device data
> >>> - * @ops:	standard thermal zone device callbacks
> >>> - * @tzp:	thermal zone platform parameters
> >>> - * @passive_delay: number of milliseconds to wait between polls when
> >>> - *		   performing passive cooling
> >>> - * @polling_delay: number of milliseconds to wait between polls when
> checking
> >>> - *		   whether trip points have been crossed (0 for interrupt
> >>> - *		   driven systems)
> >>> - *
> >>> - * thermal_zone_device_unregister() must be called when the device is
> no
> >>> - * longer needed. The passive cooling depends on the .get_trend()
> return value.
> >>> - */
> >>> -struct thermal_zone_device *thermal_zone_device_register(const
> char *type,
> >>> -	int trips, int mask, void *devdata,
> >>> -	const struct thermal_zone_device_ops *ops,
> >>> -	const struct thermal_zone_params *tzp,
> >>> -	int passive_delay, int polling_delay)
> >>> -{
> >>> -	struct thermal_zone_device *tz;
> >>> -	enum thermal_trip_type trip_type;
> >>> -	int result;
> >>> -	int count;
> >>> -	int passive = 0;
> >>> -
> >>> -	if (type && strlen(type) >= THERMAL_NAME_LENGTH)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	if (trips > THERMAL_MAX_TRIPS || trips < 0 || mask >> trips)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	if (!ops || !ops->get_temp)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	if (trips > 0 && !ops->get_trip_type)
> >>> -		return ERR_PTR(-EINVAL);
> >>> -
> >>> -	tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
> >>> -	if (!tz)
> >>> -		return ERR_PTR(-ENOMEM);
> >>> -
> >>> -	INIT_LIST_HEAD(&tz->thermal_instances);
> >>> -	idr_init(&tz->idr);
> >>> -	mutex_init(&tz->lock);
> >>> -	result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
> >>> -	if (result) {
> >>> -		kfree(tz);
> >>> -		return ERR_PTR(result);
> >>> -	}
> >>> -
> >>> -	strcpy(tz->type, type ? : "");
> >>> -	tz->ops = ops;
> >>> -	tz->tzp = tzp;
> >>> -	tz->device.class = &thermal_class;
> >>> -	tz->devdata = devdata;
> >>> -	tz->trips = trips;
> >>> -	tz->passive_delay = passive_delay;
> >>> -	tz->polling_delay = polling_delay;
> >>> -
> >>> -	dev_set_name(&tz->device, "thermal_zone%d", tz->id);
> >>> -	result = device_register(&tz->device);
> >>> -	if (result) {
> >>> -		release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> -		kfree(tz);
> >>> -		return ERR_PTR(result);
> >>> -	}
> >>> -
> >>> -	/* sys I/F */
> >>> -	if (type) {
> >>> -		result = device_create_file(&tz->device, &dev_attr_type);
> >>> -		if (result)
> >>> -			goto unregister;
> >>> -	}
> >>> -
> >>> -	result = device_create_file(&tz->device, &dev_attr_temp);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	if (ops->get_mode) {
> >>> -		result = device_create_file(&tz->device, &dev_attr_mode);
> >>> -		if (result)
> >>> -			goto unregister;
> >>> -	}
> >>> -
> >>> -	result = create_trip_attrs(tz, mask);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	for (count = 0; count < trips; count++) {
> >>> -		tz->ops->get_trip_type(tz, count, &trip_type);
> >>> -		if (trip_type == THERMAL_TRIP_PASSIVE)
> >>> -			passive = 1;
> >>> -	}
> >>> -
> >>> -	if (!passive) {
> >>> -		result = device_create_file(&tz->device, &dev_attr_passive);
> >>> -		if (result)
> >>> -			goto unregister;
> >>> -	}
> >>> -
> >>> -#ifdef CONFIG_THERMAL_EMULATION
> >>> -	result = device_create_file(&tz->device, &dev_attr_emul_temp);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -#endif
> >>> -	/* Create policy attribute */
> >>> -	result = device_create_file(&tz->device, &dev_attr_policy);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	/* Update 'this' zone's governor information */
> >>> -	mutex_lock(&thermal_governor_lock);
> >>> -
> >>> -	if (tz->tzp)
> >>> -		tz->governor = __find_governor(tz->tzp->governor_name);
> >>> -	else
> >>> -		tz->governor =
> __find_governor(DEFAULT_THERMAL_GOVERNOR);
> >>> -
> >>> -	mutex_unlock(&thermal_governor_lock);
> >>> -
> >>> -	result = thermal_add_hwmon_sysfs(tz);
> >>> -	if (result)
> >>> -		goto unregister;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_add_tail(&tz->node, &thermal_tz_list);
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	/* Bind cooling devices for this zone */
> >>> -	bind_tz(tz);
> >>> -
> >>> -	INIT_DELAYED_WORK(&(tz->poll_queue),
> thermal_zone_device_check);
> >>> -
> >>> -	thermal_zone_device_update(tz);
> >>> -
> >>> -	if (!result)
> >>> -		return tz;
> >>> -
> >>> -unregister:
> >>> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> -	device_unregister(&tz->device);
> >>> -	return ERR_PTR(result);
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_device_register);
> >>> -
> >>> -/**
> >>> - * thermal_device_unregister - removes the registered thermal zone
> device
> >>> - * @tz: the thermal zone device to remove
> >>> - */
> >>> -void thermal_zone_device_unregister(struct thermal_zone_device *tz)
> >>> -{
> >>> -	int i;
> >>> -	const struct thermal_zone_params *tzp;
> >>> -	struct thermal_cooling_device *cdev;
> >>> -	struct thermal_zone_device *pos = NULL;
> >>> -
> >>> -	if (!tz)
> >>> -		return;
> >>> -
> >>> -	tzp = tz->tzp;
> >>> -
> >>> -	mutex_lock(&thermal_list_lock);
> >>> -	list_for_each_entry(pos, &thermal_tz_list, node)
> >>> -	    if (pos == tz)
> >>> -		break;
> >>> -	if (pos != tz) {
> >>> -		/* thermal zone device not found */
> >>> -		mutex_unlock(&thermal_list_lock);
> >>> -		return;
> >>> -	}
> >>> -	list_del(&tz->node);
> >>> -
> >>> -	/* Unbind all cdevs associated with 'this' thermal zone */
> >>> -	list_for_each_entry(cdev, &thermal_cdev_list, node) {
> >>> -		if (tz->ops->unbind) {
> >>> -			tz->ops->unbind(tz, cdev);
> >>> -			continue;
> >>> -		}
> >>> -
> >>> -		if (!tzp || !tzp->tbp)
> >>> -			break;
> >>> -
> >>> -		for (i = 0; i < tzp->num_tbps; i++) {
> >>> -			if (tzp->tbp[i].cdev == cdev) {
> >>> -				__unbind(tz, tzp->tbp[i].trip_mask, cdev);
> >>> -				tzp->tbp[i].cdev = NULL;
> >>> -			}
> >>> -		}
> >>> -	}
> >>> -
> >>> -	mutex_unlock(&thermal_list_lock);
> >>> -
> >>> -	thermal_zone_device_set_polling(tz, 0);
> >>> -
> >>> -	if (tz->type[0])
> >>> -		device_remove_file(&tz->device, &dev_attr_type);
> >>> -	device_remove_file(&tz->device, &dev_attr_temp);
> >>> -	if (tz->ops->get_mode)
> >>> -		device_remove_file(&tz->device, &dev_attr_mode);
> >>> -	device_remove_file(&tz->device, &dev_attr_policy);
> >>> -	remove_trip_attrs(tz);
> >>> -	tz->governor = NULL;
> >>> -
> >>> -	thermal_remove_hwmon_sysfs(tz);
> >>> -	release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
> >>> -	idr_destroy(&tz->idr);
> >>> -	mutex_destroy(&tz->lock);
> >>> -	device_unregister(&tz->device);
> >>> -	return;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_zone_device_unregister);
> >>> -
> >>> -#ifdef CONFIG_NET
> >>> -static struct genl_family thermal_event_genl_family = {
> >>> -	.id = GENL_ID_GENERATE,
> >>> -	.name = THERMAL_GENL_FAMILY_NAME,
> >>> -	.version = THERMAL_GENL_VERSION,
> >>> -	.maxattr = THERMAL_GENL_ATTR_MAX,
> >>> -};
> >>> -
> >>> -static struct genl_multicast_group thermal_event_mcgrp = {
> >>> -	.name = THERMAL_GENL_MCAST_GROUP_NAME,
> >>> -};
> >>> -
> >>> -int thermal_generate_netlink_event(struct thermal_zone_device *tz,
> >>> -					enum events event)
> >>> -{
> >>> -	struct sk_buff *skb;
> >>> -	struct nlattr *attr;
> >>> -	struct thermal_genl_event *thermal_event;
> >>> -	void *msg_header;
> >>> -	int size;
> >>> -	int result;
> >>> -	static unsigned int thermal_event_seqnum;
> >>> -
> >>> -	if (!tz)
> >>> -		return -EINVAL;
> >>> -
> >>> -	/* allocate memory */
> >>> -	size = nla_total_size(sizeof(struct thermal_genl_event)) +
> >>> -	       nla_total_size(0);
> >>> -
> >>> -	skb = genlmsg_new(size, GFP_ATOMIC);
> >>> -	if (!skb)
> >>> -		return -ENOMEM;
> >>> -
> >>> -	/* add the genetlink message header */
> >>> -	msg_header = genlmsg_put(skb, 0, thermal_event_seqnum++,
> >>> -				 &thermal_event_genl_family, 0,
> >>> -				 THERMAL_GENL_CMD_EVENT);
> >>> -	if (!msg_header) {
> >>> -		nlmsg_free(skb);
> >>> -		return -ENOMEM;
> >>> -	}
> >>> -
> >>> -	/* fill the data */
> >>> -	attr = nla_reserve(skb, THERMAL_GENL_ATTR_EVENT,
> >>> -			   sizeof(struct thermal_genl_event));
> >>> -
> >>> -	if (!attr) {
> >>> -		nlmsg_free(skb);
> >>> -		return -EINVAL;
> >>> -	}
> >>> -
> >>> -	thermal_event = nla_data(attr);
> >>> -	if (!thermal_event) {
> >>> -		nlmsg_free(skb);
> >>> -		return -EINVAL;
> >>> -	}
> >>> -
> >>> -	memset(thermal_event, 0, sizeof(struct thermal_genl_event));
> >>> -
> >>> -	thermal_event->orig = tz->id;
> >>> -	thermal_event->event = event;
> >>> -
> >>> -	/* send multicast genetlink message */
> >>> -	result = genlmsg_end(skb, msg_header);
> >>> -	if (result < 0) {
> >>> -		nlmsg_free(skb);
> >>> -		return result;
> >>> -	}
> >>> -
> >>> -	result = genlmsg_multicast(skb, 0, thermal_event_mcgrp.id,
> GFP_ATOMIC);
> >>> -	if (result)
> >>> -		dev_err(&tz->device, "Failed to send netlink event:%d",
> result);
> >>> -
> >>> -	return result;
> >>> -}
> >>> -EXPORT_SYMBOL(thermal_generate_netlink_event);
> >>> -
> >>> -static int genetlink_init(void)
> >>> -{
> >>> -	int result;
> >>> -
> >>> -	result = genl_register_family(&thermal_event_genl_family);
> >>> -	if (result)
> >>> -		return result;
> >>> -
> >>> -	result = genl_register_mc_group(&thermal_event_genl_family,
> >>> -					&thermal_event_mcgrp);
> >>> -	if (result)
> >>> -		genl_unregister_family(&thermal_event_genl_family);
> >>> -	return result;
> >>> -}
> >>> -
> >>> -static void genetlink_exit(void)
> >>> -{
> >>> -	genl_unregister_family(&thermal_event_genl_family);
> >>> -}
> >>> -#else /* !CONFIG_NET */
> >>> -static inline int genetlink_init(void) { return 0; }
> >>> -static inline void genetlink_exit(void) {}
> >>> -#endif /* !CONFIG_NET */
> >>> -
> >>> -static int __init thermal_init(void)
> >>> -{
> >>> -	int result = 0;
> >>> -
> >>> -	result = class_register(&thermal_class);
> >>> -	if (result) {
> >>> -		idr_destroy(&thermal_tz_idr);
> >>> -		idr_destroy(&thermal_cdev_idr);
> >>> -		mutex_destroy(&thermal_idr_lock);
> >>> -		mutex_destroy(&thermal_list_lock);
> >>> -		return result;
> >>> -	}
> >>> -	result = genetlink_init();
> >>> -	return result;
> >>> -}
> >>> -
> >>> -static void __exit thermal_exit(void)
> >>> -{
> >>> -	class_unregister(&thermal_class);
> >>> -	idr_destroy(&thermal_tz_idr);
> >>> -	idr_destroy(&thermal_cdev_idr);
> >>> -	mutex_destroy(&thermal_idr_lock);
> >>> -	mutex_destroy(&thermal_list_lock);
> >>> -	genetlink_exit();
> >>> -}
> >>> -
> >>> -fs_initcall(thermal_init);
> >>> -module_exit(thermal_exit);
> >>>
> >>
> >
> >
> >
> >


^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2013-04-01 13:09 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-26 16:26 [RFC PATCH 0/5] Thermal: build all thermal framework code into thermal_sys module Zhang Rui
2013-03-26 16:26 ` [RFC PATCH 1/5] Thermal: rename thermal_sys.c to thermal_core.c Zhang Rui
2013-03-26 16:56   ` R, Durgadoss
2013-03-26 17:08     ` Zhang Rui
2013-03-26 22:04   ` [RFC,1/5] " Eduardo Valentin
2013-03-26 22:04     ` Eduardo Valentin
2013-03-28  2:40     ` Zhang Rui
2013-04-01 12:43       ` Eduardo Valentin
2013-04-01 12:43         ` Eduardo Valentin
2013-04-01 13:09         ` R, Durgadoss
2013-04-01 13:09           ` R, Durgadoss
2013-03-26 16:26 ` [RFC PATCH 2/5] Thermal: thermal framework registration failure case cleanup Zhang Rui
2013-03-26 22:22   ` [RFC, " Eduardo Valentin
2013-03-26 22:22     ` Eduardo Valentin
2013-03-26 16:26 ` [RFC PATCH 3/5] Thermal: build thermal governors into thermal_sys module Zhang Rui
2013-03-26 16:53   ` R, Durgadoss
2013-03-26 17:12     ` Zhang Rui
2013-03-26 22:31   ` [RFC,3/5] " Eduardo Valentin
2013-03-26 22:31     ` Eduardo Valentin
2013-03-26 16:26 ` [RFC PATCH 4/5] Thermal: governor API cleanup Zhang Rui
2013-03-26 22:35   ` [RFC,4/5] " Eduardo Valentin
2013-03-26 22:35     ` Eduardo Valentin
2013-03-26 16:26 ` [RFC PATCH 5/5] Thermal: build cpu_cooling code into thermal_sys module Zhang Rui

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.