root/dev/i2c/lm75.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lmtemp_match
  2. lmtemp_attach
  3. lmtemp_temp_read
  4. lmtemp_refresh_sensor_data

    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 }

/* [<][>][^][v][top][bottom][index][help] */