1/*- 2 * Copyright (c) 2010 Andreas Tobler 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: releng/10.3/sys/dev/iicbus/ad7417.c 239397 2012-08-19 19:31:36Z andreast $"); 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/* CPU A/B sensors, temp and adc: AD7417. */ 55 56#define AD7417_TEMP 0x00 57#define AD7417_CONFIG 0x01 58#define AD7417_ADC 0x04 59#define AD7417_CONFIG2 0x05 60#define AD7417_CONFMASK 0xe0 61 62uint8_t adc741x_config; 63 64struct ad7417_sensor { 65 struct pmac_therm therm; 66 device_t dev; 67 int id; 68 enum { 69 ADC7417_TEMP_SENSOR, 70 ADC7417_ADC_SENSOR 71 } type; 72}; 73 74struct write_data { 75 uint8_t reg; 76 uint8_t val; 77}; 78 79struct read_data { 80 uint8_t reg; 81 uint16_t val; 82}; 83 84/* Regular bus attachment functions */ 85static int ad7417_probe(device_t); 86static int ad7417_attach(device_t); 87 88/* Utility functions */ 89static int ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS); 90static int ad7417_write(device_t dev, uint32_t addr, uint8_t reg, 91 uint8_t *buf, int len); 92static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, 93 uint8_t *data); 94static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, 95 uint16_t *data); 96static int ad7417_write_read(device_t dev, uint32_t addr, 97 struct write_data out, struct read_data *in); 98static int ad7417_diode_read(struct ad7417_sensor *sens); 99static int ad7417_adc_read(struct ad7417_sensor *sens); 100static int ad7417_sensor_read(struct ad7417_sensor *sens); 101 102struct ad7417_softc { 103 device_t sc_dev; 104 uint32_t sc_addr; 105 struct ad7417_sensor *sc_sensors; 106 int sc_nsensors; 107 int init_done; 108}; 109static device_method_t ad7417_methods[] = { 110 /* Device interface */ 111 DEVMETHOD(device_probe, ad7417_probe), 112 DEVMETHOD(device_attach, ad7417_attach), 113 { 0, 0 }, 114}; 115 116static driver_t ad7417_driver = { 117 "ad7417", 118 ad7417_methods, 119 sizeof(struct ad7417_softc) 120}; 121 122static devclass_t ad7417_devclass; 123 124DRIVER_MODULE(ad7417, iicbus, ad7417_driver, ad7417_devclass, 0, 0); 125static MALLOC_DEFINE(M_AD7417, "ad7417", "Supply-Monitor AD7417"); 126 127 128static int 129ad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len) 130{ 131 unsigned char buf[4]; 132 int try = 0; 133 134 struct iic_msg msg[] = { 135 { addr, IIC_M_WR, 0, buf } 136 }; 137 138 msg[0].len = len + 1; 139 buf[0] = reg; 140 memcpy(buf + 1, buff, len); 141 142 for (;;) 143 { 144 if (iicbus_transfer(dev, msg, 1) == 0) 145 return (0); 146 147 if (++try > 5) { 148 device_printf(dev, "iicbus write failed\n"); 149 return (-1); 150 } 151 pause("ad7417_write", hz); 152 } 153} 154 155static int 156ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data) 157{ 158 uint8_t buf[4]; 159 int err, try = 0; 160 161 struct iic_msg msg[2] = { 162 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 163 { addr, IIC_M_RD, 1, buf }, 164 }; 165 166 for (;;) 167 { 168 err = iicbus_transfer(dev, msg, 2); 169 if (err != 0) 170 goto retry; 171 172 *data = *((uint8_t*)buf); 173 return (0); 174 retry: 175 if (++try > 5) { 176 device_printf(dev, "iicbus read failed\n"); 177 return (-1); 178 } 179 pause("ad7417_read_1", hz); 180 } 181} 182 183static int 184ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) 185{ 186 uint8_t buf[4]; 187 int err, try = 0; 188 189 struct iic_msg msg[2] = { 190 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 191 { addr, IIC_M_RD, 2, buf }, 192 }; 193 194 for (;;) 195 { 196 err = iicbus_transfer(dev, msg, 2); 197 if (err != 0) 198 goto retry; 199 200 *data = *((uint16_t*)buf); 201 return (0); 202 retry: 203 if (++try > 5) { 204 device_printf(dev, "iicbus read failed\n"); 205 return (-1); 206 } 207 pause("ad7417_read_2", hz); 208 } 209} 210 211static int 212ad7417_write_read(device_t dev, uint32_t addr, struct write_data out, 213 struct read_data *in) 214{ 215 uint8_t buf[4]; 216 int err, try = 0; 217 218 /* Do a combined write/read. */ 219 struct iic_msg msg[3] = { 220 { addr, IIC_M_WR, 2, buf }, 221 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &in->reg }, 222 { addr, IIC_M_RD, 2, buf }, 223 }; 224 225 /* Prepare the write msg. */ 226 buf[0] = out.reg; 227 buf[1] = out.val & 0xff; 228 229 for (;;) 230 { 231 err = iicbus_transfer(dev, msg, 3); 232 if (err != 0) 233 goto retry; 234 235 in->val = *((uint16_t*)buf); 236 return (0); 237 retry: 238 if (++try > 5) { 239 device_printf(dev, "iicbus write/read failed\n"); 240 return (-1); 241 } 242 pause("ad7417_write_read", hz); 243 } 244} 245 246static int 247ad7417_init_adc(device_t dev, uint32_t addr) 248{ 249 uint8_t buf; 250 int err; 251 struct ad7417_softc *sc; 252 253 sc = device_get_softc(dev); 254 255 adc741x_config = 0; 256 /* Clear Config2 */ 257 buf = 0; 258 259 err = ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1); 260 261 /* Read & cache Config1 */ 262 buf = 0; 263 err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); 264 err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf); 265 adc741x_config = (uint8_t)buf; 266 267 /* Disable shutdown mode */ 268 adc741x_config &= 0xfe; 269 buf = adc741x_config; 270 err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); 271 if (err < 0) 272 return (-1); 273 274 sc->init_done = 1; 275 276 return (0); 277 278} 279static int 280ad7417_probe(device_t dev) 281{ 282 const char *name, *compatible; 283 struct ad7417_softc *sc; 284 285 name = ofw_bus_get_name(dev); 286 compatible = ofw_bus_get_compat(dev); 287 288 if (!name) 289 return (ENXIO); 290 291 if (strcmp(name, "supply-monitor") != 0 || 292 strcmp(compatible, "ad7417") != 0) 293 return (ENXIO); 294 295 sc = device_get_softc(dev); 296 sc->sc_dev = dev; 297 sc->sc_addr = iicbus_get_addr(dev); 298 299 device_set_desc(dev, "Supply-Monitor AD7417"); 300 301 return (0); 302} 303 304/* 305 * This function returns the number of sensors. If we call it the second time 306 * and we have allocated memory for sc->sc_sensors, we fill in the properties. 307 */ 308static int 309ad7417_fill_sensor_prop(device_t dev) 310{ 311 phandle_t child; 312 struct ad7417_softc *sc; 313 u_int id[10]; 314 char location[96]; 315 char type[32]; 316 int i = 0, j, len = 0, prop_len, prev_len = 0; 317 318 sc = device_get_softc(dev); 319 320 child = ofw_bus_get_node(dev); 321 322 /* Fill the sensor location property. */ 323 prop_len = OF_getprop(child, "hwsensor-location", location, 324 sizeof(location)); 325 while (len < prop_len) { 326 if (sc->sc_sensors != NULL) 327 strcpy(sc->sc_sensors[i].therm.name, location + len); 328 prev_len = strlen(location + len) + 1; 329 len += prev_len; 330 i++; 331 } 332 if (sc->sc_sensors == NULL) 333 return (i); 334 335 /* Fill the sensor type property. */ 336 len = 0; 337 i = 0; 338 prev_len = 0; 339 prop_len = OF_getprop(child, "hwsensor-type", type, sizeof(type)); 340 while (len < prop_len) { 341 if (strcmp(type + len, "temperature") == 0) 342 sc->sc_sensors[i].type = ADC7417_TEMP_SENSOR; 343 else 344 sc->sc_sensors[i].type = ADC7417_ADC_SENSOR; 345 prev_len = strlen(type + len) + 1; 346 len += prev_len; 347 i++; 348 } 349 350 /* Fill the sensor id property. Taken from OF. */ 351 prop_len = OF_getprop(child, "hwsensor-id", id, sizeof(id)); 352 for (j = 0; j < i; j++) 353 sc->sc_sensors[j].id = id[j]; 354 355 /* Fill the sensor zone property. Taken from OF. */ 356 prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id)); 357 for (j = 0; j < i; j++) 358 sc->sc_sensors[j].therm.zone = id[j]; 359 360 /* Finish setting up sensor properties */ 361 for (j = 0; j < i; j++) { 362 sc->sc_sensors[j].dev = dev; 363 364 /* HACK: Apple wired a random diode to the ADC line */ 365 if (strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP") 366 != NULL) { 367 sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR; 368 sc->sc_sensors[j].therm.read = 369 (int (*)(struct pmac_therm *))(ad7417_diode_read); 370 } else { 371 sc->sc_sensors[j].therm.read = 372 (int (*)(struct pmac_therm *))(ad7417_sensor_read); 373 } 374 375 if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR) 376 continue; 377 378 /* Make up some ranges */ 379 sc->sc_sensors[j].therm.target_temp = 500 + ZERO_C_TO_K; 380 sc->sc_sensors[j].therm.max_temp = 900 + ZERO_C_TO_K; 381 382 pmac_thermal_sensor_register(&sc->sc_sensors[j].therm); 383 } 384 385 return (i); 386} 387 388static int 389ad7417_attach(device_t dev) 390{ 391 struct ad7417_softc *sc; 392 struct sysctl_oid *oid, *sensroot_oid; 393 struct sysctl_ctx_list *ctx; 394 char sysctl_name[32]; 395 int i, j; 396 const char *unit; 397 const char *desc; 398 399 sc = device_get_softc(dev); 400 401 sc->sc_nsensors = 0; 402 403 /* Count the actual number of sensors. */ 404 sc->sc_nsensors = ad7417_fill_sensor_prop(dev); 405 406 device_printf(dev, "%d sensors detected.\n", sc->sc_nsensors); 407 408 if (sc->sc_nsensors == 0) 409 device_printf(dev, "WARNING: No AD7417 sensors detected!\n"); 410 411 sc->sc_sensors = malloc (sc->sc_nsensors * sizeof(struct ad7417_sensor), 412 M_AD7417, M_WAITOK | M_ZERO); 413 414 ctx = device_get_sysctl_ctx(dev); 415 sensroot_oid = SYSCTL_ADD_NODE(ctx, 416 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor", 417 CTLFLAG_RD, 0, "AD7417 Sensor Information"); 418 419 /* Now we can fill the properties into the allocated struct. */ 420 sc->sc_nsensors = ad7417_fill_sensor_prop(dev); 421 422 /* Add sysctls for the sensors. */ 423 for (i = 0; i < sc->sc_nsensors; i++) { 424 for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) { 425 sysctl_name[j] = 426 tolower(sc->sc_sensors[i].therm.name[j]); 427 if (isspace(sysctl_name[j])) 428 sysctl_name[j] = '_'; 429 } 430 sysctl_name[j] = 0; 431 432 oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid), 433 OID_AUTO, 434 sysctl_name, CTLFLAG_RD, 0, 435 "Sensor Information"); 436 437 if (sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR) { 438 unit = "temp"; 439 desc = "sensor unit (C)"; 440 } else { 441 unit = "volt"; 442 desc = "sensor unit (mV)"; 443 } 444 /* I use i to pass the sensor id. */ 445 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 446 unit, CTLTYPE_INT | CTLFLAG_RD, dev, 447 i, ad7417_sensor_sysctl, 448 sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR ? 449 "IK" : "I", desc); 450 } 451 /* Dump sensor location, ID & type. */ 452 if (bootverbose) { 453 device_printf(dev, "Sensors\n"); 454 for (i = 0; i < sc->sc_nsensors; i++) { 455 device_printf(dev, "Location: %s ID: %d type: %d\n", 456 sc->sc_sensors[i].therm.name, 457 sc->sc_sensors[i].id, 458 sc->sc_sensors[i].type); 459 } 460 } 461 462 return (0); 463} 464 465static int 466ad7417_get_temp(device_t dev, uint32_t addr, int *temp) 467{ 468 uint16_t buf[2]; 469 uint16_t read; 470 int err; 471 472 err = ad7417_read_2(dev, addr, AD7417_TEMP, buf); 473 474 if (err < 0) 475 return (-1); 476 477 read = *((int16_t*)buf); 478 479 /* The ADC is 10 bit, the resolution is 0.25 C. 480 The temperature is in tenth kelvin. 481 */ 482 *temp = (((int16_t)(read & 0xffc0)) >> 6) * 25 / 10; 483 return (0); 484} 485 486static int 487ad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value, 488 uint8_t chan) 489{ 490 uint8_t tmp; 491 int err; 492 struct write_data config; 493 struct read_data data; 494 495 tmp = chan << 5; 496 config.reg = AD7417_CONFIG; 497 data.reg = AD7417_ADC; 498 data.val = 0; 499 500 err = ad7417_read_1(dev, addr, AD7417_CONFIG, &config.val); 501 502 config.val = (config.val & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK); 503 504 err = ad7417_write_read(dev, addr, config, &data); 505 if (err < 0) 506 return (-1); 507 508 *value = ((uint32_t)data.val) >> 6; 509 510 return (0); 511} 512 513static int 514ad7417_diode_read(struct ad7417_sensor *sens) 515{ 516 static int eeprom_read = 0; 517 static cell_t eeprom[2][40]; 518 phandle_t eeprom_node; 519 int rawval, diode_slope, diode_offset; 520 int temp; 521 522 if (!eeprom_read) { 523 eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0"); 524 OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0])); 525 eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2"); 526 OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1])); 527 eeprom_read = 1; 528 } 529 530 rawval = ad7417_adc_read(sens); 531 if (rawval < 0) 532 return (-1); 533 534 if (strstr(sens->therm.name, "CPU B") != NULL) { 535 diode_slope = eeprom[1][0x11] >> 16; 536 diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12; 537 } else { 538 diode_slope = eeprom[0][0x11] >> 16; 539 diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12; 540 } 541 542 temp = (rawval*diode_slope + diode_offset) >> 2; 543 temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16); 544 545 return (temp + ZERO_C_TO_K); 546} 547 548static int 549ad7417_adc_read(struct ad7417_sensor *sens) 550{ 551 struct ad7417_softc *sc; 552 uint8_t chan; 553 int temp; 554 555 sc = device_get_softc(sens->dev); 556 557 switch (sens->id) { 558 case 11: 559 case 16: 560 chan = 1; 561 break; 562 case 12: 563 case 17: 564 chan = 2; 565 break; 566 case 13: 567 case 18: 568 chan = 3; 569 break; 570 case 14: 571 case 19: 572 chan = 4; 573 break; 574 default: 575 chan = 1; 576 } 577 578 if (ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan) < 0) 579 return (-1); 580 581 return (temp); 582} 583 584 585static int 586ad7417_sensor_read(struct ad7417_sensor *sens) 587{ 588 struct ad7417_softc *sc; 589 int temp; 590 591 sc = device_get_softc(sens->dev); 592 593 /* Init the ADC if not already done.*/ 594 if (!sc->init_done) 595 if (ad7417_init_adc(sc->sc_dev, sc->sc_addr) < 0) 596 return (-1); 597 598 if (sens->type == ADC7417_TEMP_SENSOR) { 599 if (ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp) < 0) 600 return (-1); 601 temp += ZERO_C_TO_K; 602 } else { 603 temp = ad7417_adc_read(sens); 604 } 605 return (temp); 606} 607 608static int 609ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS) 610{ 611 device_t dev; 612 struct ad7417_softc *sc; 613 struct ad7417_sensor *sens; 614 int value = 0; 615 int error; 616 617 dev = arg1; 618 sc = device_get_softc(dev); 619 sens = &sc->sc_sensors[arg2]; 620 621 value = sens->therm.read(&sens->therm); 622 if (value < 0) 623 return (ENXIO); 624 625 error = sysctl_handle_int(oidp, &value, 0, req); 626 627 return (error); 628} 629