xref: /netbsd-src/sys/dev/i2c/adm1021.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1 /*	$NetBSD: adm1021.c,v 1.12 2016/01/04 19:24:15 christos 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, and Xeon embedded temperature sensors.
24  *
25  * Some sensors differ from the ADM1021/MAX1617/NE1617A:
26  *                         ADM1021A ADM1023 ADM1032 G781 LM84 MAX1617A
27  *   company/revision reg  X        X       X       X         X
28  *   no negative temps     X        X       X       X
29  *   11-bit remote temp             X       X       X
30  *   no low limits                                       X
31  *   therm (high) limits                    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.12 2016/01/04 19:24:15 christos 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 
114 	int		sc_flags;
115 	int		sc_noexternal, sc_noneg, sc_nolow;
116 	int		sc_ext11, sc_therm;
117 	struct sysmon_envsys *sc_sme;
118 	envsys_data_t sc_sensor[ADMTEMP_NUM_SENSORS];
119 	int sc_setdef[ADMTEMP_NUM_SENSORS];
120 	uint8_t sc_highlim[ADMTEMP_NUM_SENSORS];
121 	uint8_t sc_lowlim[ADMTEMP_NUM_SENSORS];
122 	uint8_t sc_highlim2, sc_lowlim2;
123 	uint8_t sc_thermlim[ADMTEMP_NUM_SENSORS];
124 };
125 
126 int	admtemp_match(device_t, cfdata_t, void *);
127 void	admtemp_attach(device_t, device_t, void *);
128 void	admtemp_refresh(struct sysmon_envsys *, envsys_data_t *);
129 void	admtemp_getlim_1021(struct sysmon_envsys *, envsys_data_t *,
130 			sysmon_envsys_lim_t *, uint32_t *);
131 void	admtemp_getlim_1023(struct sysmon_envsys *, envsys_data_t *,
132 			sysmon_envsys_lim_t *, uint32_t *);
133 void	admtemp_getlim_1032(struct sysmon_envsys *, envsys_data_t *,
134 			sysmon_envsys_lim_t *, uint32_t *);
135 void	admtemp_setlim_1021(struct sysmon_envsys *, envsys_data_t *,
136 			sysmon_envsys_lim_t *, uint32_t *);
137 void	admtemp_setlim_1023(struct sysmon_envsys *, envsys_data_t *,
138 			sysmon_envsys_lim_t *, uint32_t *);
139 void	admtemp_setlim_1032(struct sysmon_envsys *, envsys_data_t *,
140 			sysmon_envsys_lim_t *, uint32_t *);
141 
142 CFATTACH_DECL_NEW(admtemp, sizeof(struct admtemp_softc),
143 	admtemp_match, admtemp_attach, NULL, NULL);
144 
145 /* XXX: add flags for compats to admtemp_setflags() */
146 static const char * admtemp_compats[] = {
147 	"i2c-max1617",
148 	NULL
149 };
150 
151 int
152 admtemp_match(device_t parent, cfdata_t match, void *aux)
153 {
154 	struct i2c_attach_args *ia = aux;
155 
156 	if (ia->ia_name == NULL) {
157 		/*
158 		 * Indirect config - not much we can do!
159 		 * Check typical addresses.
160 		 */
161 		if (((ia->ia_addr >= 0x18) && (ia->ia_addr <= 0x1a)) ||
162 		    ((ia->ia_addr >= 0x29) && (ia->ia_addr <= 0x2b)) ||
163 		    ((ia->ia_addr >= 0x4c) && (ia->ia_addr <= 0x4e)))
164 			return (1);
165 	} else {
166 		/*
167 		 * Direct config - match via the list of compatible
168 		 * hardware or simply match the device name.
169 		 */
170 		if (ia->ia_ncompat > 0) {
171 			if (iic_compat_match(ia, admtemp_compats))
172 				return 1;
173 		} else {
174 			if (strcmp(ia->ia_name, "admtemp") == 0)
175 				return 1;
176 		}
177 	}
178 
179 	return 0;
180 }
181 
182 static int
183 admtemp_exec(struct admtemp_softc *sc, i2c_op_t op, uint8_t *cmd,
184     uint8_t *data)
185 {
186 	return iic_exec(sc->sc_tag, op, sc->sc_addr, cmd, sizeof(*cmd), data,
187 	    sizeof(*data), 0);
188 }
189 
190 /*
191  * Set flags based on chip type for direct config, or by testing for
192  * indirect config.
193  *
194  * LM84, MAX1617, and NE1617A don't have company/revision registers.
195  * If we can't read the company register, we'll check the
196  * internal low limit to see if we have an LM84.
197  *
198  * To check if an ADM chip has 11-bit sensors, we'll write 0.125
199  * to the external temperature limit low byte register and read it
200  * back (because we can't tell from the id/rev).
201  *
202  * To check if an ADM chip has a Therm output, we check that we
203  * read 0x55 (default value) from the external therm limit.
204  *
205  * If an ADM chip doesn't have 11-bit sensors, check the revision to
206  * determine if it handles negative temperatures.
207  */
208 static void
209 admtemp_setflags(struct admtemp_softc *sc, struct i2c_attach_args *ia,
210     uint8_t* comp, uint8_t *rev, char* name)
211 {
212 	uint8_t cmd, data, tmp;
213 	int i;
214 
215 	*comp = 0;
216 	*rev = 0;
217 
218 	cmd = ADM1021_COMPANY;
219 	admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, comp);
220 
221 	cmd = ADM1021_DIE_REVISION;
222 	admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, rev);
223 
224 	sc->sc_noneg = 1;
225 	sc->sc_nolow = 0;
226 	sc->sc_ext11 = 0;
227 	sc->sc_therm = 0;
228 
229 	/* Direct config */
230 	for (i = 0; i < ia->ia_ncompat; i++) {
231 		if (strcmp("i2c-max1617", ia->ia_compat[i]) == 0) {
232 			sc->sc_noneg = 0;
233 			strlcpy(name, "MAX1617A", ADMTEMP_NAMELEN);
234 			return;
235 		}
236 	}
237 
238 	/* Indirect config */
239 	if (*comp == 0) {
240 		sc->sc_noneg = 0;
241 		cmd = ADM1021_INT_LOW_READ;
242 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, comp) == 0 &&
243 		    *comp != ADMTEMP_LOW_DEFAULT) {
244 			sc->sc_nolow = 1;
245 			strlcpy(name, "LM84", ADMTEMP_NAMELEN);
246 		} else
247 			strlcpy(name, "MAX1617", ADMTEMP_NAMELEN);
248 	}
249 
250 	if (*comp == ADM1021_COMPANY_MAXIM) {
251 		sc->sc_noneg = 0;
252 		strlcpy(name, "MAX1617A", ADMTEMP_NAMELEN);
253 	}
254 
255 	if (*comp == ADM1021_COMPANY_GMT) {
256 		sc->sc_ext11 = 1;
257 		sc->sc_therm = 1;
258 		strlcpy(name, "G781", ADMTEMP_NAMELEN);
259 	}
260 
261 	if (*comp == ADM1021_COMPANY_ADM) {
262 		cmd = ADM1023_EXT_HIGH2;
263 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &data) == 0) {
264 			tmp = 1 << ADM1023_EXT2_SHIFT;
265 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &tmp);
266 			if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd,
267 			    &tmp) == 0 && tmp == 1 << ADM1023_EXT2_SHIFT) {
268 				sc->sc_ext11 = 1;
269 				strlcpy(name, "ADM1023", ADMTEMP_NAMELEN);
270 			}
271 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &data);
272 		}
273 		cmd = ADM1032_EXT_THERM;
274 		if (sc->sc_ext11 &&
275 		    admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &data) == 0
276 		    && data == 0x55) {
277 			sc->sc_therm = 1;
278 			strlcpy(name, "ADM1032", ADMTEMP_NAMELEN);
279 		}
280 		if (!sc->sc_ext11 &&
281 		    (*rev & ADM1021_REV_MASK) == ADM1021_REV_1021A) {
282 			sc->sc_noneg = 0;
283 			strlcpy(name, "ADM1021A", ADMTEMP_NAMELEN);
284 		} else
285 			strlcpy(name, "ADM1021", ADMTEMP_NAMELEN);
286 	}
287 }
288 
289 void
290 admtemp_attach(device_t parent, device_t self, void *aux)
291 {
292 	struct admtemp_softc *sc = device_private(self);
293 	struct i2c_attach_args *ia = aux;
294 	uint8_t cmd, data, stat, comp, rev;
295 	char name[ADMTEMP_NAMELEN];
296 
297 	sc->sc_tag = ia->ia_tag;
298 	sc->sc_addr = ia->ia_addr;
299 
300 	iic_acquire_bus(sc->sc_tag, 0);
301 	cmd = ADM1021_CONFIG_READ;
302 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &data) != 0) {
303 		iic_release_bus(sc->sc_tag, 0);
304 		aprint_error_dev(self, "cannot get control register\n");
305 		return;
306 	}
307 	if (data & ADM1021_CONFIG_RUN) {
308 		cmd = ADM1021_STATUS;
309 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &stat)) {
310 			iic_release_bus(sc->sc_tag, 0);
311 			aprint_error_dev(self,
312 			    "cannot read status register\n");
313 			return;
314 		}
315 		if ((stat & ADM1021_STATUS_INVAL) == ADM1021_STATUS_INVAL) {
316 			if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd,
317 			    &stat)) {
318 				iic_release_bus(sc->sc_tag, 0);
319 				aprint_error_dev(self,
320 				    "cannot read status register\n");
321 				return;
322 			}
323 		}
324 
325 		/* means external is dead */
326 		if ((stat & ADM1021_STATUS_INVAL) != ADM1021_STATUS_INVAL &&
327 		    (stat & ADM1021_STATUS_NOEXT))
328 			sc->sc_noexternal = 1;
329 
330 		data &= ~ADM1021_CONFIG_RUN;
331 		cmd = ADM1021_CONFIG_WRITE;
332 		if (admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &data)) {
333 			iic_release_bus(sc->sc_tag, 0);
334 			aprint_error_dev(self,
335 			    "cannot set control register\n");
336 			return;
337 		}
338 	}
339 
340 	admtemp_setflags(sc, ia, &comp, &rev, name);
341 
342 	iic_release_bus(sc->sc_tag, 0);
343 
344 	aprint_normal(": %s temperature sensor", name);
345 	if (comp)
346 		aprint_normal(": id. 0x%02x, rev. 0x%02x\n", comp, rev);
347 	else
348 		aprint_normal("\n");
349 	aprint_naive(": Temperature sensor\n");
350 
351 	/* Initialize sensor data. */
352 	sc->sc_sensor[ADMTEMP_INT].state = ENVSYS_SINVALID;
353 	sc->sc_sensor[ADMTEMP_INT].units = ENVSYS_STEMP;
354 	sc->sc_sensor[ADMTEMP_EXT].state = ENVSYS_SINVALID;
355 	sc->sc_sensor[ADMTEMP_EXT].units = ENVSYS_STEMP;
356 	sc->sc_sensor[ADMTEMP_INT].flags = ENVSYS_FMONLIMITS;
357 	sc->sc_sensor[ADMTEMP_EXT].flags = ENVSYS_FMONLIMITS;
358 	strlcpy(sc->sc_sensor[ADMTEMP_INT].desc, "internal",
359 	    sizeof(sc->sc_sensor[ADMTEMP_INT].desc));
360 	strlcpy(sc->sc_sensor[ADMTEMP_EXT].desc, "external",
361 	    sizeof(sc->sc_sensor[ADMTEMP_EXT].desc));
362 	sc->sc_sme = sysmon_envsys_create();
363 	if (sysmon_envsys_sensor_attach(
364 	    sc->sc_sme, &sc->sc_sensor[ADMTEMP_INT])) {
365 		sysmon_envsys_destroy(sc->sc_sme);
366 		aprint_error_dev(self,
367 		    "unable to attach internal at sysmon\n");
368 		return;
369 	}
370 	if (sc->sc_noexternal == 0 &&
371 	    sysmon_envsys_sensor_attach(
372 	    sc->sc_sme, &sc->sc_sensor[ADMTEMP_EXT])) {
373 		sysmon_envsys_destroy(sc->sc_sme);
374 		aprint_error_dev(self,
375 		    "unable to attach external at sysmon\n");
376 		return;
377 	}
378         sc->sc_sme->sme_name = device_xname(self);
379         sc->sc_sme->sme_cookie = sc;
380         sc->sc_sme->sme_refresh = admtemp_refresh;
381 	if (sc->sc_therm) {
382 		sc->sc_sme->sme_get_limits = admtemp_getlim_1032;
383 		sc->sc_sme->sme_set_limits = admtemp_setlim_1032;
384 	} else if (sc->sc_ext11) {
385 		sc->sc_sme->sme_get_limits = admtemp_getlim_1023;
386 		sc->sc_sme->sme_set_limits = admtemp_setlim_1023;
387 	} else {
388 		sc->sc_sme->sme_get_limits = admtemp_getlim_1021;
389 		sc->sc_sme->sme_set_limits = admtemp_setlim_1021;
390 	}
391 	if (sysmon_envsys_register(sc->sc_sme)) {
392 		aprint_error_dev(self,
393 		    "unable to register with sysmon\n");
394 		sysmon_envsys_destroy(sc->sc_sme);
395 		return;
396 	}
397 }
398 
399 
400 void
401 admtemp_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
402 {
403 	struct admtemp_softc *sc = sme->sme_cookie;
404 	uint8_t cmd, xdata;
405 	int8_t sdata;
406 
407 	iic_acquire_bus(sc->sc_tag, 0);
408 
409 	if (edata->sensor == ADMTEMP_INT)
410 		cmd = ADM1021_INT_TEMP;
411 	else
412 		cmd = ADM1021_EXT_TEMP;
413 
414 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &sdata) == 0) {
415 		if (sdata == ADM1021_STATUS_INVAL) {
416 			edata->state = ENVSYS_SINVALID;
417 		} else {
418 			edata->value_cur = 273150000 + 1000000 * sdata;
419 			edata->state = ENVSYS_SVALID;
420 		}
421 	}
422 	if (edata->sensor == ADMTEMP_EXT && sc->sc_ext11) {
423 		cmd = ADM1023_EXT_TEMP2;
424 		admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xdata);
425 		edata->value_cur +=
426 		    (xdata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK) * 125000;
427 	}
428 
429 	iic_release_bus(sc->sc_tag, 0);
430 }
431 
432 void
433 admtemp_getlim_1021(struct sysmon_envsys *sme, envsys_data_t *edata,
434 	sysmon_envsys_lim_t *limits, uint32_t *props)
435 {
436 	struct admtemp_softc *sc = sme->sme_cookie;
437 	uint8_t cmd;
438 	int8_t hdata = 0x7f, ldata = 0xc9;
439 
440 	*props &= ~(PROP_CRITMAX | PROP_CRITMIN);
441 
442 	iic_acquire_bus(sc->sc_tag, 0);
443 
444 	if (edata->sensor == ADMTEMP_INT)
445 		cmd = ADM1021_INT_HIGH_READ;
446 	else
447 		cmd = ADM1021_EXT_HIGH_READ;
448 
449 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &hdata) == 0 &&
450 	    hdata != ADMTEMP_LIM_INVAL) {
451 		limits->sel_critmax = 273150000 + 1000000 * hdata;
452 		*props |= PROP_CRITMAX;
453 	}
454 
455 	if (sc->sc_nolow == 1) {
456 		goto release;
457 	}
458 
459 	if (edata->sensor == ADMTEMP_INT)
460 		cmd = ADM1021_INT_LOW_READ;
461 	else
462 		cmd = ADM1021_EXT_LOW_READ;
463 
464 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &ldata) == 0 &&
465 	    ldata != ADMTEMP_LIM_INVAL) {
466 		limits->sel_critmin = 273150000 + 1000000 * ldata;
467 		*props |= PROP_CRITMIN;
468 	}
469 
470 release:
471 	iic_release_bus(sc->sc_tag, 0);
472 
473 	/* Save the values if this is the first time through. */
474 	if (sc->sc_setdef[edata->sensor] == 0) {
475 		sc->sc_setdef[edata->sensor] = 1;
476 		sc->sc_highlim[edata->sensor] = hdata;
477 		sc->sc_lowlim[edata->sensor] = ldata;
478 	}
479 }
480 
481 void
482 admtemp_getlim_1023(struct sysmon_envsys *sme, envsys_data_t *edata,
483 	sysmon_envsys_lim_t *limits, uint32_t *props)
484 {
485 	struct admtemp_softc *sc = sme->sme_cookie;
486 	uint8_t cmd, xhdata = 0, xldata = 0;
487 	int8_t hdata = 0x7f, ldata = 0xc9;
488 
489 	*props &= ~(PROP_CRITMAX | PROP_CRITMIN);
490 
491 	iic_acquire_bus(sc->sc_tag, 0);
492 
493 	if (edata->sensor == ADMTEMP_INT)
494 		cmd = ADM1021_INT_HIGH_READ;
495 	else
496 		cmd = ADM1021_EXT_HIGH_READ;
497 
498 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &hdata) == 0 &&
499 	    hdata != ADMTEMP_LIM_INVAL) {
500 		limits->sel_critmax = 273150000 + 1000000 * hdata;
501 		*props |= PROP_CRITMAX;
502 	}
503 
504 	if (edata->sensor == ADMTEMP_EXT) {
505 		cmd = ADM1023_EXT_HIGH2;
506 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xhdata) == 0)
507 			limits->sel_critmax +=
508 			    (xhdata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK)
509 			    * 125000;
510 	}
511 
512 	if (edata->sensor == ADMTEMP_INT)
513 		cmd = ADM1021_INT_LOW_READ;
514 	else
515 		cmd = ADM1021_EXT_LOW_READ;
516 
517 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &ldata) == 0 &&
518 	    ldata != ADMTEMP_LIM_INVAL) {
519 		limits->sel_critmin = 273150000 + 1000000 * ldata;
520 		*props |= PROP_CRITMIN;
521 	}
522 
523 	if (edata->sensor == ADMTEMP_EXT) {
524 		cmd = ADM1023_EXT_LOW2;
525 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xldata) == 0)
526 			limits->sel_critmin +=
527 			    (xldata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK)
528 				* 125000;
529 	}
530 
531 	iic_release_bus(sc->sc_tag, 0);
532 
533 	/* Save the values if this is the first time through. */
534 	if (sc->sc_setdef[edata->sensor] == 0) {
535 		sc->sc_setdef[edata->sensor] = 1;
536 		sc->sc_highlim[edata->sensor] = hdata;
537 		sc->sc_lowlim[edata->sensor] = ldata;
538 		if (edata->sensor == ADMTEMP_EXT) {
539 			sc->sc_highlim2 = xhdata;
540 			sc->sc_lowlim2 = xldata;
541 		}
542 	}
543 }
544 
545 void
546 admtemp_getlim_1032(struct sysmon_envsys *sme, envsys_data_t *edata,
547 	sysmon_envsys_lim_t *limits, uint32_t *props)
548 {
549 	struct admtemp_softc *sc = sme->sme_cookie;
550 	uint8_t cmd, xhdata = 0, xldata = 0;
551 	int8_t tdata = 0x55, hdata = 0x55, ldata = 0;
552 
553 	*props &= ~(PROP_WARNMAX | PROP_CRITMAX | PROP_WARNMIN);
554 
555 	iic_acquire_bus(sc->sc_tag, 0);
556 
557 	if (edata->sensor == ADMTEMP_INT)
558 		cmd = ADM1032_INT_THERM;
559 	else
560 		cmd = ADM1032_EXT_THERM;
561 
562 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &tdata) == 0 &&
563 	    tdata != ADMTEMP_LIM_INVAL) {
564 		limits->sel_critmax = 273150000 + 1000000 * tdata;
565 		*props |= PROP_CRITMAX;
566 	}
567 
568 	if (edata->sensor == ADMTEMP_INT)
569 		cmd = ADM1021_INT_HIGH_READ;
570 	else
571 		cmd = ADM1021_EXT_HIGH_READ;
572 
573 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &hdata) == 0 &&
574 	    hdata != ADMTEMP_LIM_INVAL) {
575 		limits->sel_warnmax = 273150000 + 1000000 * hdata;
576 		*props |= PROP_WARNMAX;
577 	}
578 
579 	if (edata->sensor == ADMTEMP_EXT) {
580 		cmd = ADM1023_EXT_HIGH2;
581 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xhdata) == 0)
582 			limits->sel_warnmax +=
583 			    (xhdata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK)
584 			        * 125000;
585 	}
586 
587 	if (edata->sensor == ADMTEMP_INT)
588 		cmd = ADM1021_INT_LOW_READ;
589 	else
590 		cmd = ADM1021_EXT_LOW_READ;
591 
592 	if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &ldata) == 0 &&
593 	    ldata != ADMTEMP_LIM_INVAL) {
594 		limits->sel_warnmin = 273150000 + 1000000 * ldata;
595 		*props |= PROP_WARNMIN;
596 	}
597 
598 	if (edata->sensor == ADMTEMP_EXT) {
599 		cmd = ADM1023_EXT_LOW2;
600 		if (admtemp_exec(sc, I2C_OP_READ_WITH_STOP, &cmd, &xldata) == 0)
601 			limits->sel_warnmin +=
602 			    (xldata >> ADM1023_EXT2_SHIFT & ADM1023_EXT2_MASK)
603 			        * 125000;
604 	}
605 
606 	iic_release_bus(sc->sc_tag, 0);
607 
608 	/* Save the values if this is the first time through. */
609 	if (sc->sc_setdef[edata->sensor] == 0) {
610 		sc->sc_setdef[edata->sensor] = 1;
611 		sc->sc_thermlim[edata->sensor] = tdata;
612 		sc->sc_highlim[edata->sensor] = hdata;
613 		sc->sc_lowlim[edata->sensor] = ldata;
614 		if (edata->sensor == ADMTEMP_EXT) {
615 			sc->sc_highlim2 = xhdata;
616 			sc->sc_lowlim2 = xldata;
617 		}
618 	}
619 }
620 
621 void
622 admtemp_setlim_1021(struct sysmon_envsys *sme, envsys_data_t *edata,
623 	sysmon_envsys_lim_t *limits, uint32_t *props)
624 {
625 	struct admtemp_softc *sc = sme->sme_cookie;
626 	uint8_t cmd;
627 	int tmp;
628 	int8_t sdata;
629 
630 	iic_acquire_bus(sc->sc_tag, 0);
631 
632 	if (*props & PROP_CRITMAX) {
633 		if (edata->sensor == ADMTEMP_INT)
634 			cmd = ADM1021_INT_HIGH_WRITE;
635 		else
636 			cmd = ADM1021_EXT_HIGH_WRITE;
637 
638 		if (limits == NULL)	/* Restore defaults */
639 			sdata = sc->sc_highlim[edata->sensor];
640 		else {
641 			tmp = (limits->sel_critmax - 273150000) / 1000000;
642 			if (tmp > ADMTEMP_MAX_POS)
643 				sdata = ADMTEMP_MAX_POS;
644 			else if (tmp < 0 && sc->sc_noneg)
645 				sdata = 0;
646 			else if (tmp < ADMTEMP_MAX_NEG)
647 				sdata = ADMTEMP_MAX_NEG;
648 			else
649 				sdata = tmp & 0xff;
650 		}
651 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
652 	}
653 
654 	if (*props & PROP_CRITMIN && sc->sc_nolow == 0) {
655 		if (edata->sensor == ADMTEMP_INT)
656 			cmd = ADM1021_INT_LOW_WRITE;
657 		else
658 			cmd = ADM1021_EXT_LOW_WRITE;
659 		if (limits == NULL)
660 			sdata = sc->sc_lowlim[edata->sensor];
661 		else {
662 			tmp = (limits->sel_critmin - 273150000) / 1000000;
663 			if (tmp > ADMTEMP_MAX_POS)
664 				sdata = ADMTEMP_MAX_POS;
665 			else if (tmp < 0 && sc->sc_noneg)
666 				sdata = 0;
667 			else if (tmp < ADMTEMP_MAX_NEG)
668 				sdata = ADMTEMP_MAX_NEG;
669 			else
670 				sdata = tmp & 0xff;
671 		}
672 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
673 	}
674 
675 	iic_release_bus(sc->sc_tag, 0);
676 }
677 
678 static void
679 admtemp_encode_temp(const uint32_t val, int8_t *sdata, uint8_t *xdata,
680     const int ext11)
681 {
682 	int32_t tmp;
683 
684 	if (ext11) {
685 		/* Split temperature into high and low bytes */
686 		tmp = (val - 273150000) / 125000;
687 		*xdata = (tmp & ADM1023_EXT2_MASK) << ADM1023_EXT2_SHIFT;
688 		tmp -= (int32_t) (*xdata >> ADM1023_EXT2_SHIFT);
689 		tmp /= 8;	/* 1000000 / 125000 */
690 	} else {
691 		*xdata = 0;
692 		tmp = (val - 273150000) / 1000000;
693 	}
694 	if (tmp > ADMTEMP_MAX_POS)
695 		*sdata = ADMTEMP_MAX_POS;
696 	else if (tmp < 0)
697 		*sdata = 0;
698 	else
699 		*sdata = tmp & 0xff;
700 }
701 
702 void
703 admtemp_setlim_1023(struct sysmon_envsys *sme, envsys_data_t *edata,
704 	sysmon_envsys_lim_t *limits, uint32_t *props)
705 {
706 	struct admtemp_softc *sc = sme->sme_cookie;
707 	int ext11;
708 	uint8_t cmd, xdata;
709 	int8_t sdata;
710 
711 	if (edata->sensor == ADMTEMP_INT)
712 		ext11 = 0;
713 	else
714 		ext11 = 1;
715 
716 	iic_acquire_bus(sc->sc_tag, 0);
717 
718 	if (*props & PROP_CRITMAX) {
719 		if (edata->sensor == ADMTEMP_INT)
720 			cmd = ADM1021_INT_HIGH_WRITE;
721 		else
722 			cmd = ADM1021_EXT_HIGH_WRITE;
723 
724 		if (limits == NULL) {	/* Restore defaults */
725 			sdata = sc->sc_highlim[edata->sensor];
726 			xdata = sc->sc_highlim2;
727 		} else
728 			admtemp_encode_temp(limits->sel_critmax, &sdata,
729 			    &xdata, ext11);
730 
731 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
732 		if (ext11) {
733 			cmd = ADM1023_EXT_HIGH2;
734 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &xdata);
735 		}
736 	}
737 
738 	if (*props & PROP_CRITMIN) {
739 		if (edata->sensor == ADMTEMP_INT)
740 			cmd = ADM1021_INT_LOW_WRITE;
741 		else
742 			cmd = ADM1021_EXT_LOW_WRITE;
743 		if (limits == NULL) {
744 			sdata = sc->sc_lowlim[edata->sensor];
745 			xdata = sc->sc_lowlim2;
746 		} else
747 			admtemp_encode_temp(limits->sel_critmax, &sdata,
748 			    &xdata, ext11);
749 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
750 		if (ext11) {
751 			cmd = ADM1023_EXT_LOW2;
752 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &xdata);
753 		}
754 	}
755 
756 	iic_release_bus(sc->sc_tag, 0);
757 }
758 
759 void
760 admtemp_setlim_1032(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 = ADM1032_INT_THERM;
778 		else
779 			cmd = ADM1032_EXT_THERM;
780 		if (limits == NULL)	/* Restore default */
781 			sdata = sc->sc_thermlim[edata->sensor];
782 		else
783 			admtemp_encode_temp(limits->sel_critmax, &sdata,
784 			    &xdata, 0);
785 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
786 	}
787 
788 	if (*props & PROP_WARNMAX) {
789 		if (edata->sensor == ADMTEMP_INT)
790 			cmd = ADM1021_INT_HIGH_WRITE;
791 		else
792 			cmd = ADM1021_EXT_HIGH_WRITE;
793 
794 		if (limits == NULL) {	/* Restore defaults */
795 			sdata = sc->sc_highlim[edata->sensor];
796 			xdata = sc->sc_highlim2;
797 		} else
798 			admtemp_encode_temp(limits->sel_warnmax, &sdata,
799 			    &xdata, ext11);
800 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
801 
802 		if (ext11) {
803 			cmd = ADM1023_EXT_HIGH2;
804 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &xdata);
805 		}
806 	}
807 
808 	if (*props & PROP_WARNMIN) {
809 		if (edata->sensor == ADMTEMP_INT)
810 			cmd = ADM1021_INT_LOW_WRITE;
811 		else
812 			cmd = ADM1021_EXT_LOW_WRITE;
813 		if (limits == NULL) {
814 			sdata = sc->sc_lowlim[edata->sensor];
815 			xdata = sc->sc_lowlim2;
816 		} else
817 			admtemp_encode_temp(limits->sel_warnmin, &sdata,
818 			    &xdata, ext11);
819 		admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &sdata);
820 
821 		if (ext11) {
822 			cmd = ADM1023_EXT_LOW2;
823 			admtemp_exec(sc, I2C_OP_WRITE_WITH_STOP, &cmd, &xdata);
824 		}
825 	}
826 
827 	iic_release_bus(sc->sc_tag, 0);
828 }
829