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