summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Primero <jprimero@nvidia.com>2012-05-31 21:11:23 -0400
committerNicolin Chen <nicolinc@nvidia.com>2017-08-14 21:38:51 -0400
commitc911cea00d8b0275f80362efae41bfcdae4fe136 (patch)
tree429ed3fd98451f002b50f590c81cdad0ac89cf1a
parent34c6962a85813f6c99534000856282a6daf51916 (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.c139
-rw-r--r--include/linux/therm_est.h77
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
31int therm_est_get_temp(struct therm_estimator *est, long *temp)
32{
33 *temp = est->cur_temp;
34 return 0;
35}
36
37int 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
46int 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
59static 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
96struct 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
24struct 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
31struct 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
47struct therm_estimator *therm_est_register(
48 struct therm_est_subdevice **devs,
49 int ndevs,
50 long toffset,
51 long pperiod);
52int therm_est_get_temp(struct therm_estimator *est, long *temp);
53int therm_est_set_limits(struct therm_estimator *est,
54 long lo_limit,
55 long hi_limit);
56int therm_est_set_alert(struct therm_estimator *est,
57 void (*cb)(void *),
58 void *cb_data);
59#else
60static 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; }
66static inline int therm_est_get_temp(struct therm_estimator *est, long *temp)
67{ return -EINVAL; }
68static inline int therm_est_set_limits(struct therm_estimator *est,
69 long lo_limit,
70 long hi_limit)
71{ return -EINVAL; }
72static 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 */