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