ad7417.c revision 249132
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: stable/9/sys/dev/iicbus/ad7417.c 249132 2013-04-05 08:22:11Z mav $"); 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}; 108static device_method_t ad7417_methods[] = { 109 /* Device interface */ 110 DEVMETHOD(device_probe, ad7417_probe), 111 DEVMETHOD(device_attach, ad7417_attach), 112 { 0, 0 }, 113}; 114 115static driver_t ad7417_driver = { 116 "ad7417", 117 ad7417_methods, 118 sizeof(struct ad7417_softc) 119}; 120 121static devclass_t ad7417_devclass; 122 123DRIVER_MODULE(ad7417, iicbus, ad7417_driver, ad7417_devclass, 0, 0); 124static MALLOC_DEFINE(M_AD7417, "ad7417", "Supply-Monitor AD7417"); 125 126 127static int 128ad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len) 129{ 130 unsigned char buf[4]; 131 int try = 0; 132 133 struct iic_msg msg[] = { 134 { addr, IIC_M_WR, 0, buf } 135 }; 136 137 msg[0].len = len + 1; 138 buf[0] = reg; 139 memcpy(buf + 1, buff, len); 140 141 for (;;) 142 { 143 if (iicbus_transfer(dev, msg, 1) == 0) 144 return (0); 145 146 if (++try > 5) { 147 device_printf(dev, "iicbus write failed\n"); 148 return (-1); 149 } 150 pause("ad7417_write", hz); 151 } 152} 153 154static int 155ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data) 156{ 157 uint8_t buf[4]; 158 int err, try = 0; 159 160 struct iic_msg msg[2] = { 161 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 162 { addr, IIC_M_RD, 1, buf }, 163 }; 164 165 for (;;) 166 { 167 err = iicbus_transfer(dev, msg, 2); 168 if (err != 0) 169 goto retry; 170 171 *data = *((uint8_t*)buf); 172 return (0); 173 retry: 174 if (++try > 5) { 175 device_printf(dev, "iicbus read failed\n"); 176 return (-1); 177 } 178 pause("ad7417_read_1", hz); 179 } 180} 181 182static int 183ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) 184{ 185 uint8_t buf[4]; 186 int err, try = 0; 187 188 struct iic_msg msg[2] = { 189 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 190 { addr, IIC_M_RD, 2, buf }, 191 }; 192 193 for (;;) 194 { 195 err = iicbus_transfer(dev, msg, 2); 196 if (err != 0) 197 goto retry; 198 199 *data = *((uint16_t*)buf); 200 return (0); 201 retry: 202 if (++try > 5) { 203 device_printf(dev, "iicbus read failed\n"); 204 return (-1); 205 } 206 pause("ad7417_read_2", hz); 207 } 208} 209 210static int 211ad7417_write_read(device_t dev, uint32_t addr, struct write_data out, 212 struct read_data *in) 213{ 214 uint8_t buf[4]; 215 int err, try = 0; 216 217 /* Do a combined write/read. */ 218 struct iic_msg msg[3] = { 219 { addr, IIC_M_WR, 2, buf }, 220 { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &in->reg }, 221 { addr, IIC_M_RD, 2, buf }, 222 }; 223 224 /* Prepare the write msg. */ 225 buf[0] = out.reg; 226 buf[1] = out.val & 0xff; 227 228 for (;;) 229 { 230 err = iicbus_transfer(dev, msg, 3); 231 if (err != 0) 232 goto retry; 233 234 in->val = *((uint16_t*)buf); 235 return (0); 236 retry: 237 if (++try > 5) { 238 device_printf(dev, "iicbus write/read failed\n"); 239 return (-1); 240 } 241 pause("ad7417_write_read", hz); 242 } 243} 244 245static int 246ad7417_init_adc(device_t dev, uint32_t addr) 247{ 248 uint8_t buf; 249 int err; 250 251 adc741x_config = 0; 252 /* Clear Config2 */ 253 buf = 0; 254 255 err = ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1); 256 257 /* Read & cache Config1 */ 258 buf = 0; 259 err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); 260 err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf); 261 adc741x_config = (uint8_t)buf; 262 263 /* Disable shutdown mode */ 264 adc741x_config &= 0xfe; 265 buf = adc741x_config; 266 err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); 267 if (err < 0) 268 return (-1); 269 270 return (0); 271 272} 273static int 274ad7417_probe(device_t dev) 275{ 276 const char *name, *compatible; 277 struct ad7417_softc *sc; 278 279 name = ofw_bus_get_name(dev); 280 compatible = ofw_bus_get_compat(dev); 281 282 if (!name) 283 return (ENXIO); 284 285 if (strcmp(name, "supply-monitor") != 0 || 286 strcmp(compatible, "ad7417") != 0) 287 return (ENXIO); 288 289 sc = device_get_softc(dev); 290 sc->sc_dev = dev; 291 sc->sc_addr = iicbus_get_addr(dev); 292 293 device_set_desc(dev, "Supply-Monitor AD7417"); 294 295 return (0); 296} 297 298/* 299 * This function returns the number of sensors. If we call it the second time 300 * and we have allocated memory for sc->sc_sensors, we fill in the properties. 301 */ 302static int 303ad7417_fill_sensor_prop(device_t dev) 304{ 305 phandle_t child; 306 struct ad7417_softc *sc; 307 u_int id[10]; 308 char location[96]; 309 char type[32]; 310 int i = 0, j, len = 0, prop_len, prev_len = 0; 311 312 sc = device_get_softc(dev); 313 314 child = ofw_bus_get_node(dev); 315 316 /* Fill the sensor location property. */ 317 prop_len = OF_getprop(child, "hwsensor-location", location, 318 sizeof(location)); 319 while (len < prop_len) { 320 if (sc->sc_sensors != NULL) 321 strcpy(sc->sc_sensors[i].therm.name, location + len); 322 prev_len = strlen(location + len) + 1; 323 len += prev_len; 324 i++; 325 } 326 if (sc->sc_sensors == NULL) 327 return (i); 328 329 /* Fill the sensor type property. */ 330 len = 0; 331 i = 0; 332 prev_len = 0; 333 prop_len = OF_getprop(child, "hwsensor-type", type, sizeof(type)); 334 while (len < prop_len) { 335 if (strcmp(type + len, "temperature") == 0) 336 sc->sc_sensors[i].type = ADC7417_TEMP_SENSOR; 337 else 338 sc->sc_sensors[i].type = ADC7417_ADC_SENSOR; 339 prev_len = strlen(type + len) + 1; 340 len += prev_len; 341 i++; 342 } 343 344 /* Fill the sensor id property. Taken from OF. */ 345 prop_len = OF_getprop(child, "hwsensor-id", id, sizeof(id)); 346 for (j = 0; j < i; j++) 347 sc->sc_sensors[j].id = id[j]; 348 349 /* Fill the sensor zone property. Taken from OF. */ 350 prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id)); 351 for (j = 0; j < i; j++) 352 sc->sc_sensors[j].therm.zone = id[j]; 353 354 /* Finish setting up sensor properties */ 355 for (j = 0; j < i; j++) { 356 sc->sc_sensors[j].dev = dev; 357 358 /* HACK: Apple wired a random diode to the ADC line */ 359 if (strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP") 360 != NULL) { 361 sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR; 362 sc->sc_sensors[j].therm.read = 363 (int (*)(struct pmac_therm *))(ad7417_diode_read); 364 } else { 365 sc->sc_sensors[j].therm.read = 366 (int (*)(struct pmac_therm *))(ad7417_sensor_read); 367 } 368 369 if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR) 370 continue; 371 372 /* Make up some ranges */ 373 sc->sc_sensors[j].therm.target_temp = 500 + ZERO_C_TO_K; 374 sc->sc_sensors[j].therm.max_temp = 900 + ZERO_C_TO_K; 375 376 pmac_thermal_sensor_register(&sc->sc_sensors[j].therm); 377 } 378 379 return (i); 380} 381 382static int 383ad7417_attach(device_t dev) 384{ 385 struct ad7417_softc *sc; 386 struct sysctl_oid *oid, *sensroot_oid; 387 struct sysctl_ctx_list *ctx; 388 char sysctl_name[32]; 389 int i, j; 390 const char *unit; 391 const char *desc; 392 393 sc = device_get_softc(dev); 394 395 sc->sc_nsensors = 0; 396 397 /* Count the actual number of sensors. */ 398 sc->sc_nsensors = ad7417_fill_sensor_prop(dev); 399 400 device_printf(dev, "%d sensors detected.\n", sc->sc_nsensors); 401 402 if (sc->sc_nsensors == 0) 403 device_printf(dev, "WARNING: No AD7417 sensors detected!\n"); 404 405 sc->sc_sensors = malloc (sc->sc_nsensors * sizeof(struct ad7417_sensor), 406 M_AD7417, M_WAITOK | M_ZERO); 407 408 ctx = device_get_sysctl_ctx(dev); 409 sensroot_oid = SYSCTL_ADD_NODE(ctx, 410 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor", 411 CTLFLAG_RD, 0, "AD7417 Sensor Information"); 412 413 /* Now we can fill the properties into the allocated struct. */ 414 sc->sc_nsensors = ad7417_fill_sensor_prop(dev); 415 416 /* Add sysctls for the sensors. */ 417 for (i = 0; i < sc->sc_nsensors; i++) { 418 for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) { 419 sysctl_name[j] = 420 tolower(sc->sc_sensors[i].therm.name[j]); 421 if (isspace(sysctl_name[j])) 422 sysctl_name[j] = '_'; 423 } 424 sysctl_name[j] = 0; 425 426 oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid), 427 OID_AUTO, 428 sysctl_name, CTLFLAG_RD, 0, 429 "Sensor Information"); 430 431 if (sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR) { 432 unit = "temp"; 433 desc = "Sensor temp in C"; 434 } else { 435 unit = "volt"; 436 desc = "Sensor Volt in V"; 437 } 438 /* I use i to pass the sensor id. */ 439 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 440 unit, CTLTYPE_INT | CTLFLAG_RD, dev, 441 i, ad7417_sensor_sysctl, 442 sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR ? 443 "IK" : "I", desc); 444 } 445 /* Dump sensor location, ID & type. */ 446 if (bootverbose) { 447 device_printf(dev, "Sensors\n"); 448 for (i = 0; i < sc->sc_nsensors; i++) { 449 device_printf(dev, "Location: %s ID: %d type: %d\n", 450 sc->sc_sensors[i].therm.name, 451 sc->sc_sensors[i].id, 452 sc->sc_sensors[i].type); 453 } 454 } 455 456 return (0); 457} 458 459static int 460ad7417_get_temp(device_t dev, uint32_t addr, int *temp) 461{ 462 uint16_t buf[2]; 463 uint16_t read; 464 int err; 465 466 err = ad7417_read_2(dev, addr, AD7417_TEMP, buf); 467 468 if (err < 0) 469 return (-1); 470 471 read = *((int16_t*)buf); 472 473 /* The ADC is 10 bit, the resolution is 0.25 C. 474 The temperature is in tenth kelvin. 475 */ 476 *temp = (((int16_t)(read & 0xffc0)) >> 6) * 25 / 10; 477 return (0); 478} 479 480static int 481ad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value, 482 uint8_t chan) 483{ 484 uint8_t tmp; 485 int err; 486 struct write_data config; 487 struct read_data data; 488 489 tmp = chan << 5; 490 config.reg = AD7417_CONFIG; 491 data.reg = AD7417_ADC; 492 data.val = 0; 493 494 err = ad7417_read_1(dev, addr, AD7417_CONFIG, &config.val); 495 496 config.val = (config.val & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK); 497 498 err = ad7417_write_read(dev, addr, config, &data); 499 if (err < 0) 500 return (-1); 501 502 *value = ((uint32_t)data.val) >> 6; 503 504 return (0); 505} 506 507static int 508ad7417_diode_read(struct ad7417_sensor *sens) 509{ 510 static int eeprom_read = 0; 511 static cell_t eeprom[2][40]; 512 phandle_t eeprom_node; 513 int rawval, diode_slope, diode_offset; 514 int temp; 515 516 if (!eeprom_read) { 517 eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0"); 518 OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0])); 519 eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2"); 520 OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1])); 521 eeprom_read = 1; 522 } 523 524 rawval = ad7417_adc_read(sens); 525 if (rawval < 0) 526 return (-1); 527 528 if (strstr(sens->therm.name, "CPU B") != NULL) { 529 diode_slope = eeprom[1][0x11] >> 16; 530 diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12; 531 } else { 532 diode_slope = eeprom[0][0x11] >> 16; 533 diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12; 534 } 535 536 temp = (rawval*diode_slope + diode_offset) >> 2; 537 temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16); 538 539 return (temp + ZERO_C_TO_K); 540} 541 542static int 543ad7417_adc_read(struct ad7417_sensor *sens) 544{ 545 struct ad7417_softc *sc; 546 uint8_t chan; 547 int temp; 548 549 sc = device_get_softc(sens->dev); 550 551 switch (sens->id) { 552 case 11: 553 case 16: 554 chan = 1; 555 break; 556 case 12: 557 case 17: 558 chan = 2; 559 break; 560 case 13: 561 case 18: 562 chan = 3; 563 break; 564 case 14: 565 case 19: 566 chan = 4; 567 break; 568 default: 569 chan = 1; 570 } 571 572 if (ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan) < 0) 573 return (-1); 574 575 return (temp); 576} 577 578 579static int 580ad7417_sensor_read(struct ad7417_sensor *sens) 581{ 582 struct ad7417_softc *sc; 583 int temp; 584 585 sc = device_get_softc(sens->dev); 586 587 /* Init the ADC. */ 588 if (ad7417_init_adc(sc->sc_dev, sc->sc_addr) < 0) 589 return (-1); 590 591 if (sens->type == ADC7417_TEMP_SENSOR) { 592 if (ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp) < 0) 593 return (-1); 594 temp += ZERO_C_TO_K; 595 } else { 596 temp = ad7417_adc_read(sens); 597 } 598 return (temp); 599} 600 601static int 602ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS) 603{ 604 device_t dev; 605 struct ad7417_softc *sc; 606 struct ad7417_sensor *sens; 607 int value = 0; 608 int error; 609 610 dev = arg1; 611 sc = device_get_softc(dev); 612 sens = &sc->sc_sensors[arg2]; 613 614 value = sens->therm.read(&sens->therm); 615 if (value < 0) 616 return (ENXIO); 617 618 error = sysctl_handle_int(oidp, &value, 0, req); 619 620 return (error); 621} 622