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

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