Annotation of sys/dev/i2c/lm87.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: lm87.c,v 1.19 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: /* LM87 registers */
! 27: #define LM87_2_5V 0x20
! 28: #define LM87_VCCP1 0x21
! 29: #define LM87_VCC 0x22
! 30: #define LM87_5V 0x23
! 31: #define LM87_12V 0x24
! 32: #define LM87_VCCP2 0x25
! 33: #define LM87_EXT_TEMP 0x26
! 34: #define LM87_INT_TEMP 0x27
! 35: #define LM87_FAN1 0x28
! 36: #define LM87_FAN2 0x29
! 37: #define LM87_REVISION 0x3f
! 38: #define LM87_CONFIG1 0x40
! 39: #define LM87_CONFIG1_START 0x01
! 40: #define LM87_CONFIG1_INTCLR 0x08
! 41: #define LM87_CHANNEL 0x16
! 42: #define LM87_CHANNEL_AIN1 0x01
! 43: #define LM87_CHANNEL_AIN2 0x02
! 44: #define LM87_FANDIV 0x47
! 45:
! 46: /* Sensors */
! 47: #define LMENV_2_5V 0
! 48: #define LMENV_VCCP1 1
! 49: #define LMENV_VCC 2
! 50: #define LMENV_5V 3
! 51: #define LMENV_12V 4
! 52: #define LMENV_VCCP2 5
! 53: #define LMENV_EXT_TEMP 6
! 54: #define LMENV_INT_TEMP 7
! 55: #define LMENV_FAN1 8
! 56: #define LMENV_FAN2 9
! 57: #define LMENV_NUM_SENSORS 10
! 58:
! 59: struct lmenv_softc {
! 60: struct device sc_dev;
! 61: i2c_tag_t sc_tag;
! 62: i2c_addr_t sc_addr;
! 63:
! 64: struct ksensor sc_sensor[LMENV_NUM_SENSORS];
! 65: struct ksensordev sc_sensordev;
! 66: int sc_fan1_div, sc_fan2_div;
! 67: int sc_family;
! 68: };
! 69:
! 70: int lmenv_match(struct device *, void *, void *);
! 71: void lmenv_attach(struct device *, struct device *, void *);
! 72:
! 73: void lmenv_refresh(void *);
! 74:
! 75: struct cfattach lmenv_ca = {
! 76: sizeof(struct lmenv_softc), lmenv_match, lmenv_attach
! 77: };
! 78:
! 79: struct cfdriver lmenv_cd = {
! 80: NULL, "lmenv", DV_DULL
! 81: };
! 82:
! 83: int
! 84: lmenv_match(struct device *parent, void *match, void *aux)
! 85: {
! 86: struct i2c_attach_args *ia = aux;
! 87:
! 88: if (strcmp(ia->ia_name, "lm87") == 0 ||
! 89: strcmp(ia->ia_name, "lm87cimt") == 0 ||
! 90: strcmp(ia->ia_name, "adm9240") == 0 ||
! 91: strcmp(ia->ia_name, "lm81") == 0 ||
! 92: strcmp(ia->ia_name, "ds1780") == 0)
! 93: return (1);
! 94: return (0);
! 95: }
! 96:
! 97: void
! 98: lmenv_attach(struct device *parent, struct device *self, void *aux)
! 99: {
! 100: struct lmenv_softc *sc = (struct lmenv_softc *)self;
! 101: struct i2c_attach_args *ia = aux;
! 102: u_int8_t cmd, data, data2, channel;
! 103: int i;
! 104:
! 105: sc->sc_tag = ia->ia_tag;
! 106: sc->sc_addr = ia->ia_addr;
! 107:
! 108: sc->sc_family = 87;
! 109: if (strcmp(ia->ia_name, "lm81") == 0 ||
! 110: strcmp(ia->ia_name, "adm9240") == 0 ||
! 111: strcmp(ia->ia_name, "ds1780") == 0)
! 112: sc->sc_family = 81;
! 113:
! 114: iic_acquire_bus(sc->sc_tag, 0);
! 115:
! 116: cmd = LM87_REVISION;
! 117: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 118: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
! 119: iic_release_bus(sc->sc_tag, 0);
! 120: printf(": cannot read ID register\n");
! 121: return;
! 122: }
! 123: printf(": %s rev %x", ia->ia_name, data);
! 124:
! 125: cmd = LM87_FANDIV;
! 126: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 127: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
! 128: iic_release_bus(sc->sc_tag, 0);
! 129: printf(", cannot read Fan Divisor register\n");
! 130: return;
! 131: }
! 132: sc->sc_fan1_div = 1 << ((data >> 4) & 0x03);
! 133: sc->sc_fan2_div = 1 << ((data >> 6) & 0x03);
! 134:
! 135: if (sc->sc_family == 87) {
! 136: cmd = LM87_CHANNEL;
! 137: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 138: sc->sc_addr, &cmd, sizeof cmd, &channel,
! 139: sizeof channel, 0)) {
! 140: iic_release_bus(sc->sc_tag, 0);
! 141: printf(", cannot read Channel register\n");
! 142: return;
! 143: }
! 144: }
! 145:
! 146: cmd = LM87_CONFIG1;
! 147: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 148: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
! 149: iic_release_bus(sc->sc_tag, 0);
! 150: printf(", cannot read Configuration Register 1\n");
! 151: return;
! 152: }
! 153:
! 154: /*
! 155: * if chip is not running, try to start it.
! 156: * if it is stalled doing an interrupt, unstall it
! 157: */
! 158: data2 = (data | LM87_CONFIG1_START);
! 159: data2 = data2 & ~LM87_CONFIG1_INTCLR;
! 160:
! 161: if (data != data2) {
! 162: if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
! 163: sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
! 164: iic_release_bus(sc->sc_tag, 0);
! 165: printf(", cannot write Configuration Register 1\n");
! 166: return;
! 167: }
! 168: printf(", starting scan");
! 169: }
! 170: iic_release_bus(sc->sc_tag, 0);
! 171:
! 172: /* Initialize sensor data. */
! 173: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
! 174: sizeof(sc->sc_sensordev.xname));
! 175:
! 176: sc->sc_sensor[LMENV_2_5V].type = SENSOR_VOLTS_DC;
! 177: strlcpy(sc->sc_sensor[LMENV_2_5V].desc, "+2.5Vin",
! 178: sizeof(sc->sc_sensor[LMENV_2_5V].desc));
! 179:
! 180: sc->sc_sensor[LMENV_VCCP1].type = SENSOR_VOLTS_DC;
! 181: strlcpy(sc->sc_sensor[LMENV_VCCP1].desc, "Vccp",
! 182: sizeof(sc->sc_sensor[LMENV_VCCP1].desc));
! 183:
! 184: sc->sc_sensor[LMENV_VCC].type = SENSOR_VOLTS_DC;
! 185: strlcpy(sc->sc_sensor[LMENV_VCC].desc, "+Vcc",
! 186: sizeof(sc->sc_sensor[LMENV_VCC].desc));
! 187:
! 188: sc->sc_sensor[LMENV_5V].type = SENSOR_VOLTS_DC;
! 189: strlcpy(sc->sc_sensor[LMENV_5V].desc, "+5Vin/Vcc",
! 190: sizeof(sc->sc_sensor[LMENV_5V].desc));
! 191:
! 192: sc->sc_sensor[LMENV_12V].type = SENSOR_VOLTS_DC;
! 193: strlcpy(sc->sc_sensor[LMENV_12V].desc, "+12Vin",
! 194: sizeof(sc->sc_sensor[LMENV_12V].desc));
! 195:
! 196: sc->sc_sensor[LMENV_VCCP2].type = SENSOR_VOLTS_DC;
! 197: strlcpy(sc->sc_sensor[LMENV_VCCP2].desc, "Vccp",
! 198: sizeof(sc->sc_sensor[LMENV_VCCP2].desc));
! 199:
! 200: sc->sc_sensor[LMENV_EXT_TEMP].type = SENSOR_TEMP;
! 201: strlcpy(sc->sc_sensor[LMENV_EXT_TEMP].desc, "External",
! 202: sizeof(sc->sc_sensor[LMENV_EXT_TEMP].desc));
! 203: if (sc->sc_family == 81)
! 204: sc->sc_sensor[LMENV_EXT_TEMP].flags |= SENSOR_FINVALID;
! 205:
! 206: sc->sc_sensor[LMENV_INT_TEMP].type = SENSOR_TEMP;
! 207: strlcpy(sc->sc_sensor[LMENV_INT_TEMP].desc, "Internal",
! 208: sizeof(sc->sc_sensor[LMENV_INT_TEMP].desc));
! 209:
! 210: if (channel & LM87_CHANNEL_AIN1) {
! 211: sc->sc_sensor[LMENV_FAN1].type = SENSOR_VOLTS_DC;
! 212: strlcpy(sc->sc_sensor[LMENV_FAN1].desc, "AIN1",
! 213: sizeof(sc->sc_sensor[LMENV_FAN1].desc));
! 214: } else {
! 215: sc->sc_sensor[LMENV_FAN1].type = SENSOR_FANRPM;
! 216: }
! 217:
! 218: if (channel & LM87_CHANNEL_AIN2) {
! 219: sc->sc_sensor[LMENV_FAN2].type = SENSOR_VOLTS_DC;
! 220: strlcpy(sc->sc_sensor[LMENV_FAN2].desc, "AIN2",
! 221: sizeof(sc->sc_sensor[LMENV_FAN2].desc));
! 222: } else {
! 223: sc->sc_sensor[LMENV_FAN2].type = SENSOR_FANRPM;
! 224: }
! 225:
! 226: if (sensor_task_register(sc, lmenv_refresh, 5) == NULL) {
! 227: printf(", unable to register update task\n");
! 228: return;
! 229: }
! 230:
! 231: for (i = 0; i < LMENV_NUM_SENSORS; i++)
! 232: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
! 233: sensordev_install(&sc->sc_sensordev);
! 234:
! 235: printf("\n");
! 236: }
! 237:
! 238: void
! 239: lmenv_refresh(void *arg)
! 240: {
! 241: struct lmenv_softc *sc = arg;
! 242: u_int8_t cmd, data;
! 243: u_int tmp;
! 244: int sensor;
! 245:
! 246: iic_acquire_bus(sc->sc_tag, 0);
! 247:
! 248: for (sensor = 0; sensor < LMENV_NUM_SENSORS; sensor++) {
! 249: cmd = LM87_2_5V + sensor;
! 250: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 251: sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
! 252: sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
! 253: continue;
! 254: }
! 255:
! 256: sc->sc_sensor[sensor].flags &= ~SENSOR_FINVALID;
! 257: switch (sensor) {
! 258: case LMENV_2_5V:
! 259: sc->sc_sensor[sensor].value = 2500000 * data / 192;
! 260: break;
! 261: case LMENV_5V:
! 262: sc->sc_sensor[sensor].value = 5000000 * data / 192;
! 263: break;
! 264: case LMENV_12V:
! 265: sc->sc_sensor[sensor].value = 12000000 * data / 192;
! 266: break;
! 267: case LMENV_VCCP1:
! 268: case LMENV_VCCP2:
! 269: sc->sc_sensor[sensor].value = 2700000 * data / 192;
! 270: break;
! 271: case LMENV_VCC:
! 272: sc->sc_sensor[sensor].value = 3300000 * data / 192;
! 273: break;
! 274: case LMENV_EXT_TEMP:
! 275: if (sc->sc_family == 81) {
! 276: sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
! 277: break; /* missing on LM81 */
! 278: }
! 279: /* FALLTHROUGH */
! 280: case LMENV_INT_TEMP:
! 281: if (data == 0x80)
! 282: sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
! 283: else
! 284: sc->sc_sensor[sensor].value =
! 285: (int8_t)data * 1000000 + 273150000;
! 286: break;
! 287: case LMENV_FAN1:
! 288: if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
! 289: sc->sc_sensor[sensor].value =
! 290: 1870000 * data / 192;
! 291: break;
! 292: }
! 293: tmp = data * sc->sc_fan1_div;
! 294: if (tmp == 0)
! 295: sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
! 296: else
! 297: sc->sc_sensor[sensor].value = 1350000 / tmp;
! 298: break;
! 299: case LMENV_FAN2:
! 300: if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
! 301: sc->sc_sensor[sensor].value =
! 302: 1870000 * data / 192;
! 303: break;
! 304: }
! 305: tmp = data * sc->sc_fan2_div;
! 306: if (tmp == 0)
! 307: sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
! 308: else
! 309: sc->sc_sensor[sensor].value = 1350000 / tmp;
! 310: break;
! 311: default:
! 312: sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
! 313: break;
! 314: }
! 315: }
! 316:
! 317: iic_release_bus(sc->sc_tag, 0);
! 318: }
CVSweb