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