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