Merge branch 'exynos-fix' of .git into next
authorZhang Rui <rui.zhang@intel.com>
Wed, 24 Apr 2013 16:04:06 +0000 (00:04 +0800)
committerZhang Rui <rui.zhang@intel.com>
Wed, 24 Apr 2013 16:04:06 +0000 (00:04 +0800)
20 files changed:
Documentation/devicetree/bindings/thermal/armada-thermal.txt [new file with mode: 0644]
Documentation/thermal/exynos_thermal_emulation
Documentation/thermal/sysfs-api.txt
drivers/thermal/Kconfig
drivers/thermal/Makefile
drivers/thermal/armada_thermal.c [new file with mode: 0644]
drivers/thermal/cpu_cooling.c
drivers/thermal/db8500_thermal.c
drivers/thermal/dove_thermal.c
drivers/thermal/exynos_thermal.c
drivers/thermal/fair_share.c
drivers/thermal/kirkwood_thermal.c
drivers/thermal/rcar_thermal.c
drivers/thermal/step_wise.c
drivers/thermal/thermal_core.c [new file with mode: 0644]
drivers/thermal/thermal_core.h
drivers/thermal/thermal_sys.c [deleted file]
drivers/thermal/user_space.c
include/linux/cpu_cooling.h
include/linux/thermal.h

diff --git a/Documentation/devicetree/bindings/thermal/armada-thermal.txt b/Documentation/devicetree/bindings/thermal/armada-thermal.txt
new file mode 100644 (file)
index 0000000..fff93d5
--- /dev/null
@@ -0,0 +1,22 @@
+* Marvell Armada 370/XP thermal management
+
+Required properties:
+
+- compatible:  Should be set to one of the following:
+               marvell,armada370-thermal
+               marvell,armadaxp-thermal
+
+- reg:         Device's register space.
+               Two entries are expected, see the examples below.
+               The first one is required for the sensor register;
+               the second one is required for the control register
+               to be used for sensor initialization (a.k.a. calibration).
+
+Example:
+
+       thermal@d0018300 {
+               compatible = "marvell,armada370-thermal";
+                reg = <0xd0018300 0x4
+                      0xd0018304 0x4>;
+               status = "okay";
+       };
index b73bbfb697bb233a92d409c53651e0f80acbeb9b..36a3e79c120354bb5c19d57919b814809a4e5026 100644 (file)
@@ -13,11 +13,11 @@ Thermal emulation mode supports software debug for TMU's operation. User can set
 manually with software code and TMU will read current temperature from user value not from
 sensor's value.
 
-Enabling CONFIG_EXYNOS_THERMAL_EMUL option will make this support in available.
-When it's enabled, sysfs node will be created under
-/sys/bus/platform/devices/'exynos device name'/ with name of 'emulation'.
+Enabling CONFIG_THERMAL_EMULATION option will make this support available.
+When it's enabled, sysfs node will be created as
+/sys/devices/virtual/thermal/thermal_zone'zone id'/emul_temp.
 
