summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeerthy <j-keerthy@ti.com>2012-02-23 16:34:01 +0800
committerAndy Green <andy.green@linaro.org>2012-06-20 10:27:13 +0800
commit4e247cc2ce488bbd38ba3b4a7459af16bc54ec2d (patch)
treeb47f6a3e03a837eeb7f0cf449d35dd79ffebfdb5
parent16ca51d201b4bd717e79b2f729fa09f50529b208 (diff)
OMAP4460PLUS Thermal: Thermal framework support
The patch adds kernel thermal framework and on die CPU governer support. Signed-off-by: Dan Murphy <dmurphy@ti.com> Signed-off-by: Moiz Sonasath <m-sonasath@ti.com> Signed-off-by: Keerthy <j-keerthy@ti.com> Signed-off-by: J Keerthy <j-keerthy@ti.com>
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/thermal_framework/Kconfig18
-rw-r--r--drivers/staging/thermal_framework/Makefile5
-rw-r--r--drivers/staging/thermal_framework/governor/Kconfig10
-rw-r--r--drivers/staging/thermal_framework/governor/Makefile4
-rw-r--r--drivers/staging/thermal_framework/governor/omap_die_governor.c510
-rw-r--r--drivers/staging/thermal_framework/thermal_framework.c597
-rw-r--r--include/linux/thermal_framework.h96
9 files changed, 1243 insertions, 0 deletions
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 97d412d9145..ed94734d90e 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -132,4 +132,6 @@ source "drivers/staging/ramster/Kconfig"
source "drivers/staging/ozwpan/Kconfig"
+source "drivers/staging/thermal_framework/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index ffe7d44374e..542876b26cd 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -57,3 +57,4 @@ obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_RAMSTER) += ramster/
obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/
+obj-$(CONFIG_OMAP_THERMAL) += thermal_framework/
diff --git a/drivers/staging/thermal_framework/Kconfig b/drivers/staging/thermal_framework/Kconfig
new file mode 100644
index 00000000000..0199e129ca1
--- /dev/null
+++ b/drivers/staging/thermal_framework/Kconfig
@@ -0,0 +1,18 @@
+#
+# Generic Thermal Framework drivers configuration
+#
+
+menuconfig THERMAL_FRAMEWORK
+ bool "Thermal Framework support"
+ help
+ This is a generic thermal framework which will be used as
+ a central hub for sensors, governors and cooling devices
+ to register and pass data to.
+
+config OMAP_THERMAL
+ bool "OMAP Thermal Framework support"
+ help
+ This is the thermal framework support for OMAP4
+ processors.
+
+source "drivers/staging/thermal_framework/governor/Kconfig"
diff --git a/drivers/staging/thermal_framework/Makefile b/drivers/staging/thermal_framework/Makefile
new file mode 100644
index 00000000000..bdae4d550c9
--- /dev/null
+++ b/drivers/staging/thermal_framework/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for sensor chip drivers.
+#
+obj-$(CONFIG_THERMAL_FRAMEWORK) += thermal_framework.o \
+ governor/
diff --git a/drivers/staging/thermal_framework/governor/Kconfig b/drivers/staging/thermal_framework/governor/Kconfig
new file mode 100644
index 00000000000..e5d41a584aa
--- /dev/null
+++ b/drivers/staging/thermal_framework/governor/Kconfig
@@ -0,0 +1,10 @@
+#
+# Thermal governor driver config
+#
+
+config OMAP_DIE_GOVERNOR
+ bool "OMAP On Die thermal governor support"
+ help
+ This is the governor for the OMAP4 On-Die temperature sensor.
+ This governer will institute the policy to call specific
+ cooling agents.
diff --git a/drivers/staging/thermal_framework/governor/Makefile b/drivers/staging/thermal_framework/governor/Makefile
new file mode 100644
index 00000000000..0b5eff77ab7
--- /dev/null
+++ b/drivers/staging/thermal_framework/governor/Makefile
@@ -0,0 +1,4 @@
+#
+# Makefile for Thermal governor drivers.
+#
+obj-$(CONFIG_OMAP_DIE_GOVERNOR) += omap_die_governor.o
diff --git a/drivers/staging/thermal_framework/governor/omap_die_governor.c b/drivers/staging/thermal_framework/governor/omap_die_governor.c
new file mode 100644
index 00000000000..115ea373ec8
--- /dev/null
+++ b/drivers/staging/thermal_framework/governor/omap_die_governor.c
@@ -0,0 +1,510 @@
+/*
+ * drivers/thermal/omap_die_governor.c
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Dan Murphy <DMurphy@ti.com>
+ *
+ * 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/err.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <linux/thermal_framework.h>
+
+/* CPU Zone information */
+#define FATAL_ZONE 5
+#define PANIC_ZONE 4
+#define ALERT_ZONE 3
+#define MONITOR_ZONE 2
+#define SAFE_ZONE 1
+#define NO_ACTION 0
+#define OMAP_FATAL_TEMP 125000
+#define OMAP_PANIC_TEMP 110000
+#define OMAP_ALERT_TEMP 100000
+#define OMAP_MONITOR_TEMP 85000
+
+
+/* TODO: Define this via a configurable file */
+#define HYSTERESIS_VALUE 5000
+#define NORMAL_TEMP_MONITORING_RATE 1000
+#define FAST_TEMP_MONITORING_RATE 250
+
+static int omap_gradient_slope;
+static int omap_gradient_const;
+
+struct omap_die_governor {
+ struct thermal_dev *temp_sensor;
+ void (*update_temp_thresh) (struct thermal_dev *, int min, int max);
+ int report_rate;
+ int panic_zone_reached;
+ int cooling_level;
+};
+
+static struct thermal_dev *therm_fw;
+static struct omap_die_governor *omap_gov;
+
+static LIST_HEAD(cooling_agents);
+
+/**
+ * DOC: Introduction
+ * =================
+ * The OMAP On-Die Temperature governor maintains the policy for the CPU
+ * on die temperature sensor. The main goal of the governor is to receive
+ * a temperature report from a thermal sensor and calculate the current
+ * thermal zone. Each zone will sort through a list of cooling agents
+ * passed in to determine the correct cooling stategy that will cool the
+ * device appropriately for that zone.
+ *
+ * The temperature that is reported by the temperature sensor is first
+ * calculated to an OMAP hot spot temperature.
+ * This takes care of the existing temperature gradient between
+ * the OMAP hot spot and the on-die temp sensor.
+ * Note: The "slope" parameter is multiplied by 1000 in the configuration
+ * file to avoid using floating values.
+ * Note: The "offset" is defined in milli-celsius degrees.
+ *
+ * Next the hot spot temperature is then compared to thresholds to determine
+ * the proper zone.
+ *
+ * There are 5 zones identified:
+ *
+ * FATAL_ZONE: This zone indicates that the on-die temperature has reached
+ * a point where the device needs to be rebooted and allow ROM or the bootloader
+ * to run to allow the device to cool.
+ *
+ * PANIC_ZONE: This zone indicates a near fatal temperature is approaching
+ * and should impart all neccessary cooling agent to bring the temperature
+ * down to an acceptable level.
+ *
+ * ALERT_ZONE: This zone indicates that die is at a level that may need more
+ * agressive cooling agents to keep or lower the temperature.
+ *
+ * MONITOR_ZONE: This zone is used as a monitoring zone and may or may not use
+ * cooling agents to hold the current temperature.
+ *
+ * SAFE_ZONE: This zone is optimal thermal zone. It allows the device to
+ * run at max levels without imparting any cooling agent strategies.
+ *
+ * NO_ACTION: Means just that. There was no action taken based on the current
+ * temperature sent in.
+*/
+
+/**
+ * omap_update_report_rate() - Updates the temperature sensor monitoring rate
+ *
+ * @new_rate: New measurement rate for the temp sensor
+ *
+ * No return
+ */
+static void omap_update_report_rate(struct thermal_dev *temp_sensor,
+ int new_rate)
+{
+ if (omap_gov->report_rate == -EOPNOTSUPP) {
+ pr_err("%s:Updating the report rate is not supported\n",
+ __func__);
+ return;
+ }
+
+ if (omap_gov->report_rate != new_rate)
+ omap_gov->report_rate =
+ thermal_update_temp_rate(temp_sensor, new_rate);
+}
+
+/*
+ * convert_omap_sensor_temp_to_hotspot_temp() -Convert the temperature from the
+ * OMAP on-die temp sensor into OMAP hot spot temperature.
+ * This takes care of the existing temperature gradient between
+ * the OMAP hot spot and the on-die temp sensor.
+ *
+ * @sensor_temp: Raw temperature reported by the OMAP die temp sensor
+ *
+ * Returns the calculated hot spot temperature for the zone calculation
+ */
+static signed int convert_omap_sensor_temp_to_hotspot_temp(int sensor_temp)
+{
+ int absolute_delta;
+
+ absolute_delta = ((sensor_temp * omap_gradient_slope / 1000) +
+ omap_gradient_const);
+ return sensor_temp + absolute_delta;
+}
+
+/*
+ * hotspot_temp_to_omap_sensor_temp() - Convert the temperature from
+ * the OMAP hot spot temperature into the OMAP on-die temp sensor.
+ * This is useful to configure the thresholds at OMAP on-die
+ * sensor level. This takes care of the existing temperature
+ * gradient between the OMAP hot spot and the on-die temp sensor.
+ *
+ * @hot_spot_temp: Hot spot temperature to the be calculated to CPU on-die
+ * temperature value.
+ *
+ * Returns the calculated cpu on-die temperature.
+ */
+
+static signed hotspot_temp_to_sensor_temp(int hot_spot_temp)
+{
+ return ((hot_spot_temp - omap_gradient_const) * 1000) /
+ (1000 + omap_gradient_slope);
+}
+
+/**
+ * omap_safe_zone() - THERMAL "Safe Zone" definition:
+ * - No constraint about Max CPU frequency
+ * - No constraint about CPU freq governor
+ * - Normal temperature monitoring rate
+ *
+ * @cooling_list: The list of cooling devices available to cool the zone
+ * @cpu_temp: The current adjusted CPU temperature
+ *
+ * Returns 0 on success and -ENODEV for no cooling devices available to cool
+ */
+static int omap_safe_zone(struct list_head *cooling_list, int cpu_temp)
+{
+ struct thermal_dev *cooling_dev, *tmp;
+ int die_temp_upper = 0;
+ int die_temp_lower = 0;
+ pr_debug("%s:hot spot temp %d\n", __func__, cpu_temp);
+ /* TO DO: need to build an algo to find the right cooling agent */
+ list_for_each_entry_safe(cooling_dev, tmp, cooling_list, node) {
+ if (cooling_dev->dev_ops &&
+ cooling_dev->dev_ops->cool_device) {
+ /* TO DO: Add cooling agents to a list here */
+ list_add(&cooling_dev->node, &cooling_agents);
+ goto out;
+ } else {
+ pr_info("%s:Cannot find cool_device for %s\n",
+ __func__, cooling_dev->name);
+ }
+ }
+out:
+ if (list_empty(&cooling_agents)) {
+ pr_err("%s: No Cooling devices registered\n",
+ __func__);
+ return -ENODEV;
+ } else {
+ omap_gov->cooling_level = 0;
+ thermal_cooling_set_level(&cooling_agents,
+ omap_gov->cooling_level);
+ list_del_init(&cooling_agents);
+ die_temp_lower = hotspot_temp_to_sensor_temp(
+ OMAP_MONITOR_TEMP - HYSTERESIS_VALUE);
+ die_temp_upper = hotspot_temp_to_sensor_temp(OMAP_MONITOR_TEMP);
+ thermal_update_temp_thresholds(omap_gov->temp_sensor,
+ die_temp_lower, die_temp_upper);
+ omap_update_report_rate(omap_gov->temp_sensor,
+ NORMAL_TEMP_MONITORING_RATE);
+ omap_gov->panic_zone_reached = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * omap_monitor_zone() - Current device is in a situation that requires
+ * monitoring and may impose agents to keep the device
+ * at a steady state temperature or moderately cool the
+ * device.
+ *
+ * @cooling_list: The list of cooling devices available to cool the zone
+ * @cpu_temp: The current adjusted CPU temperature
+ *
+ * Returns 0 on success and -ENODEV for no cooling devices available to cool
+ */
+static int omap_monitor_zone(struct list_head *cooling_list, int cpu_temp)
+{
+ struct thermal_dev *cooling_dev, *tmp;
+ int die_temp_upper = 0;
+ int die_temp_lower = 0;
+
+ pr_debug("%s:hot spot temp %d\n", __func__, cpu_temp);
+ /* TO DO: need to build an algo to find the right cooling agent */
+ list_for_each_entry_safe(cooling_dev, tmp, cooling_list, node) {
+ if (cooling_dev->dev_ops &&
+ cooling_dev->dev_ops->cool_device) {
+ /* TO DO: Add cooling agents to a list here */
+ list_add(&cooling_dev->node, &cooling_agents);
+ goto out;
+ } else {
+ pr_info("%s:Cannot find cool_device for %s\n",
+ __func__, cooling_dev->name);
+ }
+ }
+out:
+ if (list_empty(&cooling_agents)) {
+ pr_err("%s: No Cooling devices registered\n",
+ __func__);
+ return -ENODEV;
+ } else {
+ omap_gov->cooling_level = 0;
+ thermal_cooling_set_level(&cooling_agents,
+ omap_gov->cooling_level);
+ list_del_init(&cooling_agents);
+ die_temp_lower = hotspot_temp_to_sensor_temp(
+ OMAP_MONITOR_TEMP - HYSTERESIS_VALUE);
+ die_temp_upper =
+ hotspot_temp_to_sensor_temp(OMAP_ALERT_TEMP);
+ thermal_update_temp_thresholds(omap_gov->temp_sensor,
+ die_temp_lower, die_temp_upper);
+ omap_update_report_rate(omap_gov->temp_sensor,
+ FAST_TEMP_MONITORING_RATE);
+ omap_gov->panic_zone_reached = 0;
+ }
+
+ return 0;
+}
+/**
+ * omap_alert_zone() - "Alert Zone" definition:
+ * - If the Panic Zone has never been reached, then
+ * - Define constraint about Max CPU frequency
+ * if Current frequency < Max frequency,
+ * then Max frequency = Current frequency
+ * - Else keep the constraints set previously until
+ * temperature falls to safe zone
+ *
+ * @cooling_list: The list of cooling devices available to cool the zone
+ * @cpu_temp: The current adjusted CPU temperature
+ *
+ * Returns 0 on success and -ENODEV for no cooling devices available to cool
+ */
+static int omap_alert_zone(struct list_head *cooling_list, int cpu_temp)
+{
+ struct thermal_dev *cooling_dev, *tmp;
+ int die_temp_upper = 0;
+ int die_temp_lower = 0;
+
+ pr_debug("%s:hot spot temp %d\n", __func__, cpu_temp);
+ /* TO DO: need to build an algo to find the right cooling agent */
+ list_for_each_entry_safe(cooling_dev, tmp, cooling_list, node) {
+ if (cooling_dev->dev_ops &&
+ cooling_dev->dev_ops->cool_device) {
+ /* TO DO: Add cooling agents to a list here */
+ list_add(&cooling_dev->node, &cooling_agents);
+ goto out;
+ } else {
+ pr_info("%s:Cannot find cool_device for %s\n",
+ __func__, cooling_dev->name);
+ }
+ }
+out:
+ if (list_empty(&cooling_agents)) {
+ pr_err("%s: No Cooling devices registered\n",
+ __func__);
+ return -ENODEV;
+ } else {
+ if (omap_gov->panic_zone_reached == 0) {
+ /* Temperature rises and enters into alert zone */
+ omap_gov->cooling_level = 0;
+ thermal_cooling_set_level(&cooling_agents,
+ omap_gov->cooling_level);
+ }
+
+ list_del_init(&cooling_agents);
+ die_temp_lower = hotspot_temp_to_sensor_temp(
+ OMAP_ALERT_TEMP - HYSTERESIS_VALUE);
+ die_temp_upper = hotspot_temp_to_sensor_temp(
+ OMAP_PANIC_TEMP);
+ thermal_update_temp_thresholds(omap_gov->temp_sensor,
+ die_temp_lower, die_temp_upper);
+ omap_update_report_rate(omap_gov->temp_sensor,
+ FAST_TEMP_MONITORING_RATE);
+ }
+
+ return 0;
+}
+
+/**
+ * omap_panic_zone() - Force CPU frequency to a "safe frequency"
+ * . Force the CPU frequency to a “safe” frequency
+ * . Limit max CPU frequency to the “safe” frequency
+ *
+ * @cooling_list: The list of cooling devices available to cool the zone
+ * @cpu_temp: The current adjusted CPU temperature
+ *
+ * Returns 0 on success and -ENODEV for no cooling devices available to cool
+ */
+static int omap_panic_zone(struct list_head *cooling_list, int cpu_temp)
+{
+ struct thermal_dev *cooling_dev, *tmp;
+ int die_temp_upper = 0;
+ int die_temp_lower = 0;
+
+ pr_debug("%s:hot spot temp %d\n", __func__, cpu_temp);
+ /* TO DO: need to build an algo to find the right cooling agent */
+ list_for_each_entry_safe(cooling_dev, tmp, cooling_list, node) {
+ if (cooling_dev->dev_ops &&
+ cooling_dev->dev_ops->cool_device) {
+ /* TO DO: Add cooling agents to a list here */
+ list_add(&cooling_dev->node, &cooling_agents);
+ goto out;
+ } else {
+ pr_info("%s:Cannot find cool_device for %s\n",
+ __func__, cooling_dev->name);
+ }
+ }
+out:
+ if (list_empty(&cooling_agents)) {
+ pr_err("%s: No Cooling devices registered\n",
+ __func__);
+ return -ENODEV;
+ } else {
+ omap_gov->cooling_level++;
+ omap_gov->panic_zone_reached++;
+ pr_debug("%s: Panic zone reached %i times\n",
+ __func__, omap_gov->panic_zone_reached);
+ thermal_cooling_set_level(&cooling_agents,
+ omap_gov->cooling_level);
+ list_del_init(&cooling_agents);
+ die_temp_lower = hotspot_temp_to_sensor_temp(
+ OMAP_PANIC_TEMP - HYSTERESIS_VALUE);
+
+ /* Set the threshold window to below fatal. This way the
+ * governor can manage the thermal if the temp should rise
+ * while throttling. We need to be agressive with throttling
+ * should we reach this zone. */
+ die_temp_upper = (((OMAP_FATAL_TEMP - OMAP_PANIC_TEMP) / 4) *
+ omap_gov->panic_zone_reached) + OMAP_PANIC_TEMP;
+ if (die_temp_upper >= OMAP_FATAL_TEMP)
+ die_temp_upper = OMAP_FATAL_TEMP;
+
+ die_temp_upper = hotspot_temp_to_sensor_temp(die_temp_upper);
+ thermal_update_temp_thresholds(omap_gov->temp_sensor,
+ die_temp_lower, die_temp_upper);
+ omap_update_report_rate(omap_gov->temp_sensor,
+ FAST_TEMP_MONITORING_RATE);
+ }
+
+ return 0;
+}
+
+/**
+ * omap_fatal_zone() - Shut-down the system to ensure OMAP Junction
+ * temperature decreases enough
+ *
+ * @cpu_temp: The current adjusted CPU temperature
+ *
+ * No return forces a restart of the system
+ */
+static void omap_fatal_zone(int cpu_temp)
+{
+ pr_emerg("%s:FATAL ZONE (hot spot temp: %i)\n", __func__, cpu_temp);
+
+ kernel_restart(NULL);
+}
+
+static int omap_cpu_thermal_manager(struct list_head *cooling_list, int temp)
+{
+ int cpu_temp;
+
+ cpu_temp = convert_omap_sensor_temp_to_hotspot_temp(temp);
+ if (cpu_temp >= OMAP_FATAL_TEMP) {
+ omap_fatal_zone(cpu_temp);
+ return FATAL_ZONE;
+ } else if (cpu_temp >= OMAP_PANIC_TEMP) {
+ omap_panic_zone(cooling_list, cpu_temp);
+ return PANIC_ZONE;
+ } else if (cpu_temp < (OMAP_PANIC_TEMP - HYSTERESIS_VALUE)) {
+ if (cpu_temp >= OMAP_ALERT_TEMP) {
+ omap_alert_zone(cooling_list, cpu_temp);
+ return ALERT_ZONE;
+ } else if (cpu_temp < (OMAP_ALERT_TEMP - HYSTERESIS_VALUE)) {
+ if (cpu_temp >= OMAP_MONITOR_TEMP) {
+ omap_monitor_zone(cooling_list, cpu_temp);
+ return MONITOR_ZONE;
+ } else {
+ /*
+ * this includes the case where :
+ * (OMAP_MONITOR_TEMP - HYSTERESIS_VALUE) <= T
+ * && T < OMAP_MONITOR_TEMP
+ */
+ omap_safe_zone(cooling_list, cpu_temp);
+ return SAFE_ZONE;
+ }
+ } else {
+ /*
+ * this includes the case where :
+ * (OMAP_ALERT_TEMP - HYSTERESIS_VALUE) <=
+ * T < OMAP_ALERT_TEMP
+ */
+ omap_monitor_zone(cooling_list, cpu_temp);
+ return MONITOR_ZONE;
+ }
+ } else {
+ /*
+ * this includes the case where :
+ * (OMAP_PANIC_TEMP - HYSTERESIS_VALUE) <= T < OMAP_PANIC_TEMP
+ */
+ omap_alert_zone(cooling_list, cpu_temp);
+ return ALERT_ZONE;
+ }
+
+ return NO_ACTION;
+
+}
+
+static int omap_process_cpu_temp(struct list_head *cooling_list,
+ struct thermal_dev *temp_sensor,
+ int temp)
+{
+ pr_debug("%s: Received temp %i\n", __func__, temp);
+ omap_gov->temp_sensor = temp_sensor;
+ return omap_cpu_thermal_manager(cooling_list, temp);
+}
+
+static struct thermal_dev_ops omap_gov_ops = {
+ .process_temp = omap_process_cpu_temp,
+};
+
+static int __init omap_die_governor_init(void)
+{
+ struct thermal_dev *thermal_fw;
+ omap_gov = kzalloc(sizeof(struct omap_die_governor), GFP_KERNEL);
+ if (!omap_gov) {
+ pr_err("%s:Cannot allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ thermal_fw = kzalloc(sizeof(struct thermal_dev), GFP_KERNEL);
+ if (thermal_fw) {
+ thermal_fw->name = "omap_ondie_governor";
+ thermal_fw->domain_name = "cpu";
+ thermal_fw->dev_ops = &omap_gov_ops;
+ thermal_governor_dev_register(thermal_fw);
+ therm_fw = thermal_fw;
+ } else {
+ pr_err("%s: Cannot allocate memory\n", __func__);
+ kfree(omap_gov);
+ return -ENOMEM;
+ }
+
+ omap_gradient_slope = thermal_get_slope(thermal_fw);
+ omap_gradient_const = thermal_get_offset(thermal_fw);
+
+ return 0;
+}
+
+static void __exit omap_die_governor_exit(void)
+{
+ thermal_governor_dev_unregister(therm_fw);
+ kfree(therm_fw);
+ kfree(omap_gov);
+}
+
+module_init(omap_die_governor_init);
+module_exit(omap_die_governor_exit);
+
+MODULE_AUTHOR("Dan Murphy <DMurphy@ti.com>");
+MODULE_DESCRIPTION("OMAP on-die thermal governor");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/thermal_framework/thermal_framework.c b/drivers/staging/thermal_framework/thermal_framework.c
new file mode 100644
index 00000000000..a1368edaa43
--- /dev/null
+++ b/drivers/staging/thermal_framework/thermal_framework.c
@@ -0,0 +1,597 @@
+/*
+ * drivers/thermal/thermal_framework.c
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Dan Murphy <DMurphy@ti.com>
+ *
+ * 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/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+
+#include <linux/thermal_framework.h>
+
+static LIST_HEAD(thermal_domain_list);
+static DEFINE_MUTEX(thermal_domain_list_lock);
+
+static atomic_t device_count;
+
+/**
+ * DOC: Introduction
+ * =================
+ * The Thermal Framework is designed to be a central location to link
+ * temperature sensor drivers, governors and cooling agents together.
+ * The principle is to have one temperature sensor to one governor to many
+ * cooling agents. This model allows the governors to impart cooling policies
+ * based on the available cooling agents for a specific domain.
+ *
+ * The temperature sensor device should register to the framework and report
+ * the temperature of the current domain for which it reports a
+ * temperature measurement.
+ *
+ * The governor is responsible for imparting the cooling policy for the specific
+ * domain. The governor will be given a list of cooling agents that it can call
+ * to cool the domain.
+ *
+ * The cooling agent's primary responsibility is to perform an operation on the
+ * device to cool the domain it is responsible for.
+ *
+ * The sensor, governor and the cooling agents are linked in the framework
+ * via the domain_name in the thermal_dev structure.
+*/
+/**
+ * struct thermal_domain - Structure that contains the pointers to the
+ * sensor, governor and a list of cooling agents.
+ * @domain_name: The domain that the thermal structure represents
+ * @node: The list node of the thermal domain
+ * @temp_sensor: The domains temperature sensor thermal device pointer.
+ * @governor: The domain governor thermal device pointer.
+ * @cooling_agents: The domains list of available cooling agents
+ *
+ */
+struct thermal_domain {
+ const char *domain_name;
+ struct list_head node;
+ struct thermal_dev *temp_sensor;
+ struct thermal_dev *governor;
+ struct list_head cooling_agents;
+};
+
+/**
+ * thermal_cooling_set_level() - Calls a list of cooling devices to cool the
+ * thermal domain
+ * @cooling_list: A list of cooling agents to call to cool the domain
+ * @level: The level of cooling that the agent should perform
+ *
+ * Returns 0 for a successfull call to the cooling agent. ENODEV if a cooling
+ * agent does not exist.
+ */
+int thermal_cooling_set_level(struct list_head *cooling_list,
+ unsigned int level)
+{
+ struct thermal_dev *cooling_dev;
+ int ret = -ENODEV;
+
+ list_for_each_entry(cooling_dev, cooling_list, node) {
+ if (cooling_dev->dev_ops &&
+ cooling_dev->dev_ops->cool_device) {
+ pr_debug("%s:Found %s\n", __func__, cooling_dev->name);
+ cooling_dev->dev_ops->cool_device(cooling_dev, level);
+ ret = 0;
+ } else {
+ pr_err("%s:Cannot find cool_device for %s\n",
+ __func__, cooling_dev->name);
+ }
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(thermal_cooling_set_level);
+
+/**
+ * thermal_sensor_set_temp() - External API to allow a sensor driver to set
+ * the current temperature for a domain
+ * @tdev: The thermal device setting the temperature
+ *
+ * Returns 0 for a successfull call to a governor. ENODEV if a governor does not
+ * exist.
+ */
+int thermal_sensor_set_temp(struct thermal_dev *tdev)
+{
+ struct thermal_domain *thermal_domain;
+ int ret = -ENODEV;
+
+ if (list_empty(&thermal_domain_list)) {
+ pr_debug("%s: No governors registered\n", __func__);
+ goto out;
+ }
+
+ list_for_each_entry(thermal_domain, &thermal_domain_list, node)
+ if (!strcmp(thermal_domain->domain_name, tdev->domain_name)) {
+ if (!thermal_domain->cooling_agents.next) {
+ pr_debug("%s:No cooling agents for domain %s\n",
+ __func__, thermal_domain->domain_name);
+ goto out;
+ }
+
+ if (thermal_domain->governor &&
+ thermal_domain->governor->dev_ops &&
+ thermal_domain->governor->dev_ops->process_temp) {
+ thermal_domain->governor->dev_ops->process_temp
+ (&thermal_domain->cooling_agents,
+ tdev, tdev->current_temp);
+ ret = 0;
+ goto out;
+ } else {
+ pr_debug("%s:Gov did not have right function\n",
+ __func__);
+ goto out;
+ }
+
+ }
+out:
+ return ret;
+}
+EXPORT_SYMBOL_GPL(thermal_sensor_set_temp);
+
+/*
+ * thermal_get_slope() - External API for the sensor driver to
+ * get the Slope
+ * for Hotspot temperature computation
+ */
+int thermal_get_slope(struct thermal_dev *tdev)
+{
+ struct thermal_domain *thermal_domain;
+ int ret = -ENODEV;
+
+ if (list_empty(&thermal_domain_list))
+ pr_info("%s: No sensors registered\n", __func__);
+
+ list_for_each_entry(thermal_domain, &thermal_domain_list, node)
+ if (!strcmp(thermal_domain->domain_name, tdev->domain_name))
+ goto found;
+ pr_err("%s: Domain not found\n", __func__);
+ return ret;
+found:
+
+ if (thermal_domain->temp_sensor &&
+ thermal_domain->temp_sensor->dev_ops &&
+ thermal_domain->temp_sensor->dev_ops->init_slope) {
+ return thermal_domain->temp_sensor->dev_ops->init_slope
+ (thermal_domain->temp_sensor);
+ } else {
+ pr_err("%s:Getting slope is not supported for domain %s\n",
+ __func__, thermal_domain->domain_name);
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(thermal_get_slope);
+
+/*
+ * thermal_get_slope() - External API for the sensor driver to
+ * get the Slope
+ * for Hotspot temperature computation
+ */
+int thermal_get_offset(struct thermal_dev *tdev)
+{
+ struct thermal_domain *thermal_domain;
+ int ret = -ENODEV;
+
+ if (list_empty(&thermal_domain_list))
+ pr_debug("%s: No sensors registered\n", __func__);
+ list_for_each_entry(thermal_domain, &thermal_domain_list, node)
+ if (!strcmp(thermal_domain->domain_name, tdev->domain_name))
+ goto found;
+ pr_err("%s: Domain not found\n", __func__);
+ return ret;
+found:
+ if (thermal_domain->temp_sensor &&
+ thermal_domain->temp_sensor->dev_ops &&
+ thermal_domain->temp_sensor->dev_ops->init_offset) {
+ return thermal_domain->temp_sensor->dev_ops->init_offset
+ (thermal_domain->temp_sensor);
+ } else {
+ pr_err("%s:Getting offset is not supported for domain %s\n",
+ __func__, thermal_domain->domain_name);
+ return -EINVAL;
+ }
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(thermal_get_offset);
+
+/**
+ * thermal_request_temp() - Requests the thermal sensor to report it's current
+ * temperature to the governor.
+ *
+ * @tdev: The agent requesting the updated temperature.
+ *
+ * Returns the current temperature of the current domain.
+ * ENODEV if the temperature sensor does not exist.
+ * EOPNOTSUPP if the temperature sensor does not support this API.
+ */
+int thermal_request_temp(struct thermal_dev *tdev)
+{
+ struct thermal_domain *thermal_domain;
+ int ret = -ENODEV;
+
+ if (list_empty(&thermal_domain_list)) {
+ pr_debug("%s: No thermal sensors registered\n", __func__);
+ return ret;
+ }
+
+ mutex_lock(&thermal_domain_list_lock);
+ list_for_each_entry(thermal_domain, &thermal_domain_list, node)
+ if (!strcmp(thermal_domain->domain_name, tdev->domain_name))
+ goto report;
+ mutex_unlock(&thermal_domain_list_lock);
+ pr_err("%s: Domain not found\n", __func__);
+ return ret;
+report:
+ mutex_unlock(&thermal_domain_list_lock);
+ if (thermal_domain->temp_sensor &&
+ thermal_domain->temp_sensor->dev_ops &&
+ thermal_domain->temp_sensor->dev_ops->report_temp) {
+ ret = thermal_domain->temp_sensor->dev_ops->report_temp
+ (thermal_domain->temp_sensor);
+ } else {
+ pr_err("%s:Getting temp is not supported for domain %s\n",
+ __func__, thermal_domain->domain_name);
+ ret = -EOPNOTSUPP;
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(thermal_request_temp);
+
+/**
+ * thermal_update_temp_thresholds() - Update the temperature reporting
+ * thresholds on the temp sensor.
+ *
+ * @min: The minimum temperature that should trigger a temperature event.
+ * @max: The maximum temperature that should trigger a temperature event.
+ *
+ * EOPNOTSUPP if the temperature sensor does not support this API.
+ */
+int thermal_update_temp_thresholds(struct thermal_dev *temp_sensor,
+ int min, int max)
+{
+ if (temp_sensor) {
+ if ((temp_sensor->dev_ops) &&
+ (temp_sensor->dev_ops->set_temp_thresh)) {
+ pr_debug("%s: Setting new temp thresholds to %i & %i\n",
+ __func__, min, max);
+ temp_sensor->dev_ops->set_temp_thresh(temp_sensor,
+ min, max);
+ return 0;
+ } else
+ pr_err("%s:Updating temp thresholds is not supported \
+ for sensor %s\n", __func__, temp_sensor->name);
+ } else
+ pr_err("%s:Temp sensor pointer is NULL\n", __func__);
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL_GPL(thermal_update_temp_thresholds);
+
+/**
+ * thermal_update_temp_rate() - Update the rate for the temp sensor to read and
+ * report the temperature data.
+ *
+ * @rate: The rate to read and report the data to the governor. Rate is defined
+ * per the temperature sensor driver
+ *
+ * Return is the current rate of the temperature acquisition.
+ */
+int thermal_update_temp_rate(struct thermal_dev *temp_sensor, int rate)
+{
+ int ret_rate = -EOPNOTSUPP;
+ if (temp_sensor) {
+ if ((temp_sensor->dev_ops) &&
+ (temp_sensor->dev_ops->set_temp_report_rate)) {
+ pr_debug("%s: Setting new temp report rate to %i\n",
+ __func__, rate);
+ ret_rate = temp_sensor->dev_ops->set_temp_report_rate(temp_sensor, rate);
+ }
+ } else
+ pr_err("%s:Temp sensor pointer is NULL\n", __func__);
+
+ return ret_rate;
+}
+EXPORT_SYMBOL_GPL(thermal_update_temp_rate);
+
+/**
+ * thermal_init_thermal_state() - Initialize the domain thermal state machine.
+ * Once all the thermal devices are available in the domain.
+ * Force the thermal sensor for the domain to report it's current
+ * temperature.
+ *
+ * @tdev: The thermal device that just registered
+ *
+ * Returns -ENODEV for empty lists and 0 for success
+ */
+static int thermal_init_thermal_state(struct thermal_dev *tdev)
+{
+ struct thermal_domain *domain;
+
+ if (list_empty(&thermal_domain_list)) {
+ pr_err("%s: No cooling devices registered\n", __func__);
+ return -ENODEV;
+ }
+
+ mutex_lock(&thermal_domain_list_lock);
+ list_for_each_entry(domain, &thermal_domain_list, node) {
+ if (!strcmp(domain->domain_name, tdev->domain_name))
+ goto check_domain;
+ }
+
+check_domain:
+ mutex_unlock(&thermal_domain_list_lock);
+ if (domain->temp_sensor &&
+ domain->governor &&
+ domain->cooling_agents.next)
+ thermal_request_temp(tdev);
+ else
+ pr_debug("%s:Not all components registered for %s domain\n",
+ __func__, domain->domain_name);
+
+ return 0;
+}
+
+/**
+ * thermal_governor_dev_register() - Registration call for thermal domain governors
+ *
+ * @tdev: The thermal governor device structure.
+ *
+ * Returns 0 for a successful registration of the governor to a domain
+ * ENOMEM if the domain could not be created.
+ *
+ */
+int thermal_governor_dev_register(struct thermal_dev *tdev)
+{
+ struct thermal_domain *therm_dom;
+ struct thermal_domain *domain;
+
+ tdev->index = atomic_inc_return(&device_count);
+ if (list_empty(&thermal_domain_list)) {
+ goto init_governor;
+ } else {
+ mutex_lock(&thermal_domain_list_lock);
+ list_for_each_entry(domain, &thermal_domain_list, node) {
+ if (!strcmp(domain->domain_name, tdev->domain_name)) {
+ pr_debug("%s:Found %s\n", __func__,
+ domain->domain_name);
+ domain->governor = tdev;
+ goto out;
+ }
+ }
+ mutex_unlock(&thermal_domain_list_lock);
+ }
+
+init_governor:
+ therm_dom = kzalloc(sizeof(struct thermal_domain), GFP_KERNEL);
+ if (!therm_dom) {
+ pr_err("%s:Cannot allocate domain memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ therm_dom->governor = tdev;
+ therm_dom->domain_name = tdev->domain_name;
+ pr_info("%s:Adding %s governor\n", __func__, tdev->name);
+ mutex_lock(&thermal_domain_list_lock);
+ list_add(&therm_dom->node, &thermal_domain_list);
+out:
+ mutex_unlock(&thermal_domain_list_lock);
+ thermal_init_thermal_state(tdev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(thermal_governor_dev_register);
+
+/**
+ * thermal_governor_dev_unregister() - Unregistration call for thermal domain
+ * governors.
+ *
+ * @tdev: The thermal governor device structure.
+ *
+ */
+void thermal_governor_dev_unregister(struct thermal_dev *tdev)
+{
+ struct thermal_domain *domain;
+
+ mutex_lock(&thermal_domain_list_lock);
+
+ list_for_each_entry(domain, &thermal_domain_list, node) {
+ if (!strcmp(domain->domain_name, tdev->domain_name)) {
+ kfree(domain->governor);
+ domain->governor = NULL;
+ }
+ }
+
+ mutex_unlock(&thermal_domain_list_lock);
+ return;
+}
+EXPORT_SYMBOL_GPL(thermal_governor_dev_unregister);
+
+/**
+ * thermal_cooling_dev_register() - Registration call for cooling agents
+ *
+ * @tdev: The cooling agent device structure.
+ *
+ * Returns 0 for a successful registration of a cooling agent to a domain
+ * ENOMEM if the domain could not be created.
+ */
+int thermal_cooling_dev_register(struct thermal_dev *tdev)
+{
+ struct thermal_domain *therm_dom;
+ struct thermal_domain *domain;
+
+ pr_debug("%s:Registering %s cooling device\n", __func__, tdev->name);
+ tdev->index = atomic_inc_return(&device_count);
+
+ if (list_empty(&thermal_domain_list)) {
+ goto init_cooling_agent;
+ } else {
+ mutex_lock(&thermal_domain_list_lock);
+ list_for_each_entry(domain, &thermal_domain_list, node) {
+ pr_debug("%s:Found %s %s\n", __func__,
+ domain->domain_name, tdev->domain_name);
+ if (!strcmp(domain->domain_name, tdev->domain_name)) {
+ if (!domain->cooling_agents.next)
+ INIT_LIST_HEAD(&domain->cooling_agents);
+ list_add(&tdev->node, &domain->cooling_agents);
+ goto out;
+ }
+ }
+ mutex_unlock(&thermal_domain_list_lock);
+ }
+
+init_cooling_agent:
+ therm_dom = kzalloc(sizeof(struct thermal_domain), GFP_KERNEL);
+ if (!therm_dom) {
+ pr_err("%s:Cannot allocate domain memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ therm_dom->domain_name = tdev->domain_name;
+ INIT_LIST_HEAD(&therm_dom->cooling_agents);
+ list_add(&tdev->node, &therm_dom->cooling_agents);
+ mutex_lock(&thermal_domain_list_lock);
+ list_add(&therm_dom->node, &thermal_domain_list);
+out:
+ mutex_unlock(&thermal_domain_list_lock);
+ thermal_init_thermal_state(tdev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(thermal_cooling_dev_register);
+
+/**
+ * thermal_cooling_dev_unregister() - Unregistration call for cooling agents
+ *
+ * @tdev: The cooling agent device structure.
+ *
+ */
+void thermal_cooling_dev_unregister(struct thermal_dev *tdev)
+{
+ struct thermal_domain *domain;
+
+ mutex_lock(&thermal_domain_list_lock);
+
+ list_for_each_entry(domain, &thermal_domain_list, node) {
+ if (!strcmp(domain->domain_name, tdev->domain_name))
+ list_del(domain->cooling_agents.next);
+ }
+
+ mutex_unlock(&thermal_domain_list_lock);
+ return;
+}
+EXPORT_SYMBOL_GPL(thermal_cooling_dev_unregister);
+
+/**
+ * thermal_sensor_dev_register() - Registration call for temperature sensors
+ *
+ * @tdev: The temperature device structure.
+ *
+ * Returns 0 for a successful registration of the temp sensor to a domain
+ * ENOMEM if the domain could not be created.
+ */
+int thermal_sensor_dev_register(struct thermal_dev *tdev)
+{
+ struct thermal_domain *therm_dom;
+ struct thermal_domain *domain;
+
+ tdev->index = atomic_inc_return(&device_count);
+ if (list_empty(&thermal_domain_list)) {
+ pr_debug("%s:Need to init the %s domain\n",
+ __func__, tdev->domain_name);
+ goto init_sensor;
+ } else {
+ mutex_lock(&thermal_domain_list_lock);
+ list_for_each_entry(domain, &thermal_domain_list, node) {
+ pr_debug("%s:Found %s %s\n", __func__,
+ domain->domain_name, tdev->domain_name);
+ if (!strcmp(domain->domain_name, tdev->domain_name)) {
+ pr_info("%s:Adding %s sensor\n",
+ __func__, tdev->name);
+ domain->temp_sensor = tdev;
+ goto out;
+ }
+ }
+ mutex_unlock(&thermal_domain_list_lock);
+ }
+
+init_sensor:
+ therm_dom = kzalloc(sizeof(struct thermal_domain),
+ GFP_KERNEL);
+ if (!therm_dom) {
+ pr_err("%s:Cannot allocate domain memory\n",
+ __func__);
+ return -ENOMEM;
+ }
+ therm_dom->temp_sensor = tdev;
+ therm_dom->domain_name = tdev->domain_name;
+ pr_debug("%s:Adding %s sensor\n", __func__, tdev->name);
+ mutex_lock(&thermal_domain_list_lock);
+ list_add(&therm_dom->node, &thermal_domain_list);
+out:
+ mutex_unlock(&thermal_domain_list_lock);
+ thermal_init_thermal_state(tdev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(thermal_sensor_dev_register);
+
+/**
+ * thermal_sensor_dev_unregister() - Unregistration call for temperature sensors
+ *
+ * @tdev: The temperature device structure.
+ *
+ */
+void thermal_sensor_dev_unregister(struct thermal_dev *tdev)
+{
+ struct thermal_domain *domain;
+
+ mutex_lock(&thermal_domain_list_lock);
+
+ list_for_each_entry(domain, &thermal_domain_list, node) {
+ if (!strcmp(domain->domain_name, tdev->domain_name)) {
+ kfree(domain->temp_sensor);
+ domain->temp_sensor = NULL;
+ }
+ }
+
+ mutex_unlock(&thermal_domain_list_lock);
+ return;
+}
+EXPORT_SYMBOL_GPL(thermal_sensor_dev_unregister);
+
+static int __init thermal_framework_init(void)
+{
+ return 0;
+}
+
+static void __exit thermal_framework_exit(void)
+{
+ return;
+}
+
+module_init(thermal_framework_init);
+module_exit(thermal_framework_exit);
+
+MODULE_AUTHOR("Dan Murphy <DMurphy@ti.com>");
+MODULE_DESCRIPTION("Thermal Framework driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/thermal_framework.h b/include/linux/thermal_framework.h
new file mode 100644
index 00000000000..f7a9c2783c3
--- /dev/null
+++ b/include/linux/thermal_framework.h
@@ -0,0 +1,96 @@
+/*
+ * Thermal Framework Driver
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Dan Murphy <DMurphy@ti.com>
+ *
+ * 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.
+ *
+*/
+
+#ifndef __LINUX_THERMAL_FRAMEWORK_H__
+#define __LINUX_THERMAL_FRAMEWORK_H__
+
+struct thermal_dev;
+
+/**
+ * struct thermal_dev_ops - Structure for device operation call backs
+ * @get_temp: A temp sensor call back to get the current temperature.
+ * temp is reported in milli degrees.
+ * @set_temp_thresh: Update the temperature sensor thresholds. This can be used
+ * to allow the sensor to only report changes when the thresholds
+ * have been crossed.
+ * @set_temp_report_rate: Update the rate at which the temperature sensor
+ * reports the temperature change. This API should return the
+* current measurement rate that the sensor is measuring at.
+ * @cool_device: The cooling agent call back to process a list of cooling agents
+ * @process_temp: The governors call back for processing a domain temperature
+ *
+ */
+struct thermal_dev_ops {
+ /* Sensor call backs */
+ int (*report_temp) (struct thermal_dev *);
+ int (*set_temp_thresh) (struct thermal_dev *temp_sensor,
+ int min, int max);
+ int (*set_temp_report_rate) (struct thermal_dev *, int rate);
+ int (*init_slope) (struct thermal_dev *);
+ int (*init_offset) (struct thermal_dev *);
+ /* Cooling agent call backs */
+ int (*cool_device) (struct thermal_dev *, int temp);
+ /* Governor call backs */
+ int (*process_temp) (struct list_head *cooling_list,
+ struct thermal_dev *temp_sensor, int temp);
+};
+
+/**
+ * struct thermal_dev - Structure for each thermal device.
+ * @name: The name of the device that is registering to the framework
+ * @domain_name: The temperature domain that the thermal device represents
+ * @dev: Device node
+ * @dev_ops: The device specific operations for the sensor, governor and cooling
+ * agents.
+ * @node: The list node of the
+ * @index: The index of the device created.
+ * @current_temp: The current temperature reported for the specific domain
+ *
+ */
+struct thermal_dev {
+ const char *name;
+ const char *domain_name;
+ struct device *dev;
+ struct thermal_dev_ops *dev_ops;
+ struct list_head node;
+ int index;
+ int current_temp;
+ int slope;
+ int constant_offset;
+ int sen_id;
+
+};
+
+extern int thermal_update_temp_thresholds(struct thermal_dev *temp_sensor,
+ int min, int max);
+extern int thermal_request_temp(struct thermal_dev *tdev);
+extern int thermal_sensor_set_temp(struct thermal_dev *tdev);
+extern int thermal_get_slope(struct thermal_dev *tdev);
+extern int thermal_get_offset(struct thermal_dev *tdev);
+extern int thermal_update_temp_rate(struct thermal_dev *temp_sensor, int rate);
+extern int thermal_cooling_set_level(struct list_head *cooling_list,
+ unsigned int level);
+
+/* Registration and unregistration calls for the thermal devices */
+extern int thermal_sensor_dev_register(struct thermal_dev *tdev);
+extern void thermal_sensor_dev_unregister(struct thermal_dev *tdev);
+extern int thermal_cooling_dev_register(struct thermal_dev *tdev);
+extern void thermal_cooling_dev_unregister(struct thermal_dev *tdev);
+extern int thermal_governor_dev_register(struct thermal_dev *tdev);
+extern void thermal_governor_dev_unregister(struct thermal_dev *tdev);
+
+#endif /* __LINUX_THERMAL_FRAMEWORK_H__ */