1222457Sattilio/*- 2222457Sattilio * Copyright (c) 2010 Andreas Tobler 3222457Sattilio * All rights reserved. 4222457Sattilio * 5222457Sattilio * Redistribution and use in source and binary forms, with or without 6222457Sattilio * modification, are permitted provided that the following conditions 7222457Sattilio * are met: 8222457Sattilio * 1. Redistributions of source code must retain the above copyright 9222457Sattilio * notice, this list of conditions and the following disclaimer. 10222457Sattilio * 2. Redistributions in binary form must reproduce the above copyright 11222457Sattilio * notice, this list of conditions and the following disclaimer in the 12222457Sattilio * documentation and/or other materials provided with the distribution. 13222457Sattilio * 14222457Sattilio * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15222457Sattilio * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16222457Sattilio * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17222457Sattilio * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18222457Sattilio * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 19222457Sattilio * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20222457Sattilio * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 21222457Sattilio * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22222457Sattilio * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23222457Sattilio * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24222457Sattilio * SUCH DAMAGE. 25222457Sattilio */ 26222457Sattilio 27222457Sattilio#include <sys/cdefs.h> 28222457Sattilio__FBSDID("$FreeBSD: releng/10.3/sys/dev/iicbus/ad7417.c 239397 2012-08-19 19:31:36Z andreast $"); 29222457Sattilio 30222457Sattilio#include <sys/param.h> 31222457Sattilio#include <sys/bus.h> 32222457Sattilio#include <sys/systm.h> 33222457Sattilio#include <sys/module.h> 34222457Sattilio#include <sys/callout.h> 35222457Sattilio#include <sys/conf.h> 36222457Sattilio#include <sys/cpu.h> 37222457Sattilio#include <sys/ctype.h> 38222457Sattilio#include <sys/kernel.h> 39222457Sattilio#include <sys/reboot.h> 40222457Sattilio#include <sys/rman.h> 41222457Sattilio#include <sys/sysctl.h> 42222457Sattilio#include <sys/limits.h> 43222457Sattilio 44222457Sattilio#include <machine/bus.h> 45222457Sattilio#include <machine/md_var.h> 46222457Sattilio 47222457Sattilio#include <dev/iicbus/iicbus.h> 48222457Sattilio#include <dev/iicbus/iiconf.h> 49222457Sattilio 50222457Sattilio#include <dev/ofw/openfirm.h> 51222457Sattilio#include <dev/ofw/ofw_bus.h> 52222526Sattilio#include <powerpc/powermac/powermac_thermal.h> 53222457Sattilio 54222457Sattilio/* CPU A/B sensors, temp and adc: AD7417. */ 55222457Sattilio 56222457Sattilio#define AD7417_TEMP 0x00 57222457Sattilio#define AD7417_CONFIG 0x01 58222457Sattilio#define AD7417_ADC 0x04 59222457Sattilio#define AD7417_CONFIG2 0x05 60222457Sattilio#define AD7417_CONFMASK 0xe0 61222457Sattilio 62222457Sattiliouint8_t adc741x_config; 63222457Sattilio 64222457Sattiliostruct ad7417_sensor { 65222526Sattilio struct pmac_therm therm; 66222526Sattilio device_t dev; 67222457Sattilio int id; 68222457Sattilio enum { 69222457Sattilio ADC7417_TEMP_SENSOR, 70222457Sattilio ADC7417_ADC_SENSOR 71222457Sattilio } type; 72222457Sattilio}; 73222457Sattilio 74222860Sandreaststruct write_data { 75222860Sandreast uint8_t reg; 76222860Sandreast uint8_t val; 77222860Sandreast}; 78222860Sandreast 79222860Sandreaststruct read_data { 80222860Sandreast uint8_t reg; 81222860Sandreast uint16_t val; 82222860Sandreast}; 83222860Sandreast 84222457Sattilio/* Regular bus attachment functions */ 85222457Sattiliostatic int ad7417_probe(device_t); 86222457Sattiliostatic int ad7417_attach(device_t); 87222457Sattilio 88222457Sattilio/* Utility functions */ 89222457Sattiliostatic int ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS); 90222457Sattiliostatic int ad7417_write(device_t dev, uint32_t addr, uint8_t reg, 91222457Sattilio uint8_t *buf, int len); 92222457Sattiliostatic int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, 93222457Sattilio uint8_t *data); 94222457Sattiliostatic int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, 95222457Sattilio uint16_t *data); 96222860Sandreaststatic int ad7417_write_read(device_t dev, uint32_t addr, 97222860Sandreast struct write_data out, struct read_data *in); 98222526Sattiliostatic int ad7417_diode_read(struct ad7417_sensor *sens); 99222526Sattiliostatic int ad7417_adc_read(struct ad7417_sensor *sens); 100222526Sattiliostatic int ad7417_sensor_read(struct ad7417_sensor *sens); 101222457Sattilio 102222457Sattiliostruct ad7417_softc { 103222457Sattilio device_t sc_dev; 104222457Sattilio uint32_t sc_addr; 105222457Sattilio struct ad7417_sensor *sc_sensors; 106222457Sattilio int sc_nsensors; 107239397Sandreast int init_done; 108222457Sattilio}; 109222457Sattiliostatic device_method_t ad7417_methods[] = { 110222457Sattilio /* Device interface */ 111222457Sattilio DEVMETHOD(device_probe, ad7417_probe), 112222457Sattilio DEVMETHOD(device_attach, ad7417_attach), 113222457Sattilio { 0, 0 }, 114222457Sattilio}; 115222457Sattilio 116222457Sattiliostatic driver_t ad7417_driver = { 117222457Sattilio "ad7417", 118222457Sattilio ad7417_methods, 119222457Sattilio sizeof(struct ad7417_softc) 120222457Sattilio}; 121222457Sattilio 122222457Sattiliostatic devclass_t ad7417_devclass; 123222457Sattilio 124222457SattilioDRIVER_MODULE(ad7417, iicbus, ad7417_driver, ad7417_devclass, 0, 0); 125227293Sedstatic MALLOC_DEFINE(M_AD7417, "ad7417", "Supply-Monitor AD7417"); 126222457Sattilio 127222457Sattilio 128222457Sattiliostatic int 129222457Sattilioad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len) 130222457Sattilio{ 131222457Sattilio unsigned char buf[4]; 132222860Sandreast int try = 0; 133222860Sandreast 134222457Sattilio struct iic_msg msg[] = { 135222457Sattilio { addr, IIC_M_WR, 0, buf } 136222457Sattilio }; 137222457Sattilio 138222457Sattilio msg[0].len = len + 1; 139222457Sattilio buf[0] = reg; 140222457Sattilio memcpy(buf + 1, buff, len); 141222457Sattilio 142222860Sandreast for (;;) 143222860Sandreast { 144222860Sandreast if (iicbus_transfer(dev, msg, 1) == 0) 145222860Sandreast return (0); 146222860Sandreast 147222860Sandreast if (++try > 5) { 148222860Sandreast device_printf(dev, "iicbus write failed\n"); 149222860Sandreast return (-1); 150222860Sandreast } 151222860Sandreast pause("ad7417_write", hz); 152222457Sattilio } 153222457Sattilio} 154222457Sattilio 155222457Sattiliostatic int 156222457Sattilioad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data) 157222457Sattilio{ 158222457Sattilio uint8_t buf[4]; 159222860Sandreast int err, try = 0; 160222457Sattilio 161222457Sattilio struct iic_msg msg[2] = { 162222457Sattilio { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 163222457Sattilio { addr, IIC_M_RD, 1, buf }, 164222457Sattilio }; 165222457Sattilio 166222860Sandreast for (;;) 167222860Sandreast { 168222860Sandreast err = iicbus_transfer(dev, msg, 2); 169222860Sandreast if (err != 0) 170222860Sandreast goto retry; 171222860Sandreast 172222860Sandreast *data = *((uint8_t*)buf); 173222860Sandreast return (0); 174222860Sandreast retry: 175222860Sandreast if (++try > 5) { 176222860Sandreast device_printf(dev, "iicbus read failed\n"); 177222860Sandreast return (-1); 178222860Sandreast } 179222860Sandreast pause("ad7417_read_1", hz); 180222457Sattilio } 181222457Sattilio} 182222457Sattilio 183222457Sattiliostatic int 184222457Sattilioad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) 185222457Sattilio{ 186222457Sattilio uint8_t buf[4]; 187222860Sandreast int err, try = 0; 188222457Sattilio 189222457Sattilio struct iic_msg msg[2] = { 190222457Sattilio { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, 191222457Sattilio { addr, IIC_M_RD, 2, buf }, 192222457Sattilio }; 193222457Sattilio 194222860Sandreast for (;;) 195222860Sandreast { 196222860Sandreast err = iicbus_transfer(dev, msg, 2); 197222860Sandreast if (err != 0) 198222860Sandreast goto retry; 199222860Sandreast 200222860Sandreast *data = *((uint16_t*)buf); 201222860Sandreast return (0); 202222860Sandreast retry: 203222860Sandreast if (++try > 5) { 204222860Sandreast device_printf(dev, "iicbus read failed\n"); 205222860Sandreast return (-1); 206222860Sandreast } 207222860Sandreast pause("ad7417_read_2", hz); 208222457Sattilio } 209222860Sandreast} 210222457Sattilio 211222860Sandreaststatic int 212222860Sandreastad7417_write_read(device_t dev, uint32_t addr, struct write_data out, 213222860Sandreast struct read_data *in) 214222860Sandreast{ 215222860Sandreast uint8_t buf[4]; 216222860Sandreast int err, try = 0; 217222457Sattilio 218222860Sandreast /* Do a combined write/read. */ 219222860Sandreast struct iic_msg msg[3] = { 220222860Sandreast { addr, IIC_M_WR, 2, buf }, 221222860Sandreast { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &in->reg }, 222222860Sandreast { addr, IIC_M_RD, 2, buf }, 223222860Sandreast }; 224222860Sandreast 225222860Sandreast /* Prepare the write msg. */ 226222860Sandreast buf[0] = out.reg; 227222860Sandreast buf[1] = out.val & 0xff; 228222860Sandreast 229222860Sandreast for (;;) 230222860Sandreast { 231222860Sandreast err = iicbus_transfer(dev, msg, 3); 232222860Sandreast if (err != 0) 233222860Sandreast goto retry; 234222860Sandreast 235222860Sandreast in->val = *((uint16_t*)buf); 236222860Sandreast return (0); 237222860Sandreast retry: 238222860Sandreast if (++try > 5) { 239222860Sandreast device_printf(dev, "iicbus write/read failed\n"); 240222860Sandreast return (-1); 241222860Sandreast } 242222860Sandreast pause("ad7417_write_read", hz); 243222860Sandreast } 244222457Sattilio} 245222457Sattilio 246222457Sattiliostatic int 247222457Sattilioad7417_init_adc(device_t dev, uint32_t addr) 248222457Sattilio{ 249222457Sattilio uint8_t buf; 250222860Sandreast int err; 251239397Sandreast struct ad7417_softc *sc; 252222457Sattilio 253239397Sandreast sc = device_get_softc(dev); 254239397Sandreast 255222457Sattilio adc741x_config = 0; 256222457Sattilio /* Clear Config2 */ 257222457Sattilio buf = 0; 258222457Sattilio 259222860Sandreast err = ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1); 260222860Sandreast 261222457Sattilio /* Read & cache Config1 */ 262222457Sattilio buf = 0; 263222860Sandreast err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); 264222860Sandreast err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf); 265222457Sattilio adc741x_config = (uint8_t)buf; 266222457Sattilio 267222457Sattilio /* Disable shutdown mode */ 268222457Sattilio adc741x_config &= 0xfe; 269222457Sattilio buf = adc741x_config; 270222860Sandreast err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); 271222860Sandreast if (err < 0) 272222860Sandreast return (-1); 273222457Sattilio 274239397Sandreast sc->init_done = 1; 275239397Sandreast 276222457Sattilio return (0); 277222457Sattilio 278222457Sattilio} 279222457Sattiliostatic int 280222457Sattilioad7417_probe(device_t dev) 281222457Sattilio{ 282222457Sattilio const char *name, *compatible; 283222457Sattilio struct ad7417_softc *sc; 284222457Sattilio 285222457Sattilio name = ofw_bus_get_name(dev); 286222457Sattilio compatible = ofw_bus_get_compat(dev); 287222457Sattilio 288222457Sattilio if (!name) 289222457Sattilio return (ENXIO); 290222457Sattilio 291222457Sattilio if (strcmp(name, "supply-monitor") != 0 || 292222457Sattilio strcmp(compatible, "ad7417") != 0) 293222457Sattilio return (ENXIO); 294222457Sattilio 295222457Sattilio sc = device_get_softc(dev); 296222457Sattilio sc->sc_dev = dev; 297222457Sattilio sc->sc_addr = iicbus_get_addr(dev); 298222457Sattilio 299222457Sattilio device_set_desc(dev, "Supply-Monitor AD7417"); 300222457Sattilio 301222457Sattilio return (0); 302222457Sattilio} 303222457Sattilio 304222457Sattilio/* 305222457Sattilio * This function returns the number of sensors. If we call it the second time 306222457Sattilio * and we have allocated memory for sc->sc_sensors, we fill in the properties. 307222457Sattilio */ 308222457Sattiliostatic int 309222457Sattilioad7417_fill_sensor_prop(device_t dev) 310222457Sattilio{ 311222457Sattilio phandle_t child; 312222457Sattilio struct ad7417_softc *sc; 313222457Sattilio u_int id[10]; 314222457Sattilio char location[96]; 315222457Sattilio char type[32]; 316222457Sattilio int i = 0, j, len = 0, prop_len, prev_len = 0; 317222457Sattilio 318222457Sattilio sc = device_get_softc(dev); 319222457Sattilio 320222457Sattilio child = ofw_bus_get_node(dev); 321222457Sattilio 322222457Sattilio /* Fill the sensor location property. */ 323222457Sattilio prop_len = OF_getprop(child, "hwsensor-location", location, 324222457Sattilio sizeof(location)); 325222457Sattilio while (len < prop_len) { 326222457Sattilio if (sc->sc_sensors != NULL) 327222526Sattilio strcpy(sc->sc_sensors[i].therm.name, location + len); 328222457Sattilio prev_len = strlen(location + len) + 1; 329222457Sattilio len += prev_len; 330222457Sattilio i++; 331222457Sattilio } 332222457Sattilio if (sc->sc_sensors == NULL) 333222457Sattilio return (i); 334222457Sattilio 335222526Sattilio /* Fill the sensor type property. */ 336222457Sattilio len = 0; 337222457Sattilio i = 0; 338222457Sattilio prev_len = 0; 339222457Sattilio prop_len = OF_getprop(child, "hwsensor-type", type, sizeof(type)); 340222457Sattilio while (len < prop_len) { 341222457Sattilio if (strcmp(type + len, "temperature") == 0) 342222457Sattilio sc->sc_sensors[i].type = ADC7417_TEMP_SENSOR; 343222457Sattilio else 344222457Sattilio sc->sc_sensors[i].type = ADC7417_ADC_SENSOR; 345222457Sattilio prev_len = strlen(type + len) + 1; 346222457Sattilio len += prev_len; 347222457Sattilio i++; 348222457Sattilio } 349222457Sattilio 350222457Sattilio /* Fill the sensor id property. Taken from OF. */ 351222457Sattilio prop_len = OF_getprop(child, "hwsensor-id", id, sizeof(id)); 352222457Sattilio for (j = 0; j < i; j++) 353222457Sattilio sc->sc_sensors[j].id = id[j]; 354222457Sattilio 355222526Sattilio /* Fill the sensor zone property. Taken from OF. */ 356222526Sattilio prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id)); 357222526Sattilio for (j = 0; j < i; j++) 358222526Sattilio sc->sc_sensors[j].therm.zone = id[j]; 359222526Sattilio 360222526Sattilio /* Finish setting up sensor properties */ 361222526Sattilio for (j = 0; j < i; j++) { 362222526Sattilio sc->sc_sensors[j].dev = dev; 363222526Sattilio 364222526Sattilio /* HACK: Apple wired a random diode to the ADC line */ 365222526Sattilio if (strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP") 366222526Sattilio != NULL) { 367222526Sattilio sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR; 368222526Sattilio sc->sc_sensors[j].therm.read = 369222526Sattilio (int (*)(struct pmac_therm *))(ad7417_diode_read); 370222526Sattilio } else { 371222526Sattilio sc->sc_sensors[j].therm.read = 372222526Sattilio (int (*)(struct pmac_therm *))(ad7417_sensor_read); 373222526Sattilio } 374222526Sattilio 375222526Sattilio if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR) 376222526Sattilio continue; 377222526Sattilio 378222526Sattilio /* Make up some ranges */ 379222860Sandreast sc->sc_sensors[j].therm.target_temp = 500 + ZERO_C_TO_K; 380222860Sandreast sc->sc_sensors[j].therm.max_temp = 900 + ZERO_C_TO_K; 381222526Sattilio 382222526Sattilio pmac_thermal_sensor_register(&sc->sc_sensors[j].therm); 383222526Sattilio } 384222526Sattilio 385222457Sattilio return (i); 386222457Sattilio} 387222457Sattilio 388222457Sattiliostatic int 389222457Sattilioad7417_attach(device_t dev) 390222457Sattilio{ 391222457Sattilio struct ad7417_softc *sc; 392222457Sattilio struct sysctl_oid *oid, *sensroot_oid; 393222457Sattilio struct sysctl_ctx_list *ctx; 394222457Sattilio char sysctl_name[32]; 395222457Sattilio int i, j; 396222457Sattilio const char *unit; 397222457Sattilio const char *desc; 398222457Sattilio 399222457Sattilio sc = device_get_softc(dev); 400222457Sattilio 401222457Sattilio sc->sc_nsensors = 0; 402222457Sattilio 403222457Sattilio /* Count the actual number of sensors. */ 404222457Sattilio sc->sc_nsensors = ad7417_fill_sensor_prop(dev); 405222457Sattilio 406222457Sattilio device_printf(dev, "%d sensors detected.\n", sc->sc_nsensors); 407222457Sattilio 408222457Sattilio if (sc->sc_nsensors == 0) 409222457Sattilio device_printf(dev, "WARNING: No AD7417 sensors detected!\n"); 410222457Sattilio 411222457Sattilio sc->sc_sensors = malloc (sc->sc_nsensors * sizeof(struct ad7417_sensor), 412222457Sattilio M_AD7417, M_WAITOK | M_ZERO); 413222457Sattilio 414222457Sattilio ctx = device_get_sysctl_ctx(dev); 415222457Sattilio sensroot_oid = SYSCTL_ADD_NODE(ctx, 416222457Sattilio SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor", 417222457Sattilio CTLFLAG_RD, 0, "AD7417 Sensor Information"); 418222457Sattilio 419222457Sattilio /* Now we can fill the properties into the allocated struct. */ 420222457Sattilio sc->sc_nsensors = ad7417_fill_sensor_prop(dev); 421222457Sattilio 422222457Sattilio /* Add sysctls for the sensors. */ 423222457Sattilio for (i = 0; i < sc->sc_nsensors; i++) { 424222526Sattilio for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) { 425222526Sattilio sysctl_name[j] = 426222526Sattilio tolower(sc->sc_sensors[i].therm.name[j]); 427222457Sattilio if (isspace(sysctl_name[j])) 428222457Sattilio sysctl_name[j] = '_'; 429222457Sattilio } 430222457Sattilio sysctl_name[j] = 0; 431222457Sattilio 432222457Sattilio oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid), 433222457Sattilio OID_AUTO, 434222457Sattilio sysctl_name, CTLFLAG_RD, 0, 435222457Sattilio "Sensor Information"); 436222457Sattilio 437222457Sattilio if (sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR) { 438222457Sattilio unit = "temp"; 439239397Sandreast desc = "sensor unit (C)"; 440222457Sattilio } else { 441222457Sattilio unit = "volt"; 442239397Sandreast desc = "sensor unit (mV)"; 443222457Sattilio } 444222457Sattilio /* I use i to pass the sensor id. */ 445222457Sattilio SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 446222457Sattilio unit, CTLTYPE_INT | CTLFLAG_RD, dev, 447222457Sattilio i, ad7417_sensor_sysctl, 448222457Sattilio sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR ? 449222457Sattilio "IK" : "I", desc); 450222457Sattilio } 451222457Sattilio /* Dump sensor location, ID & type. */ 452222457Sattilio if (bootverbose) { 453222457Sattilio device_printf(dev, "Sensors\n"); 454222457Sattilio for (i = 0; i < sc->sc_nsensors; i++) { 455222457Sattilio device_printf(dev, "Location: %s ID: %d type: %d\n", 456222526Sattilio sc->sc_sensors[i].therm.name, 457222457Sattilio sc->sc_sensors[i].id, 458222457Sattilio sc->sc_sensors[i].type); 459222457Sattilio } 460222457Sattilio } 461222457Sattilio 462222457Sattilio return (0); 463222457Sattilio} 464222457Sattilio 465222457Sattiliostatic int 466222457Sattilioad7417_get_temp(device_t dev, uint32_t addr, int *temp) 467222457Sattilio{ 468222457Sattilio uint16_t buf[2]; 469222457Sattilio uint16_t read; 470222860Sandreast int err; 471222457Sattilio 472222860Sandreast err = ad7417_read_2(dev, addr, AD7417_TEMP, buf); 473222860Sandreast 474222860Sandreast if (err < 0) 475222860Sandreast return (-1); 476222860Sandreast 477222457Sattilio read = *((int16_t*)buf); 478222457Sattilio 479222457Sattilio /* The ADC is 10 bit, the resolution is 0.25 C. 480222457Sattilio The temperature is in tenth kelvin. 481222457Sattilio */ 482222457Sattilio *temp = (((int16_t)(read & 0xffc0)) >> 6) * 25 / 10; 483222457Sattilio return (0); 484222457Sattilio} 485222457Sattilio 486222457Sattiliostatic int 487222457Sattilioad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value, 488222457Sattilio uint8_t chan) 489222457Sattilio{ 490222860Sandreast uint8_t tmp; 491222860Sandreast int err; 492222860Sandreast struct write_data config; 493222860Sandreast struct read_data data; 494222457Sattilio 495222457Sattilio tmp = chan << 5; 496222860Sandreast config.reg = AD7417_CONFIG; 497222860Sandreast data.reg = AD7417_ADC; 498222860Sandreast data.val = 0; 499222457Sattilio 500222860Sandreast err = ad7417_read_1(dev, addr, AD7417_CONFIG, &config.val); 501222457Sattilio 502222860Sandreast config.val = (config.val & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK); 503222457Sattilio 504222860Sandreast err = ad7417_write_read(dev, addr, config, &data); 505222860Sandreast if (err < 0) 506222860Sandreast return (-1); 507222457Sattilio 508222860Sandreast *value = ((uint32_t)data.val) >> 6; 509222457Sattilio 510222457Sattilio return (0); 511222457Sattilio} 512222457Sattilio 513222457Sattiliostatic int 514222526Sattilioad7417_diode_read(struct ad7417_sensor *sens) 515222457Sattilio{ 516222526Sattilio static int eeprom_read = 0; 517222526Sattilio static cell_t eeprom[2][40]; 518222526Sattilio phandle_t eeprom_node; 519222526Sattilio int rawval, diode_slope, diode_offset; 520222526Sattilio int temp; 521222526Sattilio 522222526Sattilio if (!eeprom_read) { 523222526Sattilio eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0"); 524222526Sattilio OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0])); 525222526Sattilio eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2"); 526222526Sattilio OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1])); 527222526Sattilio eeprom_read = 1; 528222526Sattilio } 529222526Sattilio 530222526Sattilio rawval = ad7417_adc_read(sens); 531222860Sandreast if (rawval < 0) 532222860Sandreast return (-1); 533222860Sandreast 534222526Sattilio if (strstr(sens->therm.name, "CPU B") != NULL) { 535222526Sattilio diode_slope = eeprom[1][0x11] >> 16; 536222526Sattilio diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12; 537222526Sattilio } else { 538222526Sattilio diode_slope = eeprom[0][0x11] >> 16; 539222526Sattilio diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12; 540222526Sattilio } 541222526Sattilio 542222526Sattilio temp = (rawval*diode_slope + diode_offset) >> 2; 543222526Sattilio temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16); 544222526Sattilio 545222860Sandreast return (temp + ZERO_C_TO_K); 546222526Sattilio} 547222526Sattilio 548222526Sattiliostatic int 549222526Sattilioad7417_adc_read(struct ad7417_sensor *sens) 550222526Sattilio{ 551222457Sattilio struct ad7417_softc *sc; 552222526Sattilio uint8_t chan; 553222526Sattilio int temp; 554222457Sattilio 555222526Sattilio sc = device_get_softc(sens->dev); 556222457Sattilio 557222526Sattilio switch (sens->id) { 558222526Sattilio case 11: 559222526Sattilio case 16: 560222526Sattilio chan = 1; 561222526Sattilio break; 562222526Sattilio case 12: 563222526Sattilio case 17: 564222526Sattilio chan = 2; 565222526Sattilio break; 566222526Sattilio case 13: 567222526Sattilio case 18: 568222526Sattilio chan = 3; 569222526Sattilio break; 570222526Sattilio case 14: 571222526Sattilio case 19: 572222526Sattilio chan = 4; 573222526Sattilio break; 574222526Sattilio default: 575222526Sattilio chan = 1; 576222526Sattilio } 577222526Sattilio 578222860Sandreast if (ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan) < 0) 579222860Sandreast return (-1); 580222526Sattilio 581222526Sattilio return (temp); 582222526Sattilio} 583222526Sattilio 584222526Sattilio 585222526Sattiliostatic int 586222526Sattilioad7417_sensor_read(struct ad7417_sensor *sens) 587222526Sattilio{ 588222526Sattilio struct ad7417_softc *sc; 589222526Sattilio int temp; 590222526Sattilio 591222526Sattilio sc = device_get_softc(sens->dev); 592222526Sattilio 593239397Sandreast /* Init the ADC if not already done.*/ 594239397Sandreast if (!sc->init_done) 595239397Sandreast if (ad7417_init_adc(sc->sc_dev, sc->sc_addr) < 0) 596239397Sandreast return (-1); 597222457Sattilio 598222457Sattilio if (sens->type == ADC7417_TEMP_SENSOR) { 599222860Sandreast if (ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp) < 0) 600222860Sandreast return (-1); 601222860Sandreast temp += ZERO_C_TO_K; 602222457Sattilio } else { 603222526Sattilio temp = ad7417_adc_read(sens); 604222457Sattilio } 605222526Sattilio return (temp); 606222457Sattilio} 607222457Sattilio 608222457Sattiliostatic int 609222457Sattilioad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS) 610222457Sattilio{ 611222457Sattilio device_t dev; 612222457Sattilio struct ad7417_softc *sc; 613222457Sattilio struct ad7417_sensor *sens; 614222457Sattilio int value = 0; 615222457Sattilio int error; 616222457Sattilio 617222457Sattilio dev = arg1; 618222457Sattilio sc = device_get_softc(dev); 619222457Sattilio sens = &sc->sc_sensors[arg2]; 620222457Sattilio 621222526Sattilio value = sens->therm.read(&sens->therm); 622222526Sattilio if (value < 0) 623222526Sattilio return (ENXIO); 624222457Sattilio 625222526Sattilio error = sysctl_handle_int(oidp, &value, 0, req); 626222457Sattilio 627222457Sattilio return (error); 628222457Sattilio} 629