| File: | dev/i2c/adt7460.c |
| Warning: | line 315, column 35 The left operand of '*' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: adt7460.c,v 1.21 2007/12/12 16:56:59 deraadt Exp $ */ | |||
| 2 | ||||
| 3 | /* | |||
| 4 | * Copyright (c) 2005 Mark Kettenis | |||
| 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 | /* ADT7460 registers */ | |||
| 27 | #define ADT7460_2_5V0x20 0x20 | |||
| 28 | #define ADT7460_VCCP0x21 0x21 | |||
| 29 | #define ADT7460_VCC0x22 0x22 | |||
| 30 | #define ADT7460_V50x23 0x23 | |||
| 31 | #define ADT7460_V120x24 0x24 | |||
| 32 | #define ADT7460_VTR0x99 0x99 | |||
| 33 | #define ADT7460_VBAT0x9a 0x9a | |||
| 34 | #define ADT7460_REM1_TEMP0x25 0x25 | |||
| 35 | #define ADT7460_LOCAL_TEMP0x26 0x26 | |||
| 36 | #define ADT7460_REM2_TEMP0x27 0x27 | |||
| 37 | #define ADT7460_TACH1L0x28 0x28 | |||
| 38 | #define ADT7460_TACH1H0x29 0x29 | |||
| 39 | #define ADT7460_TACH2L0x2a 0x2a | |||
| 40 | #define ADT7460_TACH2H0x2b 0x2b | |||
| 41 | #define ADT7460_TACH3L0x2c 0x2c | |||
| 42 | #define ADT7460_TACH3H0x2d 0x2d | |||
| 43 | #define ADT7460_TACH4L0x2e 0x2e | |||
| 44 | #define ADT7460_TACH4H0x2f 0x2f | |||
| 45 | #define ADT7460_TACH5L0xa9 0xa9 | |||
| 46 | #define ADT7460_TACH5H0xaa 0xaa | |||
| 47 | #define ADT7460_TACH6L0xab 0xab | |||
| 48 | #define ADT7460_TACH6H0xac 0xac | |||
| 49 | #define ADT7460_REVISION0x3f 0x3f | |||
| 50 | #define ADT7460_CONFIG0x40 0x40 | |||
| 51 | #define ADT7460_CONFIG_Vcc0x80 0x80 | |||
| 52 | ||||
| 53 | /* Sensors */ | |||
| 54 | #define ADT_2_5V0 0 | |||
| 55 | #define ADT_VCCP1 1 | |||
| 56 | #define ADT_VCC2 2 | |||
| 57 | #define ADT_V53 3 | |||
| 58 | #define ADT_V124 4 | |||
| 59 | #define ADT_VTR5 5 | |||
| 60 | #define ADT_VBAT6 6 | |||
| 61 | #define ADT_REM1_TEMP7 7 | |||
| 62 | #define ADT_LOCAL_TEMP8 8 | |||
| 63 | #define ADT_REM2_TEMP9 9 | |||
| 64 | #define ADT_TACH110 10 | |||
| 65 | #define ADT_TACH211 11 | |||
| 66 | #define ADT_TACH312 12 | |||
| 67 | #define ADT_TACH413 13 | |||
| 68 | #define ADT_TACH514 14 | |||
| 69 | #define ADT_TACH615 15 | |||
| 70 | #define ADT_NUM_SENSORS16 16 | |||
| 71 | ||||
| 72 | struct adt_chip { | |||
| 73 | const char *name; | |||
| 74 | short ratio[7]; | |||
| 75 | int type; | |||
| 76 | short vcc; | |||
| 77 | } adt_chips[] = { | |||
| 78 | /* register 0x20 0x21 0x22 0x23 0x24 0xa8 0xaa type */ | |||
| 79 | /* 2.5v vccp vcc 5v 12v vtr vbat */ | |||
| 80 | ||||
| 81 | { "adt7460", { 2500, 0, 3300, 0, 0, 0, 0 }, 7460, 5000 }, | |||
| 82 | { "adt7467", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 7467, 5000 }, | |||
| 83 | { "adt7475", { 0, 2250, 3300, 0, 0, 0, 0 }, 7475, 0 }, | |||
| 84 | { "adt7476", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 7476, 0 }, | |||
| 85 | { "adm1027", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 1027, 5000 }, | |||
| 86 | { "lm85", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 7467, 0 }, | |||
| 87 | { "emc6d100", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 6100, 0 }, | |||
| 88 | { "emc6w201", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 6201, 0 }, | |||
| 89 | { "lm96000", { 2500, 2250, 3300, 5000, 12000, 0, 0 }, 96000, 0 }, | |||
| 90 | { "sch5017", { 5000, 2250, 3300, 5000, 12000, 0, 0 }, 5017, 0 }, | |||
| 91 | { "sch5027", { 5000, 2250, 3300, 5000, 12000, 3300, 3300 }, 5027, 0 } | |||
| 92 | }; | |||
| 93 | ||||
| 94 | struct { | |||
| 95 | char sensor; | |||
| 96 | u_int8_t cmd; | |||
| 97 | u_short index; | |||
| 98 | } worklist[] = { | |||
| 99 | { ADT_2_5V0, ADT7460_2_5V0x20, 32768 + 0 }, | |||
| 100 | { ADT_VCCP1, ADT7460_VCCP0x21, 32768 + 1 }, | |||
| 101 | { ADT_VCC2, ADT7460_VCC0x22, 32768 + 2 }, | |||
| 102 | { ADT_V53, ADT7460_V50x23, 32768 + 3 }, | |||
| 103 | { ADT_V124, ADT7460_V120x24, 32768 + 4 }, | |||
| 104 | { ADT_VTR5, ADT7460_VTR0x99, 32768 + 5 }, | |||
| 105 | { ADT_VBAT6, ADT7460_VBAT0x9a, 32768 + 6 }, | |||
| 106 | { ADT_REM1_TEMP7, ADT7460_REM1_TEMP0x25 }, | |||
| 107 | { ADT_LOCAL_TEMP8, ADT7460_LOCAL_TEMP0x26 }, | |||
| 108 | { ADT_REM2_TEMP9, ADT7460_REM2_TEMP0x27 }, | |||
| 109 | { ADT_TACH110, ADT7460_TACH1L0x28 }, | |||
| 110 | { ADT_TACH211, ADT7460_TACH2L0x2a }, | |||
| 111 | { ADT_TACH312, ADT7460_TACH3L0x2c }, | |||
| 112 | { ADT_TACH413, ADT7460_TACH4L0x2e }, | |||
| 113 | { ADT_TACH514, ADT7460_TACH5L0xa9 }, | |||
| 114 | { ADT_TACH615, ADT7460_TACH6L0xab }, | |||
| 115 | }; | |||
| 116 | ||||
| 117 | struct adt_softc { | |||
| 118 | struct device sc_dev; | |||
| 119 | i2c_tag_t sc_tag; | |||
| 120 | i2c_addr_t sc_addr; | |||
| 121 | u_int8_t sc_conf; | |||
| 122 | struct adt_chip *chip; | |||
| 123 | ||||
| 124 | struct ksensor sc_sensor[ADT_NUM_SENSORS16]; | |||
| 125 | struct ksensordev sc_sensordev; | |||
| 126 | }; | |||
| 127 | ||||
| 128 | int adt_match(struct device *, void *, void *); | |||
| 129 | void adt_attach(struct device *, struct device *, void *); | |||
| 130 | ||||
| 131 | void adt_refresh(void *); | |||
| 132 | ||||
| 133 | struct cfattach adt_ca = { | |||
| 134 | sizeof(struct adt_softc), adt_match, adt_attach | |||
| 135 | }; | |||
| 136 | ||||
| 137 | struct cfdriver adt_cd = { | |||
| 138 | NULL((void *)0), "adt", DV_DULL | |||
| 139 | }; | |||
| 140 | ||||
| 141 | int | |||
| 142 | adt_match(struct device *parent, void *match, void *aux) | |||
| 143 | { | |||
| 144 | struct i2c_attach_args *ia = aux; | |||
| 145 | int i; | |||
| 146 | ||||
| 147 | for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++) | |||
| 148 | if (strcmp(ia->ia_name, adt_chips[i].name) == 0) | |||
| 149 | return (1); | |||
| 150 | return (0); | |||
| 151 | } | |||
| 152 | ||||
| 153 | void | |||
| 154 | adt_attach(struct device *parent, struct device *self, void *aux) | |||
| 155 | { | |||
| 156 | struct adt_softc *sc = (struct adt_softc *)self; | |||
| 157 | struct i2c_attach_args *ia = aux; | |||
| 158 | u_int8_t cmd, rev, data; | |||
| 159 | int i; | |||
| 160 | ||||
| 161 | sc->sc_tag = ia->ia_tag; | |||
| 162 | sc->sc_addr = ia->ia_addr; | |||
| 163 | ||||
| 164 | iic_acquire_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_acquire_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
| 165 | ||||
| 166 | for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++) { | |||
| 167 | if (strcmp(ia->ia_name, adt_chips[i].name) == 0) { | |||
| 168 | sc->chip = &adt_chips[i]; | |||
| 169 | break; | |||
| 170 | } | |||
| 171 | } | |||
| 172 | ||||
| 173 | cmd = ADT7460_REVISION0x3f; | |||
| 174 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
| 175 | sc->sc_addr, &cmd, sizeof cmd, &rev, sizeof rev, 0)) { | |||
| 176 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
| 177 | printf(": cannot read REV register\n"); | |||
| 178 | return; | |||
| 179 | } | |||
| 180 | ||||
| 181 | cmd = ADT7460_CONFIG0x40; | |||
| 182 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
| 183 | sc->sc_addr, &cmd, sizeof cmd, &sc->sc_conf, sizeof sc->sc_conf, 0)) { | |||
| 184 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
| 185 | printf(": cannot read config register\n"); | |||
| 186 | return; | |||
| 187 | } | |||
| 188 | ||||
| 189 | if (sc->chip->type == 7460) { | |||
| 190 | data = 1; | |||
| 191 | cmd = ADT7460_CONFIG0x40; | |||
| 192 | if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, | |||
| 193 | sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { | |||
| 194 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
| 195 | printf(": cannot set control register\n"); | |||
| 196 | return; | |||
| 197 | } | |||
| 198 | } | |||
| 199 | ||||
| 200 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
| 201 | ||||
| 202 | printf(": %s rev 0x%02x", ia->ia_name, rev); | |||
| 203 | ||||
| 204 | /* Initialize sensor data. */ | |||
| 205 | strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname, | |||
| 206 | sizeof(sc->sc_sensordev.xname)); | |||
| 207 | ||||
| 208 | sc->sc_sensor[ADT_2_5V0].type = SENSOR_VOLTS_DC; | |||
| 209 | strlcpy(sc->sc_sensor[ADT_2_5V0].desc, "+2.5Vin", | |||
| 210 | sizeof(sc->sc_sensor[ADT_2_5V0].desc)); | |||
| 211 | ||||
| 212 | if (sc->chip->type == 5017) | |||
| 213 | strlcpy(sc->sc_sensor[ADT_2_5V0].desc, "+5VTR", | |||
| 214 | sizeof(sc->sc_sensor[ADT_2_5V0].desc)); | |||
| 215 | if (sc->chip->type == 5027) | |||
| 216 | strlcpy(sc->sc_sensor[ADT_2_5V0].desc, "+5V", | |||
| 217 | sizeof(sc->sc_sensor[ADT_2_5V0].desc)); | |||
| 218 | ||||
| 219 | sc->sc_sensor[ADT_VCCP1].type = SENSOR_VOLTS_DC; | |||
| 220 | strlcpy(sc->sc_sensor[ADT_VCCP1].desc, "Vccp", | |||
| 221 | sizeof(sc->sc_sensor[ADT_VCCP1].desc)); | |||
| 222 | ||||
| 223 | sc->sc_sensor[ADT_VCC2].type = SENSOR_VOLTS_DC; | |||
| 224 | strlcpy(sc->sc_sensor[ADT_VCC2].desc, "Vcc", | |||
| 225 | sizeof(sc->sc_sensor[ADT_VCC2].desc)); | |||
| 226 | ||||
| 227 | sc->sc_sensor[ADT_V53].type = SENSOR_VOLTS_DC; | |||
| 228 | strlcpy(sc->sc_sensor[ADT_V53].desc, "+5V", | |||
| 229 | sizeof(sc->sc_sensor[ADT_V53].desc)); | |||
| 230 | ||||
| 231 | sc->sc_sensor[ADT_V124].type = SENSOR_VOLTS_DC; | |||
| 232 | strlcpy(sc->sc_sensor[ADT_V124].desc, "+12V", | |||
| 233 | sizeof(sc->sc_sensor[ADT_V124].desc)); | |||
| 234 | ||||
| 235 | sc->sc_sensor[ADT_VTR5].type = SENSOR_VOLTS_DC; | |||
| 236 | strlcpy(sc->sc_sensor[ADT_VTR5].desc, "+Vtr", | |||
| 237 | sizeof(sc->sc_sensor[ADT_VTR5].desc)); | |||
| 238 | ||||
| 239 | sc->sc_sensor[ADT_VBAT6].type = SENSOR_VOLTS_DC; | |||
| 240 | strlcpy(sc->sc_sensor[ADT_VBAT6].desc, "+Vbat", | |||
| 241 | sizeof(sc->sc_sensor[ADT_VBAT6].desc)); | |||
| 242 | ||||
| 243 | sc->sc_sensor[ADT_REM1_TEMP7].type = SENSOR_TEMP; | |||
| 244 | strlcpy(sc->sc_sensor[ADT_REM1_TEMP7].desc, "Remote", | |||
| 245 | sizeof(sc->sc_sensor[ADT_REM1_TEMP7].desc)); | |||
| 246 | ||||
| 247 | sc->sc_sensor[ADT_LOCAL_TEMP8].type = SENSOR_TEMP; | |||
| 248 | strlcpy(sc->sc_sensor[ADT_LOCAL_TEMP8].desc, "Internal", | |||
| 249 | sizeof(sc->sc_sensor[ADT_LOCAL_TEMP8].desc)); | |||
| 250 | ||||
| 251 | sc->sc_sensor[ADT_REM2_TEMP9].type = SENSOR_TEMP; | |||
| 252 | strlcpy(sc->sc_sensor[ADT_REM2_TEMP9].desc, "Remote", | |||
| 253 | sizeof(sc->sc_sensor[ADT_REM2_TEMP9].desc)); | |||
| 254 | ||||
| 255 | sc->sc_sensor[ADT_TACH110].type = SENSOR_FANRPM; | |||
| 256 | sc->sc_sensor[ADT_TACH211].type = SENSOR_FANRPM; | |||
| 257 | sc->sc_sensor[ADT_TACH312].type = SENSOR_FANRPM; | |||
| 258 | sc->sc_sensor[ADT_TACH413].type = SENSOR_FANRPM; | |||
| 259 | sc->sc_sensor[ADT_TACH514].type = SENSOR_FANRPM; | |||
| 260 | sc->sc_sensor[ADT_TACH615].type = SENSOR_FANRPM; | |||
| 261 | ||||
| 262 | if (sensor_task_register(sc, adt_refresh, 5) == NULL((void *)0)) { | |||
| 263 | printf(", unable to register update task\n"); | |||
| 264 | return; | |||
| 265 | } | |||
| 266 | ||||
| 267 | for (i = 0; i < ADT_NUM_SENSORS16; i++) { | |||
| 268 | if (worklist[i].index >= 32768 && | |||
| 269 | sc->chip->ratio[worklist[i].index - 32768] == 0) | |||
| 270 | continue; | |||
| 271 | sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]); | |||
| 272 | } | |||
| 273 | sensordev_install(&sc->sc_sensordev); | |||
| 274 | ||||
| 275 | ||||
| 276 | printf("\n"); | |||
| 277 | } | |||
| 278 | ||||
| 279 | void | |||
| 280 | adt_refresh(void *arg) | |||
| 281 | { | |||
| 282 | struct adt_softc *sc = arg; | |||
| 283 | u_int8_t cmd, data, data2; | |||
| 284 | u_int16_t fan; | |||
| 285 | int i, ratio; | |||
| ||||
| 286 | ||||
| 287 | iic_acquire_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_acquire_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
| 288 | ||||
| 289 | for (i = 0; i < sizeof worklist / sizeof(worklist[0]); i++) { | |||
| 290 | ||||
| 291 | if (worklist[i].index >= 32768) { | |||
| 292 | ratio = sc->chip->ratio[worklist[i].index - 32768]; | |||
| 293 | if (ratio == 0) /* do not read a dead register */ | |||
| 294 | continue; | |||
| 295 | } | |||
| 296 | cmd = worklist[i].cmd; | |||
| 297 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
| 298 | sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { | |||
| 299 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
| 300 | continue; | |||
| 301 | } | |||
| 302 | ||||
| 303 | sc->sc_sensor[i].flags &= ~SENSOR_FINVALID0x0001; | |||
| 304 | switch (worklist[i].sensor) { | |||
| 305 | case ADT_VCC2: | |||
| 306 | if (sc->chip->vcc && (sc->sc_conf & ADT7460_CONFIG_Vcc0x80)) | |||
| 307 | ratio = sc->chip->vcc; | |||
| 308 | /* FALLTHROUGH */ | |||
| 309 | case ADT_2_5V0: | |||
| 310 | case ADT_VCCP1: | |||
| 311 | case ADT_V53: | |||
| 312 | case ADT_V124: | |||
| 313 | case ADT_VTR5: | |||
| 314 | case ADT_VBAT6: | |||
| 315 | sc->sc_sensor[i].value = ratio * 1000 * (u_int)data / 192; | |||
| ||||
| 316 | break; | |||
| 317 | case ADT_LOCAL_TEMP8: | |||
| 318 | case ADT_REM1_TEMP7: | |||
| 319 | case ADT_REM2_TEMP9: | |||
| 320 | if (data == 0x80) | |||
| 321 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
| 322 | else | |||
| 323 | sc->sc_sensor[i].value = | |||
| 324 | (int8_t)data * 1000000 + 273150000; | |||
| 325 | break; | |||
| 326 | case ADT_TACH110: | |||
| 327 | case ADT_TACH211: | |||
| 328 | case ADT_TACH312: | |||
| 329 | case ADT_TACH413: | |||
| 330 | cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */ | |||
| 331 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
| 332 | sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) { | |||
| 333 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
| 334 | continue; | |||
| 335 | } | |||
| 336 | ||||
| 337 | fan = data + (data2 << 8); | |||
| 338 | if (fan == 0 || fan == 0xffff) | |||
| 339 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
| 340 | else | |||
| 341 | sc->sc_sensor[i].value = (90000 * 60) / fan; | |||
| 342 | break; | |||
| 343 | case ADT_TACH514: | |||
| 344 | case ADT_TACH615: | |||
| 345 | if (sc->chip->type != 5027) { | |||
| 346 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
| 347 | break; /* only 5027 has these fans? */ | |||
| 348 | } | |||
| 349 | cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */ | |||
| 350 | if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, | |||
| 351 | sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) { | |||
| 352 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
| 353 | continue; | |||
| 354 | } | |||
| 355 | ||||
| 356 | fan = data + (data2 << 8); | |||
| 357 | if (fan == 0 || fan == 0xffff) | |||
| 358 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
| 359 | else | |||
| 360 | sc->sc_sensor[i].value = fan * 60; | |||
| 361 | break; | |||
| 362 | default: | |||
| 363 | sc->sc_sensor[i].flags |= SENSOR_FINVALID0x0001; | |||
| 364 | break; | |||
| 365 | } | |||
| 366 | } | |||
| 367 | ||||
| 368 | iic_release_bus(sc->sc_tag, 0)(*(sc->sc_tag)->ic_release_bus)((sc->sc_tag)->ic_cookie , (0)); | |||
| 369 | } |