[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

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