/* $OpenBSD: adt7462.c,v 1.6 2008/04/23 11:11:14 deraadt Exp $ */ /* * Copyright (c) 2008 Theo de Raadt * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #define ADT7462_TEMPL 0x88 #define ADT7462_TEMPH 0x89 #define ADT7462_TEMP1L 0x8a #define ADT7462_TEMP1H 0x8b #define ADT7462_TEMP2L 0x8c #define ADT7462_TEMP2H 0x8d #define ADT7462_TEMP3L 0x8e #define ADT7462_TEMP3H 0x8f #define ADT7262_TACH1L 0x98 #define ADT7262_TACH1H 0x99 #define ADT7262_TACH2L 0x9a #define ADT7262_TACH2H 0x9b #define ADT7262_TACH3L 0x9c #define ADT7262_TACH3H 0x9d #define ADT7262_TACH4L 0x9e #define ADT7262_TACH4H 0x9f #define ADT7262_TACH5L 0xa2 #define ADT7262_TACH5H 0xa3 #define ADT7262_TACH6L 0xa4 #define ADT7262_TACH6H 0xa5 #define ADT7262_TACH7L 0xa6 #define ADT7262_TACH7H 0xa7 #define ADT7262_TACH8L 0xa8 #define ADT7262_TACH8H 0xa9 /* Sensors */ #define ADTFSM_TEMP0 0 #define ADTFSM_TEMP1 1 #define ADTFSM_TEMP2 2 #define ADTFSM_TEMP3 3 #define ADTFSM_TACH1 4 #define ADTFSM_TACH2 5 #define ADTFSM_TACH3 6 #define ADTFSM_TACH4 7 #define ADTFSM_TACH5 8 #define ADTFSM_TACH6 9 #define ADTFSM_TACH7 10 #define ADTFSM_TACH8 11 #define ADTFSM_NUM_SENSORS 12 struct adtfsm_softc { struct device sc_dev; i2c_tag_t sc_tag; i2c_addr_t sc_addr; int sc_fanmul; struct ksensor sc_sensor[ADTFSM_NUM_SENSORS]; struct ksensordev sc_sensordev; }; int adtfsm_match(struct device *, void *, void *); void adtfsm_attach(struct device *, struct device *, void *); void adtfsm_refresh(void *); struct cfattach adtfsm_ca = { sizeof(struct adtfsm_softc), adtfsm_match, adtfsm_attach }; struct cfdriver adtfsm_cd = { NULL, "adtfsm", DV_DULL }; int adtfsm_match(struct device *parent, void *match, void *aux) { struct i2c_attach_args *ia = aux; if (strcmp(ia->ia_name, "adt7462") == 0) return (1); return (0); } void adtfsm_attach(struct device *parent, struct device *self, void *aux) { struct adtfsm_softc *sc = (struct adtfsm_softc *)self; struct i2c_attach_args *ia = aux; int i; sc->sc_tag = ia->ia_tag; sc->sc_addr = ia->ia_addr; /* Initialize sensor data. */ strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, sizeof(sc->sc_sensordev.xname)); for (i = ADTFSM_TEMP0; i <= ADTFSM_TEMP3; i++) { sc->sc_sensor[i].type = SENSOR_TEMP; sc->sc_sensor[i].flags |= SENSOR_FINVALID; } strlcpy(sc->sc_sensor[0].desc, "Internal", sizeof(sc->sc_sensor[0].desc)); for (i = 1; i < 4; i++) strlcpy(sc->sc_sensor[i].desc, "External", sizeof(sc->sc_sensor[i].desc)); for (i = ADTFSM_TACH1; i <= ADTFSM_TACH8; i++) { sc->sc_sensor[i].type = SENSOR_FANRPM; sc->sc_sensor[i].flags |= SENSOR_FINVALID; } if (sensor_task_register(sc, adtfsm_refresh, 5) == NULL) { printf(", unable to register update task\n"); return; } for (i = 0; i < ADTFSM_NUM_SENSORS; i++) sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); sensordev_install(&sc->sc_sensordev); printf("\n"); } void adtfsm_refresh(void *arg) { struct adtfsm_softc *sc = arg; u_int8_t cmdh, cmdl, datah = 0x01, datal = 0x02; struct ksensor *ks; u_short ut; short t; int i; iic_acquire_bus(sc->sc_tag, 0); for (i = 0; i <= ADTFSM_TEMP3 - ADTFSM_TEMP0; i++) { cmdl = ADT7462_TEMPL + i * 2; cmdh = ADT7462_TEMPH + i * 2; ks = &sc->sc_sensor[ADTFSM_TEMP0 + i]; if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &cmdl, sizeof cmdl, &datal, sizeof datal, 0) == 0 && iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &cmdh, sizeof cmdh, &datah, sizeof datah, 0) == 0) { t = (((datah << 8) | datal) >> 6) - (64 << 2); ks->value = 273150000 + t * 250000; ks->flags &= ~SENSOR_FINVALID; } else ks->flags |= SENSOR_FINVALID; } for (i = 0; i <= ADTFSM_TACH8 - ADTFSM_TACH1; i++) { cmdl = ADT7262_TACH1L + i * 2; cmdh = ADT7262_TACH1H + i * 2; ks = &sc->sc_sensor[ADTFSM_TACH1 + i]; if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &cmdl, sizeof cmdl, &datal, sizeof datal, 0) == 0 && iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, &cmdh, sizeof cmdh, &datah, sizeof datah, 0) == 0) { ut = ((datah << 8) | datal); if (ut == 0x0000 || ut == 0xffff) ks->flags |= SENSOR_FINVALID; else { ks->value = 90000 * 60 / ut; ks->flags &= ~SENSOR_FINVALID; } } else ks->flags |= SENSOR_FINVALID; } iic_release_bus(sc->sc_tag, 0); }