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

          Line data    Source code
       1             : /*      $OpenBSD: lm87.c,v 1.20 2008/11/10 05:19:48 cnst Exp $  */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2005 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             : /* LM87 registers */
      27             : #define LM87_2_5V       0x20
      28             : #define LM87_VCCP1      0x21
      29             : #define LM87_VCC        0x22
      30             : #define LM87_5V         0x23
      31             : #define LM87_12V        0x24
      32             : #define LM87_VCCP2      0x25
      33             : #define LM87_EXT_TEMP   0x26
      34             : #define LM87_INT_TEMP   0x27
      35             : #define LM87_FAN1       0x28
      36             : #define LM87_FAN2       0x29
      37             : #define LM87_REVISION   0x3f
      38             : #define LM87_CONFIG1    0x40
      39             : #define  LM87_CONFIG1_START     0x01
      40             : #define  LM87_CONFIG1_INTCLR    0x08
      41             : #define LM87_CHANNEL    0x16
      42             : #define  LM87_CHANNEL_AIN1      0x01
      43             : #define  LM87_CHANNEL_AIN2      0x02
      44             : #define LM87_FANDIV     0x47
      45             : 
      46             : /* Sensors */
      47             : #define LMENV_2_5V              0
      48             : #define LMENV_VCCP1             1
      49             : #define LMENV_VCC               2
      50             : #define LMENV_5V                3
      51             : #define LMENV_12V               4
      52             : #define LMENV_VCCP2             5
      53             : #define LMENV_EXT_TEMP          6
      54             : #define LMENV_INT_TEMP          7
      55             : #define LMENV_FAN1              8
      56             : #define LMENV_FAN2              9
      57             : #define LMENV_NUM_SENSORS       10
      58             : 
      59             : struct lmenv_softc {
      60             :         struct device sc_dev;
      61             :         i2c_tag_t sc_tag;
      62             :         i2c_addr_t sc_addr;
      63             : 
      64             :         struct ksensor sc_sensor[LMENV_NUM_SENSORS];
      65             :         struct ksensordev sc_sensordev;
      66             :         int     sc_fan1_div, sc_fan2_div;
      67             :         int     sc_family;
      68             : };
      69             : 
      70             : int     lmenv_match(struct device *, void *, void *);
      71             : void    lmenv_attach(struct device *, struct device *, void *);
      72             : 
      73             : void    lmenv_refresh(void *);
      74             : 
      75             : struct cfattach lmenv_ca = {
      76             :         sizeof(struct lmenv_softc), lmenv_match, lmenv_attach
      77             : };
      78             : 
      79             : struct cfdriver lmenv_cd = {
      80             :         NULL, "lmenv", DV_DULL
      81             : };
      82             : 
      83             : int
      84           0 : lmenv_match(struct device *parent, void *match, void *aux)
      85             : {
      86           0 :         struct i2c_attach_args *ia = aux;
      87             : 
      88           0 :         if (strcmp(ia->ia_name, "lm87") == 0 ||
      89           0 :             strcmp(ia->ia_name, "lm87cimt") == 0 ||
      90           0 :             strcmp(ia->ia_name, "adm9240") == 0 ||
      91           0 :             strcmp(ia->ia_name, "lm81") == 0 ||
      92           0 :             strcmp(ia->ia_name, "ds1780") == 0)
      93           0 :                 return (1);
      94           0 :         return (0);
      95           0 : }
      96             : 
      97             : void
      98           0 : lmenv_attach(struct device *parent, struct device *self, void *aux)
      99             : {
     100           0 :         struct lmenv_softc *sc = (struct lmenv_softc *)self;
     101           0 :         struct i2c_attach_args *ia = aux;
     102           0 :         u_int8_t cmd, data, data2, channel;
     103             :         int i;
     104             : 
     105           0 :         sc->sc_tag = ia->ia_tag;
     106           0 :         sc->sc_addr = ia->ia_addr;
     107             : 
     108           0 :         sc->sc_family = 87;
     109           0 :         if (strcmp(ia->ia_name, "lm81") == 0 ||
     110           0 :             strcmp(ia->ia_name, "adm9240") == 0 ||
     111           0 :             strcmp(ia->ia_name, "ds1780") == 0)
     112           0 :                 sc->sc_family = 81;
     113             : 
     114           0 :         iic_acquire_bus(sc->sc_tag, 0);
     115             : 
     116           0 :         cmd = LM87_REVISION;
     117           0 :         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     118           0 :             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
     119           0 :                 iic_release_bus(sc->sc_tag, 0);
     120           0 :                 printf(": cannot read ID register\n");
     121           0 :                 return;
     122             :         }
     123           0 :         printf(": %s rev %x", ia->ia_name, data);
     124             : 
     125           0 :         cmd = LM87_FANDIV;
     126           0 :         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     127           0 :             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
     128           0 :                 iic_release_bus(sc->sc_tag, 0);
     129           0 :                 printf(", cannot read Fan Divisor register\n");
     130           0 :                 return;
     131             :         }
     132           0 :         sc->sc_fan1_div = 1 << ((data >> 4) & 0x03);
     133           0 :         sc->sc_fan2_div = 1 << ((data >> 6) & 0x03);
     134             : 
     135           0 :         if (sc->sc_family == 87) {
     136           0 :                 cmd = LM87_CHANNEL;
     137           0 :                 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     138           0 :                     sc->sc_addr, &cmd, sizeof cmd, &channel,
     139             :                     sizeof channel, 0)) {
     140           0 :                         iic_release_bus(sc->sc_tag, 0);
     141           0 :                         printf(", cannot read Channel register\n");
     142           0 :                         return;
     143             :                 }
     144             :         } else
     145           0 :                 channel = 0;
     146             : 
     147           0 :         cmd = LM87_CONFIG1;
     148           0 :         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     149           0 :             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
     150           0 :                 iic_release_bus(sc->sc_tag, 0);
     151           0 :                 printf(", cannot read Configuration Register 1\n");
     152           0 :                 return;
     153             :         }
     154             : 
     155             :         /*
     156             :          * if chip is not running, try to start it.
     157             :          * if it is stalled doing an interrupt, unstall it
     158             :          */
     159           0 :         data2 = (data | LM87_CONFIG1_START);
     160           0 :         data2 = data2 & ~LM87_CONFIG1_INTCLR;
     161             : 
     162           0 :         if (data != data2) {
     163           0 :                 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
     164           0 :                     sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
     165           0 :                         iic_release_bus(sc->sc_tag, 0);
     166           0 :                         printf(", cannot write Configuration Register 1\n");
     167           0 :                         return;
     168             :                 }
     169           0 :                 printf(", starting scan");
     170           0 :         }
     171           0 :         iic_release_bus(sc->sc_tag, 0);
     172             : 
     173             :         /* Initialize sensor data. */
     174           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
     175             :             sizeof(sc->sc_sensordev.xname));
     176             : 
     177           0 :         sc->sc_sensor[LMENV_2_5V].type = SENSOR_VOLTS_DC;
     178           0 :         strlcpy(sc->sc_sensor[LMENV_2_5V].desc, "+2.5Vin",
     179             :             sizeof(sc->sc_sensor[LMENV_2_5V].desc));
     180             : 
     181           0 :         sc->sc_sensor[LMENV_VCCP1].type = SENSOR_VOLTS_DC;
     182           0 :         strlcpy(sc->sc_sensor[LMENV_VCCP1].desc, "Vccp",
     183             :             sizeof(sc->sc_sensor[LMENV_VCCP1].desc));
     184             : 
     185           0 :         sc->sc_sensor[LMENV_VCC].type = SENSOR_VOLTS_DC;
     186           0 :         strlcpy(sc->sc_sensor[LMENV_VCC].desc, "+Vcc",
     187             :             sizeof(sc->sc_sensor[LMENV_VCC].desc));
     188             : 
     189           0 :         sc->sc_sensor[LMENV_5V].type = SENSOR_VOLTS_DC;
     190           0 :         strlcpy(sc->sc_sensor[LMENV_5V].desc, "+5Vin/Vcc",
     191             :             sizeof(sc->sc_sensor[LMENV_5V].desc));
     192             : 
     193           0 :         sc->sc_sensor[LMENV_12V].type = SENSOR_VOLTS_DC;
     194           0 :         strlcpy(sc->sc_sensor[LMENV_12V].desc, "+12Vin",
     195             :             sizeof(sc->sc_sensor[LMENV_12V].desc));
     196             : 
     197           0 :         sc->sc_sensor[LMENV_VCCP2].type = SENSOR_VOLTS_DC;
     198           0 :         strlcpy(sc->sc_sensor[LMENV_VCCP2].desc, "Vccp",
     199             :             sizeof(sc->sc_sensor[LMENV_VCCP2].desc));
     200             : 
     201           0 :         sc->sc_sensor[LMENV_EXT_TEMP].type = SENSOR_TEMP;
     202           0 :         strlcpy(sc->sc_sensor[LMENV_EXT_TEMP].desc, "External",
     203             :             sizeof(sc->sc_sensor[LMENV_EXT_TEMP].desc));
     204           0 :         if (sc->sc_family == 81)
     205           0 :                 sc->sc_sensor[LMENV_EXT_TEMP].flags |= SENSOR_FINVALID;
     206             : 
     207           0 :         sc->sc_sensor[LMENV_INT_TEMP].type = SENSOR_TEMP;
     208           0 :         strlcpy(sc->sc_sensor[LMENV_INT_TEMP].desc, "Internal",
     209             :             sizeof(sc->sc_sensor[LMENV_INT_TEMP].desc));
     210             : 
     211           0 :         if (channel & LM87_CHANNEL_AIN1) {
     212           0 :                 sc->sc_sensor[LMENV_FAN1].type = SENSOR_VOLTS_DC;
     213           0 :                 strlcpy(sc->sc_sensor[LMENV_FAN1].desc, "AIN1",
     214             :                     sizeof(sc->sc_sensor[LMENV_FAN1].desc));
     215           0 :         } else {
     216           0 :                 sc->sc_sensor[LMENV_FAN1].type = SENSOR_FANRPM;
     217             :         }
     218             : 
     219           0 :         if (channel & LM87_CHANNEL_AIN2) {
     220           0 :                 sc->sc_sensor[LMENV_FAN2].type = SENSOR_VOLTS_DC;
     221           0 :                 strlcpy(sc->sc_sensor[LMENV_FAN2].desc, "AIN2",
     222             :                     sizeof(sc->sc_sensor[LMENV_FAN2].desc));
     223           0 :         } else {
     224           0 :                 sc->sc_sensor[LMENV_FAN2].type = SENSOR_FANRPM;
     225             :         }
     226             : 
     227           0 :         if (sensor_task_register(sc, lmenv_refresh, 5) == NULL) {
     228           0 :                 printf(", unable to register update task\n");
     229           0 :                 return;
     230             :         }
     231             : 
     232           0 :         for (i = 0; i < LMENV_NUM_SENSORS; i++)
     233           0 :                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
     234           0 :         sensordev_install(&sc->sc_sensordev);
     235             : 
     236           0 :         printf("\n");
     237           0 : }
     238             : 
     239             : void
     240           0 : lmenv_refresh(void *arg)
     241             : {
     242           0 :         struct lmenv_softc *sc = arg;
     243           0 :         u_int8_t cmd, data;
     244             :         u_int tmp;
     245             :         int sensor;
     246             : 
     247           0 :         iic_acquire_bus(sc->sc_tag, 0);
     248             : 
     249           0 :         for (sensor = 0; sensor < LMENV_NUM_SENSORS; sensor++) {
     250           0 :                 cmd = LM87_2_5V + sensor;
     251           0 :                 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     252           0 :                     sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
     253           0 :                         sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
     254           0 :                         continue;
     255             :                 }
     256             : 
     257           0 :                 sc->sc_sensor[sensor].flags &= ~SENSOR_FINVALID;
     258           0 :                 switch (sensor) {
     259             :                 case LMENV_2_5V:
     260           0 :                         sc->sc_sensor[sensor].value = 2500000 * data / 192;
     261           0 :                         break;
     262             :                 case LMENV_5V:
     263           0 :                         sc->sc_sensor[sensor].value = 5000000 * data / 192;
     264           0 :                         break;
     265             :                 case LMENV_12V:
     266           0 :                         sc->sc_sensor[sensor].value = 12000000 * data / 192;
     267           0 :                         break;
     268             :                 case LMENV_VCCP1:
     269             :                 case LMENV_VCCP2:
     270           0 :                         sc->sc_sensor[sensor].value = 2700000 * data / 192;
     271           0 :                         break;
     272             :                 case LMENV_VCC:
     273           0 :                         sc->sc_sensor[sensor].value = 3300000 * data / 192;
     274           0 :                         break;
     275             :                 case LMENV_EXT_TEMP:
     276           0 :                         if (sc->sc_family == 81) {
     277           0 :                                 sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
     278           0 :                                 break;          /* missing on LM81 */
     279             :                         }
     280             :                         /* FALLTHROUGH */
     281             :                 case LMENV_INT_TEMP:
     282           0 :                         if (data == 0x80)
     283           0 :                                 sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
     284             :                         else
     285           0 :                                 sc->sc_sensor[sensor].value =
     286           0 :                                     (int8_t)data * 1000000 + 273150000;
     287             :                         break;
     288             :                 case LMENV_FAN1:
     289           0 :                         if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
     290           0 :                                 sc->sc_sensor[sensor].value =
     291           0 :                                     1870000 * data / 192;
     292           0 :                                 break;
     293             :                         }
     294           0 :                         tmp = data * sc->sc_fan1_div;
     295           0 :                         if (tmp == 0)
     296           0 :                                 sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
     297             :                         else
     298           0 :                                 sc->sc_sensor[sensor].value = 1350000 / tmp;
     299             :                         break;
     300             :                 case LMENV_FAN2:
     301           0 :                         if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
     302           0 :                                 sc->sc_sensor[sensor].value =
     303           0 :                                     1870000 * data / 192;
     304           0 :                                 break;
     305             :                         }
     306           0 :                         tmp = data * sc->sc_fan2_div;
     307           0 :                         if (tmp == 0)
     308           0 :                                 sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
     309             :                         else
     310           0 :                                 sc->sc_sensor[sensor].value = 1350000 / tmp;
     311             :                         break;
     312             :                 default:
     313           0 :                         sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
     314           0 :                         break;
     315             :                 }
     316             :         }
     317             : 
     318           0 :         iic_release_bus(sc->sc_tag, 0);
     319           0 : }

Generated by: LCOV version 1.13