diff options
Diffstat (limited to 'drivers/macintosh/windfarm_pid.c')
-rw-r--r-- | drivers/macintosh/windfarm_pid.c | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/drivers/macintosh/windfarm_pid.c b/drivers/macintosh/windfarm_pid.c new file mode 100644 index 000000000000..2e803b368757 --- /dev/null +++ b/drivers/macintosh/windfarm_pid.c | |||
@@ -0,0 +1,145 @@ | |||
1 | /* | ||
2 | * Windfarm PowerMac thermal control. Generic PID helpers | ||
3 | * | ||
4 | * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp. | ||
5 | * <benh@kernel.crashing.org> | ||
6 | * | ||
7 | * Released under the term of the GNU GPL v2. | ||
8 | */ | ||
9 | |||
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> | ||
15 | |||
16 | #include "windfarm_pid.h" | ||
17 | |||
18 | #undef DEBUG | ||
19 | |||
20 | #ifdef DEBUG | ||
21 | #define DBG(args...) printk(args) | ||
22 | #else | ||
23 | #define DBG(args...) do { } while(0) | ||
24 | #endif | ||
25 | |||
26 | void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param) | ||
27 | { | ||
28 | memset(st, 0, sizeof(struct wf_pid_state)); | ||
29 | st->param = *param; | ||
30 | st->first = 1; | ||
31 | } | ||
32 | EXPORT_SYMBOL_GPL(wf_pid_init); | ||
33 | |||
34 | s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample) | ||
35 | { | ||
36 | s64 error, integ, deriv; | ||
37 | s32 target; | ||
38 | int i, hlen = st->param.history_len; | ||
39 | |||
40 | /* Calculate error term */ | ||
41 | error = new_sample - st->param.itarget; | ||
42 | |||
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; | ||
48 | } | ||
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; | ||
55 | } | ||
56 | |||
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; | ||
61 | |||
62 | /* Calculate derivative term */ | ||
63 | deriv = st->errors[st->index] - | ||
64 | st->errors[(st->index + hlen - 1) % hlen]; | ||
65 | deriv /= st->param.interval; | ||
66 | |||
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; | ||
75 | |||
76 | return st->target; | ||
77 | } | ||
78 | EXPORT_SYMBOL_GPL(wf_pid_run); | ||
79 | |||
80 | void wf_cpu_pid_init(struct wf_cpu_pid_state *st, | ||
81 | struct wf_cpu_pid_param *param) | ||
82 | { | ||
83 | memset(st, 0, sizeof(struct wf_cpu_pid_state)); | ||
84 | st->param = *param; | ||
85 | st->first = 1; | ||
86 | } | ||
87 | EXPORT_SYMBOL_GPL(wf_cpu_pid_init); | ||
88 | |||
89 | s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp) | ||
90 | { | ||
91 | s64 error, integ, deriv, prop; | ||
92 | s32 target, sval, adj; | ||
93 | int i, hlen = st->param.history_len; | ||
94 | |||
95 | /* Calculate error term */ | ||
96 | error = st->param.pmaxadj - new_power; | ||
97 | |||
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; | ||
103 | } | ||
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; | ||
113 | } | ||
114 | |||
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 - ((integ >> 20) & 0xffffffff); | ||
121 | adj = min(st->param.ttarget, sval); | ||
122 | |||
123 | DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj); | ||
124 | |||
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; | ||
130 | |||
131 | /* Calculate proportional term */ | ||
132 | prop = (new_temp - adj); | ||
133 | prop *= st->param.gp; | ||
134 | |||
135 | DBG("deriv: %lx, prop: %lx\n", deriv, prop); | ||
136 | |||
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; | ||
142 | |||
143 | return st->target; | ||
144 | } | ||
145 | EXPORT_SYMBOL_GPL(wf_cpu_pid_run); | ||