1 /*	$OpenBSD: it.c,v 1.15 2005/07/26 19:08:09 grange Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 Julien Bordet <zejames@greyhats.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
it_match(struct device * parent,void * match,void * aux)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 	u_int8_t cr;
82 
83 	iot = ia->ia_iot;
84 	iobase = ia->ipa_io[0].base;
85 
86 	if (bus_space_map(iot, iobase, 8, 0, &ioh)) {
87 		DPRINTF(("it: can't map i/o space\n"));
88 		return (0);
89 	}
90 
91 	/* Check Vendor ID */
92 	bus_space_write_1(iot, ioh, ITC_ADDR, ITD_CHIPID);
93 	cr = bus_space_read_1(iot, ioh, ITC_DATA);
94 	bus_space_unmap(iot, ioh, 8);
95 	DPRINTF(("it: vendor id 0x%x\n", cr));
96 	if (cr != IT_ID_IT87)
97 		return (0);
98 
99 	ia->ipa_nio = 1;
100 	ia->ipa_io[0].length = 8;
101 	ia->ipa_nmem = 0;
102 	ia->ipa_nirq = 0;
103 	ia->ipa_ndrq = 0;
104 
105 	return (1);
106 }
107 
108 void
it_attach(struct device * parent,struct device * self,void * aux)109 it_attach(struct device *parent, struct device *self, void *aux)
110 {
111 	struct it_softc *sc = (void *)self;
112 	int iobase;
113 	bus_space_tag_t iot;
114 	struct isa_attach_args *ia = aux;
115 	int i;
116 	u_int8_t cr;
117 
118 	iobase = ia->ipa_io[0].base;
119 	iot = sc->it_iot = ia->ia_iot;
120 
121 	if (bus_space_map(iot, iobase, 8, 0, &sc->it_ioh)) {
122 		printf(": can't map i/o space\n");
123 		return;
124 	}
125 
126 	i = it_readreg(sc, ITD_CHIPID);
127 	switch (i) {
128 		case IT_ID_IT87:
129 			printf(": IT87\n");
130 			break;
131 	}
132 
133 	sc->numsensors = IT_NUM_SENSORS;
134 
135 	it_setup_fan(sc, 0, 3);
136 	it_setup_volt(sc, 3, 9);
137 	it_setup_temp(sc, 12, 3);
138 
139 	/* Activate monitoring */
140 	cr = it_readreg(sc, ITD_CONFIG);
141 	cr |= 0x01 | 0x08;
142 	it_writereg(sc, ITD_CONFIG, cr);
143 
144 	/* Initialize sensors */
145 	for (i = 0; i < sc->numsensors; ++i) {
146 		strlcpy(sc->sensors[i].device, sc->sc_dev.dv_xname,
147 		    sizeof(sc->sensors[i].device));
148 		SENSOR_ADD(&sc->sensors[i]);
149 	}
150 
151 	timeout_set(&it_timeout, it_refresh, sc);
152 	timeout_add(&it_timeout, (15 * hz) / 10);
153 }
154 
155 u_int8_t
it_readreg(struct it_softc * sc,int reg)156 it_readreg(struct it_softc *sc, int reg)
157 {
158 	bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg);
159 	return (bus_space_read_1(sc->it_iot, sc->it_ioh, ITC_DATA));
160 }
161 
162 void
it_writereg(struct it_softc * sc,int reg,int val)163 it_writereg(struct it_softc *sc, int reg, int val)
164 {
165 	bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_ADDR, reg);
166 	bus_space_write_1(sc->it_iot, sc->it_ioh, ITC_DATA, val);
167 }
168 
169 void
it_setup_volt(struct it_softc * sc,int start,int n)170 it_setup_volt(struct it_softc *sc, int start, int n)
171 {
172 	int i;
173 
174 	for (i = 0; i < n; ++i) {
175 		sc->sensors[start + i].type = SENSOR_VOLTS_DC;
176 	}
177 
178 	sc->sensors[start + 0].rfact = 10000;
179 	snprintf(sc->sensors[start + 0].desc, sizeof(sc->sensors[0].desc),
180 	    "VCORE_A");
181 	sc->sensors[start + 1].rfact = 10000;
182 	snprintf(sc->sensors[start + 1].desc, sizeof(sc->sensors[1].desc),
183 	    "VCORE_B");
184 	sc->sensors[start + 2].rfact = 10000;
185 	snprintf(sc->sensors[start + 2].desc, sizeof(sc->sensors[2].desc),
186 	    "+3.3V");
187 	sc->sensors[start + 3].rfact = (int)(( 16.8 / 10) * 10000);
188 	snprintf(sc->sensors[start + 3].desc, sizeof(sc->sensors[3].desc),
189 	    "+5V");
190 	sc->sensors[start + 4].rfact = (int)(( 40 / 10) * 10000);
191 	snprintf(sc->sensors[start + 4].desc, sizeof(sc->sensors[4].desc),
192 	    "+12V");
193 	sc->sensors[start + 5].rfact = (int)(( 31.0 / 10) * 10000);
194 	snprintf(sc->sensors[start + 5].desc, sizeof(sc->sensors[5].desc),
195 	    "Unused");
196 	sc->sensors[start + 6].rfact = (int)(( 103.0 / 20) * 10000);
197 	snprintf(sc->sensors[start + 6].desc, sizeof(sc->sensors[6].desc),
198 	    "-12V");
199 	sc->sensors[start + 7].rfact = (int)(( 16.8 / 10) * 10000);
200 	snprintf(sc->sensors[start + 7].desc, sizeof(sc->sensors[7].desc),
201 	    "+5VSB");
202 	sc->sensors[start + 8].rfact = 10000;
203 	snprintf(sc->sensors[start + 8].desc, sizeof(sc->sensors[8].desc),
204 	    "VBAT");
205 
206 	/* Enable voltage monitoring */
207 	it_writereg(sc, ITD_VOLTENABLE, 0xff);
208 }
209 
210 void
it_setup_temp(struct it_softc * sc,int start,int n)211 it_setup_temp(struct it_softc *sc, int start, int n)
212 {
213 	int i;
214 
215 	for (i = 0; i < n; ++i) {
216 		sc->sensors[start + i].type = SENSOR_TEMP;
217 		snprintf(sc->sensors[start + i].desc,
218 		    sizeof(sc->sensors[start + i].desc),
219 		    "Temp%d", i + 1);
220 	}
221 
222 	/* Enable temperature monitoring
223 	 * bits 7 and 8 are reserved, so we don't change them */
224 	i = it_readreg(sc, ITD_TEMPENABLE) & 0xc0;
225 	it_writereg(sc, ITD_TEMPENABLE, i | 0x38);
226 }
227 
228 void
it_setup_fan(struct it_softc * sc,int start,int n)229 it_setup_fan(struct it_softc *sc, int start, int n)
230 {
231 	int i;
232 
233 	for (i = 0; i < n; ++i) {
234 		sc->sensors[start + i].type = SENSOR_FANRPM;
235 		snprintf(sc->sensors[start + i].desc,
236 		    sizeof(sc->sensors[start + i].desc),
237 		    "Fan%d", i + 1);
238 	}
239 
240 	/* Enable fan rpm monitoring
241 	 * bits 4 to 6 are the only interesting bits */
242 	i = it_readreg(sc, ITD_FANENABLE) & 0x8f;
243 	it_writereg(sc, ITD_FANENABLE, i | 0x70);
244 }
245 
246 void
it_generic_stemp(struct it_softc * sc,struct sensor * sensors)247 it_generic_stemp(struct it_softc *sc, struct sensor *sensors)
248 {
249 	int i, sdata;
250 
251 	for (i = 0; i < 3; i++) {
252 		sdata = it_readreg(sc, ITD_SENSORTEMPBASE + i);
253 		/* Convert temperature to Fahrenheit degres */
254 		sensors[i].value = sdata * 1000000 + 273150000;
255 	}
256 }
257 
258 void
it_generic_svolt(struct it_softc * sc,struct sensor * sensors)259 it_generic_svolt(struct it_softc *sc, struct sensor *sensors)
260 {
261 	int i, sdata;
262 
263 	for (i = 0; i < 9; i++) {
264 		sdata = it_readreg(sc, ITD_SENSORVOLTBASE + i);
265 		DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
266 		/* voltage returned as (mV >> 4) */
267 		sensors[i].value = (sdata << 4);
268 		/* rfact is (factor * 10^4) */
269 		sensors[i].value *= sensors[i].rfact;
270 		/* these two values are negative and formula is different */
271 		if (i == 5)
272 			sensors[i].value -=
273 			    (int) (21.0 / 10 * IT_VREF * 10000);
274 		if (i == 6)
275 			sensors[i].value -=
276 			    (int) (83.0 / 20 * IT_VREF * 10000);
277 		/* division by 10 gets us back to uVDC */
278 		sensors[i].value /= 10;
279 
280 	}
281 }
282 
283 void
it_generic_fanrpm(struct it_softc * sc,struct sensor * sensors)284 it_generic_fanrpm(struct it_softc *sc, struct sensor *sensors)
285 {
286 	int i, sdata, divisor, odivisor, ndivisor;
287 
288 	odivisor = ndivisor = divisor = it_readreg(sc, ITD_FAN);
289 	for (i = 0; i < 3; i++, divisor >>= 3) {
290 		sensors[i].flags &= ~SENSOR_FINVALID;
291 		if ((sdata = it_readreg(sc, ITD_SENSORFANBASE + i)) == 0xff) {
292 			sensors[i].flags |= SENSOR_FINVALID;
293 			if (i == 2)
294 				ndivisor ^= 0x40;
295 			else {
296 				ndivisor &= ~(7 << (i * 3));
297 				ndivisor |= ((divisor + 1) & 7) << (i * 3);
298 			}
299 		} else if (sdata == 0) {
300 			sensors[i].value = 0;
301 		} else {
302 			if (i == 2)
303 				divisor = divisor & 1 ? 3 : 1;
304 			sensors[i].value = 1350000 / (sdata << (divisor & 7));
305 		}
306 	}
307 	if (ndivisor != odivisor)
308 		it_writereg(sc, ITD_FAN, ndivisor);
309 }
310 
311 /*
312  * pre:  last read occurred >= 1.5 seconds ago
313  * post: sensors[] current data are the latest from the chip
314  */
315 void
it_refresh_sensor_data(struct it_softc * sc)316 it_refresh_sensor_data(struct it_softc *sc)
317 {
318 	/* Refresh our stored data for every sensor */
319 	it_generic_stemp(sc, &sc->sensors[12]);
320 	it_generic_svolt(sc, &sc->sensors[3]);
321 	it_generic_fanrpm(sc, &sc->sensors[0]);
322 }
323 
324 void
it_refresh(void * arg)325 it_refresh(void *arg)
326 {
327 	struct it_softc *sc = (struct it_softc *)arg;
328 
329 	it_refresh_sensor_data(sc);
330 	timeout_add(&it_timeout, (15 * hz) / 10);
331 }
332