xref: /freebsd/sys/dev/iicbus/pwm/adt746x.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2012 Andreas Tobler
5  * Copyright (c) 2014 Justin Hibbits
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/param.h>
31 #include <sys/bus.h>
32 #include <sys/systm.h>
33 #include <sys/module.h>
34 #include <sys/callout.h>
35 #include <sys/conf.h>
36 #include <sys/cpu.h>
37 #include <sys/ctype.h>
38 #include <sys/kernel.h>
39 #include <sys/reboot.h>
40 #include <sys/rman.h>
41 #include <sys/sysctl.h>
42 #include <sys/limits.h>
43 
44 #include <machine/bus.h>
45 #include <machine/md_var.h>
46 
47 #include <dev/iicbus/iicbus.h>
48 #include <dev/iicbus/iiconf.h>
49 
50 #include <dev/ofw/openfirm.h>
51 #include <dev/ofw/ofw_bus.h>
52 #include <powerpc/powermac/powermac_thermal.h>
53 
54 /* ADT746X registers. */
55 #define ADT746X_TACH1LOW          0x28
56 #define ADT746X_TACH1HIGH         0x29
57 #define ADT746X_TACH2LOW          0x2a
58 #define ADT746X_TACH2HIGH         0x2b
59 #define ADT746X_PWM1              0x30
60 #define ADT746X_PWM2              0x31
61 #define ADT746X_DEVICE_ID         0x3d
62 #define ADT746X_COMPANY_ID        0x3e
63 #define ADT746X_REV_ID            0x3f
64 #define ADT746X_CONFIG            0x40
65 #define ADT746X_PWM1_CONF         0x5c
66 #define ADT746X_PWM2_CONF         0x5d
67 #define ADT746X_MANUAL_MASK       0xe0
68 
69 #define ADT7460_DEV_ID            0x27
70 #define ADT7467_DEV_ID            0x68
71 
72 struct adt746x_fan {
73 	struct pmac_fan fan;
74 	device_t        dev;
75 	int             id;
76 	int             setpoint;
77 	int		pwm_reg;
78 	int		conf_reg;
79 };
80 
81 struct adt746x_sensor {
82 	struct pmac_therm therm;
83 	device_t          dev;
84 	int               id;
85 	cell_t	          reg;
86 	enum {
87 		ADT746X_SENSOR_TEMP,
88 		ADT746X_SENSOR_VOLT,
89 		ADT746X_SENSOR_SPEED
90 	} type;
91 };
92 
93 struct adt746x_softc {
94 	device_t		sc_dev;
95 	struct intr_config_hook enum_hook;
96 	uint32_t                sc_addr;
97 	/* The 7467 supports up to 4 fans, 2 voltage and 3 temperature sensors. */
98 	struct adt746x_fan	sc_fans[4];
99 	int			sc_nfans;
100 	struct adt746x_sensor   sc_sensors[9];
101 	int			sc_nsensors;
102 	int                     device_id;
103 
104 };
105 
106 
107 /* Regular bus attachment functions */
108 
109 static int  adt746x_probe(device_t);
110 static int  adt746x_attach(device_t);
111 
112 
113 /* Utility functions */
114 static void adt746x_attach_fans(device_t dev);
115 static void adt746x_attach_sensors(device_t dev);
116 static int  adt746x_fill_fan_prop(device_t dev);
117 static int  adt746x_fill_sensor_prop(device_t dev);
118 
119 static int  adt746x_fan_set_pwm(struct adt746x_fan *fan, int pwm);
120 static int  adt746x_fan_get_pwm(struct adt746x_fan *fan);
121 static int  adt746x_sensor_read(struct adt746x_sensor *sens);
122 static void adt746x_start(void *xdev);
123 
124 /* i2c read/write functions. */
125 static int  adt746x_write(device_t dev, uint32_t addr, uint8_t reg,
126 			  uint8_t *buf);
127 static int  adt746x_read(device_t dev, uint32_t addr, uint8_t reg,
128 			 uint8_t *data);
129 
130 static device_method_t  adt746x_methods[] = {
131 	/* Device interface */
132 	DEVMETHOD(device_probe,	 adt746x_probe),
133 	DEVMETHOD(device_attach, adt746x_attach),
134 	{ 0, 0 },
135 };
136 
137 static driver_t adt746x_driver = {
138 	"adt746x",
139 	adt746x_methods,
140 	sizeof(struct adt746x_softc)
141 };
142 
143 DRIVER_MODULE(adt746x, iicbus, adt746x_driver, 0, 0);
144 static MALLOC_DEFINE(M_ADT746X, "adt746x", "ADT Sensor Information");
145 
146 
147 /* i2c read/write functions. */
148 
149 static int
150 adt746x_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff)
151 {
152 	uint8_t buf[4];
153 	int try = 0;
154 
155 	struct iic_msg msg[] = {
156 		{addr, IIC_M_WR, 2, buf }
157 	};
158 
159 	/* Prepare the write msg. */
160 	buf[0] = reg;
161 	memcpy(buf + 1, buff, 1);
162 
163 	for (;;)
164 	{
165 		if (iicbus_transfer(dev, msg, 1) == 0)
166 			return (0);
167 		if (++try > 5) {
168 			device_printf(dev, "iicbus write failed\n");
169 			return (-1);
170 		}
171 		pause("adt746x_write", hz);
172 	}
173 	return (0);
174 }
175 
176 static int
177 adt746x_read(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data)
178 {
179 	uint8_t buf[4];
180 	int err, try = 0;
181 
182 	struct iic_msg msg[2] = {
183 		{addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg},
184 		{addr, IIC_M_RD, 1, buf},
185 	};
186 
187 	for (;;)
188 	{
189 		err = iicbus_transfer(dev, msg, 2);
190 		if (err != 0)
191 			goto retry;
192 
193 		*data = *((uint8_t*)buf);
194 		return (0);
195 	retry:
196 		if (++try > 5) {
197 			device_printf(dev, "iicbus read failed\n");
198 			return (-1);
199 		}
200 		pause("adt746x_read", hz);
201 	}
202 }
203 
204 static int
205 adt746x_probe(device_t dev)
206 {
207 	const char  *name, *compatible;
208 	struct adt746x_softc *sc;
209 
210 	name = ofw_bus_get_name(dev);
211 	compatible = ofw_bus_get_compat(dev);
212 
213 	if (!name)
214 		return (ENXIO);
215 
216 	if (strcmp(name, "fan") != 0 ||
217 	    (strcmp(compatible, "adt7460") != 0 &&
218 	     strcmp(compatible, "adt7467") != 0))
219 		return (ENXIO);
220 
221 	sc = device_get_softc(dev);
222 	sc->sc_dev = dev;
223 	sc->sc_addr = iicbus_get_addr(dev);
224 
225 	device_set_desc(dev, "Apple Thermostat Unit ADT746X");
226 
227 	return (0);
228 }
229 
230 static int
231 adt746x_attach(device_t dev)
232 {
233 	struct adt746x_softc *sc;
234 
235 	sc = device_get_softc(dev);
236 
237 	sc->enum_hook.ich_func = adt746x_start;
238 	sc->enum_hook.ich_arg = dev;
239 
240 	/* We have to wait until interrupts are enabled. I2C read and write
241 	 * only works if the interrupts are available.
242 	 * The unin/i2c is controlled by the htpic on unin. But this is not
243 	 * the master. The openpic on mac-io is controlling the htpic.
244 	 * This one gets attached after the mac-io probing and then the
245 	 * interrupts will be available.
246 	 */
247 
248 	if (config_intrhook_establish(&sc->enum_hook) != 0)
249 		return (ENOMEM);
250 
251 	return (0);
252 }
253 
254 static void
255 adt746x_start(void *xdev)
256 {
257 	uint8_t did, cid, rev, conf;
258 
259 	struct adt746x_softc *sc;
260 
261 	device_t dev = (device_t)xdev;
262 
263 	sc = device_get_softc(dev);
264 
265 	adt746x_read(sc->sc_dev, sc->sc_addr, ADT746X_DEVICE_ID, &did);
266 	adt746x_read(sc->sc_dev, sc->sc_addr, ADT746X_COMPANY_ID, &cid);
267 	adt746x_read(sc->sc_dev, sc->sc_addr, ADT746X_REV_ID, &rev);
268 	adt746x_read(sc->sc_dev, sc->sc_addr, ADT746X_CONFIG, &conf);
269 
270 	device_printf(dev, "Dev ID %#x, Company ID %#x, Rev ID %#x CNF: %#x\n",
271 		      did, cid, rev, conf);
272 
273 	/* We can get the device id either from 'of' properties or from the chip
274 	   itself. This method makes sure we can read the chip, otherwise
275 	   we return.  */
276 
277 	sc->device_id = did;
278 
279 	conf = 1;
280 	/* Start the ADT7460.  */
281 	if (sc->device_id == ADT7460_DEV_ID)
282 		adt746x_write(sc->sc_dev, sc->sc_addr, ADT746X_CONFIG, &conf);
283 
284 	/* Detect and attach child devices.  */
285 	adt746x_attach_fans(dev);
286 	adt746x_attach_sensors(dev);
287 	config_intrhook_disestablish(&sc->enum_hook);
288 }
289 
290 /*
291  * Sensor and fan management
292  */
293 static int
294 adt746x_fan_set_pwm(struct adt746x_fan *fan, int pwm)
295 {
296 	uint8_t reg = 0, manual, mode = 0;
297 	struct adt746x_softc *sc;
298 	uint8_t buf;
299 
300 	sc = device_get_softc(fan->dev);
301 
302 	/* Clamp to allowed range */
303 	pwm = max(fan->fan.min_rpm, pwm);
304 	pwm = min(fan->fan.max_rpm, pwm);
305 
306 	reg = fan->pwm_reg;
307 	mode = fan->conf_reg;
308 
309 	/* From the 7460 datasheet:
310 	   PWM dutycycle can be programmed from 0% (0x00) to 100% (0xFF)
311 	   in steps of 0.39% (256 steps).
312 	 */
313 	buf = (pwm * 100 / 39) - (pwm ? 1 : 0);
314 	fan->setpoint = buf;
315 
316 	/* Manual mode.  */
317 	adt746x_read(sc->sc_dev, sc->sc_addr, mode, &manual);
318 	manual |= ADT746X_MANUAL_MASK;
319 	adt746x_write(sc->sc_dev, sc->sc_addr, mode, &manual);
320 
321 	/* Write speed.  */
322 	adt746x_write(sc->sc_dev, sc->sc_addr, reg, &buf);
323 
324 	return (0);
325 }
326 
327 static int
328 adt746x_fan_get_pwm(struct adt746x_fan *fan)
329 {
330 	uint8_t buf, reg;
331 	uint16_t pwm;
332 	struct adt746x_softc *sc;
333 
334 	sc = device_get_softc(fan->dev);
335 
336 	reg = fan->pwm_reg;
337 
338 	adt746x_read(sc->sc_dev, sc->sc_addr, reg, &buf);
339 
340 	pwm = (buf * 39 / 100) + (buf ? 1 : 0);
341 	return (pwm);
342 }
343 
344 static int
345 adt746x_fill_fan_prop(device_t dev)
346 {
347 	phandle_t child;
348 	struct adt746x_softc *sc;
349 	u_int *id;
350 	char *location;
351 	int i, id_len, len = 0, location_len, prev_len = 0;
352 
353 	sc = device_get_softc(dev);
354 
355 	child = ofw_bus_get_node(dev);
356 
357 	/* Fill the fan location property. */
358 	location_len = OF_getprop_alloc(child, "hwctrl-location", (void **)&location);
359 	id_len = OF_getprop_alloc_multi(child, "hwctrl-id", sizeof(cell_t), (void **)&id);
360 	if (location_len == -1 || id_len == -1) {
361 		OF_prop_free(location);
362 		OF_prop_free(id);
363 		return 0;
364 	}
365 
366 	/* Fill in all the properties for each fan. */
367 	for (i = 0; i < id_len; i++) {
368 		strlcpy(sc->sc_fans[i].fan.name, location + len, 32);
369 		prev_len = strlen(location + len) + 1;
370 		len += prev_len;
371 		sc->sc_fans[i].id = id[i];
372 		if (id[i] == 6) {
373 			sc->sc_fans[i].pwm_reg = ADT746X_PWM1;
374 			sc->sc_fans[i].conf_reg = ADT746X_PWM1_CONF;
375 		} else if (id[i] == 7) {
376 			sc->sc_fans[i].pwm_reg = ADT746X_PWM2;
377 			sc->sc_fans[i].conf_reg = ADT746X_PWM2_CONF;
378 		} else {
379 			sc->sc_fans[i].pwm_reg = ADT746X_PWM1 + i;
380 			sc->sc_fans[i].conf_reg = ADT746X_PWM1_CONF + i;
381 		}
382 		sc->sc_fans[i].dev = sc->sc_dev;
383 		sc->sc_fans[i].fan.min_rpm = 5;	/* Percent */
384 		sc->sc_fans[i].fan.max_rpm = 100;
385 		sc->sc_fans[i].fan.read = NULL;
386 		sc->sc_fans[i].fan.set =
387 			(int (*)(struct pmac_fan *, int))(adt746x_fan_set_pwm);
388 		sc->sc_fans[i].fan.default_rpm = sc->sc_fans[i].fan.max_rpm;
389 	}
390 	OF_prop_free(location);
391 	OF_prop_free(id);
392 
393 	return (i);
394 }
395 
396 static int
397 adt746x_fill_sensor_prop(device_t dev)
398 {
399 	phandle_t child, node;
400 	struct adt746x_softc *sc;
401 	char sens_type[32];
402 	int i = 0, reg, sensid;
403 
404 	sc = device_get_softc(dev);
405 
406 	child = ofw_bus_get_node(dev);
407 
408 	/* Fill in the sensor properties for each child. */
409 	for (node = OF_child(child); node != 0; node = OF_peer(node)) {
410 		if (OF_getprop(node, "sensor-id", &sensid, sizeof(sensid)) == -1)
411 		    continue;
412 		OF_getprop(node, "location", sc->sc_sensors[i].therm.name, 32);
413 		OF_getprop(node, "device_type", sens_type, sizeof(sens_type));
414 		if (strcmp(sens_type, "temperature") == 0)
415 			sc->sc_sensors[i].type = ADT746X_SENSOR_TEMP;
416 		else if (strcmp(sens_type, "voltage") == 0)
417 			sc->sc_sensors[i].type = ADT746X_SENSOR_VOLT;
418 		else
419 			sc->sc_sensors[i].type = ADT746X_SENSOR_SPEED;
420 		OF_getprop(node, "reg", &reg, sizeof(reg));
421 		OF_getprop(node, "sensor-id", &sensid,
422 			sizeof(sensid));
423 		/* This is the i2c register of the sensor.  */
424 		sc->sc_sensors[i].reg = reg;
425 		sc->sc_sensors[i].id = sensid;
426 		OF_getprop(node, "zone", &sc->sc_sensors[i].therm.zone,
427 			sizeof(sc->sc_sensors[i].therm.zone));
428 		sc->sc_sensors[i].dev = dev;
429 		sc->sc_sensors[i].therm.read =
430 		    (int (*)(struct pmac_therm *))adt746x_sensor_read;
431 		if (sc->sc_sensors[i].type == ADT746X_SENSOR_TEMP) {
432 		    /* Make up some ranges */
433 		    sc->sc_sensors[i].therm.target_temp = 500 + ZERO_C_TO_K;
434 		    sc->sc_sensors[i].therm.max_temp = 800 + ZERO_C_TO_K;
435 
436 		    pmac_thermal_sensor_register(&sc->sc_sensors[i].therm);
437 		}
438 		i++;
439 	}
440 
441 	return (i);
442 }
443 
444 static int
445 adt746x_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
446 {
447 	device_t adt;
448 	struct adt746x_softc *sc;
449 	struct adt746x_fan *fan;
450 	int pwm = 0, error;
451 
452 	adt = arg1;
453 	sc = device_get_softc(adt);
454 	fan = &sc->sc_fans[arg2];
455 	pwm = adt746x_fan_get_pwm(fan);
456 	error = sysctl_handle_int(oidp, &pwm, 0, req);
457 
458 	if (error || !req->newptr)
459 		return (error);
460 
461 	return (adt746x_fan_set_pwm(fan, pwm));
462 }
463 
464 static void
465 adt746x_attach_fans(device_t dev)
466 {
467 	struct adt746x_softc *sc;
468 	struct sysctl_oid *oid, *fanroot_oid;
469 	struct sysctl_ctx_list *ctx;
470 	char sysctl_name[32];
471 	int i, j;
472 
473 	sc = device_get_softc(dev);
474 
475 	sc->sc_nfans = 0;
476 
477 	/* Count the actual number of fans. */
478 	sc->sc_nfans = adt746x_fill_fan_prop(dev);
479 
480 	device_printf(dev, "%d fans detected!\n", sc->sc_nfans);
481 
482 	if (sc->sc_nfans == 0) {
483 		device_printf(dev, "WARNING: No fans detected!\n");
484 		return;
485 	}
486 
487 	ctx = device_get_sysctl_ctx(dev);
488 	fanroot_oid = SYSCTL_ADD_NODE(ctx,
489 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fans",
490 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "ADT Fan Information");
491 
492 	/* Now we can fill the properties into the allocated struct. */
493 	sc->sc_nfans = adt746x_fill_fan_prop(dev);
494 
495 	/* Register fans with pmac_thermal */
496 	for (i = 0; i < sc->sc_nfans; i++)
497 		pmac_thermal_fan_register(&sc->sc_fans[i].fan);
498 
499 	/* Add sysctls for the fans. */
500 	for (i = 0; i < sc->sc_nfans; i++) {
501 		for (j = 0; j < strlen(sc->sc_fans[i].fan.name); j++) {
502 			sysctl_name[j] = tolower(sc->sc_fans[i].fan.name[j]);
503 			if (isspace(sysctl_name[j]))
504 				sysctl_name[j] = '_';
505 		}
506 		sysctl_name[j] = 0;
507 
508 		sc->sc_fans[i].setpoint =
509 			adt746x_fan_get_pwm(&sc->sc_fans[i]);
510 
511 		oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid),
512 		    OID_AUTO, sysctl_name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
513 		    "Fan Information");
514 
515 		/* I use i to pass the fan id. */
516 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
517 		    "pwm", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, dev,
518 		    i, adt746x_fanrpm_sysctl, "I", "Fan PWM in %");
519 	}
520 
521 	/* Dump fan location & type. */
522 	if (bootverbose) {
523 		for (i = 0; i < sc->sc_nfans; i++) {
524 			device_printf(dev, "Fan location: %s",
525 				      sc->sc_fans[i].fan.name);
526 			device_printf(dev, " id: %d RPM: %d\n",
527 				      sc->sc_fans[i].id,
528 				      sc->sc_fans[i].setpoint);
529 		}
530 	}
531 }
532 
533 static int
534 adt746x_sensor_read(struct adt746x_sensor *sens)
535 {
536 	struct adt746x_softc *sc;
537 	int tmp = 0;
538 	uint16_t val;
539 	uint8_t data[1], data1[1];
540 	int8_t temp;
541 
542 	sc = device_get_softc(sens->dev);
543 	if (sens->type != ADT746X_SENSOR_SPEED) {
544 		if (adt746x_read(sc->sc_dev, sc->sc_addr, sens->reg,
545 				 &temp) < 0)
546 			return (-1);
547 		if (sens->type == ADT746X_SENSOR_TEMP)
548 			tmp = 10 * temp + ZERO_C_TO_K;
549 		else
550 			tmp = temp;
551 	} else {
552 		if (adt746x_read(sc->sc_dev, sc->sc_addr, sens->reg,
553 				 data) < 0)
554 			return (-1);
555 		if (adt746x_read(sc->sc_dev, sc->sc_addr, sens->reg + 1,
556 				 data1) < 0)
557 			return (-1);
558 		val = data[0] + (data1[0] << 8);
559 		/* A value of 0xffff means the fan is stopped.  */
560 		if (val == 0 || val == 0xffff)
561 			tmp = 0;
562 		else
563 			tmp = (90000 * 60) / val;
564 	}
565 	return (tmp);
566 }
567 
568 static int
569 adt746x_sensor_sysctl(SYSCTL_HANDLER_ARGS)
570 {
571 	device_t dev;
572 	struct adt746x_softc *sc;
573 	struct adt746x_sensor *sens;
574 	int value, error;
575 
576 	dev = arg1;
577 	sc = device_get_softc(dev);
578 	sens = &sc->sc_sensors[arg2];
579 
580 	value = sens->therm.read(&sens->therm);
581 	if (value < 0)
582 		return (ENXIO);
583 
584 	error = sysctl_handle_int(oidp, &value, 0, req);
585 
586 	return (error);
587 }
588 
589 static void
590 adt746x_attach_sensors(device_t dev)
591 {
592 	struct adt746x_softc *sc;
593 	struct sysctl_oid *oid, *sensroot_oid;
594 	struct sysctl_ctx_list *ctx;
595 	char sysctl_name[40];
596 	const char *unit;
597 	const char *desc;
598 	int i, j;
599 
600 
601 	sc = device_get_softc(dev);
602 	sc->sc_nsensors = 0;
603 
604 	/* Count the actual number of sensors. */
605 	sc->sc_nsensors = adt746x_fill_sensor_prop(dev);
606 	device_printf(dev, "%d sensors detected!\n", sc->sc_nsensors);
607 	if (sc->sc_nsensors == 0) {
608 		device_printf(dev, "WARNING: No sensors detected!\n");
609 		return;
610 	}
611 
612 	ctx = device_get_sysctl_ctx(dev);
613 	sensroot_oid = SYSCTL_ADD_NODE(ctx,
614 	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensors",
615 	    CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "ADT Sensor Information");
616 
617 	/* Add the sysctl for the sensors. */
618 	for (i = 0; i < sc->sc_nsensors; i++) {
619 		for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) {
620 			sysctl_name[j] = tolower(sc->sc_sensors[i].therm.name[j]);
621 			if (isspace(sysctl_name[j]))
622 				sysctl_name[j] = '_';
623 		}
624 		sysctl_name[j] = 0;
625 		oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid),
626 		    OID_AUTO, sysctl_name, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
627 		    "Sensor Information");
628 		if (sc->sc_sensors[i].type == ADT746X_SENSOR_TEMP) {
629 			unit = "temp";
630 			desc = "sensor unit (C)";
631 		} else if (sc->sc_sensors[i].type == ADT746X_SENSOR_VOLT) {
632 			unit = "volt";
633 			desc = "sensor unit (mV)";
634 		} else {
635 			unit = "rpm";
636 			desc = "sensor unit (RPM)";
637 		}
638 		/* I use i to pass the sensor id. */
639 		SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
640 		    unit, CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_NEEDGIANT, dev, i,
641 		    adt746x_sensor_sysctl,
642 		    sc->sc_sensors[i].type == ADT746X_SENSOR_TEMP ?
643 		    "IK" : "I", desc);
644 	}
645 
646 	/* Dump sensor location & type. */
647 	if (bootverbose) {
648 		for (i = 0; i < sc->sc_nsensors; i++) {
649 			device_printf(dev, "Sensor location: %s",
650 				      sc->sc_sensors[i].therm.name);
651 			device_printf(dev, " type: %d id: %d reg: 0x%x\n",
652 				      sc->sc_sensors[i].type,
653 				      sc->sc_sensors[i].id,
654 				      sc->sc_sensors[i].reg);
655 		}
656 	}
657 }
658