Path: blob/master/drivers/macintosh/windfarm_pid.c
15111 views
/*1* Windfarm PowerMac thermal control. Generic PID helpers2*3* (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.4* <[email protected]>5*6* Released under the term of the GNU GPL v2.7*/89#include <linux/types.h>10#include <linux/errno.h>11#include <linux/kernel.h>12#include <linux/string.h>13#include <linux/module.h>1415#include "windfarm_pid.h"1617#undef DEBUG1819#ifdef DEBUG20#define DBG(args...) printk(args)21#else22#define DBG(args...) do { } while(0)23#endif2425void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param)26{27memset(st, 0, sizeof(struct wf_pid_state));28st->param = *param;29st->first = 1;30}31EXPORT_SYMBOL_GPL(wf_pid_init);3233s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample)34{35s64 error, integ, deriv;36s32 target;37int i, hlen = st->param.history_len;3839/* Calculate error term */40error = new_sample - st->param.itarget;4142/* Get samples into our history buffer */43if (st->first) {44for (i = 0; i < hlen; i++) {45st->samples[i] = new_sample;46st->errors[i] = error;47}48st->first = 0;49st->index = 0;50} else {51st->index = (st->index + 1) % hlen;52st->samples[st->index] = new_sample;53st->errors[st->index] = error;54}5556/* Calculate integral term */57for (i = 0, integ = 0; i < hlen; i++)58integ += st->errors[(st->index + hlen - i) % hlen];59integ *= st->param.interval;6061/* Calculate derivative term */62deriv = st->errors[st->index] -63st->errors[(st->index + hlen - 1) % hlen];64deriv /= st->param.interval;6566/* Calculate target */67target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd +68error * (s64)st->param.gp) >> 36);69if (st->param.additive)70target += st->target;71target = max(target, st->param.min);72target = min(target, st->param.max);73st->target = target;7475return st->target;76}77EXPORT_SYMBOL_GPL(wf_pid_run);7879void wf_cpu_pid_init(struct wf_cpu_pid_state *st,80struct wf_cpu_pid_param *param)81{82memset(st, 0, sizeof(struct wf_cpu_pid_state));83st->param = *param;84st->first = 1;85}86EXPORT_SYMBOL_GPL(wf_cpu_pid_init);8788s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)89{90s64 integ, deriv, prop;91s32 error, target, sval, adj;92int i, hlen = st->param.history_len;9394/* Calculate error term */95error = st->param.pmaxadj - new_power;9697/* Get samples into our history buffer */98if (st->first) {99for (i = 0; i < hlen; i++) {100st->powers[i] = new_power;101st->errors[i] = error;102}103st->temps[0] = st->temps[1] = new_temp;104st->first = 0;105st->index = st->tindex = 0;106} else {107st->index = (st->index + 1) % hlen;108st->powers[st->index] = new_power;109st->errors[st->index] = error;110st->tindex = (st->tindex + 1) % 2;111st->temps[st->tindex] = new_temp;112}113114/* Calculate integral term */115for (i = 0, integ = 0; i < hlen; i++)116integ += st->errors[(st->index + hlen - i) % hlen];117integ *= st->param.interval;118integ *= st->param.gr;119sval = st->param.tmax - (s32)(integ >> 20);120adj = min(st->param.ttarget, sval);121122DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj);123124/* Calculate derivative term */125deriv = st->temps[st->tindex] -126st->temps[(st->tindex + 2 - 1) % 2];127deriv /= st->param.interval;128deriv *= st->param.gd;129130/* Calculate proportional term */131prop = st->last_delta = (new_temp - adj);132prop *= st->param.gp;133134DBG("deriv: %lx, prop: %lx\n", deriv, prop);135136/* Calculate target */137target = st->target + (s32)((deriv + prop) >> 36);138target = max(target, st->param.min);139target = min(target, st->param.max);140st->target = target;141142return st->target;143}144EXPORT_SYMBOL_GPL(wf_cpu_pid_run);145146MODULE_AUTHOR("Benjamin Herrenschmidt <[email protected]>");147MODULE_DESCRIPTION("PID algorithm for PowerMacs thermal control");148MODULE_LICENSE("GPL");149150151