summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Primero <jprimero@nvidia.com>2012-05-31 18:11:23 -0700
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-06-28 08:57:30 -0700
commit344fc0637ade58d0dee983234777d11e869c98e1 (patch)
tree96dbc0c3757f37ee35a64612246229110174ed0e
parent6fa6a2dac0db8ccdf361a1dfee036aebb145b0a8 (diff)
drivers: misc: Thermal estimator driver
Added driver which estimates temperature based on a linear formula from other temperature sensors. bug 1007726 Change-Id: Ic0d3ba7f0d369d4321f55b03e6326ff4efbb512e Signed-off-by: Joshua Primero <jprimero@nvidia.com> Reviewed-on: http://git-master/r/105988 Reviewed-by: Automatic_Commit_Validation_User GVS: Gerrit_Virtual_Submit Reviewed-by: Sachin Nikam <snikam@nvidia.com>
-rw-r--r--drivers/misc/Kconfig6
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/therm_est.c139
-rw-r--r--include/linux/therm_est.h77
4 files changed, 223 insertions, 0 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 7b7e948ff4f5..0e9992f09412 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -562,6 +562,12 @@ config MAX1749_VIBRATOR
---help---
Adds a timed output vibrator device node for MAX1749 vibrator motor
+config THERM_EST
+ bool "Thermal estimator driver"
+ default n
+ ---help---
+ Thermal driver which estimates temperature based of other sensors.
+
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 5b3728ebcaee..9ba46dbd2c4b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_INV_SENSORS) += inv_mpu/
obj-$(CONFIG_TEGRA_CRYPTO_DEV) += tegra-cryptodev.o
obj-$(CONFIG_TEGRA_BB_SUPPORT) += tegra-baseband/
obj-$(CONFIG_MAX1749_VIBRATOR) += max1749.o
+obj-$(CONFIG_THERM_EST) += therm_est.o
diff --git a/drivers/misc/therm_est.c b/drivers/misc/therm_est.c
new file mode 100644
index 000000000000..fde61bc458ba
--- /dev/null
+++ b/drivers/misc/therm_est.c
@@ -0,0 +1,139 @@
+/*
+ * drivers/misc/therm_est.c
+ *
+ * Copyright (C) 2010-2012 NVIDIA Corporation.
+ *
+ * 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/kernel.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/therm_est.h>
+
+int therm_est_get_temp(struct therm_estimator *est, long *temp)
+{
+ *temp = est->cur_temp;
+ return 0;
+}
+
+int therm_est_set_limits(struct therm_estimator *est,
+ long lo_limit,
+ long hi_limit)
+{
+ est->therm_est_lo_limit = lo_limit;
+ est->therm_est_hi_limit = hi_limit;
+ return 0;
+}
+
+int therm_est_set_alert(struct therm_estimator *est,
+ void (*cb)(void *),
+ void *cb_data)
+{
+ if ((!cb) || est->callback)
+ BUG();
+
+ est->callback = cb;
+ est->callback_data = cb_data;
+
+ return 0;
+}
+
+static void therm_est_work_func(struct work_struct *work)
+{
+ int i, j, index, sum = 0;
+ long temp;
+ struct delayed_work *dwork = container_of (work,
+ struct delayed_work, work);
+ struct therm_estimator *est = container_of(
+ dwork,
+ struct therm_estimator,
+ therm_est_work);
+
+ for (i = 0; i < est->ndevs; i++) {
+ if (est->devs[i]->get_temp(est->devs[i]->dev_data, &temp))
+ continue;
+ est->devs[i]->hist[(est->ntemp % HIST_LEN)] = temp;
+ }
+
+ for (i = 0; i < est->ndevs; i++) {
+ for (j = 0; j < HIST_LEN; j++) {
+ index = (est->ntemp - j + HIST_LEN) % HIST_LEN;
+ sum += est->devs[i]->hist[index] *
+ est->devs[i]->coeffs[j];
+ }
+ }
+
+ est->cur_temp = sum / 100 + est->toffset;
+
+ est->ntemp++;
+
+ if (est->callback && ((est->cur_temp >= est->therm_est_hi_limit) ||
+ (est->cur_temp <= est->therm_est_hi_limit)))
+ est->callback(est->callback_data);
+
+ queue_delayed_work(est->workqueue, &est->therm_est_work,
+ msecs_to_jiffies(est->polling_period));
+}
+
+struct therm_estimator *therm_est_register(
+ struct therm_est_subdevice **devs,
+ int ndevs,
+ long toffset,
+ long polling_period)
+{
+ int i, j;
+ long temp;
+ struct therm_estimator *est;
+ struct therm_est_subdevice *dev;
+
+ est = kzalloc(sizeof(struct therm_estimator), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(est))
+ return ERR_PTR(-ENOMEM);
+
+ est->devs = devs;
+ est->ndevs = ndevs;
+ est->toffset = toffset;
+ est->polling_period = polling_period;
+
+ /* initialize history */
+ for (i = 0; i < ndevs; i++) {
+ dev = est->devs[i];
+
+ if (dev->get_temp(dev->dev_data, &temp)) {
+ kfree(est);
+ return ERR_PTR(-EINVAL);
+ }
+
+ for (j = 0; j < HIST_LEN; j++) {
+ dev->hist[j] = temp;
+ }
+ }
+
+ est->workqueue = alloc_workqueue("therm_est",
+ WQ_HIGHPRI | WQ_UNBOUND | WQ_RESCUER, 1);
+ INIT_DELAYED_WORK(&est->therm_est_work, therm_est_work_func);
+
+ queue_delayed_work(est->workqueue,
+ &est->therm_est_work,
+ msecs_to_jiffies(est->polling_period));
+
+ return est;
+}
diff --git a/include/linux/therm_est.h b/include/linux/therm_est.h
new file mode 100644
index 000000000000..035b08fa9813
--- /dev/null
+++ b/include/linux/therm_est.h
@@ -0,0 +1,77 @@
+/*
+ * include/linux/therm_est.h
+ *
+ * Copyright (c) 2010-2012, NVIDIA Corporation.
+ *
+ * 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_THERM_EST_H
+#define _LINUX_THERM_EST_H
+
+#include <linux/workqueue.h>
+
+#define HIST_LEN (20)
+
+struct therm_est_subdevice {
+ void *dev_data;
+ int (*get_temp)(void *, long *);
+ long coeffs[HIST_LEN];
+ long hist[HIST_LEN];
+};
+
+struct therm_estimator {
+ long therm_est_lo_limit;
+ long therm_est_hi_limit;
+ void (*callback)(void *);
+ void *callback_data;
+ long cur_temp;
+ long polling_period;
+ struct workqueue_struct *workqueue;
+ struct delayed_work therm_est_work;
+ long toffset;
+ int ntemp;
+ int ndevs;
+ struct therm_est_subdevice **devs;
+};
+
+#ifdef CONFIG_THERM_EST
+struct therm_estimator *therm_est_register(
+ struct therm_est_subdevice **devs,
+ int ndevs,
+ long toffset,
+ long pperiod);
+int therm_est_get_temp(struct therm_estimator *est, long *temp);
+int therm_est_set_limits(struct therm_estimator *est,
+ long lo_limit,
+ long hi_limit);
+int therm_est_set_alert(struct therm_estimator *est,
+ void (*cb)(void *),
+ void *cb_data);
+#else
+static inline struct therm_estimator *therm_est_register(
+ struct therm_est_subdevice **devs,
+ int ndevs,
+ long toffset,
+ long pperiod)
+{ return NULL; }
+static inline int therm_est_get_temp(struct therm_estimator *est, long *temp)
+{ return -EINVAL; }
+static inline int therm_est_set_limits(struct therm_estimator *est,
+ long lo_limit,
+ long hi_limit)
+{ return -EINVAL; }
+static inline int therm_est_set_alert(struct therm_estimator *est,
+ void (*cb)(void *),
+ void *cb_data)
+{ return -EINVAL; }
+#endif
+#endif /* _LINUX_THERM_EST_H */