Annotation of sys/dev/i2c/adt7460.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: adt7460.c,v 1.18 2007/06/24 05:34:35 dlg 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_5V 0x20
! 28: #define ADT7460_VCCP 0x21
! 29: #define ADT7460_VCC 0x22
! 30: #define ADT7460_V5 0x23
! 31: #define ADT7460_V12 0x24
! 32: #define ADT7460_REM1_TEMP 0x25
! 33: #define ADT7460_LOCAL_TEMP 0x26
! 34: #define ADT7460_REM2_TEMP 0x27
! 35: #define ADT7460_TACH1L 0x28
! 36: #define ADT7460_TACH1H 0x29
! 37: #define ADT7460_TACH2L 0x2a
! 38: #define ADT7460_TACH2H 0x2b
! 39: #define ADT7460_TACH3L 0x2c
! 40: #define ADT7460_TACH3H 0x2d
! 41: #define ADT7460_TACH4L 0x2e
! 42: #define ADT7460_TACH4H 0x2f
! 43: #define ADT7460_REVISION 0x3f
! 44: #define ADT7460_CONFIG 0x40
! 45: #define ADT7460_CONFIG_Vcc 0x80
! 46:
! 47: /* Sensors */
! 48: #define ADT_2_5V 0
! 49: #define ADT_VCCP 1
! 50: #define ADT_VCC 2
! 51: #define ADT_V5 3
! 52: #define ADT_V12 4
! 53: #define ADT_REM1_TEMP 5
! 54: #define ADT_LOCAL_TEMP 6
! 55: #define ADT_REM2_TEMP 7
! 56: #define ADT_TACH1 8
! 57: #define ADT_TACH2 9
! 58: #define ADT_TACH3 10
! 59: #define ADT_TACH4 11
! 60: #define ADT_NUM_SENSORS 12
! 61:
! 62: struct adt_chip {
! 63: const char *name;
! 64: short ratio[5];
! 65: int type;
! 66: short vcc;
! 67: } adt_chips[] = {
! 68: /* register 0x20 0x21 0x22 0x23 0x24 type */
! 69: /* 2.5v vccp vcc 5v 12v */
! 70:
! 71: { "adt7460", { 2500, 0, 3300, 0, 0 }, 7460, 5000 },
! 72: { "adt7467", { 2500, 2250, 3300, 5000, 12000 }, 7467, 5000 },
! 73: { "adt7475", { 0, 2250, 3300, 0, 0 }, 7475, 0 },
! 74: { "adt7476", { 2500, 2250, 3300, 5000, 12000 }, 7476, 0 },
! 75: { "adm1027", { 2500, 2250, 3300, 5000, 12000 }, 1027, 5000 },
! 76: { "lm85", { 2500, 2250, 3300, 5000, 12000 }, 7467, 0 },
! 77: { "emc6d100", { 2500, 2250, 3300, 5000, 12000 }, 6100, 0 },
! 78: { "emc6w201", { 2500, 2250, 3300, 5000, 12000 }, 6201, 0 },
! 79: { "lm96000", { 2500, 2250, 3300, 5000, 12000 }, 96000, 0 },
! 80: { "sch5017", { 5000, 2250, 3300, 5000, 12000 }, 5017, 0 }
! 81: };
! 82:
! 83: struct {
! 84: char sensor;
! 85: u_int8_t cmd;
! 86: u_short index;
! 87: } worklist[] = {
! 88: { ADT_2_5V, ADT7460_2_5V, 32768 + 0 },
! 89: { ADT_VCCP, ADT7460_VCCP, 32768 + 1 },
! 90: { ADT_VCC, ADT7460_VCC, 32768 + 2 },
! 91: { ADT_V5, ADT7460_V5, 32768 + 3 },
! 92: { ADT_V12, ADT7460_V12, 32768 + 4 },
! 93: { ADT_REM1_TEMP, ADT7460_REM1_TEMP },
! 94: { ADT_LOCAL_TEMP, ADT7460_LOCAL_TEMP },
! 95: { ADT_REM2_TEMP, ADT7460_REM2_TEMP },
! 96: { ADT_TACH1, ADT7460_TACH1L },
! 97: { ADT_TACH2, ADT7460_TACH2L },
! 98: { ADT_TACH3, ADT7460_TACH3L },
! 99: { ADT_TACH4, ADT7460_TACH4L },
! 100: };
! 101:
! 102: struct adt_softc {
! 103: struct device sc_dev;
! 104: i2c_tag_t sc_tag;
! 105: i2c_addr_t sc_addr;
! 106: u_int8_t sc_conf;
! 107: struct adt_chip *chip;
! 108:
! 109: struct ksensor sc_sensor[ADT_NUM_SENSORS];
! 110: struct ksensordev sc_sensordev;
! 111: };
! 112:
! 113: int adt_match(struct device *, void *, void *);
! 114: void adt_attach(struct device *, struct device *, void *);
! 115:
! 116: void adt_refresh(void *);
! 117:
! 118: struct cfattach adt_ca = {
! 119: sizeof(struct adt_softc), adt_match, adt_attach
! 120: };
! 121:
! 122: struct cfdriver adt_cd = {
! 123: NULL, "adt", DV_DULL
! 124: };
! 125:
! 126: int
! 127: adt_match(struct device *parent, void *match, void *aux)
! 128: {
! 129: struct i2c_attach_args *ia = aux;
! 130: int i;
! 131:
! 132: for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++)
! 133: if (strcmp(ia->ia_name, adt_chips[i].name) == 0)
! 134: return (1);
! 135: return (0);
! 136: }
! 137:
! 138: void
! 139: adt_attach(struct device *parent, struct device *self, void *aux)
! 140: {
! 141: struct adt_softc *sc = (struct adt_softc *)self;
! 142: struct i2c_attach_args *ia = aux;
! 143: u_int8_t cmd, rev, data;
! 144: int i;
! 145:
! 146: sc->sc_tag = ia->ia_tag;
! 147: sc->sc_addr = ia->ia_addr;
! 148:
! 149: iic_acquire_bus(sc->sc_tag, 0);
! 150:
! 151: for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++) {
! 152: if (strcmp(ia->ia_name, adt_chips[i].name) == 0) {
! 153: sc->chip = &adt_chips[i];
! 154: break;
! 155: }
! 156: }
! 157:
! 158: cmd = ADT7460_REVISION;
! 159: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 160: sc->sc_addr, &cmd, sizeof cmd, &rev, sizeof rev, 0)) {
! 161: iic_release_bus(sc->sc_tag, 0);
! 162: printf(": cannot read REV register\n");
! 163: return;
! 164: }
! 165:
! 166: cmd = ADT7460_CONFIG;
! 167: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 168: sc->sc_addr, &cmd, sizeof cmd, &sc->sc_conf, sizeof sc->sc_conf, 0)) {
! 169: iic_release_bus(sc->sc_tag, 0);
! 170: printf(": cannot read config register\n");
! 171: return;
! 172: }
! 173:
! 174: if (sc->chip->type == 7460) {
! 175: data = 1;
! 176: cmd = ADT7460_CONFIG;
! 177: if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
! 178: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
! 179: iic_release_bus(sc->sc_tag, 0);
! 180: printf(": cannot set control register\n");
! 181: return;
! 182: }
! 183: }
! 184:
! 185: iic_release_bus(sc->sc_tag, 0);
! 186:
! 187: printf(": %s rev 0x%02x", ia->ia_name, rev);
! 188:
! 189: /* Initialize sensor data. */
! 190: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
! 191: sizeof(sc->sc_sensordev.xname));
! 192:
! 193: sc->sc_sensor[ADT_2_5V].type = SENSOR_VOLTS_DC;
! 194: strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+2.5Vin",
! 195: sizeof(sc->sc_sensor[ADT_2_5V].desc));
! 196:
! 197: if (sc->chip->type == 5017)
! 198: strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+5VTR",
! 199: sizeof(sc->sc_sensor[ADT_2_5V].desc));
! 200:
! 201: sc->sc_sensor[ADT_VCCP].type = SENSOR_VOLTS_DC;
! 202: strlcpy(sc->sc_sensor[ADT_VCCP].desc, "Vccp",
! 203: sizeof(sc->sc_sensor[ADT_VCCP].desc));
! 204:
! 205: sc->sc_sensor[ADT_VCC].type = SENSOR_VOLTS_DC;
! 206: strlcpy(sc->sc_sensor[ADT_VCC].desc, "Vcc",
! 207: sizeof(sc->sc_sensor[ADT_VCC].desc));
! 208:
! 209: sc->sc_sensor[ADT_V5].type = SENSOR_VOLTS_DC;
! 210: strlcpy(sc->sc_sensor[ADT_V5].desc, "+5V",
! 211: sizeof(sc->sc_sensor[ADT_V5].desc));
! 212:
! 213: sc->sc_sensor[ADT_V12].type = SENSOR_VOLTS_DC;
! 214: strlcpy(sc->sc_sensor[ADT_V12].desc, "+12V",
! 215: sizeof(sc->sc_sensor[ADT_V12].desc));
! 216:
! 217: sc->sc_sensor[ADT_REM1_TEMP].type = SENSOR_TEMP;
! 218: strlcpy(sc->sc_sensor[ADT_REM1_TEMP].desc, "Remote",
! 219: sizeof(sc->sc_sensor[ADT_REM1_TEMP].desc));
! 220:
! 221: sc->sc_sensor[ADT_LOCAL_TEMP].type = SENSOR_TEMP;
! 222: strlcpy(sc->sc_sensor[ADT_LOCAL_TEMP].desc, "Internal",
! 223: sizeof(sc->sc_sensor[ADT_LOCAL_TEMP].desc));
! 224:
! 225: sc->sc_sensor[ADT_REM2_TEMP].type = SENSOR_TEMP;
! 226: strlcpy(sc->sc_sensor[ADT_REM2_TEMP].desc, "Remote",
! 227: sizeof(sc->sc_sensor[ADT_REM2_TEMP].desc));
! 228:
! 229: sc->sc_sensor[ADT_TACH1].type = SENSOR_FANRPM;
! 230: sc->sc_sensor[ADT_TACH2].type = SENSOR_FANRPM;
! 231: sc->sc_sensor[ADT_TACH3].type = SENSOR_FANRPM;
! 232: sc->sc_sensor[ADT_TACH4].type = SENSOR_FANRPM;
! 233:
! 234: if (sensor_task_register(sc, adt_refresh, 5) == NULL) {
! 235: printf(", unable to register update task\n");
! 236: return;
! 237: }
! 238:
! 239: for (i = 0; i < ADT_NUM_SENSORS; i++) {
! 240: if (worklist[i].index >= 32768 &&
! 241: sc->chip->ratio[worklist[i].index - 32768] == 0)
! 242: continue;
! 243: sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
! 244: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
! 245: }
! 246: sensordev_install(&sc->sc_sensordev);
! 247:
! 248:
! 249: printf("\n");
! 250: }
! 251:
! 252: void
! 253: adt_refresh(void *arg)
! 254: {
! 255: struct adt_softc *sc = arg;
! 256: u_int8_t cmd, data, data2;
! 257: u_int16_t fan;
! 258: int i, ratio;
! 259:
! 260: iic_acquire_bus(sc->sc_tag, 0);
! 261:
! 262: for (i = 0; i < sizeof worklist / sizeof(worklist[0]); i++) {
! 263:
! 264: if (worklist[i].index >= 32768) {
! 265: ratio = sc->chip->ratio[worklist[i].index - 32768];
! 266: if (ratio == 0) /* do not read a dead register */
! 267: continue;
! 268: }
! 269: cmd = worklist[i].cmd;
! 270: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 271: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
! 272: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
! 273: continue;
! 274: }
! 275:
! 276: sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
! 277: switch (worklist[i].sensor) {
! 278: case ADT_VCC:
! 279: if (sc->chip->vcc && (sc->sc_conf & ADT7460_CONFIG_Vcc))
! 280: ratio = sc->chip->vcc;
! 281: /* FALLTHROUGH */
! 282: case ADT_2_5V:
! 283: case ADT_VCCP:
! 284: case ADT_V5:
! 285: case ADT_V12:
! 286: sc->sc_sensor[i].value = ratio * 1000 * (u_int)data / 192;
! 287: break;
! 288: case ADT_LOCAL_TEMP:
! 289: case ADT_REM1_TEMP:
! 290: case ADT_REM2_TEMP:
! 291: if (data == 0x80)
! 292: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
! 293: else
! 294: sc->sc_sensor[i].value =
! 295: (int8_t)data * 1000000 + 273150000;
! 296: break;
! 297: case ADT_TACH1:
! 298: case ADT_TACH2:
! 299: case ADT_TACH3:
! 300: case ADT_TACH4:
! 301: cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */
! 302: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 303: sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
! 304: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
! 305: continue;
! 306: }
! 307:
! 308: fan = data + (data2 << 8);
! 309: if (fan == 0 || fan == 0xffff)
! 310: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
! 311: else
! 312: sc->sc_sensor[i].value = (90000 * 60) / fan;
! 313: break;
! 314: default:
! 315: sc->sc_sensor[i].flags |= SENSOR_FINVALID;
! 316: break;
! 317: }
! 318: }
! 319:
! 320: iic_release_bus(sc->sc_tag, 0);
! 321: }
CVSweb