]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
ENGR00155627 [MX6]Add thermal cooling device
authorAnson Huang <b20788@freescale.com>
Thu, 1 Sep 2011 02:00:58 +0000 (10:00 +0800)
committerOliver Wendt <ow@karo-electronics.de>
Mon, 30 Sep 2013 12:09:34 +0000 (14:09 +0200)
Add anatop thermal cooling device,currently only
support secondary CPUs hotplug when temperature is
too hot,binding the processor cooling device with
anatop thermal zone.

Signed-off-by: Anson Huang <b20788@freescale.com>
drivers/mxc/thermal/Makefile
drivers/mxc/thermal/anatop_driver.h
drivers/mxc/thermal/cooling.c [new file with mode: 0644]
drivers/mxc/thermal/thermal.c

index aed4877c6bef7cd560b88e1067cd77be96a0cb96..4823d6d569c13b416d356de373ec5539023edd47 100644 (file)
@@ -2,4 +2,4 @@
 # Makefile for i.MX ANATOP
 #
 
-obj-$(CONFIG_ANATOP_THERMAL)   += thermal.o
+obj-$(CONFIG_ANATOP_THERMAL)   += thermal.o cooling.o
index ecdd941c88b6552a63c7c0c5b27d705498987a55..51837cc1fdce84f4eb0a2141b4c3ea681372724d 100644 (file)
@@ -1,9 +1,8 @@
 /*
- *  acpi_drivers.h  ($Revision: 31 $)
+ *  anatop_drivers.h
  *
  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
- *
  *  Copyright (C) 2011 Freescale Semiconductor, Inc.
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  *
 typedef void *anatop_handle;   /* Actually a ptr to a NS Node */
 
 /* Device */
