Linux Audio

Check our new training course

Loading...
v4.10.11
 
  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
 26void 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}
 32EXPORT_SYMBOL_GPL(wf_pid_init);
 33
 34s32 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}
 78EXPORT_SYMBOL_GPL(wf_pid_run);
 79
 80void 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}
 87EXPORT_SYMBOL_GPL(wf_cpu_pid_init);
 88
 89s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
 90{
 91	s64	integ, deriv, prop;
 92	s32	error, 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 - (s32)(integ >> 20);
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 = st->last_delta = (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}
145EXPORT_SYMBOL_GPL(wf_cpu_pid_run);
146
147MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
148MODULE_DESCRIPTION("PID algorithm for PowerMacs thermal control");
149MODULE_LICENSE("GPL");
v6.2
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Windfarm PowerMac thermal control. Generic PID helpers
  4 *
  5 * (c) Copyright 2005 Benjamin Herrenschmidt, IBM Corp.
  6 *                    <benh@kernel.crashing.org>
 
 
  7 */
  8
  9#include <linux/types.h>
 10#include <linux/errno.h>
 11#include <linux/kernel.h>
 12#include <linux/string.h>
 13#include <linux/module.h>
 14
 15#include "windfarm_pid.h"
 16
 17#undef DEBUG
 18
 19#ifdef DEBUG
 20#define DBG(args...)	printk(args)
 21#else
 22#define DBG(args...)	do { } while(0)
 23#endif
 24
 25void wf_pid_init(struct wf_pid_state *st, struct wf_pid_param *param)
 26{
 27	memset(st, 0, sizeof(struct wf_pid_state));
 28	st->param = *param;
 29	st->first = 1;
 30}
 31EXPORT_SYMBOL_GPL(wf_pid_init);
 32
 33s32 wf_pid_run(struct wf_pid_state *st, s32 new_sample)
 34{
 35	s64	error, integ, deriv;
 36	s32	target;
 37	int	i, hlen = st->param.history_len;
 38
 39	/* Calculate error term */
 40	error = new_sample - st->param.itarget;
 41
 42	/* Get samples into our history buffer */
 43	if (st->first) {
 44		for (i = 0; i < hlen; i++) {
 45			st->samples[i] = new_sample;
 46			st->errors[i] = error;
 47		}
 48		st->first = 0;
 49		st->index = 0;
 50	} else {
 51		st->index = (st->index + 1) % hlen;
 52		st->samples[st->index] = new_sample;
 53		st->errors[st->index] = error;
 54	}
 55
 56	/* Calculate integral term */
 57	for (i = 0, integ = 0; i < hlen; i++)
 58		integ += st->errors[(st->index + hlen - i) % hlen];
 59	integ *= st->param.interval;
 60
 61	/* Calculate derivative term */
 62	deriv = st->errors[st->index] -
 63		st->errors[(st->index + hlen - 1) % hlen];
 64	deriv /= st->param.interval;
 65
 66	/* Calculate target */
 67	target = (s32)((integ * (s64)st->param.gr + deriv * (s64)st->param.gd +
 68		  error * (s64)st->param.gp) >> 36);
 69	if (st->param.additive)
 70		target += st->target;
 71	target = max(target, st->param.min);
 72	target = min(target, st->param.max);
 73	st->target = target;
 74
 75	return st->target;
 76}
 77EXPORT_SYMBOL_GPL(wf_pid_run);
 78
 79void wf_cpu_pid_init(struct wf_cpu_pid_state *st,
 80		     struct wf_cpu_pid_param *param)
 81{
 82	memset(st, 0, sizeof(struct wf_cpu_pid_state));
 83	st->param = *param;
 84	st->first = 1;
 85}
 86EXPORT_SYMBOL_GPL(wf_cpu_pid_init);
 87
 88s32 wf_cpu_pid_run(struct wf_cpu_pid_state *st, s32 new_power, s32 new_temp)
 89{
 90	s64	integ, deriv, prop;
 91	s32	error, target, sval, adj;
 92	int	i, hlen = st->param.history_len;
 93
 94	/* Calculate error term */
 95	error = st->param.pmaxadj - new_power;
 96
 97	/* Get samples into our history buffer */
 98	if (st->first) {
 99		for (i = 0; i < hlen; i++) {
100			st->powers[i] = new_power;
101			st->errors[i] = error;
102		}
103		st->temps[0] = st->temps[1] = new_temp;
104		st->first = 0;
105		st->index = st->tindex = 0;
106	} else {
107		st->index = (st->index + 1) % hlen;
108		st->powers[st->index] = new_power;
109		st->errors[st->index] = error;
110		st->tindex = (st->tindex + 1) % 2;
111		st->temps[st->tindex] = new_temp;
112	}
113
114	/* Calculate integral term */
115	for (i = 0, integ = 0; i < hlen; i++)
116		integ += st->errors[(st->index + hlen - i) % hlen];
117	integ *= st->param.interval;
118	integ *= st->param.gr;
119	sval = st->param.tmax - (s32)(integ >> 20);
120	adj = min(st->param.ttarget, sval);
121
122	DBG("integ: %lx, sval: %lx, adj: %lx\n", integ, sval, adj);
123
124	/* Calculate derivative term */
125	deriv = st->temps[st->tindex] -
126		st->temps[(st->tindex + 2 - 1) % 2];
127	deriv /= st->param.interval;
128	deriv *= st->param.gd;
129
130	/* Calculate proportional term */
131	prop = st->last_delta = (new_temp - adj);
132	prop *= st->param.gp;
133
134	DBG("deriv: %lx, prop: %lx\n", deriv, prop);
135
136	/* Calculate target */
137	target = st->target + (s32)((deriv + prop) >> 36);
138	target = max(target, st->param.min);
139	target = min(target, st->param.max);
140	st->target = target;
141
142	return st->target;
143}
144EXPORT_SYMBOL_GPL(wf_cpu_pid_run);
145
146MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
147MODULE_DESCRIPTION("PID algorithm for PowerMacs thermal control");
148MODULE_LICENSE("GPL");