1 /* $NetBSD: nslm7x.c,v 1.15 2002/04/05 16:11:47 bouyer 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.15 2002/04/05 16:11:47 bouyer 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 case LM_ID_LM81: 249 printf(": LM81\n"); 250 break; 251 default: 252 return 0; 253 } 254 lm_common_match(sc); 255 return 1; 256 } 257 258 int 259 def_match(sc) 260 struct lm_softc *sc; 261 { 262 int i; 263 264 i = lm_readreg(sc, LMD_CHIPID) & LM_ID_MASK; 265 printf(": Unknow chip (ID %d)\n", i); 266 lm_common_match(sc); 267 return 1; 268 } 269 270 void 271 lm_common_match(sc) 272 struct lm_softc *sc; 273 { 274 int i; 275 sc->numsensors = LM_NUM_SENSORS; 276 sc->refresh_sensor_data = lm_refresh_sensor_data; 277 278 for (i = 0; i < 7; ++i) { 279 sc->sensors[i].units = sc->info[i].units = 280 ENVSYS_SVOLTS_DC; 281 sprintf(sc->info[i].desc, "IN %d", i); 282 } 283 284 /* default correction factors for resistors on higher voltage inputs */ 285 sc->info[0].rfact = sc->info[1].rfact = 286 sc->info[2].rfact = 10000; 287 sc->info[3].rfact = (int)(( 90.9 / 60.4) * 10000); 288 sc->info[4].rfact = (int)(( 38.0 / 10.0) * 10000); 289 sc->info[5].rfact = (int)((210.0 / 60.4) * 10000); 290 sc->info[6].rfact = (int)(( 90.9 / 60.4) * 10000); 291 292 sc->sensors[7].units = ENVSYS_STEMP; 293 strcpy(sc->info[7].desc, "Temp"); 294 295 setup_fan(sc, 8, 3); 296 sc->sc_sysmon.sme_streinfo = lm_streinfo; 297 } 298 299 int 300 wb_match(sc) 301 struct lm_softc *sc; 302 { 303 int i, j; 304 305 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_HBAC); 306 j = lm_readreg(sc, WB_VENDID) << 8; 307 lm_writereg(sc, WB_BANKSEL, 0); 308 j |= lm_readreg(sc, WB_VENDID); 309 DPRINTF(("winbond vend id 0x%x\n", j)); 310 if (j != WB_VENDID_WINBOND) 311 return 0; 312 /* read device ID */ 313 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); 314 j = lm_readreg(sc, WB_BANK0_CHIPID); 315 DPRINTF(("winbond chip id 0x%x\n", j)); 316 switch(j) { 317 case WB_CHIPID_83781: 318 case WB_CHIPID_83781_2: 319 printf(": W83781D\n"); 320 321 for (i = 0; i < 7; ++i) { 322 sc->sensors[i].units = sc->info[i].units = 323 ENVSYS_SVOLTS_DC; 324 sprintf(sc->info[i].desc, "IN %d", i); 325 } 326 327 /* default correction factors for higher voltage inputs */ 328 sc->info[0].rfact = sc->info[1].rfact = 329 sc->info[2].rfact = 10000; 330 sc->info[3].rfact = (int)(( 90.9 / 60.4) * 10000); 331 sc->info[4].rfact = (int)(( 38.0 / 10.0) * 10000); 332 sc->info[5].rfact = (int)((210.0 / 60.4) * 10000); 333 sc->info[6].rfact = (int)(( 90.9 / 60.4) * 10000); 334 335 setup_temp(sc, 7, 3); 336 setup_fan(sc, 10, 3); 337 338 sc->numsensors = WB83781_NUM_SENSORS; 339 sc->refresh_sensor_data = wb781_refresh_sensor_data; 340 sc->sc_sysmon.sme_streinfo = wb781_streinfo; 341 return 1; 342 case WB_CHIPID_83697: 343 printf(": W83697HF\n"); 344 wb_setup_volt(sc); 345 setup_temp(sc, 9, 2); 346 setup_fan(sc, 11, 3); 347 sc->numsensors = WB83697_NUM_SENSORS; 348 sc->refresh_sensor_data = wb697_refresh_sensor_data; 349 sc->sc_sysmon.sme_streinfo = wb782_streinfo; 350 return 1; 351 break; 352 case WB_CHIPID_83782: 353 printf(": W83782D\n"); 354 break; 355 case WB_CHIPID_83627: 356 printf(": W83627HF\n"); 357 break; 358 default: 359 printf(": unknow winbond chip ID 0x%x\n", j); 360 /* handle as a standart lm7x */ 361 lm_common_match(sc); 362 return 1; 363 } 364 /* common code for the W83782D and W83627HF */ 365 wb_setup_volt(sc); 366 setup_temp(sc, 9, 3); 367 setup_fan(sc, 12, 3); 368 sc->numsensors = WB_NUM_SENSORS; 369 sc->refresh_sensor_data = wb782_refresh_sensor_data; 370 sc->sc_sysmon.sme_streinfo = wb782_streinfo; 371 return 1; 372 } 373 374 static void 375 wb_setup_volt(sc) 376 struct lm_softc *sc; 377 { 378 sc->sensors[0].units = sc->info[0].units = ENVSYS_SVOLTS_DC; 379 sprintf(sc->info[0].desc, "VCORE A"); 380 sc->info[0].rfact = 10000; 381 sc->sensors[1].units = sc->info[1].units = ENVSYS_SVOLTS_DC; 382 sprintf(sc->info[1].desc, "VCORE B"); 383 sc->info[1].rfact = 10000; 384 sc->sensors[2].units = sc->info[2].units = ENVSYS_SVOLTS_DC; 385 sprintf(sc->info[2].desc, "+3.3V"); 386 sc->info[2].rfact = 10000; 387 sc->sensors[3].units = sc->info[3].units = ENVSYS_SVOLTS_DC; 388 sprintf(sc->info[3].desc, "+5V"); 389 sc->info[3].rfact = 16778; 390 sc->sensors[4].units = sc->info[4].units = ENVSYS_SVOLTS_DC; 391 sprintf(sc->info[4].desc, "+12V"); 392 sc->info[4].rfact = 38000; 393 sc->sensors[5].units = sc->info[5].units = ENVSYS_SVOLTS_DC; 394 sprintf(sc->info[5].desc, "-12V"); 395 sc->info[5].rfact = 10000; 396 sc->sensors[6].units = sc->info[6].units = ENVSYS_SVOLTS_DC; 397 sprintf(sc->info[6].desc, "-5V"); 398 sc->info[6].rfact = 10000; 399 sc->sensors[7].units = sc->info[7].units = ENVSYS_SVOLTS_DC; 400 sprintf(sc->info[7].desc, "+5VSB"); 401 sc->info[7].rfact = 15151; 402 sc->sensors[8].units = sc->info[8].units = ENVSYS_SVOLTS_DC; 403 sprintf(sc->info[8].desc, "VBAT"); 404 sc->info[8].rfact = 10000; 405 } 406 407 static void 408 setup_temp(sc, start, n) 409 struct lm_softc *sc; 410 int start, n; 411 { 412 int i; 413 414 for (i = 0; i < n; i++) { 415 sc->sensors[start + i].units = ENVSYS_STEMP; 416 sprintf(sc->info[start + i].desc, "Temp %d", i + 1); 417 } 418 } 419 420 421 static void 422 setup_fan(sc, start, n) 423 struct lm_softc *sc; 424 int start, n; 425 { 426 int i; 427 for (i = 0; i < n; ++i) { 428 sc->sensors[start + i].units = ENVSYS_SFANRPM; 429 sc->info[start + i].units = ENVSYS_SFANRPM; 430 sprintf(sc->info[start + i].desc, "Fan %d", i + 1); 431 } 432 } 433 434 int 435 lm_gtredata(sme, tred) 436 struct sysmon_envsys *sme; 437 struct envsys_tre_data *tred; 438 { 439 static const struct timeval onepointfive = { 1, 500000 }; 440 struct timeval t; 441 struct lm_softc *sc = sme->sme_cookie; 442 int i, s; 443 444 /* read new values at most once every 1.5 seconds */ 445 timeradd(&sc->lastread, &onepointfive, &t); 446 s = splclock(); 447 i = timercmp(&mono_time, &t, >); 448 if (i) { 449 sc->lastread.tv_sec = mono_time.tv_sec; 450 sc->lastread.tv_usec = mono_time.tv_usec; 451 } 452 splx(s); 453 454 if (i) 455 sc->refresh_sensor_data(sc); 456 457 *tred = sc->sensors[tred->sensor]; 458 459 return (0); 460 } 461 462 int 463 generic_streinfo_fan(sc, info, n, binfo) 464 struct lm_softc *sc; 465 struct envsys_basic_info *info; 466 int n; 467 struct envsys_basic_info *binfo; 468 { 469 u_int8_t sdata; 470 int divisor; 471 472 /* FAN1 and FAN2 can have divisors set, but not FAN3 */ 473 if ((sc->info[binfo->sensor].units == ENVSYS_SFANRPM) 474 && (n < 2)) { 475 if (binfo->rpms == 0) { 476 binfo->validflags = 0; 477 return (0); 478 } 479 480 /* write back the nominal FAN speed */ 481 info->rpms = binfo->rpms; 482 483 /* 153 is the nominal FAN speed value */ 484 divisor = 1350000 / (binfo->rpms * 153); 485 486 /* ...but we need lg(divisor) */ 487 if (divisor <= 1) 488 divisor = 0; 489 else if (divisor <= 2) 490 divisor = 1; 491 else if (divisor <= 4) 492 divisor = 2; 493 else 494 divisor = 3; 495 496 /* 497 * FAN1 div is in bits <5:4>, FAN2 div is 498 * in <7:6> 499 */ 500 sdata = lm_readreg(sc, LMD_VIDFAN); 501 if ( n == 0 ) { /* FAN1 */ 502 divisor <<= 4; 503 sdata = (sdata & 0xCF) | divisor; 504 } else { /* FAN2 */ 505 divisor <<= 6; 506 sdata = (sdata & 0x3F) | divisor; 507 } 508 509 lm_writereg(sc, LMD_VIDFAN, sdata); 510 } 511 return (0); 512 513 } 514 515 int 516 lm_streinfo(sme, binfo) 517 struct sysmon_envsys *sme; 518 struct envsys_basic_info *binfo; 519 { 520 struct lm_softc *sc = sme->sme_cookie; 521 522 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC) 523 sc->info[binfo->sensor].rfact = binfo->rfact; 524 else { 525 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) { 526 generic_streinfo_fan(sc, &sc->info[binfo->sensor], 527 binfo->sensor - 8, binfo); 528 } 529 memcpy(sc->info[binfo->sensor].desc, binfo->desc, 530 sizeof(sc->info[binfo->sensor].desc)); 531 sc->info[binfo->sensor].desc[ 532 sizeof(sc->info[binfo->sensor].desc) - 1] = '\0'; 533 534 binfo->validflags = ENVSYS_FVALID; 535 } 536 return (0); 537 } 538 539 int 540 wb781_streinfo(sme, binfo) 541 struct sysmon_envsys *sme; 542 struct envsys_basic_info *binfo; 543 { 544 struct lm_softc *sc = sme->sme_cookie; 545 int divisor; 546 u_int8_t sdata; 547 int i; 548 549 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC) 550 sc->info[binfo->sensor].rfact = binfo->rfact; 551 else { 552 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) { 553 if (binfo->rpms == 0) { 554 binfo->validflags = 0; 555 return (0); 556 } 557 558 /* write back the nominal FAN speed */ 559 sc->info[binfo->sensor].rpms = binfo->rpms; 560 561 /* 153 is the nominal FAN speed value */ 562 divisor = 1350000 / (binfo->rpms * 153); 563 564 /* ...but we need lg(divisor) */ 565 for (i = 0; i < 7; i++) { 566 if (divisor <= (1 << i)) 567 break; 568 } 569 divisor = i; 570 571 if (binfo->sensor == 10 || binfo->sensor == 11) { 572 /* 573 * FAN1 div is in bits <5:4>, FAN2 div 574 * is in <7:6> 575 */ 576 sdata = lm_readreg(sc, LMD_VIDFAN); 577 if ( binfo->sensor == 10 ) { /* FAN1 */ 578 sdata = (sdata & 0xCF) | 579 ((divisor & 0x3) << 4); 580 } else { /* FAN2 */ 581 sdata = (sdata & 0x3F) | 582 ((divisor & 0x3) << 6); 583 } 584 lm_writereg(sc, LMD_VIDFAN, sdata); 585 } else { 586 /* FAN3 is in WB_PIN <7:6> */ 587 sdata = lm_readreg(sc, WB_PIN); 588 sdata = (sdata & 0x3F) | 589 ((divisor & 0x3) << 6); 590 lm_writereg(sc, WB_PIN, sdata); 591 } 592 } 593 memcpy(sc->info[binfo->sensor].desc, binfo->desc, 594 sizeof(sc->info[binfo->sensor].desc)); 595 sc->info[binfo->sensor].desc[ 596 sizeof(sc->info[binfo->sensor].desc) - 1] = '\0'; 597 598 binfo->validflags = ENVSYS_FVALID; 599 } 600 return (0); 601 } 602 603 int 604 wb782_streinfo(sme, binfo) 605 struct sysmon_envsys *sme; 606 struct envsys_basic_info *binfo; 607 { 608 struct lm_softc *sc = sme->sme_cookie; 609 int divisor; 610 u_int8_t sdata; 611 int i; 612 613 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC) 614 sc->info[binfo->sensor].rfact = binfo->rfact; 615 else { 616 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) { 617 if (binfo->rpms == 0) { 618 binfo->validflags = 0; 619 return (0); 620 } 621 622 /* write back the nominal FAN speed */ 623 sc->info[binfo->sensor].rpms = binfo->rpms; 624 625 /* 153 is the nominal FAN speed value */ 626 divisor = 1350000 / (binfo->rpms * 153); 627 628 /* ...but we need lg(divisor) */ 629 for (i = 0; i < 7; i++) { 630 if (divisor <= (1 << i)) 631 break; 632 } 633 divisor = i; 634 635 if (binfo->sensor == 12 || binfo->sensor == 13) { 636 /* 637 * FAN1 div is in bits <5:4>, FAN2 div 638 * is in <7:6> 639 */ 640 sdata = lm_readreg(sc, LMD_VIDFAN); 641 if ( binfo->sensor == 12 ) { /* FAN1 */ 642 sdata = (sdata & 0xCF) | 643 ((divisor & 0x3) << 4); 644 } else { /* FAN2 */ 645 sdata = (sdata & 0x3F) | 646 ((divisor & 0x3) << 6); 647 } 648 lm_writereg(sc, LMD_VIDFAN, sdata); 649 } else { 650 /* FAN3 is in WB_PIN <7:6> */ 651 sdata = lm_readreg(sc, WB_PIN); 652 sdata = (sdata & 0x3F) | 653 ((divisor & 0x3) << 6); 654 lm_writereg(sc, WB_PIN, sdata); 655 } 656 /* Bit 2 of divisor is in WB_BANK0_FANBAT */ 657 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); 658 sdata = lm_readreg(sc, WB_BANK0_FANBAT); 659 sdata &= ~(0x20 << (binfo->sensor - 12)); 660 sdata |= (divisor & 0x4) << (binfo->sensor - 9); 661 lm_writereg(sc, WB_BANK0_FANBAT, sdata); 662 } 663 664 memcpy(sc->info[binfo->sensor].desc, binfo->desc, 665 sizeof(sc->info[binfo->sensor].desc)); 666 sc->info[binfo->sensor].desc[ 667 sizeof(sc->info[binfo->sensor].desc) - 1] = '\0'; 668 669 binfo->validflags = ENVSYS_FVALID; 670 } 671 return (0); 672 } 673 674 static void 675 generic_stemp(sc, sensor) 676 struct lm_softc *sc; 677 struct envsys_tre_data *sensor; 678 { 679 int sdata = lm_readreg(sc, LMD_SENSORBASE + 7); 680 DPRINTF(("sdata[temp] 0x%x\n", sdata)); 681 /* temp is given in deg. C, we convert to uK */ 682 sensor->cur.data_us = sdata * 1000000 + 273150000; 683 } 684 685 static void 686 generic_svolt(sc, sensors, infos) 687 struct lm_softc *sc; 688 struct envsys_tre_data *sensors; 689 struct envsys_basic_info *infos; 690 { 691 int i, sdata; 692 693 for (i = 0; i < 7; i++) { 694 sdata = lm_readreg(sc, LMD_SENSORBASE + i); 695 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); 696 /* voltage returned as (mV >> 4), we convert to uVDC */ 697 sensors[i].cur.data_s = (sdata << 4); 698 /* rfact is (factor * 10^4) */ 699 sensors[i].cur.data_s *= infos[i].rfact; 700 /* division by 10 gets us back to uVDC */ 701 sensors[i].cur.data_s /= 10; 702 703 /* these two are negative voltages */ 704 if ( (i == 5) || (i == 6) ) 705 sensors[i].cur.data_s *= -1; 706 } 707 } 708 709 static void 710 generic_fanrpm(sc, sensors) 711 struct lm_softc *sc; 712 struct envsys_tre_data *sensors; 713 { 714 int i, sdata, divisor; 715 for (i = 0; i < 3; i++) { 716 sdata = lm_readreg(sc, LMD_SENSORBASE + 8 + i); 717 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); 718 if (i == 2) 719 divisor = 2; /* Fixed divisor for FAN3 */ 720 else if (i == 1) /* Bits 7 & 6 of VID/FAN */ 721 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 6) & 0x3; 722 else 723 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 4) & 0x3; 724 725 if (sdata == 0xff || sdata == 0x00) { 726 sensors[i].cur.data_us = 0; 727 } else { 728 sensors[i].cur.data_us = 1350000 / (sdata << divisor); 729 } 730 } 731 } 732 733 /* 734 * pre: last read occurred >= 1.5 seconds ago 735 * post: sensors[] current data are the latest from the chip 736 */ 737 void 738 lm_refresh_sensor_data(sc) 739 struct lm_softc *sc; 740 { 741 /* Refresh our stored data for every sensor */ 742 generic_stemp(sc, &sc->sensors[7]); 743 generic_svolt(sc, &sc->sensors[0], &sc->info[0]); 744 generic_fanrpm(sc, &sc->sensors[8]); 745 } 746 747 static void 748 wb_svolt(sc) 749 struct lm_softc *sc; 750 { 751 int i, sdata; 752 for (i = 0; i < 9; ++i) { 753 if (i < 7) { 754 sdata = lm_readreg(sc, LMD_SENSORBASE + i); 755 } else { 756 /* from bank5 */ 757 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B5); 758 sdata = lm_readreg(sc, (i == 7) ? 759 WB_BANK5_5VSB : WB_BANK5_VBAT); 760 } 761 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); 762 /* voltage returned as (mV >> 4), we convert to uV */ 763 sdata = sdata << 4; 764 /* special case for negative voltages */ 765 if (i == 5) { 766 /* 767 * -12Vdc, assume Winbond recommended values for 768 * resistors 769 */ 770 sdata = ((sdata * 1000) - (3600 * 805)) / 195; 771 } else if (i == 6) { 772 /* 773 * -5Vdc, assume Winbond recommended values for 774 * resistors 775 */ 776 sdata = ((sdata * 1000) - (3600 * 682)) / 318; 777 } 778 /* rfact is (factor * 10^4) */ 779 sc->sensors[i].cur.data_s = sdata * sc->info[i].rfact; 780 /* division by 10 gets us back to uVDC */ 781 sc->sensors[i].cur.data_s /= 10; 782 } 783 } 784 785 static void 786 wb_stemp(sc, sensors, n) 787 struct lm_softc *sc; 788 struct envsys_tre_data *sensors; 789 int n; 790 { 791 int sdata; 792 /* temperatures. Given in dC, we convert to uK */ 793 sdata = lm_readreg(sc, LMD_SENSORBASE + 7); 794 DPRINTF(("sdata[temp0] 0x%x\n", sdata)); 795 sensors[0].cur.data_us = sdata * 1000000 + 273150000; 796 /* from bank1 */ 797 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B1); 798 sdata = lm_readreg(sc, WB_BANK1_T2H) << 1; 799 sdata |= (lm_readreg(sc, WB_BANK1_T2L) & 0x80) >> 7; 800 DPRINTF(("sdata[temp1] 0x%x\n", sdata)); 801 sensors[1].cur.data_us = (sdata * 1000000) / 2 + 273150000; 802 if (n < 3) 803 return; 804 /* from bank2 */ 805 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B2); 806 sdata = lm_readreg(sc, WB_BANK2_T3H) << 1; 807 sdata |= (lm_readreg(sc, WB_BANK2_T3L) & 0x80) >> 7; 808 DPRINTF(("sdata[temp2] 0x%x\n", sdata)); 809 sensors[2].cur.data_us = (sdata * 1000000) / 2 + 273150000; 810 } 811 812 static void 813 wb781_fanrpm(sc, sensors) 814 struct lm_softc *sc; 815 struct envsys_tre_data *sensors; 816 { 817 int i, divisor, sdata; 818 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); 819 for (i = 0; i < 3; i++) { 820 sdata = lm_readreg(sc, LMD_SENSORBASE + i + 8); 821 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); 822 if (i == 0) 823 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 4) & 0x3; 824 else if (i == 1) 825 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 6) & 0x3; 826 else 827 divisor = (lm_readreg(sc, WB_PIN) >> 6) & 0x3; 828 829 DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor)); 830 if (sdata == 0xff || sdata == 0x00) { 831 sensors[i].cur.data_us = 0; 832 } else { 833 sensors[i].cur.data_us = 1350000 / 834 (sdata << divisor); 835 } 836 } 837 } 838 839 static void 840 wb_fanrpm(sc, sensors) 841 struct lm_softc *sc; 842 struct envsys_tre_data *sensors; 843 { 844 int i, divisor, sdata; 845 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); 846 for (i = 0; i < 3; i++) { 847 sdata = lm_readreg(sc, LMD_SENSORBASE + i + 8); 848 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); 849 if (i == 0) 850 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 4) & 0x3; 851 else if (i == 1) 852 divisor = (lm_readreg(sc, LMD_VIDFAN) >> 6) & 0x3; 853 else 854 divisor = (lm_readreg(sc, WB_PIN) >> 6) & 0x3; 855 divisor |= (lm_readreg(sc, WB_BANK0_FANBAT) >> (i + 3)) & 0x4; 856 857 DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor)); 858 if (sdata == 0xff || sdata == 0x00) { 859 sensors[i].cur.data_us = 0; 860 } else { 861 sensors[i].cur.data_us = 1350000 / 862 (sdata << divisor); 863 } 864 } 865 } 866 867 void 868 wb781_refresh_sensor_data(sc) 869 struct lm_softc *sc; 870 { 871 /* Refresh our stored data for every sensor */ 872 /* we need to reselect bank0 to access common registers */ 873 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); 874 generic_svolt(sc, &sc->sensors[0], &sc->info[0]); 875 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); 876 wb_stemp(sc, &sc->sensors[7], 3); 877 lm_writereg(sc, WB_BANKSEL, WB_BANKSEL_B0); 878 wb781_fanrpm(sc, &sc->sensors[10]); 879 } 880 881 void 882 wb782_refresh_sensor_data(sc) 883 struct lm_softc *sc; 884 { 885 /* Refresh our stored data for every sensor */ 886 wb_svolt(sc); 887 wb_stemp(sc, &sc->sensors[9], 3); 888 wb_fanrpm(sc, &sc->sensors[12]); 889 } 890 891 void 892 wb697_refresh_sensor_data(sc) 893 struct lm_softc *sc; 894 { 895 /* Refresh our stored data for every sensor */ 896 wb_svolt(sc); 897 wb_stemp(sc, &sc->sensors[9], 2); 898 wb_fanrpm(sc, &sc->sensors[11]); 899 } 900