-The sysfs node, 'emulation', will contain value 0 for the initial state. When you input any
+The sysfs node, 'emul_node', will contain value 0 for the initial state. When you input any
 temperature you want to update to sysfs node, it automatically enable emulation mode and
 current temperature will be changed into it.
 (Exynos also supports user changable delay time which would be used to delay of
index 6859661c9d31be090a78e5a2c35a9a5fdad7ca80..b2ffe98cf469f7d3f0a105ea923ab319415f505c 100644 (file)
@@ -265,6 +265,10 @@ emul_temp
        Unit: millidegree Celsius
        WO, Optional
 
+         WARNING: Be careful while enabling this option on production systems,
+         because userland can easily disable the thermal policy by simply
+         flooding this sysfs node with low temperature values.
+
 *****************************
 * Cooling device attributes *
 *****************************
@@ -375,11 +379,3 @@ platform data is provided, this uses the step_wise throttling policy.
 This function serves as an arbitrator to set the state of a cooling
 device. It sets the cooling device to the deepest cooling state if
 possible.
-
-5.5:thermal_register_governor:
-This function lets the various thermal governors to register themselves
-with the Thermal framework. At run time, depending on a zone's platform
-data, a particular governor is used for throttling.
-
-5.6:thermal_unregister_governor:
-This function unregisters a governor from the thermal framework.
index a764f165b58930da5044c208693a86a817bab93f..d1c2160492aacb2dc4886dc8ee9c173235ace1df 100644 (file)
@@ -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
@@ -86,6 +86,10 @@ config THERMAL_EMULATION
          user can manually input temperature and test the different trip
          threshold behaviour for simulation purpose.
 
+         WARNING: Be careful while enabling this option on production systems,
+         because userland can easily disable the thermal policy by simply
+         flooding this sysfs node with low temperature values.
+
 config SPEAR_THERMAL
        bool "SPEAr thermal sensor driver"
        depends on PLAT_SPEAR
@@ -117,15 +121,6 @@ config EXYNOS_THERMAL
          If you say yes here you get support for TMU (Thermal Management
          Unit) on SAMSUNG EXYNOS series of SoC.
 
-config EXYNOS_THERMAL_EMUL
-       bool "EXYNOS TMU emulation mode support"
-       depends on EXYNOS_THERMAL
-       help
-         Exynos 4412 and 4414 and 5 series has emulation mode on TMU.
-         Enable this option will be make sysfs node in exynos thermal platform
-         device directory to support emulation mode. With emulation mode sysfs
-         node, you can manually input temperature to TMU for simulation purpose.
-
 config DOVE_THERMAL
        tristate "Temperature sensor on Marvell Dove SoCs"
        depends on ARCH_DOVE
@@ -144,6 +139,14 @@ config DB8500_THERMAL
          created. Cooling devices can be bound to the trip points to cool this
          thermal zone if trip points reached.
 
+config ARMADA_THERMAL
+       tristate "Armada 370/XP thermal management"
+       depends on ARCH_MVEBU
+       depends on OF
+       help
+         Enable this option if you want to have support for thermal management
+         controller present in Armada 370 and Armada XP SoC.
+
 config DB8500_CPUFREQ_COOLING
        tristate "DB8500 cpufreq cooling"
        depends on ARCH_U8500
index d3a2b38c31e86b694df71a4ccbb2b366025fb317..c054d410ac3f001e7192f63c0bf65767d55b22b3 100644 (file)
@@ -3,14 +3,15 @@
 #
 
 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
+thermal_sys-$(CONFIG_CPU_THERMAL)      += cpu_cooling.o
 
 # platform thermal drivers
 obj-$(CONFIG_SPEAR_THERMAL)    += spear_thermal.o
@@ -19,6 +20,7 @@ obj-$(CONFIG_KIRKWOOD_THERMAL)  += kirkwood_thermal.o
 obj-$(CONFIG_EXYNOS_THERMAL)   += exynos_thermal.o
 obj-$(CONFIG_DOVE_THERMAL)     += dove_thermal.o
 obj-$(CONFIG_DB8500_THERMAL)   += db8500_thermal.o
+obj-$(CONFIG_ARMADA_THERMAL)   += armada_thermal.o
 obj-$(CONFIG_DB8500_CPUFREQ_COOLING)   += db8500_cpufreq_cooling.o
 obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
 
diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c
new file mode 100644 (file)
index 0000000..5b4d75f
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Marvell Armada 370/XP thermal sensor driver
+ *
+ * Copyright (C) 2013 Marvell
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/of_device.h>
+#include <linux/thermal.h>
+
+#define THERMAL_VALID_OFFSET           9
+#define THERMAL_VALID_MASK             0x1
+#define THERMAL_TEMP_OFFSET            10
+#define THERMAL_TEMP_MASK              0x1ff
+
+/* Thermal Manager Control and Status Register */
+#define PMU_TDC0_SW_RST_MASK           (0x1 << 1)
+#define PMU_TM_DISABLE_OFFS            0
+#define PMU_TM_DISABLE_MASK            (0x1 << PMU_TM_DISABLE_OFFS)
+#define PMU_TDC0_REF_CAL_CNT_OFFS      11
+#define PMU_TDC0_REF_CAL_CNT_MASK      (0x1ff << PMU_TDC0_REF_CAL_CNT_OFFS)
+#define PMU_TDC0_OTF_CAL_MASK          (0x1 << 30)
+#define PMU_TDC0_START_CAL_MASK                (0x1 << 25)
+
+struct armada_thermal_ops;
+
+/* Marvell EBU Thermal Sensor Dev Structure */
+struct armada_thermal_priv {
+       void __iomem *sensor;
+       void __iomem *control;
+       struct armada_thermal_ops *ops;
+};
+
+struct armada_thermal_ops {
+       /* Initialize the sensor */
+       void (*init_sensor)(struct armada_thermal_priv *);
+
+       /* Test for a valid sensor value (optional) */
+       bool (*is_valid)(struct armada_thermal_priv *);
+};
+
+static void armadaxp_init_sensor(struct armada_thermal_priv *priv)
+{
+       unsigned long reg;
+
+       reg = readl_relaxed(priv->control);
+       reg |= PMU_TDC0_OTF_CAL_MASK;
+       writel(reg, priv->control);
+
+       /* Reference calibration value */
+       reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
+       reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
+       writel(reg, priv->control);
+
+       /* Reset the sensor */
+       reg = readl_relaxed(priv->control);
+       writel((reg | PMU_TDC0_SW_RST_MASK), priv->control);
+
+       writel(reg, priv->control);
+
+       /* Enable the sensor */
+       reg = readl_relaxed(priv->sensor);
+       reg &= ~PMU_TM_DISABLE_MASK;
+       writel(reg, priv->sensor);
+}
+
+static void armada370_init_sensor(struct armada_thermal_priv *priv)
+{
+       unsigned long reg;
+
+       reg = readl_relaxed(priv->control);
+       reg |= PMU_TDC0_OTF_CAL_MASK;
+       writel(reg, priv->control);
+
+       /* Reference calibration value */
+       reg &= ~PMU_TDC0_REF_CAL_CNT_MASK;
+       reg |= (0xf1 << PMU_TDC0_REF_CAL_CNT_OFFS);
+       writel(reg, priv->control);
+
+       reg &= ~PMU_TDC0_START_CAL_MASK;
+       writel(reg, priv->control);
+
+       mdelay(10);
+}
+
+static bool armada_is_valid(struct armada_thermal_priv *priv)
+{
+       unsigned long reg = readl_relaxed(priv->sensor);
+
+       return (reg >> THERMAL_VALID_OFFSET) & THERMAL_VALID_MASK;
+}
+
+static int armada_get_temp(struct thermal_zone_device *thermal,
+                         unsigned long *temp)
+{
+       struct armada_thermal_priv *priv = thermal->devdata;
+       unsigned long reg;
+
+       /* Valid check */
+       if (priv->ops->is_valid && !priv->ops->is_valid(priv)) {
+               dev_err(&thermal->device,
+                       "Temperature sensor reading not valid\n");
+               return -EIO;
+       }
+
+       reg = readl_relaxed(priv->sensor);
+       reg = (reg >> THERMAL_TEMP_OFFSET) & THERMAL_TEMP_MASK;
+       *temp = (3153000000UL - (10000000UL*reg)) / 13825;
+       return 0;
+}
+
+static struct thermal_zone_device_ops ops = {
+       .get_temp = armada_get_temp,
+};
+
+static const struct armada_thermal_ops armadaxp_ops = {
+       .init_sensor = armadaxp_init_sensor,
+};
+
+static const struct armada_thermal_ops armada370_ops = {
+       .is_valid = armada_is_valid,
+       .init_sensor = armada370_init_sensor,
+};
+
+static const struct of_device_id armada_thermal_id_table[] = {
+       {
+               .compatible = "marvell,armadaxp-thermal",
+               .data       = &armadaxp_ops,
+       },
+       {
+               .compatible = "marvell,armada370-thermal",
+               .data       = &armada370_ops,
+       },
+       {
+               /* sentinel */
+       },
+};
+MODULE_DEVICE_TABLE(of, armada_thermal_id_table);
+
+static int armada_thermal_probe(struct platform_device *pdev)
+{
+       struct thermal_zone_device *thermal;
+       const struct of_device_id *match;
+       struct armada_thermal_priv *priv;
+       struct resource *res;
+
+       match = of_match_device(armada_thermal_id_table, &pdev->dev);
+       if (!match)
+               return -ENODEV;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Failed to get platform resource\n");
+               return -ENODEV;
+       }
+
+       priv->sensor = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->sensor))
+               return PTR_ERR(priv->sensor);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res) {
+               dev_err(&pdev->dev, "Failed to get platform resource\n");
+               return -ENODEV;
+       }
+
+       priv->control = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(priv->control))
+               return PTR_ERR(priv->control);
+
+       priv->ops = (struct armada_thermal_ops *)match->data;
+       priv->ops->init_sensor(priv);
+
+       thermal = thermal_zone_device_register("armada_thermal", 0, 0,
+                                              priv, &ops, NULL, 0, 0);
+       if (IS_ERR(thermal)) {
+               dev_err(&pdev->dev,
+                       "Failed to register thermal zone device\n");
+               return PTR_ERR(thermal);
+       }
+
+       platform_set_drvdata(pdev, thermal);
+
+       return 0;
+}
+
+static int armada_thermal_exit(struct platform_device *pdev)
+{
+       struct thermal_zone_device *armada_thermal =
+               platform_get_drvdata(pdev);
+
+       thermal_zone_device_unregister(armada_thermal);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver armada_thermal_driver = {
+       .probe = armada_thermal_probe,
+       .remove = armada_thermal_exit,
+       .driver = {
+               .name = "armada_thermal",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(armada_thermal_id_table),
+       },
+};
+
+module_platform_driver(armada_thermal_driver);
+
+MODULE_AUTHOR("Ezequiel Garcia <ezequiel.garcia@free-electrons.com>");
+MODULE_DESCRIPTION("Armada 370/XP thermal driver");
+MODULE_LICENSE("GPL v2");
index 8dc44cbb3e09fe253546347e376c0834957efc1e..768b508f0d69e814af847f97e7a884bf0ce2f9c9 100644 (file)
@@ -108,54 +108,120 @@ static int is_cpufreq_valid(int cpu)
        return !cpufreq_get_policy(&policy, cpu);
 }
 
