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

Annotation of sys/dev/i2c/lm87.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: lm87.c,v 1.19 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: /* LM87 registers */
                     27: #define LM87_2_5V      0x20
                     28: #define LM87_VCCP1     0x21
                     29: #define LM87_VCC       0x22
                     30: #define LM87_5V                0x23
                     31: #define LM87_12V       0x24
                     32: #define LM87_VCCP2     0x25
                     33: #define LM87_EXT_TEMP  0x26
                     34: #define LM87_INT_TEMP  0x27
                     35: #define LM87_FAN1      0x28
                     36: #define LM87_FAN2      0x29
                     37: #define LM87_REVISION  0x3f
                     38: #define LM87_CONFIG1   0x40
                     39: #define  LM87_CONFIG1_START    0x01
                     40: #define  LM87_CONFIG1_INTCLR   0x08
                     41: #define LM87_CHANNEL   0x16
                     42: #define  LM87_CHANNEL_AIN1     0x01
                     43: #define  LM87_CHANNEL_AIN2     0x02
                     44: #define LM87_FANDIV    0x47
                     45:
                     46: /* Sensors */
                     47: #define LMENV_2_5V             0
                     48: #define LMENV_VCCP1            1
                     49: #define LMENV_VCC              2
                     50: #define LMENV_5V               3
                     51: #define LMENV_12V              4
                     52: #define LMENV_VCCP2            5
                     53: #define LMENV_EXT_TEMP         6
                     54: #define LMENV_INT_TEMP         7
                     55: #define LMENV_FAN1             8
                     56: #define LMENV_FAN2             9
                     57: #define LMENV_NUM_SENSORS      10
                     58:
                     59: struct lmenv_softc {
                     60:        struct device sc_dev;
                     61:        i2c_tag_t sc_tag;
                     62:        i2c_addr_t sc_addr;
                     63:
                     64:        struct ksensor sc_sensor[LMENV_NUM_SENSORS];
                     65:        struct ksensordev sc_sensordev;
                     66:        int     sc_fan1_div, sc_fan2_div;
                     67:        int     sc_family;
                     68: };
                     69:
                     70: int    lmenv_match(struct device *, void *, void *);
                     71: void   lmenv_attach(struct device *, struct device *, void *);
                     72:
                     73: void   lmenv_refresh(void *);
                     74:
                     75: struct cfattach lmenv_ca = {
                     76:        sizeof(struct lmenv_softc), lmenv_match, lmenv_attach
                     77: };
                     78:
                     79: struct cfdriver lmenv_cd = {
                     80:        NULL, "lmenv", DV_DULL
                     81: };
                     82:
                     83: int
                     84: lmenv_match(struct device *parent, void *match, void *aux)
                     85: {
                     86:        struct i2c_attach_args *ia = aux;
                     87:
                     88:        if (strcmp(ia->ia_name, "lm87") == 0 ||
                     89:            strcmp(ia->ia_name, "lm87cimt") == 0 ||
                     90:            strcmp(ia->ia_name, "adm9240") == 0 ||
                     91:            strcmp(ia->ia_name, "lm81") == 0 ||
                     92:            strcmp(ia->ia_name, "ds1780") == 0)
                     93:                return (1);
                     94:        return (0);
                     95: }
                     96:
                     97: void
                     98: lmenv_attach(struct device *parent, struct device *self, void *aux)
                     99: {
                    100:        struct lmenv_softc *sc = (struct lmenv_softc *)self;
                    101:        struct i2c_attach_args *ia = aux;
                    102:        u_int8_t cmd, data, data2, channel;
                    103:        int i;
                    104:
                    105:        sc->sc_tag = ia->ia_tag;
                    106:        sc->sc_addr = ia->ia_addr;
                    107:
                    108:        sc->sc_family = 87;
                    109:        if (strcmp(ia->ia_name, "lm81") == 0 ||
                    110:            strcmp(ia->ia_name, "adm9240") == 0 ||
                    111:            strcmp(ia->ia_name, "ds1780") == 0)
                    112:                sc->sc_family = 81;
                    113:
                    114:        iic_acquire_bus(sc->sc_tag, 0);
                    115:
                    116:        cmd = LM87_REVISION;
                    117:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    118:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    119:                iic_release_bus(sc->sc_tag, 0);
                    120:                printf(": cannot read ID register\n");
                    121:                return;
                    122:        }
                    123:        printf(": %s rev %x", ia->ia_name, data);
                    124:
                    125:        cmd = LM87_FANDIV;
                    126:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    127:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    128:                iic_release_bus(sc->sc_tag, 0);
                    129:                printf(", cannot read Fan Divisor register\n");
                    130:                return;
                    131:        }
                    132:        sc->sc_fan1_div = 1 << ((data >> 4) & 0x03);
                    133:        sc->sc_fan2_div = 1 << ((data >> 6) & 0x03);
                    134:
                    135:        if (sc->sc_family == 87) {
                    136:                cmd = LM87_CHANNEL;
                    137:                if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    138:                    sc->sc_addr, &cmd, sizeof cmd, &channel,
                    139:                    sizeof channel, 0)) {
                    140:                        iic_release_bus(sc->sc_tag, 0);
                    141:                        printf(", cannot read Channel register\n");
                    142:                        return;
                    143:                }
                    144:        }
                    145:
                    146:        cmd = LM87_CONFIG1;
                    147:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    148:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    149:                iic_release_bus(sc->sc_tag, 0);
                    150:                printf(", cannot read Configuration Register 1\n");
                    151:                return;
                    152:        }
                    153:
                    154:        /*
                    155:         * if chip is not running, try to start it.
                    156:         * if it is stalled doing an interrupt, unstall it
                    157:         */
                    158:        data2 = (data | LM87_CONFIG1_START);
                    159:        data2 = data2 & ~LM87_CONFIG1_INTCLR;
                    160:
                    161:        if (data != data2) {
                    162:                if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
                    163:                    sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
                    164:                        iic_release_bus(sc->sc_tag, 0);
                    165:                        printf(", cannot write Configuration Register 1\n");
                    166:                        return;
                    167:                }
                    168:                printf(", starting scan");
                    169:        }
                    170:        iic_release_bus(sc->sc_tag, 0);
                    171:
                    172:        /* Initialize sensor data. */
                    173:        strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
                    174:            sizeof(sc->sc_sensordev.xname));
                    175:
                    176:        sc->sc_sensor[LMENV_2_5V].type = SENSOR_VOLTS_DC;
                    177:        strlcpy(sc->sc_sensor[LMENV_2_5V].desc, "+2.5Vin",
                    178:            sizeof(sc->sc_sensor[LMENV_2_5V].desc));
                    179:
                    180:        sc->sc_sensor[LMENV_VCCP1].type = SENSOR_VOLTS_DC;
                    181:        strlcpy(sc->sc_sensor[LMENV_VCCP1].desc, "Vccp",
                    182:            sizeof(sc->sc_sensor[LMENV_VCCP1].desc));
                    183:
                    184:        sc->sc_sensor[LMENV_VCC].type = SENSOR_VOLTS_DC;
                    185:        strlcpy(sc->sc_sensor[LMENV_VCC].desc, "+Vcc",
                    186:            sizeof(sc->sc_sensor[LMENV_VCC].desc));
                    187:
                    188:        sc->sc_sensor[LMENV_5V].type = SENSOR_VOLTS_DC;
                    189:        strlcpy(sc->sc_sensor[LMENV_5V].desc, "+5Vin/Vcc",
                    190:            sizeof(sc->sc_sensor[LMENV_5V].desc));
                    191:
                    192:        sc->sc_sensor[LMENV_12V].type = SENSOR_VOLTS_DC;
                    193:        strlcpy(sc->sc_sensor[LMENV_12V].desc, "+12Vin",
                    194:            sizeof(sc->sc_sensor[LMENV_12V].desc));
                    195:
                    196:        sc->sc_sensor[LMENV_VCCP2].type = SENSOR_VOLTS_DC;
                    197:        strlcpy(sc->sc_sensor[LMENV_VCCP2].desc, "Vccp",
                    198:            sizeof(sc->sc_sensor[LMENV_VCCP2].desc));
                    199:
                    200:        sc->sc_sensor[LMENV_EXT_TEMP].type = SENSOR_TEMP;
                    201:        strlcpy(sc->sc_sensor[LMENV_EXT_TEMP].desc, "External",
                    202:            sizeof(sc->sc_sensor[LMENV_EXT_TEMP].desc));
                    203:        if (sc->sc_family == 81)
                    204:                sc->sc_sensor[LMENV_EXT_TEMP].flags |= SENSOR_FINVALID;
                    205:
                    206:        sc->sc_sensor[LMENV_INT_TEMP].type = SENSOR_TEMP;
                    207:        strlcpy(sc->sc_sensor[LMENV_INT_TEMP].desc, "Internal",
                    208:            sizeof(sc->sc_sensor[LMENV_INT_TEMP].desc));
                    209:
                    210:        if (channel & LM87_CHANNEL_AIN1) {
                    211:                sc->sc_sensor[LMENV_FAN1].type = SENSOR_VOLTS_DC;
                    212:                strlcpy(sc->sc_sensor[LMENV_FAN1].desc, "AIN1",
                    213:                    sizeof(sc->sc_sensor[LMENV_FAN1].desc));
                    214:        } else {
                    215:                sc->sc_sensor[LMENV_FAN1].type = SENSOR_FANRPM;
                    216:        }
                    217:
                    218:        if (channel & LM87_CHANNEL_AIN2) {
                    219:                sc->sc_sensor[LMENV_FAN2].type = SENSOR_VOLTS_DC;
                    220:                strlcpy(sc->sc_sensor[LMENV_FAN2].desc, "AIN2",
                    221:                    sizeof(sc->sc_sensor[LMENV_FAN2].desc));
                    222:        } else {
                    223:                sc->sc_sensor[LMENV_FAN2].type = SENSOR_FANRPM;
                    224:        }
                    225:
                    226:        if (sensor_task_register(sc, lmenv_refresh, 5) == NULL) {
                    227:                printf(", unable to register update task\n");
                    228:                return;
                    229:        }
                    230:
                    231:        for (i = 0; i < LMENV_NUM_SENSORS; i++)
                    232:                sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
                    233:        sensordev_install(&sc->sc_sensordev);
                    234:
                    235:        printf("\n");
                    236: }
                    237:
                    238: void
                    239: lmenv_refresh(void *arg)
                    240: {
                    241:        struct lmenv_softc *sc = arg;
                    242:        u_int8_t cmd, data;
                    243:        u_int tmp;
                    244:        int sensor;
                    245:
                    246:        iic_acquire_bus(sc->sc_tag, 0);
                    247:
                    248:        for (sensor = 0; sensor < LMENV_NUM_SENSORS; sensor++) {
                    249:                cmd = LM87_2_5V + sensor;
                    250:                if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    251:                    sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    252:                        sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
                    253:                        continue;
                    254:                }
                    255:
                    256:                sc->sc_sensor[sensor].flags &= ~SENSOR_FINVALID;
                    257:                switch (sensor) {
                    258:                case LMENV_2_5V:
                    259:                        sc->sc_sensor[sensor].value = 2500000 * data / 192;
                    260:                        break;
                    261:                case LMENV_5V:
                    262:                        sc->sc_sensor[sensor].value = 5000000 * data / 192;
                    263:                        break;
                    264:                case LMENV_12V:
                    265:                        sc->sc_sensor[sensor].value = 12000000 * data / 192;
                    266:                        break;
                    267:                case LMENV_VCCP1:
                    268:                case LMENV_VCCP2:
                    269:                        sc->sc_sensor[sensor].value = 2700000 * data / 192;
                    270:                        break;
                    271:                case LMENV_VCC:
                    272:                        sc->sc_sensor[sensor].value = 3300000 * data / 192;
                    273:                        break;
                    274:                case LMENV_EXT_TEMP:
                    275:                        if (sc->sc_family == 81) {
                    276:                                sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
                    277:                                break;          /* missing on LM81 */
                    278:                        }
                    279:                        /* FALLTHROUGH */
                    280:                case LMENV_INT_TEMP:
                    281:                        if (data == 0x80)
                    282:                                sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
                    283:                        else
                    284:                                sc->sc_sensor[sensor].value =
                    285:                                    (int8_t)data * 1000000 + 273150000;
                    286:                        break;
                    287:                case LMENV_FAN1:
                    288:                        if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
                    289:                                sc->sc_sensor[sensor].value =
                    290:                                    1870000 * data / 192;
                    291:                                break;
                    292:                        }
                    293:                        tmp = data * sc->sc_fan1_div;
                    294:                        if (tmp == 0)
                    295:                                sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
                    296:                        else
                    297:                                sc->sc_sensor[sensor].value = 1350000 / tmp;
                    298:                        break;
                    299:                case LMENV_FAN2:
                    300:                        if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
                    301:                                sc->sc_sensor[sensor].value =
                    302:                                    1870000 * data / 192;
                    303:                                break;
                    304:                        }
                    305:                        tmp = data * sc->sc_fan2_div;
                    306:                        if (tmp == 0)
                    307:                                sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
                    308:                        else
                    309:                                sc->sc_sensor[sensor].value = 1350000 / tmp;
                    310:                        break;
                    311:                default:
                    312:                        sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
                    313:                        break;
                    314:                }
                    315:        }
                    316:
                    317:        iic_release_bus(sc->sc_tag, 0);
                    318: }

CVSweb