root/dev/i2c/gl518sm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. glenv_match
  2. glenv_attach
  3. glenv_refresh

    1 /*      $OpenBSD: gl518sm.c,v 1.6 2007/06/24 05:34:35 dlg Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2006 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 /* GL518SM registers */
   27 #define GL518SM_CHIPID          0x00
   28 #define GL518SM_REVISION        0x01
   29 #define GL518SM_VENDORID        0x02
   30 #define GL518SM_CONFIG          0x03
   31 #define  GL518SM_CONFIG_START           0x40
   32 #define  GL518SM_CONFIG_CLEARST         0x20
   33 #define  GL518SM_CONFIG_NOFAN2          0x10
   34 #define GL518SM_TEMP            0x04
   35 #define GL518SM_TEMP_OVER       0x05
   36 #define GL518SM_TEMP_HYST       0x06
   37 #define GL518SM_FAN_COUNT       0x07
   38 #define GL518SM_FAN_LIMIT       0x08
   39 #define GL518SM_VIN1_LIMIT      0x09
   40 #define GL518SM_VIN2_LIMIT      0x0a
   41 #define GL518SM_VIN3_LIMIT      0x0b
   42 #define GL518SM_VDD_LIMIT       0x0c
   43 #define GL518SM_VOLTMETER       0x0d
   44 #define GL518SM_MISC            0x0f
   45 #define GL518SM_ALARM           0x10
   46 #define GL518SM_MASK            0x11
   47 #define GL518SM_INTSTAT         0x12
   48 
   49 /* Sensors */
   50 #define GLENV_VIN3              0
   51 #define GLENV_TEMP              1
   52 #define GLENV_FAN1              2
   53 #define GLENV_FAN2              3
   54 #define GLENV_NUM_SENSORS       4
   55 
   56 struct glenv_softc {
   57         struct device sc_dev;
   58 
   59         i2c_tag_t sc_tag;
   60         i2c_addr_t sc_addr;
   61 
   62         struct ksensor sc_sensor[GLENV_NUM_SENSORS];
   63         struct ksensordev sc_sensordev;
   64         int     sc_fan1_div, sc_fan2_div;
   65 };
   66 
   67 int     glenv_match(struct device *, void *, void *);
   68 void    glenv_attach(struct device *, struct device *, void *);
   69 
   70 void    glenv_refresh(void *);
   71 
   72 struct cfattach glenv_ca = {
   73         sizeof(struct glenv_softc), glenv_match, glenv_attach
   74 };
   75 
   76 struct cfdriver glenv_cd = {
   77         NULL, "glenv", DV_DULL
   78 };
   79 
   80 int
   81 glenv_match(struct device *parent, void *match, void *aux)
   82 {
   83         struct i2c_attach_args *ia = aux;
   84 
   85         if (strcmp(ia->ia_name, "gl518sm") == 0)
   86                 return (1);
   87         return (0);
   88 }
   89 
   90 void
   91 glenv_attach(struct device *parent, struct device *self, void *aux)
   92 {
   93         struct glenv_softc *sc = (struct glenv_softc *)self;
   94         struct i2c_attach_args *ia = aux;
   95         u_int8_t cmd, data;
   96         int i;
   97 
   98         sc->sc_tag = ia->ia_tag;
   99         sc->sc_addr = ia->ia_addr;
  100 
  101         iic_acquire_bus(sc->sc_tag, 0);
  102 
  103         cmd = GL518SM_REVISION;
  104         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  105             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  106                 iic_release_bus(sc->sc_tag, 0);
  107                 printf(": cannot read revision register\n");
  108                 return;
  109         }
  110         
  111         printf(": GL518SM rev 0x%02x", data);
  112 
  113         cmd = GL518SM_MISC;
  114         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  115             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  116                 iic_release_bus(sc->sc_tag, 0);
  117                 printf(", cannot read misc register\n");
  118                 return;
  119         }
  120         sc->sc_fan1_div = 1 << ((data >> 6) & 0x03);
  121         sc->sc_fan2_div = 1 << ((data >> 4) & 0x03);
  122 
  123         cmd = GL518SM_CONFIG;
  124         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  125             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  126                 iic_release_bus(sc->sc_tag, 0);
  127                 printf(", cannot read configuration register\n");
  128                 return;
  129         }
  130         if (data & GL518SM_CONFIG_NOFAN2)
  131                 sc->sc_fan2_div = 0;
  132 
  133         /* Start monitoring and clear interrupt status. */
  134         data = (data | GL518SM_CONFIG_START | GL518SM_CONFIG_CLEARST);
  135         if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
  136             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  137                         iic_release_bus(sc->sc_tag, 0);
  138                         printf(", cannot write configuration register\n");
  139                         return;
  140         }
  141 
  142         iic_release_bus(sc->sc_tag, 0);
  143 
  144         /* Initialize sensor data. */
  145         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
  146             sizeof(sc->sc_sensordev.xname));
  147 
  148         sc->sc_sensor[GLENV_VIN3].type = SENSOR_VOLTS_DC;
  149 
  150         sc->sc_sensor[GLENV_TEMP].type = SENSOR_TEMP;
  151 
  152         sc->sc_sensor[GLENV_FAN1].type = SENSOR_FANRPM;
  153 
  154         sc->sc_sensor[GLENV_FAN2].type = SENSOR_FANRPM;
  155         if (sc->sc_fan2_div == -1)
  156                 sc->sc_sensor[GLENV_FAN2].flags |= SENSOR_FINVALID;
  157 
  158         if (sensor_task_register(sc, glenv_refresh, 5) == NULL) {
  159                 printf(", unable to register update task\n");
  160                 return;
  161         }
  162 
  163         for (i = 0; i < GLENV_NUM_SENSORS; i++)
  164                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
  165         sensordev_install(&sc->sc_sensordev);
  166 
  167         printf("\n");
  168 }
  169 
  170 void
  171 glenv_refresh(void *arg)
  172 {
  173         struct glenv_softc *sc = arg;
  174         u_int8_t cmd, data, data2[2];
  175         u_int tmp;
  176 
  177         iic_acquire_bus(sc->sc_tag, 0);
  178 
  179         cmd = GL518SM_VOLTMETER;
  180         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  181             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  182                 sc->sc_sensor[GLENV_VIN3].flags |= SENSOR_FINVALID;
  183         } else {
  184                 sc->sc_sensor[GLENV_VIN3].flags &= ~SENSOR_FINVALID;
  185                 sc->sc_sensor[GLENV_VIN3].value = data * 19000;
  186         }
  187         
  188         cmd = GL518SM_TEMP;
  189         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  190             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  191                 sc->sc_sensor[GLENV_TEMP].flags |= SENSOR_FINVALID;
  192         } else {
  193                 sc->sc_sensor[GLENV_TEMP].flags &= ~SENSOR_FINVALID;
  194                 sc->sc_sensor[GLENV_TEMP].value =
  195                         (data - 119) * 1000000 + 273150000;
  196         }
  197 
  198         cmd = GL518SM_FAN_COUNT;
  199         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  200             sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
  201                 sc->sc_sensor[GLENV_FAN1].flags |= SENSOR_FINVALID;
  202                 sc->sc_sensor[GLENV_FAN2].flags |= SENSOR_FINVALID;
  203         } else {
  204                 sc->sc_sensor[GLENV_FAN1].flags &= ~SENSOR_FINVALID;
  205                 tmp = data2[0] * sc->sc_fan1_div * 2;
  206                 if (tmp == 0)
  207                         sc->sc_sensor[GLENV_FAN1].flags |= SENSOR_FINVALID;
  208                 else
  209                         sc->sc_sensor[GLENV_FAN1].value = 960000 / tmp;
  210 
  211                 sc->sc_sensor[GLENV_FAN2].flags &= ~SENSOR_FINVALID;
  212                 tmp = data2[1] * sc->sc_fan2_div * 2;
  213                 if (tmp == 0)
  214                         sc->sc_sensor[GLENV_FAN2].flags |= SENSOR_FINVALID;
  215                 else
  216                         sc->sc_sensor[GLENV_FAN2].value = 960000 / tmp;
  217         }
  218 
  219         iic_release_bus(sc->sc_tag, 0);
  220 }

/* [<][>][^][v][top][bottom][index][help] */