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, ®}, 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", ®, 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