xref: /openbsd-src/sys/dev/isa/it.c (revision db3296cf5c1dd9058ceecc3a29fe4aaa0bd26000)
1 /*	$OpenBSD: it.c,v 1.2 2003/05/28 19:21:11 grange Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 Julien Bordet <zejames@greygats.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/device.h>
31 #include <sys/kernel.h>
32 #include <sys/sensors.h>
33 #include <sys/timeout.h>
34 #include <machine/bus.h>
35 
36 #include <dev/isa/isareg.h>
37 #include <dev/isa/isavar.h>
38 
39 #include <dev/isa/itvar.h>
40 
41 #if defined(ITDEBUG)
42 #define DPRINTF(x)		do { printf x; } while (0)
43 #else
44 #define DPRINTF(x)
45 #endif
46 
47 int  it_match(struct device *, void *, void *);
48 void it_attach(struct device *, struct device *, void *);
49 u_int8_t it_readreg(struct it_softc *, int);
50 void it_writereg(struct it_softc *, int, int);
51 void it_setup_volt(struct it_softc *, int, int);
52 void it_setup_temp(struct it_softc *, int, int);
53 void it_setup_fan(struct it_softc *, int, int);
54 
55 void it_generic_stemp(struct it_softc *, struct sensor *);
56 void it_generic_svolt(struct it_softc *, struct sensor *);
57 void it_generic_fanrpm(struct it_softc *, struct sensor *);
58 
59 void it_refresh_sensor_data(struct it_softc *);
60 void it_refresh(void *);
61 
62 struct cfattach it_ca = {
63 	sizeof(struct it_softc),
64 	it_match,
65 	it_attach
66 };
67 
68 struct cfdriver it_cd = {
69 	NULL, "it", DV_DULL
70 };
71 
72 struct timeout it_timeout;
73 
74 int
75 it_match(struct device *parent, void *match, void *aux)
76 {
77 	bus_space_tag_t iot;
78 	bus_space_handle_t ioh;
79 	struct isa_attach_args *ia = aux;
80 	int iobase;
81 	int rv;
82 	u_int8_t cr;
83 
84 	/* Must supply an address */
85 	if (ia->ipa_nio < 1) {
86 		DPRINTF(("%s: ipa_nio=%d\n", __func__, ia->ipa_nio));
87 		return (0);
88 	}
89 
90 	iot = ia->ia_iot;
91 	iobase = ia->ipa_io[0].base;
92 
93 	if (bus_space_map(iot, iobase, 8, 0, &ioh)) {
94 		DPRINTF(("%s: can't map i/o space\n", __func__));
95 		return (0);
96 	}
97 
98 	/* Check for some power-on defaults */
99 	bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CONFIG);
100 	cr = bus_space_read_1(iot, ioh, ITC_DATA);
101 
102 	/* The monitoring may have been enabled by BIOS */
103 	if (cr == 0x18 || cr == 0x19)
104 		rv = 1;
105 
106 	DPRINTF(("it: rv = %d, cr = %x\n", rv, cr));
107 
108 	bus_space_unmap(iot, ioh, 8);
109 
110 	if (rv) {
111 		ia->ipa_nio = 1;
112 		ia->ipa_io[0].length = 8;
113 
114 		ia->ipa_nmem = 0;
115 		ia->ipa_nirq = 0;
116 		ia->ipa_ndrq = 0;
117 	}
118 
119 	return (rv);
120 }
121 
122 void
123 it_attach(struct device *parent, struct device *self, void *aux)
124 {
125 	struct it_softc *sc = (void *)self;
126 	int iobase;
127 	bus_space_tag_t iot;
128 	struct isa_attach_args *ia = aux;
129 	int i;
130 	u_int8_t cr;
131 	extern int nsensors;
132 	extern struct sensors_head sensors;
133 
134         iobase = ia->ipa_io[0].base;
135 	iot = sc->it_iot = ia->ia_iot;
136 
137 	if (bus_space_map(iot, iobase, 8, 0, &sc->it_ioh)) {
138 		printf(": can't map i/o space\n");
139 		return;
140 	}
141 
142 	i = it_readreg(sc, ITD_CHIPID);
143 	switch (i) {
144 		case IT_ID_IT87:
145 			printf(": IT87\n");
146 			break;
147 		default:
148 			printf(": unknown chip (ID %d)\n", i);
149 			break;
150 	}
151 
152 	sc->numsensors = IT_NUM_SENSORS;
153 
154 	/* Reset chip */
155 	it_writereg(sc, ITD_CONFIG, 0x80);
156 
157 	it_setup_fan(sc, 0, 3);
158 	it_setup_volt(sc, 3, 9);
159 	it_setup_temp(sc, 12, 3);
160 
161 	/* Activate monitoring */
162 	cr = it_readreg(sc, ITD_CONFIG);
163 	cr |= 0x01 | 0x08;
164 	it_writereg(sc, ITD_CONFIG, cr);
165 
166 	/* Initialize sensors */
167 	for (i = 0; i < sc->numsensors; ++i) {
168 		strlcpy(sc->sensors[i].device, sc->sc_dev.dv_xname,
169 		    sizeof(sc->sensors[i].device));
170 		sc->sensors[i].num = nsensors++;
171 		SLIST_INSERT_HEAD(&sensors, &sc->sensors[i], list);
172 	}
173 
174 	timeout_set(&it_timeout, it_refresh, sc);
175 	timeout_add(&it_timeout, (15 * hz) / 10);
176 }
177 
178 u_int8_t
179 it_readreg(struct it_softc *sc, int reg)
180 {
181 	bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg);
182 	return (bus_space_read_1(sc->it_iot, sc->it_ioh, ITC_DATA));
183 }
184 
185 void
186 it_writereg(struct it_softc *sc, int reg, int val)
187 {
188 	bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg);
189 	bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_DATA, val);
190 }
191 
192 void
193 it_setup_volt(struct it_softc *sc, int start, int n)
194 {
195 	int i;
196 
197 	for (i = 0; i < n; ++i) {
198 		sc->sensors[start + i].type = SENSOR_VOLTS_DC;
199 	}
200 
201 	sc->sensors[start + 0].rfact = 10000;
202 	snprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc),
203 	    "VCORE_A");
204 	sc->sensors[start + 1].rfact = 10000;
205 	snprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc),
206 	    "VCORE_B");
207 	sc->sensors[start + 2].rfact = 10000;
208 	snprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc),
209 	    "+3.3V");
210 	sc->sensors[start + 3].rfact = (int)(( 16.8 / 10) * 10000);
211 	snprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc),
212 	    "+5V");
213 	sc->sensors[start + 4].rfact = (int)(( 40 / 10) * 10000);
214 	snprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc),
215 	    "+12V");
216 	sc->sensors[start + 5].rfact = (int)(( 31.0 / 10) * 10000);
217 	snprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc),
218 	    "Unused");
219 	sc->sensors[start + 6].rfact = (int)(( 103.0 / 20) * 10000);
220 	snprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc),
221 	    "-12V");
222 	sc->sensors[start + 7].rfact = (int)(( 16.8 / 10) * 10000);
223 	snprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc),
224 	    "+5VSB");
225 	sc->sensors[start + 8].rfact = 10000;
226 	snprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc),
227 	    "VBAT");
228 
229 	/* Enable voltage monitoring */
230 	it_writereg(sc, ITD_VOLTENABLE, 0xff);
231 }
232 
233 void
234 it_setup_temp(struct it_softc *sc, int start, int n)
235 {
236 	int i;
237 
238 	for (i = 0; i < n; ++i) {
239 		sc->sensors[start + i].type = SENSOR_TEMP;
240 		snprintf(sc->sensors[start + i].desc,
241 		    sizeof(sc->sensors[start + i].desc),
242 		    "Temp%d", i + 1);
243 	}
244 
245 	/* Enable temperature monitoring
246 	 * bits 7 and 8 are reserved, so we don't change them */
247 	i = it_readreg(sc, ITD_TEMPENABLE) & 0xc0;
248 	it_writereg(sc, ITD_TEMPENABLE, i | 0x38);
249 }
250 
251 void
252 it_setup_fan(struct it_softc *sc, int start, int n)
253 {
254 	int i;
255 
256 	for (i = 0; i < n; ++i) {
257 		sc->sensors[start + i].type = SENSOR_FANRPM;
258 		snprintf(sc->sensors[start + i].desc,
259 		    sizeof(sc->sensors[start + i].desc),
260 		    "Fan%d", i + 1);
261 	}
262 
263 	/* Enable fan rpm monitoring
264 	 * bits 4 to 6 are the only interesting bits */
265 	i = it_readreg(sc, ITD_FANENABLE) & 0x8f;
266 	it_writereg(sc, ITD_FANENABLE, i | 0x70);
267 }
268 
269 void
270 it_generic_stemp(struct it_softc *sc, struct sensor *sensors)
271 {
272 	int i, sdata;
273 
274 	for (i = 0; i < 3; i++) {
275 		sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i);
276 		/* Convert temperature to Fahrenheit degres */
277 		sensors[i].value = sdata * 1000000 + 273150000;
278 	}
279 }
280 
281 void
282 it_generic_svolt(struct it_softc *sc, struct sensor *sensors)
283 {
284 	int i, sdata;
285 
286 	for (i = 0; i < 9; i++) {
287 		sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i);
288 		DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
289 		/* voltage returned as (mV >> 4) */
290 		sensors[i].value = (sdata << 4);
291 		/* rfact is (factor * 10^4) */
292 		sensors[i].value *= sensors[i].rfact;
293 		/* these two values are negative and formula is different */
294 		if (i == 5)
295 			sensors[i].value -=
296 			    (int) (21.0 / 10 * IT_VREF * 10000);
297 		if (i == 6)
298 			sensors[i].value -=
299 			    (int) (83.0 / 20 * IT_VREF * 10000);
300 		/* division by 10 gets us back to uVDC */
301 		sensors[i].value /= 10;
302 
303 	}
304 }
305 
306 void
307 it_generic_fanrpm(struct it_softc *sc, struct sensor *sensors)
308 {
309 	int i, sdata, divisor;
310 
311 	for (i = 0; i < 2; i++) {
312 		sdata = it_readreg(sc, ITD_SENSORFANBASE + i);
313 		switch (i) {
314 			case 2:
315 				divisor = 2;
316 			case 1:
317 				divisor = (it_readreg(sc,
318 				    ITD_FAN) >> 3) & 0x7;
319 				break;
320 			default:
321 				divisor = it_readreg(sc, ITD_FAN) & 0x7;
322 				break;
323 		}
324 
325 		if (sdata == 0xff || sdata == 0) {
326 			sensors[i].value = 0;
327 		} else {
328 			sensors[i].value = 1350000 / (sdata << divisor);
329 		}
330 	}
331 }
332 
333 /*
334  * pre:  last read occurred >= 1.5 seconds ago
335  * post: sensors[] current data are the latest from the chip
336  */
337 void
338 it_refresh_sensor_data(struct it_softc *sc)
339 {
340 	/* Refresh our stored data for every sensor */
341 	it_generic_stemp(sc, &sc->sensors[12]);
342 	it_generic_svolt(sc, &sc->sensors[3]);
343 	it_generic_fanrpm(sc, &sc->sensors[0]);
344 }
345 
346 void
347 it_refresh(void *arg)
348 {
349 	struct it_softc *sc = (struct it_softc *)arg;
350 
351 	it_refresh_sensor_data(sc);
352 	timeout_add(&it_timeout, (15 * hz) / 10);
353 }
354