1 /* $OpenBSD: adt7462.c,v 1.6 2008/04/23 11:11:14 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Theo de Raadt 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/sensors.h> 23 24 #include <dev/i2c/i2cvar.h> 25 26 #define ADT7462_TEMPL 0x88 27 #define ADT7462_TEMPH 0x89 28 #define ADT7462_TEMP1L 0x8a 29 #define ADT7462_TEMP1H 0x8b 30 #define ADT7462_TEMP2L 0x8c 31 #define ADT7462_TEMP2H 0x8d 32 #define ADT7462_TEMP3L 0x8e 33 #define ADT7462_TEMP3H 0x8f 34 #define ADT7262_TACH1L 0x98 35 #define ADT7262_TACH1H 0x99 36 #define ADT7262_TACH2L 0x9a 37 #define ADT7262_TACH2H 0x9b 38 #define ADT7262_TACH3L 0x9c 39 #define ADT7262_TACH3H 0x9d 40 #define ADT7262_TACH4L 0x9e 41 #define ADT7262_TACH4H 0x9f 42 #define ADT7262_TACH5L 0xa2 43 #define ADT7262_TACH5H 0xa3 44 #define ADT7262_TACH6L 0xa4 45 #define ADT7262_TACH6H 0xa5 46 #define ADT7262_TACH7L 0xa6 47 #define ADT7262_TACH7H 0xa7 48 #define ADT7262_TACH8L 0xa8 49 #define ADT7262_TACH8H 0xa9 50 51 /* Sensors */ 52 #define ADTFSM_TEMP0 0 53 #define ADTFSM_TEMP1 1 54 #define ADTFSM_TEMP2 2 55 #define ADTFSM_TEMP3 3 56 #define ADTFSM_TACH1 4 57 #define ADTFSM_TACH2 5 58 #define ADTFSM_TACH3 6 59 #define ADTFSM_TACH4 7 60 #define ADTFSM_TACH5 8 61 #define ADTFSM_TACH6 9 62 #define ADTFSM_TACH7 10 63 #define ADTFSM_TACH8 11 64 #define ADTFSM_NUM_SENSORS 12 65 66 struct adtfsm_softc { 67 struct device sc_dev; 68 i2c_tag_t sc_tag; 69 i2c_addr_t sc_addr; 70 int sc_fanmul; 71 72 struct ksensor sc_sensor[ADTFSM_NUM_SENSORS]; 73 struct ksensordev sc_sensordev; 74 }; 75 76 int adtfsm_match(struct device *, void *, void *); 77 void adtfsm_attach(struct device *, struct device *, void *); 78 void adtfsm_refresh(void *); 79 80 struct cfattach adtfsm_ca = { 81 sizeof(struct adtfsm_softc), adtfsm_match, adtfsm_attach 82 }; 83 84 struct cfdriver adtfsm_cd = { 85 NULL, "adtfsm", DV_DULL 86 }; 87 88 int 89 adtfsm_match(struct device *parent, void *match, void *aux) 90 { 91 struct i2c_attach_args *ia = aux; 92 93 if (strcmp(ia->ia_name, "adt7462") == 0) 94 return (1); 95 return (0); 96 } 97 98 void 99 adtfsm_attach(struct device *parent, struct device *self, void *aux) 100 { 101 struct adtfsm_softc *sc = (struct adtfsm_softc *)self; 102 struct i2c_attach_args *ia = aux; 103 int i; 104 105 sc->sc_tag = ia->ia_tag; 106 sc->sc_addr = ia->ia_addr; 107 108 /* Initialize sensor data. */ 109 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 110 sizeof(sc->sc_sensordev.xname)); 111 112 for (i = ADTFSM_TEMP0; i <= ADTFSM_TEMP3; i++) { 113 sc->sc_sensor[i].type = SENSOR_TEMP; 114 sc->sc_sensor[i].flags |= SENSOR_FINVALID; 115 } 116 117 strlcpy(sc->sc_sensor[0].desc, "Internal", 118 sizeof(sc->sc_sensor[0].desc)); 119 for (i = 1; i < 4; i++) 120 strlcpy(sc->sc_sensor[i].desc, "External", 121 sizeof(sc->sc_sensor[i].desc)); 122 123 for (i = ADTFSM_TACH1; i <= ADTFSM_TACH8; i++) { 124 sc->sc_sensor[i].type = SENSOR_FANRPM; 125 sc->sc_sensor[i].flags |= SENSOR_FINVALID; 126 } 127 128 if (sensor_task_register(sc, adtfsm_refresh, 5) == NULL) { 129 printf(", unable to register update task\n"); 130 return; 131 } 132 133 for (i = 0; i < ADTFSM_NUM_SENSORS; i++) 134 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); 135 sensordev_install(&sc->sc_sensordev); 136 137 printf("\n"); 138 } 139 140 void 141 adtfsm_refresh(void *arg) 142 { 143 struct adtfsm_softc *sc = arg; 144 u_int8_t cmdh, cmdl, datah = 0x01, datal = 0x02; 145 struct ksensor *ks; 146 u_short ut; 147 short t; 148 int i; 149 150 iic_acquire_bus(sc->sc_tag, 0); 151 152 for (i = 0; i <= ADTFSM_TEMP3 - ADTFSM_TEMP0; i++) { 153 cmdl = ADT7462_TEMPL + i * 2; 154 cmdh = ADT7462_TEMPH + i * 2; 155 ks = &sc->sc_sensor[ADTFSM_TEMP0 + i]; 156 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 157 sc->sc_addr, &cmdl, sizeof cmdl, &datal, 158 sizeof datal, 0) == 0 && 159 iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 160 sc->sc_addr, &cmdh, sizeof cmdh, &datah, 161 sizeof datah, 0) == 0) { 162 t = (((datah << 8) | datal) >> 6) - (64 << 2); 163 ks->value = 273150000 + t * 250000; 164 ks->flags &= ~SENSOR_FINVALID; 165 } else 166 ks->flags |= SENSOR_FINVALID; 167 } 168 169 for (i = 0; i <= ADTFSM_TACH8 - ADTFSM_TACH1; i++) { 170 cmdl = ADT7262_TACH1L + i * 2; 171 cmdh = ADT7262_TACH1H + i * 2; 172 ks = &sc->sc_sensor[ADTFSM_TACH1 + i]; 173 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 174 sc->sc_addr, &cmdl, sizeof cmdl, &datal, 175 sizeof datal, 0) == 0 && 176 iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 177 sc->sc_addr, &cmdh, sizeof cmdh, &datah, 178 sizeof datah, 0) == 0) { 179 ut = ((datah << 8) | datal); 180 if (ut == 0x0000 || ut == 0xffff) 181 ks->flags |= SENSOR_FINVALID; 182 else { 183 ks->value = 90000 * 60 / ut; 184 ks->flags &= ~SENSOR_FINVALID; 185 } 186 } else 187 ks->flags |= SENSOR_FINVALID; 188 } 189 190 iic_release_bus(sc->sc_tag, 0); 191 } 192