LCOV - code coverage report
Current view: top level - dev/i2c - lm75.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 80 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 4 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: lm75.c,v 1.20 2015/05/30 08:39:05 kettenis 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/LM76/LM77 temperature sensor.
      22             :  */
      23             : 
      24             : #include <sys/param.h>
      25             : #include <sys/systm.h>
      26             : #include <sys/device.h>
      27             : #include <sys/sensors.h>
      28             : 
      29             : #include <dev/i2c/i2cvar.h>
      30             : 
      31             : #define LM_MODEL_LM75   1
      32             : #define LM_MODEL_LM77   2
      33             : #define LM_MODEL_DS1775 3
      34             : #define LM_MODEL_LM75A  4
      35             : #define LM_MODEL_LM76   5
      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             :         int     sc_ratio;
      64             : 
      65             :         struct ksensor sc_sensor;
      66             :         struct ksensordev sc_sensordev;
      67             : };
      68             : 
      69             : int  lmtemp_match(struct device *, void *, void *);
      70             : void lmtemp_attach(struct device *, struct device *, void *);
      71             : 
      72             : struct cfattach lmtemp_ca = {
      73             :         sizeof(struct lmtemp_softc),
      74             :         lmtemp_match,
      75             :         lmtemp_attach
      76             : };
      77             : 
      78             : struct cfdriver lmtemp_cd = {
      79             :         NULL, "lmtemp", DV_DULL
      80             : };
      81             : 
      82             : /*
      83             :  * Temperature on the LM75 is represented by a 9-bit two's complement
      84             :  * integer in steps of 0.5C.  The following examples are taken from
      85             :  * the LM75 data sheet:
      86             :  *
      87             :  *      +125C   0 1111 1010     0x0fa
      88             :  *      +25C    0 0011 0010     0x032
      89             :  *      +0.5C   0 0000 0001     0x001
      90             :  *      0C      0 0000 0000     0x000
      91             :  *      -0.5C   1 1111 1111     0x1ff
      92             :  *      -25C    1 1100 1110     0x1ce
      93             :  *      -55C    1 1001 0010     0x192
      94             :  *
      95             :  * Temperature on the LM75A is represented by an 11-bit two's complement
      96             :  * integer in steps of 0.125C.  The LM75A can be treated like an LM75 if
      97             :  * the extra precision is not required.  The following examples are
      98             :  * taken from the LM75A data sheet:
      99             :  *
     100             :  *      +127.000C       011 1111 1000   0x3f8
     101             :  *      +126.875C       011 1111 0111   0x3f7
     102             :  *      +126.125C       011 1111 0001   0x3f1
     103             :  *      +125.000C       011 1110 1000   0x3e8
     104             :  *      +25.000C        000 1100 1000   0x0c8
     105             :  *      +0.125C         000 0000 0001   0x001
     106             :  *      0C              000 0000 0000   0x000
     107             :  *      -0.125C         111 1111 1111   0x7ff
     108             :  *      -25.000C        111 0011 1000   0x738
     109             :  *      -54.875C        110 0100 1001   0x649
     110             :  *      -55.000C        110 0100 1000   0x648
     111             :  *
     112             :  * Temperature on the LM77 is represented by a 13-bit two's complement
     113             :  * integer in steps of 0.5C.  The LM76 is similar, but the integer is
     114             :  * in steps of 0.065C
     115             :  *
     116             :  * LM75 temperature word:
     117             :  *
     118             :  * MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X X X
     119             :  * 15  14   13   12   11   10   9    8    7    6 5 4 3 2 1 0
     120             :  *
     121             :  *
     122             :  * LM75A temperature word:
     123             :  *
     124             :  * MSB Bit9 Bit8 Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 X X X X X
     125             :  * 15  14   13   12   11   10   9    8    7    6    5    4 3 2 1 0
     126             :  *
     127             :  *
     128             :  * LM77 temperature word:
     129             :  *
     130             :  * Sign Sign Sign Sign MSB Bit7 Bit6 Bit5 Bit4 Bit3 Bit2 Bit1 Bit0 Status bits
     131             :  * 15   14   13   12   11  10   9    8    7    6    5    4    3    2 1 0
     132             :  */
     133             : 
     134             : int  lmtemp_temp_read(struct lmtemp_softc *, uint8_t, int *);
     135             : void lmtemp_refresh_sensor_data(void *);
     136             : 
     137             : int
     138           0 : lmtemp_match(struct device *parent, void *match, void *aux)
     139             : {
     140           0 :         struct i2c_attach_args *ia = aux;
     141             : 
     142           0 :         if (strcmp(ia->ia_name, "lm75") == 0 ||
     143           0 :             strcmp(ia->ia_name, "lm76") == 0 ||
     144           0 :             strcmp(ia->ia_name, "lm77") == 0 ||
     145           0 :             strcmp(ia->ia_name, "ds1775") == 0 ||
     146           0 :             strcmp(ia->ia_name, "lm75a") == 0)
     147           0 :                 return (1);
     148           0 :         return (0);
     149           0 : }
     150             : 
     151             : void
     152           0 : lmtemp_attach(struct device *parent, struct device *self, void *aux)
     153             : {
     154           0 :         struct lmtemp_softc *sc = (struct lmtemp_softc *)self;
     155           0 :         struct i2c_attach_args *ia = aux;
     156           0 :         u_int8_t cmd, data;
     157             : 
     158           0 :         sc->sc_tag = ia->ia_tag;
     159           0 :         sc->sc_addr = ia->ia_addr;
     160             : 
     161           0 :         printf(": %s", ia->ia_name);
     162             : 
     163             :         /* If in SHUTDOWN mode, wake it up */
     164           0 :         iic_acquire_bus(sc->sc_tag, 0);
     165           0 :         cmd = LM75_REG_CONFIG;
     166           0 :         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     167           0 :             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
     168           0 :                 iic_release_bus(sc->sc_tag, 0);
     169           0 :                 printf(", fails to respond\n");
     170           0 :                 return;
     171             :         }
     172           0 :         if (data & LM75_CONFIG_SHUTDOWN) {
     173           0 :                 data &= ~LM75_CONFIG_SHUTDOWN;
     174           0 :                 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
     175           0 :                     sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
     176           0 :                         printf(", cannot wake up\n");
     177           0 :                         iic_release_bus(sc->sc_tag, 0);
     178           0 :                         return;
     179             :                 }
     180           0 :                 printf(", woken up");
     181           0 :         }
     182           0 :         iic_release_bus(sc->sc_tag, 0);
     183             : 
     184           0 :         sc->sc_model = LM_MODEL_LM75;
     185           0 :         sc->sc_bits = 9;
     186           0 :         sc->sc_ratio = 500000;               /* 0.5 degC for LSB */
     187           0 :         if (strcmp(ia->ia_name, "lm77") == 0) {
     188           0 :                 sc->sc_model = LM_MODEL_LM77;
     189           0 :                 sc->sc_bits = 13;
     190           0 :         } else if (strcmp(ia->ia_name, "lm76") == 0) {
     191           0 :                 sc->sc_model = LM_MODEL_LM76;
     192           0 :                 sc->sc_bits = 13;
     193           0 :                 sc->sc_ratio = 62500;        /* 0.0625 degC for LSB */
     194           0 :         } else if (strcmp(ia->ia_name, "ds1775") == 0) {
     195           0 :                 sc->sc_model = LM_MODEL_DS1775;
     196             :                 //sc->sc_bits = DS1755_CONFIG_RESOLUTION(data);
     197           0 :         } else if (strcmp(ia->ia_name, "lm75a") == 0) {
     198             :                 /* For simplicity's sake, treat the LM75A as an LM75 */
     199           0 :                 sc->sc_model = LM_MODEL_LM75A;
     200           0 :         }
     201             : 
     202           0 :         printf("\n");
     203             : 
     204             :         /* Initialize sensor data */
     205           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
     206             :             sizeof(sc->sc_sensordev.xname));
     207           0 :         sc->sc_sensor.type = SENSOR_TEMP;
     208             : 
     209             :         /* Hook into the hw.sensors sysctl */
     210           0 :         sensor_attach(&sc->sc_sensordev, &sc->sc_sensor);
     211           0 :         sensordev_install(&sc->sc_sensordev);
     212             : 
     213           0 :         sensor_task_register(sc, lmtemp_refresh_sensor_data, LM_POLLTIME);
     214           0 : }
     215             : 
     216             : int
     217           0 : lmtemp_temp_read(struct lmtemp_softc *sc, uint8_t which, int *valp)
     218             : {
     219           0 :         u_int8_t cmd = which;
     220           0 :         u_int16_t data = 0x0000;
     221             :         int error;
     222             : 
     223           0 :         iic_acquire_bus(sc->sc_tag, 0);
     224           0 :         error = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     225           0 :             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0);
     226           0 :         iic_release_bus(sc->sc_tag, 0);
     227           0 :         if (error)
     228           0 :                 return (error);
     229             : 
     230             :         /* Some chips return transient 0's.. we try next time */
     231           0 :         if (data == 0x0000)
     232           0 :                 return (1);
     233             : 
     234             :         /* convert to half-degrees C */
     235           0 :         *valp = betoh16(data) / (1 << (16 - sc->sc_bits));
     236           0 :         return (0);
     237           0 : }
     238             : 
     239             : void
     240           0 : lmtemp_refresh_sensor_data(void *aux)
     241             : {
     242           0 :         struct lmtemp_softc *sc = aux;
     243           0 :         int val;
     244             :         int error;
     245             : 
     246           0 :         error = lmtemp_temp_read(sc, LM75_REG_TEMP, &val);
     247           0 :         if (error) {
     248             : #if 0
     249             :                 printf("%s: unable to read temperature, error = %d\n",
     250             :                     sc->sc_dev.dv_xname, error);
     251             : #endif
     252           0 :                 sc->sc_sensor.flags |= SENSOR_FINVALID;
     253           0 :                 return;
     254             :         }
     255             : 
     256           0 :         sc->sc_sensor.value = val * sc->sc_ratio + 273150000;
     257           0 :         sc->sc_sensor.flags &= ~SENSOR_FINVALID;
     258           0 : }

Generated by: LCOV version 1.13