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