Committer: Michael Beasley <mike@snafu.setup>
[mikesnafu-overlay.git] / drivers / macintosh / windfarm_pid.c
blobf10efb28cae42ef355e42c53d68d920b062b60d4
1 /*
2 * Windfarm PowerMac thermal control. Generic PID helpers
4 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
5 * <benh@kernel.crashing.org>
7 * Released under the term of the GNU GPL v2.
8 */
10 #include <linux/types.h>
11 #include <linux/errno.h>
12 #include <linux/kernel.h>
13 #include <linux/string.h>
14 #include <linux/module.h>
16 #include "windfarm_pid.h"
18 #undef DEBUG
20 #ifdef DEBUG
21 #define DBG(args...) printk(args)
22 #else
23 #define DBG(args...) do { } while(0)
24 #endif
26 void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param)
28 memset(st, 0, sizeof(struct wf_pid_state));
29 st->param = *param;
30 st->first = 1;
32 EXPORT_SYMBOL_GPL(wf_pid_init);
34 s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample)
36 s64 error, integ, deriv;
37 s32 target;
38 int i, hlen = st->param.history_len;
40 /* Calculate error term */
41 error = new_sample - st->param.itarget;
43 /* Get samples into our history buffer */
44 if (st->first) {
45 for (i = 0; i < hlen; i++) {
46 st->samples[i] = new_sample;
47 st->errors[i] = error;
49 st->first = 0;
50 st->index = 0;
51 } else {
52 st->index = (st->index + 1) % hlen;
53 st->samples[st->index] = new_sample;
54 st->errors[st->index] = error;
57 /* Calculate integral term */
58 for (i = 0, integ = 0; i < hlen; i++)
59 integ += st->errors[(st->index + hlen - i) % hlen];
60 integ *= st->param.interval;
62 /* Calculate derivative term */
63 deriv = st->errors[st->index] -
64 st->errors[(st->index + hlen - 1) % hlen];
65 deriv /= st->param.interval;
67 /* Calculate target */
68 target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd +
69 error * (s64)st->param.gp) >> 36);
70 if (st->param.additive)
71 target += st->target;
72 target = max(target, st->param.min);
73 target = min(target, st->param.max);
74 st->target = target;
76 return st->target;
78 EXPORT_SYMBOL_GPL(wf_pid_run);
80 void wf_cpu_pid_init(struct wf_cpu_pid_state *st,
81 struct wf_cpu_pid_param *param)
83 memset(st, 0, sizeof(struct wf_cpu_pid_state));
84 st->param = *param;
85 st->first = 1;
87 EXPORT_SYMBOL_GPL(wf_cpu_pid_init);
89 s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
91 s64 integ, deriv, prop;
92 s32 error, target, sval, adj;
93 int i, hlen = st->param.history_len;
95 /* Calculate error term */
96 error = st->param.pmaxadj - new_power;
98 /* Get samples into our history buffer */
99 if (st->first) {
100 for (i = 0; i < hlen; i++) {
101 st->powers[i] = new_power;
102 st->errors[i] = error;
104 st->temps[0] = st->temps[1] = new_temp;
105 st->first = 0;
106 st->index = st->tindex = 0;
107 } else {
108 st->index = (st->index + 1) % hlen;
109 st->powers[st->index] = new_power;
110 st->errors[st->index] = error;
111 st->tindex = (st->tindex + 1) % 2;
112 st->temps[st->tindex] = new_temp;
115 /* Calculate integral term */
116 for (i = 0, integ = 0; i < hlen; i++)
117 integ += st->errors[(st->index + hlen - i) % hlen];
118 integ *= st->param.interval;
119 integ *= st->param.gr;
120 sval = st->param.tmax - (s32)(integ >> 20);
121 adj = min(st->param.ttarget, sval);
123 DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj);
125 /* Calculate derivative term */
126 deriv = st->temps[st->tindex] -
127 st->temps[(st->tindex + 2 - 1) % 2];
128 deriv /= st->param.interval;
129 deriv *= st->param.gd;
131 /* Calculate proportional term */
132 prop = st->last_delta = (new_temp - adj);
133 prop *= st->param.gp;
135 DBG("deriv: %lx, prop: %lx\n", deriv, prop);
137 /* Calculate target */
138 target = st->target + (s32)((deriv + prop) >> 36);
139 target = max(target, st->param.min);
140 target = min(target, st->param.max);
141 st->target = target;
143 return st->target;
145 EXPORT_SYMBOL_GPL(wf_cpu_pid_run);
147 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
148 MODULE_DESCRIPTION("PID algorithm for PowerMacs thermal control");
149 MODULE_LICENSE("GPL");