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

Annotation of sys/dev/i2c/lm75.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: lm75.c,v 1.15 2007/03/22 16:55:31 deraadt Exp $       */
        !             2: /*     $NetBSD: lm75.c,v 1.1 2003/09/30 00:35:31 thorpej Exp $ */
        !             3: /*
        !             4:  * Copyright (c) 2006 Theo de Raadt <deraadt@openbsd.org>
        !             5:  * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
        !             6:  *
        !             7:  * Permission to use, copy, modify, and distribute this software for any
        !             8:  * purpose with or without fee is hereby granted, provided that the above
        !             9:  * copyright notice and this permission notice appear in all copies.
        !            10:  *
        !            11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            18:  */
        !            19:
        !            20: /*
        !            21:  * National Semiconductor LM75/LM77 temperature sensor.
        !            22:  */
        !            23:
        !            24: #include <sys/param.h>
        !            25: #include <sys/systm.h>
        !            26: #include <sys/device.h>
        !            27: #include <sys/kernel.h>
        !            28: #include <sys/sensors.h>
        !            29:
        !            30: #include <dev/i2c/i2cvar.h>
        !            31:
        !            32: #define        LM_MODEL_LM75   1
        !            33: #define        LM_MODEL_LM77   2
        !            34: #define        LM_MODEL_DS1775 3
        !            35: #define        LM_MODEL_LM75A  4
        !            36:
        !            37: #define LM_POLLTIME    3       /* 3s */
        !            38:
        !            39: #define        LM75_REG_TEMP                   0x00
        !            40: #define        LM75_REG_CONFIG                 0x01
        !            41: #define  LM75_CONFIG_SHUTDOWN          0x01
        !            42: #define  LM75_CONFIG_CMPINT            0x02
        !            43: #define  LM75_CONFIG_OSPOLARITY                0x04
        !            44: #define  LM75_CONFIG_FAULT_QUEUE_MASK  0x18
        !            45: #define  LM75_CONFIG_FAULT_QUEUE_1     (0 << 3)
        !            46: #define  LM75_CONFIG_FAULT_QUEUE_2     (1 << 3)
        !            47: #define  LM75_CONFIG_FAULT_QUEUE_4     (2 << 3)
        !            48: #define  LM75_CONFIG_FAULT_QUEUE_6     (3 << 3)
        !            49: #define  LM77_CONFIG_INTPOLARITY       0x08
        !            50: #define  LM77_CONFIG_FAULT_QUEUE_4     0x10
        !            51: #define  DS1755_CONFIG_RESOLUTION(i)   (9 + (((i) >> 5) & 3))
        !            52: #define        LM75_REG_THYST_SET_POINT        0x02
        !            53: #define        LM75_REG_TOS_SET_POINT          0x03
        !            54: #define        LM77_REG_TLOW                   0x04
        !            55: #define        LM77_REG_THIGH                  0x05
        !            56:
        !            57: struct lmtemp_softc {
        !            58:        struct device sc_dev;
        !            59:        i2c_tag_t sc_tag;
        !            60:        int     sc_addr;
        !            61:        int     sc_model;
        !            62:        int     sc_bits;
        !            63:
        !            64:        struct ksensor sc_sensor;
        !            65:        struct ksensordev sc_sensordev;
        !            66: };
        !            67:
        !            68: int  lmtemp_match(struct device *, void *, void *);
        !            69: void lmtemp_attach(struct device *, struct device *, void *);
        !            70:
        !            71: struct cfattach lmtemp_ca = {
        !            72:        sizeof(struct lmtemp_softc),
        !            73:        lmtemp_match,
        !            74:        lmtemp_attach
        !            75: };
        !            76:
        !            77: struct cfdriver lmtemp_cd = {
        !            78:        NULL, "lmtemp", DV_DULL
        !            79: };
        !            80:
        !            81: /*
        !            82:  * Temperature on the LM75 is represented by a 9-bit two's complement
        !            83:  * integer in steps of 0.5C.  The following examples are taken from
        !            84:  * the LM75 data sheet:
        !            85:  *
        !            86:  *     +125C   0 1111 1010     0x0fa
        !            87:  *     +25C    0 0011 0010     0x032
        !            88:  *     +0.5C   0 0000 0001     0x001
        !            89:  *     0C      0 0000 0000     0x000
        !            90:  *     -0.5C   1 1111 1111     0x1ff
        !            91:  *     -25C    1 1100 1110     0x1ce
        !            92:  *     -55C    1 1001 0010     0x192
        !            93:  *
        !            94:  * Temperature on the LM75A is represented by an 11-bit two's complement
        !            95:  * integer in steps of 0.125C.  The LM75A can be treated like an LM75 if
        !            96:  * the extra precision is not required.  The following examples are
        !            97:  * taken from the LM75A data sheet:
        !            98:  *
        !            99:  *     +127.000C       011 1111 1000   0x3f8
        !           100:  *     +126.875C       011 1111 0111   0x3f7
        !           101:  *     +126.125C       011 1111 0001   0x3f1
        !           102:  *     +125.000C       011 1110 1000   0x3e8
        !           103:  *     +25.000C        000 1100 1000   0x0c8
        !           104:  *     +0.125C         000 0000 0001   0x001
        !           105:  *     0C              000 0000 0000   0x000
        !           106:  *     -0.125C         111 1111 1111   0x7ff
        !           107:  *     -25.000C        111 0011 1000   0x738
        !           108:  *     -54.875C        110 0100 1001   0x649
        !           109:  *     -55.000C        110 0100 1000   0x648
        !           110:  *
        !           111:  * Temperature on the LM77 is represented by a 10-bit two's complement
        !           112:  * integer in steps of 0.5C:
        !           113:  *
        !           114:  *     +130C   01 0000 0100    0x104
        !           115:  *     +125C   00 1111 1010    0x0fa
        !           116:  *     +25C    00 0011 0010    0x032
        !           117:  *     +0.5C   00 0000 0001    0x001
        !           118:  *     0C      00 0000 0000    0x000
        !           119:  *     -0.5C   11 1111 1111    0x3ff
        !           120:  *     -25C    11 1100 1110    0x3ce
        !           121:  *     -55C    11 1001 0010    0x392
        !           122:  *
        !           123:  * LM75 temperature word:
        !           124:  *
        !           125:  * MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X X X
        !           126:  * 15  14   13   12   11   10   9    8    7    6 5 4 3 2 1 0
        !           127:  *
        !           128:  *
        !           129:  * LM75A temperature word:
        !           130:  *
        !           131:  * MSB Bit9 Bit8 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X
        !           132:  * 15  14   13   12   11   10   9    8    7    6    5    4 3 2 1 0
        !           133:  *
        !           134:  *
        !           135:  * LM77 temperature word:
        !           136:  *
        !           137:  * Sign Sign Sign Sign MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 Status bits
        !           138:  * 15   14   13   12   11  10   9    8    7    6    5    4    3    2 1 0
        !           139:  */
        !           140:
        !           141: int  lmtemp_temp_read(struct lmtemp_softc *, uint8_t, int *);
        !           142: void lmtemp_refresh_sensor_data(void *);
        !           143:
        !           144: int
        !           145: lmtemp_match(struct device *parent, void *match, void *aux)
        !           146: {
        !           147:        struct i2c_attach_args *ia = aux;
        !           148:
        !           149:        if (strcmp(ia->ia_name, "lm75") == 0 ||
        !           150:            strcmp(ia->ia_name, "lm77") == 0 ||
        !           151:            strcmp(ia->ia_name, "ds1775") == 0 ||
        !           152:            strcmp(ia->ia_name, "lm75a") == 0)
        !           153:                return (1);
        !           154:        return (0);
        !           155: }
        !           156:
        !           157: void
        !           158: lmtemp_attach(struct device *parent, struct device *self, void *aux)
        !           159: {
        !           160:        struct lmtemp_softc *sc = (struct lmtemp_softc *)self;
        !           161:        struct i2c_attach_args *ia = aux;
        !           162:        u_int8_t cmd, data;
        !           163:
        !           164:        sc->sc_tag = ia->ia_tag;
        !           165:        sc->sc_addr = ia->ia_addr;
        !           166:
        !           167:        printf(": %s", ia->ia_name);
        !           168:
        !           169:        /* If in SHUTDOWN mode, wake it up */
        !           170:        iic_acquire_bus(sc->sc_tag, 0);
        !           171:        cmd = LM75_REG_CONFIG;
        !           172:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
        !           173:            sc->sc_addr, &cmd, 1, &data, 1, 0)) {
        !           174:                iic_release_bus(sc->sc_tag, 0);
        !           175:                return;
        !           176:        }
        !           177:        if (data & LM75_CONFIG_SHUTDOWN) {
        !           178:                data &= ~LM75_CONFIG_SHUTDOWN;
        !           179:                if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
        !           180:                    sc->sc_addr, &cmd, 1, &data, 1, 0)) {
        !           181:                        printf(", cannot wake up\n");
        !           182:                        iic_release_bus(sc->sc_tag, 0);
        !           183:                        return;
        !           184:                }
        !           185:                printf(", woken up");
        !           186:        }
        !           187:        iic_release_bus(sc->sc_tag, 0);
        !           188:
        !           189:        sc->sc_model = LM_MODEL_LM75;
        !           190:        sc->sc_bits = 9;
        !           191:        if (strcmp(ia->ia_name, "lm77") == 0) {
        !           192:                sc->sc_model = LM_MODEL_LM77;
        !           193:                sc->sc_bits = 13;
        !           194:        } else if (strcmp(ia->ia_name, "ds1775") == 0) {
        !           195:                sc->sc_model = LM_MODEL_DS1775;
        !           196:                sc->sc_bits = 9;
        !           197:                //sc->sc_bits = DS1755_CONFIG_RESOLUTION(data);
        !           198:        } else if (strcmp(ia->ia_name, "lm75a") == 0) {
        !           199:                /* For simplicity's sake, treat the LM75A as an LM75 */
        !           200:                sc->sc_model = LM_MODEL_LM75A;
        !           201:                sc->sc_bits = 9;
        !           202:        }
        !           203:
        !           204:        printf("\n");
        !           205:
        !           206:        /* Initialize sensor data */
        !           207:        strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
        !           208:            sizeof(sc->sc_sensordev.xname));
        !           209:        sc->sc_sensor.type = SENSOR_TEMP;
        !           210:
        !           211:        /* Hook into the hw.sensors sysctl */
        !           212:        sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
        !           213:        sensordev_install(&sc->sc_sensordev);
        !           214:
        !           215:
        !           216:        sensor_task_register(sc, lmtemp_refresh_sensor_data, LM_POLLTIME);
        !           217: }
        !           218:
        !           219: int
        !           220: lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, int *valp)
        !           221: {
        !           222:        u_int8_t cmd, buf[2];
        !           223:        int error;
        !           224:
        !           225:        cmd = which;
        !           226:        error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
        !           227:            sc->sc_addr, &cmd, 1, buf, 2, 0);
        !           228:        if (error)
        !           229:                return (error);
        !           230:
        !           231:        /* Some chips return transient 0's.. we try next time */
        !           232:        if (buf[0] == 0x00 && buf[1] == 0x00)
        !           233:                return (1);
        !           234:
        !           235:        /* convert to half-degrees C */
        !           236:        *valp = ((buf[0] << 8) | buf[1]) / (1 << (16 - sc->sc_bits));
        !           237:        return (0);
        !           238: }
        !           239:
        !           240: void
        !           241: lmtemp_refresh_sensor_data(void *aux)
        !           242: {
        !           243:        struct lmtemp_softc *sc = aux;
        !           244:        int val;
        !           245:        int error;
        !           246:
        !           247:        error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val);
        !           248:        if (error) {
        !           249: #if 0
        !           250:                printf("%s: unable to read temperature, error = %d\n",
        !           251:                    sc->sc_dev.dv_xname, error);
        !           252: #endif
        !           253:                sc->sc_sensor.flags |= SENSOR_FINVALID;
        !           254:                return;
        !           255:        }
        !           256:
        !           257:        sc->sc_sensor.value = val * 500000 + 273150000;
        !           258:        sc->sc_sensor.flags &= ~SENSOR_FINVALID;
        !           259: }

CVSweb