1 /* $NetBSD: nslm7x.c,v 1.24 2005/12/11 12:21:28 christos 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.24 2005/12/11 12:21:28 christos 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 itec_match(struct lm_softc *); 92 int def_match(struct lm_softc *); 93 void lm_common_match(struct lm_softc *); 94 static int lm_generic_banksel(struct lm_softc *, int); 95 96 static void generic_stemp(struct lm_softc *, struct envsys_tre_data *); 97 static void generic_svolt(struct lm_softc *, struct envsys_tre_data *, 98 struct envsys_basic_info *); 99 static void generic_fanrpm(struct lm_softc *, struct envsys_tre_data *); 100 101 void lm_refresh_sensor_data(struct lm_softc *); 102 103 static void wb_svolt(struct lm_softc *); 104 static void wb_stemp(struct lm_softc *, struct envsys_tre_data *, int); 105 static void wb781_fanrpm(struct lm_softc *, struct envsys_tre_data *); 106 static void wb_fanrpm(struct lm_softc *, struct envsys_tre_data *); 107 108 void wb781_refresh_sensor_data(struct lm_softc *); 109 void wb782_refresh_sensor_data(struct lm_softc *); 110 void wb697_refresh_sensor_data(struct lm_softc *); 111 112 static void itec_svolt(struct lm_softc *, struct envsys_tre_data *, 113 struct envsys_basic_info *); 114 static void itec_stemp(struct lm_softc *, struct envsys_tre_data *); 115 static void itec_fanrpm(struct lm_softc *, struct envsys_tre_data *); 116 void itec_refresh_sensor_data(struct lm_softc *); 117 118 int lm_gtredata(struct sysmon_envsys *, struct envsys_tre_data *); 119 120 int generic_streinfo_fan(struct lm_softc *, struct envsys_basic_info *, 121 int, struct envsys_basic_info *); 122 int lm_streinfo(struct sysmon_envsys *, struct envsys_basic_info *); 123 int wb781_streinfo(struct sysmon_envsys *, struct envsys_basic_info *); 124 int wb782_streinfo(struct sysmon_envsys *, struct envsys_basic_info *); 125 int itec_streinfo(struct sysmon_envsys *, struct envsys_basic_info *); 126 127 struct lm_chip { 128 int (*chip_match)(struct lm_softc *); 129 }; 130 131 struct lm_chip lm_chips[] = { 132 { itec_match }, 133 { wb_match }, 134 { lm_match }, 135 { def_match } /* Must be last */ 136 }; 137 138 139 int 140 lm_generic_banksel(lmsc, bank) 141 struct lm_softc *lmsc; 142 int bank; 143 { 144 145 (*lmsc->lm_writereg)(lmsc, WB_BANKSEL, bank); 146 return 0; 147 } 148 149 150 /* 151 * bus independent probe 152 */ 153 int 154 lm_probe(iot, ioh) 155 bus_space_tag_t iot; 156 bus_space_handle_t ioh; 157 { 158 u_int8_t cr; 159 int rv; 160 161 /* 162 * Check for it8705f, before we do the chip reset. 163 * In case of an it8705f this might reset all the fan control 164 * parameters to defaults which would void all settings done by 165 * the BOOTROM/BIOS. 166 */ 167 bus_space_write_1(iot, ioh, LMC_ADDR, ITEC_RES48); 168 cr = bus_space_read_1(iot, ioh, LMC_DATA); 169 170 if (cr == ITEC_RES48_DEFAULT) { 171 bus_space_write_1(iot, ioh, LMC_ADDR, ITEC_RES52); 172 cr = bus_space_read_1(iot, ioh, LMC_DATA); 173 if (cr == ITEC_RES52_DEFAULT) 174 return 1; 175 } 176 177 /* Check for some power-on defaults */ 178 bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG); 179 180 /* Perform LM78 reset */ 181 bus_space_write_1(iot, ioh, LMC_DATA, 0x80); 182 183 /* XXX - Why do I have to reselect the register? */ 184 bus_space_write_1(iot, ioh, LMC_ADDR, LMD_CONFIG); 185 cr = bus_space_read_1(iot, ioh, LMC_DATA); 186 187 /* XXX - spec says *only* 0x08! */ 188 if ((cr == 0x08) || (cr == 0x01) || (cr == 0x03)) 189 rv = 1; 190 else 191 rv = 0; 192 193 DPRINTF(("lm: rv = %d, cr = %x\n", rv, cr)); 194 195 return (rv); 196 } 197 198 199 /* 200 * pre: lmsc contains valid busspace tag and handle 201 */ 202 void 203 lm_attach(lmsc) 204 struct lm_softc *lmsc; 205 { 206 u_int i; 207 208 /* Install default bank selection routine, if none given. */ 209 if (lmsc->lm_banksel == NULL) 210 lmsc->lm_banksel = lm_generic_banksel; 211 212 for (i = 0; i < sizeof(lm_chips) / sizeof(lm_chips[0]); i++) 213 if (lm_chips[i].chip_match(lmsc)) 214 break; 215 216 /* Start the monitoring loop */ 217 (*lmsc->lm_writereg)(lmsc, LMD_CONFIG, 0x01); 218 219 /* Indicate we have never read the registers */ 220 timerclear(&lmsc->lastread); 221 222 /* Initialize sensors */ 223 for (i = 0; i < lmsc->numsensors; ++i) { 224 lmsc->sensors[i].sensor = lmsc->info[i].sensor = i; 225 lmsc->sensors[i].validflags = (ENVSYS_FVALID|ENVSYS_FCURVALID); 226 lmsc->info[i].validflags = ENVSYS_FVALID; 227 lmsc->sensors[i].warnflags = ENVSYS_WARN_OK; 228 } 229 /* 230 * Hook into the System Monitor. 231 */ 232 lmsc->sc_sysmon.sme_ranges = lm_ranges; 233 lmsc->sc_sysmon.sme_sensor_info = lmsc->info; 234 lmsc->sc_sysmon.sme_sensor_data = lmsc->sensors; 235 lmsc->sc_sysmon.sme_cookie = lmsc; 236 237 lmsc->sc_sysmon.sme_gtredata = lm_gtredata; 238 /* sme_streinfo set in chip-specific attach */ 239 240 lmsc->sc_sysmon.sme_nsensors = lmsc->numsensors; 241 lmsc->sc_sysmon.sme_envsys_version = 1000; 242 243 if (sysmon_envsys_register(&lmsc->sc_sysmon)) 244 printf("%s: unable to register with sysmon\n", 245 lmsc->sc_dev.dv_xname); 246 } 247 248 int 249 lm_match(sc) 250 struct lm_softc *sc; 251 { 252 int i; 253 254 /* See if we have an LM78 or LM79 */ 255 i = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK; 256 switch(i) { 257 case LM_ID_LM78: 258 printf(": LM78\n"); 259 break; 260 case LM_ID_LM78J: 261 printf(": LM78J\n"); 262 break; 263 case LM_ID_LM79: 264 printf(": LM79\n"); 265 break; 266 case LM_ID_LM81: 267 printf(": LM81\n"); 268 break; 269 default: 270 return 0; 271 } 272 lm_common_match(sc); 273 return 1; 274 } 275 276 int 277 def_match(sc) 278 struct lm_softc *sc; 279 { 280 int i; 281 282 i = (*sc->lm_readreg)(sc, LMD_CHIPID) & LM_ID_MASK; 283 printf(": Unknown chip (ID %d)\n", i); 284 lm_common_match(sc); 285 return 1; 286 } 287 288 void 289 lm_common_match(sc) 290 struct lm_softc *sc; 291 { 292 int i; 293 sc->numsensors = LM_NUM_SENSORS; 294 sc->refresh_sensor_data = lm_refresh_sensor_data; 295 296 for (i = 0; i < 7; ++i) { 297 sc->sensors[i].units = sc->info[i].units = 298 ENVSYS_SVOLTS_DC; 299 snprintf(sc->info[i].desc, sizeof(sc->info[i].desc), 300 "IN %d", i); 301 } 302 303 /* default correction factors for resistors on higher voltage inputs */ 304 sc->info[0].rfact = sc->info[1].rfact = 305 sc->info[2].rfact = 10000; 306 sc->info[3].rfact = (int)(( 90.9 / 60.4) * 10000); 307 sc->info[4].rfact = (int)(( 38.0 / 10.0) * 10000); 308 sc->info[5].rfact = (int)((210.0 / 60.4) * 10000); 309 sc->info[6].rfact = (int)(( 90.9 / 60.4) * 10000); 310 311 sc->sensors[7].units = ENVSYS_STEMP; 312 strcpy(sc->info[7].desc, "Temp"); 313 314 setup_fan(sc, 8, 3); 315 sc->sc_sysmon.sme_streinfo = lm_streinfo; 316 } 317 318 int 319 wb_match(sc) 320 struct lm_softc *sc; 321 { 322 int i, j; 323 324 (*sc->lm_writereg)(sc, WB_BANKSEL, WB_BANKSEL_HBAC); 325 j = (*sc->lm_readreg)(sc, WB_VENDID) << 8; 326 (*sc->lm_writereg)(sc, WB_BANKSEL, 0); 327 j |= (*sc->lm_readreg)(sc, WB_VENDID); 328 DPRINTF(("winbond vend id 0x%x\n", j)); 329 if (j != WB_VENDID_WINBOND) 330 return 0; 331 /* read device ID */ 332 (*sc->lm_banksel)(sc, 0); 333 j = (*sc->lm_readreg)(sc, WB_BANK0_CHIPID); 334 DPRINTF(("winbond chip id 0x%x\n", j)); 335 switch(j) { 336 case WB_CHIPID_83781: 337 case WB_CHIPID_83781_2: 338 printf(": W83781D\n"); 339 340 for (i = 0; i < 7; ++i) { 341 sc->sensors[i].units = sc->info[i].units = 342 ENVSYS_SVOLTS_DC; 343 snprintf(sc->info[i].desc, sizeof(sc->info[i].desc), 344 "IN %d", i); 345 } 346 347 /* default correction factors for higher voltage inputs */ 348 sc->info[0].rfact = sc->info[1].rfact = 349 sc->info[2].rfact = 10000; 350 sc->info[3].rfact = (int)(( 90.9 / 60.4) * 10000); 351 sc->info[4].rfact = (int)(( 38.0 / 10.0) * 10000); 352 sc->info[5].rfact = (int)((210.0 / 60.4) * 10000); 353 sc->info[6].rfact = (int)(( 90.9 / 60.4) * 10000); 354 355 setup_temp(sc, 7, 3); 356 setup_fan(sc, 10, 3); 357 358 sc->numsensors = WB83781_NUM_SENSORS; 359 sc->refresh_sensor_data = wb781_refresh_sensor_data; 360 sc->sc_sysmon.sme_streinfo = wb781_streinfo; 361 return 1; 362 case WB_CHIPID_83697: 363 printf(": W83697HF\n"); 364 wb_setup_volt(sc); 365 setup_temp(sc, 9, 2); 366 setup_fan(sc, 11, 3); 367 sc->numsensors = WB83697_NUM_SENSORS; 368 sc->refresh_sensor_data = wb697_refresh_sensor_data; 369 sc->sc_sysmon.sme_streinfo = wb782_streinfo; 370 return 1; 371 case WB_CHIPID_83782: 372 printf(": W83782D\n"); 373 break; 374 case WB_CHIPID_83627: 375 printf(": W83627HF\n"); 376 break; 377 case WB_CHIPID_83627THF: 378 printf(": W83627THF\n"); 379 break; 380 default: 381 printf(": unknow winbond chip ID 0x%x\n", j); 382 /* handle as a standart lm7x */ 383 lm_common_match(sc); 384 return 1; 385 } 386 /* common code for the W83782D and W83627HF */ 387 wb_setup_volt(sc); 388 setup_temp(sc, 9, 3); 389 setup_fan(sc, 12, 3); 390 sc->numsensors = WB_NUM_SENSORS; 391 sc->refresh_sensor_data = wb782_refresh_sensor_data; 392 sc->sc_sysmon.sme_streinfo = wb782_streinfo; 393 return 1; 394 } 395 396 static void 397 wb_setup_volt(sc) 398 struct lm_softc *sc; 399 { 400 sc->sensors[0].units = sc->info[0].units = ENVSYS_SVOLTS_DC; 401 snprintf(sc->info[0].desc, sizeof(sc->info[0].desc), "VCORE A"); 402 sc->info[0].rfact = 10000; 403 sc->sensors[1].units = sc->info[1].units = ENVSYS_SVOLTS_DC; 404 snprintf(sc->info[1].desc, sizeof(sc->info[1].desc), "VCORE B"); 405 sc->info[1].rfact = 10000; 406 sc->sensors[2].units = sc->info[2].units = ENVSYS_SVOLTS_DC; 407 snprintf(sc->info[2].desc, sizeof(sc->info[2].desc), "+3.3V"); 408 sc->info[2].rfact = 10000; 409 sc->sensors[3].units = sc->info[3].units = ENVSYS_SVOLTS_DC; 410 snprintf(sc->info[3].desc, sizeof(sc->info[3].desc), "+5V"); 411 sc->info[3].rfact = 16778; 412 sc->sensors[4].units = sc->info[4].units = ENVSYS_SVOLTS_DC; 413 snprintf(sc->info[4].desc, sizeof(sc->info[4].desc), "+12V"); 414 sc->info[4].rfact = 38000; 415 sc->sensors[5].units = sc->info[5].units = ENVSYS_SVOLTS_DC; 416 snprintf(sc->info[5].desc, sizeof(sc->info[5].desc), "-12V"); 417 sc->info[5].rfact = 10000; 418 sc->sensors[6].units = sc->info[6].units = ENVSYS_SVOLTS_DC; 419 snprintf(sc->info[6].desc, sizeof(sc->info[6].desc), "-5V"); 420 sc->info[6].rfact = 10000; 421 sc->sensors[7].units = sc->info[7].units = ENVSYS_SVOLTS_DC; 422 snprintf(sc->info[7].desc, sizeof(sc->info[7].desc), "+5VSB"); 423 sc->info[7].rfact = 15151; 424 sc->sensors[8].units = sc->info[8].units = ENVSYS_SVOLTS_DC; 425 snprintf(sc->info[8].desc, sizeof(sc->info[8].desc), "VBAT"); 426 sc->info[8].rfact = 10000; 427 } 428 429 int 430 itec_match(sc) 431 struct lm_softc *sc; 432 { 433 int vendor, coreid; 434 435 /* do the same thing as in lm_probe() */ 436 if ((*sc->lm_readreg)(sc, ITEC_RES48) != ITEC_RES48_DEFAULT) 437 return 0; 438 439 if ((*sc->lm_readreg)(sc, ITEC_RES52) != ITEC_RES52_DEFAULT) 440 return 0; 441 442 /* We check for the core ID register (0x5B), which is available 443 * only in the 8712F, if that fails, we check the vendor ID 444 * register, available on 8705F and 8712F */ 445 446 coreid = (*sc->lm_readreg)(sc, ITEC_COREID); 447 448 if (coreid == ITEC_COREID_ITE) 449 printf(": ITE8712F\n"); 450 else { 451 vendor = (*sc->lm_readreg)(sc, ITEC_VENDID); 452 if (vendor == ITEC_VENDID_ITE) 453 printf(": ITE8705F\n"); 454 else 455 printf(": unknown ITE87%02x compatible\n", vendor); 456 } 457 458 /* 459 * XXX this is a litle bit lame... 460 * All VIN inputs work exactly the same way, it depends of the 461 * external wiring what voltages they monitor and which correction 462 * factors are needed. We assume a pretty standard setup here 463 */ 464 wb_setup_volt(sc); 465 strlcpy(sc->info[0].desc, "CPU", sizeof(sc->info[0].desc)); 466 strlcpy(sc->info[1].desc, "AGP", sizeof(sc->info[1].desc)); 467 strlcpy(sc->info[6].desc, "+2.5V", sizeof(sc->info[6].desc)); 468 sc->info[5].rfact = 51100; 469 sc->info[7].rfact = 16778; 470 471 setup_temp(sc, 9, 3); 472 setup_fan(sc, 12, 3); 473 sc->numsensors = ITEC_NUM_SENSORS; 474 sc->refresh_sensor_data = itec_refresh_sensor_data; 475 sc->sc_sysmon.sme_streinfo = itec_streinfo; 476 477 return 1; 478 } 479 480 481 static void 482 setup_temp(sc, start, n) 483 struct lm_softc *sc; 484 int start, n; 485 { 486 int i; 487 488 for (i = 0; i < n; i++) { 489 sc->sensors[start + i].units = ENVSYS_STEMP; 490 snprintf(sc->info[start + i].desc, 491 sizeof(sc->info[start + i].desc), "Temp %d", i + 1); 492 } 493 } 494 495 496 static void 497 setup_fan(sc, start, n) 498 struct lm_softc *sc; 499 int start, n; 500 { 501 int i; 502 for (i = 0; i < n; ++i) { 503 sc->sensors[start + i].units = ENVSYS_SFANRPM; 504 sc->info[start + i].units = ENVSYS_SFANRPM; 505 snprintf(sc->info[start + i].desc, 506 sizeof(sc->info[start + i].desc), "Fan %d", i + 1); 507 } 508 } 509 510 int 511 lm_gtredata(sme, tred) 512 struct sysmon_envsys *sme; 513 struct envsys_tre_data *tred; 514 { 515 static const struct timeval onepointfive = { 1, 500000 }; 516 struct timeval t; 517 struct lm_softc *sc = sme->sme_cookie; 518 int i, s; 519 520 /* read new values at most once every 1.5 seconds */ 521 timeradd(&sc->lastread, &onepointfive, &t); 522 s = splclock(); 523 i = timercmp(&mono_time, &t, >); 524 if (i) { 525 sc->lastread.tv_sec = mono_time.tv_sec; 526 sc->lastread.tv_usec = mono_time.tv_usec; 527 } 528 splx(s); 529 530 if (i) 531 sc->refresh_sensor_data(sc); 532 533 *tred = sc->sensors[tred->sensor]; 534 535 return 0; 536 } 537 538 int 539 generic_streinfo_fan(sc, info, n, binfo) 540 struct lm_softc *sc; 541 struct envsys_basic_info *info; 542 int n; 543 struct envsys_basic_info *binfo; 544 { 545 u_int8_t sdata; 546 int divisor; 547 548 /* FAN1 and FAN2 can have divisors set, but not FAN3 */ 549 if ((sc->info[binfo->sensor].units == ENVSYS_SFANRPM) 550 && (n < 2)) { 551 if (binfo->rpms == 0) { 552 binfo->validflags = 0; 553 return 0; 554 } 555 556 /* write back the nominal FAN speed */ 557 info->rpms = binfo->rpms; 558 559 /* 153 is the nominal FAN speed value */ 560 divisor = 1350000 / (binfo->rpms * 153); 561 562 /* ...but we need lg(divisor) */ 563 if (divisor <= 1) 564 divisor = 0; 565 else if (divisor <= 2) 566 divisor = 1; 567 else if (divisor <= 4) 568 divisor = 2; 569 else 570 divisor = 3; 571 572 /* 573 * FAN1 div is in bits <5:4>, FAN2 div is 574 * in <7:6> 575 */ 576 sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN); 577 if ( n == 0 ) { /* FAN1 */ 578 divisor <<= 4; 579 sdata = (sdata & 0xCF) | divisor; 580 } else { /* FAN2 */ 581 divisor <<= 6; 582 sdata = (sdata & 0x3F) | divisor; 583 } 584 585 (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata); 586 } 587 return 0; 588 589 } 590 591 int 592 lm_streinfo(sme, binfo) 593 struct sysmon_envsys *sme; 594 struct envsys_basic_info *binfo; 595 { 596 struct lm_softc *sc = sme->sme_cookie; 597 598 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC) 599 sc->info[binfo->sensor].rfact = binfo->rfact; 600 else { 601 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) { 602 generic_streinfo_fan(sc, &sc->info[binfo->sensor], 603 binfo->sensor - 8, binfo); 604 } 605 strlcpy(sc->info[binfo->sensor].desc, binfo->desc, 606 sizeof(sc->info[binfo->sensor].desc)); 607 binfo->validflags = ENVSYS_FVALID; 608 } 609 return 0; 610 } 611 612 int 613 wb781_streinfo(sme, binfo) 614 struct sysmon_envsys *sme; 615 struct envsys_basic_info *binfo; 616 { 617 struct lm_softc *sc = sme->sme_cookie; 618 int divisor; 619 u_int8_t sdata; 620 int i; 621 622 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC) 623 sc->info[binfo->sensor].rfact = binfo->rfact; 624 else { 625 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) { 626 if (binfo->rpms == 0) { 627 binfo->validflags = 0; 628 return 0; 629 } 630 631 /* write back the nominal FAN speed */ 632 sc->info[binfo->sensor].rpms = binfo->rpms; 633 634 /* 153 is the nominal FAN speed value */ 635 divisor = 1350000 / (binfo->rpms * 153); 636 637 /* ...but we need lg(divisor) */ 638 for (i = 0; i < 7; i++) { 639 if (divisor <= (1 << i)) 640 break; 641 } 642 divisor = i; 643 644 if (binfo->sensor == 10 || binfo->sensor == 11) { 645 /* 646 * FAN1 div is in bits <5:4>, FAN2 div 647 * is in <7:6> 648 */ 649 sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN); 650 if ( binfo->sensor == 10 ) { /* FAN1 */ 651 sdata = (sdata & 0xCF) | 652 ((divisor & 0x3) << 4); 653 } else { /* FAN2 */ 654 sdata = (sdata & 0x3F) | 655 ((divisor & 0x3) << 6); 656 } 657 (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata); 658 } else { 659 /* FAN3 is in WB_PIN <7:6> */ 660 sdata = (*sc->lm_readreg)(sc, WB_PIN); 661 sdata = (sdata & 0x3F) | 662 ((divisor & 0x3) << 6); 663 (*sc->lm_writereg)(sc, WB_PIN, sdata); 664 } 665 } 666 strlcpy(sc->info[binfo->sensor].desc, binfo->desc, 667 sizeof(sc->info[binfo->sensor].desc)); 668 binfo->validflags = ENVSYS_FVALID; 669 } 670 return 0; 671 } 672 673 int 674 wb782_streinfo(sme, binfo) 675 struct sysmon_envsys *sme; 676 struct envsys_basic_info *binfo; 677 { 678 struct lm_softc *sc = sme->sme_cookie; 679 int divisor; 680 u_int8_t sdata; 681 int i; 682 683 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC) 684 sc->info[binfo->sensor].rfact = binfo->rfact; 685 else { 686 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) { 687 if (binfo->rpms == 0) { 688 binfo->validflags = 0; 689 return 0; 690 } 691 692 /* write back the nominal FAN speed */ 693 sc->info[binfo->sensor].rpms = binfo->rpms; 694 695 /* 153 is the nominal FAN speed value */ 696 divisor = 1350000 / (binfo->rpms * 153); 697 698 /* ...but we need lg(divisor) */ 699 for (i = 0; i < 7; i++) { 700 if (divisor <= (1 << i)) 701 break; 702 } 703 divisor = i; 704 705 if (binfo->sensor == 12 || binfo->sensor == 13) { 706 /* 707 * FAN1 div is in bits <5:4>, FAN2 div 708 * is in <7:6> 709 */ 710 sdata = (*sc->lm_readreg)(sc, LMD_VIDFAN); 711 if ( binfo->sensor == 12 ) { /* FAN1 */ 712 sdata = (sdata & 0xCF) | 713 ((divisor & 0x3) << 4); 714 } else { /* FAN2 */ 715 sdata = (sdata & 0x3F) | 716 ((divisor & 0x3) << 6); 717 } 718 (*sc->lm_writereg)(sc, LMD_VIDFAN, sdata); 719 } else { 720 /* FAN3 is in WB_PIN <7:6> */ 721 sdata = (*sc->lm_readreg)(sc, WB_PIN); 722 sdata = (sdata & 0x3F) | 723 ((divisor & 0x3) << 6); 724 (*sc->lm_writereg)(sc, WB_PIN, sdata); 725 } 726 /* Bit 2 of divisor is in WB_BANK0_FANBAT */ 727 (*sc->lm_banksel)(sc, 0); 728 sdata = (*sc->lm_readreg)(sc, WB_BANK0_FANBAT); 729 sdata &= ~(0x20 << (binfo->sensor - 12)); 730 sdata |= (divisor & 0x4) << (binfo->sensor - 9); 731 (*sc->lm_writereg)(sc, WB_BANK0_FANBAT, sdata); 732 } 733 734 strlcpy(sc->info[binfo->sensor].desc, binfo->desc, 735 sizeof(sc->info[binfo->sensor].desc)); 736 binfo->validflags = ENVSYS_FVALID; 737 } 738 return 0; 739 } 740 741 int 742 itec_streinfo(sme, binfo) 743 struct sysmon_envsys *sme; 744 struct envsys_basic_info *binfo; 745 { 746 struct lm_softc *sc = sme->sme_cookie; 747 int divisor; 748 u_int8_t sdata; 749 int i; 750 751 if (sc->info[binfo->sensor].units == ENVSYS_SVOLTS_DC) 752 sc->info[binfo->sensor].rfact = binfo->rfact; 753 else { 754 if (sc->info[binfo->sensor].units == ENVSYS_SFANRPM) { 755 if (binfo->rpms == 0) { 756 binfo->validflags = 0; 757 return 0; 758 } 759 760 /* write back the nominal FAN speed */ 761 sc->info[binfo->sensor].rpms = binfo->rpms; 762 763 /* 153 is the nominal FAN speed value */ 764 divisor = 1350000 / (binfo->rpms * 153); 765 766 /* ...but we need lg(divisor) */ 767 for (i = 0; i < 7; i++) { 768 if (divisor <= (1 << i)) 769 break; 770 } 771 divisor = i; 772 773 sdata = (*sc->lm_readreg)(sc, ITEC_FANDIV); 774 /* 775 * FAN1 div is in bits <0:2>, FAN2 is in <3:5> 776 * FAN3 is in <6>, if set divisor is 8, else 2 777 */ 778 if ( binfo->sensor == 10 ) { /* FAN1 */ 779 sdata = (sdata & 0xf8) | divisor; 780 } else if ( binfo->sensor == 11 ) { /* FAN2 */ 781 sdata = (sdata & 0xc7) | divisor << 3; 782 } else { /* FAN3 */ 783 if (divisor>2) 784 sdata = sdata & 0xbf; 785 else 786 sdata = sdata | 0x40; 787 } 788 (*sc->lm_writereg)(sc, ITEC_FANDIV, sdata); 789 } 790 strlcpy(sc->info[binfo->sensor].desc, binfo->desc, 791 sizeof(sc->info[binfo->sensor].desc)); 792 binfo->validflags = ENVSYS_FVALID; 793 } 794 return 0; 795 } 796 797 static void 798 generic_stemp(sc, sensor) 799 struct lm_softc *sc; 800 struct envsys_tre_data *sensor; 801 { 802 int sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 7); 803 DPRINTF(("sdata[temp] 0x%x\n", sdata)); 804 /* temp is given in deg. C, we convert to uK */ 805 sensor->cur.data_us = sdata * 1000000 + 273150000; 806 } 807 808 static void 809 generic_svolt(sc, sensors, infos) 810 struct lm_softc *sc; 811 struct envsys_tre_data *sensors; 812 struct envsys_basic_info *infos; 813 { 814 int i, sdata; 815 816 for (i = 0; i < 7; i++) { 817 sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i); 818 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); 819 /* voltage returned as (mV >> 4), we convert to uVDC */ 820 sensors[i].cur.data_s = (sdata << 4); 821 /* rfact is (factor * 10^4) */ 822 sensors[i].cur.data_s *= infos[i].rfact; 823 /* division by 10 gets us back to uVDC */ 824 sensors[i].cur.data_s /= 10; 825 826 /* these two are negative voltages */ 827 if ( (i == 5) || (i == 6) ) 828 sensors[i].cur.data_s *= -1; 829 } 830 } 831 832 static void 833 generic_fanrpm(sc, sensors) 834 struct lm_softc *sc; 835 struct envsys_tre_data *sensors; 836 { 837 int i, sdata, divisor; 838 for (i = 0; i < 3; i++) { 839 sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 8 + i); 840 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); 841 if (i == 2) 842 divisor = 2; /* Fixed divisor for FAN3 */ 843 else if (i == 1) /* Bits 7 & 6 of VID/FAN */ 844 divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 6) & 0x3; 845 else 846 divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 4) & 0x3; 847 848 if (sdata == 0xff || sdata == 0x00) { 849 sensors[i].cur.data_us = 0; 850 } else { 851 sensors[i].cur.data_us = 1350000 / (sdata << divisor); 852 } 853 } 854 } 855 856 /* 857 * pre: last read occurred >= 1.5 seconds ago 858 * post: sensors[] current data are the latest from the chip 859 */ 860 void 861 lm_refresh_sensor_data(sc) 862 struct lm_softc *sc; 863 { 864 /* Refresh our stored data for every sensor */ 865 generic_stemp(sc, &sc->sensors[7]); 866 generic_svolt(sc, &sc->sensors[0], &sc->info[0]); 867 generic_fanrpm(sc, &sc->sensors[8]); 868 } 869 870 static void 871 wb_svolt(sc) 872 struct lm_softc *sc; 873 { 874 int i, sdata; 875 for (i = 0; i < 9; ++i) { 876 if (i < 7) { 877 sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i); 878 } else { 879 /* from bank5 */ 880 (*sc->lm_banksel)(sc, 5); 881 sdata = (*sc->lm_readreg)(sc, (i == 7) ? 882 WB_BANK5_5VSB : WB_BANK5_VBAT); 883 } 884 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); 885 /* voltage returned as (mV >> 4), we convert to uV */ 886 sdata = sdata << 4; 887 /* special case for negative voltages */ 888 if (i == 5) { 889 /* 890 * -12Vdc, assume Winbond recommended values for 891 * resistors 892 */ 893 sdata = ((sdata * 1000) - (3600 * 805)) / 195; 894 } else if (i == 6) { 895 /* 896 * -5Vdc, assume Winbond recommended values for 897 * resistors 898 */ 899 sdata = ((sdata * 1000) - (3600 * 682)) / 318; 900 } 901 /* rfact is (factor * 10^4) */ 902 sc->sensors[i].cur.data_s = sdata * sc->info[i].rfact; 903 /* division by 10 gets us back to uVDC */ 904 sc->sensors[i].cur.data_s /= 10; 905 } 906 } 907 908 static void 909 wb_stemp(sc, sensors, n) 910 struct lm_softc *sc; 911 struct envsys_tre_data *sensors; 912 int n; 913 { 914 int sdata; 915 /* temperatures. Given in dC, we convert to uK */ 916 sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + 7); 917 DPRINTF(("sdata[temp0] 0x%x\n", sdata)); 918 sensors[0].cur.data_us = sdata * 1000000 + 273150000; 919 /* from bank1 */ 920 if ((*sc->lm_banksel)(sc, 1)) 921 sensors[1].validflags &= ~ENVSYS_FCURVALID; 922 else { 923 sdata = (*sc->lm_readreg)(sc, WB_BANK1_T2H) << 1; 924 sdata |= ((*sc->lm_readreg)(sc, WB_BANK1_T2L) & 0x80) >> 7; 925 DPRINTF(("sdata[temp1] 0x%x\n", sdata)); 926 sensors[1].cur.data_us = (sdata * 1000000) / 2 + 273150000; 927 } 928 if (n < 3) 929 return; 930 /* from bank2 */ 931 if ((*sc->lm_banksel)(sc, 2)) 932 sensors[2].validflags &= ~ENVSYS_FCURVALID; 933 else { 934 sdata = (*sc->lm_readreg)(sc, WB_BANK2_T3H) << 1; 935 sdata |= ((*sc->lm_readreg)(sc, WB_BANK2_T3L) & 0x80) >> 7; 936 DPRINTF(("sdata[temp2] 0x%x\n", sdata)); 937 sensors[2].cur.data_us = (sdata * 1000000) / 2 + 273150000; 938 } 939 } 940 941 static void 942 wb781_fanrpm(sc, sensors) 943 struct lm_softc *sc; 944 struct envsys_tre_data *sensors; 945 { 946 int i, divisor, sdata; 947 (*sc->lm_banksel)(sc, 0); 948 for (i = 0; i < 3; i++) { 949 sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i + 8); 950 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); 951 if (i == 0) 952 divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 4) & 0x3; 953 else if (i == 1) 954 divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 6) & 0x3; 955 else 956 divisor = ((*sc->lm_readreg)(sc, WB_PIN) >> 6) & 0x3; 957 958 DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor)); 959 if (sdata == 0xff || sdata == 0x00) { 960 sensors[i].cur.data_us = 0; 961 } else { 962 sensors[i].cur.data_us = 1350000 / 963 (sdata << divisor); 964 } 965 } 966 } 967 968 static void 969 wb_fanrpm(sc, sensors) 970 struct lm_softc *sc; 971 struct envsys_tre_data *sensors; 972 { 973 int i, divisor, sdata; 974 (*sc->lm_banksel)(sc, 0); 975 for (i = 0; i < 3; i++) { 976 sdata = (*sc->lm_readreg)(sc, LMD_SENSORBASE + i + 8); 977 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); 978 if (i == 0) 979 divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 4) & 0x3; 980 else if (i == 1) 981 divisor = ((*sc->lm_readreg)(sc, LMD_VIDFAN) >> 6) & 0x3; 982 else 983 divisor = ((*sc->lm_readreg)(sc, WB_PIN) >> 6) & 0x3; 984 divisor |= ((*sc->lm_readreg)(sc, WB_BANK0_FANBAT) >> (i + 3)) & 0x4; 985 986 DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor)); 987 if (sdata == 0xff || sdata == 0x00) { 988 sensors[i].cur.data_us = 0; 989 } else { 990 sensors[i].cur.data_us = 1350000 / 991 (sdata << divisor); 992 } 993 } 994 } 995 996 void 997 wb781_refresh_sensor_data(sc) 998 struct lm_softc *sc; 999 { 1000 /* Refresh our stored data for every sensor */ 1001 /* we need to reselect bank0 to access common registers */ 1002 (*sc->lm_banksel)(sc, 0); 1003 generic_svolt(sc, &sc->sensors[0], &sc->info[0]); 1004 (*sc->lm_banksel)(sc, 0); 1005 wb_stemp(sc, &sc->sensors[7], 3); 1006 (*sc->lm_banksel)(sc, 0); 1007 wb781_fanrpm(sc, &sc->sensors[10]); 1008 } 1009 1010 void 1011 wb782_refresh_sensor_data(sc) 1012 struct lm_softc *sc; 1013 { 1014 /* Refresh our stored data for every sensor */ 1015 wb_svolt(sc); 1016 wb_stemp(sc, &sc->sensors[9], 3); 1017 wb_fanrpm(sc, &sc->sensors[12]); 1018 } 1019 1020 void 1021 wb697_refresh_sensor_data(sc) 1022 struct lm_softc *sc; 1023 { 1024 /* Refresh our stored data for every sensor */ 1025 wb_svolt(sc); 1026 wb_stemp(sc, &sc->sensors[9], 2); 1027 wb_fanrpm(sc, &sc->sensors[11]); 1028 } 1029 1030 static void 1031 itec_svolt(sc, sensors, infos) 1032 struct lm_softc *sc; 1033 struct envsys_tre_data *sensors; 1034 struct envsys_basic_info *infos; 1035 { 1036 int i, sdata; 1037 1038 for (i = 0; i < 9; i++) { 1039 sdata = (*sc->lm_readreg)(sc, ITEC_VIN0 + i); 1040 DPRINTF(("sdata[volt%d] 0x%x\n", i, sdata)); 1041 /* voltage returned as (mV >> 4), we convert to uVDC */ 1042 sensors[i].cur.data_s = ( sdata << 4 ); 1043 /* rfact is (factor * 10^4) */ 1044 1045 sensors[i].cur.data_s *= infos[i].rfact; 1046 /* 1047 * XXX We assume input 5 is wired the way iTE suggests to 1048 * monitor a negative voltage. I'd prefer using negative rfacts 1049 * for detecting those cases but since rfact is an u_int this 1050 * isn't possible. 1051 */ 1052 if (i == 5) 1053 sensors[i].cur.data_s -= 1054 (infos[i].rfact - 10000) * ITEC_VREF; 1055 /* division by 10 gets us back to uVDC */ 1056 sensors[i].cur.data_s /= 10; 1057 } 1058 } 1059 1060 static void 1061 itec_stemp(sc, sensors) 1062 struct lm_softc *sc; 1063 struct envsys_tre_data *sensors; 1064 { 1065 int i, sdata; 1066 1067 /* temperatures. Given in dC, we convert to uK */ 1068 for (i = 0; i < 3; i++) { 1069 sdata = (*sc->lm_readreg)(sc, ITEC_TEMP1 + i); 1070 DPRINTF(("sdata[temp%d] 0x%x\n",i, sdata)); 1071 sensors[i].cur.data_us = sdata * 1000000 + 273150000; 1072 } 1073 } 1074 1075 static void 1076 itec_fanrpm(sc, sensors) 1077 struct lm_softc *sc; 1078 struct envsys_tre_data *sensors; 1079 { 1080 int i, fandiv, divisor, sdata; 1081 (*sc->lm_banksel)(sc, 0); 1082 fandiv = ((*sc->lm_readreg)(sc, ITEC_FANDIV)); 1083 1084 for (i = 0; i < 3; i++) { 1085 sdata = (*sc->lm_readreg)(sc, ITEC_FAN1 + i); 1086 DPRINTF(("sdata[fan%d] 0x%x\n", i, sdata)); 1087 switch (i) { 1088 case 0: 1089 divisor = fandiv & 0x7; 1090 break; 1091 case 1: 1092 divisor = (fandiv >> 3) & 0x7; 1093 break; 1094 case 2: 1095 default: /* XXX */ 1096 divisor = (fandiv & 0x40) ? 3 : 1; 1097 break; 1098 } 1099 DPRINTF(("sdata[%d] 0x%x div 0x%x\n", i, sdata, divisor)); 1100 if (sdata == 0xff || sdata == 0x00) { 1101 sensors[i].cur.data_us = 0; 1102 } else { 1103 sensors[i].cur.data_us = 1350000 / 1104 (sdata << divisor); 1105 } 1106 } 1107 1108 } 1109 1110 void 1111 itec_refresh_sensor_data(sc) 1112 struct lm_softc *sc; 1113 { 1114 itec_svolt(sc, &sc->sensors[0], &sc->info[0]); 1115 itec_stemp(sc, &sc->sensors[9]); 1116 itec_fanrpm(sc, &sc->sensors[12]); 1117 } 1118