summaryrefslogtreecommitdiff
path: root/drivers/misc
diff options
context:
space:
mode:
authorJoshua Primero <jprimero@nvidia.com>2012-05-31 18:11:23 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 12:13:13 -0700
commit2d43a46c3a0f70da190c985e8f4c7be096b5ef72 (patch)
tree76645cf9db9c96d1bf5c9d42a09b68afc1124eea /drivers/misc
parent478614075eb7328a81e46145c40b23b3240ec63b (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> Rebase-Id: Reb6f2ab85d80012c062621d8b5782a61ce0a1ddc
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/Kconfig6
-rw-r--r--drivers/misc/Makefile1
-rw-r--r--drivers/misc/therm_est.c139
3 files changed, 146 insertions, 0 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3250e8389f12..05706f05fda2 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -579,6 +579,12 @@ config APANIC_PLABEL
If your platform uses a different flash partition label for storing
crashdumps, enter it here.
+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 9e7ca087787a..f691eb8eac5c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -63,3 +63,4 @@ obj-$(CONFIG_TEGRA_CRYPTO_DEV) += tegra-cryptodev.o
obj-$(CONFIG_TEGRA_BB_SUPPORT) += tegra-baseband/
obj-$(CONFIG_MAX1749_VIBRATOR) += max1749.o
obj-$(CONFIG_APANIC) += apanic.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;
+}