-/**
- * get_cpu_frequency - get the absolute value of frequency from level.
- * @cpu: cpu for which frequency is fetched.
- * @level: level of frequency, equals cooling state of cpu cooling device
- *     e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
- */
-static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
+enum cpufreq_cooling_property {
+       GET_LEVEL,
+       GET_FREQ,
+       GET_MAXL,
+};
+
+/*
+ * this is the common function to
+ * 1. get maximum cpu cooling states
+ * 2. translate frequency to cooling state
+ * 3. translate cooling state to frequency
+ * Note that the code may be not in good shape
+ * but it is written in this way in order to:
+ * a) reduce duplicate code as most of the code can be shared.
+ * b) make sure the logic is consistent when translating between
+ *    cooling states and frequencies.
+*/
+static int get_property(unsigned int cpu, unsigned long input,
+       unsigned int* output, enum cpufreq_cooling_property property)
 {
-       int ret = 0, i = 0;
-       unsigned long level_index;
-       bool descend = false;
+       int i, j;
+       unsigned long max_level = 0, level;
+       unsigned int freq = CPUFREQ_ENTRY_INVALID;
+       int descend = -1;
        struct cpufreq_frequency_table *table =
                                        cpufreq_frequency_get_table(cpu);
+       
+       if (!output)
+               return -EINVAL;
+
        if (!table)
-               return ret;
+               return -EINVAL;
 
-       while (table[i].frequency != CPUFREQ_TABLE_END) {
+       
+       for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+               /* ignore invalid entries */
                if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
                        continue;
 
-               /*check if table in ascending or descending order*/
-               if ((table[i + 1].frequency != CPUFREQ_TABLE_END) &&
-                       (table[i + 1].frequency < table[i].frequency)
-                       && !descend) {
-                       descend = true;
-               }
+               /* ignore duplicate entry */
+               if (freq == table[i].frequency)
+                       continue;
+
+               /* get the frequency order */
+               if (freq != CPUFREQ_ENTRY_INVALID && descend != -1)
+                       descend = !!(freq > table[i].frequency);
 
-               /*return if level matched and table in descending order*/
-               if (descend && i == level)
-                       return table[i].frequency;
-               i++;
+               freq = table[i].frequency;
+               max_level++;
        }
-       i--;
 
-       if (level > i || descend)
-               return ret;
-       level_index = i - level;
+       /* get max level */
+       if (property == GET_MAXL) {
+               *output = (unsigned int)max_level;
+               return 0;
+       }
+
+       if (property == GET_FREQ)
+               level = descend ? input : (max_level - input -1);
+
 
-       /*Scan the table in reverse order and match the level*/
-       while (i >= 0) {
+       for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
+               /* ignore invalid entry */
                if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
                        continue;
-               /*return if level matched*/
-               if (i == level_index)
-                       return table[i].frequency;
-               i--;
+
+               /* ignore duplicate entry */
+               if (freq == table[i].frequency)
+                       continue;
+
+               /* now we have a valid frequency entry */
+               freq = table[i].frequency;
+
+               if (property == GET_LEVEL && (unsigned int)input == freq) {
+                       /* get level by frequency */
+                       *output = descend ? j : (max_level - j - 1);
+                       return 0;
+               }
+               if (property == GET_FREQ && level == j) {
+                       /* get frequency by level */
+                       *output = freq;
+                       return 0;
+               }
+               j++;
        }
-       return ret;
+       return -EINVAL;
+}
+
+unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq)
+{
+       unsigned int val;
+
+       if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL))
+               return THERMAL_CSTATE_INVALID;
+       return (unsigned long)val;
+}
+
+EXPORT_SYMBOL(cpufreq_cooling_get_level);
+
+/**
+ * get_cpu_frequency - get the absolute value of frequency from level.
+ * @cpu: cpu for which frequency is fetched.
+ * @level: level of frequency, equals cooling state of cpu cooling device
+ *     e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc
+ */
+static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level)
+{
+       int ret = 0;
+       unsigned int freq;
+
+       ret = get_property(cpu, level, &freq, GET_FREQ);
+       if (ret)
+               return 0;
+       return freq;
 }
 
 /**
@@ -168,8 +234,8 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
                                unsigned long cooling_state)
 {
        unsigned int cpuid, clip_freq;
-       struct cpumask *maskPtr = &cpufreq_device->allowed_cpus;
-       unsigned int cpu = cpumask_any(maskPtr);
+       struct cpumask *mask = &cpufreq_device->allowed_cpus;
+       unsigned int cpu = cpumask_any(mask);
 
 
        /* Check if the old cooling action is same as new cooling action */
