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