summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnson Huang <b20788@freescale.com>2011-09-01 10:00:58 +0800
committerAnson Huang <b20788@freescale.com>2011-09-01 11:05:56 +0800
commit081ccd6d86013b0bac695dacd20028b17f74b615 (patch)
tree30a88a060faa0153e088811311abb386844f6658
parentbd0e3c609c0c4d23913331c3691d1bd4f44acfb1 (diff)
ENGR00155627 [MX6]Add thermal cooling device
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>
-rw-r--r--drivers/mxc/thermal/Makefile2
-rw-r--r--drivers/mxc/thermal/anatop_driver.h37
-rw-r--r--drivers/mxc/thermal/cooling.c175
-rw-r--r--drivers/mxc/thermal/thermal.c462
4 files changed, 423 insertions, 253 deletions
diff --git a/drivers/mxc/thermal/Makefile b/drivers/mxc/thermal/Makefile
index aed4877c6bef..4823d6d569c1 100644
--- a/drivers/mxc/thermal/Makefile
+++ b/drivers/mxc/thermal/Makefile
@@ -2,4 +2,4 @@
# Makefile for i.MX ANATOP
#
-obj-$(CONFIG_ANATOP_THERMAL) += thermal.o
+obj-$(CONFIG_ANATOP_THERMAL) += thermal.o cooling.o
diff --git a/drivers/mxc/thermal/anatop_driver.h b/drivers/mxc/thermal/anatop_driver.h
index ecdd941c88b6..51837cc1fdce 100644
--- a/drivers/mxc/thermal/anatop_driver.h
+++ b/drivers/mxc/thermal/anatop_driver.h
@@ -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.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -31,10 +30,12 @@
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
index 000000000000..b1d90becd6d4
--- /dev/null
+++ b/drivers/mxc/thermal/cooling.c
@@ -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,
+};
+
diff --git a/drivers/mxc/thermal/thermal.c b/drivers/mxc/thermal/thermal.c
index c5566223a337..84c7a631ed62 100644
--- a/drivers/mxc/thermal/thermal.c
+++ b/drivers/mxc/thermal/thermal.c
@@ -21,14 +21,6 @@
* 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 */
@@ -88,11 +82,9 @@
#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"
@@ -104,47 +96,53 @@
#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",