-#define ACPI_MAX_HANDLES       10
+#define ANATOP_MAX_HANDLES     10
+#define ANATOP_DEVICE_ID_LENGTH        0x09
+
 struct anatop_handle_list {
        u32 count;
-       anatop_handle handles[ACPI_MAX_HANDLES];
+       anatop_handle handles[ANATOP_MAX_HANDLES];
 };
 
 struct anatop_device {
@@ -45,8 +46,7 @@ struct anatop_device {
        void *driver_data;
 };
 struct anatop_device_id {
-       __u8 id[ACPI_ID_LEN];
-       kernel_ulong_t driver_data;
+       __u8 id[ANATOP_DEVICE_ID_LENGTH];
 };
 typedef int (*anatop_op_add) (struct anatop_device *device);
 typedef int (*anatop_op_remove) (struct anatop_device *device, int type);
@@ -77,7 +77,7 @@ struct anatop_device_ops {
 struct anatop_driver {
        char name[80];
        char class[80];
-       const struct acpi_device_id *ids; /* Supported Hardware IDs */
+       const struct anatop_device_id *ids; /* Supported Hardware IDs */
        unsigned int flags;
        struct anatop_device_ops ops;
        struct device_driver drv;
@@ -94,10 +94,7 @@ typedef u32 anatop_status;   /* All ANATOP Exceptions */
 
 #define ANATOP_MAX_STRING                      80
 
-/*
- * Please update drivers/acpi/debug.c and Documentation/acpi/debug.txt
- * if you add to this list.
- */
+
 #define ANATOP_BUS_COMPONENT           0x00010000
 #define ANATOP_AC_COMPONENT            0x00020000
 #define ANATOP_BATTERY_COMPONENT               0x00040000
@@ -113,11 +110,6 @@ typedef u32 anatop_status; /* All ANATOP Exceptions */
 #define ANATOP_VIDEO_COMPONENT         0x10000000
 #define ANATOP_PROCESSOR_COMPONENT     0x20000000
 
-/*
- * _HID definitions
- * HIDs must conform to ACPI spec(6.1.4)
- * Linux specific HIDs do not apply to this and begin with LNX:
- */
 
 #define ANATOP_POWER_HID                       "LNXPOWER"
 #define ANATOP_PROCESSOR_OBJECT_HID    "LNXCPU"
@@ -131,14 +123,6 @@ typedef u32 anatop_status; /* All ANATOP Exceptions */
 /* Quirk for broken IBM BIOSes */
 #define ANATOP_SMBUS_IBM_HID           "SMBUSIBM"
 
-/*
- * For fixed hardware buttons, we fabricate acpi_devices with HID
- * ACPI_BUTTON_HID_POWERF or ACPI_BUTTON_HID_SLEEPF.  Fixed hardware
- * signals only an event; it doesn't supply a notification value.
- * To allow drivers to treat notifications from fixed hardware the
- * same as those from real devices, we turn the events into this
- * notification value.
- */
 #define ANATOP_FIXED_HARDWARE_EVENT    0x100
 
 static inline void *anatop_driver_data(struct anatop_device *d)
@@ -146,4 +130,9 @@ static inline void *anatop_driver_data(struct anatop_device *d)
        return d->driver_data;
 }
 
+extern void anatop_thermal_cpufreq_init(void);
+extern int anatop_thermal_cpu_hotplug(bool cpu_on);
+extern struct thermal_cooling_device_ops imx_processor_cooling_ops;
+extern void arch_reset(char mode, const char *cmd);
+
 #endif /*__ANATOP_DRIVERS_H__*/
diff --git a/drivers/mxc/thermal/cooling.c b/drivers/mxc/thermal/cooling.c
new file mode 100644 (file)
index 0000000..b1d90be
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/thermal.h>
+#include <linux/syscalls.h>
+#include "anatop_driver.h"
+
+#define        CPUx_SHUTDOWN           "/sys/devices/system/cpu/cpu"
+
+extern unsigned long temperature_hotplug;
+static unsigned char cpu_shutdown[40];
+static unsigned int cpu_mask;
+static unsigned int anatop_thermal_cpufreq_is_init;
+static DEFINE_PER_CPU(unsigned int, cpufreq_thermal_reduction_pctg);
+
+int anatop_thermal_cpu_hotplug(bool cpu_on)
+{
+       unsigned int ret, i;
+       char online;
+       char cpu_number[9];
+       int fd;
+
+       ret = -EINVAL;
+       if (cpu_on) {
+               for (i = 1; i < 4; i++) {
+                       strcpy(cpu_shutdown, CPUx_SHUTDOWN);
+                       sprintf(cpu_number, "%d%s", i, "/online");
+                       strcat(cpu_shutdown, cpu_number);
+                       fd = sys_open((const char __user __force *)cpu_shutdown,
+                         O_RDWR, 0700);
+                       if (fd >= 0) {
+                               sys_read(fd, &online, 1);
+                               if (online == '0') {
+                                       sys_write(fd, (char *)"1", 1);
+                                       cpu_mask &= ~(0x1 << i);
+                                       ret = 0;
+                                       break;
+                               }
+                               sys_close(fd);
+                       }
+               }
+       } else {
+               for (i = 3; i > 0; i--) {
+                       strcpy(cpu_shutdown, CPUx_SHUTDOWN);
+                       sprintf(cpu_number, "%d%s", i, "/online");
+                       strcat(cpu_shutdown, cpu_number);
+                       fd = sys_open((const char __user __force *)cpu_shutdown,
+                                       O_RDWR, 0700);
+                       if (fd >= 0) {
+                               sys_read(fd, &online, 1);
+                               if (online == '1') {
+                                       sys_write(fd, (char *)"0", 1);
+                                       cpu_mask |= 0x1 << i;
+                                       ret = 0;
+                                       break;
+                               }
+                               sys_close(fd);
+                       }
+               }
+       }
+       return ret;
+}
+
+static int
+imx_processor_get_max_state(struct thermal_cooling_device *cdev,
+                       unsigned long *state)
+{
+       *state = cpu_mask | (0x1 << 1) | (0x1 << 2) | (0x1 << 3);
+       return 0;
+}
+
+static int
+imx_processor_get_cur_state(struct thermal_cooling_device *cdev,
+                       unsigned long *cur_state)
+{
+       *cur_state = cpu_mask;
+       return 0;
+}
+
+static int
+imx_processor_set_cur_state(struct thermal_cooling_device *cdev,
+                       unsigned long state)
+{
+       int result = 0;
+       int i;
+
+       /* state =0 means we are at a low temp, we should try to attach the
+       secondary CPUs that detached by thermal driver */
+       if (!state) {
+               for (i = 1; i < 4; i++) {
+                       if (cpu_mask && (0x1 << i)) {
+                               anatop_thermal_cpu_hotplug(true);
+                               temperature_hotplug = 0;
+                               break;
+                       }
+               }
+       } else
+               printk(KERN_DEBUG "Temperature is about to reach hot point!\n");
+       return result;
+}
+
+static int anatop_thermal_cpufreq_notifier(struct notifier_block *nb,
+                                        unsigned long event, void *data)
+{
+       struct cpufreq_policy *policy = data;
+       unsigned long max_freq = 0;
+
+       if (event != CPUFREQ_ADJUST)
+               goto out;
+
+       max_freq = (
+           policy->cpuinfo.max_freq *
+           (100 - per_cpu(cpufreq_thermal_reduction_pctg, policy->cpu) * 20)
+       ) / 100;
+
+       cpufreq_verify_within_limits(policy, 0, max_freq);
+
+out:
+       return 0;
+}
+static struct notifier_block anatop_thermal_cpufreq_notifier_block = {
+       .notifier_call = anatop_thermal_cpufreq_notifier,
+};
+
+void anatop_thermal_cpufreq_init(void)
+{
+       int i;
+
+       for (i = 0; i < nr_cpu_ids; i++)
+               if (cpu_present(i))
+                       per_cpu(cpufreq_thermal_reduction_pctg, i) = 0;
+
+       i = cpufreq_register_notifier(&anatop_thermal_cpufreq_notifier_block,
+                                     CPUFREQ_POLICY_NOTIFIER);
+       if (!i)
+               anatop_thermal_cpufreq_is_init = 1;
+}
+
+void anatop_thermal_cpufreq_exit(void)
+{
+       if (anatop_thermal_cpufreq_is_init)
+               cpufreq_unregister_notifier
+                   (&anatop_thermal_cpufreq_notifier_block,
+                    CPUFREQ_POLICY_NOTIFIER);
+
+       anatop_thermal_cpufreq_is_init = 0;
+}
+
+struct thermal_cooling_device_ops imx_processor_cooling_ops = {
+       .get_max_state = imx_processor_get_max_state,
+       .get_cur_state = imx_processor_get_cur_state,
+       .set_cur_state = imx_processor_set_cur_state,
+};
+
index c5566223a3376ed9775976e74337b2174f0dd1a5..84c7a631ed6294b983dfb36420ec9f526540fe9c 100644 (file)
  *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  *
  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  This driver fully implements the anatop thermal policy as described in the
- *  anatop 2.0 Specification.
- *
- *  TBD: 1. Implement passive cooling hysteresis.
- *       2. Enhance passive cooling (CPU) states/limit interface to support
- *          concepts of 'multiple limiters', upper/lower limits, etc.
- *
  */
 
 #include <linux/kernel.h>
@@ -46,6 +38,8 @@
 #include <linux/thermal.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
+#include <linux/syscalls.h>
+#include <linux/cpufreq.h>
 #include "anatop_driver.h"
 
 /* register define of anatop */
 #define BF_ANADIG_TEMPSENSE1_MEASURE_FREQ(v)  \
        (((v) << 0) & BM_ANADIG_TEMPSENSE1_MEASURE_FREQ)
 
-
+/* define */
 #define PREFIX "ANATOP: "
-
 #define ANATOP_THERMAL_DRIVER_NAME     "Anatop Thermal"
-#define ANATOP_THERMAL_DEVICE_NAME     "Thermal Zone"
 #define ANATOP_THERMAL_FILE_STATE              "state"
 #define ANATOP_THERMAL_FILE_TEMPERATURE        "temperature"
 #define ANATOP_THERMAL_FILE_TRIP_POINTS        "trip_points"
 #define ANATOP_THERMAL_NOTIFY_CRITICAL 0xF0
 #define ANATOP_THERMAL_NOTIFY_HOT              0xF1
 #define ANATOP_THERMAL_MODE_ACTIVE     0x00
-
 #define ANATOP_THERMAL_MAX_ACTIVE      10
 #define ANATOP_THERMAL_MAX_LIMIT_STR_LEN 65
+#define ANATOP_TRIPS_CRITICAL  0x01
+#define ANATOP_TRIPS_HOT               0x02
+#define ANATOP_TRIPS_PASSIVE   0x04
+#define ANATOP_TRIPS_ACTIVE        0x08
+#define ANATOP_TRIPS_DEVICES   0x10
+
+#define ANATOP_TRIPS_POINT_CRITICAL    0x0
+#define ANATOP_TRIPS_POINT_HOT     0x1
+#define ANATOP_TRIPS_POINT_ACTIVE      0x2
+
+#define ANATOP_TRIPS_INIT      (ANATOP_TRIPS_CRITICAL | \
+               ANATOP_TRIPS_HOT | ANATOP_TRIPS_ACTIVE)
 
 #define _COMPONENT             ANATOP_THERMAL_COMPONENT
-#define POLLING_FREQ                   20
-#define TEMP_CRITICAL_SHUTDOWN 380
-#define TEMP_CRITICAL_SLEEP            360
-#define TEMP_PASSIVE                   320
+#define KELVIN_OFFSET                  273
+#define POLLING_FREQ                   2000 /* 2s */
+#define TEMP_CRITICAL                  323 /* 50 C*/
+#define TEMP_HOT                               313 /* 40 C*/
+#define TEMP_ACTIVE                            303 /* 30 C*/
 #define MEASURE_FREQ                   327  /* 327 RTC clocks delay, 10ms */
-#define CONVER_CONST                   1413  /* rough value, need calibration */
-#define CONVER_DIV_1024                        550  /* div value, need calibration */
-
+#define CONVER_CONST                   14113  /* need calibration */
+#define CONVER_DIV                             17259
+#define KELVIN_TO_CEL(t, off) (((t) - (off)))
+#define CEL_TO_KELVIN(t, off) (((t) + (off)))
+#define REG_VALUE_TO_CEL(val) (((CONVER_CONST - val * 10)\
+                       * 1000) / CONVER_DIV);
 #define ANATOP_DEBUG   false
 
