LCOV - code coverage report
Current view: top level - dev/i2c - w83793g.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 116 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: w83793g.c,v 1.5 2009/01/26 15:07:49 kettenis Exp $    */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2007 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             : /* Winbond W83793G Hardware Monitor */
      27             : 
      28             : #define WB_BANKSELECT   0x00
      29             : 
      30             : /* Voltage */
      31             : #define WB_NUM_VOLTS    10
      32             : 
      33             : static const char *wb_volt_desc[WB_NUM_VOLTS] = {
      34             :         "VCore", "VCore", "VTT",
      35             :         "", "", "3.3V", "12V", "5VDD", "5VSB", "VBat"
      36             : };
      37             : 
      38             : #define WB_VCOREA       0x10
      39             : #define WB_VCOREB       0x11
      40             : #define WB_VTT          0x12
      41             : #define WB_VLOW         0x1b
      42             : 
      43             : #define WB_VSENS1       0x14
      44             : #define WB_VSENS2       0x15
      45             : #define WB_3VSEN        0x16
      46             : #define WB_12VSEN       0x17
      47             : #define WB_5VDD         0x18
      48             : #define WB_5VSB         0x19
      49             : #define WB_VBAT         0x1a
      50             : 
      51             : /* Temperature */
      52             : #define WB_NUM_TEMPS    6
      53             : 
      54             : #define WB_TD_COUNT     4
      55             : #define WB_TD_START     0x1c
      56             : #define WB_TDLOW        0x22
      57             : 
      58             : #define WB_TR_COUNT     2
      59             : #define WB_TR_START     0x20
      60             : 
      61             : /* Fan */
      62             : #define WB_NUM_FANS     12
      63             : #define WB_FAN_START    0x23
      64             : 
      65             : 
      66             : struct wbng_softc {
      67             :         struct device   sc_dev;
      68             :         i2c_tag_t       sc_tag;
      69             :         i2c_addr_t      sc_addr;
      70             : 
      71             :         struct ksensor  sc_sensors[WB_NUM_VOLTS + WB_NUM_TEMPS + WB_NUM_FANS];
      72             :         struct ksensordev sc_sensordev;
      73             : };
      74             : 
      75             : 
      76             : int     wbng_match(struct device *, void *, void *);
      77             : void    wbng_attach(struct device *, struct device *, void *);
      78             : void    wbng_refresh(void *);
      79             : 
      80             : void    wbng_refresh_volts(struct wbng_softc *);
      81             : void    wbng_refresh_temps(struct wbng_softc *);
      82             : void    wbng_refresh_fans(struct wbng_softc *);
      83             : 
      84             : uint8_t wbng_readreg(struct wbng_softc *, uint8_t);
      85             : void    wbng_writereg(struct wbng_softc *, uint8_t, uint8_t);
      86             : 
      87             : 
      88             : struct cfattach wbng_ca = {
      89             :         sizeof(struct wbng_softc), wbng_match, wbng_attach
      90             : };
      91             : 
      92             : struct cfdriver wbng_cd = {
      93             :         NULL, "wbng", DV_DULL
      94             : };
      95             : 
      96             : 
      97             : int
      98           0 : wbng_match(struct device *parent, void *match, void *aux)
      99             : {
     100           0 :         struct i2c_attach_args *ia = aux;
     101             : 
     102           0 :         if (strcmp(ia->ia_name, "w83793g") == 0)
     103           0 :                 return 1;
     104           0 :         return 0;
     105           0 : }
     106             : 
     107             : void
     108           0 : wbng_attach(struct device *parent, struct device *self, void *aux)
     109             : {
     110           0 :         struct wbng_softc *sc = (struct wbng_softc *)self;
     111           0 :         struct i2c_attach_args *ia = aux;
     112             :         int i, j;
     113             : 
     114           0 :         sc->sc_tag = ia->ia_tag;
     115           0 :         sc->sc_addr = ia->ia_addr;
     116             : 
     117           0 :         printf(": %s", ia->ia_name);
     118             : 
     119           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
     120             :             sizeof(sc->sc_sensordev.xname));
     121             : 
     122           0 :         for (i = 0; i < WB_NUM_VOLTS; i++) {
     123           0 :                 strlcpy(sc->sc_sensors[i].desc, wb_volt_desc[i],
     124             :                     sizeof(sc->sc_sensors[i].desc));
     125           0 :                 sc->sc_sensors[i].type = SENSOR_VOLTS_DC;
     126             :         }
     127             : 
     128           0 :         for (j = i + WB_NUM_TEMPS; i < j; i++)
     129           0 :                 sc->sc_sensors[i].type = SENSOR_TEMP;
     130             : 
     131           0 :         for (j = i + WB_NUM_FANS; i < j; i++)
     132           0 :                 sc->sc_sensors[i].type = SENSOR_FANRPM;
     133             : 
     134           0 :         for (i = 0; i < WB_NUM_VOLTS + WB_NUM_TEMPS + WB_NUM_FANS; i++)
     135           0 :                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
     136             : 
     137           0 :         if (sensor_task_register(sc, wbng_refresh, 5) == NULL) {
     138           0 :                 printf(", unable to register update task\n");
     139           0 :                 return;
     140             :         }
     141             : 
     142           0 :         sensordev_install(&sc->sc_sensordev);
     143           0 :         printf("\n");
     144           0 : }
     145             : 
     146             : void
     147           0 : wbng_refresh(void *arg)
     148             : {
     149           0 :         struct wbng_softc *sc = arg;
     150             :         uint8_t bsr;
     151             : 
     152           0 :         iic_acquire_bus(sc->sc_tag, 0);
     153             : 
     154           0 :         bsr = wbng_readreg(sc, WB_BANKSELECT);
     155           0 :         if ((bsr & 0x07) != 0x0)
     156           0 :                 wbng_writereg(sc, WB_BANKSELECT, bsr & 0xf8);
     157             : 
     158           0 :         wbng_refresh_volts(sc);
     159           0 :         wbng_refresh_temps(sc);
     160           0 :         wbng_refresh_fans(sc);
     161             : 
     162           0 :         if ((bsr & 0x07) != 0x0)
     163           0 :                 wbng_writereg(sc, WB_BANKSELECT, bsr);
     164             : 
     165           0 :         iic_release_bus(sc->sc_tag, 0);
     166           0 : }
     167             : 
     168             : void
     169           0 : wbng_refresh_volts(struct wbng_softc *sc)
     170             : {
     171           0 :         struct ksensor *s = &sc->sc_sensors[0];
     172             :         uint8_t vlow, data;
     173             : 
     174             :         /* high precision voltage sensors */
     175             : 
     176           0 :         vlow = wbng_readreg(sc, WB_VLOW);
     177             : 
     178           0 :         data = wbng_readreg(sc, WB_VCOREA);
     179           0 :         s[0].value = ((data << 3) | (((vlow & 0x03)) << 1)) * 1000;
     180             : 
     181           0 :         data = wbng_readreg(sc, WB_VCOREB);
     182           0 :         s[1].value = ((data << 3) | (((vlow & 0x0c) >> 2) << 1)) * 1000;
     183             : 
     184           0 :         data = wbng_readreg(sc, WB_VTT);
     185           0 :         s[2].value = ((data << 3) | (((vlow & 0x30) >> 4) << 1)) * 1000;
     186             : 
     187             :         /* low precision voltage sensors */
     188             : 
     189           0 :         data = wbng_readreg(sc, WB_VSENS1);
     190           0 :         s[3].value = (data << 4) * 1000;
     191             : 
     192           0 :         data = wbng_readreg(sc, WB_VSENS2);
     193           0 :         s[4].value = (data << 4) * 1000;
     194             : 
     195           0 :         data = wbng_readreg(sc, WB_3VSEN);
     196           0 :         s[5].value = (data << 4) * 1000;
     197             : 
     198           0 :         data = wbng_readreg(sc, WB_12VSEN);
     199           0 :         s[6].value = (data << 4) * 6100;  /*XXX, the factor is a guess */
     200             : 
     201           0 :         data = wbng_readreg(sc, WB_5VDD);
     202           0 :         s[7].value = (data << 4) * 1500 + 150000;
     203             : 
     204           0 :         data = wbng_readreg(sc, WB_5VSB);
     205           0 :         s[8].value = (data << 4) * 1500 + 150000;
     206             : 
     207           0 :         data = wbng_readreg(sc, WB_VBAT);
     208           0 :         s[9].value = (data << 4) * 1000;
     209           0 : }
     210             : 
     211             : void
     212           0 : wbng_refresh_temps(struct wbng_softc *sc)
     213             : {
     214           0 :         struct ksensor *s = &sc->sc_sensors[WB_NUM_VOLTS];
     215             :         int data, i;
     216             :         uint8_t tdlow, low;
     217             : 
     218             :         /* high precision temperature sensors */
     219           0 :         tdlow = wbng_readreg(sc, WB_TDLOW);
     220           0 :         for (i = 0; i < WB_TD_COUNT; i++) {
     221           0 :                 data = wbng_readreg(sc, WB_TD_START + i);
     222             :                 /*
     223             :                  * XXX: datasheet says nothing about acceptable values,
     224             :                  * let's consider only values between -55 degC and +125 degC.
     225             :                  */
     226           0 :                 if (data > 0x7f && data < 0xc9) {
     227           0 :                         s[i].flags |= SENSOR_FINVALID;
     228           0 :                         s[i].value = 0;
     229           0 :                         continue;
     230             :                 }
     231           0 :                 if (data & 0x80)
     232           0 :                         data -= 0x100;
     233           0 :                 low = (tdlow & (0x03 << (i * 2))) >> (i * 2);
     234           0 :                 s[i].value = data * 1000000 + low * 250000 + 273150000;
     235           0 :                 s[i].flags &= ~SENSOR_FINVALID;
     236           0 :         }
     237           0 :         s += i;
     238             : 
     239             :         /* low precision temperature sensors */
     240           0 :         for (i = 0; i < WB_TR_COUNT; i++) {
     241           0 :                 data = wbng_readreg(sc, WB_TR_START + i);
     242             :                 /*
     243             :                  * XXX: datasheet says nothing about acceptable values,
     244             :                  * let's consider only values between -55 degC and +125 degC.
     245             :                  */
     246           0 :                 if (data > 0x7f && data < 0xc9) {
     247           0 :                         s[i].flags |= SENSOR_FINVALID;
     248           0 :                         s[i].value = 0;
     249           0 :                         continue;
     250             :                 }
     251           0 :                 if (data & 0x80)
     252           0 :                         data -= 0x100;
     253           0 :                 s[i].value = data * 1000000 + 273150000;
     254           0 :                 s[i].flags &= ~SENSOR_FINVALID;
     255           0 :         }
     256           0 : }
     257             : 
     258             : void
     259           0 : wbng_refresh_fans(struct wbng_softc *sc)
     260             : {
     261           0 :         struct ksensor *s = &sc->sc_sensors[WB_NUM_VOLTS + WB_NUM_TEMPS];
     262             :         int i;
     263             : 
     264           0 :         for (i = 0; i < WB_NUM_FANS; i++) {
     265           0 :                 uint8_t h = wbng_readreg(sc, WB_FAN_START + i * 2);
     266           0 :                 uint8_t l = wbng_readreg(sc, WB_FAN_START + i * 2 + 1);
     267           0 :                 uint16_t b = h << 8 | l;
     268             : 
     269           0 :                 if (b >= 0x0fff || b == 0x0f00 || b == 0x0000) {
     270           0 :                         s[i].flags |= SENSOR_FINVALID;
     271           0 :                         s[i].value = 0;
     272           0 :                 } else {
     273           0 :                         s[i].flags &= ~SENSOR_FINVALID;
     274           0 :                         s[i].value = 1350000 / b;
     275             :                 }
     276             :         }
     277           0 : }
     278             : 
     279             : uint8_t
     280           0 : wbng_readreg(struct wbng_softc *sc, uint8_t reg)
     281             : {
     282           0 :         uint8_t data;
     283             : 
     284           0 :         iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     285           0 :             sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
     286             : 
     287           0 :         return data;
     288           0 : }
     289             : 
     290             : void
     291           0 : wbng_writereg(struct wbng_softc *sc, uint8_t reg, uint8_t data)
     292             : {
     293           0 :         iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
     294           0 :             sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
     295           0 : }

Generated by: LCOV version 1.13