1261421Sjhibbits/*- 2261421Sjhibbits * Copyright (c) 2012 Andreas Tobler 3261421Sjhibbits * Copyright (c) 2014 Justin Hibbits 4261421Sjhibbits * All rights reserved. 5261421Sjhibbits * 6261421Sjhibbits * Redistribution and use in source and binary forms, with or without 7261421Sjhibbits * modification, are permitted provided that the following conditions 8261421Sjhibbits * are met: 9261421Sjhibbits * 1. Redistributions of source code must retain the above copyright 10261421Sjhibbits * notice, this list of conditions and the following disclaimer. 11261421Sjhibbits * 2. Redistributions in binary form must reproduce the above copyright 12261421Sjhibbits * notice, this list of conditions and the following disclaimer in the 13261421Sjhibbits * documentation and/or other materials provided with the distribution. 14261421Sjhibbits * 15261421Sjhibbits * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16261421Sjhibbits * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17261421Sjhibbits * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18261421Sjhibbits * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19261421Sjhibbits * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 20261421Sjhibbits * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21261421Sjhibbits * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22261421Sjhibbits * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23261421Sjhibbits * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24261421Sjhibbits * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25261421Sjhibbits * SUCH DAMAGE. 26261421Sjhibbits */ 27261421Sjhibbits 28261421Sjhibbits#include <sys/cdefs.h> 29261421Sjhibbits__FBSDID("$FreeBSD: releng/10.3/sys/dev/iicbus/adt746x.c 263197 2014-03-15 00:23:35Z jhibbits $"); 30261421Sjhibbits 31261421Sjhibbits#include <sys/param.h> 32261421Sjhibbits#include <sys/bus.h> 33261421Sjhibbits#include <sys/systm.h> 34261421Sjhibbits#include <sys/module.h> 35261421Sjhibbits#include <sys/callout.h> 36261421Sjhibbits#include <sys/conf.h> 37261421Sjhibbits#include <sys/cpu.h> 38261421Sjhibbits#include <sys/ctype.h> 39261421Sjhibbits#include <sys/kernel.h> 40261421Sjhibbits#include <sys/reboot.h> 41261421Sjhibbits#include <sys/rman.h> 42261421Sjhibbits#include <sys/sysctl.h> 43261421Sjhibbits#include <sys/limits.h> 44261421Sjhibbits 45261421Sjhibbits#include <machine/bus.h> 46261421Sjhibbits#include <machine/md_var.h> 47261421Sjhibbits 48261421Sjhibbits#include <dev/iicbus/iicbus.h> 49261421Sjhibbits#include <dev/iicbus/iiconf.h> 50261421Sjhibbits 51261421Sjhibbits#include <dev/ofw/openfirm.h> 52261421Sjhibbits#include <dev/ofw/ofw_bus.h> 53261421Sjhibbits#include <powerpc/powermac/powermac_thermal.h> 54261421Sjhibbits 55261421Sjhibbits/* ADT746X registers. */ 56261421Sjhibbits#define ADT746X_TACH1LOW 0x28 57261421Sjhibbits#define ADT746X_TACH1HIGH 0x29 58261421Sjhibbits#define ADT746X_TACH2LOW 0x2a 59261421Sjhibbits#define ADT746X_TACH2HIGH 0x2b 60261421Sjhibbits#define ADT746X_PWM1 0x30 61261421Sjhibbits#define ADT746X_PWM2 0x31 62261421Sjhibbits#define ADT746X_DEVICE_ID 0x3d 63261421Sjhibbits#define ADT746X_COMPANY_ID 0x3e 64261421Sjhibbits#define ADT746X_REV_ID 0x3f 65261421Sjhibbits#define ADT746X_CONFIG 0x40 66261421Sjhibbits#define ADT746X_PWM1_CONF 0x5c 67261421Sjhibbits#define ADT746X_PWM2_CONF 0x5d 68261421Sjhibbits#define ADT746X_MANUAL_MASK 0xe0 69261421Sjhibbits 70261421Sjhibbits#define ADT7460_DEV_ID 0x27 71261421Sjhibbits#define ADT7467_DEV_ID 0x68 72261421Sjhibbits 73261421Sjhibbitsstruct adt746x_fan { 74261421Sjhibbits struct pmac_fan fan; 75261421Sjhibbits device_t dev; 76261421Sjhibbits int id; 77261421Sjhibbits int setpoint; 78261421Sjhibbits int pwm_reg; 79261421Sjhibbits int conf_reg; 80261421Sjhibbits}; 81261421Sjhibbits 82261421Sjhibbitsstruct adt746x_sensor { 83261421Sjhibbits struct pmac_therm therm; 84261421Sjhibbits device_t dev; 85261421Sjhibbits int id; 86261421Sjhibbits cell_t reg; 87261421Sjhibbits enum { 88261421Sjhibbits ADT746X_SENSOR_TEMP, 89261421Sjhibbits ADT746X_SENSOR_VOLT, 90261421Sjhibbits ADT746X_SENSOR_SPEED 91261421Sjhibbits } type; 92261421Sjhibbits}; 93261421Sjhibbits 94261421Sjhibbitsstruct adt746x_softc { 95261421Sjhibbits device_t sc_dev; 96261421Sjhibbits struct intr_config_hook enum_hook; 97261421Sjhibbits uint32_t sc_addr; 98261421Sjhibbits /* The 7467 supports up to 4 fans, 2 voltage and 3 temperature sensors. */ 99261421Sjhibbits struct adt746x_fan sc_fans[4]; 100261421Sjhibbits int sc_nfans; 101261421Sjhibbits struct adt746x_sensor sc_sensors[9]; 102261421Sjhibbits int sc_nsensors; 103261421Sjhibbits int device_id; 104261421Sjhibbits 105261421Sjhibbits}; 106261421Sjhibbits 107261421Sjhibbits 108261421Sjhibbits/* Regular bus attachment functions */ 109261421Sjhibbits 110261421Sjhibbitsstatic int adt746x_probe(device_t); 111261421Sjhibbitsstatic int adt746x_attach(device_t); 112261421Sjhibbits 113261421Sjhibbits 114261421Sjhibbits/* Utility functions */ 115261421Sjhibbitsstatic void adt746x_attach_fans(device_t dev); 116261421Sjhibbitsstatic void adt746x_attach_sensors(device_t dev); 117261421Sjhibbitsstatic int adt746x_fill_fan_prop(device_t dev); 118261421Sjhibbitsstatic int adt746x_fill_sensor_prop(device_t dev); 119261421Sjhibbits 120261421Sjhibbitsstatic int adt746x_fan_set_pwm(struct adt746x_fan *fan, int pwm); 121261421Sjhibbitsstatic int adt746x_fan_get_pwm(struct adt746x_fan *fan); 122261421Sjhibbitsstatic int adt746x_sensor_read(struct adt746x_sensor *sens); 123261421Sjhibbitsstatic void adt746x_start(void *xdev); 124261421Sjhibbits 125261421Sjhibbits/* i2c read/write functions. */ 126261421Sjhibbitsstatic int adt746x_write(device_t dev, uint32_t addr, uint8_t reg, 127261421Sjhibbits uint8_t *buf); 128261421Sjhibbitsstatic int adt746x_read(device_t dev, uint32_t addr, uint8_t reg, 129261421Sjhibbits uint8_t *data); 130261421Sjhibbits 131261421Sjhibbitsstatic device_method_t adt746x_methods[] = { 132261421Sjhibbits /* Device interface */ 133261421Sjhibbits DEVMETHOD(device_probe, adt746x_probe), 134261421Sjhibbits DEVMETHOD(device_attach, adt746x_attach), 135261421Sjhibbits { 0, 0 }, 136261421Sjhibbits}; 137261421Sjhibbits 138261421Sjhibbitsstatic driver_t adt746x_driver = { 139261421Sjhibbits "adt746x", 140261421Sjhibbits adt746x_methods, 141261421Sjhibbits sizeof(struct adt746x_softc) 142261421Sjhibbits}; 143261421Sjhibbits 144261421Sjhibbitsstatic devclass_t adt746x_devclass; 145261421Sjhibbits 146261421SjhibbitsDRIVER_MODULE(adt746x, iicbus, adt746x_driver, adt746x_devclass, 0, 0); 147261421Sjhibbitsstatic MALLOC_DEFINE(M_ADT746X, "adt746x", "ADT Sensor Information"); 148261421Sjhibbits 149261421Sjhibbits 150261421Sjhibbits/* i2c read/write functions. */ 151261421Sjhibbits 152261421Sjhibbitsstatic int 153261421Sjhibbitsadt746x_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff) 154261421Sjhibbits{ 155261421Sjhibbits uint8_t buf[4]; 156261421Sjhibbits int try = 0; 157261421Sjhibbits 158261421Sjhibbits struct iic_msg msg[] = { 159261421Sjhibbits {addr, IIC_M_WR, 2, buf } 160261421Sjhibbits }; 161261421Sjhibbits 162261421Sjhibbits /* Prepare the write msg. */ 163261421Sjhibbits buf[0] = reg; 164261421Sjhibbits memcpy(buf + 1, buff, 1); 165261421Sjhibbits 166261421Sjhibbits for (;;) 167261421Sjhibbits { 168261421Sjhibbits if (iicbus_transfer(dev, msg, 1) == 0) 169261421Sjhibbits return (0); 170261421Sjhibbits if (++try > 5) { 171261421Sjhibbits device_printf(dev, "iicbus write failed\n"); 172261421Sjhibbits return (-1); 173261421Sjhibbits } 174261421Sjhibbits pause("adt746x_write", hz); 175261421Sjhibbits } 176261421Sjhibbits return (0); 177261421Sjhibbits} 178261421Sjhibbits 179261421Sjhibbitsstatic int 180261421Sjhibbitsadt746x_read(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data) 181261421Sjhibbits{ 182261421Sjhibbits uint8_t buf[4]; 183261421Sjhibbits int err, try = 0; 184261421Sjhibbits 185261421Sjhibbits struct iic_msg msg[2] = { 186261421Sjhibbits {addr, IIC_M_WR | IIC_M_NOSTOP, 1, ®}, 187261421Sjhibbits {addr, IIC_M_RD, 1, buf}, 188261421Sjhibbits }; 189261421Sjhibbits 190261421Sjhibbits for (;;) 191261421Sjhibbits { 192261421Sjhibbits err = iicbus_transfer(dev, msg, 2); 193261421Sjhibbits if (err != 0) 194261421Sjhibbits goto retry; 195261421Sjhibbits 196261421Sjhibbits *data = *((uint8_t*)buf); 197261421Sjhibbits return (0); 198261421Sjhibbits retry: 199261421Sjhibbits if (++try > 5) { 200261421Sjhibbits device_printf(dev, "iicbus read failed\n"); 201261421Sjhibbits return (-1); 202261421Sjhibbits } 203261421Sjhibbits pause("adt746x_read", hz); 204261421Sjhibbits } 205261421Sjhibbits} 206261421Sjhibbits 207261421Sjhibbitsstatic int 208261421Sjhibbitsadt746x_probe(device_t dev) 209261421Sjhibbits{ 210261421Sjhibbits const char *name, *compatible; 211261421Sjhibbits struct adt746x_softc *sc; 212261421Sjhibbits 213261421Sjhibbits name = ofw_bus_get_name(dev); 214261421Sjhibbits compatible = ofw_bus_get_compat(dev); 215261421Sjhibbits 216261421Sjhibbits if (!name) 217261421Sjhibbits return (ENXIO); 218261421Sjhibbits 219261421Sjhibbits if (strcmp(name, "fan") != 0 || 220261421Sjhibbits (strcmp(compatible, "adt7460") != 0 && 221261421Sjhibbits strcmp(compatible, "adt7467") != 0)) 222261421Sjhibbits return (ENXIO); 223261421Sjhibbits 224261421Sjhibbits sc = device_get_softc(dev); 225261421Sjhibbits sc->sc_dev = dev; 226261421Sjhibbits sc->sc_addr = iicbus_get_addr(dev); 227261421Sjhibbits 228261421Sjhibbits device_set_desc(dev, "Apple Thermostat Unit ADT746X"); 229261421Sjhibbits 230261421Sjhibbits return (0); 231261421Sjhibbits} 232261421Sjhibbits 233261421Sjhibbitsstatic int 234261421Sjhibbitsadt746x_attach(device_t dev) 235261421Sjhibbits{ 236261421Sjhibbits struct adt746x_softc *sc; 237261421Sjhibbits 238261421Sjhibbits sc = device_get_softc(dev); 239261421Sjhibbits 240261421Sjhibbits sc->enum_hook.ich_func = adt746x_start; 241261421Sjhibbits sc->enum_hook.ich_arg = dev; 242261421Sjhibbits 243261421Sjhibbits /* We have to wait until interrupts are enabled. I2C read and write 244261421Sjhibbits * only works if the interrupts are available. 245261421Sjhibbits * The unin/i2c is controlled by the htpic on unin. But this is not 246261421Sjhibbits * the master. The openpic on mac-io is controlling the htpic. 247261421Sjhibbits * This one gets attached after the mac-io probing and then the 248261421Sjhibbits * interrupts will be available. 249261421Sjhibbits */ 250261421Sjhibbits 251261421Sjhibbits if (config_intrhook_establish(&sc->enum_hook) != 0) 252261421Sjhibbits return (ENOMEM); 253261421Sjhibbits 254261421Sjhibbits return (0); 255261421Sjhibbits} 256261421Sjhibbits 257261421Sjhibbitsstatic void 258261421Sjhibbitsadt746x_start(void *xdev) 259261421Sjhibbits{ 260261421Sjhibbits uint8_t did, cid, rev, conf; 261261421Sjhibbits 262261421Sjhibbits struct adt746x_softc *sc; 263261421Sjhibbits 264261421Sjhibbits device_t dev = (device_t)xdev; 265261421Sjhibbits 266261421Sjhibbits sc = device_get_softc(dev); 267261421Sjhibbits 268261421Sjhibbits adt746x_read(sc->sc_dev, sc->sc_addr, ADT746X_DEVICE_ID, &did); 269261421Sjhibbits adt746x_read(sc->sc_dev, sc->sc_addr, ADT746X_COMPANY_ID, &cid); 270261421Sjhibbits adt746x_read(sc->sc_dev, sc->sc_addr, ADT746X_REV_ID, &rev); 271261421Sjhibbits adt746x_read(sc->sc_dev, sc->sc_addr, ADT746X_CONFIG, &conf); 272261421Sjhibbits 273261421Sjhibbits device_printf(dev, "Dev ID %#x, Company ID %#x, Rev ID %#x CNF: %#x\n", 274261421Sjhibbits did, cid, rev, conf); 275261421Sjhibbits 276261421Sjhibbits /* We can get the device id either from 'of' properties or from the chip 277261421Sjhibbits itself. This method makes sure we can read the chip, otherwise 278261421Sjhibbits we return. */ 279261421Sjhibbits 280261421Sjhibbits sc->device_id = did; 281261421Sjhibbits 282261421Sjhibbits conf = 1; 283261421Sjhibbits /* Start the ADT7460. */ 284261421Sjhibbits if (sc->device_id == ADT7460_DEV_ID) 285261421Sjhibbits adt746x_write(sc->sc_dev, sc->sc_addr, ADT746X_CONFIG, &conf); 286261421Sjhibbits 287261421Sjhibbits /* Detect and attach child devices. */ 288261421Sjhibbits adt746x_attach_fans(dev); 289261421Sjhibbits adt746x_attach_sensors(dev); 290261421Sjhibbits config_intrhook_disestablish(&sc->enum_hook); 291261421Sjhibbits} 292261421Sjhibbits 293261421Sjhibbits/* 294261421Sjhibbits * Sensor and fan management 295261421Sjhibbits */ 296261421Sjhibbitsstatic int 297261421Sjhibbitsadt746x_fan_set_pwm(struct adt746x_fan *fan, int pwm) 298261421Sjhibbits{ 299261421Sjhibbits uint8_t reg = 0, manual, mode = 0; 300261421Sjhibbits struct adt746x_softc *sc; 301261421Sjhibbits uint8_t buf; 302261421Sjhibbits 303261421Sjhibbits sc = device_get_softc(fan->dev); 304261421Sjhibbits 305261421Sjhibbits /* Clamp to allowed range */ 306261421Sjhibbits pwm = max(fan->fan.min_rpm, pwm); 307261421Sjhibbits pwm = min(fan->fan.max_rpm, pwm); 308261421Sjhibbits 309261421Sjhibbits reg = fan->pwm_reg; 310261421Sjhibbits mode = fan->conf_reg; 311261421Sjhibbits 312261421Sjhibbits /* From the 7460 datasheet: 313261421Sjhibbits PWM dutycycle can be programmed from 0% (0x00) to 100% (0xFF) 314261421Sjhibbits in steps of 0.39% (256 steps). 315261421Sjhibbits */ 316261421Sjhibbits buf = (pwm * 100 / 39) - (pwm ? 1 : 0); 317261421Sjhibbits fan->setpoint = buf; 318261421Sjhibbits 319261421Sjhibbits /* Manual mode. */ 320261421Sjhibbits adt746x_read(sc->sc_dev, sc->sc_addr, mode, &manual); 321261421Sjhibbits manual |= ADT746X_MANUAL_MASK; 322261421Sjhibbits adt746x_write(sc->sc_dev, sc->sc_addr, mode, &manual); 323261421Sjhibbits 324261421Sjhibbits /* Write speed. */ 325261421Sjhibbits adt746x_write(sc->sc_dev, sc->sc_addr, reg, &buf); 326261421Sjhibbits 327261421Sjhibbits return (0); 328261421Sjhibbits} 329261421Sjhibbits 330261421Sjhibbitsstatic int 331261421Sjhibbitsadt746x_fan_get_pwm(struct adt746x_fan *fan) 332261421Sjhibbits{ 333261421Sjhibbits uint8_t buf, reg; 334261421Sjhibbits uint16_t pwm; 335261421Sjhibbits struct adt746x_softc *sc; 336261421Sjhibbits 337261421Sjhibbits sc = device_get_softc(fan->dev); 338261421Sjhibbits 339261421Sjhibbits reg = fan->pwm_reg; 340261421Sjhibbits 341261421Sjhibbits adt746x_read(sc->sc_dev, sc->sc_addr, reg, &buf); 342261421Sjhibbits 343261421Sjhibbits pwm = (buf * 39 / 100) + (buf ? 1 : 0); 344261421Sjhibbits return (pwm); 345261421Sjhibbits} 346261421Sjhibbits 347261421Sjhibbitsstatic int 348261421Sjhibbitsadt746x_fill_fan_prop(device_t dev) 349261421Sjhibbits{ 350261421Sjhibbits phandle_t child; 351261421Sjhibbits struct adt746x_softc *sc; 352261421Sjhibbits u_int *id; 353261421Sjhibbits char *location; 354261421Sjhibbits int i, id_len, len = 0, location_len, prev_len = 0; 355261421Sjhibbits 356261421Sjhibbits sc = device_get_softc(dev); 357261421Sjhibbits 358261421Sjhibbits child = ofw_bus_get_node(dev); 359261421Sjhibbits 360261421Sjhibbits /* Fill the fan location property. */ 361261421Sjhibbits location_len = OF_getprop_alloc(child, "hwctrl-location", 1, (void **)&location); 362261421Sjhibbits id_len = OF_getprop_alloc(child, "hwctrl-id", sizeof(cell_t), (void **)&id); 363261421Sjhibbits if (location_len == -1 || id_len == -1) { 364261421Sjhibbits free(location, M_OFWPROP); 365261421Sjhibbits free(id, M_OFWPROP); 366261421Sjhibbits return 0; 367261421Sjhibbits } 368261421Sjhibbits 369261421Sjhibbits /* Fill in all the properties for each fan. */ 370261421Sjhibbits for (i = 0; i < id_len; i++) { 371261421Sjhibbits strlcpy(sc->sc_fans[i].fan.name, location + len, 32); 372261421Sjhibbits prev_len = strlen(location + len) + 1; 373261421Sjhibbits len += prev_len; 374261421Sjhibbits sc->sc_fans[i].id = id[i]; 375261421Sjhibbits if (id[i] == 6) { 376261421Sjhibbits sc->sc_fans[i].pwm_reg = ADT746X_PWM1; 377261421Sjhibbits sc->sc_fans[i].conf_reg = ADT746X_PWM1_CONF; 378261421Sjhibbits } else if (id[i] == 7) { 379261421Sjhibbits sc->sc_fans[i].pwm_reg = ADT746X_PWM2; 380261421Sjhibbits sc->sc_fans[i].conf_reg = ADT746X_PWM2_CONF; 381261421Sjhibbits } else { 382261421Sjhibbits sc->sc_fans[i].pwm_reg = ADT746X_PWM1 + i; 383261421Sjhibbits sc->sc_fans[i].conf_reg = ADT746X_PWM1_CONF + i; 384261421Sjhibbits } 385261421Sjhibbits sc->sc_fans[i].dev = sc->sc_dev; 386261421Sjhibbits sc->sc_fans[i].fan.min_rpm = 5; /* Percent */ 387261421Sjhibbits sc->sc_fans[i].fan.max_rpm = 100; 388261421Sjhibbits sc->sc_fans[i].fan.read = NULL; 389261421Sjhibbits sc->sc_fans[i].fan.set = 390261421Sjhibbits (int (*)(struct pmac_fan *, int))(adt746x_fan_set_pwm); 391261421Sjhibbits sc->sc_fans[i].fan.default_rpm = sc->sc_fans[i].fan.max_rpm; 392261421Sjhibbits } 393261421Sjhibbits free(location, M_OFWPROP); 394261421Sjhibbits free(id, M_OFWPROP); 395261421Sjhibbits 396261421Sjhibbits return (i); 397261421Sjhibbits} 398261421Sjhibbits 399261421Sjhibbitsstatic int 400261421Sjhibbitsadt746x_fill_sensor_prop(device_t dev) 401261421Sjhibbits{ 402261421Sjhibbits phandle_t child, node; 403261421Sjhibbits struct adt746x_softc *sc; 404261421Sjhibbits char sens_type[32]; 405261421Sjhibbits int i = 0, reg, sensid; 406261421Sjhibbits 407261421Sjhibbits sc = device_get_softc(dev); 408261421Sjhibbits 409261421Sjhibbits child = ofw_bus_get_node(dev); 410261421Sjhibbits 411261421Sjhibbits /* Fill in the sensor properties for each child. */ 412261421Sjhibbits for (node = OF_child(child); node != 0; node = OF_peer(node)) { 413261421Sjhibbits if (OF_getprop(node, "sensor-id", &sensid, sizeof(sensid)) == -1) 414261421Sjhibbits continue; 415261421Sjhibbits OF_getprop(node, "location", sc->sc_sensors[i].therm.name, 32); 416261421Sjhibbits OF_getprop(node, "device_type", sens_type, sizeof(sens_type)); 417261421Sjhibbits if (strcmp(sens_type, "temperature") == 0) 418261421Sjhibbits sc->sc_sensors[i].type = ADT746X_SENSOR_TEMP; 419261421Sjhibbits else if (strcmp(sens_type, "voltage") == 0) 420261421Sjhibbits sc->sc_sensors[i].type = ADT746X_SENSOR_VOLT; 421261421Sjhibbits else 422261421Sjhibbits sc->sc_sensors[i].type = ADT746X_SENSOR_SPEED; 423261421Sjhibbits OF_getprop(node, "reg", ®, sizeof(reg)); 424261421Sjhibbits OF_getprop(node, "sensor-id", &sensid, 425261421Sjhibbits sizeof(sensid)); 426261421Sjhibbits /* This is the i2c register of the sensor. */ 427261421Sjhibbits sc->sc_sensors[i].reg = reg; 428261421Sjhibbits sc->sc_sensors[i].id = sensid; 429261421Sjhibbits OF_getprop(node, "zone", &sc->sc_sensors[i].therm.zone, 430261421Sjhibbits sizeof(sc->sc_sensors[i].therm.zone)); 431261421Sjhibbits sc->sc_sensors[i].dev = dev; 432261421Sjhibbits sc->sc_sensors[i].therm.read = 433261421Sjhibbits (int (*)(struct pmac_therm *))adt746x_sensor_read; 434261421Sjhibbits if (sc->sc_sensors[i].type == ADT746X_SENSOR_TEMP) { 435261421Sjhibbits /* Make up some ranges */ 436261421Sjhibbits sc->sc_sensors[i].therm.target_temp = 500 + ZERO_C_TO_K; 437261421Sjhibbits sc->sc_sensors[i].therm.max_temp = 800 + ZERO_C_TO_K; 438261421Sjhibbits 439261421Sjhibbits pmac_thermal_sensor_register(&sc->sc_sensors[i].therm); 440261421Sjhibbits } 441261421Sjhibbits i++; 442261421Sjhibbits } 443261421Sjhibbits 444261421Sjhibbits return (i); 445261421Sjhibbits} 446261421Sjhibbits 447261421Sjhibbitsstatic int 448261421Sjhibbitsadt746x_fanrpm_sysctl(SYSCTL_HANDLER_ARGS) 449261421Sjhibbits{ 450261421Sjhibbits device_t adt; 451261421Sjhibbits struct adt746x_softc *sc; 452261421Sjhibbits struct adt746x_fan *fan; 453261421Sjhibbits int pwm = 0, error; 454261421Sjhibbits 455261421Sjhibbits adt = arg1; 456261421Sjhibbits sc = device_get_softc(adt); 457261421Sjhibbits fan = &sc->sc_fans[arg2]; 458261421Sjhibbits pwm = adt746x_fan_get_pwm(fan); 459261421Sjhibbits error = sysctl_handle_int(oidp, &pwm, 0, req); 460261421Sjhibbits 461261421Sjhibbits if (error || !req->newptr) 462261421Sjhibbits return (error); 463261421Sjhibbits 464261421Sjhibbits return (adt746x_fan_set_pwm(fan, pwm)); 465261421Sjhibbits} 466261421Sjhibbits 467261421Sjhibbitsstatic void 468261421Sjhibbitsadt746x_attach_fans(device_t dev) 469261421Sjhibbits{ 470261421Sjhibbits struct adt746x_softc *sc; 471261421Sjhibbits struct sysctl_oid *oid, *fanroot_oid; 472261421Sjhibbits struct sysctl_ctx_list *ctx; 473261421Sjhibbits phandle_t child; 474261421Sjhibbits char sysctl_name[32]; 475261421Sjhibbits int i, j; 476261421Sjhibbits 477261421Sjhibbits sc = device_get_softc(dev); 478261421Sjhibbits 479261421Sjhibbits sc->sc_nfans = 0; 480261421Sjhibbits 481261421Sjhibbits child = ofw_bus_get_node(dev); 482261421Sjhibbits 483261421Sjhibbits /* Count the actual number of fans. */ 484261421Sjhibbits sc->sc_nfans = adt746x_fill_fan_prop(dev); 485261421Sjhibbits 486261421Sjhibbits device_printf(dev, "%d fans detected!\n", sc->sc_nfans); 487261421Sjhibbits 488261421Sjhibbits if (sc->sc_nfans == 0) { 489261421Sjhibbits device_printf(dev, "WARNING: No fans detected!\n"); 490261421Sjhibbits return; 491261421Sjhibbits } 492261421Sjhibbits 493261421Sjhibbits ctx = device_get_sysctl_ctx(dev); 494261421Sjhibbits fanroot_oid = SYSCTL_ADD_NODE(ctx, 495261421Sjhibbits SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fans", 496261421Sjhibbits CTLFLAG_RD, 0, "ADT Fan Information"); 497261421Sjhibbits 498261421Sjhibbits /* Now we can fill the properties into the allocated struct. */ 499261421Sjhibbits sc->sc_nfans = adt746x_fill_fan_prop(dev); 500261421Sjhibbits 501261421Sjhibbits /* Register fans with pmac_thermal */ 502261421Sjhibbits for (i = 0; i < sc->sc_nfans; i++) 503261421Sjhibbits pmac_thermal_fan_register(&sc->sc_fans[i].fan); 504261421Sjhibbits 505261421Sjhibbits /* Add sysctls for the fans. */ 506261421Sjhibbits for (i = 0; i < sc->sc_nfans; i++) { 507261421Sjhibbits for (j = 0; j < strlen(sc->sc_fans[i].fan.name); j++) { 508261421Sjhibbits sysctl_name[j] = tolower(sc->sc_fans[i].fan.name[j]); 509261421Sjhibbits if (isspace(sysctl_name[j])) 510261421Sjhibbits sysctl_name[j] = '_'; 511261421Sjhibbits } 512261421Sjhibbits sysctl_name[j] = 0; 513261421Sjhibbits 514261421Sjhibbits sc->sc_fans[i].setpoint = 515261421Sjhibbits adt746x_fan_get_pwm(&sc->sc_fans[i]); 516261421Sjhibbits 517261421Sjhibbits oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid), 518261421Sjhibbits OID_AUTO, sysctl_name, CTLFLAG_RD, 0, "Fan Information"); 519261421Sjhibbits 520261421Sjhibbits /* I use i to pass the fan id. */ 521261421Sjhibbits SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 522261421Sjhibbits "pwm", CTLTYPE_INT | CTLFLAG_RW, dev, i, 523261421Sjhibbits adt746x_fanrpm_sysctl, "I", "Fan PWM in %"); 524261421Sjhibbits } 525261421Sjhibbits 526261421Sjhibbits /* Dump fan location & type. */ 527261421Sjhibbits if (bootverbose) { 528261421Sjhibbits for (i = 0; i < sc->sc_nfans; i++) { 529261421Sjhibbits device_printf(dev, "Fan location: %s", 530261421Sjhibbits sc->sc_fans[i].fan.name); 531261421Sjhibbits device_printf(dev, " id: %d RPM: %d\n", 532261421Sjhibbits sc->sc_fans[i].id, 533261421Sjhibbits sc->sc_fans[i].setpoint); 534261421Sjhibbits } 535261421Sjhibbits } 536261421Sjhibbits} 537261421Sjhibbits 538261421Sjhibbitsstatic int 539261421Sjhibbitsadt746x_sensor_read(struct adt746x_sensor *sens) 540261421Sjhibbits{ 541261421Sjhibbits struct adt746x_softc *sc; 542261421Sjhibbits uint16_t tmp = 0; 543261421Sjhibbits uint16_t val; 544261421Sjhibbits uint8_t temp, data[1], data1[1]; 545261421Sjhibbits 546261421Sjhibbits sc = device_get_softc(sens->dev); 547261421Sjhibbits if (sens->type != ADT746X_SENSOR_SPEED) { 548261421Sjhibbits if (adt746x_read(sc->sc_dev, sc->sc_addr, sens->reg, 549261421Sjhibbits &temp) < 0) 550261421Sjhibbits return (-1); 551261421Sjhibbits if (sens->type == ADT746X_SENSOR_TEMP) 552261421Sjhibbits tmp = 10 * temp + ZERO_C_TO_K; 553261421Sjhibbits else 554261421Sjhibbits tmp = temp; 555261421Sjhibbits } else { 556261421Sjhibbits if (adt746x_read(sc->sc_dev, sc->sc_addr, sens->reg, 557261421Sjhibbits data) < 0) 558261421Sjhibbits return (-1); 559261421Sjhibbits if (adt746x_read(sc->sc_dev, sc->sc_addr, sens->reg + 1, 560261421Sjhibbits data1) < 0) 561261421Sjhibbits return (-1); 562261421Sjhibbits val = data[0] + (data1[0] << 8); 563261421Sjhibbits /* A value of 0xffff means the fan is stopped. */ 564261421Sjhibbits if (val == 0 || val == 0xffff) 565261421Sjhibbits tmp = 0; 566261421Sjhibbits else 567261421Sjhibbits tmp = (90000 * 60) / val; 568261421Sjhibbits } 569261421Sjhibbits return (tmp); 570261421Sjhibbits} 571261421Sjhibbits 572261421Sjhibbitsstatic int 573261421Sjhibbitsadt746x_sensor_sysctl(SYSCTL_HANDLER_ARGS) 574261421Sjhibbits{ 575261421Sjhibbits device_t dev; 576261421Sjhibbits struct adt746x_softc *sc; 577261421Sjhibbits struct adt746x_sensor *sens; 578261421Sjhibbits int value, error; 579261421Sjhibbits 580261421Sjhibbits dev = arg1; 581261421Sjhibbits sc = device_get_softc(dev); 582261421Sjhibbits sens = &sc->sc_sensors[arg2]; 583261421Sjhibbits 584261421Sjhibbits value = sens->therm.read(&sens->therm); 585261421Sjhibbits if (value < 0) 586261421Sjhibbits return (ENXIO); 587261421Sjhibbits 588261421Sjhibbits error = sysctl_handle_int(oidp, &value, 0, req); 589261421Sjhibbits 590261421Sjhibbits return (error); 591261421Sjhibbits} 592261421Sjhibbits 593261421Sjhibbitsstatic void 594261421Sjhibbitsadt746x_attach_sensors(device_t dev) 595261421Sjhibbits{ 596261421Sjhibbits struct adt746x_softc *sc; 597261421Sjhibbits struct sysctl_oid *oid, *sensroot_oid; 598261421Sjhibbits struct sysctl_ctx_list *ctx; 599261421Sjhibbits phandle_t child; 600261421Sjhibbits char sysctl_name[40]; 601261421Sjhibbits const char *unit; 602261421Sjhibbits const char *desc; 603261421Sjhibbits int i, j; 604261421Sjhibbits 605261421Sjhibbits 606261421Sjhibbits sc = device_get_softc(dev); 607261421Sjhibbits sc->sc_nsensors = 0; 608261421Sjhibbits child = ofw_bus_get_node(dev); 609261421Sjhibbits 610261421Sjhibbits /* Count the actual number of sensors. */ 611261421Sjhibbits sc->sc_nsensors = adt746x_fill_sensor_prop(dev); 612261421Sjhibbits device_printf(dev, "%d sensors detected!\n", sc->sc_nsensors); 613261421Sjhibbits if (sc->sc_nsensors == 0) { 614261421Sjhibbits device_printf(dev, "WARNING: No sensors detected!\n"); 615261421Sjhibbits return; 616261421Sjhibbits } 617261421Sjhibbits 618261421Sjhibbits ctx = device_get_sysctl_ctx(dev); 619261421Sjhibbits sensroot_oid = SYSCTL_ADD_NODE(ctx, 620261421Sjhibbits SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensors", 621261421Sjhibbits CTLFLAG_RD, 0, "ADT Sensor Information"); 622261421Sjhibbits 623261421Sjhibbits /* Add the sysctl for the sensors. */ 624261421Sjhibbits for (i = 0; i < sc->sc_nsensors; i++) { 625261421Sjhibbits for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) { 626261421Sjhibbits sysctl_name[j] = tolower(sc->sc_sensors[i].therm.name[j]); 627261421Sjhibbits if (isspace(sysctl_name[j])) 628261421Sjhibbits sysctl_name[j] = '_'; 629261421Sjhibbits } 630261421Sjhibbits sysctl_name[j] = 0; 631261421Sjhibbits oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid), 632261421Sjhibbits OID_AUTO, 633261421Sjhibbits sysctl_name, CTLFLAG_RD, 0, 634261421Sjhibbits "Sensor Information"); 635261421Sjhibbits if (sc->sc_sensors[i].type == ADT746X_SENSOR_TEMP) { 636261421Sjhibbits unit = "temp"; 637261421Sjhibbits desc = "sensor unit (C)"; 638261421Sjhibbits } else if (sc->sc_sensors[i].type == ADT746X_SENSOR_VOLT) { 639261421Sjhibbits unit = "volt"; 640261421Sjhibbits desc = "sensor unit (mV)"; 641261421Sjhibbits } else { 642261421Sjhibbits unit = "rpm"; 643261421Sjhibbits desc = "sensor unit (RPM)"; 644261421Sjhibbits } 645261421Sjhibbits /* I use i to pass the sensor id. */ 646261421Sjhibbits SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 647261421Sjhibbits unit, CTLTYPE_INT | CTLFLAG_RD, dev, i, 648261421Sjhibbits adt746x_sensor_sysctl, 649261421Sjhibbits sc->sc_sensors[i].type == ADT746X_SENSOR_TEMP ? 650261421Sjhibbits "IK" : "I", desc); 651261421Sjhibbits } 652261421Sjhibbits 653261421Sjhibbits /* Dump sensor location & type. */ 654261421Sjhibbits if (bootverbose) { 655261421Sjhibbits for (i = 0; i < sc->sc_nsensors; i++) { 656261421Sjhibbits device_printf(dev, "Sensor location: %s", 657261421Sjhibbits sc->sc_sensors[i].therm.name); 658261421Sjhibbits device_printf(dev, " type: %d id: %d reg: 0x%x\n", 659261421Sjhibbits sc->sc_sensors[i].type, 660261421Sjhibbits sc->sc_sensors[i].id, 661261421Sjhibbits sc->sc_sensors[i].reg); 662261421Sjhibbits } 663261421Sjhibbits } 664261421Sjhibbits} 665