-MODULE_AUTHOR("Anson Huang");
-MODULE_DESCRIPTION("ANATOP Thermal Zone Driver");
-MODULE_LICENSE("GPL");
-
-static int psv;
+/* variables */
 unsigned long anatop_base;
+static bool full_run = true;
+unsigned long temperature_hotplug;
+static const struct anatop_device_id thermal_device_ids[] = {
+       {ANATOP_THERMAL_HID},
+       {""},
+};
 
-module_param(psv, int, 0644);
-MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
-
+/* functions */
 static int anatop_thermal_add(struct anatop_device *device);
 static int anatop_thermal_remove(struct platform_device *pdev);
 static int anatop_thermal_suspend(struct platform_device *pdev,
-       pm_message_t state);
+               pm_message_t state);
 static int anatop_thermal_resume(struct platform_device *pdev);
-/* static void anatop_thermal_notify(struct anatop_device *device,
- * u32 event); */
-static int anatop_thermal_power_on(void);
-static int anatop_thermal_power_down(void);
-
-static const struct anatop_device_id thermal_device_ids[] = {
-       {ANATOP_THERMAL_HID, 0},
-       {"", 0},
-};
-MODULE_DEVICE_TABLE(anatop, thermal_device_ids);
 
+/* struct */
 struct anatop_thermal_state {
        u8 critical:1;
        u8 hot:1;
@@ -187,12 +185,12 @@ struct anatop_thermal_trips {
        struct anatop_thermal_critical critical;
        struct anatop_thermal_hot hot;
        struct anatop_thermal_passive passive;
-       struct anatop_thermal_active active[ANATOP_THERMAL_MAX_ACTIVE];
+       struct anatop_thermal_active active;
 };
 
 struct anatop_thermal_flags {
-       u8 cooling_mode:1;      /* _SCP */
-       u8 devices:1;           /* _TZD */
+       u8 cooling_mode:1;
+       u8 devices:1;
        u8 reserved:6;
 };
 
@@ -212,32 +210,26 @@ struct anatop_thermal {
        struct mutex lock;
 };
 
-/* -----------------------------------------------------------
-                       Thermal Zone Management
-   ----------------------------------------------------------- */
+/***************************************************************
+                                               Function
+****************************************************************/
 static int anatop_dump_temperature_register(void)
 {
        if (!anatop_base) {
                pr_info("anatop_base is not initialized!!!\n");
                return -EINVAL;
        }
-
        pr_info("HW_ANADIG_TEMPSENSE0 = 0x%x\n",
                        __raw_readl(anatop_base + HW_ANADIG_TEMPSENSE0));
        pr_info("HW_ANADIG_TEMPSENSE1 = 0x%x\n",
                        __raw_readl(anatop_base + HW_ANADIG_TEMPSENSE1));
        return 0;
 }
-static int anatop_tempsense_value_to_dc(int val)
-{
-       int val_dc;
-       val_dc = (CONVER_CONST - val) * CONVER_DIV_1024 / 1024;
-
-       return val_dc;
-}
-static int anatop_thermal_get_temperature(struct anatop_thermal *tz)
+static int anatop_thermal_get_temp(struct thermal_zone_device *thermal,
+                           unsigned long *temp)
 {
-       unsigned int tmp = 300;
+       struct anatop_thermal *tz = thermal->devdata;
+       unsigned int tmp;
        unsigned int reg;
        unsigned int i;
        if (!tz)
@@ -247,7 +239,10 @@ static int anatop_thermal_get_temperature(struct anatop_thermal *tz)
 
        /* now we only using single measure, every time we measure
        the temperature, we will power on/down the anadig module*/
-       anatop_thermal_power_on();
+       __raw_writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN,
+                       anatop_base + HW_ANADIG_TEMPSENSE0_CLR);
+       __raw_writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF,
+                       anatop_base + HW_ANADIG_ANA_MISC0_SET);
 
        /* write measure freq */
        reg = __raw_readl(anatop_base + HW_ANADIG_TEMPSENSE1);
