diff options
| author | Joshua Primero <jprimero@nvidia.com> | 2012-05-31 21:11:23 -0400 |
|---|---|---|
| committer | Nicolin Chen <nicolinc@nvidia.com> | 2017-08-14 21:38:51 -0400 |
| commit | c911cea00d8b0275f80362efae41bfcdae4fe136 (patch) | |
| tree | 429ed3fd98451f002b50f590c81cdad0ac89cf1a | |
| parent | 34c6962a85813f6c99534000856282a6daf51916 (diff) | |
drivers: misc: Thermal estimator driver
Added driver which estimates temperature based on
a linear formula from other temperature sensors.
Edit: WQ_RESCUER has been removed for K4.9 port.
bug 1007726
Change-Id: Ic0d3ba7f0d369d4321f55b03e6326ff4efbb512e
Signed-off-by: Joshua Primero <jprimero@nvidia.com>
Reviewed-on: http://git-master/r/105988
| -rw-r--r-- | drivers/misc/therm_est.c | 139 | ||||
| -rw-r--r-- | include/linux/therm_est.h | 77 |
2 files changed, 216 insertions, 0 deletions
diff --git a/drivers/misc/therm_est.c b/drivers/misc/therm_est.c new file mode 100644 index 000000000..485d10d36 --- /dev/null +++ b/drivers/misc/therm_est.c | |||
| @@ -0,0 +1,139 @@ | |||
| 1 | /* | ||
| 2 | * drivers/misc/therm_est.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2010-2012 NVIDIA Corporation. | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/cpufreq.h> | ||
| 19 | #include <linux/delay.h> | ||
| 20 | #include <linux/mutex.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/err.h> | ||
| 23 | #include <linux/clk.h> | ||
| 24 | #include <linux/debugfs.h> | ||
| 25 | #include <linux/seq_file.h> | ||
| 26 | #include <linux/uaccess.h> | ||
| 27 | #include <linux/slab.h> | ||
| 28 | #include <linux/syscalls.h> | ||
| 29 | #include <linux/therm_est.h> | ||
| 30 | |||
| 31 | int therm_est_get_temp(struct therm_estimator *est, long *temp) | ||
| 32 | { | ||
| 33 | *temp = est->cur_temp; | ||
| 34 | return 0; | ||
| 35 | } | ||
| 36 | |||
| 37 | int therm_est_set_limits(struct therm_estimator *est, | ||
| 38 | long lo_limit, | ||
| 39 | long hi_limit) | ||
| 40 | { | ||
| 41 | est->therm_est_lo_limit = lo_limit; | ||
| 42 | est->therm_est_hi_limit = hi_limit; | ||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | int therm_est_set_alert(struct therm_estimator *est, | ||
| 47 | void (*cb)(void *), | ||
| 48 | void *cb_data) | ||
| 49 | { | ||
| 50 | if ((!cb) || est->callback) | ||
| 51 | BUG(); | ||
| 52 | |||
| 53 | est->callback = cb; | ||
| 54 | est->callback_data = cb_data; | ||
| 55 | |||
| 56 | return 0; | ||
| 57 | } | ||
| 58 | |||
| 59 | static void therm_est_work_func(struct work_struct *work) | ||
| 60 | { | ||
| 61 | int i, j, index, sum = 0; | ||
| 62 | long temp; | ||
| 63 | struct delayed_work *dwork = container_of (work, | ||
| 64 | struct delayed_work, work); | ||
| 65 | struct therm_estimator *est = container_of( | ||
| 66 | dwork, | ||
| 67 | struct therm_estimator, | ||
| 68 | therm_est_work); | ||
| 69 | |||
| 70 | for (i = 0; i < est->ndevs; i++) { | ||
| 71 | if (est->devs[i]->get_temp(est->devs[i]->dev_data, &temp)) | ||
| 72 | continue; | ||
| 73 | est->devs[i]->hist[(est->ntemp % HIST_LEN)] = temp; | ||
| 74 | } | ||
| 75 | |||
| 76 | for (i = 0; i < est->ndevs; i++) { | ||
| 77 | for (j = 0; j < HIST_LEN; j++) { | ||
| 78 | index = (est->ntemp - j + HIST_LEN) % HIST_LEN; | ||
| 79 | sum += est->devs[i]->hist[index] * | ||
| 80 | est->devs[i]->coeffs[j]; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | |||
| 84 | est->cur_temp = sum / 100 + est->toffset; | ||
| 85 | |||
| 86 | est->ntemp++; | ||
| 87 | |||
| 88 | if (est->callback && ((est->cur_temp >= est->therm_est_hi_limit) || | ||
| 89 | (est->cur_temp <= est->therm_est_hi_limit))) | ||
| 90 | est->callback(est->callback_data); | ||
| 91 | |||
| 92 | queue_delayed_work(est->workqueue, &est->therm_est_work, | ||
| 93 | msecs_to_jiffies(est->polling_period)); | ||
| 94 | } | ||
| 95 | |||
| 96 | struct therm_estimator *therm_est_register( | ||
| 97 | struct therm_est_subdevice **devs, | ||
| 98 | int ndevs, | ||
| 99 | long toffset, | ||
| 100 | long polling_period) | ||
| 101 | { | ||
| 102 | int i, j; | ||
| 103 | long temp; | ||
| 104 | struct therm_estimator *est; | ||
| 105 | struct therm_est_subdevice *dev; | ||
| 106 | |||
| 107 | est = kzalloc(sizeof(struct therm_estimator), GFP_KERNEL); | ||
| 108 | if (IS_ERR_OR_NULL(est)) | ||
| 109 | return ERR_PTR(-ENOMEM); | ||
| 110 | |||
| 111 | est->devs = devs; | ||
| 112 | est->ndevs = ndevs; | ||
| 113 | est->toffset = toffset; | ||
| 114 | est->polling_period = polling_period; | ||
| 115 | |||
| 116 | /* initialize history */ | ||
| 117 | for (i = 0; i < ndevs; i++) { | ||
| 118 | dev = est->devs[i]; | ||
| 119 | |||
| 120 | if (dev->get_temp(dev->dev_data, &temp)) { | ||
| 121 | kfree(est); | ||
| 122 | return ERR_PTR(-EINVAL); | ||
| 123 | } | ||
| 124 | |||
| 125 | for (j = 0; j < HIST_LEN; j++) { | ||
| 126 | dev->hist[j] = temp; | ||
| 127 | } | ||
| 128 | } | ||
| 129 | |||
| 130 | est->workqueue = alloc_workqueue("therm_est", | ||
| 131 | WQ_HIGHPRI | WQ_UNBOUND, 1); | ||
| 132 | INIT_DELAYED_WORK(&est->therm_est_work, therm_est_work_func); | ||
| 133 | |||
| 134 | queue_delayed_work(est->workqueue, | ||
| 135 | &est->therm_est_work, | ||
| 136 | msecs_to_jiffies(est->polling_period)); | ||
| 137 | |||
| 138 | return est; | ||
| 139 | } | ||
diff --git a/include/linux/therm_est.h b/include/linux/therm_est.h new file mode 100644 index 000000000..035b08fa9 --- /dev/null +++ b/include/linux/therm_est.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* | ||
| 2 | * include/linux/therm_est.h | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010-2012, NVIDIA Corporation. | ||
| 5 | * | ||
| 6 | * This software is licensed under the terms of the GNU General Public | ||
| 7 | * License version 2, as published by the Free Software Foundation, and | ||
| 8 | * may be copied, distributed, and modified under those terms. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef _LINUX_THERM_EST_H | ||
| 18 | #define _LINUX_THERM_EST_H | ||
| 19 | |||
| 20 | #include <linux/workqueue.h> | ||
| 21 | |||
| 22 | #define HIST_LEN (20) | ||
| 23 | |||
| 24 | struct therm_est_subdevice { | ||
| 25 | void *dev_data; | ||
| 26 | int (*get_temp)(void *, long *); | ||
| 27 | long coeffs[HIST_LEN]; | ||
| 28 | long hist[HIST_LEN]; | ||
| 29 | }; | ||
| 30 | |||
| 31 | struct therm_estimator { | ||
| 32 | long therm_est_lo_limit; | ||
| 33 | long therm_est_hi_limit; | ||
| 34 | void (*callback)(void *); | ||
| 35 | void *callback_data; | ||
| 36 | long cur_temp; | ||
| 37 | long polling_period; | ||
| 38 | struct workqueue_struct *workqueue; | ||
| 39 | struct delayed_work therm_est_work; | ||
| 40 | long toffset; | ||
| 41 | int ntemp; | ||
| 42 | int ndevs; | ||
| 43 | struct therm_est_subdevice **devs; | ||
| 44 | }; | ||
| 45 | |||
| 46 | #ifdef CONFIG_THERM_EST | ||
| 47 | struct therm_estimator *therm_est_register( | ||
| 48 | struct therm_est_subdevice **devs, | ||
| 49 | int ndevs, | ||
| 50 | long toffset, | ||
| 51 | long pperiod); | ||
| 52 | int therm_est_get_temp(struct therm_estimator *est, long *temp); | ||
| 53 | int therm_est_set_limits(struct therm_estimator *est, | ||
| 54 | long lo_limit, | ||
| 55 | long hi_limit); | ||
| 56 | int therm_est_set_alert(struct therm_estimator *est, | ||
| 57 | void (*cb)(void *), | ||
| 58 | void *cb_data); | ||
| 59 | #else | ||
| 60 | static inline struct therm_estimator *therm_est_register( | ||
| 61 | struct therm_est_subdevice **devs, | ||
| 62 | int ndevs, | ||
| 63 | long toffset, | ||
| 64 | long pperiod) | ||
| 65 | { return NULL; } | ||
| 66 | static inline int therm_est_get_temp(struct therm_estimator *est, long *temp) | ||
| 67 | { return -EINVAL; } | ||
| 68 | static inline int therm_est_set_limits(struct therm_estimator *est, | ||
| 69 | long lo_limit, | ||
| 70 | long hi_limit) | ||
| 71 | { return -EINVAL; } | ||
| 72 | static inline int therm_est_set_alert(struct therm_estimator *est, | ||
| 73 | void (*cb)(void *), | ||
| 74 | void *cb_data) | ||
| 75 | { return -EINVAL; } | ||
| 76 | #endif | ||
| 77 | #endif /* _LINUX_THERM_EST_H */ | ||
