lm75.c revision 1.30 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