1 /* $OpenBSD: adm1021.c,v 1.28 2011/03/10 23:14:30 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2005 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 /* ADM 1021 registers */ 27 #define ADM1021_INT_TEMP 0x00 28 #define ADM1021_EXT_TEMP 0x01 29 #define ADM1021_STATUS 0x02 30 #define ADM1021_STATUS_INVAL 0x7f 31 #define ADM1021_STATUS_NOEXT 0x40 32 #define ADM1021_CONFIG_READ 0x03 33 #define ADM1021_CONFIG_WRITE 0x09 34 #define ADM1021_CONFIG_RUN 0x40 35 #define ADM1021_COMPANY 0xfe /* contains 0x41 */ 36 #define ADM1021_STEPPING 0xff /* contains 0x3? */ 37 38 /* Sensors */ 39 #define ADMTEMP_EXT 0 40 #define ADMTEMP_INT 1 41 #define ADMTEMP_NUM_SENSORS 2 42 43 struct admtemp_softc { 44 struct device sc_dev; 45 i2c_tag_t sc_tag; 46 i2c_addr_t sc_addr; 47 48 struct ksensor sc_sensor[ADMTEMP_NUM_SENSORS]; 49 struct ksensordev sc_sensordev; 50 int sc_noexternal; 51 }; 52 53 int admtemp_match(struct device *, void *, void *); 54 void admtemp_attach(struct device *, struct device *, void *); 55 void admtemp_refresh(void *); 56 57 struct cfattach admtemp_ca = { 58 sizeof(struct admtemp_softc), admtemp_match, admtemp_attach 59 }; 60 61 struct cfdriver admtemp_cd = { 62 NULL, "admtemp", DV_DULL 63 }; 64 65 int 66 admtemp_match(struct device *parent, void *match, void *aux) 67 { 68 struct i2c_attach_args *ia = aux; 69 70 if (strcmp(ia->ia_name, "adm1021") == 0 || 71 strcmp(ia->ia_name, "adm1023") == 0 || 72 strcmp(ia->ia_name, "adm1032") == 0 || 73 strcmp(ia->ia_name, "g781") == 0 || 74 strcmp(ia->ia_name, "g781-1") == 0 || 75 strcmp(ia->ia_name, "gl523sm") == 0 || 76 strcmp(ia->ia_name, "max1617") == 0 || 77 strcmp(ia->ia_name, "sa56004x") == 0 || 78 strcmp(ia->ia_name, "xeontemp") == 0) 79 return (1); 80 return (0); 81 } 82 83 void 84 admtemp_attach(struct device *parent, struct device *self, void *aux) 85 { 86 struct admtemp_softc *sc = (struct admtemp_softc *)self; 87 struct i2c_attach_args *ia = aux; 88 u_int8_t cmd, data, stat; 89 int xeon = 0, i; 90 91 sc->sc_tag = ia->ia_tag; 92 sc->sc_addr = ia->ia_addr; 93 94 if (strcmp(ia->ia_name, "xeontemp") == 0) { 95 printf(": Xeon"); 96 xeon = 1; 97 } else 98 printf(": %s", ia->ia_name); 99 100 iic_acquire_bus(sc->sc_tag, 0); 101 cmd = ADM1021_CONFIG_READ; 102 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 103 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 104 iic_release_bus(sc->sc_tag, 0); 105 printf(", cannot get control register\n"); 106 return; 107 } 108 if (data & ADM1021_CONFIG_RUN) { 109 cmd = ADM1021_STATUS; 110 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 111 sc->sc_addr, &cmd, sizeof cmd, &stat, sizeof stat, 0)) { 112 iic_release_bus(sc->sc_tag, 0); 113 printf(", cannot read status register\n"); 114 return; 115 } 116 if ((stat & ADM1021_STATUS_INVAL) == ADM1021_STATUS_INVAL) { 117 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 118 sc->sc_addr, &cmd, sizeof cmd, &stat, sizeof stat, 0)) { 119 iic_release_bus(sc->sc_tag, 0); 120 printf(", cannot read status register\n"); 121 return; 122 } 123 } 124 125 /* means external is dead */ 126 if ((stat & ADM1021_STATUS_INVAL) != ADM1021_STATUS_INVAL && 127 (stat & ADM1021_STATUS_NOEXT)) 128 sc->sc_noexternal = 1; 129 130 data &= ~ADM1021_CONFIG_RUN; 131 cmd = ADM1021_CONFIG_WRITE; 132 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 133 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 134 iic_release_bus(sc->sc_tag, 0); 135 printf(", cannot set control register\n"); 136 return; 137 } 138 } 139 iic_release_bus(sc->sc_tag, 0); 140 141 /* Initialize sensor data. */ 142 strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, 143 sizeof(sc->sc_sensordev.xname)); 144 145 sc->sc_sensor[ADMTEMP_EXT].type = SENSOR_TEMP; 146 strlcpy(sc->sc_sensor[ADMTEMP_EXT].desc, 147 xeon ? "Xeon" : "External", 148 sizeof(sc->sc_sensor[ADMTEMP_EXT].desc)); 149 150 sc->sc_sensor[ADMTEMP_INT].type = SENSOR_TEMP; 151 strlcpy(sc->sc_sensor[ADMTEMP_INT].desc, 152 xeon ? "Xeon" : "Internal", 153 sizeof(sc->sc_sensor[ADMTEMP_INT].desc)); 154 155 if (sensor_task_register(sc, admtemp_refresh, 5) == NULL) { 156 printf(", unable to register update task\n"); 157 return; 158 } 159 160 for (i = 0; i < (sc->sc_noexternal ? 1 : ADMTEMP_NUM_SENSORS); i++) 161 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); 162 sensordev_install(&sc->sc_sensordev); 163 164 printf("\n"); 165 } 166 167 void 168 admtemp_refresh(void *arg) 169 { 170 struct admtemp_softc *sc = arg; 171 u_int8_t cmd; 172 int8_t sdata; 173 174 iic_acquire_bus(sc->sc_tag, 0); 175 176 if (sc->sc_noexternal == 0) { 177 cmd = ADM1021_EXT_TEMP; 178 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 179 &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) { 180 if (sdata == 0x7f) { 181 sc->sc_sensor[ADMTEMP_EXT].flags |= SENSOR_FINVALID; 182 } else { 183 sc->sc_sensor[ADMTEMP_EXT].value = 184 273150000 + 1000000 * sdata; 185 sc->sc_sensor[ADMTEMP_EXT].flags &= ~SENSOR_FINVALID; 186 } 187 } 188 } else 189 sc->sc_sensor[ADMTEMP_EXT].flags |= SENSOR_FINVALID; 190 191 192 cmd = ADM1021_INT_TEMP; 193 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 194 &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0) { 195 if (sdata == 0x7f) { 196 sc->sc_sensor[ADMTEMP_INT].flags |= SENSOR_FINVALID; 197 } else { 198 sc->sc_sensor[ADMTEMP_INT].value = 199 273150000 + 1000000 * sdata; 200 sc->sc_sensor[ADMTEMP_INT].flags &= ~SENSOR_FINVALID; 201 } 202 } 203 204 iic_release_bus(sc->sc_tag, 0); 205 } 206