[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

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