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

          Line data    Source code
       1             : /*      $OpenBSD: asc7611.c,v 1.2 2009/01/26 15:07:49 kettenis Exp $    */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2008 Constantine A. Murenin <cnst+openbsd@bugmail.mojo.ru>
       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             : /*
      27             :  * Andigilog aSC7611
      28             :  *      Hardware Monitor with Integrated Fan Control
      29             :  * http://www.andigilog.com/downloads/aSC7611_70A05007.pdf
      30             :  * October 2006
      31             :  */
      32             : 
      33             : /* Temperature */
      34             : #define ANDL_NUM_TEMPS  3
      35             : static const struct {
      36             :         const char      *name;
      37             :         const uint8_t   mreg;
      38             :         const uint8_t   lreg;
      39             : } andl_temp[ANDL_NUM_TEMPS] = {
      40             :         { "External", 0x25, 0x10 },
      41             :         { "Internal", 0x26, 0x15 },
      42             :         { "External", 0x27, 0x0e }
      43             : };
      44             : 
      45             : /* Voltage */
      46             : #define ANDL_NUM_VOLTS  5
      47             : static const struct {
      48             :         const char      *name;
      49             :         const short     nominal;
      50             :         const uint8_t   mreg;
      51             : } andl_volt[ANDL_NUM_VOLTS] = {
      52             :         { "+2.5V", 2500, 0x20 },
      53             :         { "Vccp", 2250, 0x21 },
      54             :         { "+3.3V", 3300, 0x22 },
      55             :         { "+5V", 5000, 0x23 },
      56             :         { "+12V", 12000, 0x24 }
      57             : };
      58             : 
      59             : /* Fan */
      60             : #define ANDL_NUM_TACHS  4
      61             : #define ANDL_TACH_START 0x28
      62             : 
      63             : #define ANDL_NUM_TOTAL  (ANDL_NUM_TEMPS + ANDL_NUM_VOLTS + ANDL_NUM_TACHS)
      64             : 
      65             : struct andl_softc {
      66             :         struct device   sc_dev;
      67             :         i2c_tag_t       sc_tag;
      68             :         i2c_addr_t      sc_addr;
      69             : 
      70             :         struct ksensor  sc_sensors[ANDL_NUM_TOTAL];
      71             :         struct ksensordev sc_sensordev;
      72             : };
      73             : 
      74             : 
      75             : int     andl_match(struct device *, void *, void *);
      76             : void    andl_attach(struct device *, struct device *, void *);
      77             : void    andl_refresh(void *);
      78             : 
      79             : int     andl_refresh_temps(struct andl_softc *, struct ksensor *);
      80             : int     andl_refresh_volts(struct andl_softc *, struct ksensor *);
      81             : int     andl_refresh_tachs(struct andl_softc *, struct ksensor *);
      82             : 
      83             : uint8_t andl_readreg(struct andl_softc *, uint8_t);
      84             : void    andl_writereg(struct andl_softc *, uint8_t, uint8_t);
      85             : 
      86             : 
      87             : struct cfattach andl_ca = {
      88             :         sizeof(struct andl_softc), andl_match, andl_attach
      89             : };
      90             : 
      91             : struct cfdriver andl_cd = {
      92             :         NULL, "andl", DV_DULL
      93             : };
      94             : 
      95             : 
      96             : int
      97           0 : andl_match(struct device *parent, void *match, void *aux)
      98             : {
      99           0 :         struct i2c_attach_args *ia = aux;
     100             : 
     101           0 :         if (strcmp(ia->ia_name, "asc7611") == 0)
     102           0 :                 return 1;
     103           0 :         return 0;
     104           0 : }
     105             : 
     106             : void
     107           0 : andl_attach(struct device *parent, struct device *self, void *aux)
     108             : {
     109           0 :         struct andl_softc *sc = (struct andl_softc *)self;
     110           0 :         struct i2c_attach_args *ia = aux;
     111             :         int i, j;
     112             : 
     113           0 :         sc->sc_tag = ia->ia_tag;
     114           0 :         sc->sc_addr = ia->ia_addr;
     115             : 
     116           0 :         printf(": %s", ia->ia_name);
     117             : 
     118           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
     119             :             sizeof(sc->sc_sensordev.xname));
     120             : 
     121           0 :         for (i = 0; i < ANDL_NUM_TEMPS; i++) {
     122           0 :                 strlcpy(sc->sc_sensors[i].desc, andl_temp[i].name,
     123             :                     sizeof(sc->sc_sensors[i].desc));
     124           0 :                 sc->sc_sensors[i].type = SENSOR_TEMP;
     125             :         }
     126             : 
     127           0 :         for (j = i; i < j + ANDL_NUM_VOLTS; i++) {
     128           0 :                 strlcpy(sc->sc_sensors[i].desc, andl_volt[i - j].name,
     129             :                     sizeof(sc->sc_sensors[i].desc));
     130           0 :                 sc->sc_sensors[i].type = SENSOR_VOLTS_DC;
     131             :         }
     132             : 
     133           0 :         for (j = i + ANDL_NUM_TACHS; i < j; i++)
     134           0 :                 sc->sc_sensors[i].type = SENSOR_FANRPM;
     135             : 
     136           0 :         for (i = 0; i < j; i++)
     137           0 :                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
     138             : 
     139           0 :         if (sensor_task_register(sc, andl_refresh, 5) == NULL) {
     140           0 :                 printf(", unable to register update task\n");
     141           0 :                 return;
     142             :         }
     143             : 
     144           0 :         sensordev_install(&sc->sc_sensordev);
     145           0 :         printf("\n");
     146           0 : }
     147             : 
     148             : void
     149           0 : andl_refresh(void *arg)
     150             : {
     151           0 :         struct andl_softc *sc = arg;
     152           0 :         struct ksensor *s = sc->sc_sensors;
     153             : 
     154           0 :         iic_acquire_bus(sc->sc_tag, 0);
     155             : 
     156           0 :         s += andl_refresh_temps(sc, s);
     157           0 :         s += andl_refresh_volts(sc, s);
     158           0 :         s += andl_refresh_tachs(sc, s);
     159             : 
     160           0 :         iic_release_bus(sc->sc_tag, 0);
     161           0 : }
     162             : 
     163             : int
     164           0 : andl_refresh_temps(struct andl_softc *sc, struct ksensor *s)
     165             : {
     166             :         int i;
     167             : 
     168           0 :         for (i = 0; i < ANDL_NUM_TEMPS; i++) {
     169           0 :                 uint8_t m = andl_readreg(sc, andl_temp[i].mreg);
     170           0 :                 uint8_t l = andl_readreg(sc, andl_temp[i].lreg);
     171           0 :                 int32_t t = (m << 8 | l) >> (16 - 10);
     172             : 
     173           0 :                 if (t & 0x200)
     174           0 :                         t -= 0x400;
     175           0 :                 t *= 250;
     176           0 :                 if (t < -55000 || t > 125000) {
     177           0 :                         s[i].flags |= SENSOR_FINVALID;
     178           0 :                         s[i].value = 0;
     179           0 :                 } else {
     180           0 :                         s[i].value = t * 1000 + 273150000;
     181           0 :                         s[i].flags &= ~SENSOR_FINVALID;
     182             :                 }
     183             :         }
     184           0 :         return i;
     185             : }
     186             : 
     187             : int
     188           0 : andl_refresh_volts(struct andl_softc *sc, struct ksensor *s)
     189             : {
     190             :         int i;
     191             : 
     192           0 :         for (i = 0; i < ANDL_NUM_VOLTS; i++)
     193           0 :                 s[i].value = 1000ll * andl_readreg(sc, andl_volt[i].mreg) *
     194           0 :                     andl_volt[i].nominal / 0xc0;
     195           0 :         return i;
     196             : }
     197             : 
     198             : int
     199           0 : andl_refresh_tachs(struct andl_softc *sc, struct ksensor *s)
     200             : {
     201             :         int i;
     202             : 
     203           0 :         for (i = 0; i < ANDL_NUM_TACHS; i++) {
     204           0 :                 uint8_t l = andl_readreg(sc, ANDL_TACH_START + i * 2);
     205           0 :                 uint8_t m = andl_readreg(sc, ANDL_TACH_START + i * 2 + 1);
     206           0 :                 uint16_t b = m << 8 | l;
     207             : 
     208           0 :                 if (b >= 0xfffc || b == 0) {
     209           0 :                         s[i].flags |= SENSOR_FINVALID;
     210           0 :                         s[i].value = 0;
     211           0 :                 } else {
     212           0 :                         s[i].value = (90000 * 60) / b;
     213           0 :                         s[i].flags &= ~SENSOR_FINVALID;
     214             :                 }
     215             :         }
     216           0 :         return i;
     217             : }
     218             : 
     219             : uint8_t
     220           0 : andl_readreg(struct andl_softc *sc, uint8_t reg)
     221             : {
     222           0 :         uint8_t data;
     223             : 
     224           0 :         iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     225           0 :             sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
     226             : 
     227           0 :         return data;
     228           0 : }
     229             : 
     230             : void
     231           0 : andl_writereg(struct andl_softc *sc, uint8_t reg, uint8_t data)
     232             : {
     233           0 :         iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
     234           0 :             sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
     235           0 : }

Generated by: LCOV version 1.13