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.
 
  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"
 
  21 #define DBG(args...)    printk(args)
 
  23 #define DBG(args...)    do { } while(0)
 
  26 void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param)
 
  28         memset(st, 0, sizeof(struct wf_pid_state));
 
  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;
 
  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 */
 
  45                 for (i = 0; i < hlen; i++) {
 
  46                         st->samples[i] = new_sample;
 
  47                         st->errors[i] = error;
 
  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)
 
  72         target = max(target, st->param.min);
 
  73         target = min(target, st->param.max);
 
  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));
 
  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 */
 
 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;
 
 106                 st->index = st->tindex = 0;
 
 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);
 
 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");