lm75.c revision 1.32 1 /* $NetBSD: lm75.c,v 1.32 2018/06/18 17:07:07 thorpej 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.32 2018/06/18 17:07:07 thorpej 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 static const struct device_compatible_entry lmtemp_compat_data[] = {
115 DEVICE_COMPAT_ENTRY(lmtemp_compats),
116 DEVICE_COMPAT_TERMINATOR
117 };
118
119 enum {
120 lmtemp_lm75 = 0,
121 lmtemp_ds75,
122 lmtemp_lm77,
123 };
124 static const struct {
125 int lmtemp_type;
126 const char *lmtemp_name;
127 int lmtemp_addrmask;
128 int lmtemp_addr;
129 uint32_t (*lmtemp_decode)(const uint8_t *, int);
130 void (*lmtemp_encode)(const uint32_t, uint8_t *, int);
131 void (*lmtemp_getlim)(struct sysmon_envsys *, envsys_data_t *,
132 sysmon_envsys_lim_t *, uint32_t *);
133 void (*lmtemp_setlim)(struct sysmon_envsys *, envsys_data_t *,
134 sysmon_envsys_lim_t *, uint32_t *);
135 } lmtemptbl[] = {
136 { lmtemp_lm75, "LM75", LM75_ADDRMASK, LM75_ADDR,
137 lmtemp_decode_lm75, lmtemp_encode_lm75,
138 lmtemp_getlim_lm75, lmtemp_setlim_lm75 },
139 { lmtemp_ds75, "DS75", LM75_ADDRMASK, LM75_ADDR,
140 lmtemp_decode_ds75, lmtemp_encode_ds75,
141 lmtemp_getlim_lm75, lmtemp_setlim_lm75 },
142 { lmtemp_lm77, "LM77", LM77_ADDRMASK, LM77_ADDR,
143 lmtemp_decode_lm77, lmtemp_encode_lm77,
144 lmtemp_getlim_lm77, lmtemp_setlim_lm77 },
145 { -1, NULL, 0, 0,
146 NULL, NULL,
147 NULL, NULL }
148 };
149
150 static int
151 lmtemp_match(device_t parent, cfdata_t cf, void *aux)
152 {
153 struct i2c_attach_args *ia = aux;
154 int i, match_result;
155
156 if (iic_use_direct_match(ia, cf, lmtemp_compat_data, &match_result))
157 return match_result;
158
159 /*
160 * Indirect config - not much we can do!
161 */
162 for (i = 0; lmtemptbl[i].lmtemp_type != -1 ; i++)
163 if (lmtemptbl[i].lmtemp_type == cf->cf_flags)
164 break;
165 if (lmtemptbl[i].lmtemp_type == -1)
166 return 0;
167
168 if ((ia->ia_addr & lmtemptbl[i].lmtemp_addrmask) ==
169 lmtemptbl[i].lmtemp_addr)
170 return I2C_MATCH_ADDRESS_ONLY;
171
172 return 0;
173 }
174
175 static void
176 lmtemp_attach(device_t parent, device_t self, void *aux)
177 {
178 struct lmtemp_softc *sc = device_private(self);
179 struct i2c_attach_args *ia = aux;
180 char name[64];
181 int i;
182
183 sc->sc_dev = self;
184 if (ia->ia_name == NULL) {
185 for (i = 0; lmtemptbl[i].lmtemp_type != -1 ; i++)
186 if (lmtemptbl[i].lmtemp_type ==
187 device_cfdata(self)->cf_flags)
188 break;
189 } else {
190 if (strcmp(ia->ia_name, "ds1775") == 0) {
191 i = 1; /* LMTYPE_DS75 */
192 } else {
193 /* XXX - add code when adding other direct matches! */
194 i = 0;
195 }
196 }
197
198 sc->sc_tag = ia->ia_tag;
199 sc->sc_address = ia->ia_addr;
200
201 aprint_naive(": Temperature Sensor\n");
202 if (ia->ia_name) {
203 aprint_normal(": %s %s Temperature Sensor\n", ia->ia_name,
204 lmtemptbl[i].lmtemp_name);
205 } else {
206 aprint_normal(": %s Temperature Sensor\n",
207 lmtemptbl[i].lmtemp_name);
208 }
209
210 sc->sc_lmtemp_decode = lmtemptbl[i].lmtemp_decode;
211 sc->sc_lmtemp_encode = lmtemptbl[i].lmtemp_encode;
212
213 iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
214
215 /* Read temperature limit(s) and remember initial value(s). */
216 if (i == lmtemp_lm77) {
217 if (lmtemp_temp_read(sc, LM77_REG_TCRIT_SET_POINT,
218 &sc->sc_scrit, 1) != 0) {
219 aprint_error_dev(self,
220 "unable to read low register\n");
221 iic_release_bus(sc->sc_tag, I2C_F_POLL);
222 return;
223 }
224 if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT,
225 &sc->sc_smin, 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_THIGH_SET_POINT,
232 &sc->sc_smax, 1) != 0) {
233 aprint_error_dev(self,
234 "unable to read high register\n");
235 iic_release_bus(sc->sc_tag, I2C_F_POLL);
236 return;
237 }
238 } else { /* LM75 or compatible */
239 if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT,
240 &sc->sc_smax, 1) != 0) {
241 aprint_error_dev(self, "unable to read Tos register\n");
242 iic_release_bus(sc->sc_tag, I2C_F_POLL);
243 return;
244 }
245 }
246 sc->sc_tmax = sc->sc_smax;
247
248 if (i == lmtemp_lm75)
249 lmtemp_setup_sysctl(sc);
250
251 /* Set the configuration of the LM75 to defaults. */
252 if (lmtemp_config_write(sc, LM75_CONFIG_FAULT_QUEUE_4) != 0) {
253 aprint_error_dev(self, "unable to write config register\n");
254 iic_release_bus(sc->sc_tag, I2C_F_POLL);
255 return;
256 }
257 iic_release_bus(sc->sc_tag, I2C_F_POLL);
258
259 sc->sc_sme = sysmon_envsys_create();
260 /* Initialize sensor data. */
261 sc->sc_sensor.units = ENVSYS_STEMP;
262 sc->sc_sensor.state = ENVSYS_SINVALID;
263 sc->sc_sensor.flags = ENVSYS_FMONLIMITS;
264
265 (void)strlcpy(name,
266 ia->ia_name? ia->ia_name : device_xname(self),
267 sizeof(sc->sc_sensor.desc));
268 #ifdef HAVE_OF
269 int ch;
270 ch = OF_child(ia->ia_cookie);
271 if (ch != 0) {
272 OF_getprop(ch, "location", name, 64);
273 }
274 #endif
275 (void)strlcpy(sc->sc_sensor.desc, name,
276 sizeof(sc->sc_sensor.desc));
277 if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) {
278 sysmon_envsys_destroy(sc->sc_sme);
279 return;
280 }
281
282 /* Hook into system monitor. */
283 sc->sc_sme->sme_name = device_xname(self);
284 sc->sc_sme->sme_cookie = sc;
285 sc->sc_sme->sme_refresh = lmtemp_refresh;
286 sc->sc_sme->sme_get_limits = lmtemptbl[i].lmtemp_getlim;
287 sc->sc_sme->sme_set_limits = lmtemptbl[i].lmtemp_setlim;
288
289 if (sysmon_envsys_register(sc->sc_sme)) {
290 aprint_error_dev(self, "unable to register with sysmon\n");
291 sysmon_envsys_destroy(sc->sc_sme);
292 }
293 }
294
295 static int
296 lmtemp_config_write(struct lmtemp_softc *sc, uint8_t val)
297 {
298 uint8_t cmdbuf[2];
299
300 cmdbuf[0] = LM75_REG_CONFIG;
301 cmdbuf[1] = val;
302
303 return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
304 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 1, I2C_F_POLL);
305 }
306
307 static int
308 lmtemp_temp_write(struct lmtemp_softc *sc, uint8_t reg, uint32_t val, int degc)
309 {
310 uint8_t cmdbuf[3];
311
312 cmdbuf[0] = reg;
313 sc->sc_lmtemp_encode(val, &cmdbuf[1], degc);
314
315 return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
316 sc->sc_address, cmdbuf, 1, &cmdbuf[1], 2, I2C_F_POLL);
317 }
318
319 static int
320 lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, uint32_t *valp,
321 int degc)
322 {
323 int error;
324 uint8_t cmdbuf[1];
325 uint8_t buf[LM75_TEMP_LEN];
326
327 cmdbuf[0] = which;
328
329 error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
330 sc->sc_address, cmdbuf, 1, buf, LM75_TEMP_LEN, 0);
331 if (error)
332 return error;
333
334 *valp = sc->sc_lmtemp_decode(buf, degc);
335 return 0;
336 }
337
338 static void
339 lmtemp_refresh_sensor_data(struct lmtemp_softc *sc)
340 {
341 uint32_t val;
342 int error;
343
344 error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val, 0);
345 if (error) {
346 #if 0
347 aprint_error_dev(sc->sc_dev, "unable to read temperature, error = %d\n",
348 error);
349 #endif
350 sc->sc_sensor.state = ENVSYS_SINVALID;
351 return;
352 }
353
354 sc->sc_sensor.value_cur = val;
355 sc->sc_sensor.state = ENVSYS_SVALID;
356 }
357
358 static void
359 lmtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
360 {
361 struct lmtemp_softc *sc = sme->sme_cookie;
362
363 iic_acquire_bus(sc->sc_tag, 0); /* also locks our instance */
364 lmtemp_refresh_sensor_data(sc);
365 iic_release_bus(sc->sc_tag, 0); /* also unlocks our instance */
366 }
367
368 static void
369 lmtemp_getlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata,
370 sysmon_envsys_lim_t *limits, uint32_t *props)
371 {
372 struct lmtemp_softc *sc = sme->sme_cookie;
373 uint32_t val;
374
375 *props &= ~(PROP_CRITMAX);
376
377 iic_acquire_bus(sc->sc_tag, 0);
378 if (lmtemp_temp_read(sc, LM75_REG_TOS_SET_POINT, &val, 0) == 0) {
379 limits->sel_critmax = val;
380 *props |= PROP_CRITMAX;
381 }
382 iic_release_bus(sc->sc_tag, 0);
383 }
384
385 static void
386 lmtemp_getlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata,
387 sysmon_envsys_lim_t *limits, uint32_t *props)
388 {
389 struct lmtemp_softc *sc = sme->sme_cookie;
390 uint32_t val;
391
392 *props &= ~(PROP_CRITMAX | PROP_WARNMAX | PROP_WARNMIN);
393
394 iic_acquire_bus(sc->sc_tag, 0);
395 if (lmtemp_temp_read(sc, LM77_REG_TCRIT_SET_POINT, &val, 0) == 0) {
396 limits->sel_critmax = val;
397 *props |= PROP_CRITMAX;
398 }
399 if (lmtemp_temp_read(sc, LM77_REG_THIGH_SET_POINT, &val, 0) == 0) {
400 limits->sel_warnmax = val;
401 *props |= PROP_WARNMAX;
402 }
403 if (lmtemp_temp_read(sc, LM77_REG_TLOW_SET_POINT, &val, 0) == 0) {
404 limits->sel_warnmin = val;
405 *props |= PROP_WARNMIN;
406 }
407 iic_release_bus(sc->sc_tag, 0);
408 }
409
410 static void
411 lmtemp_setlim_lm75(struct sysmon_envsys *sme, envsys_data_t *edata,
412 sysmon_envsys_lim_t *limits, uint32_t *props)
413 {
414 struct lmtemp_softc *sc = sme->sme_cookie;
415 int32_t limit;
416
417 if (*props & PROP_CRITMAX) {
418 if (limits == NULL) /* Restore defaults */
419 limit = sc->sc_smax;
420 else
421 limit = limits->sel_critmax;
422 iic_acquire_bus(sc->sc_tag, 0);
423 lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT,
424 limit - 5000000, 0);
425 lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT, limit, 0);
426 iic_release_bus(sc->sc_tag, 0);
427
428 /* Synchronise sysctl */
429 sc->sc_tmax = (limit - 273150000) / 1000000;
430 }
431 }
432
433 static void
434 lmtemp_setlim_lm77(struct sysmon_envsys *sme, envsys_data_t *edata,
435 sysmon_envsys_lim_t *limits, uint32_t *props)
436 {
437 struct lmtemp_softc *sc = sme->sme_cookie;
438 int32_t limit;
439
440 iic_acquire_bus(sc->sc_tag, 0);
441 if (*props & PROP_CRITMAX) {
442 if (limits == NULL) /* Restore defaults */
443 limit = sc->sc_scrit;
444 else
445 limit = limits->sel_critmax;
446 lmtemp_temp_write(sc, LM77_REG_TCRIT_SET_POINT, limit, 0);
447 }
448 if (*props & PROP_WARNMAX) {
449 if (limits == NULL) /* Restore defaults */
450 limit = sc->sc_smax;
451 else
452 limit = limits->sel_warnmax;
453 lmtemp_temp_write(sc, LM77_REG_THIGH_SET_POINT, limit, 0);
454 }
455 if (*props & PROP_WARNMIN) {
456 if (limits == NULL) /* Restore defaults */
457 limit = sc->sc_smin;
458 else
459 limit = limits->sel_warnmin;
460 lmtemp_temp_write(sc, LM77_REG_TLOW_SET_POINT, limit, 0);
461 }
462 iic_release_bus(sc->sc_tag, 0);
463 }
464
465 static uint32_t
466 lmtemp_decode_lm75(const uint8_t *buf, int degc)
467 {
468 int temp;
469 uint32_t val;
470
471 /*
472 * LM75 temps are the most-significant 9 bits of a 16-bit reg.
473 * sign-extend the MSB and add in the 0.5 from the LSB
474 */
475 temp = (int8_t) buf[0];
476 temp = (temp << 1) + ((buf[1] >> 7) & 0x1);
477
478 /* Temp is given in 1/2 deg. C, we convert to C or uK. */
479 if (degc)
480 val = temp / 2;
481 else
482 val = temp * 500000 + 273150000;
483
484 return val;
485 }
486
487 static uint32_t
488 lmtemp_decode_ds75(const uint8_t *buf, int degc)
489 {
490 int temp;
491
492 /*
493 * Sign-extend the MSB byte, and add in the fractions of a
494 * degree contained in the LSB (precision 1/16th DegC).
495 */
496 temp = (int8_t)buf[0];
497 temp = (temp << 4) | ((buf[1] >> 4) & 0xf);
498
499 /*
500 * Conversion to C or uK is simple.
501 */
502 if (degc)
503 return temp / 16;
504 else
505 return (temp * 62500 + 273150000);
506 }
507
508 static uint32_t
509 lmtemp_decode_lm77(const uint8_t *buf, int degc)
510 {
511 int temp;
512 uint32_t val;
513
514 /*
515 * Describe each bits of temperature registers on LM77.
516 * D15 - D12: Sign
517 * D11 - D3 : Bit8(MSB) - Bit0
518 */
519 temp = (int8_t)buf[0];
520 temp = (temp << 5) | ((buf[1] >> 3) & 0x1f);
521
522 /* Temp is given in 1/2 deg. C, we convert to C or uK. */
523 if (degc)
524 val = temp / 2;
525 else
526 val = temp * 500000 + 273150000;
527
528 return val;
529 }
530
531 static void lmtemp_encode_lm75(const uint32_t val, uint8_t *buf, int degc)
532 {
533 int temp;
534
535 /* Convert from C or uK to register format */
536 if (degc)
537 temp = val * 2;
538 else
539 temp = (val - 273150000) / 500000;
540 buf[0] = (temp >> 1) & 0xff;
541 buf[1] = (temp & 1) << 7;
542 }
543
544 static void lmtemp_encode_ds75(const uint32_t val, uint8_t *buf, int degc)
545 {
546 int temp;
547
548 /* Convert from C or uK to register format */
549 if (degc)
550 temp = val * 16;
551 else
552 temp = (val - 273150000) / 62500;
553 buf[0] = (temp >> 4) & 0xff;
554 buf[1] = (temp & 0xf) << 4;
555 }
556
557 static void lmtemp_encode_lm77(const uint32_t val, uint8_t *buf, int degc)
558 {
559 int temp;
560
561 /* Convert from C or uK to register format */
562 if (degc)
563 temp = val * 2;
564 else
565 temp = (val - 273150000) / 500000;
566 buf[0] = (temp >> 5) & 0xff;
567 buf[1] = (temp & 0x1f) << 3;
568 }
569
570 static void
571 lmtemp_setup_sysctl(struct lmtemp_softc *sc)
572 {
573 const struct sysctlnode *me = NULL, *node = NULL;
574
575 sysctl_createv(NULL, 0, NULL, &me,
576 CTLFLAG_READWRITE,
577 CTLTYPE_NODE, device_xname(sc->sc_dev), NULL,
578 NULL, 0, NULL, 0,
579 CTL_MACHDEP, CTL_CREATE, CTL_EOL);
580
581 sysctl_createv(NULL, 0, NULL, &node,
582 CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
583 CTLTYPE_INT, "temp", "Threshold temperature",
584 sysctl_lm75_temp, 1, (void *)sc, 0,
585 CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
586 }
587
588 static int
589 sysctl_lm75_temp(SYSCTLFN_ARGS)
590 {
591 struct sysctlnode node = *rnode;
592 struct lmtemp_softc *sc = node.sysctl_data;
593 int temp;
594
595 if (newp) {
596
597 /* we're asked to write */
598 node.sysctl_data = &sc->sc_tmax;
599 if (sysctl_lookup(SYSCTLFN_CALL(&node)) == 0) {
600
601 temp = *(int *)node.sysctl_data;
602 sc->sc_tmax = temp;
603 iic_acquire_bus(sc->sc_tag, I2C_F_POLL);
604 lmtemp_temp_write(sc, LM75_REG_THYST_SET_POINT,
605 sc->sc_tmax - 5, 1);
606 lmtemp_temp_write(sc, LM75_REG_TOS_SET_POINT,
607 sc->sc_tmax, 1);
608 iic_release_bus(sc->sc_tag, I2C_F_POLL);
609
610 /* Synchronise envsys - calls lmtemp_getlim_lm75() */
611 sysmon_envsys_update_limits(sc->sc_sme, &sc->sc_sensor);
612 return 0;
613 }
614 return EINVAL;
615 } else {
616
617 node.sysctl_data = &sc->sc_tmax;
618 node.sysctl_size = 4;
619 return (sysctl_lookup(SYSCTLFN_CALL(&node)));
620 }
621
622 return 0;
623 }
624
625 SYSCTL_SETUP(sysctl_lmtemp_setup, "sysctl lmtemp subtree setup")
626 {
627
628 sysctl_createv(NULL, 0, NULL, NULL,
629 CTLFLAG_PERMANENT,
630 CTLTYPE_NODE, "machdep", NULL,
631 NULL, 0, NULL, 0,
632 CTL_MACHDEP, CTL_EOL);
633 }
634
635
636