1 /* $NetBSD: lm75.c,v 1.30 2017/10/01 05:12:18 macallan Exp $ */ 2 3 /* 4 * Copyright (c) 2003 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __KERNEL_RCSID(0, "$NetBSD: lm75.c,v 1.30 2017/10/01 05:12:18 macallan Exp $"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/device.h> 44 #include <sys/kernel.h> 45 #include <sys/sysctl.h> 46 47 #include <dev/sysmon/sysmonvar.h> 48 49 #include <dev/i2c/i2cvar.h> 50 #include <dev/i2c/lm75reg.h> 51 52 #ifdef macppc 53 #define HAVE_OF 1 54 #endif 55 56 #ifdef HAVE_OF 57 #include <dev/ofw/openfirm.h> 58 #endif 59 60 struct lmtemp_softc { 61 device_t sc_dev; 62 i2c_tag_t sc_tag; 63 int sc_address; 64 65 struct sysmon_envsys *sc_sme; 66 envsys_data_t sc_sensor; 67 int sc_tmax; 68 uint32_t sc_smax, sc_smin, sc_scrit; 69 70 uint32_t (*sc_lmtemp_decode)(const uint8_t *, int); 71 void (*sc_lmtemp_encode)(const uint32_t, uint8_t *, int); 72 }; 73 74 static int lmtemp_match(device_t, cfdata_t, void *); 75 static void lmtemp_attach(device_t, device_t, void *); 76 77 CFATTACH_DECL_NEW(lmtemp, sizeof(struct lmtemp_softc), 78 lmtemp_match, lmtemp_attach, NULL, NULL); 79 80 static void lmtemp_refresh(struct sysmon_envsys *, envsys_data_t *); 81 static int lmtemp_config_write(struct lmtemp_softc *, uint8_t); 82 static int lmtemp_temp_write(struct lmtemp_softc *, uint8_t, uint32_t, 83 int); 84 static int lmtemp_temp_read(struct lmtemp_softc *, uint8_t, uint32_t *, 85 int); 86 static uint32_t lmtemp_decode_lm75(const uint8_t *, int); 87 static uint32_t lmtemp_decode_ds75(const uint8_t *, int); 88 static uint32_t lmtemp_decode_lm77(const uint8_t *, int); 89 static void lmtemp_encode_lm75(const uint32_t, uint8_t *, int); 90 static void lmtemp_encode_ds75(const uint32_t, uint8_t *, int); 91 static void lmtemp_encode_lm77(const uint32_t, uint8_t *, int); 92 static void lmtemp_getlim_lm75(struct sysmon_envsys *, envsys_data_t *, 93 sysmon_envsys_lim_t *, uint32_t *); 94 static void lmtemp_getlim_lm77(struct sysmon_envsys *, envsys_data_t *, 95 sysmon_envsys_lim_t *, uint32_t *); 96 static void lmtemp_setlim_lm75(struct sysmon_envsys *, envsys_data_t *, 97 sysmon_envsys_lim_t *, uint32_t *); 98 static void lmtemp_setlim_lm77(struct sysmon_envsys *, envsys_data_t *, 99 sysmon_envsys_lim_t *, uint32_t *); 100 101 static void lmtemp_setup_sysctl(struct lmtemp_softc *); 102 static int sysctl_lm75_temp(SYSCTLFN_ARGS); 103 104 static const char * lmtemp_compats[] = { 105 "i2c-lm75", 106 "ds1775", 107 /* 108 * see XXX in _attach() below: add code once non-lm75 matches are 109 * added here! 110 */ 111 NULL 112 }; 113 114 enum { 115 lmtemp_lm75 = 0, 116 lmtemp_ds75, 117 lmtemp_lm77, 118 }; 119 static const struct { 120 int lmtemp_type; 121 const char *lmtemp_name; 122 int lmtemp_addrmask; 123 int lmtemp_addr; 124 uint32_t (*lmtemp_decode)(const uint8_t *, int); 125 void (*lmtemp_encode)(const uint32_t, uint8_t *, int); 126 void (*lmtemp_getlim)(struct sysmon_envsys *, envsys_data_t *, 127 sysmon_envsys_lim_t *, uint32_t *); 128 void (*lmtemp_setlim)(struct sysmon_envsys *, envsys_data_t *, 129 sysmon_envsys_lim_t *, uint32_t *); 130 } lmtemptbl[] = { 131 { lmtemp_lm75, "LM75", LM75_ADDRMASK, LM75_ADDR, 132 lmtemp_decode_lm75, lmtemp_encode_lm75, 133 lmtemp_getlim_lm75, lmtemp_setlim_lm75 }, 134 { lmtemp_ds75, "DS75", LM75_ADDRMASK, LM75_ADDR, 135 lmtemp_decode_ds75, lmtemp_encode_ds75, 136 lmtemp_getlim_lm75, lmtemp_setlim_lm75 }, 137 { lmtemp_lm77, "LM77", LM77_ADDRMASK, LM77_ADDR, 138 lmtemp_decode_lm77, lmtemp_encode_lm77, 139 lmtemp_getlim_lm77, lmtemp_setlim_lm77 }, 140 { -1, NULL, 0, 0, 141 NULL, NULL, 142 NULL, NULL } 143 }; 144 145 static int 146 lmtemp_match(device_t parent, cfdata_t cf, void *aux) 147 { 148 struct i2c_attach_args *ia = aux; 149 int i; 150 151 if (ia->ia_name == NULL) { 152 /* 153 * Indirect config - not much we can do! 154 */ 155 for (i = 0; lmtemptbl[i].lmtemp_type != -1 ; i++) 156 if (lmtemptbl[i].lmtemp_type == cf->cf_flags) 157 break; 158 if (lmtemptbl[i].lmtemp_type == -1) 159 return 0; 160 161 if ((ia->ia_addr & lmtemptbl[i].lmtemp_addrmask) == 162 lmtemptbl[i].lmtemp_addr) 163 return 1; 164 } else { 165 /* 166 * Direct config - match via the list of compatible 167 * hardware or simply match the device name. 168 */ 169 if (ia->ia_ncompat > 0) { 170 if (iic_compat_match(ia, lmtemp_compats)) 171 return 1; 172 } else { 173 if (strcmp(ia->ia_name, "lmtemp") == 0) 174 return 1; 175 } 176 } 177 178 179 return 0; 180 } 181 182 static void 183 lmtemp_attach(device_t parent, device_t self, void *aux) 184 { 185 struct lmtemp_softc *sc = device_private(self); 186 struct i2c_attach_args *ia = aux; 187 char name[64]; 188 int i; 189 190 sc->sc_dev = self; 191 if (ia->ia_name == NULL) { 192 for (i = 0; lmtemptbl[i].lmtemp_type != -1 ; i++) 193 if (lmtemptbl[i].lmtemp_type == 194 device_cfdata(self)->cf_flags) 195 break; 196 } else { 197 if (strcmp(ia->ia_name, "ds1775") == 0) { 198 i = 1; /* LMTYPE_DS75 */ 199 } else { 200 /* XXX - add code when adding other direct matches! */ 201 i = 0; 202 } 203 } 204 205 sc->sc_tag = ia->ia_tag; 206 sc->sc_address = ia->ia_addr; 207 208 aprint_naive(": Temperature Sensor\n"); 209 if (ia->ia_name) { 210 aprint_normal(": %s %s Temperature Sensor\n", ia->ia_name, 211 lmtemptbl[i].lmtemp_name); 212 } else { 213 aprint_normal(": %s Temperature Sensor\n", 214 lmtemptbl[i].lmtemp_name); 215 } 216 217 sc->sc_lmtemp_decode = lmtemptbl[i].lmtemp_decode; 218 sc->sc_lmtemp_encode = lmtemptbl[i].lmtemp_encode; 219 220 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 221 222 /* Read temperature limit(s) and remember initial value(s). */ 223 if (i == lmtemp_lm77) { 224 if (lmtemp_temp_read(sc, LM77_REG_TCRIT_SET_POINT, 225 &sc->sc_scrit, 1) != 0) { 226 aprint_error_dev(self, 227 "unable to read low register\n"); 228 iic_release_bus(sc->sc_tag, I2C_F_POLL); 229 return; 230 } 231 if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT, 232 &sc->sc_smin, 1) != 0) { 233 aprint_error_dev(self, 234 "unable to read low register\n"); 235 iic_release_bus(sc->sc_tag, I2C_F_POLL); 236 return; 237 } 238 if (lmtemp_temp_read(sc, LM77_REG_THIGH_SET_POINT, 239 &sc->sc_smax, 1) != 0) { 240 aprint_error_dev(self, 241 "unable to read high register\n"); 242 iic_release_bus(sc->sc_tag, I2C_F_POLL); 243 return; 244 } 245 } else { /* LM75 or compatible */ 246 if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, 247 &sc->sc_smax, 1) != 0) { 248 aprint_error_dev(self, "unable to read Tos register\n"); 249 iic_release_bus(sc->sc_tag, I2C_F_POLL); 250 return; 251 } 252 } 253 sc->sc_tmax = sc->sc_smax; 254 255 if (i == lmtemp_lm75) 256 lmtemp_setup_sysctl(sc); 257 258 /* Set the configuration of the LM75 to defaults. */ 259 if (lmtemp_config_write(sc, LM75_CONFIG_FAULT_QUEUE_4) != 0) { 260 aprint_error_dev(self, "unable to write config register\n"); 261 iic_release_bus(sc->sc_tag, I2C_F_POLL); 262 return; 263 } 264 iic_release_bus(sc->sc_tag, I2C_F_POLL); 265 266 sc->sc_sme = sysmon_envsys_create(); 267 /* Initialize sensor data. */ 268 sc->sc_sensor.units = ENVSYS_STEMP; 269 sc->sc_sensor.state = ENVSYS_SINVALID; 270 sc->sc_sensor.flags = ENVSYS_FMONLIMITS; 271 272 (void)strlcpy(name, 273 ia->ia_name? ia->ia_name : device_xname(self), 274 sizeof(sc->sc_sensor.desc)); 275 #ifdef HAVE_OF 276 int ch; 277 ch = OF_child(ia->ia_cookie); 278 if (ch != 0) { 279 OF_getprop(ch, "location", name, 64); 280 } 281 #endif 282 (void)strlcpy(sc->sc_sensor.desc, name, 283 sizeof(sc->sc_sensor.desc)); 284 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) { 285 sysmon_envsys_destroy(sc->sc_sme); 286 return; 287 } 288 289 /* Hook into system monitor. */ 290 sc->sc_sme->sme_name = device_xname(self); 291 sc->sc_sme->sme_cookie = sc; 292 sc->sc_sme->sme_refresh = lmtemp_refresh; 293 sc->sc_sme->sme_get_limits = lmtemptbl[i].lmtemp_getlim; 294 sc->sc_sme->sme_set_limits = lmtemptbl[i].lmtemp_setlim; 295 296 if (sysmon_envsys_register(sc->sc_sme)) { 297 aprint_error_dev(self, "unable to register with sysmon\n"); 298 sysmon_envsys_destroy(sc->sc_sme); 299 } 300 } 301 302 static int 303 lmtemp_config_write(struct lmtemp_softc *sc, uint8_t val) 304 { 305 uint8_t cmdbuf[2]; 306 307 cmdbuf[0] = LM75_REG_CONFIG; 308 cmdbuf[1] = val; 309 310 return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 311 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL); 312 } 313 314 static int 315 lmtemp_temp_write(struct lmtemp_softc *sc, uint8_t reg, uint32_t val, int degc) 316 { 317 uint8_t cmdbuf[3]; 318 319 cmdbuf[0] = reg; 320 sc->sc_lmtemp_encode(val, &cmdbuf[1], degc); 321 322 return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 323 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 2, I2C_F_POLL); 324 } 325 326 static int 327 lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, uint32_t *valp, 328 int degc) 329 { 330 int error; 331 uint8_t cmdbuf[1]; 332 uint8_t buf[LM75_TEMP_LEN]; 333 334 cmdbuf[0] = which; 335 336 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 337 sc->sc_address, cmdbuf, 1, buf, LM75_TEMP_LEN, 0); 338 if (error) 339 return error; 340 341 *valp = sc->sc_lmtemp_decode(buf, degc); 342 return 0; 343 } 344 345 static void 346 lmtemp_refresh_sensor_data(struct lmtemp_softc *sc) 347 { 348 uint32_t val; 349 int error; 350 351 error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val, 0); 352 if (error) { 353 #if 0 354 aprint_error_dev(sc->sc_dev, "unable to read temperature, error = %d\n", 355 error); 356 #endif 357 sc->sc_sensor.state = ENVSYS_SINVALID; 358 return; 359 } 360 361 sc->sc_sensor.value_cur = val; 362 sc->sc_sensor.state = ENVSYS_SVALID; 363 } 364 365 static void 366 lmtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata) 367 { 368 struct lmtemp_softc *sc = sme->sme_cookie; 369 370 iic_acquire_bus(sc->sc_tag, 0); /* also locks our instance */ 371 lmtemp_refresh_sensor_data(sc); 372 iic_release_bus(sc->sc_tag, 0); /* also unlocks our instance */ 373 } 374 375 static void 376 lmtemp_getlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata, 377 sysmon_envsys_lim_t *limits, uint32_t *props) 378 { 379 struct lmtemp_softc *sc = sme->sme_cookie; 380 uint32_t val; 381 382 *props &= ~(PROP_CRITMAX); 383 384 iic_acquire_bus(sc->sc_tag, 0); 385 if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, &val, 0) == 0) { 386 limits->sel_critmax = val; 387 *props |= PROP_CRITMAX; 388 } 389 iic_release_bus(sc->sc_tag, 0); 390 } 391 392 static void 393 lmtemp_getlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata, 394 sysmon_envsys_lim_t *limits, uint32_t *props) 395 { 396 struct lmtemp_softc *sc = sme->sme_cookie; 397 uint32_t val; 398 399 *props &= ~(PROP_CRITMAX | PROP_WARNMAX | PROP_WARNMIN); 400 401 iic_acquire_bus(sc->sc_tag, 0); 402 if (lmtemp_temp_read(sc, LM77_REG_TCRIT_SET_POINT, &val, 0) == 0) { 403 limits->sel_critmax = val; 404 *props |= PROP_CRITMAX; 405 } 406 if (lmtemp_temp_read(sc, LM77_REG_THIGH_SET_POINT, &val, 0) == 0) { 407 limits->sel_warnmax = val; 408 *props |= PROP_WARNMAX; 409 } 410 if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT, &val, 0) == 0) { 411 limits->sel_warnmin = val; 412 *props |= PROP_WARNMIN; 413 } 414 iic_release_bus(sc->sc_tag, 0); 415 } 416 417 static void 418 lmtemp_setlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata, 419 sysmon_envsys_lim_t *limits, uint32_t *props) 420 { 421 struct lmtemp_softc *sc = sme->sme_cookie; 422 int32_t limit; 423 424 if (*props & PROP_CRITMAX) { 425 if (limits == NULL) /* Restore defaults */ 426 limit = sc->sc_smax; 427 else 428 limit = limits->sel_critmax; 429 iic_acquire_bus(sc->sc_tag, 0); 430 lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT, 431 limit - 5000000, 0); 432 lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT, limit, 0); 433 iic_release_bus(sc->sc_tag, 0); 434 435 /* Synchronise sysctl */ 436 sc->sc_tmax = (limit - 273150000) / 1000000; 437 } 438 } 439 440 static void 441 lmtemp_setlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata, 442 sysmon_envsys_lim_t *limits, uint32_t *props) 443 { 444 struct lmtemp_softc *sc = sme->sme_cookie; 445 int32_t limit; 446 447 iic_acquire_bus(sc->sc_tag, 0); 448 if (*props & PROP_CRITMAX) { 449 if (limits == NULL) /* Restore defaults */ 450 limit = sc->sc_scrit; 451 else 452 limit = limits->sel_critmax; 453 lmtemp_temp_write(sc, LM77_REG_TCRIT_SET_POINT, limit, 0); 454 } 455 if (*props & PROP_WARNMAX) { 456 if (limits == NULL) /* Restore defaults */ 457 limit = sc->sc_smax; 458 else 459 limit = limits->sel_warnmax; 460 lmtemp_temp_write(sc, LM77_REG_THIGH_SET_POINT, limit, 0); 461 } 462 if (*props & PROP_WARNMIN) { 463 if (limits == NULL) /* Restore defaults */ 464 limit = sc->sc_smin; 465 else 466 limit = limits->sel_warnmin; 467 lmtemp_temp_write(sc, LM77_REG_TLOW_SET_POINT, limit, 0); 468 } 469 iic_release_bus(sc->sc_tag, 0); 470 } 471 472 static uint32_t 473 lmtemp_decode_lm75(const uint8_t *buf, int degc) 474 { 475 int temp; 476 uint32_t val; 477 478 /* 479 * LM75 temps are the most-significant 9 bits of a 16-bit reg. 480 * sign-extend the MSB and add in the 0.5 from the LSB 481 */ 482 temp = (int8_t) buf[0]; 483 temp = (temp << 1) + ((buf[1] >> 7) & 0x1); 484 485 /* Temp is given in 1/2 deg. C, we convert to C or uK. */ 486 if (degc) 487 val = temp / 2; 488 else 489 val = temp * 500000 + 273150000; 490 491 return val; 492 } 493 494 static uint32_t 495 lmtemp_decode_ds75(const uint8_t *buf, int degc) 496 { 497 int temp; 498 499 /* 500 * Sign-extend the MSB byte, and add in the fractions of a 501 * degree contained in the LSB (precision 1/16th DegC). 502 */ 503 temp = (int8_t)buf[0]; 504 temp = (temp << 4) | ((buf[1] >> 4) & 0xf); 505 506 /* 507 * Conversion to C or uK is simple. 508 */ 509 if (degc) 510 return temp / 16; 511 else 512 return (temp * 62500 + 273150000); 513 } 514 515 static uint32_t 516 lmtemp_decode_lm77(const uint8_t *buf, int degc) 517 { 518 int temp; 519 uint32_t val; 520 521 /* 522 * Describe each bits of temperature registers on LM77. 523 * D15 - D12: Sign 524 * D11 - D3 : Bit8(MSB) - Bit0 525 */ 526 temp = (int8_t)buf[0]; 527 temp = (temp << 5) | ((buf[1] >> 3) & 0x1f); 528 529 /* Temp is given in 1/2 deg. C, we convert to C or uK. */ 530 if (degc) 531 val = temp / 2; 532 else 533 val = temp * 500000 + 273150000; 534 535 return val; 536 } 537 538 static void lmtemp_encode_lm75(const uint32_t val, uint8_t *buf, int degc) 539 { 540 int temp; 541 542 /* Convert from C or uK to register format */ 543 if (degc) 544 temp = val * 2; 545 else 546 temp = (val - 273150000) / 500000; 547 buf[0] = (temp >> 1) & 0xff; 548 buf[1] = (temp & 1) << 7; 549 } 550 551 static void lmtemp_encode_ds75(const uint32_t val, uint8_t *buf, int degc) 552 { 553 int temp; 554 555 /* Convert from C or uK to register format */ 556 if (degc) 557 temp = val * 16; 558 else 559 temp = (val - 273150000) / 62500; 560 buf[0] = (temp >> 4) & 0xff; 561 buf[1] = (temp & 0xf) << 4; 562 } 563 564 static void lmtemp_encode_lm77(const uint32_t val, uint8_t *buf, int degc) 565 { 566 int temp; 567 568 /* Convert from C or uK to register format */ 569 if (degc) 570 temp = val * 2; 571 else 572 temp = (val - 273150000) / 500000; 573 buf[0] = (temp >> 5) & 0xff; 574 buf[1] = (temp & 0x1f) << 3; 575 } 576 577 static void 578 lmtemp_setup_sysctl(struct lmtemp_softc *sc) 579 { 580 const struct sysctlnode *me = NULL, *node = NULL; 581 582 sysctl_createv(NULL, 0, NULL, &me, 583 CTLFLAG_READWRITE, 584 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL, 585 NULL, 0, NULL, 0, 586 CTL_MACHDEP, CTL_CREATE, CTL_EOL); 587 588 sysctl_createv(NULL, 0, NULL, &node, 589 CTLFLAG_READWRITE | CTLFLAG_OWNDESC, 590 CTLTYPE_INT, "temp", "Threshold temperature", 591 sysctl_lm75_temp, 1, (void *)sc, 0, 592 CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL); 593 } 594 595 static int 596 sysctl_lm75_temp(SYSCTLFN_ARGS) 597 { 598 struct sysctlnode node = *rnode; 599 struct lmtemp_softc *sc = node.sysctl_data; 600 int temp; 601 602 if (newp) { 603 604 /* we're asked to write */ 605 node.sysctl_data = &sc->sc_tmax; 606 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) { 607 608 temp = *(int *)node.sysctl_data; 609 sc->sc_tmax = temp; 610 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 611 lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT, 612 sc->sc_tmax - 5, 1); 613 lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT, 614 sc->sc_tmax, 1); 615 iic_release_bus(sc->sc_tag, I2C_F_POLL); 616 617 /* Synchronise envsys - calls lmtemp_getlim_lm75() */ 618 sysmon_envsys_update_limits(sc->sc_sme, &sc->sc_sensor); 619 return 0; 620 } 621 return EINVAL; 622 } else { 623 624 node.sysctl_data = &sc->sc_tmax; 625 node.sysctl_size = 4; 626 return (sysctl_lookup(SYSCTLFN_CALL(&node))); 627 } 628 629 return 0; 630 } 631 632 SYSCTL_SETUP(sysctl_lmtemp_setup, "sysctl lmtemp subtree setup") 633 { 634 635 sysctl_createv(NULL, 0, NULL, NULL, 636 CTLFLAG_PERMANENT, 637 CTLTYPE_NODE, "machdep", NULL, 638 NULL, 0, NULL, 0, 639 CTL_MACHDEP, CTL_EOL); 640 } 641 642 643