@@ -184,7 +250,7 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device,
        cpufreq_device->cpufreq_val = clip_freq;
        notify_device = cpufreq_device;
 
-       for_each_cpu(cpuid, maskPtr) {
+       for_each_cpu(cpuid, mask) {
                if (is_cpufreq_valid(cpuid))
                        cpufreq_update_policy(cpuid);
        }
@@ -235,31 +301,19 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev,
                                 unsigned long *state)
 {
        struct cpufreq_cooling_device *cpufreq_device = cdev->devdata;
-       struct cpumask *maskPtr = &cpufreq_device->allowed_cpus;
+       struct cpumask *mask = &cpufreq_device->allowed_cpus;
        unsigned int cpu;
-       struct cpufreq_frequency_table *table;
-       unsigned long count = 0;
-       int i = 0;
-
-       cpu = cpumask_any(maskPtr);
-       table = cpufreq_frequency_get_table(cpu);
-       if (!table) {
-               *state = 0;
-               return 0;
-       }
+       unsigned int count = 0;
+       int ret;
 
-       for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
-               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
-                       continue;
-               count++;
-       }
+       cpu = cpumask_any(mask);
 
-       if (count > 0) {
-               *state = --count;
-               return 0;
-       }
+       ret = get_property(cpu, 0, &count, GET_MAXL);
 
-       return -EINVAL;
+       if (count > 0)
+               *state = count;
+
+       return ret;
 }
 
 /**
index 61ce60a35921d8ca543bcc275a5b7d479b98fa4f..1e3b3bf9f993be5d1e3eee1404091883dd21751f 100644 (file)
@@ -419,7 +419,8 @@ static int db8500_thermal_probe(struct platform_device *pdev)
        low_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_LOW");
        if (low_irq < 0) {
                dev_err(&pdev->dev, "Get IRQ_HOTMON_LOW failed.\n");
-               return low_irq;
+               ret = low_irq;
+               goto out_unlock;
        }
 
        ret = devm_request_threaded_irq(&pdev->dev, low_irq, NULL,
@@ -427,13 +428,14 @@ static int db8500_thermal_probe(struct platform_device *pdev)
                "dbx500_temp_low", pzone);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to allocate temp low irq.\n");
-               return ret;
+               goto out_unlock;
        }
 
        high_irq = platform_get_irq_byname(pdev, "IRQ_HOTMON_HIGH");
        if (high_irq < 0) {
                dev_err(&pdev->dev, "Get IRQ_HOTMON_HIGH failed.\n");
-               return high_irq;
+               ret = high_irq;
+               goto out_unlock;
        }
 
        ret = devm_request_threaded_irq(&pdev->dev, high_irq, NULL,
@@ -441,15 +443,16 @@ static int db8500_thermal_probe(struct platform_device *pdev)
                "dbx500_temp_high", pzone);
        if (ret < 0) {
                dev_err(&pdev->dev, "Failed to allocate temp high irq.\n");
-               return ret;
+               goto out_unlock;
        }
 
        pzone->therm_dev = thermal_zone_device_register("db8500_thermal_zone",
                ptrips->num_trips, 0, pzone, &thdev_ops, NULL, 0, 0);
 
-       if (IS_ERR_OR_NULL(pzone->therm_dev)) {
+       if (IS_ERR(pzone->therm_dev)) {
                dev_err(&pdev->dev, "Register thermal zone device failed.\n");
-               return PTR_ERR(pzone->therm_dev);
+               ret = PTR_ERR(pzone->therm_dev);
+               goto out_unlock;
        }
        dev_info(&pdev->dev, "Thermal zone device registered.\n");
 
@@ -461,9 +464,11 @@ static int db8500_thermal_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, pzone);
        pzone->mode = THERMAL_DEVICE_ENABLED;
+
+out_unlock:
        mutex_unlock(&pzone->th_lock);
 
-       return 0;
+       return ret;
 }
 
 static int db8500_thermal_remove(struct platform_device *pdev)
index 3078c403b42d84029968b23ff20b39ebd4af295d..4b15a5f270dc71a021bde1b6e96e8656720d45bc 100644 (file)
@@ -107,12 +107,13 @@ static int dove_get_temp(struct thermal_zone_device *thermal,
        }
 
        /*
-        * Calculate temperature. See Section 8.10.1 of 88AP510,
-        * Documentation/arm/Marvell/README
+        * Calculate temperature. According to Marvell internal
+        * documentation the formula for this is:
+        * Celsius = (322-reg)/1.3625
         */
        reg = readl_relaxed(priv->sensor);
        reg = (reg >> DOVE_THERMAL_TEMP_OFFSET) & DOVE_THERMAL_TEMP_MASK;
