xref: /netbsd-src/sys/dev/i2c/adm1021.c (revision 796c32c94f6e154afc9de0f63da35c91bb739b45)
1 /*	$NetBSD: adm1021.c,v 1.16 2017/09/29 14:17:47 macallan Exp $ */
2 /*	$OpenBSD: adm1021.c,v 1.27 2007/06/24 05:34:35 dlg Exp $	*/
3 
4 /*
5  * Copyright (c) 2005 Theo de Raadt
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /*
21  * Driver for ADM1021 and compatible temperature sensors, including ADM1021,
22  * ADM1021A, ADM1023, ADM1032, GL523SM, G781, LM84, MAX1617, MAX1617A,
23  * NE1617A, MAX6642 and Xeon embedded temperature sensors.
24  *
25  * Some sensors differ from the ADM1021/MAX1617/NE1617A:
26  *                         ADM1021A ADM1023 ADM1032 G781 LM84 MAX1617A MAX6642
27  *   company/revision reg  X        X       X       X         X        X
28  *   no negative temps     X        X       X       X
29  *   11-bit remote temp             X       X       X                  X
30  *   no low limits                                       X             X
31  *   therm (high) limits                    X       X                  X
32  *
33  * Registers 0x00 to 0x0f have separate read/write addresses, but
34  * registers 0x10 and above have the same read/write address.
35  * The 11-bit (extended) temperature consists of a separate register with
36  * 3 valid bits that are always added to the external temperature (even if
37  * the temperature is negative).
38  */
39 
40 #include <sys/cdefs.h>
41 __KERNEL_RCSID(0, "$NetBSD: adm1021.c,v 1.16 2017/09/29 14:17:47 macallan Exp $");
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/device.h>
46 #include <dev/sysmon/sysmonvar.h>
47 
48 #include <dev/i2c/i2cvar.h>
49 
50 #ifdef macppc
51 #define HAVE_OF 1
52 #endif
53 
54 #ifdef HAVE_OF
55 #include <dev/ofw/openfirm.h>
56 #endif
57 
58 /* Registers */
59 #define ADM1021_INT_TEMP	0x00	/* Internal temperature value */
60 #define ADM1021_EXT_TEMP	0x01	/* External temperature value */
61 #define ADM1021_STATUS		0x02	/* Status */
62 #define ADM1021_CONFIG_READ	0x03	/* Read configuration */
63 #define ADM1021_CONV_RATE_READ	0x04	/* Read conversion rate */
64 #define ADM1021_INT_HIGH_READ	0x05	/* Read internal high limit */
65 #define ADM1021_INT_LOW_READ	0x06	/* Read internal low limit */
66 #define ADM1021_EXT_HIGH_READ	0x07	/* Read external high limit */
67 #define ADM1021_EXT_LOW_READ	0x08	/* Read external low limit */
68 #define ADM1021_CONFIG_WRITE	0x09	/* Write configuration */
69 #define ADM1021_CONV_RATE_WRITE 0x0a	/* Write conversion rate */
70 #define ADM1021_INT_HIGH_WRITE	0x0b	/* Write internal high limit */
71 #define ADM1021_INT_LOW_WRITE	0x0c	/* Write internal low limit */
72 #define ADM1021_EXT_HIGH_WRITE	0x0d	/* Write external high limit */
73 #define ADM1021_EXT_LOW_WRITE	0x0e	/* Write external low limit */
74 #define ADM1021_ONE_SHOT	0x0f	/* One shot command */
75 #define ADM1023_EXT_TEMP2	0x10	/* R/W external temp low byte */
76 #define ADM1023_EXT_TEMP_OFF	0x11	/* R/W external temp offset */
77 #define ADM1023_EXT_TEMP_OFF2	0x12	/* R/W external temp off low byte */
78 #define ADM1023_EXT_HIGH2	0x13	/* R/W external high lim low byte */
79 #define ADM1023_EXT_LOW2	0x14	/* R/W external low lim low byte */
80 #define ADM1032_EXT_THERM	0x19	/* R/W external Therm (high) limit */
81 #define ADM1032_INT_THERM	0x20	/* R/W internal Therm (high) limit */
82 #define ADM1032_THERM_HYST	0x21	/* R/W Therm hysteris */
83 #define ADM1032_ALERT_QUEUE	0x22	/* R/W consecutive alert queue */
84 #define ADM1021_COMPANY		0xfe	/* Company ID */
85 #define ADM1021_DIE_REVISION	0xff	/* Die revision code */
86 
87 /* Register values */
88 #define ADM1021_CONFIG_RUN	0x40
89 
90 #define ADM1021_STATUS_INVAL	0x7f
91 #define ADM1021_STATUS_NOEXT	0x40	/* External diode is open-circuit */
92 
93 #define ADM1023_EXT2_SHIFT	5
94 #define ADM1023_EXT2_MASK	0x07
95 
96 #define ADM1021_COMPANY_ADM	0x41	/* 'A' */
97 #define ADM1021_COMPANY_GMT	0x47	/* 'G' */
98 #define ADM1021_COMPANY_MAXIM	0x4d	/* 'M' */
99 
100 #define ADM1021_REV_1021	0x00
101 #define ADM1021_REV_1021A	0x30
102 #define ADM1021_REV_MASK	0xf0
103 
104 /* Sensors */
105 #define ADMTEMP_INT		0
106 #define ADMTEMP_EXT		1
107 #define ADMTEMP_NUM_SENSORS	2
108 
109 #define ADMTEMP_MAX_NEG		-65
110 #define ADMTEMP_MAX_POS		127
111 #define ADMTEMP_LOW_DEFAULT	0xc9	/* (-55)	*/
112 
113 /* Limit registers might read 0xff, so we ignore them if they do */
114 #define ADMTEMP_LIM_INVAL	-1	/* 0xff */
115 
116 #define ADMTEMP_NAMELEN		9	/* Maximum name length + 1 */
117 
118 struct admtemp_softc {
119 	i2c_tag_t	sc_tag;
120 	i2c_addr_t	sc_addr;
121 
122 	int		sc_flags;
123 	int		sc_noexternal, sc_noneg, sc_nolow;
124 	int		sc_ext11, sc_therm;
125 	struct sysmon_envsys *sc_sme;
126 	envsys_data_t sc_sensor[ADMTEMP_NUM_SENSORS];
127 	int sc_setdef[ADMTEMP_NUM_SENSORS];
128 	uint8_t sc_highlim[ADMTEMP_NUM_SENSORS];
129 	uint8_t sc_lowlim[ADMTEMP_NUM_SENSORS];
130 	uint8_t sc_highlim2, sc_lowlim2;
131 	uint8_t sc_thermlim[ADMTEMP_NUM_SENSORS];
132 };
133 
134 int	admtemp_match(device_t, cfdata_t, void *);
135 void	admtemp_attach(device_t, device_t, void *);
136 void	admtemp_refresh(struct sysmon_envsys *, envsys_data_t *);
137 void	admtemp_getlim_1021(struct sysmon_envsys *, envsys_data_t *,
138 			sysmon_envsys_lim_t *, uint32_t *);
139 void	admtemp_getlim_1023(struct sysmon_envsys *, envsys_data_t *,
140 			sysmon_envsys_lim_t *, uint32_t *);
141 void	admtemp_getlim_1032(struct sysmon_envsys *, envsys_data_t *,
142 			sysmon_envsys_lim_t *, uint32_t *);
143 void	admtemp_setlim_1021(struct sysmon_envsys *, envsys_data_t *,
144 			sysmon_envsys_lim_t *, uint32_t *);
145 void	admtemp_setlim_1023(struct sysmon_envsys *, envsys_data_t *,
146 			sysmon_envsys_lim_t *, uint32_t *);
147 void	admtemp_setlim_1032(struct sysmon_envsys *, envsys_data_t *,
148 			sysmon_envsys_lim_t *, uint32_t *);
149 
150 CFATTACH_DECL_NEW(admtemp, sizeof(struct admtemp_softc),
151 	admtemp_match, admtemp_attach, NULL, NULL);
152 
153 /* XXX: add flags for compats to admtemp_setflags() */
154 static const char * admtemp_compats[] = {
155 	"i2c-max1617",
156 	"max6642",
157 	"max6690",
158 	NULL
159 };
160 
161 int
162 admtemp_match(device_t parent, cfdata_t match, void *aux)
163 {
164 	struct i2c_attach_args *ia = aux;
165 
166 	if (ia->ia_name == NULL) {
167 		/*
168 		 * Indirect config - not much we can do!
169 		 * Check typical addresses.
170 		 */
171 		if (((ia->ia_addr >= 0x18) && (ia->ia_addr <= 0x1a)) ||
172 		    ((ia->ia_addr >= 0x29) && (ia->ia_addr <= 0x2b)) ||
173 		    ((ia->ia_addr >= 0x48) && (ia->ia_addr <= 0x4e)))
174 			return (1);
175 	} else {
176 		/*
177 		 * Direct config - match via the list of compatible
178 		 * hardware or simply match the device name.
179 		 */
180 		if (ia->ia_ncompat > 0) {
181 			if (iic_compat_match(ia, admtemp_compats))
182 				return 1;
183 		} else {
184 			if (strcmp(ia->ia_name, "admtemp") == 0)
185 				return 1;
186 		}
187 	}
188 
189 	return 0;
190 }
191 
192 static int
193 admtemp_exec(struct admtemp_softc *sc, i2c_op_t op, uint8_t *cmd,
194     uint8_t *data)
195 {
196 	return iic_exec(sc->sc_tag, op, sc->sc_addr, cmd, sizeof(*cmd), data,
197 	    sizeof(*data), 0);
198 }
199 
200 /*
201  * Set flags based on chip type for direct config, or by testing for
202  * indirect config.
203  *
204  * LM84, MAX1617, and NE1617A don't have company/revision registers.
205  * If we can't read the company register, we'll check the
206  * internal low limit to see if we have an LM84.
207  *
208  * To check if an ADM chip has 11-bit sensors, we'll write 0.125
209  * to the external temperature limit low byte register and read it
210  * back (because we can't tell from the id/rev).
211  *
212  * To check if an ADM chip has a Therm output, we check that we
213  * read 0x55 (default value) from the external therm limit.
214  *
215  * If an ADM chip doesn't have 11-bit sensors, check the revision to
216  * determine if it handles negative temperatures.
217  */
218 static void
219 admtemp_setflags(struct admtemp_softc *sc, struct i2c_attach_args *ia,
220     uint8_t* comp, uint8_t *rev, char* name)
221 {
222 	uint8_t cmd, data, tmp;
223 	int i;
224 
225 	*comp = 0;
226 	*rev = 0;
227 
228 	cmd = ADM1021_COMPANY;
229 	admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, comp);
230 
231 	cmd = ADM1021_DIE_REVISION;
232 	admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, rev);
233 
234 	sc->sc_noneg = 1;
235 	sc->sc_nolow = 0;
236 	sc->sc_ext11 = 0;
237 	sc->sc_therm = 0;
238 
239 	/* Direct config */
240 	for (i = 0; i < ia->ia_ncompat; i++) {
241 		if (strcmp("i2c-max1617", ia->ia_compat[i]) == 0) {
242 			sc->sc_noneg = 0;
243 			strlcpy(name, "MAX1617A", ADMTEMP_NAMELEN);
244 			return;
245 		}
246 		if (strcmp("max6642", ia->ia_compat[i]) == 0) {
247 			sc->sc_noneg = 0;
248 			sc->sc_nolow = 1;
249 			strlcpy(name, "MAX6642", ADMTEMP_NAMELEN);
250 			return;
251 		}
252 		if (strcmp("max6690", ia->ia_compat[i]) == 0) {
253 			sc->sc_noneg = 0;
254 			sc->sc_ext11 = 1;
255 			strlcpy(name, "MAX6690", ADMTEMP_NAMELEN);
256 			return;
257 		}
258 	}
259 
260 	/* Indirect config */
261 	if (*comp == 0) {
262 		sc->sc_noneg = 0;
263 		cmd = ADM1021_INT_LOW_READ;
264 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, comp) == 0 &&
265 		    *comp != ADMTEMP_LOW_DEFAULT) {
266 			sc->sc_nolow = 1;
267 			strlcpy(name, "LM84", ADMTEMP_NAMELEN);
268 		} else
269 			strlcpy(name, "MAX1617", ADMTEMP_NAMELEN);
270 	}
271 
272 	if (*comp == ADM1021_COMPANY_MAXIM) {
273 		sc->sc_noneg = 0;
274 		/*
275 		 * MAX6642 doesn't have a revision register
276 		 * XXX this works only on macppc with iic at pmu because the
277 		 * pmu doesn't return an error for nonexistant registers, it
278 		 * just repeats previous data
279 		 */
280 		if (*comp == *rev) {
281 			sc->sc_therm = 0;	/* */
282 			sc->sc_nolow = 1;
283 			strlcpy(name, "MAX6642", ADMTEMP_NAMELEN);
284 		} else if (*rev == 0) {
285 			strlcpy(name, "MAX6690", ADMTEMP_NAMELEN);
286 			sc->sc_ext11 = 1;
287 		} else {
288 			strlcpy(name, "MAX1617A", ADMTEMP_NAMELEN);
289 		}
290 	}
291 
292 	if (*comp == ADM1021_COMPANY_GMT) {
293 		sc->sc_ext11 = 1;
294 		sc->sc_therm = 1;
295 		strlcpy(name, "G781", ADMTEMP_NAMELEN);
296 	}
297 
298 	if (*comp == ADM1021_COMPANY_ADM) {
299 		cmd = ADM1023_EXT_HIGH2;
300 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &data) == 0) {
301 			tmp = 1 << ADM1023_EXT2_SHIFT;
302 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &tmp);
303 			if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd,
304 			    &tmp) == 0 && tmp == 1 << ADM1023_EXT2_SHIFT) {
305 				sc->sc_ext11 = 1;
306 				strlcpy(name, "ADM1023", ADMTEMP_NAMELEN);
307 			}
308 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &data);
309 		}
310 		cmd = ADM1032_EXT_THERM;
311 		if (sc->sc_ext11 &&
312 		    admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &data) == 0
313 		    && data == 0x55) {
314 			sc->sc_therm = 1;
315 			strlcpy(name, "ADM1032", ADMTEMP_NAMELEN);
316 		}
317 		if (!sc->sc_ext11 &&
318 		    (*rev & ADM1021_REV_MASK) == ADM1021_REV_1021A) {
319 			sc->sc_noneg = 0;
320 			strlcpy(name, "ADM1021A", ADMTEMP_NAMELEN);
321 		} else
322 			strlcpy(name, "ADM1021", ADMTEMP_NAMELEN);
323 	}
324 }
325 
326 void
327 admtemp_attach(device_t parent, device_t self, void *aux)
328 {
329 	struct admtemp_softc *sc = device_private(self);
330 	struct i2c_attach_args *ia = aux;
331 	uint8_t cmd, data, stat, comp, rev;
332 	char name[ADMTEMP_NAMELEN];
333 #ifdef HAVE_OF
334 	char ename[64], iname[64];
335 	int ch;
336 #endif
337 	sc->sc_tag = ia->ia_tag;
338 	sc->sc_addr = ia->ia_addr;
339 
340 	iic_acquire_bus(sc->sc_tag, 0);
341 	cmd = ADM1021_CONFIG_READ;
342 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &data) != 0) {
343 		iic_release_bus(sc->sc_tag, 0);
344 		aprint_error_dev(self, "cannot get control register\n");
345 		return;
346 	}
347 	if (data & ADM1021_CONFIG_RUN) {
348 		cmd = ADM1021_STATUS;
349 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &stat)) {
350 			iic_release_bus(sc->sc_tag, 0);
351 			aprint_error_dev(self,
352 			    "cannot read status register\n");
353 			return;
354 		}
355 		if ((stat & ADM1021_STATUS_INVAL) == ADM1021_STATUS_INVAL) {
356 			if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd,
357 			    &stat)) {
358 				iic_release_bus(sc->sc_tag, 0);
359 				aprint_error_dev(self,
360 				    "cannot read status register\n");
361 				return;
362 			}
363 		}
364 
365 		/* means external is dead */
366 		if ((stat & ADM1021_STATUS_INVAL) != ADM1021_STATUS_INVAL &&
367 		    (stat & ADM1021_STATUS_NOEXT))
368 			sc->sc_noexternal = 1;
369 
370 		data &= ~ADM1021_CONFIG_RUN;
371 		cmd = ADM1021_CONFIG_WRITE;
372 		if (admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &data)) {
373 			iic_release_bus(sc->sc_tag, 0);
374 			aprint_error_dev(self,
375 			    "cannot set control register\n");
376 			return;
377 		}
378 	}
379 
380 	admtemp_setflags(sc, ia, &comp, &rev, name);
381 
382 	iic_release_bus(sc->sc_tag, 0);
383 
384 	aprint_normal(": %s temperature sensor", name);
385 	if (comp)
386 		aprint_normal(": id. 0x%02x, rev. 0x%02x\n", comp, rev);
387 	else
388 		aprint_normal("\n");
389 	aprint_naive(": Temperature sensor\n");
390 
391 	/* Initialize sensor data. */
392 	sc->sc_sensor[ADMTEMP_INT].state = ENVSYS_SINVALID;
393 	sc->sc_sensor[ADMTEMP_INT].units = ENVSYS_STEMP;
394 	sc->sc_sensor[ADMTEMP_EXT].state = ENVSYS_SINVALID;
395 	sc->sc_sensor[ADMTEMP_EXT].units = ENVSYS_STEMP;
396 	sc->sc_sensor[ADMTEMP_INT].flags = ENVSYS_FMONLIMITS;
397 	sc->sc_sensor[ADMTEMP_EXT].flags = ENVSYS_FMONLIMITS;
398 #ifdef HAVE_OF
399 	strcpy(iname, "internal");
400 	strcpy(ename, "external");
401 	ch = OF_child(ia->ia_cookie);
402 	if (ch != 0) {
403 		OF_getprop(ch, "location", iname, 64);
404 		ch = OF_peer(ch);
405 		if (ch != 0) {
406 			OF_getprop(ch, "location", ename, 64);
407 		}
408 	}
409 	strlcpy(sc->sc_sensor[ADMTEMP_INT].desc, iname,
410 	    sizeof(sc->sc_sensor[ADMTEMP_INT].desc));
411 	strlcpy(sc->sc_sensor[ADMTEMP_EXT].desc, ename,
412 	    sizeof(sc->sc_sensor[ADMTEMP_EXT].desc));
413 #else
414 	strlcpy(sc->sc_sensor[ADMTEMP_INT].desc, "internal",
415 	    sizeof(sc->sc_sensor[ADMTEMP_INT].desc));
416 	strlcpy(sc->sc_sensor[ADMTEMP_EXT].desc, "external",
417 	    sizeof(sc->sc_sensor[ADMTEMP_EXT].desc));
418 #endif
419 	sc->sc_sme = sysmon_envsys_create();
420 	if (sysmon_envsys_sensor_attach(
421 	    sc->sc_sme, &sc->sc_sensor[ADMTEMP_INT])) {
422 		sysmon_envsys_destroy(sc->sc_sme);
423 		aprint_error_dev(self,
424 		    "unable to attach internal at sysmon\n");
425 		return;
426 	}
427 	if (sc->sc_noexternal == 0 &&
428 	    sysmon_envsys_sensor_attach(
429 	    sc->sc_sme, &sc->sc_sensor[ADMTEMP_EXT])) {
430 		sysmon_envsys_destroy(sc->sc_sme);
431 		aprint_error_dev(self,
432 		    "unable to attach external at sysmon\n");
433 		return;
434 	}
435         sc->sc_sme->sme_name = device_xname(self);
436         sc->sc_sme->sme_cookie = sc;
437         sc->sc_sme->sme_refresh = admtemp_refresh;
438 	if (sc->sc_therm) {
439 		sc->sc_sme->sme_get_limits = admtemp_getlim_1032;
440 		sc->sc_sme->sme_set_limits = admtemp_setlim_1032;
441 	} else if (sc->sc_ext11) {
442 		sc->sc_sme->sme_get_limits = admtemp_getlim_1023;
443 		sc->sc_sme->sme_set_limits = admtemp_setlim_1023;
444 	} else {
445 		sc->sc_sme->sme_get_limits = admtemp_getlim_1021;
446 		sc->sc_sme->sme_set_limits = admtemp_setlim_1021;
447 	}
448 	if (sysmon_envsys_register(sc->sc_sme)) {
449 		aprint_error_dev(self,
450 		    "unable to register with sysmon\n");
451 		sysmon_envsys_destroy(sc->sc_sme);
452 		return;
453 	}
454 }
455 
456 
457 void
458 admtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
459 {
460 	struct admtemp_softc *sc = sme->sme_cookie;
461 	uint8_t cmd, xdata;
462 	int8_t sdata;
463 
464 	iic_acquire_bus(sc->sc_tag, 0);
465 
466 	if (edata->sensor == ADMTEMP_INT)
467 		cmd = ADM1021_INT_TEMP;
468 	else
469 		cmd = ADM1021_EXT_TEMP;
470 
471 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &sdata) == 0) {
472 		if (sdata == ADM1021_STATUS_INVAL) {
473 			edata->state = ENVSYS_SINVALID;
474 		} else {
475 			edata->value_cur = 273150000 + 1000000 * sdata;
476 			edata->state = ENVSYS_SVALID;
477 		}
478 	}
479 	if (edata->sensor == ADMTEMP_EXT && sc->sc_ext11) {
480 		cmd = ADM1023_EXT_TEMP2;
481 		admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xdata);
482 		edata->value_cur +=
483 		    (xdata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK) * 125000;
484 	}
485 
486 	iic_release_bus(sc->sc_tag, 0);
487 }
488 
489 void
490 admtemp_getlim_1021(struct sysmon_envsys *sme, envsys_data_t *edata,
491 	sysmon_envsys_lim_t *limits, uint32_t *props)
492 {
493 	struct admtemp_softc *sc = sme->sme_cookie;
494 	uint8_t cmd;
495 	int8_t hdata = 0x7f, ldata = 0xc9;
496 
497 	*props &= ~(PROP_CRITMAX | PROP_CRITMIN);
498 
499 	iic_acquire_bus(sc->sc_tag, 0);
500 
501 	if (edata->sensor == ADMTEMP_INT)
502 		cmd = ADM1021_INT_HIGH_READ;
503 	else
504 		cmd = ADM1021_EXT_HIGH_READ;
505 
506 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &hdata) == 0 &&
507 	    hdata != ADMTEMP_LIM_INVAL) {
508 		limits->sel_critmax = 273150000 + 1000000 * hdata;
509 		*props |= PROP_CRITMAX;
510 	}
511 
512 	if (sc->sc_nolow == 1) {
513 		goto release;
514 	}
515 
516 	if (edata->sensor == ADMTEMP_INT)
517 		cmd = ADM1021_INT_LOW_READ;
518 	else
519 		cmd = ADM1021_EXT_LOW_READ;
520 
521 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &ldata) == 0 &&
522 	    ldata != ADMTEMP_LIM_INVAL) {
523 		limits->sel_critmin = 273150000 + 1000000 * ldata;
524 		*props |= PROP_CRITMIN;
525 	}
526 
527 release:
528 	iic_release_bus(sc->sc_tag, 0);
529 
530 	/* Save the values if this is the first time through. */
531 	if (sc->sc_setdef[edata->sensor] == 0) {
532 		sc->sc_setdef[edata->sensor] = 1;
533 		sc->sc_highlim[edata->sensor] = hdata;
534 		sc->sc_lowlim[edata->sensor] = ldata;
535 	}
536 }
537 
538 void
539 admtemp_getlim_1023(struct sysmon_envsys *sme, envsys_data_t *edata,
540 	sysmon_envsys_lim_t *limits, uint32_t *props)
541 {
542 	struct admtemp_softc *sc = sme->sme_cookie;
543 	uint8_t cmd, xhdata = 0, xldata = 0;
544 	int8_t hdata = 0x7f, ldata = 0xc9;
545 
546 	*props &= ~(PROP_CRITMAX | PROP_CRITMIN);
547 
548 	iic_acquire_bus(sc->sc_tag, 0);
549 
550 	if (edata->sensor == ADMTEMP_INT)
551 		cmd = ADM1021_INT_HIGH_READ;
552 	else
553 		cmd = ADM1021_EXT_HIGH_READ;
554 
555 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &hdata) == 0 &&
556 	    hdata != ADMTEMP_LIM_INVAL) {
557 		limits->sel_critmax = 273150000 + 1000000 * hdata;
558 		*props |= PROP_CRITMAX;
559 	}
560 
561 	if (edata->sensor == ADMTEMP_EXT) {
562 		cmd = ADM1023_EXT_HIGH2;
563 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xhdata) == 0)
564 			limits->sel_critmax +=
565 			    (xhdata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK)
566 			    * 125000;
567 	}
568 
569 	if (edata->sensor == ADMTEMP_INT)
570 		cmd = ADM1021_INT_LOW_READ;
571 	else
572 		cmd = ADM1021_EXT_LOW_READ;
573 
574 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &ldata) == 0 &&
575 	    ldata != ADMTEMP_LIM_INVAL) {
576 		limits->sel_critmin = 273150000 + 1000000 * ldata;
577 		*props |= PROP_CRITMIN;
578 	}
579 
580 	if (edata->sensor == ADMTEMP_EXT) {
581 		cmd = ADM1023_EXT_LOW2;
582 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xldata) == 0)
583 			limits->sel_critmin +=
584 			    (xldata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK)
585 				* 125000;
586 	}
587 
588 	iic_release_bus(sc->sc_tag, 0);
589 
590 	/* Save the values if this is the first time through. */
591 	if (sc->sc_setdef[edata->sensor] == 0) {
592 		sc->sc_setdef[edata->sensor] = 1;
593 		sc->sc_highlim[edata->sensor] = hdata;
594 		sc->sc_lowlim[edata->sensor] = ldata;
595 		if (edata->sensor == ADMTEMP_EXT) {
596 			sc->sc_highlim2 = xhdata;
597 			sc->sc_lowlim2 = xldata;
598 		}
599 	}
600 }
601 
602 void
603 admtemp_getlim_1032(struct sysmon_envsys *sme, envsys_data_t *edata,
604 	sysmon_envsys_lim_t *limits, uint32_t *props)
605 {
606 	struct admtemp_softc *sc = sme->sme_cookie;
607 	uint8_t cmd, xhdata = 0, xldata = 0;
608 	int8_t tdata = 0x55, hdata = 0x55, ldata = 0;
609 
610 	*props &= ~(PROP_WARNMAX | PROP_CRITMAX | PROP_WARNMIN);
611 
612 	iic_acquire_bus(sc->sc_tag, 0);
613 
614 	if (edata->sensor == ADMTEMP_INT)
615 		cmd = ADM1032_INT_THERM;
616 	else
617 		cmd = ADM1032_EXT_THERM;
618 
619 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &tdata) == 0 &&
620 	    tdata != ADMTEMP_LIM_INVAL) {
621 		limits->sel_critmax = 273150000 + 1000000 * tdata;
622 		*props |= PROP_CRITMAX;
623 	}
624 
625 	if (edata->sensor == ADMTEMP_INT)
626 		cmd = ADM1021_INT_HIGH_READ;
627 	else
628 		cmd = ADM1021_EXT_HIGH_READ;
629 
630 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &hdata) == 0 &&
631 	    hdata != ADMTEMP_LIM_INVAL) {
632 		limits->sel_warnmax = 273150000 + 1000000 * hdata;
633 		*props |= PROP_WARNMAX;
634 	}
635 
636 	if (edata->sensor == ADMTEMP_EXT) {
637 		cmd = ADM1023_EXT_HIGH2;
638 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xhdata) == 0)
639 			limits->sel_warnmax +=
640 			    (xhdata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK)
641 			        * 125000;
642 	}
643 
644 	if (edata->sensor == ADMTEMP_INT)
645 		cmd = ADM1021_INT_LOW_READ;
646 	else
647 		cmd = ADM1021_EXT_LOW_READ;
648 
649 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &ldata) == 0 &&
650 	    ldata != ADMTEMP_LIM_INVAL) {
651 		limits->sel_warnmin = 273150000 + 1000000 * ldata;
652 		*props |= PROP_WARNMIN;
653 	}
654 
655 	if (edata->sensor == ADMTEMP_EXT) {
656 		cmd = ADM1023_EXT_LOW2;
657 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xldata) == 0)
658 			limits->sel_warnmin +=
659 			    (xldata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK)
660 			        * 125000;
661 	}
662 
663 	iic_release_bus(sc->sc_tag, 0);
664 
665 	/* Save the values if this is the first time through. */
666 	if (sc->sc_setdef[edata->sensor] == 0) {
667 		sc->sc_setdef[edata->sensor] = 1;
668 		sc->sc_thermlim[edata->sensor] = tdata;
669 		sc->sc_highlim[edata->sensor] = hdata;
670 		sc->sc_lowlim[edata->sensor] = ldata;
671 		if (edata->sensor == ADMTEMP_EXT) {
672 			sc->sc_highlim2 = xhdata;
673 			sc->sc_lowlim2 = xldata;
674 		}
675 	}
676 }
677 
678 void
679 admtemp_setlim_1021(struct sysmon_envsys *sme, envsys_data_t *edata,
680 	sysmon_envsys_lim_t *limits, uint32_t *props)
681 {
682 	struct admtemp_softc *sc = sme->sme_cookie;
683 	uint8_t cmd;
684 	int tmp;
685 	int8_t sdata;
686 
687 	iic_acquire_bus(sc->sc_tag, 0);
688 
689 	if (*props & PROP_CRITMAX) {
690 		if (edata->sensor == ADMTEMP_INT)
691 			cmd = ADM1021_INT_HIGH_WRITE;
692 		else
693 			cmd = ADM1021_EXT_HIGH_WRITE;
694 
695 		if (limits == NULL)	/* Restore defaults */
696 			sdata = sc->sc_highlim[edata->sensor];
697 		else {
698 			tmp = (limits->sel_critmax - 273150000) / 1000000;
699 			if (tmp > ADMTEMP_MAX_POS)
700 				sdata = ADMTEMP_MAX_POS;
701 			else if (tmp < 0 && sc->sc_noneg)
702 				sdata = 0;
703 			else if (tmp < ADMTEMP_MAX_NEG)
704 				sdata = ADMTEMP_MAX_NEG;
705 			else
706 				sdata = tmp & 0xff;
707 		}
708 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
709 	}
710 
711 	if (*props & PROP_CRITMIN && sc->sc_nolow == 0) {
712 		if (edata->sensor == ADMTEMP_INT)
713 			cmd = ADM1021_INT_LOW_WRITE;
714 		else
715 			cmd = ADM1021_EXT_LOW_WRITE;
716 		if (limits == NULL)
717 			sdata = sc->sc_lowlim[edata->sensor];
718 		else {
719 			tmp = (limits->sel_critmin - 273150000) / 1000000;
720 			if (tmp > ADMTEMP_MAX_POS)
721 				sdata = ADMTEMP_MAX_POS;
722 			else if (tmp < 0 && sc->sc_noneg)
723 				sdata = 0;
724 			else if (tmp < ADMTEMP_MAX_NEG)
725 				sdata = ADMTEMP_MAX_NEG;
726 			else
727 				sdata = tmp & 0xff;
728 		}
729 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
730 	}
731 
732 	iic_release_bus(sc->sc_tag, 0);
733 }
734 
735 static void
736 admtemp_encode_temp(const uint32_t val, int8_t *sdata, uint8_t *xdata,
737     const int ext11)
738 {
739 	int32_t tmp;
740 
741 	if (ext11) {
742 		/* Split temperature into high and low bytes */
743 		tmp = (val - 273150000) / 125000;
744 		*xdata = (tmp & ADM1023_EXT2_MASK) << ADM1023_EXT2_SHIFT;
745 		tmp -= (int32_t) (*xdata >> ADM1023_EXT2_SHIFT);
746 		tmp /= 8;	/* 1000000 / 125000 */
747 	} else {
748 		*xdata = 0;
749 		tmp = (val - 273150000) / 1000000;
750 	}
751 	if (tmp > ADMTEMP_MAX_POS)
752 		*sdata = ADMTEMP_MAX_POS;
753 	else if (tmp < 0)
754 		*sdata = 0;
755 	else
756 		*sdata = tmp & 0xff;
757 }
758 
759 void
760 admtemp_setlim_1023(struct sysmon_envsys *sme, envsys_data_t *edata,
761 	sysmon_envsys_lim_t *limits, uint32_t *props)
762 {
763 	struct admtemp_softc *sc = sme->sme_cookie;
764 	int ext11;
765 	uint8_t cmd, xdata;
766 	int8_t sdata;
767 
768 	if (edata->sensor == ADMTEMP_INT)
769 		ext11 = 0;
770 	else
771 		ext11 = 1;
772 
773 	iic_acquire_bus(sc->sc_tag, 0);
774 
775 	if (*props & PROP_CRITMAX) {
776 		if (edata->sensor == ADMTEMP_INT)
777 			cmd = ADM1021_INT_HIGH_WRITE;
778 		else
779 			cmd = ADM1021_EXT_HIGH_WRITE;
780 
781 		if (limits == NULL) {	/* Restore defaults */
782 			sdata = sc->sc_highlim[edata->sensor];
783 			xdata = sc->sc_highlim2;
784 		} else
785 			admtemp_encode_temp(limits->sel_critmax, &sdata,
786 			    &xdata, ext11);
787 
788 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
789 		if (ext11) {
790 			cmd = ADM1023_EXT_HIGH2;
791 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &xdata);
792 		}
793 	}
794 
795 	if (*props & PROP_CRITMIN) {
796 		if (edata->sensor == ADMTEMP_INT)
797 			cmd = ADM1021_INT_LOW_WRITE;
798 		else
799 			cmd = ADM1021_EXT_LOW_WRITE;
800 		if (limits == NULL) {
801 			sdata = sc->sc_lowlim[edata->sensor];
802 			xdata = sc->sc_lowlim2;
803 		} else
804 			admtemp_encode_temp(limits->sel_critmax, &sdata,
805 			    &xdata, ext11);
806 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
807 		if (ext11) {
808 			cmd = ADM1023_EXT_LOW2;
809 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &xdata);
810 		}
811 	}
812 
813 	iic_release_bus(sc->sc_tag, 0);
814 }
815 
816 void
817 admtemp_setlim_1032(struct sysmon_envsys *sme, envsys_data_t *edata,
818 	sysmon_envsys_lim_t *limits, uint32_t *props)
819 {
820 	struct admtemp_softc *sc = sme->sme_cookie;
821 	int ext11;
822 	uint8_t cmd, xdata;
823 	int8_t sdata;
824 
825 	if (edata->sensor == ADMTEMP_INT)
826 		ext11 = 0;
827 	else
828 		ext11 = 1;
829 
830 	iic_acquire_bus(sc->sc_tag, 0);
831 
832 	if (*props & PROP_CRITMAX) {
833 		if (edata->sensor == ADMTEMP_INT)
834 			cmd = ADM1032_INT_THERM;
835 		else
836 			cmd = ADM1032_EXT_THERM;
837 		if (limits == NULL)	/* Restore default */
838 			sdata = sc->sc_thermlim[edata->sensor];
839 		else
840 			admtemp_encode_temp(limits->sel_critmax, &sdata,
841 			    &xdata, 0);
842 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
843 	}
844 
845 	if (*props & PROP_WARNMAX) {
846 		if (edata->sensor == ADMTEMP_INT)
847 			cmd = ADM1021_INT_HIGH_WRITE;
848 		else
849 			cmd = ADM1021_EXT_HIGH_WRITE;
850 
851 		if (limits == NULL) {	/* Restore defaults */
852 			sdata = sc->sc_highlim[edata->sensor];
853 			xdata = sc->sc_highlim2;
854 		} else
855 			admtemp_encode_temp(limits->sel_warnmax, &sdata,
856 			    &xdata, ext11);
857 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
858 
859 		if (ext11) {
860 			cmd = ADM1023_EXT_HIGH2;
861 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &xdata);
862 		}
863 	}
864 
865 	if (*props & PROP_WARNMIN) {
866 		if (edata->sensor == ADMTEMP_INT)
867 			cmd = ADM1021_INT_LOW_WRITE;
868 		else
869 			cmd = ADM1021_EXT_LOW_WRITE;
870 		if (limits == NULL) {
871 			sdata = sc->sc_lowlim[edata->sensor];
872 			xdata = sc->sc_lowlim2;
873 		} else
874 			admtemp_encode_temp(limits->sel_warnmin, &sdata,
875 			    &xdata, ext11);
876 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
877 
878 		if (ext11) {
879 			cmd = ADM1023_EXT_LOW2;
880 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &xdata);
881 		}
882 	}
883 
884 	iic_release_bus(sc->sc_tag, 0);
885 }
886