root/dev/i2c/lm87.c

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

DEFINITIONS

This source file includes following definitions.
  1. lmenv_match
  2. lmenv_attach
  3. lmenv_refresh

    1 /*      $OpenBSD: lm87.c,v 1.19 2007/06/24 05:34:35 dlg 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 lmenv_match(struct device *parent, void *match, void *aux)
   85 {
   86         struct i2c_attach_args *ia = aux;
   87 
   88         if (strcmp(ia->ia_name, "lm87") == 0 ||
   89             strcmp(ia->ia_name, "lm87cimt") == 0 ||
   90             strcmp(ia->ia_name, "adm9240") == 0 ||
   91             strcmp(ia->ia_name, "lm81") == 0 ||
   92             strcmp(ia->ia_name, "ds1780") == 0)
   93                 return (1);
   94         return (0);
   95 }
   96 
   97 void
   98 lmenv_attach(struct device *parent, struct device *self, void *aux)
   99 {
  100         struct lmenv_softc *sc = (struct lmenv_softc *)self;
  101         struct i2c_attach_args *ia = aux;
  102         u_int8_t cmd, data, data2, channel;
  103         int i;
  104 
  105         sc->sc_tag = ia->ia_tag;
  106         sc->sc_addr = ia->ia_addr;
  107 
  108         sc->sc_family = 87;
  109         if (strcmp(ia->ia_name, "lm81") == 0 ||
  110             strcmp(ia->ia_name, "adm9240") == 0 ||
  111             strcmp(ia->ia_name, "ds1780") == 0)
  112                 sc->sc_family = 81;
  113 
  114         iic_acquire_bus(sc->sc_tag, 0);
  115 
  116         cmd = LM87_REVISION;
  117         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  118             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  119                 iic_release_bus(sc->sc_tag, 0);
  120                 printf(": cannot read ID register\n");
  121                 return;
  122         }
  123         printf(": %s rev %x", ia->ia_name, data);
  124 
  125         cmd = LM87_FANDIV;
  126         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  127             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  128                 iic_release_bus(sc->sc_tag, 0);
  129                 printf(", cannot read Fan Divisor register\n");
  130                 return;
  131         }
  132         sc->sc_fan1_div = 1 << ((data >> 4) & 0x03);
  133         sc->sc_fan2_div = 1 << ((data >> 6) & 0x03);
  134 
  135         if (sc->sc_family == 87) {
  136                 cmd = LM87_CHANNEL;
  137                 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  138                     sc->sc_addr, &cmd, sizeof cmd, &channel,
  139                     sizeof channel, 0)) {
  140                         iic_release_bus(sc->sc_tag, 0);
  141                         printf(", cannot read Channel register\n");
  142                         return;
  143                 }
  144         }
  145 
  146         cmd = LM87_CONFIG1;
  147         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  148             sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  149                 iic_release_bus(sc->sc_tag, 0);
  150                 printf(", cannot read Configuration Register 1\n");
  151                 return;
  152         }
  153 
  154         /*
  155          * if chip is not running, try to start it.
  156          * if it is stalled doing an interrupt, unstall it
  157          */
  158         data2 = (data | LM87_CONFIG1_START);
  159         data2 = data2 & ~LM87_CONFIG1_INTCLR;
  160 
  161         if (data != data2) {
  162                 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
  163                     sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
  164                         iic_release_bus(sc->sc_tag, 0);
  165                         printf(", cannot write Configuration Register 1\n");
  166                         return;
  167                 }
  168                 printf(", starting scan");
  169         }
  170         iic_release_bus(sc->sc_tag, 0);
  171 
  172         /* Initialize sensor data. */
  173         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
  174             sizeof(sc->sc_sensordev.xname));
  175 
  176         sc->sc_sensor[LMENV_2_5V].type = SENSOR_VOLTS_DC;
  177         strlcpy(sc->sc_sensor[LMENV_2_5V].desc, "+2.5Vin",
  178             sizeof(sc->sc_sensor[LMENV_2_5V].desc));
  179 
  180         sc->sc_sensor[LMENV_VCCP1].type = SENSOR_VOLTS_DC;
  181         strlcpy(sc->sc_sensor[LMENV_VCCP1].desc, "Vccp",
  182             sizeof(sc->sc_sensor[LMENV_VCCP1].desc));
  183 
  184         sc->sc_sensor[LMENV_VCC].type = SENSOR_VOLTS_DC;
  185         strlcpy(sc->sc_sensor[LMENV_VCC].desc, "+Vcc",
  186             sizeof(sc->sc_sensor[LMENV_VCC].desc));
  187 
  188         sc->sc_sensor[LMENV_5V].type = SENSOR_VOLTS_DC;
  189         strlcpy(sc->sc_sensor[LMENV_5V].desc, "+5Vin/Vcc",
  190             sizeof(sc->sc_sensor[LMENV_5V].desc));
  191 
  192         sc->sc_sensor[LMENV_12V].type = SENSOR_VOLTS_DC;
  193         strlcpy(sc->sc_sensor[LMENV_12V].desc, "+12Vin",
  194             sizeof(sc->sc_sensor[LMENV_12V].desc));
  195 
  196         sc->sc_sensor[LMENV_VCCP2].type = SENSOR_VOLTS_DC;
  197         strlcpy(sc->sc_sensor[LMENV_VCCP2].desc, "Vccp",
  198             sizeof(sc->sc_sensor[LMENV_VCCP2].desc));
  199 
  200         sc->sc_sensor[LMENV_EXT_TEMP].type = SENSOR_TEMP;
  201         strlcpy(sc->sc_sensor[LMENV_EXT_TEMP].desc, "External",
  202             sizeof(sc->sc_sensor[LMENV_EXT_TEMP].desc));
  203         if (sc->sc_family == 81)
  204                 sc->sc_sensor[LMENV_EXT_TEMP].flags |= SENSOR_FINVALID;
  205 
  206         sc->sc_sensor[LMENV_INT_TEMP].type = SENSOR_TEMP;
  207         strlcpy(sc->sc_sensor[LMENV_INT_TEMP].desc, "Internal",
  208             sizeof(sc->sc_sensor[LMENV_INT_TEMP].desc));
  209 
  210         if (channel & LM87_CHANNEL_AIN1) {
  211                 sc->sc_sensor[LMENV_FAN1].type = SENSOR_VOLTS_DC;
  212                 strlcpy(sc->sc_sensor[LMENV_FAN1].desc, "AIN1",
  213                     sizeof(sc->sc_sensor[LMENV_FAN1].desc));
  214         } else {
  215                 sc->sc_sensor[LMENV_FAN1].type = SENSOR_FANRPM;
  216         }
  217 
  218         if (channel & LM87_CHANNEL_AIN2) {
  219                 sc->sc_sensor[LMENV_FAN2].type = SENSOR_VOLTS_DC;
  220                 strlcpy(sc->sc_sensor[LMENV_FAN2].desc, "AIN2",
  221                     sizeof(sc->sc_sensor[LMENV_FAN2].desc));
  222         } else {
  223                 sc->sc_sensor[LMENV_FAN2].type = SENSOR_FANRPM;
  224         }
  225 
  226         if (sensor_task_register(sc, lmenv_refresh, 5) == NULL) {
  227                 printf(", unable to register update task\n");
  228                 return;
  229         }
  230 
  231         for (i = 0; i < LMENV_NUM_SENSORS; i++)
  232                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
  233         sensordev_install(&sc->sc_sensordev);
  234 
  235         printf("\n");
  236 }
  237 
  238 void
  239 lmenv_refresh(void *arg)
  240 {
  241         struct lmenv_softc *sc = arg;
  242         u_int8_t cmd, data;
  243         u_int tmp;
  244         int sensor;
  245 
  246         iic_acquire_bus(sc->sc_tag, 0);
  247 
  248         for (sensor = 0; sensor < LMENV_NUM_SENSORS; sensor++) {
  249                 cmd = LM87_2_5V + sensor;
  250                 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  251                     sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  252                         sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
  253                         continue;
  254                 }
  255 
  256                 sc->sc_sensor[sensor].flags &= ~SENSOR_FINVALID;
  257                 switch (sensor) {
  258                 case LMENV_2_5V:
  259                         sc->sc_sensor[sensor].value = 2500000 * data / 192;
  260                         break;
  261                 case LMENV_5V:
  262                         sc->sc_sensor[sensor].value = 5000000 * data / 192;
  263                         break;
  264                 case LMENV_12V:
  265                         sc->sc_sensor[sensor].value = 12000000 * data / 192;
  266                         break;
  267                 case LMENV_VCCP1:
  268                 case LMENV_VCCP2:
  269                         sc->sc_sensor[sensor].value = 2700000 * data / 192;
  270                         break;
  271                 case LMENV_VCC:
  272                         sc->sc_sensor[sensor].value = 3300000 * data / 192;
  273                         break;
  274                 case LMENV_EXT_TEMP:
  275                         if (sc->sc_family == 81) {
  276                                 sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
  277                                 break;          /* missing on LM81 */
  278                         }
  279                         /* FALLTHROUGH */
  280                 case LMENV_INT_TEMP:
  281                         if (data == 0x80)
  282                                 sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
  283                         else
  284                                 sc->sc_sensor[sensor].value =
  285                                     (int8_t)data * 1000000 + 273150000;
  286                         break;
  287                 case LMENV_FAN1:
  288                         if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
  289                                 sc->sc_sensor[sensor].value =
  290                                     1870000 * data / 192;
  291                                 break;
  292                         }
  293                         tmp = data * sc->sc_fan1_div;
  294                         if (tmp == 0)
  295                                 sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
  296                         else
  297                                 sc->sc_sensor[sensor].value = 1350000 / tmp;
  298                         break;
  299                 case LMENV_FAN2:
  300                         if (sc->sc_sensor[sensor].type == SENSOR_VOLTS_DC) {
  301                                 sc->sc_sensor[sensor].value =
  302                                     1870000 * data / 192;
  303                                 break;
  304                         }
  305                         tmp = data * sc->sc_fan2_div;
  306                         if (tmp == 0)
  307                                 sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
  308                         else
  309                                 sc->sc_sensor[sensor].value = 1350000 / tmp;
  310                         break;
  311                 default:
  312                         sc->sc_sensor[sensor].flags |= SENSOR_FINVALID;
  313                         break;
  314                 }
  315         }
  316 
  317         iic_release_bus(sc->sc_tag, 0);
  318 }

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