@@ -278,57 +273,42 @@ static int anatop_thermal_get_temperature(struct anatop_thermal *tz)
        }
 
        tmp = tmp / 5;
-       tz->temperature = anatop_tempsense_value_to_dc(tmp);
-
+       tz->temperature = REG_VALUE_TO_CEL(tmp);
        pr_debug("Temperature is %lu C\n", tz->temperature);
-       anatop_thermal_power_down();
-
-       return 0;
-}
+       /* power down anatop thermal sensor */
+       __raw_writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN,
+                       anatop_base + HW_ANADIG_TEMPSENSE0_SET);
+       __raw_writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF,
+                       anatop_base + HW_ANADIG_ANA_MISC0_CLR);
 
-static int anatop_thermal_get_polling_frequency(struct anatop_thermal *tz)
-{
-       /* treat the polling interval as freq */
-       tz->polling_frequency = POLLING_FREQ;
+       *temp = tz->temperature;
 
        return 0;
 }
 
 static int anatop_thermal_set_cooling_mode(struct anatop_thermal *tz, int mode)
 {
-
        return 0;
 }
 
-#define ANATOP_TRIPS_CRITICAL  0x01
-#define ANATOP_TRIPS_HOT               0x02
-#define ANATOP_TRIPS_PASSIVE   0x04
-#define ANATOP_TRIPS_ACTIVE        0x08
-#define ANATOP_TRIPS_DEVICES   0x10
-
-#define ANATOP_TRIPS_INIT      (ANATOP_TRIPS_CRITICAL | \
-               ANATOP_TRIPS_HOT | ANATOP_TRIPS_PASSIVE)
-
 static int anatop_thermal_trips_update(struct anatop_thermal *tz, int flag)
 {
        /* Critical Shutdown */
        if (flag & ANATOP_TRIPS_CRITICAL) {
-               tz->trips.critical.temperature = TEMP_CRITICAL_SHUTDOWN;
+               tz->trips.critical.temperature = TEMP_CRITICAL;
                tz->trips.critical.flags.valid = 1;
-
        }
 
-       /* Critical Sleep(HOT) (optional) */
+       /* Hot */
        if (flag & ANATOP_TRIPS_HOT) {
-                       tz->trips.hot.temperature = TEMP_CRITICAL_SLEEP;
+                       tz->trips.hot.temperature = TEMP_HOT;
                        tz->trips.hot.flags.valid = 1;
-
        }
 
-       /* Passive (optional) */
-       if (flag & ANATOP_TRIPS_PASSIVE) {
-                       tz->trips.passive.temperature = TEMP_PASSIVE;
-                       tz->trips.passive.flags.valid = 1;
+       /* Active */
+       if (flag & ANATOP_TRIPS_ACTIVE) {
+                       tz->trips.active.temperature = TEMP_ACTIVE;
+                       tz->trips.active.flags.valid = 1;
        }
 
        return 0;
@@ -336,54 +316,24 @@ static int anatop_thermal_trips_update(struct anatop_thermal *tz, int flag)
 
 static int anatop_thermal_get_trip_points(struct anatop_thermal *tz)
 {
-       int i, valid, ret = anatop_thermal_trips_update(tz, ANATOP_TRIPS_INIT);
+       int valid, ret;
 
-       if (ret)
-               return ret;
+       ret = anatop_thermal_trips_update(tz, ANATOP_TRIPS_INIT);
 
        valid = tz->trips.critical.flags.valid |
                tz->trips.hot.flags.valid |
-               tz->trips.passive.flags.valid;
-
-       for (i = 0; i < ANATOP_THERMAL_MAX_ACTIVE; i++)
-               valid |= tz->trips.active[i].flags.valid;
+               tz->trips.active.flags.valid;
 
        if (!valid) {
-               printk(KERN_WARNING FW_BUG "No valid trip found\n");
-               return -ENODEV;
+               printk(KERN_WARNING "No valid trip found\n");
+               ret = -ENODEV;
        }
-       return 0;
+       return ret;
 }
 
-static void anatop_thermal_check(void *data)
-{
-       struct anatop_thermal *tz = data;
-
-       thermal_zone_device_update(tz->thermal_zone);
-}
-
-/* sys I/F for generic thermal sysfs support */
-#define KELVIN_TO_CEL(t, off) (((t) - (off)))
-
-static int thermal_get_temp(struct thermal_zone_device *thermal,
-                           unsigned long *temp)
-{
-       struct anatop_thermal *tz = thermal->devdata;
-       int result;
-
-       if (!tz)
-               return -EINVAL;
-       result = 0;
-       result = anatop_thermal_get_temperature(tz);
-       *temp = tz->temperature;
-       if (result)
-               return result;
-       else
-               return 0;
-}
 static const char enabled[] = "kernel";
 static const char disabled[] = "user";
-static int thermal_get_mode(struct thermal_zone_device *thermal,
+static int anatop_thermal_get_mode(struct thermal_zone_device *thermal,
                                enum thermal_device_mode *mode)
 {
        struct anatop_thermal *tz = thermal->devdata;
@@ -397,7 +347,7 @@ static int thermal_get_mode(struct thermal_zone_device *thermal,
        return 0;
 }
 
-static int thermal_set_mode(struct thermal_zone_device *thermal,
+static int anatop_thermal_set_mode(struct thermal_zone_device *thermal,
                                enum thermal_device_mode mode)
 {
        struct anatop_thermal *tz = thermal->devdata;
@@ -416,21 +366,17 @@ static int thermal_set_mode(struct thermal_zone_device *thermal,
 
        if (enable != tz->tz_enabled) {
                tz->tz_enabled = enable;
-               /*
-               printk((KERN_INFO,
-                       "%s anatop thermal control\n",
-                       tz->tz_enabled ? enabled : disabled));
-               */
-               anatop_thermal_check(tz);
+               printk(KERN_INFO "%s anatop thermal control\n",
+                       tz->tz_enabled ? enabled : disabled);
+               thermal_zone_device_update(tz->thermal_zone);
        }
        return 0;
 }
 
-static int thermal_get_trip_type(struct thermal_zone_device *thermal,
+static int anatop_thermal_get_trip_type(struct thermal_zone_device *thermal,
                                 int trip, enum thermal_trip_type *type)
 {
        struct anatop_thermal *tz = thermal->devdata;
-       int i;
 
        if (!tz || trip < 0)
                return -EINVAL;
@@ -459,8 +405,7 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
                trip--;
        }
 
-       for (i = 0; i < ANATOP_THERMAL_MAX_ACTIVE &&
-               tz->trips.active[i].flags.valid; i++) {
+       if (tz->trips.active.flags.valid) {
                if (!trip) {
                        *type = THERMAL_TRIP_ACTIVE;
                        return 0;
@@ -471,11 +416,44 @@ static int thermal_get_trip_type(struct thermal_zone_device *thermal,
        return -EINVAL;
 }
 
-static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
+static int anatop_thermal_set_trip_temp(struct thermal_zone_device *thermal,
+                                int trip, unsigned long *temp)
+{
+       struct anatop_thermal *tz = thermal->devdata;
+
+       if (!tz || trip < 0)
+               return -EINVAL;
+
+       switch (trip) {
+       case ANATOP_TRIPS_POINT_CRITICAL:
+               /* Critical Shutdown */
+               if (tz->trips.critical.flags.valid)
+                       tz->trips.critical.temperature = CEL_TO_KELVIN(
+                               *temp, tz->kelvin_offset);
+               break;
+       case ANATOP_TRIPS_POINT_HOT:
+               /* Hot */
+               if (tz->trips.hot.flags.valid)
+                               tz->trips.hot.temperature = CEL_TO_KELVIN(
+                               *temp, tz->kelvin_offset);
+               break;
+       case ANATOP_TRIPS_POINT_ACTIVE:
+               /* Active */
+               if (tz->trips.active.flags.valid)
+                               tz->trips.active.temperature = CEL_TO_KELVIN(
+                               *temp, tz->kelvin_offset);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int anatop_thermal_get_trip_temp(struct thermal_zone_device *thermal,
                                 int trip, unsigned long *temp)
 {
        struct anatop_thermal *tz = thermal->devdata;
-       int i;
 
        if (!tz || trip < 0)
                return -EINVAL;
@@ -509,11 +487,10 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
                trip--;
        }
 
-       for (i = 0; i < ANATOP_THERMAL_MAX_ACTIVE &&
-               tz->trips.active[i].flags.valid; i++) {
+       if (tz->trips.active.flags.valid) {
                if (!trip) {
                        *temp = KELVIN_TO_CEL(
-                               tz->trips.active[i].temperature,
+                               tz->trips.active.temperature,
                                tz->kelvin_offset);
                        return 0;
                }
@@ -523,7 +500,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
        return -EINVAL;
 }
 
-static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
+static int anatop_thermal_get_crit_temp(struct thermal_zone_device *thermal,
                                unsigned long *temperature) {
        struct anatop_thermal *tz = thermal->devdata;
 
@@ -536,22 +513,39 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
                return -EINVAL;
 }
 
-static int thermal_notify(struct thermal_zone_device *thermal, int trip,
+static int anatop_thermal_notify(struct thermal_zone_device *thermal, int trip,
                           enum thermal_trip_type trip_type)
 {
+       int ret = 0;
        u8 type = 0;
-       /* struct anatop_thermal *tz = thermal->devdata; */
+       char mode = 'r';
+       const char *cmd = "reboot";
+       struct anatop_thermal *tz = thermal->devdata;
 
-       if (trip_type == THERMAL_TRIP_CRITICAL)
+       if (trip_type == THERMAL_TRIP_CRITICAL) {
                type = ANATOP_THERMAL_NOTIFY_CRITICAL;
-       else if (trip_type == THERMAL_TRIP_HOT)
+               printk(KERN_WARNING "thermal_notify: trip_critical reached!\n");
+               arch_reset(mode, cmd);
+       } else if (trip_type == THERMAL_TRIP_HOT) {
+               printk(KERN_DEBUG "thermal_notify: trip_hot reached!\n");
                type = ANATOP_THERMAL_NOTIFY_HOT;
-       else
-               return 0;
-/*
-       if (trip_type == THERMAL_TRIP_CRITICAL && nocrt)
-               return 1;
-*/
+               /* if temperature increase, continue to detach secondary CPUs*/
+               if (tz->temperature > (temperature_hotplug + 1)) {
+                       anatop_thermal_cpu_hotplug(false);
+                       temperature_hotplug = tz->temperature;
+               }
+               if (ret)
+                       printk(KERN_INFO "No secondary CPUs detached!\n");
+               full_run = false;
+       } else {
+               if (!full_run) {
+                       temperature_hotplug = 0;
+                       anatop_thermal_cpu_hotplug(true);
+                       if (ret)
+                               printk(KERN_INFO "No secondary CPUs attached!\n");
+               }
+       }
+
        return 0;
 }
 
@@ -561,11 +555,42 @@ static int anatop_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
                                        struct thermal_cooling_device *cdev,
                                        cb action)
 {
-       /* struct anatop_thermal *tz = thermal->devdata; */
-
+       struct anatop_thermal *tz = thermal->devdata;
+       anatop_handle handle;
+       int i;
+       int trip = -1;
        int result = 0;
 
+       if (tz->trips.critical.flags.valid)
+               trip++;
+
+       if (tz->trips.hot.flags.valid)
+               trip++;
+
+       if (tz->trips.passive.flags.valid) {
+               trip++;
+               result = action(thermal, trip, cdev);
+               if (result)
+                       goto failed;
+       }
+
+       if (tz->trips.active.flags.valid) {
+               trip++;
+               result = action(thermal, trip, cdev);
+               if (result)
+                       goto failed;
+       }
+
+       for (i = 0; i < tz->devices.count; i++) {
+               handle = tz->devices.handles[i];
+               result = action(thermal, -1, cdev);
+               if (result)
+                       goto failed;
+       }
+
+failed:
        return result;
+
 }
 
 static int
@@ -587,19 +612,19 @@ anatop_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
 static struct thermal_zone_device_ops anatop_thermal_zone_ops = {
        .bind = anatop_thermal_bind_cooling_device,
        .unbind = anatop_thermal_unbind_cooling_device,
-       .get_temp = thermal_get_temp,
-       .get_mode = thermal_get_mode,
-       .set_mode = thermal_set_mode,
-       .get_trip_type = thermal_get_trip_type,
-       .get_trip_temp = thermal_get_trip_temp,
-       .get_crit_temp = thermal_get_crit_temp,
-       .notify = thermal_notify,
+       .get_temp = anatop_thermal_get_temp,
+       .get_mode = anatop_thermal_get_mode,
+       .set_mode = anatop_thermal_set_mode,
+       .get_trip_type = anatop_thermal_get_trip_type,
+       .get_trip_temp = anatop_thermal_get_trip_temp,
+       .set_trip_temp = anatop_thermal_set_trip_temp,
+       .get_crit_temp = anatop_thermal_get_crit_temp,
+       .notify = anatop_thermal_notify,
 };
 
 static int anatop_thermal_register_thermal_zone(struct anatop_thermal *tz)
 {
        int trips = 0;
-       int i;
 
        if (tz->trips.critical.flags.valid)
                trips++;
@@ -610,9 +635,8 @@ static int anatop_thermal_register_thermal_zone(struct anatop_thermal *tz)
        if (tz->trips.passive.flags.valid)
                trips++;
 
-       for (i = 0; i < ANATOP_THERMAL_MAX_ACTIVE
-                       && tz->trips.active[i].flags.valid; i++, trips++)
-               ;
+       if (tz->trips.active.flags.valid)
+               trips++;
 
        if (tz->trips.passive.flags.valid)
                tz->thermal_zone =
@@ -627,26 +651,14 @@ static int anatop_thermal_register_thermal_zone(struct anatop_thermal *tz)
                        thermal_zone_device_register("anatoptz", trips, tz,
                                                     &anatop_thermal_zone_ops,
                                                     0, 0, 0,
-                                                    tz->polling_frequency*100);
-#if 0
-       result = sysfs_create_link(&tz->device->dev.kobj,
-                               &tz->thermal_zone->device.kobj, "thermal_zone");
-       if (result)
-               return result;
-
-       result = sysfs_create_link(&tz->thermal_zone->device.kobj,
-                                  &tz->device->dev.kobj, "device");
-       if (result)
-               return result;
-#endif
-
+                                                    tz->polling_frequency);
        tz->tz_enabled = 1;
 
-       dev_info(&tz->device->dev, "registered as thermal_zone%d\n",
-                tz->thermal_zone->id);
+       printk(KERN_INFO "%s registered as thermal_zone%d\n",
+                tz->device->name, tz->thermal_zone->id);
        return 0;
 }
-/*
+
 static void anatop_thermal_unregister_thermal_zone(struct anatop_thermal *tz)
 {
        sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
@@ -654,7 +666,6 @@ static void anatop_thermal_unregister_thermal_zone(struct anatop_thermal *tz)
        thermal_zone_device_unregister(tz->thermal_zone);
        tz->thermal_zone = NULL;
 }
-*/
 
 /* --------------------------------------------------------------
                                                Driver Interface
@@ -666,11 +677,6 @@ static int anatop_thermal_get_info(struct anatop_thermal *tz)
        if (!tz)
                return -EINVAL;
 
-       /* Get temperature [_TMP] (required) */
-       result = anatop_thermal_get_temperature(tz);
-       if (result)
-               return result;
-
        /* Get trip points [_CRT, _PSV, etc.] (required) */
        result = anatop_thermal_get_trip_points(tz);
        if (result)
@@ -683,20 +689,16 @@ static int anatop_thermal_get_info(struct anatop_thermal *tz)
                tz->flags.cooling_mode = 1;
 
        /* Get default polling frequency [_TZP] (optional) */
-       anatop_thermal_get_polling_frequency(tz);
+       tz->polling_frequency = POLLING_FREQ;
 
        return 0;
 }
-
-static void anatop_thermal_guess_offset(struct anatop_thermal *tz)
-{
-       tz->kelvin_offset = 273;
-}
-
 static int anatop_thermal_add(struct anatop_device *device)
 {
        int result = 0;
        struct anatop_thermal *tz = NULL;
+       struct thermal_cooling_device *cd = NULL;
+
        if (!device)
                return -EINVAL;
 
@@ -704,8 +706,12 @@ static int anatop_thermal_add(struct anatop_device *device)
        if (!tz)
                return -ENOMEM;
 
+       cd = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
+       if (!cd)
+               return -ENOMEM;
+
        tz->device = device;
-       strcpy(device->name, ANATOP_THERMAL_DEVICE_NAME);
+       strcpy(device->name, ANATOP_THERMAL_DRIVER_NAME);
        device->driver_data = tz;
        mutex_init(&tz->lock);
 
@@ -713,52 +719,26 @@ static int anatop_thermal_add(struct anatop_device *device)
        if (result)
                goto free_memory;
 
-       anatop_thermal_guess_offset(tz);
+       tz->kelvin_offset = KELVIN_OFFSET;
 
        result = anatop_thermal_register_thermal_zone(tz);
        if (result)
                goto free_memory;
 
+       cd = thermal_cooling_device_register("i.mx_processor", device,
+                                               &imx_processor_cooling_ops);
+       if (IS_ERR(cd)) {
+               result = PTR_ERR(cd);
+               goto free_memory;
+       }
        goto end;
 
 free_memory:
        kfree(tz);
+       kfree(cd);
 end:
        return result;
 }
-static int anatop_thermal_remove(struct platform_device *pdev)
-{
-       /* struct anatop_device *device = platform_get_drvdata(pdev); */
-       return 0;
-}
-static int anatop_thermal_suspend(struct platform_device *pdev,
-pm_message_t state)
-{
-       return 0;
-}
-static int anatop_thermal_resume(struct platform_device *pdev)
-{
-       return 0;
-}
-static int anatop_thermal_power_on(void)
-{
-       __raw_writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN,
-                       anatop_base + HW_ANADIG_TEMPSENSE0_CLR);
-
-       __raw_writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF,
-                       anatop_base + HW_ANADIG_ANA_MISC0_SET);
-       return 0;
-}
-
-static int anatop_thermal_power_down(void)
-{
-       __raw_writel(BM_ANADIG_TEMPSENSE0_POWER_DOWN,
-                       anatop_base + HW_ANADIG_TEMPSENSE0_SET);
-
-       __raw_writel(BM_ANADIG_ANA_MISC0_REFTOP_SELBIASOFF,
-                       anatop_base + HW_ANADIG_ANA_MISC0_CLR);
-       return 0;
-}
 
 static int anatop_thermal_probe(struct platform_device *pdev)
 {
@@ -778,28 +758,54 @@ static int anatop_thermal_probe(struct platform_device *pdev)
        /* ioremap the base address */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
-               dev_err(&pdev->dev, "No anatop base address provided\n");
+               dev_err(&pdev->dev, "No anatop base address provided!\n");
                goto anatop_failed;
        }
 
        base = ioremap(res->start, res->end - res->start);
        if (base == NULL) {
-               dev_err(&pdev->dev, "failed to rebase anatop base address\n");
+               dev_err(&pdev->dev, "failed to remap anatop base address!\n");
                goto anatop_failed;
        }
        anatop_base = (unsigned long)base;
 
        anatop_thermal_add(device);
+       /* anatop_thermal_cpufreq_init(); */
 
        goto success;
 anatop_failed:
        kfree(device);
 device_alloc_failed:
 success:
-       pr_info("%s\n", __func__);
+
        return retval;
 }
 
+static int anatop_thermal_remove(struct platform_device *pdev)
+{
+       struct anatop_thermal *tz;
+
+       if (!pdev)
+               return -EINVAL;
+
+       tz = platform_get_drvdata(pdev);
+
+       anatop_thermal_unregister_thermal_zone(tz);
+
+       mutex_destroy(&tz->lock);
+       kfree(tz);
+       return 0;
+}
+static int anatop_thermal_suspend(struct platform_device *pdev,
+               pm_message_t state)
+{
+       return 0;
+}
+static int anatop_thermal_resume(struct platform_device *pdev)
+{
+       return 0;
+}
+
 static struct platform_driver anatop_thermal_driver_ldm = {
        .driver = {
                   .name = "anatop_thermal",