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

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

1.1       nbrk        1: /*     $OpenBSD: gl518sm.c,v 1.6 2007/06/24 05:34:35 dlg Exp $ */
                      2:
                      3: /*
                      4:  * Copyright (c) 2006 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: /* GL518SM registers */
                     27: #define GL518SM_CHIPID         0x00
                     28: #define GL518SM_REVISION       0x01
                     29: #define GL518SM_VENDORID       0x02
                     30: #define GL518SM_CONFIG         0x03
                     31: #define  GL518SM_CONFIG_START          0x40
                     32: #define  GL518SM_CONFIG_CLEARST                0x20
                     33: #define  GL518SM_CONFIG_NOFAN2         0x10
                     34: #define GL518SM_TEMP           0x04
                     35: #define GL518SM_TEMP_OVER      0x05
                     36: #define GL518SM_TEMP_HYST      0x06
                     37: #define GL518SM_FAN_COUNT      0x07
                     38: #define GL518SM_FAN_LIMIT      0x08
                     39: #define GL518SM_VIN1_LIMIT     0x09
                     40: #define GL518SM_VIN2_LIMIT     0x0a
                     41: #define GL518SM_VIN3_LIMIT     0x0b
                     42: #define GL518SM_VDD_LIMIT      0x0c
                     43: #define GL518SM_VOLTMETER      0x0d
                     44: #define GL518SM_MISC           0x0f
                     45: #define GL518SM_ALARM          0x10
                     46: #define GL518SM_MASK           0x11
                     47: #define GL518SM_INTSTAT                0x12
                     48:
                     49: /* Sensors */
                     50: #define GLENV_VIN3             0
                     51: #define GLENV_TEMP             1
                     52: #define GLENV_FAN1             2
                     53: #define GLENV_FAN2             3
                     54: #define GLENV_NUM_SENSORS      4
                     55:
                     56: struct glenv_softc {
                     57:        struct device sc_dev;
                     58:
                     59:        i2c_tag_t sc_tag;
                     60:        i2c_addr_t sc_addr;
                     61:
                     62:        struct ksensor sc_sensor[GLENV_NUM_SENSORS];
                     63:        struct ksensordev sc_sensordev;
                     64:        int     sc_fan1_div, sc_fan2_div;
                     65: };
                     66:
                     67: int    glenv_match(struct device *, void *, void *);
                     68: void   glenv_attach(struct device *, struct device *, void *);
                     69:
                     70: void   glenv_refresh(void *);
                     71:
                     72: struct cfattach glenv_ca = {
                     73:        sizeof(struct glenv_softc), glenv_match, glenv_attach
                     74: };
                     75:
                     76: struct cfdriver glenv_cd = {
                     77:        NULL, "glenv", DV_DULL
                     78: };
                     79:
                     80: int
                     81: glenv_match(struct device *parent, void *match, void *aux)
                     82: {
                     83:        struct i2c_attach_args *ia = aux;
                     84:
                     85:        if (strcmp(ia->ia_name, "gl518sm") == 0)
                     86:                return (1);
                     87:        return (0);
                     88: }
                     89:
                     90: void
                     91: glenv_attach(struct device *parent, struct device *self, void *aux)
                     92: {
                     93:        struct glenv_softc *sc = (struct glenv_softc *)self;
                     94:        struct i2c_attach_args *ia = aux;
                     95:        u_int8_t cmd, data;
                     96:        int i;
                     97:
                     98:        sc->sc_tag = ia->ia_tag;
                     99:        sc->sc_addr = ia->ia_addr;
                    100:
                    101:        iic_acquire_bus(sc->sc_tag, 0);
                    102:
                    103:        cmd = GL518SM_REVISION;
                    104:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    105:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    106:                iic_release_bus(sc->sc_tag, 0);
                    107:                printf(": cannot read revision register\n");
                    108:                return;
                    109:        }
                    110:
                    111:        printf(": GL518SM rev 0x%02x", data);
                    112:
                    113:        cmd = GL518SM_MISC;
                    114:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    115:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    116:                iic_release_bus(sc->sc_tag, 0);
                    117:                printf(", cannot read misc register\n");
                    118:                return;
                    119:        }
                    120:        sc->sc_fan1_div = 1 << ((data >> 6) & 0x03);
                    121:        sc->sc_fan2_div = 1 << ((data >> 4) & 0x03);
                    122:
                    123:        cmd = GL518SM_CONFIG;
                    124:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    125:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    126:                iic_release_bus(sc->sc_tag, 0);
                    127:                printf(", cannot read configuration register\n");
                    128:                return;
                    129:        }
                    130:        if (data & GL518SM_CONFIG_NOFAN2)
                    131:                sc->sc_fan2_div = 0;
                    132:
                    133:        /* Start monitoring and clear interrupt status. */
                    134:        data = (data | GL518SM_CONFIG_START | GL518SM_CONFIG_CLEARST);
                    135:        if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
                    136:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    137:                        iic_release_bus(sc->sc_tag, 0);
                    138:                        printf(", cannot write configuration register\n");
                    139:                        return;
                    140:        }
                    141:
                    142:        iic_release_bus(sc->sc_tag, 0);
                    143:
                    144:        /* Initialize sensor data. */
                    145:        strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
                    146:            sizeof(sc->sc_sensordev.xname));
                    147:
                    148:        sc->sc_sensor[GLENV_VIN3].type = SENSOR_VOLTS_DC;
                    149:
                    150:        sc->sc_sensor[GLENV_TEMP].type = SENSOR_TEMP;
                    151:
                    152:        sc->sc_sensor[GLENV_FAN1].type = SENSOR_FANRPM;
                    153:
                    154:        sc->sc_sensor[GLENV_FAN2].type = SENSOR_FANRPM;
                    155:        if (sc->sc_fan2_div == -1)
                    156:                sc->sc_sensor[GLENV_FAN2].flags |= SENSOR_FINVALID;
                    157:
                    158:        if (sensor_task_register(sc, glenv_refresh, 5) == NULL) {
                    159:                printf(", unable to register update task\n");
                    160:                return;
                    161:        }
                    162:
                    163:        for (i = 0; i < GLENV_NUM_SENSORS; i++)
                    164:                sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
                    165:        sensordev_install(&sc->sc_sensordev);
                    166:
                    167:        printf("\n");
                    168: }
                    169:
                    170: void
                    171: glenv_refresh(void *arg)
                    172: {
                    173:        struct glenv_softc *sc = arg;
                    174:        u_int8_t cmd, data, data2[2];
                    175:        u_int tmp;
                    176:
                    177:        iic_acquire_bus(sc->sc_tag, 0);
                    178:
                    179:        cmd = GL518SM_VOLTMETER;
                    180:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    181:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    182:                sc->sc_sensor[GLENV_VIN3].flags |= SENSOR_FINVALID;
                    183:        } else {
                    184:                sc->sc_sensor[GLENV_VIN3].flags &= ~SENSOR_FINVALID;
                    185:                sc->sc_sensor[GLENV_VIN3].value = data * 19000;
                    186:        }
                    187:
                    188:        cmd = GL518SM_TEMP;
                    189:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    190:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
                    191:                sc->sc_sensor[GLENV_TEMP].flags |= SENSOR_FINVALID;
                    192:        } else {
                    193:                sc->sc_sensor[GLENV_TEMP].flags &= ~SENSOR_FINVALID;
                    194:                sc->sc_sensor[GLENV_TEMP].value =
                    195:                        (data - 119) * 1000000 + 273150000;
                    196:        }
                    197:
                    198:        cmd = GL518SM_FAN_COUNT;
                    199:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
                    200:            sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
                    201:                sc->sc_sensor[GLENV_FAN1].flags |= SENSOR_FINVALID;
                    202:                sc->sc_sensor[GLENV_FAN2].flags |= SENSOR_FINVALID;
                    203:        } else {
                    204:                sc->sc_sensor[GLENV_FAN1].flags &= ~SENSOR_FINVALID;
                    205:                tmp = data2[0] * sc->sc_fan1_div * 2;
                    206:                if (tmp == 0)
                    207:                        sc->sc_sensor[GLENV_FAN1].flags |= SENSOR_FINVALID;
                    208:                else
                    209:                        sc->sc_sensor[GLENV_FAN1].value = 960000 / tmp;
                    210:
                    211:                sc->sc_sensor[GLENV_FAN2].flags &= ~SENSOR_FINVALID;
                    212:                tmp = data2[1] * sc->sc_fan2_div * 2;
                    213:                if (tmp == 0)
                    214:                        sc->sc_sensor[GLENV_FAN2].flags |= SENSOR_FINVALID;
                    215:                else
                    216:                        sc->sc_sensor[GLENV_FAN2].value = 960000 / tmp;
                    217:        }
                    218:
                    219:        iic_release_bus(sc->sc_tag, 0);
                    220: }

CVSweb