xref: /netbsd-src/sys/dev/ic/nslm7x.c (revision aaf4ece63a859a04e37cf3a7229b5fab0157cc06)
1 /*	$NetBSD: nslm7x.c,v 1.24 2005/12/11 12:21:28 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2000 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Bill Squier.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: nslm7x.c,v 1.24 2005/12/11 12:21:28 christos Exp $");
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/kernel.h>
45 #include <sys/proc.h>
46 #include <sys/device.h>
47 #include <sys/malloc.h>
48 #include <sys/errno.h>
49 #include <sys/queue.h>
50 #include <sys/lock.h>
51 #include <sys/ioctl.h>
52 #include <sys/conf.h>
53 #include <sys/time.h>
54 
55 #include <machine/bus.h>
56 
57 #include <dev/isa/isareg.h>
58 #include <dev/isa/isavar.h>
59 
60 #include <dev/sysmon/sysmonvar.h>
61 
62 #include <dev/ic/nslm7xvar.h>
63 
64 #include <machine/intr.h>
65 #include <machine/bus.h>
66 
67 #if defined(LMDEBUG)
68 #define DPRINTF(x)		printf x
69 #else
70 #define DPRINTF(x)
71 #endif
72 
73 const struct envsys_range lm_ranges[] = {	/* sc->sensors sub-intervals */
74 					/* for each unit type */
75 	{ 7, 7,    ENVSYS_STEMP   },
76 	{ 8, 10,   ENVSYS_SFANRPM },
77 	{ 1, 0,    ENVSYS_SVOLTS_AC },	/* None */
78 	{ 0, 6,    ENVSYS_SVOLTS_DC },
79 	{ 1, 0,    ENVSYS_SOHMS },	/* None */
80 	{ 1, 0,    ENVSYS_SWATTS },	/* None */
81 	{ 1, 0,    ENVSYS_SAMPS }	/* None */
82 };
83 
84 
85 static void setup_fan(struct lm_softc *, int, int);
86 static void setup_temp(struct lm_softc *, int, int);
87 static void wb_setup_volt(struct lm_softc *);
88 
89 int lm_match(struct lm_softc *);
90 int wb_match(struct lm_softc *);
91 int itec_match(struct lm_softc *);
92 int def_match(struct lm_softc *);
93 void lm_common_match(struct lm_softc *);
94 static int lm_generic_banksel(struct lm_softc *, int);
95 
96 static void generic_stemp(struct lm_softc *, struct envsys_tre_data *);
97 static void generic_svolt(struct lm_softc *, struct envsys_tre_data *,
98     struct envsys_basic_info *);
99 static void generic_fanrpm(struct lm_softc *, struct envsys_tre_data *);
100 
101 void lm_refresh_sensor_data(struct lm_softc *);
102 
103 static void wb_svolt(struct lm_softc *);
104 static void wb_stemp(struct lm_softc *, struct envsys_tre_data *, int);
105 static void wb781_fanrpm(struct lm_softc *, struct envsys_tre_data *);
106 static void wb_fanrpm(struct lm_softc *, struct envsys_tre_data *);
107 
108 void wb781_refresh_sensor_data(struct lm_softc *);
109 void wb782_refresh_sensor_data(struct lm_softc *);
110 void wb697_refresh_sensor_data(struct lm_softc *);
111 
112 static void itec_svolt(struct lm_softc *, struct envsys_tre_data *,
113     struct envsys_basic_info *);
114 static void itec_stemp(struct lm_softc *, struct envsys_tre_data *);
115 static void itec_fanrpm(struct lm_softc *, struct envsys_tre_data *);
116 void itec_refresh_sensor_data(struct lm_softc *);
117 
118 int lm_gtredata(struct sysmon_envsys *, struct envsys_tre_data *);
119 
120 int generic_streinfo_fan(struct lm_softc *, struct envsys_basic_info *,
121            int, struct envsys_basic_info *);
122 int lm_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
123 int wb781_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
124 int wb782_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
125 int itec_streinfo(struct sysmon_envsys *, struct envsys_basic_info *);
126 
127 struct lm_chip {
128 	int (*chip_match)(struct lm_softc *);
129 };
130 
131 struct lm_chip lm_chips[] = {
132 	{ itec_match },
133 	{ wb_match },
134 	{ lm_match },
135 	{ def_match } /* Must be last */
136 };
137 
138 
139 int
140 lm_generic_banksel(lmsc, bank)
141 	struct lm_softc *lmsc;
142 	int bank;
143 {
144 
145 	(*lmsc->lm_writereg)(lmsc, WB_BANKSEL, bank);
146 	return 0;
147 }
148 
149 
150 /*
151  * bus independent probe
152  */
153 int
154 lm_probe(iot, ioh)
155 	bus_space_tag_t iot;
156 	bus_space_handle_t ioh;
157 {
158 	u_int8_t cr;
159 	int rv;
160 
161 	/*
162 	 * Check for it8705f, before we do the chip reset.
163 	 * In case of an it8705f this might reset all the fan control
164 	 * parameters to defaults which would void all settings done by
165 	 * the BOOTROM/BIOS.
166 	 */
167 	bus_space_write_1(iot, ioh, LMC_ADDR, ITEC_RES48);
168 	cr = bus_space_read_1(iot, ioh, LMC_DATA);
169 
170 	if (cr == ITEC_RES48_DEFAULT) {
171 		bus_space_write_1(iot, ioh, LMC_ADDR, ITEC_RES52);
172 		cr = bus_space_read_1(iot, ioh, LMC_DATA);
173 		if (cr == ITEC_RES52_DEFAULT)
174 			return 1;
175 	}
176 
177 	/* Check for some power-on defaults */
178 	bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
179 
180 	/* Perform LM78 reset */
181 	bus_space_write_1(iot, ioh, LMC_DATA, 0x80);
182 
183 	/* XXX - Why do I have to reselect the register? */
184 	bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
185 	cr = bus_space_read_1(iot, ioh, LMC_DATA);
186 
187 	/* XXX - spec says *only* 0x08! */
188 	if ((cr == 0x08) || (cr == 0x01) || (cr == 0x03))
189 		rv = 1;
190 	else
191 		rv = 0;
192 
193 	DPRINTF(("lm: rv = %d, cr = %x\n", rv, cr));
194 
195 	return (rv);
196 }
197 
198 
199 /*
200  * pre:  lmsc contains valid busspace tag and handle
201  */
202 void
203 lm_attach(lmsc)
204 	struct lm_softc *lmsc;
205 {
206 	u_int i;
207 
208 	/* Install default bank selection routine, if none given. */
209 	if (lmsc->lm_banksel == NULL)
210 		lmsc->lm_banksel = lm_generic_banksel;
211 
212 	for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++)
213 		if (lm_chips[i].chip_match(lmsc))
214 			break;
215 
216 	/* Start the monitoring loop */
217 	(*lmsc->lm_writereg)(lmsc, LMD_CONFIG, 0x01);
218 
219 	/* Indicate we have never read the registers */
220 	timerclear(&lmsc->lastread);
221 
222 	/* Initialize sensors */
223 	for (i = 0; i < lmsc->numsensors; ++i) {
224 		lmsc->sensors[i].sensor = lmsc->info[i].sensor = i;
225 		lmsc->sensors[i].validflags = (ENVSYS_FVALID|ENVSYS_FCURVALID);
226 		lmsc->info[i].validflags = ENVSYS_FVALID;
227 		lmsc->sensors[i].warnflags = ENVSYS_WARN_OK;
228 	}
229 	/*
230 	 * Hook into the System Monitor.
231 	 */
232 	lmsc->sc_sysmon.sme_ranges = lm_ranges;
233 	lmsc->sc_sysmon.sme_sensor_info = lmsc->info;
234 	lmsc->sc_sysmon.sme_sensor_data = lmsc->sensors;
235 	lmsc->sc_sysmon.sme_cookie = lmsc;
236 
237 	lmsc->sc_sysmon.sme_gtredata = lm_gtredata;
238 	/* sme_streinfo set in chip-specific attach */
239 
240 	lmsc->sc_sysmon.sme_nsensors = lmsc->numsensors;
241 	lmsc->sc_sysmon.sme_envsys_version = 1000;
242 
243 	if (sysmon_envsys_register(&lmsc->sc_sysmon))
244 		printf("%s: unable to register with sysmon\n",
245 		    lmsc->sc_dev.dv_xname);
246 }
247 
248 int
249 lm_match(sc)
250 	struct lm_softc *sc;
251 {
252 	int i;
253 
254 	/* See if we have an LM78 or LM79 */
255 	i = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK;
256 	switch(i) {
257 	case LM_ID_LM78:
258 		printf(": LM78\n");
259 		break;
260 	case LM_ID_LM78J:
261 		printf(": LM78J\n");
262 		break;
263 	case LM_ID_LM79:
264 		printf(": LM79\n");
265 		break;
266 	case LM_ID_LM81:
267 		printf(": LM81\n");
268 		break;
269 	default:
270 		return 0;
271 	}
272 	lm_common_match(sc);
273 	return 1;
274 }
275 
276 int
277 def_match(sc)
278 	struct lm_softc *sc;
279 {
280 	int i;
281 
282 	i = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK;
283 	printf(": Unknown chip (ID %d)\n", i);
284 	lm_common_match(sc);
285 	return 1;
286 }
287 
288 void
289 lm_common_match(sc)
290 	struct lm_softc *sc;
291 {
292 	int i;
293 	sc->numsensors = LM_NUM_SENSORS;
294 	sc->refresh_sensor_data = lm_refresh_sensor_data;
295 
296 	for (i = 0; i < 7; ++i) {
297 		sc->sensors[i].units = sc->info[i].units =
298 		    ENVSYS_SVOLTS_DC;
299 		snprintf(sc->info[i].desc, sizeof(sc->info[i].desc),
300 		    "IN %d", i);
301 	}
302 
303 	/* default correction factors for resistors on higher voltage inputs */
304 	sc->info[0].rfact = sc->info[1].rfact =
305 	    sc->info[2].rfact = 10000;
306 	sc->info[3].rfact = (int)(( 90.9 / 60.4) * 10000);
307 	sc->info[4].rfact = (int)(( 38.0 / 10.0) * 10000);
308 	sc->info[5].rfact = (int)((210.0 / 60.4) * 10000);
309 	sc->info[6].rfact = (int)(( 90.9 / 60.4) * 10000);
310 
311 	sc->sensors[7].units = ENVSYS_STEMP;
312 	strcpy(sc->info[7].desc, "Temp");
313 
314 	setup_fan(sc, 8, 3);
315 	sc->sc_sysmon.sme_streinfo = lm_streinfo;
316 }
317 
318 int
319 wb_match(sc)
320 	struct lm_softc *sc;
321 {
322 	int i, j;
323 
324 	(*sc->lm_writereg)(sc, WB_BANKSEL, WB_BANKSEL_HBAC);
325 	j = (*sc->lm_readreg)(sc, WB_VENDID) << 8;
326 	(*sc->lm_writereg)(sc, WB_BANKSEL, 0);
327 	j |= (*sc->lm_readreg)(sc, WB_VENDID);
328 	DPRINTF(("winbond vend id 0x%x\n", j));
329 	if (j != WB_VENDID_WINBOND)
330 		return 0;
331 	/* read device ID */
332 	(*sc->lm_banksel)(sc, 0);
333 	j = (*sc->lm_readreg)(sc, WB_BANK0_CHIPID);
334 	DPRINTF(("winbond chip id 0x%x\n", j));
335 	switch(j) {
336 	case WB_CHIPID_83781:
337 	case WB_CHIPID_83781_2:
338 		printf(": W83781D\n");
339 
340 		for (i = 0; i < 7; ++i) {
341 			sc->sensors[i].units = sc->info[i].units =
342 			    ENVSYS_SVOLTS_DC;
343 			snprintf(sc->info[i].desc, sizeof(sc->info[i].desc),
344 			    "IN %d", i);
345 		}
346 
347 		/* default correction factors for higher voltage inputs */
348 		sc->info[0].rfact = sc->info[1].rfact =
349 		    sc->info[2].rfact = 10000;
350 		sc->info[3].rfact = (int)(( 90.9 / 60.4) * 10000);
351 		sc->info[4].rfact = (int)(( 38.0 / 10.0) * 10000);
352 		sc->info[5].rfact = (int)((210.0 / 60.4) * 10000);
353 		sc->info[6].rfact = (int)(( 90.9 / 60.4) * 10000);
354 
355 		setup_temp(sc, 7, 3);
356 		setup_fan(sc, 10, 3);
357 
358 		sc->numsensors = WB83781_NUM_SENSORS;
359 		sc->refresh_sensor_data = wb781_refresh_sensor_data;
360 		sc->sc_sysmon.sme_streinfo = wb781_streinfo;
361 		return 1;
362 	case WB_CHIPID_83697:
363 		printf(": W83697HF\n");
364 		wb_setup_volt(sc);
365 		setup_temp(sc, 9, 2);
366 		setup_fan(sc, 11, 3);
367 		sc->numsensors = WB83697_NUM_SENSORS;
368 		sc->refresh_sensor_data = wb697_refresh_sensor_data;
369 		sc->sc_sysmon.sme_streinfo = wb782_streinfo;
370 		return 1;
371 	case WB_CHIPID_83782:
372 		printf(": W83782D\n");
373 		break;
374 	case WB_CHIPID_83627:
375 		printf(": W83627HF\n");
376 		break;
377 	case WB_CHIPID_83627THF:
378 		printf(": W83627THF\n");
379 		break;
380 	default:
381 		printf(": unknow winbond chip ID 0x%x\n", j);
382 		/* handle as a standart lm7x */
383 		lm_common_match(sc);
384 		return 1;
385 	}
386 	/* common code for the W83782D and W83627HF */
387 	wb_setup_volt(sc);
388 	setup_temp(sc, 9, 3);
389 	setup_fan(sc, 12, 3);
390 	sc->numsensors = WB_NUM_SENSORS;
391 	sc->refresh_sensor_data = wb782_refresh_sensor_data;
392 	sc->sc_sysmon.sme_streinfo = wb782_streinfo;
393 	return 1;
394 }
395 
396 static void
397 wb_setup_volt(sc)
398 	struct lm_softc *sc;
399 {
400 	sc->sensors[0].units = sc->info[0].units = ENVSYS_SVOLTS_DC;
401 	snprintf(sc->info[0].desc, sizeof(sc->info[0].desc), "VCORE A");
402 	sc->info[0].rfact = 10000;
403 	sc->sensors[1].units = sc->info[1].units = ENVSYS_SVOLTS_DC;
404 	snprintf(sc->info[1].desc, sizeof(sc->info[1].desc), "VCORE B");
405 	sc->info[1].rfact = 10000;
406 	sc->sensors[2].units = sc->info[2].units = ENVSYS_SVOLTS_DC;
407 	snprintf(sc->info[2].desc, sizeof(sc->info[2].desc), "+3.3V");
408 	sc->info[2].rfact = 10000;
409 	sc->sensors[3].units = sc->info[3].units = ENVSYS_SVOLTS_DC;
410 	snprintf(sc->info[3].desc, sizeof(sc->info[3].desc), "+5V");
411 	sc->info[3].rfact = 16778;
412 	sc->sensors[4].units = sc->info[4].units = ENVSYS_SVOLTS_DC;
413 	snprintf(sc->info[4].desc, sizeof(sc->info[4].desc), "+12V");
414 	sc->info[4].rfact = 38000;
415 	sc->sensors[5].units = sc->info[5].units = ENVSYS_SVOLTS_DC;
416 	snprintf(sc->info[5].desc, sizeof(sc->info[5].desc), "-12V");
417 	sc->info[5].rfact = 10000;
418 	sc->sensors[6].units = sc->info[6].units = ENVSYS_SVOLTS_DC;
419 	snprintf(sc->info[6].desc, sizeof(sc->info[6].desc), "-5V");
420 	sc->info[6].rfact = 10000;
421 	sc->sensors[7].units = sc->info[7].units = ENVSYS_SVOLTS_DC;
422 	snprintf(sc->info[7].desc, sizeof(sc->info[7].desc), "+5VSB");
423 	sc->info[7].rfact = 15151;
424 	sc->sensors[8].units = sc->info[8].units = ENVSYS_SVOLTS_DC;
425 	snprintf(sc->info[8].desc, sizeof(sc->info[8].desc), "VBAT");
426 	sc->info[8].rfact = 10000;
427 }
428 
429 int
430 itec_match(sc)
431 	struct lm_softc *sc;
432 {
433 	int vendor, coreid;
434 
435 	/* do the same thing as in  lm_probe() */
436 	if ((*sc->lm_readreg)(sc, ITEC_RES48) != ITEC_RES48_DEFAULT)
437 		return 0;
438 
439 	if ((*sc->lm_readreg)(sc, ITEC_RES52) != ITEC_RES52_DEFAULT)
440 		return 0;
441 
442 	/* We check for the core ID register (0x5B), which is available
443 	 * only in the 8712F, if that fails, we check the vendor ID
444 	 * register, available on 8705F and 8712F */
445 
446 	coreid = (*sc->lm_readreg)(sc, ITEC_COREID);
447 
448 	if (coreid == ITEC_COREID_ITE)
449 		printf(": ITE8712F\n");
450 	else {
451 		vendor = (*sc->lm_readreg)(sc, ITEC_VENDID);
452 		if (vendor == ITEC_VENDID_ITE)
453 			printf(": ITE8705F\n");
454 		else
455 			printf(": unknown ITE87%02x compatible\n", vendor);
456 	}
457 
458 	/*
459 	 * XXX this is a litle bit lame...
460 	 * All VIN inputs work exactly the same way, it depends of the
461 	 * external wiring what voltages they monitor and which correction
462 	 * factors are needed. We assume a pretty standard setup here
463 	 */
464 	wb_setup_volt(sc);
465 	strlcpy(sc->info[0].desc, "CPU", sizeof(sc->info[0].desc));
466 	strlcpy(sc->info[1].desc, "AGP", sizeof(sc->info[1].desc));
467 	strlcpy(sc->info[6].desc, "+2.5V", sizeof(sc->info[6].desc));
468 	sc->info[5].rfact = 51100;
469 	sc->info[7].rfact = 16778;
470 
471 	setup_temp(sc, 9, 3);
472 	setup_fan(sc, 12, 3);
473 	sc->numsensors = ITEC_NUM_SENSORS;
474 	sc->refresh_sensor_data = itec_refresh_sensor_data;
475 	sc->sc_sysmon.sme_streinfo = itec_streinfo;
476 
477 	return 1;
478 }
479 
480 
481 static void
482 setup_temp(sc, start, n)
483 	struct lm_softc *sc;
484 	int start, n;
485 {
486 	int i;
487 
488 	for (i = 0; i < n; i++) {
489 		sc->sensors[start + i].units = ENVSYS_STEMP;
490 		snprintf(sc->info[start + i].desc,
491 		    sizeof(sc->info[start + i].desc), "Temp %d", i + 1);
492 	}
493 }
494 
495 
496 static void
497 setup_fan(sc, start, n)
498 	struct lm_softc *sc;
499 	int start, n;
500 {
501 	int i;
502 	for (i = 0; i < n; ++i) {
503 		sc->sensors[start + i].units = ENVSYS_SFANRPM;
504 		sc->info[start + i].units = ENVSYS_SFANRPM;
505 		snprintf(sc->info[start + i].desc,
506 		    sizeof(sc->info[start + i].desc), "Fan %d", i + 1);
507 	}
508 }
509 
510 int
511 lm_gtredata(sme, tred)
512 	 struct sysmon_envsys *sme;
513 	 struct envsys_tre_data *tred;
514 {
515 	 static const struct timeval onepointfive = { 1, 500000 };
516 	 struct timeval t;
517 	 struct lm_softc *sc = sme->sme_cookie;
518 	 int i, s;
519 
520 	 /* read new values at most once every 1.5 seconds */
521 	 timeradd(&sc->lastread, &onepointfive, &t);
522 	 s = splclock();
523 	 i = timercmp(&mono_time, &t, >);
524 	 if (i) {
525 		  sc->lastread.tv_sec  = mono_time.tv_sec;
526 		  sc->lastread.tv_usec = mono_time.tv_usec;
527 	 }
528 	 splx(s);
529 
530 	 if (i)
531 		  sc->refresh_sensor_data(sc);
532 
533 	 *tred = sc->sensors[tred->sensor];
534 
535 	 return 0;
536 }
537 
538 int
539 generic_streinfo_fan(sc, info, n, binfo)
540 	struct lm_softc *sc;
541 	struct envsys_basic_info *info;
542 	int n;
543 	struct envsys_basic_info *binfo;
544 {
545 	u_int8_t sdata;
546 	int divisor;
547 
548 	/* FAN1 and FAN2 can have divisors set, but not FAN3 */
549 	if ((sc->info[binfo->sensor].units == ENVSYS_SFANRPM)
550 	    && (n < 2)) {
551 		if (binfo->rpms == 0) {
552 			binfo->validflags = 0;
553 			return 0;
554 		}
555 
556 		/* write back the nominal FAN speed  */
557 		info->rpms = binfo->rpms;
558 
559 		/* 153 is the nominal FAN speed value */
560 		divisor = 1350000 / (binfo->rpms * 153);
561 
562 		/* ...but we need lg(divisor) */
563 		if (divisor <= 1)
564 		    divisor = 0;
565 		else if (divisor <= 2)
566 		    divisor = 1;
567 		else if (divisor <= 4)
568 		    divisor = 2;
569 		else
570 		    divisor = 3;
571 
572 		/*
573 		 * FAN1 div is in bits <5:4>, FAN2 div is
574 		 * in <7:6>
575 		 */
576 		sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
577 		if ( n == 0 ) {  /* FAN1 */
578 		    divisor <<= 4;
579 		    sdata = (sdata & 0xCF) | divisor;
580 		} else { /* FAN2 */
581 		    divisor <<= 6;
582 		    sdata = (sdata & 0x3F) | divisor;
583 		}
584 
585 		(*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
586 	}
587 	return 0;
588 
589 }
590 
591 int
592 lm_streinfo(sme, binfo)
593 	 struct sysmon_envsys *sme;
594 	 struct envsys_basic_info *binfo;
595 {
596 	 struct lm_softc *sc = sme->sme_cookie;
597 
598 	 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
599 		  sc->info[binfo->sensor].rfact = binfo->rfact;
600 	 else {
601 		if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
602 			generic_streinfo_fan(sc, &sc->info[binfo->sensor],
603 			    binfo->sensor - 8, binfo);
604 		}
605 		strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
606 		    sizeof(sc->info[binfo->sensor].desc));
607 		binfo->validflags = ENVSYS_FVALID;
608 	 }
609 	 return 0;
610 }
611 
612 int
613 wb781_streinfo(sme, binfo)
614 	 struct sysmon_envsys *sme;
615 	 struct envsys_basic_info *binfo;
616 {
617 	 struct lm_softc *sc = sme->sme_cookie;
618 	 int divisor;
619 	 u_int8_t sdata;
620 	 int i;
621 
622 	 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
623 		  sc->info[binfo->sensor].rfact = binfo->rfact;
624 	 else {
625 		if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
626 			if (binfo->rpms == 0) {
627 				binfo->validflags = 0;
628 				return 0;
629 			}
630 
631 			/* write back the nominal FAN speed  */
632 			sc->info[binfo->sensor].rpms = binfo->rpms;
633 
634 			/* 153 is the nominal FAN speed value */
635 			divisor = 1350000 / (binfo->rpms * 153);
636 
637 			/* ...but we need lg(divisor) */
638 			for (i = 0; i < 7; i++) {
639 				if (divisor <= (1 << i))
640 				 	break;
641 			}
642 			divisor = i;
643 
644 			if (binfo->sensor == 10 || binfo->sensor == 11) {
645 				/*
646 				 * FAN1 div is in bits <5:4>, FAN2 div
647 				 * is in <7:6>
648 				 */
649 				sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
650 				if ( binfo->sensor == 10 ) {  /* FAN1 */
651 					 sdata = (sdata & 0xCF) |
652 					     ((divisor & 0x3) << 4);
653 				} else { /* FAN2 */
654 					 sdata = (sdata & 0x3F) |
655 					     ((divisor & 0x3) << 6);
656 				}
657 				(*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
658 			} else {
659 				/* FAN3 is in WB_PIN <7:6> */
660 				sdata = (*sc->lm_readreg)(sc, WB_PIN);
661 				sdata = (sdata & 0x3F) |
662 				     ((divisor & 0x3) << 6);
663 				(*sc->lm_writereg)(sc, WB_PIN, sdata);
664 			}
665 		}
666 		strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
667 		    sizeof(sc->info[binfo->sensor].desc));
668 		binfo->validflags = ENVSYS_FVALID;
669 	 }
670 	 return 0;
671 }
672 
673 int
674 wb782_streinfo(sme, binfo)
675 	 struct sysmon_envsys *sme;
676 	 struct envsys_basic_info *binfo;
677 {
678 	 struct lm_softc *sc = sme->sme_cookie;
679 	 int divisor;
680 	 u_int8_t sdata;
681 	 int i;
682 
683 	 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
684 		  sc->info[binfo->sensor].rfact = binfo->rfact;
685 	 else {
686 	 	if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
687 			if (binfo->rpms == 0) {
688 				binfo->validflags = 0;
689 				return 0;
690 			}
691 
692 			/* write back the nominal FAN speed  */
693 			sc->info[binfo->sensor].rpms = binfo->rpms;
694 
695 			/* 153 is the nominal FAN speed value */
696 			divisor = 1350000 / (binfo->rpms * 153);
697 
698 			/* ...but we need lg(divisor) */
699 			for (i = 0; i < 7; i++) {
700 				if (divisor <= (1 << i))
701 				 	break;
702 			}
703 			divisor = i;
704 
705 			if (binfo->sensor == 12 || binfo->sensor == 13) {
706 				/*
707 				 * FAN1 div is in bits <5:4>, FAN2 div
708 				 * is in <7:6>
709 				 */
710 				sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN);
711 				if ( binfo->sensor == 12 ) {  /* FAN1 */
712 					 sdata = (sdata & 0xCF) |
713 					     ((divisor & 0x3) << 4);
714 				} else { /* FAN2 */
715 					 sdata = (sdata & 0x3F) |
716 					     ((divisor & 0x3) << 6);
717 				}
718 				(*sc->lm_writereg)(sc, LMD_VIDFAN, sdata);
719 			} else {
720 				/* FAN3 is in WB_PIN <7:6> */
721 				sdata = (*sc->lm_readreg)(sc, WB_PIN);
722 				sdata = (sdata & 0x3F) |
723 				     ((divisor & 0x3) << 6);
724 				(*sc->lm_writereg)(sc, WB_PIN, sdata);
725 			}
726 			/* Bit 2 of divisor is in WB_BANK0_FANBAT */
727 			(*sc->lm_banksel)(sc, 0);
728 			sdata = (*sc->lm_readreg)(sc, WB_BANK0_FANBAT);
729 			sdata &= ~(0x20 << (binfo->sensor - 12));
730 			sdata |= (divisor & 0x4) << (binfo->sensor - 9);
731 			(*sc->lm_writereg)(sc, WB_BANK0_FANBAT, sdata);
732 		}
733 
734 		strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
735 		    sizeof(sc->info[binfo->sensor].desc));
736 		binfo->validflags = ENVSYS_FVALID;
737 	}
738 	return 0;
739 }
740 
741 int
742 itec_streinfo(sme, binfo)
743 	 struct sysmon_envsys *sme;
744 	 struct envsys_basic_info *binfo;
745 {
746 	 struct lm_softc *sc = sme->sme_cookie;
747 	 int divisor;
748 	 u_int8_t sdata;
749 	 int i;
750 
751 	 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
752 		  sc->info[binfo->sensor].rfact = binfo->rfact;
753 	 else {
754 		if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
755 			if (binfo->rpms == 0) {
756 				binfo->validflags = 0;
757 				return 0;
758 			}
759 
760 			/* write back the nominal FAN speed  */
761 			sc->info[binfo->sensor].rpms = binfo->rpms;
762 
763 			/* 153 is the nominal FAN speed value */
764 			divisor = 1350000 / (binfo->rpms * 153);
765 
766 			/* ...but we need lg(divisor) */
767 			for (i = 0; i < 7; i++) {
768 				if (divisor <= (1 << i))
769 				 	break;
770 			}
771 			divisor = i;
772 
773 			sdata = (*sc->lm_readreg)(sc, ITEC_FANDIV);
774 			/*
775 			 * FAN1 div is in bits <0:2>, FAN2 is in <3:5>
776 			 * FAN3 is in <6>, if set divisor is 8, else 2
777 			 */
778 			if ( binfo->sensor == 10 ) {  /* FAN1 */
779 				 sdata = (sdata & 0xf8) | divisor;
780 			} else if ( binfo->sensor == 11 ) { /* FAN2 */
781 				 sdata = (sdata & 0xc7) | divisor << 3;
782 			} else { /* FAN3 */
783 				if (divisor>2)
784 					sdata = sdata & 0xbf;
785 				else
786 					sdata = sdata | 0x40;
787 			}
788 			(*sc->lm_writereg)(sc, ITEC_FANDIV, sdata);
789 		}
790 		strlcpy(sc->info[binfo->sensor].desc, binfo->desc,
791 		    sizeof(sc->info[binfo->sensor].desc));
792 		binfo->validflags = ENVSYS_FVALID;
793 	 }
794 	 return 0;
795 }
796 
797 static void
798 generic_stemp(sc, sensor)
799 	struct lm_softc *sc;
800 	struct envsys_tre_data *sensor;
801 {
802 	int sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 7);
803 	DPRINTF(("sdata[temp] 0x%x\n", sdata));
804 	/* temp is given in deg. C, we convert to uK */
805 	sensor->cur.data_us = sdata * 1000000 + 273150000;
806 }
807 
808 static void
809 generic_svolt(sc, sensors, infos)
810 	struct lm_softc *sc;
811 	struct envsys_tre_data *sensors;
812 	struct envsys_basic_info *infos;
813 {
814 	int i, sdata;
815 
816 	for (i = 0; i < 7; i++) {
817 		sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i);
818 		DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
819 		/* voltage returned as (mV >> 4), we convert to uVDC */
820 		sensors[i].cur.data_s = (sdata << 4);
821 		/* rfact is (factor * 10^4) */
822 		sensors[i].cur.data_s *= infos[i].rfact;
823 		/* division by 10 gets us back to uVDC */
824 		sensors[i].cur.data_s /= 10;
825 
826 		/* these two are negative voltages */
827 		if ( (i == 5) || (i == 6) )
828 			sensors[i].cur.data_s *= -1;
829 	}
830 }
831 
832 static void
833 generic_fanrpm(sc, sensors)
834 	struct lm_softc *sc;
835 	struct envsys_tre_data *sensors;
836 {
837 	int i, sdata, divisor;
838 	for (i = 0; i < 3; i++) {
839 		sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 8 + i);
840 		DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
841 		if (i == 2)
842 			divisor = 2;	/* Fixed divisor for FAN3 */
843 		else if (i == 1)	/* Bits 7 & 6 of VID/FAN  */
844 			divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 6) & 0x3;
845 		else
846 			divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 4) & 0x3;
847 
848 		if (sdata == 0xff || sdata == 0x00) {
849 			sensors[i].cur.data_us = 0;
850 		} else {
851 			sensors[i].cur.data_us = 1350000 / (sdata << divisor);
852 		}
853 	}
854 }
855 
856 /*
857  * pre:  last read occurred >= 1.5 seconds ago
858  * post: sensors[] current data are the latest from the chip
859  */
860 void
861 lm_refresh_sensor_data(sc)
862 	struct lm_softc *sc;
863 {
864 	/* Refresh our stored data for every sensor */
865 	generic_stemp(sc, &sc->sensors[7]);
866 	generic_svolt(sc, &sc->sensors[0], &sc->info[0]);
867 	generic_fanrpm(sc, &sc->sensors[8]);
868 }
869 
870 static void
871 wb_svolt(sc)
872 	struct lm_softc *sc;
873 {
874 	int i, sdata;
875 	for (i = 0; i < 9; ++i) {
876 		if (i < 7) {
877 			sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i);
878 		} else {
879 			/* from bank5 */
880 			(*sc->lm_banksel)(sc, 5);
881 			sdata = (*sc->lm_readreg)(sc, (i == 7) ?
882 			    WB_BANK5_5VSB : WB_BANK5_VBAT);
883 		}
884 		DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
885 		/* voltage returned as (mV >> 4), we convert to uV */
886 		sdata =  sdata << 4;
887 		/* special case for negative voltages */
888 		if (i == 5) {
889 			/*
890 			 * -12Vdc, assume Winbond recommended values for
891 			 * resistors
892 			 */
893 			sdata = ((sdata * 1000) - (3600 * 805)) / 195;
894 		} else if (i == 6) {
895 			/*
896 			 * -5Vdc, assume Winbond recommended values for
897 			 * resistors
898 			 */
899 			sdata = ((sdata * 1000) - (3600 * 682)) / 318;
900 		}
901 		/* rfact is (factor * 10^4) */
902 		sc->sensors[i].cur.data_s = sdata * sc->info[i].rfact;
903 		/* division by 10 gets us back to uVDC */
904 		sc->sensors[i].cur.data_s /= 10;
905 	}
906 }
907 
908 static void
909 wb_stemp(sc, sensors, n)
910 	struct lm_softc *sc;
911 	struct  envsys_tre_data *sensors;
912 	int n;
913 {
914 	int sdata;
915 	/* temperatures. Given in dC, we convert to uK */
916 	sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 7);
917 	DPRINTF(("sdata[temp0] 0x%x\n", sdata));
918 	sensors[0].cur.data_us = sdata * 1000000 + 273150000;
919 	/* from bank1 */
920 	if ((*sc->lm_banksel)(sc, 1))
921 		sensors[1].validflags &= ~ENVSYS_FCURVALID;
922 	else {
923 		sdata = (*sc->lm_readreg)(sc, WB_BANK1_T2H) << 1;
924 		sdata |=  ((*sc->lm_readreg)(sc, WB_BANK1_T2L) & 0x80) >> 7;
925 		DPRINTF(("sdata[temp1] 0x%x\n", sdata));
926 		sensors[1].cur.data_us = (sdata * 1000000) / 2 + 273150000;
927 	}
928 	if (n < 3)
929 		return;
930 	/* from bank2 */
931 	if ((*sc->lm_banksel)(sc, 2))
932 		sensors[2].validflags &= ~ENVSYS_FCURVALID;
933 	else {
934 		sdata = (*sc->lm_readreg)(sc, WB_BANK2_T3H) << 1;
935 		sdata |=  ((*sc->lm_readreg)(sc, WB_BANK2_T3L) & 0x80) >> 7;
936 		DPRINTF(("sdata[temp2] 0x%x\n", sdata));
937 		sensors[2].cur.data_us = (sdata * 1000000) / 2 + 273150000;
938 	}
939 }
940 
941 static void
942 wb781_fanrpm(sc, sensors)
943 	struct lm_softc *sc;
944 	struct envsys_tre_data *sensors;
945 {
946 	int i, divisor, sdata;
947 	(*sc->lm_banksel)(sc, 0);
948 	for (i = 0; i < 3; i++) {
949 		sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i + 8);
950 		DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
951 		if (i == 0)
952 			divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 4) & 0x3;
953 		else if (i == 1)
954 			divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 6) & 0x3;
955 		else
956 			divisor = ((*sc->lm_readreg)(sc, WB_PIN) >> 6) & 0x3;
957 
958 		DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor));
959 		if (sdata == 0xff || sdata == 0x00) {
960 			sensors[i].cur.data_us = 0;
961 		} else {
962 			sensors[i].cur.data_us = 1350000 /
963 			    (sdata << divisor);
964 		}
965 	}
966 }
967 
968 static void
969 wb_fanrpm(sc, sensors)
970 	struct lm_softc *sc;
971 	struct envsys_tre_data *sensors;
972 {
973 	int i, divisor, sdata;
974 	(*sc->lm_banksel)(sc, 0);
975 	for (i = 0; i < 3; i++) {
976 		sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i + 8);
977 		DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
978 		if (i == 0)
979 			divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 4) & 0x3;
980 		else if (i == 1)
981 			divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 6) & 0x3;
982 		else
983 			divisor = ((*sc->lm_readreg)(sc, WB_PIN) >> 6) & 0x3;
984 		divisor |= ((*sc->lm_readreg)(sc, WB_BANK0_FANBAT) >> (i + 3)) & 0x4;
985 
986 		DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor));
987 		if (sdata == 0xff || sdata == 0x00) {
988 			sensors[i].cur.data_us = 0;
989 		} else {
990 			sensors[i].cur.data_us = 1350000 /
991 			    (sdata << divisor);
992 		}
993 	}
994 }
995 
996 void
997 wb781_refresh_sensor_data(sc)
998 	struct lm_softc *sc;
999 {
1000 	/* Refresh our stored data for every sensor */
1001 	/* we need to reselect bank0 to access common registers */
1002 	(*sc->lm_banksel)(sc, 0);
1003 	generic_svolt(sc, &sc->sensors[0], &sc->info[0]);
1004 	(*sc->lm_banksel)(sc, 0);
1005 	wb_stemp(sc, &sc->sensors[7], 3);
1006 	(*sc->lm_banksel)(sc, 0);
1007 	wb781_fanrpm(sc, &sc->sensors[10]);
1008 }
1009 
1010 void
1011 wb782_refresh_sensor_data(sc)
1012 	struct lm_softc *sc;
1013 {
1014 	/* Refresh our stored data for every sensor */
1015 	wb_svolt(sc);
1016 	wb_stemp(sc, &sc->sensors[9], 3);
1017 	wb_fanrpm(sc, &sc->sensors[12]);
1018 }
1019 
1020 void
1021 wb697_refresh_sensor_data(sc)
1022 	struct lm_softc *sc;
1023 {
1024 	/* Refresh our stored data for every sensor */
1025 	wb_svolt(sc);
1026 	wb_stemp(sc, &sc->sensors[9], 2);
1027 	wb_fanrpm(sc, &sc->sensors[11]);
1028 }
1029 
1030 static void
1031 itec_svolt(sc, sensors, infos)
1032 	struct lm_softc *sc;
1033 	struct envsys_tre_data *sensors;
1034 	struct envsys_basic_info *infos;
1035 {
1036 	int i, sdata;
1037 
1038 	for (i = 0; i < 9; i++) {
1039 		sdata = (*sc->lm_readreg)(sc, ITEC_VIN0 + i);
1040 		DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
1041 		/* voltage returned as (mV >> 4), we convert to uVDC */
1042 		sensors[i].cur.data_s = ( sdata << 4 );
1043 		/* rfact is (factor * 10^4) */
1044 
1045 		sensors[i].cur.data_s *= infos[i].rfact;
1046 		/*
1047 		 * XXX We assume input 5 is wired the way iTE suggests to
1048 		 * monitor a negative voltage. I'd prefer using negative rfacts
1049 		 * for detecting those cases but since rfact is an u_int this
1050 		 * isn't possible.
1051 		 */
1052 		if (i == 5)
1053 			sensors[i].cur.data_s -=
1054 			    (infos[i].rfact - 10000) * ITEC_VREF;
1055 		/* division by 10 gets us back to uVDC */
1056 		sensors[i].cur.data_s /= 10;
1057 	}
1058 }
1059 
1060 static void
1061 itec_stemp(sc, sensors)
1062 	struct lm_softc *sc;
1063 	struct  envsys_tre_data *sensors;
1064 {
1065 	int i, sdata;
1066 
1067 	/* temperatures. Given in dC, we convert to uK */
1068 	for (i = 0; i < 3; i++) {
1069 		sdata = (*sc->lm_readreg)(sc, ITEC_TEMP1 + i);
1070 		DPRINTF(("sdata[temp%d] 0x%x\n",i, sdata));
1071 		sensors[i].cur.data_us = sdata * 1000000 + 273150000;
1072 	}
1073 }
1074 
1075 static void
1076 itec_fanrpm(sc, sensors)
1077 	struct lm_softc *sc;
1078 	struct envsys_tre_data *sensors;
1079 {
1080 	int i, fandiv, divisor, sdata;
1081 	(*sc->lm_banksel)(sc, 0);
1082 	fandiv = ((*sc->lm_readreg)(sc, ITEC_FANDIV));
1083 
1084 	for (i = 0; i < 3; i++) {
1085 		sdata = (*sc->lm_readreg)(sc, ITEC_FAN1 + i);
1086 		DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
1087 		switch (i) {
1088 		case 0:
1089 			divisor = fandiv & 0x7;
1090 			break;
1091 		case 1:
1092 			divisor = (fandiv >> 3) & 0x7;
1093 			break;
1094 		case 2:
1095 		default:	/* XXX */
1096 			divisor = (fandiv & 0x40) ? 3 : 1;
1097 			break;
1098 		}
1099 		DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor));
1100 		if (sdata == 0xff || sdata == 0x00) {
1101 			sensors[i].cur.data_us = 0;
1102 		} else {
1103 			sensors[i].cur.data_us = 1350000 /
1104 			    (sdata << divisor);
1105 		}
1106 	}
1107 
1108 }
1109 
1110 void
1111 itec_refresh_sensor_data(sc)
1112 	struct lm_softc *sc;
1113 {
1114 	itec_svolt(sc, &sc->sensors[0], &sc->info[0]);
1115 	itec_stemp(sc, &sc->sensors[9]);
1116 	itec_fanrpm(sc, &sc->sensors[12]);
1117 }
1118