xref: /openbsd/sys/arch/sparc64/dev/tda.c (revision 404b540a)
1 /*	$OpenBSD: tda.c,v 1.4 2008/02/27 17:25:00 robert Exp $ */
2 
3 /*
4  * Copyright (c) 2008 Robert Nagy <robert@openbsd.org>
5  * Copyright (c) 2008 Mark Kettenis <kettenis@openbsd.org>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/kernel.h>
23 #include <sys/device.h>
24 #include <sys/sensors.h>
25 
26 #include <machine/autoconf.h>
27 #include <machine/openfirm.h>
28 
29 #include <dev/i2c/i2cvar.h>
30 
31 /* fan control registers */
32 #define TDA_SYSFAN_REG		0xf0
33 #define TDA_CPUFAN_REG		0xf2
34 #define TDA_PSFAN_REG		0xf4
35 
36 #define TDA_FANSPEED_MIN        0x0c
37 #define TDA_FANSPEED_MAX        0x3f
38 
39 #define TDA_PSFAN_ON            0x1f
40 #define TDA_PSFAN_OFF           0x00
41 
42 /* Internal and External temperature senor numbers */
43 #define SENSOR_TEMP_EXT		0
44 #define SENSOR_TEMP_INT		1
45 
46 #define CPU_TEMP_MAX		(67 * 1000000 + 273150000)
47 #define CPU_TEMP_MIN		(57 * 1000000 + 273150000)
48 #define SYS_TEMP_MAX		(30 * 1000000 + 273150000)
49 #define SYS_TEMP_MIN		(20 * 1000000 + 273150000)
50 
51 struct tda_softc {
52 	struct device		sc_dev;
53 	i2c_tag_t		sc_tag;
54 	i2c_addr_t		sc_addr;
55 
56 	u_int16_t		sc_cfan_speed;	/* current CPU fan speed */
57 	u_int16_t		sc_sfan_speed;	/* current SYS fan speed */
58 
59 	int			sc_nsensors;
60 };
61 #define DEVNAME(_s)		((_s)->sc_dev.dv_xname)
62 
63 int	tda_match(struct device *, void *, void *);
64 void	tda_attach(struct device *, struct device *, void *);
65 
66 void	tda_setspeed(struct tda_softc *);
67 void	tda_adjust(void *);
68 
69 struct cfattach tda_ca = {
70 	sizeof(struct tda_softc), tda_match, tda_attach
71 };
72 
73 struct cfdriver tda_cd = {
74 	NULL, "tda", DV_DULL
75 };
76 
77 void *tda_cookie;
78 
79 int
80 tda_match(struct device *parent, void *match, void *aux)
81 {
82 	struct i2c_attach_args *ia = aux;
83 	char name[32];
84 
85 	if (strcmp(ia->ia_name, "tda8444") != 0)
86 		return (0);
87 
88 	/* Only attach on the Sun Blade 1000/2000. */
89 	if (OF_getprop(findroot(), "name", name, sizeof(name)) <= 0)
90 		return (0);
91 	if (strcmp(name, "SUNW,Sun-Blade-1000") != 0)
92 		return (0);
93 
94 	return (1);
95 }
96 
97 void
98 tda_attach(struct device *parent, struct device *self, void *aux)
99 {
100 	struct tda_softc *sc = (struct tda_softc *)self;
101 	struct i2c_attach_args *ia = aux;
102 	int i;
103 
104 	sc->sc_tag = ia->ia_tag;
105 	sc->sc_addr = ia->ia_addr;
106 
107 	printf("\n");
108 
109 	/*
110 	 * Set the fans to maximum speed and save the power levels;
111 	 * the controller is write-only.
112 	 */
113 	sc->sc_cfan_speed = sc->sc_sfan_speed = TDA_FANSPEED_MAX;
114 	tda_setspeed(sc);
115 
116 	/* Get the number of sensor devices. */
117 	for (i = 0; i < MAXSENSORDEVICES; i++) {
118 		if (sensordev_get(i) == NULL)
119 			break;
120 	}
121 	sc->sc_nsensors = i;
122 
123 	if (!sc->sc_nsensors) {
124 		printf("%s: no temperature sensors found\n", DEVNAME(sc));
125 		return;
126 	}
127 
128 	if (sensor_task_register(sc, tda_adjust, 10) == NULL) {
129 		printf("%s: unable to register update task\n", DEVNAME(sc));
130 		return;
131 	}
132 
133 	tda_cookie = sc;
134 }
135 
136 void
137 tda_setspeed(struct tda_softc *sc)
138 {
139 	u_int8_t cmd[2];
140 
141 	if (sc->sc_cfan_speed < TDA_FANSPEED_MIN)
142 		sc->sc_cfan_speed = TDA_FANSPEED_MIN;
143 	if (sc->sc_sfan_speed < TDA_FANSPEED_MIN)
144 		sc->sc_sfan_speed = TDA_FANSPEED_MIN;
145 	if (sc->sc_cfan_speed > TDA_FANSPEED_MAX)
146 		sc->sc_cfan_speed = TDA_FANSPEED_MAX;
147 	if (sc->sc_sfan_speed > TDA_FANSPEED_MAX)
148 		sc->sc_sfan_speed = TDA_FANSPEED_MAX;
149 
150 	iic_acquire_bus(sc->sc_tag, 0);
151 
152 	cmd[0] = TDA_CPUFAN_REG;
153 	cmd[1] = sc->sc_cfan_speed;
154 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
155 	    sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) {
156 		printf("%s: cannot write cpu-fan register\n",
157 		    DEVNAME(sc));
158 		iic_release_bus(sc->sc_tag, 0);
159 		return;
160         }
161 
162 	cmd[0] = TDA_SYSFAN_REG;
163 	cmd[1] = sc->sc_sfan_speed;
164 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
165 	    sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) {
166 		printf("%s: cannot write system-fan register\n",
167 		    DEVNAME(sc));
168 		iic_release_bus(sc->sc_tag, 0);
169 		return;
170         }
171 
172 	iic_release_bus(sc->sc_tag, 0);
173 
174 #if 0
175         printf("%s: changed fan speed to cpu=%d system=%d\n",
176                DEVNAME(sc), sc->sc_cfan_speed, sc->sc_sfan_speed);
177 #endif
178 
179 }
180 
181 void
182 tda_adjust(void *v)
183 {
184 	struct tda_softc *sc = v;
185 	struct ksensor *ks;
186 	u_int64_t ctemp, stemp;
187 	int i;
188 
189 	/* Default to running the fans at maximum speed. */
190 	sc->sc_cfan_speed = sc->sc_sfan_speed = TDA_FANSPEED_MAX;
191 
192 	ctemp = stemp = 0;
193 	for (i = 0; i < sc->sc_nsensors; i++) {
194 		ks = sensor_find(i, SENSOR_TEMP, SENSOR_TEMP_EXT);
195 		if (ks == NULL) {
196 			printf("%s: failed to get external sensor\n",
197 			    DEVNAME(sc));
198 			goto out;
199 		}
200 		ctemp = MAX(ctemp, ks->value);
201 
202 		ks = sensor_find(i, SENSOR_TEMP, SENSOR_TEMP_INT);
203 		if (ks == NULL) {
204 			printf("%s: failed to get internal sensors\n",
205 			    DEVNAME(sc));
206 			goto out;
207 		}
208 		stemp = MAX(stemp, ks->value);
209 	}
210 
211 	if (ctemp < CPU_TEMP_MIN)
212 		sc->sc_cfan_speed = TDA_FANSPEED_MIN;
213 	else if (ctemp < CPU_TEMP_MAX)
214 		sc->sc_cfan_speed = TDA_FANSPEED_MIN +
215 			(ctemp - CPU_TEMP_MIN) *
216 			(TDA_FANSPEED_MAX - TDA_FANSPEED_MIN) /
217 			(CPU_TEMP_MAX - CPU_TEMP_MIN);
218 
219 	if (stemp < SYS_TEMP_MIN)
220 		sc->sc_sfan_speed = TDA_FANSPEED_MIN;
221 	else if (stemp < SYS_TEMP_MAX)
222 		sc->sc_sfan_speed = TDA_FANSPEED_MIN +
223 			(stemp - SYS_TEMP_MIN) *
224 			(TDA_FANSPEED_MAX - TDA_FANSPEED_MIN) /
225 			(SYS_TEMP_MAX - SYS_TEMP_MIN);
226 
227 out:
228 	tda_setspeed(sc);
229 }
230 
231 /* This code gets called when we are about to drop to ddb,
232  * in order to operate the fans at full speed during the
233  * timeouts are not working.
234  */
235 void
236 tda_full_blast()
237 {
238 	struct tda_softc *sc = tda_cookie;
239 	u_int8_t cmd[2];
240 
241 	if (sc == NULL)
242 		return;
243 
244 	sc->sc_cfan_speed = sc->sc_sfan_speed = TDA_FANSPEED_MAX;
245 
246 	iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
247 
248 	cmd[0] = TDA_CPUFAN_REG;
249 	cmd[1] = sc->sc_cfan_speed;
250 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
251 	    sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) {
252 		printf("%s: cannot write cpu-fan register\n",
253 		    DEVNAME(sc));
254 		iic_release_bus(sc->sc_tag, I2C_F_POLL);
255 		return;
256         }
257 
258 	cmd[0] = TDA_SYSFAN_REG;
259 	cmd[1] = sc->sc_sfan_speed;
260 	if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
261 	    sc->sc_addr, &cmd, sizeof(cmd), NULL, 0, 0)) {
262 		printf("%s: cannot write system-fan register\n",
263 		    DEVNAME(sc));
264 		iic_release_bus(sc->sc_tag, I2C_F_POLL);
265 		return;
266 	}
267 
268 	iic_release_bus(sc->sc_tag, I2C_F_POLL);
269 }
270