2 * drivers/misc/therm_est.c
4 * Copyright (C) 2010-2012 NVIDIA Corporation.
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.
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.
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>
31 int therm_est_get_temp(struct therm_estimator *est, long *temp)
33 *temp = est->cur_temp;
37 int therm_est_set_limits(struct therm_estimator *est,
41 est->therm_est_lo_limit = lo_limit;
42 est->therm_est_hi_limit = hi_limit;
46 int therm_est_set_alert(struct therm_estimator *est,
50 if ((!cb) || est->callback)
54 est->callback_data = cb_data;
59 static void therm_est_work_func(struct work_struct *work)
61 int i, j, index, sum = 0;
63 struct delayed_work *dwork = container_of (work,
64 struct delayed_work, work);
65 struct therm_estimator *est = container_of(
67 struct therm_estimator,
70 for (i = 0; i < est->ndevs; i++) {
71 if (est->devs[i]->get_temp(est->devs[i]->dev_data, &temp))
73 est->devs[i]->hist[(est->ntemp % HIST_LEN)] = temp;
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];
84 est->cur_temp = sum / 100 + est->toffset;
88 if (est->callback && ((est->cur_temp >= est->therm_est_hi_limit) ||
89 (est->cur_temp <= est->therm_est_lo_limit)))
90 est->callback(est->callback_data);
92 queue_delayed_work(est->workqueue, &est->therm_est_work,
93 msecs_to_jiffies(est->polling_period));
96 struct therm_estimator *therm_est_register(
97 struct therm_est_subdevice **devs,
104 struct therm_estimator *est;
105 struct therm_est_subdevice *dev;
107 est = kzalloc(sizeof(struct therm_estimator), GFP_KERNEL);
108 if (IS_ERR_OR_NULL(est))
109 return ERR_PTR(-ENOMEM);
113 est->toffset = toffset;
114 est->polling_period = polling_period;
116 /* initialize history */
117 for (i = 0; i < ndevs; i++) {
120 if (dev->get_temp(dev->dev_data, &temp)) {
122 return ERR_PTR(-EINVAL);
125 for (j = 0; j < HIST_LEN; j++) {
130 est->workqueue = alloc_workqueue("therm_est",
131 WQ_HIGHPRI | WQ_UNBOUND | WQ_RESCUER, 1);
132 INIT_DELAYED_WORK(&est->therm_est_work, therm_est_work_func);
134 queue_delayed_work(est->workqueue,
135 &est->therm_est_work,
136 msecs_to_jiffies(est->polling_period));