Annotation of sys/dev/i2c/asb100.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: asb100.c,v 1.10 2007/06/24 05:34:35 dlg Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2005 Damien Miller <djm@openbsd.org>
! 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: /* Apparently the ASB100 always lives here */
! 27: #define ASB100_ADDR 0x2d
! 28:
! 29: /* ASB100 registers */
! 30: #define ASB100_TEMP3 0x17
! 31: #define ASB100_TEMP3_MAX 0x18
! 32: #define ASB100_TEMP3_HYST 0x19
! 33: #define ASB100_VIN0 0x20
! 34: #define ASB100_VIN1 0x21
! 35: #define ASB100_VIN2 0x22
! 36: #define ASB100_VIN3 0x23
! 37: #define ASB100_VIN4 0x24
! 38: #define ASB100_VIN5 0x25
! 39: #define ASB100_VIN6 0x26
! 40: #define ASB100_TEMP0 0x27
! 41: #define ASB100_FAN0 0x28
! 42: #define ASB100_FAN1 0x29
! 43: #define ASB100_FAN2 0x30
! 44: #define ASB100_VIN0_MIN 0x2b
! 45: #define ASB100_VIN0_MAX 0x2c
! 46: #define ASB100_VIN1_MIN 0x2d
! 47: #define ASB100_VIN1_MAX 0x2e
! 48: #define ASB100_VIN2_MIN 0x2f
! 49: #define ASB100_VIN2_MAX 0x30
! 50: #define ASB100_VIN3_MIN 0x31
! 51: #define ASB100_VIN3_MAX 0x32
! 52: #define ASB100_VIN4_MIN 0x33
! 53: #define ASB100_VIN4_MAX 0x34
! 54: #define ASB100_VIN5_MIN 0x35
! 55: #define ASB100_VIN5_MAX 0x36
! 56: #define ASB100_VIN6_MIN 0x37
! 57: #define ASB100_VIN6_MAX 0x38
! 58: #define ASB100_TEMP0_MAX 0x39
! 59: #define ASB100_TEMP0_HYST 0x3a
! 60: #define ASB100_FAN0_MIN 0x3b
! 61: #define ASB100_FAN1_MIN 0x3c
! 62: #define ASB100_FAN2_MIN 0x3d
! 63: #define ASB100_CONFIG 0x40
! 64: #define ASB100_ALARM1 0x41
! 65: #define ASB100_ALARM2 0x42
! 66: #define ASB100_SMIM1 0x43
! 67: #define ASB100_SMIM2 0x44
! 68: #define ASB100_VID_FANDIV01 0x47 /* 0-3 vid, 4-5 fan0, 6-7 fan1 */
! 69: #define ASB100_I2C_ADDR 0x48
! 70: #define ASB100_CHIPID 0x49
! 71: #define ASB100_I2C_SUBADDR 0x4a
! 72: #define ASB100_PIN_FANDIV2 0x4b /* 6-7 fan2 */
! 73: #define ASB100_IRQ 0x4c
! 74: #define ASB100_BANK 0x4e
! 75: #define ASB100_CHIPMAN 0x4f
! 76: #define ASB100_VID_CHIPID 0x58 /* 0 vid highbit, 1-7 chipid */
! 77: #define ASB100_PWM 0x59 /* 0-3 duty cycle, 7 enable */
! 78:
! 79: /* TEMP1/2 sensors live on other chips, pointed to by the I2C_SUBADDR reg */
! 80: #define ASB100_SUB1_TEMP1 0x50 /* LM75 format */
! 81: #define ASB100_SUB1_TEMP1_HYST 0x53
! 82: #define ASB100_SUB1_TEMP1_MAX 0x55
! 83: #define ASB100_SUB2_TEMP2 0x50 /* LM75 format */
! 84: #define ASB100_SUB2_TEMP2_HYST 0x53
! 85: #define ASB100_SUB2_TEMP2_MAX 0x55
! 86:
! 87: /* Sensors */
! 88: #define ASB100_SENSOR_VIN0 0
! 89: #define ASB100_SENSOR_VIN1 1
! 90: #define ASB100_SENSOR_VIN2 2
! 91: #define ASB100_SENSOR_VIN3 3
! 92: #define ASB100_SENSOR_VIN4 4
! 93: #define ASB100_SENSOR_VIN5 5
! 94: #define ASB100_SENSOR_VIN6 6
! 95: #define ASB100_SENSOR_FAN0 7
! 96: #define ASB100_SENSOR_FAN1 8
! 97: #define ASB100_SENSOR_FAN2 9
! 98: #define ASB100_SENSOR_TEMP0 10
! 99: #define ASB100_SENSOR_TEMP1 11
! 100: #define ASB100_SENSOR_TEMP2 12
! 101: #define ASB100_SENSOR_TEMP3 13
! 102: #define ASB100_NUM_SENSORS 14
! 103:
! 104: struct asbtm_softc {
! 105: struct device sc_dev;
! 106: i2c_tag_t sc_tag;
! 107: i2c_addr_t sc_addr;
! 108:
! 109: struct ksensor sc_sensor[ASB100_NUM_SENSORS];
! 110: struct ksensordev sc_sensordev;
! 111: int sc_fanmul[3];
! 112: int sc_satellite[2];
! 113: };
! 114:
! 115: int asbtm_banksel(struct asbtm_softc *, u_int8_t, u_int8_t *);
! 116: int asbtm_match(struct device *, void *, void *);
! 117: void asbtm_attach(struct device *, struct device *, void *);
! 118: void asbtm_refresh(void *);
! 119:
! 120: struct cfattach asbtm_ca = {
! 121: sizeof(struct asbtm_softc), asbtm_match, asbtm_attach
! 122: };
! 123:
! 124: struct cfdriver asbtm_cd = {
! 125: NULL, "asbtm", DV_DULL
! 126: };
! 127:
! 128: int
! 129: asbtm_match(struct device *parent, void *match, void *aux)
! 130: {
! 131: struct i2c_attach_args *ia = aux;
! 132:
! 133: if (strcmp(ia->ia_name, "asb100") == 0)
! 134: return (1);
! 135:
! 136: return (0);
! 137: }
! 138:
! 139: int
! 140: asbtm_banksel(struct asbtm_softc *sc, u_int8_t new_bank, u_int8_t *orig_bank)
! 141: {
! 142: u_int8_t cmd, data;
! 143:
! 144: new_bank &= 0xf;
! 145:
! 146: cmd = ASB100_BANK;
! 147: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 148: &cmd, sizeof cmd, &data, sizeof data, 0))
! 149: return (-1);
! 150:
! 151: if (orig_bank != NULL)
! 152: *orig_bank = data & 0x0f;
! 153:
! 154: if ((data & 0xf) != new_bank) {
! 155: cmd = ASB100_BANK;
! 156: data = new_bank | (data & 0xf0);
! 157: if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
! 158: &cmd, sizeof cmd, &data, sizeof data, 0))
! 159: return (-1);
! 160: }
! 161:
! 162: return (0);
! 163: }
! 164:
! 165: void
! 166: asbtm_attach(struct device *parent, struct device *self, void *aux)
! 167: {
! 168: struct asbtm_softc *sc = (struct asbtm_softc *)self;
! 169: struct i2c_attach_args *ia = aux;
! 170: u_int8_t orig_bank, cmd, data;
! 171: int i;
! 172:
! 173: sc->sc_tag = ia->ia_tag;
! 174: sc->sc_addr = ia->ia_addr;
! 175:
! 176: iic_acquire_bus(sc->sc_tag, 0);
! 177:
! 178: if (asbtm_banksel(sc, 0, &orig_bank) == -1) {
! 179: printf(": cannot get/set register bank\n");
! 180: iic_release_bus(sc->sc_tag, 0);
! 181: return;
! 182: }
! 183:
! 184: cmd = ASB100_VID_FANDIV01;
! 185: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 186: &cmd, sizeof cmd, &data, sizeof data, 0)) {
! 187: printf(": cannot get fan01 register\n");
! 188: iic_release_bus(sc->sc_tag, 0);
! 189: return;
! 190: }
! 191: sc->sc_fanmul[0] = (1 << (data >> 4) & 0x3);
! 192: sc->sc_fanmul[1] = (1 << (data >> 6) & 0x3);
! 193:
! 194: cmd = ASB100_PIN_FANDIV2;
! 195: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 196: &cmd, sizeof cmd, &data, sizeof data, 0)) {
! 197: printf(": cannot get fan2 register\n");
! 198: iic_release_bus(sc->sc_tag, 0);
! 199: return;
! 200: }
! 201: sc->sc_fanmul[0] = (1 << (data >> 6) & 0x3);
! 202:
! 203: cmd = ASB100_I2C_SUBADDR;
! 204: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 205: &cmd, sizeof cmd, &data, sizeof data, 0)) {
! 206: printf(": cannot get satellite chip address register\n");
! 207: iic_release_bus(sc->sc_tag, 0);
! 208: return;
! 209: }
! 210: /* Maybe a relative address of zero means "not present" here... */
! 211: sc->sc_satellite[0] = 0x48 + (data & 0xf);
! 212: sc->sc_satellite[1] = 0x48 + ((data >> 4) & 0xf);
! 213:
! 214: iic_ignore_addr(sc->sc_satellite[0]);
! 215: iic_ignore_addr(sc->sc_satellite[1]);
! 216: if (sc->sc_satellite[0] == sc->sc_satellite[1])
! 217: sc->sc_satellite[1] = -1;
! 218:
! 219: if (asbtm_banksel(sc, orig_bank, NULL) == -1) {
! 220: printf(": cannot restore saved bank %d\n", orig_bank);
! 221: iic_release_bus(sc->sc_tag, 0);
! 222: return;
! 223: }
! 224:
! 225: iic_release_bus(sc->sc_tag, 0);
! 226:
! 227: /* Initialize sensor data. */
! 228: strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
! 229: sizeof(sc->sc_sensordev.xname));
! 230:
! 231: sc->sc_sensor[ASB100_SENSOR_VIN0].type = SENSOR_VOLTS_DC;
! 232: sc->sc_sensor[ASB100_SENSOR_VIN1].type = SENSOR_VOLTS_DC;
! 233: sc->sc_sensor[ASB100_SENSOR_VIN2].type = SENSOR_VOLTS_DC;
! 234: sc->sc_sensor[ASB100_SENSOR_VIN3].type = SENSOR_VOLTS_DC;
! 235: sc->sc_sensor[ASB100_SENSOR_VIN4].type = SENSOR_VOLTS_DC;
! 236: sc->sc_sensor[ASB100_SENSOR_VIN5].type = SENSOR_VOLTS_DC;
! 237: sc->sc_sensor[ASB100_SENSOR_VIN6].type = SENSOR_VOLTS_DC;
! 238:
! 239: sc->sc_sensor[ASB100_SENSOR_FAN0].type = SENSOR_FANRPM;
! 240: sc->sc_sensor[ASB100_SENSOR_FAN1].type = SENSOR_FANRPM;
! 241: sc->sc_sensor[ASB100_SENSOR_FAN2].type = SENSOR_FANRPM;
! 242:
! 243: sc->sc_sensor[ASB100_SENSOR_TEMP0].type = SENSOR_TEMP;
! 244: strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP0].desc, "External",
! 245: sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP0].desc));
! 246:
! 247: sc->sc_sensor[ASB100_SENSOR_TEMP1].type = SENSOR_TEMP;
! 248: strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP1].desc, "Internal",
! 249: sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP1].desc));
! 250:
! 251: sc->sc_sensor[ASB100_SENSOR_TEMP2].type = SENSOR_TEMP;
! 252: strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP2].desc, "Internal",
! 253: sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP2].desc));
! 254: if (sc->sc_satellite[1] == -1)
! 255: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags |= SENSOR_FINVALID;
! 256:
! 257: sc->sc_sensor[ASB100_SENSOR_TEMP3].type = SENSOR_TEMP;
! 258: strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP3].desc, "External",
! 259: sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP3].desc));
! 260:
! 261: if (sensor_task_register(sc, asbtm_refresh, 5) == NULL) {
! 262: printf(", unable to register update task\n");
! 263: return;
! 264: }
! 265:
! 266: for (i = 0; i < ASB100_NUM_SENSORS; i++)
! 267: sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
! 268: sensordev_install(&sc->sc_sensordev);
! 269:
! 270: printf("\n");
! 271: }
! 272:
! 273: static void
! 274: fanval(struct ksensor *sens, int mul, u_int8_t data)
! 275: {
! 276: int tmp = data * mul;
! 277:
! 278: if (tmp == 0)
! 279: sens->flags |= SENSOR_FINVALID;
! 280: else {
! 281: sens->value = 1350000 / tmp;
! 282: sens->flags &= ~SENSOR_FINVALID;
! 283: }
! 284: }
! 285:
! 286: void
! 287: asbtm_refresh(void *arg)
! 288: {
! 289: struct asbtm_softc *sc = arg;
! 290: u_int8_t orig_bank, cmd, data;
! 291: int8_t sdata;
! 292: u_int16_t sdata2;
! 293:
! 294: iic_acquire_bus(sc->sc_tag, 0);
! 295:
! 296: if (asbtm_banksel(sc, 0, &orig_bank) == -1) {
! 297: printf("%s: cannot get/set register bank\n",
! 298: sc->sc_dev.dv_xname);
! 299: iic_release_bus(sc->sc_tag, 0);
! 300: return;
! 301: }
! 302:
! 303: cmd = ASB100_VIN0;
! 304: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 305: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 306: sc->sc_sensor[ASB100_SENSOR_VIN0].value = (data * 1000000) / 16;
! 307:
! 308: cmd = ASB100_VIN1;
! 309: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 310: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 311: sc->sc_sensor[ASB100_SENSOR_VIN1].value = (data * 1000000) / 16;
! 312:
! 313: cmd = ASB100_VIN2;
! 314: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 315: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 316: sc->sc_sensor[ASB100_SENSOR_VIN2].value = (data * 1000000) / 16;
! 317:
! 318: cmd = ASB100_VIN3;
! 319: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 320: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 321: sc->sc_sensor[ASB100_SENSOR_VIN3].value = (data * 1000000) / 16;
! 322:
! 323: cmd = ASB100_VIN4;
! 324: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 325: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 326: sc->sc_sensor[ASB100_SENSOR_VIN4].value = (data * 1000000) / 16;
! 327:
! 328: cmd = ASB100_VIN5;
! 329: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 330: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 331: sc->sc_sensor[ASB100_SENSOR_VIN5].value = (data * 1000000) / 16;
! 332:
! 333: cmd = ASB100_VIN6;
! 334: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 335: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 336: sc->sc_sensor[ASB100_SENSOR_VIN6].value = (data * 1000000) / 16;
! 337:
! 338: cmd = ASB100_FAN0;
! 339: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 340: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 341: fanval(&sc->sc_sensor[ASB100_SENSOR_FAN0],
! 342: sc->sc_fanmul[0], data);
! 343:
! 344: cmd = ASB100_FAN1;
! 345: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 346: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 347: fanval(&sc->sc_sensor[ASB100_SENSOR_FAN1],
! 348: sc->sc_fanmul[1], data);
! 349:
! 350: cmd = ASB100_FAN2;
! 351: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 352: &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
! 353: fanval(&sc->sc_sensor[ASB100_SENSOR_FAN2],
! 354: sc->sc_fanmul[2], data);
! 355:
! 356: cmd = ASB100_TEMP0;
! 357: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 358: &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
! 359: sc->sc_sensor[ASB100_SENSOR_TEMP0].value = 273150000 +
! 360: 1000000 * sdata;
! 361:
! 362: cmd = ASB100_TEMP3;
! 363: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
! 364: &cmd, sizeof cmd, &data, sizeof sdata, 0) == 0)
! 365: sc->sc_sensor[ASB100_SENSOR_TEMP3].value = 273150000 +
! 366: 1000000 * sdata;
! 367:
! 368: /* Read satellite chips for TEMP1/TEMP2 */
! 369: cmd = ASB100_SUB1_TEMP1;
! 370: if (sc->sc_satellite[0] != -1) {
! 371: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 372: sc->sc_satellite[0], &cmd, sizeof cmd, &sdata2,
! 373: sizeof sdata2, 0) == 0 && sdata2 != 0xffff) {
! 374: sc->sc_sensor[ASB100_SENSOR_TEMP1].value = 273150000 +
! 375: 500000 * (swap16(sdata2) / 128);
! 376: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags &=
! 377: ~SENSOR_FINVALID;
! 378: } else {
! 379: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags |=
! 380: SENSOR_FINVALID;
! 381: }
! 382: }
! 383:
! 384: cmd = ASB100_SUB2_TEMP2;
! 385: if (sc->sc_satellite[1] != -1) {
! 386: if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
! 387: sc->sc_satellite[1], &cmd, sizeof cmd, &sdata2,
! 388: sizeof sdata2, 0) == 0 && sdata2 != 0xffff) {
! 389: sc->sc_sensor[ASB100_SENSOR_TEMP2].value = 273150000 +
! 390: 500000 * (swap16(sdata2) / 128);
! 391: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags &=
! 392: ~SENSOR_FINVALID;
! 393: } else {
! 394: sc->sc_sensor[ASB100_SENSOR_TEMP2].flags |=
! 395: SENSOR_FINVALID;
! 396: }
! 397: }
! 398:
! 399: asbtm_banksel(sc, orig_bank, NULL);
! 400:
! 401: iic_release_bus(sc->sc_tag, 0);
! 402: }
CVSweb