nslm7x.c revision 1.14 1 /* $NetBSD: nslm7x.c,v 1.14 2002/03/30 13:37:41 tron 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.14 2002/03/30 13:37:41 tron 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) do { printf x; } while (0)
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 u_int8_t lm_readreg __P((struct lm_softc *, int));
86 void lm_writereg __P((struct lm_softc *, int, int));
87
88 static void setup_fan __P((struct lm_softc *, int, int));
89 static void setup_temp __P((struct lm_softc *, int, int));
90 static void wb_setup_volt __P((struct lm_softc *));
91
92 int lm_match __P((struct lm_softc *));
93 int wb_match __P((struct lm_softc *));
94 int def_match __P((struct lm_softc *));
95 void lm_common_match __P((struct lm_softc *));
96
97 static void generic_stemp __P((struct lm_softc *, struct envsys_tre_data *));
98 static void generic_svolt __P((struct lm_softc *, struct envsys_tre_data *,
99 struct envsys_basic_info *));
100 static void generic_fanrpm __P((struct lm_softc *, struct envsys_tre_data *));
101
102 void lm_refresh_sensor_data __P((struct lm_softc *));
103
104 static void wb_svolt __P((struct lm_softc *));
105 static void wb_stemp __P((struct lm_softc *, struct envsys_tre_data *, int));
106 static void wb781_fanrpm __P((struct lm_softc *, struct envsys_tre_data *));
107 static void wb_fanrpm __P((struct lm_softc *, struct envsys_tre_data *));
108
109 void wb781_refresh_sensor_data __P((struct lm_softc *));
110 void wb782_refresh_sensor_data __P((struct lm_softc *));
111 void wb697_refresh_sensor_data __P((struct lm_softc *));
112
113 int lm_gtredata __P((struct sysmon_envsys *, struct envsys_tre_data *));
114
115 int generic_streinfo_fan __P((struct lm_softc *, struct envsys_basic_info *,
116 int, struct envsys_basic_info *));
117 int lm_streinfo __P((struct sysmon_envsys *, struct envsys_basic_info *));
118 int wb781_streinfo __P((struct sysmon_envsys *, struct envsys_basic_info *));
119 int wb782_streinfo __P((struct sysmon_envsys *, struct envsys_basic_info *));
120
121 struct lm_chip {
122 int (*chip_match) __P((struct lm_softc *));
123 };
124
125 struct lm_chip lm_chips[] = {
126 { wb_match },
127 { lm_match },
128 { def_match } /* Must be last */
129 };
130
131
132 u_int8_t
133 lm_readreg(sc, reg)
134 struct lm_softc *sc;
135 int reg;
136 {
137 bus_space_write_1(sc->lm_iot, sc->lm_ioh, LMC_ADDR, reg);
138 return (bus_space_read_1(sc->lm_iot, sc->lm_ioh, LMC_DATA));
139 }
140
141 void
142 lm_writereg(sc, reg, val)
143 struct lm_softc *sc;
144 int reg;
145 int val;
146 {
147 bus_space_write_1(sc->lm_iot, sc->lm_ioh, LMC_ADDR, reg);
148 bus_space_write_1(sc->lm_iot, sc->lm_ioh, LMC_DATA, val);
149 }
150
151
152 /*
153 * bus independent probe
154 */
155 int
156 lm_probe(iot, ioh)
157 bus_space_tag_t iot;
158 bus_space_handle_t ioh;
159 {
160 u_int8_t cr;
161 int rv;
162
163 /* Check for some power-on defaults */
164 bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
165
166 /* Perform LM78 reset */
167 bus_space_write_1(iot, ioh, LMC_DATA, 0x80);
168
169 /* XXX - Why do I have to reselect the register? */
170 bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG);
171 cr = bus_space_read_1(iot, ioh, LMC_DATA);
172
173 /* XXX - spec says *only* 0x08! */
174 if ((cr == 0x08) || (cr == 0x01))
175 rv = 1;
176 else
177 rv = 0;
178
179 DPRINTF(("lm: rv = %d, cr = %x\n", rv, cr));
180
181 return (rv);
182 }
183
184
185 /*
186 * pre: lmsc contains valid busspace tag and handle
187 */
188 void
189 lm_attach(lmsc)
190 struct lm_softc *lmsc;
191 {
192 int i;
193
194 for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++)
195 if (lm_chips[i].chip_match(lmsc))
196 break;
197
198 /* Start the monitoring loop */
199 lm_writereg(lmsc, LMD_CONFIG, 0x01);
200
201 /* Indicate we have never read the registers */
202 timerclear(&lmsc->lastread);
203
204 /* Initialize sensors */
205 for (i = 0; i < lmsc->numsensors; ++i) {
206 lmsc->sensors[i].sensor = lmsc->info[i].sensor = i;
207 lmsc->sensors[i].validflags = (ENVSYS_FVALID|ENVSYS_FCURVALID);
208 lmsc->info[i].validflags = ENVSYS_FVALID;
209 lmsc->sensors[i].warnflags = ENVSYS_WARN_OK;
210 }
211 /*
212 * Hook into the System Monitor.
213 */
214 lmsc->sc_sysmon.sme_ranges = lm_ranges;
215 lmsc->sc_sysmon.sme_sensor_info = lmsc->info;
216 lmsc->sc_sysmon.sme_sensor_data = lmsc->sensors;
217 lmsc->sc_sysmon.sme_cookie = lmsc;
218
219 lmsc->sc_sysmon.sme_gtredata = lm_gtredata;
220 /* sme_streinfo set in chip-specific attach */
221
222 lmsc->sc_sysmon.sme_nsensors = lmsc->numsensors;
223 lmsc->sc_sysmon.sme_envsys_version = 1000;
224
225 if (sysmon_envsys_register(&lmsc->sc_sysmon))
226 printf("%s: unable to register with sysmon\n",
227 lmsc->sc_dev.dv_xname);
228 }
229
230 int
231 lm_match(sc)
232 struct lm_softc *sc;
233 {
234 int i;
235
236 /* See if we have an LM78 or LM79 */
237 i = lm_readreg(sc, LMD_CHIPID) & LM_ID_MASK;
238 switch(i) {
239 case LM_ID_LM78:
240 printf(": LM78\n");
241 break;
242 case LM_ID_LM78J:
243 printf(": LM78J\n");
244 break;
245 case LM_ID_LM79:
246 printf(": LM79\n");
247 break;
248 default:
249 return 0;
250 }
251 lm_common_match(sc);
252 return 1;
253 }
254
255 int
256 def_match(sc)
257 struct lm_softc *sc;
258 {
259 int i;
260
261 i = lm_readreg(sc, LMD_CHIPID) & LM_ID_MASK;
262 printf(": Unknow chip (ID %d)\n", i);
263 lm_common_match(sc);
264 return 1;
265 }
266
267 void
268 lm_common_match(sc)
269 struct lm_softc *sc;
270 {
271 int i;
272 sc->numsensors = LM_NUM_SENSORS;
273 sc->refresh_sensor_data = lm_refresh_sensor_data;
274
275 for (i = 0; i < 7; ++i) {
276 sc->sensors[i].units = sc->info[i].units =
277 ENVSYS_SVOLTS_DC;
278 sprintf(sc->info[i].desc, "IN %d", i);
279 }
280
281 /* default correction factors for resistors on higher voltage inputs */
282 sc->info[0].rfact = sc->info[1].rfact =
283 sc->info[2].rfact = 10000;
284 sc->info[3].rfact = (int)(( 90.9 / 60.4) * 10000);
285 sc->info[4].rfact = (int)(( 38.0 / 10.0) * 10000);
286 sc->info[5].rfact = (int)((210.0 / 60.4) * 10000);
287 sc->info[6].rfact = (int)(( 90.9 / 60.4) * 10000);
288
289 sc->sensors[7].units = ENVSYS_STEMP;
290 strcpy(sc->info[7].desc, "Temp");
291
292 setup_fan(sc, 8, 3);
293 sc->sc_sysmon.sme_streinfo = lm_streinfo;
294 }
295
296 int
297 wb_match(sc)
298 struct lm_softc *sc;
299 {
300 int i, j;
301
302 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_HBAC);
303 j = lm_readreg(sc, WB_VENDID) << 8;
304 lm_writereg(sc, WB_BANKSEL, 0);
305 j |= lm_readreg(sc, WB_VENDID);
306 DPRINTF(("winbond vend id 0x%x\n", j));
307 if (j != WB_VENDID_WINBOND)
308 return 0;
309 /* read device ID */
310 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
311 j = lm_readreg(sc, WB_BANK0_CHIPID);
312 DPRINTF(("winbond chip id 0x%x\n", j));
313 switch(j) {
314 case WB_CHIPID_83781:
315 case WB_CHIPID_83781_2:
316 printf(": W83781D\n");
317
318 for (i = 0; i < 7; ++i) {
319 sc->sensors[i].units = sc->info[i].units =
320 ENVSYS_SVOLTS_DC;
321 sprintf(sc->info[i].desc, "IN %d", i);
322 }
323
324 /* default correction factors for higher voltage inputs */
325 sc->info[0].rfact = sc->info[1].rfact =
326 sc->info[2].rfact = 10000;
327 sc->info[3].rfact = (int)(( 90.9 / 60.4) * 10000);
328 sc->info[4].rfact = (int)(( 38.0 / 10.0) * 10000);
329 sc->info[5].rfact = (int)((210.0 / 60.4) * 10000);
330 sc->info[6].rfact = (int)(( 90.9 / 60.4) * 10000);
331
332 setup_temp(sc, 7, 3);
333 setup_fan(sc, 10, 3);
334
335 sc->numsensors = WB83781_NUM_SENSORS;
336 sc->refresh_sensor_data = wb781_refresh_sensor_data;
337 sc->sc_sysmon.sme_streinfo = wb781_streinfo;
338 return 1;
339 case WB_CHIPID_83697:
340 printf(": W83697HF\n");
341 wb_setup_volt(sc);
342 setup_temp(sc, 9, 2);
343 setup_fan(sc, 11, 3);
344 sc->numsensors = WB83697_NUM_SENSORS;
345 sc->refresh_sensor_data = wb697_refresh_sensor_data;
346 sc->sc_sysmon.sme_streinfo = wb782_streinfo;
347 return 1;
348 break;
349 case WB_CHIPID_83782:
350 printf(": W83782D\n");
351 break;
352 case WB_CHIPID_83627:
353 printf(": W83627HF\n");
354 break;
355 default:
356 printf(": unknow winbond chip ID 0x%x\n", j);
357 /* handle as a standart lm7x */
358 lm_common_match(sc);
359 return 1;
360 }
361 /* common code for the W83782D and W83627HF */
362 wb_setup_volt(sc);
363 setup_temp(sc, 9, 3);
364 setup_fan(sc, 12, 3);
365 sc->numsensors = WB_NUM_SENSORS;
366 sc->refresh_sensor_data = wb782_refresh_sensor_data;
367 sc->sc_sysmon.sme_streinfo = wb782_streinfo;
368 return 1;
369 }
370
371 static void
372 wb_setup_volt(sc)
373 struct lm_softc *sc;
374 {
375 sc->sensors[0].units = sc->info[0].units = ENVSYS_SVOLTS_DC;
376 sprintf(sc->info[0].desc, "VCORE A");
377 sc->info[0].rfact = 10000;
378 sc->sensors[1].units = sc->info[1].units = ENVSYS_SVOLTS_DC;
379 sprintf(sc->info[1].desc, "VCORE B");
380 sc->info[1].rfact = 10000;
381 sc->sensors[2].units = sc->info[2].units = ENVSYS_SVOLTS_DC;
382 sprintf(sc->info[2].desc, "+3.3V");
383 sc->info[2].rfact = 10000;
384 sc->sensors[3].units = sc->info[3].units = ENVSYS_SVOLTS_DC;
385 sprintf(sc->info[3].desc, "+5V");
386 sc->info[3].rfact = 16778;
387 sc->sensors[4].units = sc->info[4].units = ENVSYS_SVOLTS_DC;
388 sprintf(sc->info[4].desc, "+12V");
389 sc->info[4].rfact = 38000;
390 sc->sensors[5].units = sc->info[5].units = ENVSYS_SVOLTS_DC;
391 sprintf(sc->info[5].desc, "-12V");
392 sc->info[5].rfact = 10000;
393 sc->sensors[6].units = sc->info[6].units = ENVSYS_SVOLTS_DC;
394 sprintf(sc->info[6].desc, "-5V");
395 sc->info[6].rfact = 10000;
396 sc->sensors[7].units = sc->info[7].units = ENVSYS_SVOLTS_DC;
397 sprintf(sc->info[7].desc, "+5VSB");
398 sc->info[7].rfact = 15151;
399 sc->sensors[8].units = sc->info[8].units = ENVSYS_SVOLTS_DC;
400 sprintf(sc->info[8].desc, "VBAT");
401 sc->info[8].rfact = 10000;
402 }
403
404 static void
405 setup_temp(sc, start, n)
406 struct lm_softc *sc;
407 int start, n;
408 {
409 int i;
410
411 for (i = 0; i < n; i++) {
412 sc->sensors[start + i].units = ENVSYS_STEMP;
413 sprintf(sc->info[start + i].desc, "Temp %d", i + 1);
414 }
415 }
416
417
418 static void
419 setup_fan(sc, start, n)
420 struct lm_softc *sc;
421 int start, n;
422 {
423 int i;
424 for (i = 0; i < n; ++i) {
425 sc->sensors[start + i].units = ENVSYS_SFANRPM;
426 sc->info[start + i].units = ENVSYS_SFANRPM;
427 sprintf(sc->info[start + i].desc, "Fan %d", i + 1);
428 }
429 }
430
431 int
432 lm_gtredata(sme, tred)
433 struct sysmon_envsys *sme;
434 struct envsys_tre_data *tred;
435 {
436 static const struct timeval onepointfive = { 1, 500000 };
437 struct timeval t;
438 struct lm_softc *sc = sme->sme_cookie;
439 int i, s;
440
441 /* read new values at most once every 1.5 seconds */
442 timeradd(&sc->lastread, &onepointfive, &t);
443 s = splclock();
444 i = timercmp(&mono_time, &t, >);
445 if (i) {
446 sc->lastread.tv_sec = mono_time.tv_sec;
447 sc->lastread.tv_usec = mono_time.tv_usec;
448 }
449 splx(s);
450
451 if (i)
452 sc->refresh_sensor_data(sc);
453
454 *tred = sc->sensors[tred->sensor];
455
456 return (0);
457 }
458
459 int
460 generic_streinfo_fan(sc, info, n, binfo)
461 struct lm_softc *sc;
462 struct envsys_basic_info *info;
463 int n;
464 struct envsys_basic_info *binfo;
465 {
466 u_int8_t sdata;
467 int divisor;
468
469 /* FAN1 and FAN2 can have divisors set, but not FAN3 */
470 if ((sc->info[binfo->sensor].units == ENVSYS_SFANRPM)
471 && (n < 2)) {
472 if (binfo->rpms == 0) {
473 binfo->validflags = 0;
474 return (0);
475 }
476
477 /* write back the nominal FAN speed */
478 info->rpms = binfo->rpms;
479
480 /* 153 is the nominal FAN speed value */
481 divisor = 1350000 / (binfo->rpms * 153);
482
483 /* ...but we need lg(divisor) */
484 if (divisor <= 1)
485 divisor = 0;
486 else if (divisor <= 2)
487 divisor = 1;
488 else if (divisor <= 4)
489 divisor = 2;
490 else
491 divisor = 3;
492
493 /*
494 * FAN1 div is in bits <5:4>, FAN2 div is
495 * in <7:6>
496 */
497 sdata = lm_readreg(sc, LMD_VIDFAN);
498 if ( n == 0 ) { /* FAN1 */
499 divisor <<= 4;
500 sdata = (sdata & 0xCF) | divisor;
501 } else { /* FAN2 */
502 divisor <<= 6;
503 sdata = (sdata & 0x3F) | divisor;
504 }
505
506 lm_writereg(sc, LMD_VIDFAN, sdata);
507 }
508 return (0);
509
510 }
511
512 int
513 lm_streinfo(sme, binfo)
514 struct sysmon_envsys *sme;
515 struct envsys_basic_info *binfo;
516 {
517 struct lm_softc *sc = sme->sme_cookie;
518
519 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
520 sc->info[binfo->sensor].rfact = binfo->rfact;
521 else {
522 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
523 generic_streinfo_fan(sc, &sc->info[binfo->sensor],
524 binfo->sensor - 8, binfo);
525 }
526 memcpy(sc->info[binfo->sensor].desc, binfo->desc,
527 sizeof(sc->info[binfo->sensor].desc));
528 sc->info[binfo->sensor].desc[
529 sizeof(sc->info[binfo->sensor].desc) - 1] = '\0';
530
531 binfo->validflags = ENVSYS_FVALID;
532 }
533 return (0);
534 }
535
536 int
537 wb781_streinfo(sme, binfo)
538 struct sysmon_envsys *sme;
539 struct envsys_basic_info *binfo;
540 {
541 struct lm_softc *sc = sme->sme_cookie;
542 int divisor;
543 u_int8_t sdata;
544 int i;
545
546 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
547 sc->info[binfo->sensor].rfact = binfo->rfact;
548 else {
549 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
550 if (binfo->rpms == 0) {
551 binfo->validflags = 0;
552 return (0);
553 }
554
555 /* write back the nominal FAN speed */
556 sc->info[binfo->sensor].rpms = binfo->rpms;
557
558 /* 153 is the nominal FAN speed value */
559 divisor = 1350000 / (binfo->rpms * 153);
560
561 /* ...but we need lg(divisor) */
562 for (i = 0; i < 7; i++) {
563 if (divisor <= (1 << i))
564 break;
565 }
566 divisor = i;
567
568 if (binfo->sensor == 10 || binfo->sensor == 11) {
569 /*
570 * FAN1 div is in bits <5:4>, FAN2 div
571 * is in <7:6>
572 */
573 sdata = lm_readreg(sc, LMD_VIDFAN);
574 if ( binfo->sensor == 10 ) { /* FAN1 */
575 sdata = (sdata & 0xCF) |
576 ((divisor & 0x3) << 4);
577 } else { /* FAN2 */
578 sdata = (sdata & 0x3F) |
579 ((divisor & 0x3) << 6);
580 }
581 lm_writereg(sc, LMD_VIDFAN, sdata);
582 } else {
583 /* FAN3 is in WB_PIN <7:6> */
584 sdata = lm_readreg(sc, WB_PIN);
585 sdata = (sdata & 0x3F) |
586 ((divisor & 0x3) << 6);
587 lm_writereg(sc, WB_PIN, sdata);
588 }
589 }
590 memcpy(sc->info[binfo->sensor].desc, binfo->desc,
591 sizeof(sc->info[binfo->sensor].desc));
592 sc->info[binfo->sensor].desc[
593 sizeof(sc->info[binfo->sensor].desc) - 1] = '\0';
594
595 binfo->validflags = ENVSYS_FVALID;
596 }
597 return (0);
598 }
599
600 int
601 wb782_streinfo(sme, binfo)
602 struct sysmon_envsys *sme;
603 struct envsys_basic_info *binfo;
604 {
605 struct lm_softc *sc = sme->sme_cookie;
606 int divisor;
607 u_int8_t sdata;
608 int i;
609
610 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC)
611 sc->info[binfo->sensor].rfact = binfo->rfact;
612 else {
613 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) {
614 if (binfo->rpms == 0) {
615 binfo->validflags = 0;
616 return (0);
617 }
618
619 /* write back the nominal FAN speed */
620 sc->info[binfo->sensor].rpms = binfo->rpms;
621
622 /* 153 is the nominal FAN speed value */
623 divisor = 1350000 / (binfo->rpms * 153);
624
625 /* ...but we need lg(divisor) */
626 for (i = 0; i < 7; i++) {
627 if (divisor <= (1 << i))
628 break;
629 }
630 divisor = i;
631
632 if (binfo->sensor == 12 || binfo->sensor == 13) {
633 /*
634 * FAN1 div is in bits <5:4>, FAN2 div
635 * is in <7:6>
636 */
637 sdata = lm_readreg(sc, LMD_VIDFAN);
638 if ( binfo->sensor == 12 ) { /* FAN1 */
639 sdata = (sdata & 0xCF) |
640 ((divisor & 0x3) << 4);
641 } else { /* FAN2 */
642 sdata = (sdata & 0x3F) |
643 ((divisor & 0x3) << 6);
644 }
645 lm_writereg(sc, LMD_VIDFAN, sdata);
646 } else {
647 /* FAN3 is in WB_PIN <7:6> */
648 sdata = lm_readreg(sc, WB_PIN);
649 sdata = (sdata & 0x3F) |
650 ((divisor & 0x3) << 6);
651 lm_writereg(sc, WB_PIN, sdata);
652 }
653 /* Bit 2 of divisor is in WB_BANK0_FANBAT */
654 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
655 sdata = lm_readreg(sc, WB_BANK0_FANBAT);
656 sdata &= ~(0x20 << (binfo->sensor - 12));
657 sdata |= (divisor & 0x4) << (binfo->sensor - 9);
658 lm_writereg(sc, WB_BANK0_FANBAT, sdata);
659 }
660
661 memcpy(sc->info[binfo->sensor].desc, binfo->desc,
662 sizeof(sc->info[binfo->sensor].desc));
663 sc->info[binfo->sensor].desc[
664 sizeof(sc->info[binfo->sensor].desc) - 1] = '\0';
665
666 binfo->validflags = ENVSYS_FVALID;
667 }
668 return (0);
669 }
670
671 static void
672 generic_stemp(sc, sensor)
673 struct lm_softc *sc;
674 struct envsys_tre_data *sensor;
675 {
676 int sdata = lm_readreg(sc, LMD_SENSORBASE + 7);
677 DPRINTF(("sdata[temp] 0x%x\n", sdata));
678 /* temp is given in deg. C, we convert to uK */
679 sensor->cur.data_us = sdata * 1000000 + 273150000;
680 }
681
682 static void
683 generic_svolt(sc, sensors, infos)
684 struct lm_softc *sc;
685 struct envsys_tre_data *sensors;
686 struct envsys_basic_info *infos;
687 {
688 int i, sdata;
689
690 for (i = 0; i < 7; i++) {
691 sdata = lm_readreg(sc, LMD_SENSORBASE + i);
692 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
693 /* voltage returned as (mV >> 4), we convert to uVDC */
694 sensors[i].cur.data_s = (sdata << 4);
695 /* rfact is (factor * 10^4) */
696 sensors[i].cur.data_s *= infos[i].rfact;
697 /* division by 10 gets us back to uVDC */
698 sensors[i].cur.data_s /= 10;
699
700 /* these two are negative voltages */
701 if ( (i == 5) || (i == 6) )
702 sensors[i].cur.data_s *= -1;
703 }
704 }
705
706 static void
707 generic_fanrpm(sc, sensors)
708 struct lm_softc *sc;
709 struct envsys_tre_data *sensors;
710 {
711 int i, sdata, divisor;
712 for (i = 0; i < 3; i++) {
713 sdata = lm_readreg(sc, LMD_SENSORBASE + 8 + i);
714 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
715 if (i == 2)
716 divisor = 2; /* Fixed divisor for FAN3 */
717 else if (i == 1) /* Bits 7 & 6 of VID/FAN */
718 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 6) & 0x3;
719 else
720 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 4) & 0x3;
721
722 if (sdata == 0xff || sdata == 0x00) {
723 sensors[i].cur.data_us = 0;
724 } else {
725 sensors[i].cur.data_us = 1350000 / (sdata << divisor);
726 }
727 }
728 }
729
730 /*
731 * pre: last read occurred >= 1.5 seconds ago
732 * post: sensors[] current data are the latest from the chip
733 */
734 void
735 lm_refresh_sensor_data(sc)
736 struct lm_softc *sc;
737 {
738 /* Refresh our stored data for every sensor */
739 generic_stemp(sc, &sc->sensors[7]);
740 generic_svolt(sc, &sc->sensors[0], &sc->info[0]);
741 generic_fanrpm(sc, &sc->sensors[8]);
742 }
743
744 static void
745 wb_svolt(sc)
746 struct lm_softc *sc;
747 {
748 int i, sdata;
749 for (i = 0; i < 9; ++i) {
750 if (i < 7) {
751 sdata = lm_readreg(sc, LMD_SENSORBASE + i);
752 } else {
753 /* from bank5 */
754 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B5);
755 sdata = lm_readreg(sc, (i == 7) ?
756 WB_BANK5_5VSB : WB_BANK5_VBAT);
757 }
758 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata));
759 /* voltage returned as (mV >> 4), we convert to uV */
760 sdata = sdata << 4;
761 /* special case for negative voltages */
762 if (i == 5) {
763 /*
764 * -12Vdc, assume Winbond recommended values for
765 * resistors
766 */
767 sdata = ((sdata * 1000) - (3600 * 805)) / 195;
768 } else if (i == 6) {
769 /*
770 * -5Vdc, assume Winbond recommended values for
771 * resistors
772 */
773 sdata = ((sdata * 1000) - (3600 * 682)) / 318;
774 }
775 /* rfact is (factor * 10^4) */
776 sc->sensors[i].cur.data_s = sdata * sc->info[i].rfact;
777 /* division by 10 gets us back to uVDC */
778 sc->sensors[i].cur.data_s /= 10;
779 }
780 }
781
782 static void
783 wb_stemp(sc, sensors, n)
784 struct lm_softc *sc;
785 struct envsys_tre_data *sensors;
786 int n;
787 {
788 int sdata;
789 /* temperatures. Given in dC, we convert to uK */
790 sdata = lm_readreg(sc, LMD_SENSORBASE + 7);
791 DPRINTF(("sdata[temp0] 0x%x\n", sdata));
792 sensors[0].cur.data_us = sdata * 1000000 + 273150000;
793 /* from bank1 */
794 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B1);
795 sdata = lm_readreg(sc, WB_BANK1_T2H) << 1;
796 sdata |= (lm_readreg(sc, WB_BANK1_T2L) & 0x80) >> 7;
797 DPRINTF(("sdata[temp1] 0x%x\n", sdata));
798 sensors[1].cur.data_us = (sdata * 1000000) / 2 + 273150000;
799 if (n < 3)
800 return;
801 /* from bank2 */
802 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B2);
803 sdata = lm_readreg(sc, WB_BANK2_T3H) << 1;
804 sdata |= (lm_readreg(sc, WB_BANK2_T3L) & 0x80) >> 7;
805 DPRINTF(("sdata[temp2] 0x%x\n", sdata));
806 sensors[2].cur.data_us = (sdata * 1000000) / 2 + 273150000;
807 }
808
809 static void
810 wb781_fanrpm(sc, sensors)
811 struct lm_softc *sc;
812 struct envsys_tre_data *sensors;
813 {
814 int i, divisor, sdata;
815 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
816 for (i = 0; i < 3; i++) {
817 sdata = lm_readreg(sc, LMD_SENSORBASE + i + 8);
818 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
819 if (i == 0)
820 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 4) & 0x3;
821 else if (i == 1)
822 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 6) & 0x3;
823 else
824 divisor = (lm_readreg(sc, WB_PIN) >> 6) & 0x3;
825
826 DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor));
827 if (sdata == 0xff || sdata == 0x00) {
828 sensors[i].cur.data_us = 0;
829 } else {
830 sensors[i].cur.data_us = 1350000 /
831 (sdata << divisor);
832 }
833 }
834 }
835
836 static void
837 wb_fanrpm(sc, sensors)
838 struct lm_softc *sc;
839 struct envsys_tre_data *sensors;
840 {
841 int i, divisor, sdata;
842 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
843 for (i = 0; i < 3; i++) {
844 sdata = lm_readreg(sc, LMD_SENSORBASE + i + 8);
845 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata));
846 if (i == 0)
847 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 4) & 0x3;
848 else if (i == 1)
849 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 6) & 0x3;
850 else
851 divisor = (lm_readreg(sc, WB_PIN) >> 6) & 0x3;
852 divisor |= (lm_readreg(sc, WB_BANK0_FANBAT) >> (i + 3)) & 0x4;
853
854 DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor));
855 if (sdata == 0xff || sdata == 0x00) {
856 sensors[i].cur.data_us = 0;
857 } else {
858 sensors[i].cur.data_us = 1350000 /
859 (sdata << divisor);
860 }
861 }
862 }
863
864 void
865 wb781_refresh_sensor_data(sc)
866 struct lm_softc *sc;
867 {
868 /* Refresh our stored data for every sensor */
869 /* we need to reselect bank0 to access common registers */
870 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
871 generic_svolt(sc, &sc->sensors[0], &sc->info[0]);
872 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
873 wb_stemp(sc, &sc->sensors[7], 3);
874 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0);
875 wb781_fanrpm(sc, &sc->sensors[10]);
876 }
877
878 void
879 wb782_refresh_sensor_data(sc)
880 struct lm_softc *sc;
881 {
882 /* Refresh our stored data for every sensor */
883 wb_svolt(sc);
884 wb_stemp(sc, &sc->sensors[9], 3);
885 wb_fanrpm(sc, &sc->sensors[12]);
886 }
887
888 void
889 wb697_refresh_sensor_data(sc)
890 struct lm_softc *sc;
891 {
892 /* Refresh our stored data for every sensor */
893 wb_svolt(sc);
894 wb_stemp(sc, &sc->sensors[9], 2);
895 wb_fanrpm(sc, &sc->sensors[11]);
896 }
897