-       *temp = ((2281638UL - (7298*reg)) / 10);
+       *temp = ((3220000000UL - (10000000UL * reg)) / 13625);
 
        return 0;
 }
index 3d6e32a9ccdc152aad65cdfc7c0c2bde5326a8de..d20ce9e614034ba4077d797b5584cfad4d994727 100644 (file)
@@ -39,8 +39,6 @@
 #include <linux/cpu_cooling.h>
 #include <linux/of.h>
 
-#include <plat/cpu.h>
-
 /* Exynos generic registers */
 #define EXYNOS_TMU_REG_TRIMINFO                0x0
 #define EXYNOS_TMU_REG_CONTROL         0x20
 #define IDLE_INTERVAL 10000
 #define MCELSIUS       1000
 
-#ifdef CONFIG_EXYNOS_THERMAL_EMUL
+#ifdef CONFIG_THERMAL_EMULATION
 #define EXYNOS_EMUL_TIME       0x57F0
 #define EXYNOS_EMUL_TIME_SHIFT 16
 #define EXYNOS_EMUL_DATA_SHIFT 8
 #define EXYNOS_EMUL_DATA_MASK  0xFF
 #define EXYNOS_EMUL_ENABLE     0x1
-#endif /* CONFIG_EXYNOS_THERMAL_EMUL */
+#endif /* CONFIG_THERMAL_EMULATION */
 
 /* CPU Zone information */
 #define PANIC_ZONE      4
