[BACK]Return to asb100.c CVS log [TXT][DIR] Up to [local] / sys / dev / i2c

Annotation of sys/dev/i2c/asb100.c, Revision 1.1.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