[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     ! 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