@@ -145,6 +143,7 @@ struct      thermal_cooling_conf {
 struct thermal_sensor_conf {
        char name[SENSOR_NAME_LEN];
        int (*read_temperature)(void *data);
+       int (*write_emul_temp)(void *drv_data, unsigned long temp);
        struct thermal_trip_point_conf trip_data;
        struct thermal_cooling_conf cooling_data;
        void *private_data;
@@ -242,26 +241,6 @@ static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
        return ret;
 }
 
-static int exynos_get_frequency_level(unsigned int cpu, unsigned int freq)
-{
-       int i = 0, ret = -EINVAL;
-       struct cpufreq_frequency_table *table = NULL;
-#ifdef CONFIG_CPU_FREQ
-       table = cpufreq_frequency_get_table(cpu);
-#endif
-       if (!table)
-               return ret;
-
-       while (table[i].frequency != CPUFREQ_TABLE_END) {
-               if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
-                       continue;
-               if (table[i].frequency == freq)
-                       return i;
-               i++;
-       }
-       return ret;
-}
-
 /* Bind callback functions for thermal zone */
 static int exynos_bind(struct thermal_zone_device *thermal,
                        struct thermal_cooling_device *cdev)
@@ -288,8 +267,8 @@ static int exynos_bind(struct thermal_zone_device *thermal,
        /* Bind the thermal zone to the cpufreq cooling device */
        for (i = 0; i < tab_size; i++) {
                clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
-               level = exynos_get_frequency_level(0, clip_data->freq_clip_max);
-               if (level < 0)
+               level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
+               if (level == THERMAL_CSTATE_INVALID)
                        return 0;
                switch (GET_ZONE(i)) {
                case MONITOR_ZONE:
@@ -369,6 +348,23 @@ static int exynos_get_temp(struct thermal_zone_device *thermal,
        return 0;
 }
 
+/* Get temperature callback functions for thermal zone */
+static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
+                                               unsigned long temp)
+{
+       void *data;
+       int ret = -EINVAL;
+
+       if (!th_zone->sensor_conf) {
+               pr_info("Temperature sensor not initialised\n");
+               return -EINVAL;
+       }
+       data = th_zone->sensor_conf->private_data;
+       if (th_zone->sensor_conf->write_emul_temp)
+               ret = th_zone->sensor_conf->write_emul_temp(data, temp);
+       return ret;
+}
+
 /* Get the temperature trend */
 static int exynos_get_trend(struct thermal_zone_device *thermal,
                        int trip, enum thermal_trend *trend)
@@ -392,6 +388,7 @@ static struct thermal_zone_device_ops const exynos_dev_ops = {
        .bind = exynos_bind,
        .unbind = exynos_unbind,
        .get_temp = exynos_get_temp,
+       .set_emul_temp = exynos_set_emul_temp,
        .get_trend = exynos_get_trend,
        .get_mode = exynos_get_mode,
        .set_mode = exynos_set_mode,
@@ -714,6 +711,47 @@ static int exynos_tmu_read(struct exynos_tmu_data *data)
        return temp;
 }
 
+#ifdef CONFIG_THERMAL_EMULATION
+static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
+{
+       struct exynos_tmu_data *data = drv_data;
+       unsigned int reg;
+       int ret = -EINVAL;
+
+       if (data->soc == SOC_ARCH_EXYNOS4210)
+               goto out;
+
+       if (temp && temp < MCELSIUS)
+               goto out;
+
+       mutex_lock(&data->lock);
+       clk_enable(data->clk);
+
+       reg = readl(data->base + EXYNOS_EMUL_CON);
+
+       if (temp) {
+               temp /= MCELSIUS;
+
+               reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
+                       (temp_to_code(data, temp)
+                        << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
+       } else {
+               reg &= ~EXYNOS_EMUL_ENABLE;
+       }
+
+       writel(reg, data->base + EXYNOS_EMUL_CON);
+
+       clk_disable(data->clk);
+       mutex_unlock(&data->lock);
+       return 0;
+out:
+       return ret;
+}
+#else
+static int exynos_tmu_set_emulation(void *drv_data,    unsigned long temp)
+       { return -EINVAL; }
+#endif/*CONFIG_THERMAL_EMULATION*/
+
 static void exynos_tmu_work(struct work_struct *work)
 {
        struct exynos_tmu_data *data = container_of(work,
@@ -747,6 +785,7 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
 static struct thermal_sensor_conf exynos_sensor_conf = {
        .name                   = "exynos-therm",
        .read_temperature       = (int (*)(void *))exynos_tmu_read,
+       .write_emul_temp        = exynos_tmu_set_emulation,
 };
 
 #if defined(CONFIG_CPU_EXYNOS4210)
@@ -857,93 +896,6 @@ static inline struct  exynos_tmu_platform_data *exynos_get_driver_data(
                        platform_get_device_id(pdev)->driver_data;
 }
 
-#ifdef CONFIG_EXYNOS_THERMAL_EMUL
-static ssize_t exynos_tmu_emulation_show(struct device *dev,
-                                        struct device_attribute *attr,
-                                        char *buf)
-{
-       struct platform_device *pdev = container_of(dev,
-                                       struct platform_device, dev);
-       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-       unsigned int reg;
-       u8 temp_code;
-       int temp = 0;
-
-       if (data->soc == SOC_ARCH_EXYNOS4210)
-               goto out;
-
-       mutex_lock(&data->lock);
-       clk_enable(data->clk);
-       reg = readl(data->base + EXYNOS_EMUL_CON);
-       clk_disable(data->clk);
-       mutex_unlock(&data->lock);
-
-       if (reg & EXYNOS_EMUL_ENABLE) {
-               reg >>= EXYNOS_EMUL_DATA_SHIFT;
-               temp_code = reg & EXYNOS_EMUL_DATA_MASK;
-               temp = code_to_temp(data, temp_code);
-       }
-out:
-       return sprintf(buf, "%d\n", temp * MCELSIUS);
-}
-
-static ssize_t exynos_tmu_emulation_store(struct device *dev,
-                                       struct device_attribute *attr,
-                                       const char *buf, size_t count)
-{
-       struct platform_device *pdev = container_of(dev,
-                                       struct platform_device, dev);
-       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
-       unsigned int reg;
-       int temp;
-
-       if (data->soc == SOC_ARCH_EXYNOS4210)
-               goto out;
-
-       if (!sscanf(buf, "%d\n", &temp) || temp < 0)
-               return -EINVAL;
-
-       mutex_lock(&data->lock);
-       clk_enable(data->clk);
-
-       reg = readl(data->base + EXYNOS_EMUL_CON);
-
-       if (temp) {
-               /* Both CELSIUS and MCELSIUS type are available for input */
-               if (temp > MCELSIUS)
-                       temp /= MCELSIUS;
-
-               reg = (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT) |
-                       (temp_to_code(data, (temp / MCELSIUS))
-                        << EXYNOS_EMUL_DATA_SHIFT) | EXYNOS_EMUL_ENABLE;
-       } else {
-               reg &= ~EXYNOS_EMUL_ENABLE;
-       }
-
-       writel(reg, data->base + EXYNOS_EMUL_CON);
-
-       clk_disable(data->clk);
-       mutex_unlock(&data->lock);
-
-out:
-       return count;
-}
-
-static DEVICE_ATTR(emulation, 0644, exynos_tmu_emulation_show,
-                                       exynos_tmu_emulation_store);
-static int create_emulation_sysfs(struct device *dev)
-{
-       return device_create_file(dev, &dev_attr_emulation);
-}
-static void remove_emulation_sysfs(struct device *dev)
-{
-       device_remove_file(dev, &dev_attr_emulation);
-}
-#else
-static inline int create_emulation_sysfs(struct device *dev) { return 0; }
-static inline void remove_emulation_sysfs(struct device *dev) {}
-#endif
-
 static int exynos_tmu_probe(struct platform_device *pdev)
 {
        struct exynos_tmu_data *data;
@@ -1047,10 +999,6 @@ static int exynos_tmu_probe(struct platform_device *pdev)
                goto err_clk;
        }
 
-       ret = create_emulation_sysfs(&pdev->dev);
-       if (ret)
-               dev_err(&pdev->dev, "Failed to create emulation mode sysfs node\n");
-
        return 0;
 err_clk:
        platform_set_drvdata(pdev, NULL);
@@ -1062,8 +1010,6 @@ static int exynos_tmu_remove(struct platform_device *pdev)
 {
        struct exynos_tmu_data *data = platform_get_drvdata(pdev);
 
-       remove_emulation_sysfs(&pdev->dev);
-
        exynos_tmu_control(pdev, false);
 
        exynos_unregister_thermal();
index 792479f2b64b7d25b4e1f8a1ac68de8271c65f84..944ba2f340c83cfed436c569c949d58dc6a60dfe 100644 (file)
@@ -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");
index e5500edb528568a009597b9336fa3d951df852ac..dfeceaffbc03c3f462170d721124ad3b3eac1db9 100644 (file)
@@ -41,21 +41,21 @@ static int kirkwood_get_temp(struct thermal_zone_device *thermal,
        reg = readl_relaxed(priv->sensor);
 
        /* Valid check */
-       if (!(reg >> KIRKWOOD_THERMAL_VALID_OFFSET) &
-           KIRKWOOD_THERMAL_VALID_MASK) {
+       if (!((reg >> KIRKWOOD_THERMAL_VALID_OFFSET) &
+           KIRKWOOD_THERMAL_VALID_MASK)) {
                dev_err(&thermal->device,
                        "Temperature sensor reading not valid\n");
                return -EIO;
        }
 
        /*
-        * Calculate temperature. See Section 8.10.1 of the 88AP510,
-        * datasheet, which has the same sensor.
-        * Documentation/arm/Marvell/README
+        * Calculate temperature. According to Marvell internal
+        * documentation the formula for this is:
+        * Celsius = (322-reg)/1.3625
         */
        reg = (reg >> KIRKWOOD_THERMAL_TEMP_OFFSET) &
                KIRKWOOD_THERMAL_TEMP_MASK;
-       *temp = ((2281638UL - (7298*reg)) / 10);
+       *temp = ((3220000000UL - (10000000UL * reg)) / 13625);
 
        return 0;
 }
index 2cc5b6115e3e200d13955f8103b97a2ddf3c0514..8d7edd4c82285f2bce93fd811b013bb4f6a9a54a 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/reboot.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
@@ -377,6 +378,9 @@ static int rcar_thermal_probe(struct platform_device *pdev)
        spin_lock_init(&common->lock);
        common->dev = dev;
 
+       pm_runtime_enable(dev);
+       pm_runtime_get_sync(dev);
+
        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (irq) {
                int ret;
@@ -419,12 +423,15 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
                if (!priv) {
                        dev_err(dev, "Could not allocate priv\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error_unregister;
                }
 
                priv->base = devm_ioremap_resource(dev, res);
-               if (IS_ERR(priv->base))
-                       return PTR_ERR(priv->base);
+               if (IS_ERR(priv->base)) {
+                       ret = PTR_ERR(priv->base);
+                       goto error_unregister;
+               }
 
                priv->common = common;
                priv->id = i;
@@ -443,10 +450,10 @@ static int rcar_thermal_probe(struct platform_device *pdev)
                        goto error_unregister;
                }
 
-               list_move_tail(&priv->list, &common->head);
-
                if (rcar_has_irq_support(priv))
                        rcar_thermal_irq_enable(priv);
+
+               list_move_tail(&priv->list, &common->head);
        }
 
        platform_set_drvdata(pdev, common);
@@ -456,8 +463,14 @@ static int rcar_thermal_probe(struct platform_device *pdev)
        return 0;
 
 error_unregister:
-       rcar_thermal_for_each_priv(priv, common)
+       rcar_thermal_for_each_priv(priv, common) {
                thermal_zone_device_unregister(priv->zone);
+               if (rcar_has_irq_support(priv))
+                       rcar_thermal_irq_disable(priv);
+       }
+
+       pm_runtime_put_sync(dev);
+       pm_runtime_disable(dev);
 
        return ret;
 }
@@ -465,13 +478,20 @@ error_unregister:
 static int rcar_thermal_remove(struct platform_device *pdev)
 {
        struct rcar_thermal_common *common = platform_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
        struct rcar_thermal_priv *priv;
 
-       rcar_thermal_for_each_priv(priv, common)
+       rcar_thermal_for_each_priv(priv, common) {
                thermal_zone_device_unregister(priv->zone);
+               if (rcar_has_irq_support(priv))
+                       rcar_thermal_irq_disable(priv);
+       }
 
        platform_set_drvdata(pdev, NULL);
 
+       pm_runtime_put_sync(dev);
+       pm_runtime_disable(dev);
+
        return 0;
 }
 
index 407cde3211c1bccfcf1e43515fb0a47a5a99e67c..4d4ddae1a99183cee9705f24e7acdc91cde62cc6 100644 (file)
@@ -22,9 +22,6 @@
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
 #include <linux/thermal.h>
 
 #include "thermal_core.h"
@@ -59,9 +56,12 @@ static unsigned long get_target_state(struct thermal_instance *instance,
 
        switch (trend) {
        case THERMAL_TREND_RAISING:
-               if (throttle)
+               if (throttle) {
                        cur_state = cur_state < instance->upper ?
                                    (cur_state + 1) : instance->upper;
+                       if (cur_state < instance->lower)
+                               cur_state = instance->lower;
+               }
                break;
        case THERMAL_TREND_RAISE_FULL:
                if (throttle)
@@ -71,8 +71,11 @@ static unsigned long get_target_state(struct thermal_instance *instance,
                if (cur_state == instance->lower) {
                        if (!throttle)
                                cur_state = -1;
-               } else
+               } else {
                        cur_state -= 1;
+                       if (cur_state > instance->upper)
+                               cur_state = instance->upper;
+               }
                break;
        case THERMAL_TREND_DROP_FULL:
                if (cur_state == instance->lower) {
@@ -180,23 +183,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
new file mode 100644 (file)
index 0000000..c0779ad
--- /dev/null
@@ -0,0 +1,1977 @@
+/*
+ *  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;
+}
+
+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;
+}
+
+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);
+}
+
+/**
+ * thermal_zone_get_temp() - returns its the temperature of thermal zone
+ * @tz: a valid pointer to a struct thermal_zone_device
+ * @temp: a valid pointer to where to store the resulting temperature.
+ *
+ * When a valid thermal zone reference is passed, it will fetch its
+ * temperature and fill @temp.
+ *
+ * Return: On success returns 0, an error code otherwise
+ */
+int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
+{
+       int ret = -EINVAL;
+#ifdef CONFIG_THERMAL_EMULATION
+       int count;
+       unsigned long crit_temp = -1UL;
+       enum thermal_trip_type type;
+#endif
+
+       if (IS_ERR_OR_NULL(tz))
+               goto exit;
+
+       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);
+exit:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
+
+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);
+
+/**
+ * thermal_zone_get_zone_by_name() - search for a zone and returns its ref
+ * @name: thermal zone name to fetch the temperature
+ *
+ * When only one zone is found with the passed name, returns a reference to it.
+ *
+ * Return: On success returns a reference to an unique thermal zone with
+ * matching name equals to @name, an ERR_PTR otherwise (-EINVAL for invalid
+ * paramenters, -ENODEV for not found and -EEXIST for multiple matches).
+ */
+struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name)
+{
+       struct thermal_zone_device *pos = NULL, *ref = ERR_PTR(-EINVAL);
+       unsigned int found = 0;
+
+       if (!name)
+               goto exit;
+
+       mutex_lock(&thermal_list_lock);
+       list_for_each_entry(pos, &thermal_tz_list, node)
+               if (!strnicmp(name, pos->type, THERMAL_NAME_LENGTH)) {
+                       found++;
+                       ref = pos;
+               }
+       mutex_unlock(&thermal_list_lock);
+
+       /* nothing has been found, thus an error code for it */
+       if (found == 0)
+               ref = ERR_PTR(-ENODEV);
+       else if (found > 1)
+       /* Success only when an unique zone is found */
+               ref = ERR_PTR(-EEXIST);
+
+exit:
+       return ref;
+}
+EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);
+
+#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_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;
+
+       return thermal_gov_user_space_register();
+}
+
+static void 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;
+
+       result = thermal_register_governors();
+       if (result)
+               goto error;
+
+       result = class_register(&thermal_class);
+       if (result)
+               goto unregister_governors;
+
+       result = genetlink_init();
+       if (result)
+               goto unregister_class;
+
+       return 0;
+
+unregister_governors:
+       thermal_unregister_governors();
+unregister_class:
+       class_unregister(&thermal_class);
+error:
+       idr_destroy(&thermal_tz_idr);
+       idr_destroy(&thermal_cdev_idr);
+       mutex_destroy(&thermal_idr_lock);
+       mutex_destroy(&thermal_list_lock);
+       mutex_destroy(&thermal_governor_lock);
+       return result;
+}
+
+static void __exit thermal_exit(void)
+{
+       genetlink_exit();
+       class_unregister(&thermal_class);
+       thermal_unregister_governors();
+       idr_destroy(&thermal_tz_idr);
+       idr_destroy(&thermal_cdev_idr);
+       mutex_destroy(&thermal_idr_lock);
+       mutex_destroy(&thermal_list_lock);
+       mutex_destroy(&thermal_governor_lock);
+}
+
+fs_initcall(thermal_init);
+module_exit(thermal_exit);
index 0d3205a18112a00820fce0da168bf54aea1fa3a6..7cf2f66262517a0bfcc2727dee8232edcd2ec6d7 100644 (file)
@@ -50,4 +50,31 @@ struct thermal_instance {
        struct list_head cdev_node; /* node in cdev->thermal_instances */
 };
 
+int thermal_register_governor(struct thermal_governor *);
+void thermal_unregister_governor(struct thermal_governor *);
+
+#ifdef CONFIG_THERMAL_GOV_STEP_WISE
+int thermal_gov_step_wise_register(void);
+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
+int thermal_gov_fair_share_register(void);
+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
+int thermal_gov_user_space_register(void);
+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/thermal_sys.c b/drivers/thermal/thermal_sys.c
deleted file mode 100644 (file)
index 5b7863a..0000000
+++ /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);
index 6bbb380b6d19ecf0c6e1e245dceee040c08e2a3b..10adcddc88211e9589f27b1ab6c79eaa75cb7fe7 100644 (file)
@@ -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");
index 40b4ef54cc7d50661553545724951e4e47b4c4e8..77c87c9d019341443e1e37712df9a16d33fd5eb1 100644 (file)
@@ -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
@@ -42,6 +42,8 @@ struct thermal_cooling_device *cpufreq_cooling_register(
  * @cdev: thermal cooling device pointer.
  */
 void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev);
+
+unsigned long cpufreq_cooling_get_level(unsigned int, unsigned int);
 #else /* !CONFIG_CPU_THERMAL */
 static inline struct thermal_cooling_device *cpufreq_cooling_register(
        const struct cpumask *clip_cpus)
@@ -53,6 +55,11 @@ static inline void cpufreq_cooling_unregister(
 {
        return;
 }
+static inline unsigned long cpufreq_cooling_get_level(unsigned int,
+                                                unsigned int)
+{
+       return THERMAL_CSTATE_INVALID;
+}
 #endif /* CONFIG_CPU_THERMAL */
 
 #endif /* __CPU_COOLING_H__ */
index f0bd7f90a90d45d3aeeb3aed8bc2d2f8295c8be0..ec2b886f9d9675a9f4d743662086681a19216511 100644 (file)
 #define THERMAL_MAX_TRIPS      12
 #define THERMAL_NAME_LENGTH    20
 
+/* invalid cooling state */
+#define THERMAL_CSTATE_INVALID -1UL
+
 /* No upper/lower limit requirement */
-#define THERMAL_NO_LIMIT       -1UL
+#define THERMAL_NO_LIMIT       THERMAL_CSTATE_INVALID
 
 /* Unit conversion macros */
 #define KELVIN_TO_CELSIUS(t)   (long)(((long)t-2732 >= 0) ?    \
@@ -184,7 +187,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 */
@@ -237,6 +239,8 @@ void thermal_zone_device_update(struct thermal_zone_device *);
 struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
                const struct thermal_cooling_device_ops *);
 void thermal_cooling_device_unregister(struct thermal_cooling_device *);
+struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
+int thermal_zone_get_temp(struct thermal_zone_device *tz, unsigned long *temp);
 
 int get_tz_trend(struct thermal_zone_device *, int);
 struct thermal_instance *get_thermal_instance(struct thermal_zone_device *,
@@ -244,14 +248,11 @@ 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);
 #else
-static int thermal_generate_netlink_event(struct thermal_zone_device *tz,
+static inline int thermal_generate_netlink_event(struct thermal_zone_device *tz,
                                                enum events event)
 {
        return 0;
This page took 0.084611 seconds and 5 git commands to generate.