1*992a98bbSderaadt /* $OpenBSD: adm1021.c,v 1.8 2005/12/26 01:04:55 deraadt Exp $ */ 24e3ece99Sderaadt 34e3ece99Sderaadt /* 44e3ece99Sderaadt * Copyright (c) 2005 Theo de Raadt 54e3ece99Sderaadt * 64e3ece99Sderaadt * Permission to use, copy, modify, and distribute this software for any 74e3ece99Sderaadt * purpose with or without fee is hereby granted, provided that the above 84e3ece99Sderaadt * copyright notice and this permission notice appear in all copies. 94e3ece99Sderaadt * 104e3ece99Sderaadt * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 114e3ece99Sderaadt * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 124e3ece99Sderaadt * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 134e3ece99Sderaadt * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 144e3ece99Sderaadt * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 154e3ece99Sderaadt * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 164e3ece99Sderaadt * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 174e3ece99Sderaadt */ 184e3ece99Sderaadt 194e3ece99Sderaadt #include <sys/param.h> 204e3ece99Sderaadt #include <sys/systm.h> 214e3ece99Sderaadt #include <sys/device.h> 224e3ece99Sderaadt #include <sys/sensors.h> 234e3ece99Sderaadt 244e3ece99Sderaadt #include <dev/i2c/i2cvar.h> 254e3ece99Sderaadt 264e3ece99Sderaadt /* ADM 1021 registers */ 274e3ece99Sderaadt #define ADM1021_INT_TEMP 0x00 284e3ece99Sderaadt #define ADM1021_EXT_TEMP 0x01 294e3ece99Sderaadt #define ADM1021_STATUS 0x02 30dd58f502Sderaadt #define ADM1021_CONFIG_READ 0x03 31dd58f502Sderaadt #define ADM1021_CONFIG_WRITE 0x09 32*992a98bbSderaadt #define ADM1021_CONFIG_RUN 0x40 334e3ece99Sderaadt #define ADM1021_COMPANY 0xfe /* contains 0x41 */ 344e3ece99Sderaadt #define ADM1021_STEPPING 0xff /* contains 0x3? */ 354e3ece99Sderaadt 364e3ece99Sderaadt /* Sensors */ 374a9fb704Sderaadt #define ADMTEMP_EXT 0 384a9fb704Sderaadt #define ADMTEMP_INT 1 394e3ece99Sderaadt #define ADMTEMP_NUM_SENSORS 2 404e3ece99Sderaadt 414e3ece99Sderaadt struct admtemp_softc { 424e3ece99Sderaadt struct device sc_dev; 434e3ece99Sderaadt i2c_tag_t sc_tag; 444e3ece99Sderaadt i2c_addr_t sc_addr; 454e3ece99Sderaadt 464e3ece99Sderaadt struct sensor sc_sensor[ADMTEMP_NUM_SENSORS]; 47af73b13aSderaadt int sc_xeon; 484e3ece99Sderaadt }; 494e3ece99Sderaadt 504e3ece99Sderaadt int admtemp_match(struct device *, void *, void *); 514e3ece99Sderaadt void admtemp_attach(struct device *, struct device *, void *); 524e3ece99Sderaadt void admtemp_refresh(void *); 534e3ece99Sderaadt 544e3ece99Sderaadt struct cfattach admtemp_ca = { 554e3ece99Sderaadt sizeof(struct admtemp_softc), admtemp_match, admtemp_attach 564e3ece99Sderaadt }; 574e3ece99Sderaadt 584e3ece99Sderaadt struct cfdriver admtemp_cd = { 594e3ece99Sderaadt NULL, "admtemp", DV_DULL 604e3ece99Sderaadt }; 614e3ece99Sderaadt 624e3ece99Sderaadt int 634e3ece99Sderaadt admtemp_match(struct device *parent, void *match, void *aux) 644e3ece99Sderaadt { 654e3ece99Sderaadt struct i2c_attach_args *ia = aux; 664e3ece99Sderaadt 67e109779fSderaadt if (strcmp(ia->ia_name, "adm1021") == 0 || 68e109779fSderaadt strcmp(ia->ia_name, "xeon") == 0) { 694e3ece99Sderaadt /* 704e3ece99Sderaadt * should also ensure that 714e3ece99Sderaadt * config & 0x80 == 0x00 724e3ece99Sderaadt * status1 & 0xc0 == 0x00 734e3ece99Sderaadt * status2 & 0xbc == 0x00 744e3ece99Sderaadt * before accepting this to be for real 754e3ece99Sderaadt */ 764e3ece99Sderaadt return (1); 774e3ece99Sderaadt } 78f571b3bfSderaadt return (0); 794e3ece99Sderaadt } 804e3ece99Sderaadt 814e3ece99Sderaadt void 824e3ece99Sderaadt admtemp_attach(struct device *parent, struct device *self, void *aux) 834e3ece99Sderaadt { 844e3ece99Sderaadt struct admtemp_softc *sc = (struct admtemp_softc *)self; 854e3ece99Sderaadt struct i2c_attach_args *ia = aux; 86*992a98bbSderaadt u_int8_t cmd, data; 874e3ece99Sderaadt int i; 884e3ece99Sderaadt 894e3ece99Sderaadt sc->sc_tag = ia->ia_tag; 904e3ece99Sderaadt sc->sc_addr = ia->ia_addr; 914e3ece99Sderaadt 92af73b13aSderaadt if (ia->ia_name && strcmp(ia->ia_name, "xeon") == 0) { 93c179919eSderaadt printf(": Xeon"); 94af73b13aSderaadt sc->sc_xeon = 1; 95af73b13aSderaadt } 96af73b13aSderaadt 97*992a98bbSderaadt iic_acquire_bus(sc->sc_tag, 0); 98*992a98bbSderaadt cmd = ADM1021_CONFIG_READ; 99*992a98bbSderaadt if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 100*992a98bbSderaadt sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) { 101*992a98bbSderaadt iic_release_bus(sc->sc_tag, 0); 102*992a98bbSderaadt printf(": cannot get control register\n"); 103*992a98bbSderaadt return; 104*992a98bbSderaadt } 105*992a98bbSderaadt data &= ~ADM1021_CONFIG_RUN; 106*992a98bbSderaadt cmd = ADM1021_CONFIG_WRITE; 107*992a98bbSderaadt if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 108*992a98bbSderaadt sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) { 109*992a98bbSderaadt iic_release_bus(sc->sc_tag, 0); 110*992a98bbSderaadt printf(": cannot set control register\n"); 111*992a98bbSderaadt return; 112*992a98bbSderaadt } 113*992a98bbSderaadt iic_release_bus(sc->sc_tag, 0); 114dd58f502Sderaadt 1154e3ece99Sderaadt /* Initialize sensor data. */ 1164e3ece99Sderaadt for (i = 0; i < ADMTEMP_NUM_SENSORS; i++) 1174e3ece99Sderaadt strlcpy(sc->sc_sensor[i].device, sc->sc_dev.dv_xname, 1184e3ece99Sderaadt sizeof(sc->sc_sensor[i].device)); 1194e3ece99Sderaadt 1204a9fb704Sderaadt sc->sc_sensor[ADMTEMP_EXT].type = SENSOR_TEMP; 1214a9fb704Sderaadt strlcpy(sc->sc_sensor[ADMTEMP_EXT].desc, 1224a9fb704Sderaadt sc->sc_xeon ? "Xeon" : "External", 1234a9fb704Sderaadt sizeof(sc->sc_sensor[ADMTEMP_EXT].desc)); 1244a9fb704Sderaadt 1254e3ece99Sderaadt sc->sc_sensor[ADMTEMP_INT].type = SENSOR_TEMP; 1264e3ece99Sderaadt strlcpy(sc->sc_sensor[ADMTEMP_INT].desc, "Internal", 1274e3ece99Sderaadt sizeof(sc->sc_sensor[ADMTEMP_INT].desc)); 1284e3ece99Sderaadt 1294e3ece99Sderaadt if (sensor_task_register(sc, admtemp_refresh, 5)) { 1304e3ece99Sderaadt printf(", unable to register update task\n"); 1314e3ece99Sderaadt return; 1324e3ece99Sderaadt } 1334e3ece99Sderaadt 1344a9fb704Sderaadt for (i = 0; i < (sc->sc_xeon ? 1 : ADMTEMP_NUM_SENSORS); i++) 1354e3ece99Sderaadt SENSOR_ADD(&sc->sc_sensor[i]); 1364e3ece99Sderaadt 1374e3ece99Sderaadt printf("\n"); 1384e3ece99Sderaadt } 1394e3ece99Sderaadt 1404e3ece99Sderaadt void 1414e3ece99Sderaadt admtemp_refresh(void *arg) 1424e3ece99Sderaadt { 1434e3ece99Sderaadt struct admtemp_softc *sc = arg; 144dd58f502Sderaadt u_int8_t cmd; 145dd58f502Sderaadt int8_t sdata; 1464e3ece99Sderaadt 1474e3ece99Sderaadt iic_acquire_bus(sc->sc_tag, 0); 1484e3ece99Sderaadt 1494a9fb704Sderaadt cmd = ADM1021_EXT_TEMP; 1504a9fb704Sderaadt if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 1514a9fb704Sderaadt &cmd, sizeof cmd, &sdata, sizeof sdata, I2C_F_POLL) == 0) 1524a9fb704Sderaadt sc->sc_sensor[ADMTEMP_EXT].value = 1534a9fb704Sderaadt 273150000 + 1000000 * sdata; 1544a9fb704Sderaadt 155af73b13aSderaadt if (sc->sc_xeon == 0) { 1564e3ece99Sderaadt cmd = ADM1021_INT_TEMP; 1574a9fb704Sderaadt if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 1584a9fb704Sderaadt &cmd, sizeof cmd, &sdata, sizeof sdata, I2C_F_POLL) == 0) 159af73b13aSderaadt sc->sc_sensor[ADMTEMP_INT].value = 160af73b13aSderaadt 273150000 + 1000000 * sdata; 161af73b13aSderaadt } 1624e3ece99Sderaadt 1634e3ece99Sderaadt iic_release_bus(sc->sc_tag, 0); 1644e3ece99Sderaadt } 165