LCOV - code coverage report
Current view: top level - dev/i2c - w83795g.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 122 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: w83795g.c,v 1.1 2011/07/03 21:30:20 kettenis Exp $    */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2011 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             : /* Nuvoton W83795G Hardware Monitor */
      27             : 
      28             : #define NVT_BANKSELECT          0x00
      29             : #define NVT_CONFIG              0x01
      30             : #define  NVT_CONFIG_48          0x04
      31             : #define NVT_VOLT_CTRL1          0x02
      32             : #define NVT_VOLT_CTRL2          0x03
      33             : #define NVT_TEMP_CTRL1          0x04
      34             : #define NVT_TEMP_CTRL2          0x05
      35             : #define NVT_FANIN_CTRL1         0x06
      36             : #define NVT_FANIN_CTRL2         0x07
      37             : #define NVT_VSEN1               0x10
      38             : #define NVT_3VDD                0x1c
      39             : #define NVT_3VSB                0x1d
      40             : #define NVT_VBAT                0x1e
      41             : #define NVT_TR5                 0x1f
      42             : #define NVT_TR6                 0x20
      43             : #define NVT_TD1                 0x21
      44             : #define NVT_TD2                 0x22
      45             : #define NVT_TD3                 0x23
      46             : #define NVT_TD4                 0x24
      47             : #define NVT_FANIN1_COUNT        0x2e
      48             : #define NVT_VRLSB               0x3c
      49             : 
      50             : /* Voltage */
      51             : #define NVT_NUM_VOLTS   15
      52             : 
      53             : static const char *nvt_volt_desc[NVT_NUM_VOLTS] = {
      54             :         "", "", "", "", "", "", "", "", "", "", "",
      55             :         "VTT", "3VDD", "3VSB", "VBat"
      56             : };
      57             : 
      58             : /* Temperature */
      59             : #define NVT_NUM_TEMPS   6
      60             : #define NVT_NUM_TR      2
      61             : #define NVT_NUM_TD      4
      62             : 
      63             : /* Fan */
      64             : #define NVT_NUM_FANS    14
      65             : 
      66             : #define NVT_NUM_SENSORS (NVT_NUM_VOLTS + NVT_NUM_TEMPS + NVT_NUM_FANS)
      67             : 
      68             : struct nvt_softc {
      69             :         struct device   sc_dev;
      70             :         i2c_tag_t       sc_tag;
      71             :         i2c_addr_t      sc_addr;
      72             : 
      73             :         uint16_t        sc_vctrl;
      74             :         uint16_t        sc_tctrl1, sc_tctrl2;
      75             :         uint16_t        sc_fctrl;
      76             : 
      77             :         struct ksensor  sc_sensors[NVT_NUM_SENSORS];
      78             :         struct ksensordev sc_sensordev;
      79             : };
      80             : 
      81             : 
      82             : int     nvt_match(struct device *, void *, void *);
      83             : void    nvt_attach(struct device *, struct device *, void *);
      84             : void    nvt_refresh(void *);
      85             : 
      86             : void    nvt_refresh_volts(struct nvt_softc *);
      87             : void    nvt_refresh_temps(struct nvt_softc *);
      88             : void    nvt_refresh_fans(struct nvt_softc *);
      89             : 
      90             : uint8_t nvt_readreg(struct nvt_softc *, uint8_t);
      91             : void    nvt_writereg(struct nvt_softc *, uint8_t, uint8_t);
      92             : 
      93             : 
      94             : struct cfattach nvt_ca = {
      95             :         sizeof(struct nvt_softc), nvt_match, nvt_attach
      96             : };
      97             : 
      98             : struct cfdriver nvt_cd = {
      99             :         NULL, "nvt", DV_DULL
     100             : };
     101             : 
     102             : 
     103             : int
     104           0 : nvt_match(struct device *parent, void *match, void *aux)
     105             : {
     106           0 :         struct i2c_attach_args *ia = aux;
     107             : 
     108           0 :         if (strcmp(ia->ia_name, "w83795g") == 0)
     109           0 :                 return (1);
     110           0 :         return (0);
     111           0 : }
     112             : 
     113             : void
     114           0 : nvt_attach(struct device *parent, struct device *self, void *aux)
     115             : {
     116           0 :         struct nvt_softc *sc = (struct nvt_softc *)self;
     117           0 :         struct i2c_attach_args *ia = aux;
     118             :         uint8_t cfg, vctrl1, vctrl2;
     119             :         uint8_t tctrl1, tctrl2, fctrl1, fctrl2;
     120             :         int i, j;
     121             : 
     122           0 :         sc->sc_tag = ia->ia_tag;
     123           0 :         sc->sc_addr = ia->ia_addr;
     124             : 
     125           0 :         cfg = nvt_readreg(sc, NVT_CONFIG);
     126           0 :         if (cfg & NVT_CONFIG_48)
     127           0 :                 printf(": W83795ADG");
     128             :         else
     129           0 :                 printf(": W83795G");
     130             : 
     131           0 :         vctrl1 = nvt_readreg(sc, NVT_VOLT_CTRL1);
     132           0 :         vctrl2 = nvt_readreg(sc, NVT_VOLT_CTRL2);
     133           0 :         tctrl1 = nvt_readreg(sc, NVT_TEMP_CTRL1);
     134           0 :         tctrl2 = nvt_readreg(sc, NVT_TEMP_CTRL2);
     135           0 :         fctrl1 = nvt_readreg(sc, NVT_FANIN_CTRL1);
     136           0 :         fctrl2 = nvt_readreg(sc, NVT_FANIN_CTRL2);
     137             : 
     138           0 :         sc->sc_vctrl = vctrl2 << 8 | vctrl1;
     139           0 :         sc->sc_tctrl1 = tctrl1;
     140           0 :         sc->sc_tctrl2 = tctrl2;
     141           0 :         sc->sc_fctrl = fctrl2 << 8 | fctrl1;
     142             : 
     143           0 :         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
     144             :             sizeof(sc->sc_sensordev.xname));
     145             : 
     146           0 :         for (i = 0; i < NVT_NUM_VOLTS; i++) {
     147           0 :                 strlcpy(sc->sc_sensors[i].desc, nvt_volt_desc[i],
     148             :                     sizeof(sc->sc_sensors[i].desc));
     149           0 :                 sc->sc_sensors[i].type = SENSOR_VOLTS_DC;
     150             :         }
     151             : 
     152           0 :         for (j = i + NVT_NUM_TEMPS; i < j; i++)
     153           0 :                 sc->sc_sensors[i].type = SENSOR_TEMP;
     154             : 
     155           0 :         for (j = i + NVT_NUM_FANS; i < j; i++)
     156           0 :                 sc->sc_sensors[i].type = SENSOR_FANRPM;
     157             : 
     158           0 :         for (i = 0; i < NVT_NUM_VOLTS + NVT_NUM_TEMPS + NVT_NUM_FANS; i++)
     159           0 :                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
     160             : 
     161           0 :         if (sensor_task_register(sc, nvt_refresh, 5) == NULL) {
     162           0 :                 printf(", unable to register update task\n");
     163           0 :                 return;
     164             :         }
     165             : 
     166           0 :         sensordev_install(&sc->sc_sensordev);
     167           0 :         printf("\n");
     168           0 : }
     169             : 
     170             : void
     171           0 : nvt_refresh(void *arg)
     172             : {
     173           0 :         struct nvt_softc *sc = arg;
     174             :         uint8_t bsr;
     175             : 
     176           0 :         iic_acquire_bus(sc->sc_tag, 0);
     177             : 
     178           0 :         bsr = nvt_readreg(sc, NVT_BANKSELECT);
     179           0 :         if ((bsr & 0x07) != 0x00)
     180           0 :                 nvt_writereg(sc, NVT_BANKSELECT, bsr & 0xf8);
     181             : 
     182           0 :         nvt_refresh_volts(sc);
     183           0 :         nvt_refresh_temps(sc);
     184           0 :         nvt_refresh_fans(sc);
     185             : 
     186           0 :         if ((bsr & 0x07) != 0x00)
     187           0 :                 nvt_writereg(sc, NVT_BANKSELECT, bsr);
     188             : 
     189           0 :         iic_release_bus(sc->sc_tag, 0);
     190           0 : }
     191             : 
     192             : void
     193           0 : nvt_refresh_volts(struct nvt_softc *sc)
     194             : {
     195           0 :         struct ksensor *s = &sc->sc_sensors[0];
     196             :         uint8_t vrlsb, data;
     197             :         int i, reg;
     198             : 
     199           0 :         for (i = 0; i < NVT_NUM_VOLTS; i++) {
     200           0 :                 if ((sc->sc_vctrl & (1 << i)) == 0) {
     201           0 :                         s[i].flags |= SENSOR_FINVALID;
     202           0 :                         s[i].value = 0;
     203           0 :                         continue;
     204             :                 }
     205             : 
     206           0 :                 reg = NVT_VSEN1 + i;
     207           0 :                 data = nvt_readreg(sc, reg);
     208           0 :                 vrlsb = nvt_readreg(sc, NVT_VRLSB);
     209           0 :                 if (reg != NVT_3VDD && reg != NVT_3VSB && reg != NVT_VBAT)
     210           0 :                         s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 2000;
     211             :                 else
     212           0 :                         s[i].value = 10000000 - ((data << 3) | (vrlsb >> 6)) * 6000;
     213           0 :                 s[i].flags &= ~SENSOR_FINVALID;
     214           0 :         }
     215           0 : }
     216             : 
     217             : void
     218           0 : nvt_refresh_temps(struct nvt_softc *sc)
     219             : {
     220           0 :         struct ksensor *s = &sc->sc_sensors[NVT_NUM_VOLTS];
     221             :         uint8_t vrlsb;
     222             :         int8_t data;
     223             :         int i;
     224             : 
     225           0 :         for (i = 0; i < NVT_NUM_TEMPS; i++) {
     226           0 :                 if (i < NVT_NUM_TR
     227           0 :                     && (sc->sc_tctrl1 & (1 << (2 * i))) == 0) {
     228           0 :                         s[i].flags |= SENSOR_FINVALID;
     229           0 :                         s[i].value = 0;
     230           0 :                         continue;
     231             :                 }
     232             : 
     233           0 :                 if (i >= NVT_NUM_TR
     234           0 :                     && (sc->sc_tctrl2 & (1 << (2 * (i - NVT_NUM_TR)))) == 0) {
     235           0 :                         s[i].flags |= SENSOR_FINVALID;
     236           0 :                         s[i].value = 0;
     237           0 :                         continue;
     238             :                 }
     239             : 
     240           0 :                 data = nvt_readreg(sc, NVT_TR5 + i);
     241           0 :                 vrlsb = nvt_readreg(sc, NVT_VRLSB);
     242           0 :                 if (data == -128 && (vrlsb >> 6) == 0) {
     243           0 :                         s[i].flags |= SENSOR_FINVALID;
     244           0 :                         s[i].value = 0;
     245           0 :                         continue;
     246             :                 }
     247           0 :                 s[i].value = data * 1000000 + (vrlsb >> 6) * 250000;
     248           0 :                 s[i].value += 273150000;
     249           0 :                 s[i].flags &= ~SENSOR_FINVALID;
     250           0 :         }
     251           0 : }
     252             : 
     253             : void
     254           0 : nvt_refresh_fans(struct nvt_softc *sc)
     255             : {
     256           0 :         struct ksensor *s = &sc->sc_sensors[NVT_NUM_VOLTS + NVT_NUM_TEMPS];
     257             :         uint8_t data, vrlsb;
     258             :         uint16_t count;
     259             :         int i;
     260             : 
     261           0 :         for (i = 0; i < NVT_NUM_FANS; i++) {
     262           0 :                 if ((sc->sc_fctrl & (1 << i)) == 0) {
     263           0 :                         s[i].flags |= SENSOR_FINVALID;
     264           0 :                         s[i].value = 0;
     265           0 :                         continue;
     266             :                 }
     267             : 
     268           0 :                 data = nvt_readreg(sc, NVT_FANIN1_COUNT + i);
     269           0 :                 vrlsb = nvt_readreg(sc, NVT_VRLSB);
     270           0 :                 count = (data << 4) + (vrlsb >> 4);
     271           0 :                 if (count == 0) {
     272           0 :                         s[i].flags |= SENSOR_FINVALID;
     273           0 :                         s[i].value = 0;
     274           0 :                         continue;
     275             :                 }
     276           0 :                 s[i].value = 1350000 / (count * 2);
     277           0 :                 s[i].flags &= ~SENSOR_FINVALID;
     278           0 :         }
     279           0 : }
     280             : 
     281             : uint8_t
     282           0 : nvt_readreg(struct nvt_softc *sc, uint8_t reg)
     283             : {
     284           0 :         uint8_t data;
     285             : 
     286           0 :         iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
     287           0 :             sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
     288             : 
     289           0 :         return data;
     290           0 : }
     291             : 
     292             : void
     293           0 : nvt_writereg(struct nvt_softc *sc, uint8_t reg, uint8_t data)
     294             : {
     295           0 :         iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
     296           0 :             sc->sc_addr, &reg, sizeof reg, &data, sizeof data, 0);
     297           0 : }

Generated by: LCOV version 1.13