diff options
author | Joshua Primero <jprimero@nvidia.com> | 2012-05-31 18:11:23 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 12:13:13 -0700 |
commit | 2d43a46c3a0f70da190c985e8f4c7be096b5ef72 (patch) | |
tree | 76645cf9db9c96d1bf5c9d42a09b68afc1124eea /drivers/misc | |
parent | 478614075eb7328a81e46145c40b23b3240ec63b (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/Kconfig | 6 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/therm_est.c | 139 |
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; +} |