root/dev/i2c/w83l784r.c

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

DEFINITIONS

This source file includes following definitions.
  1. wbenv_match
  2. wbenv_attach
  3. wbenv_setup_sensors
  4. wbenv_refresh
  5. w83l784r_refresh_volt
  6. w83l785r_refresh_volt
  7. wbenv_refresh_temp
  8. w83l784r_refresh_temp
  9. w83l784r_refresh_fanrpm
  10. w83l785r_refresh_fanrpm
  11. wbenv_readreg
  12. wbenv_writereg

    1 /*      $OpenBSD: w83l784r.c,v 1.12 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 /* W83L784R registers */
   27 #define W83L784R_VCORE          0x20
   28 #define W83L784R_VBAT           0x21
   29 #define W83L784R_3_3V           0x22
   30 #define W83L784R_VCC            0x23
   31 #define W83L784R_TEMP1          0x27
   32 #define W83L784R_FAN1           0x28
   33 #define W83L784R_FAN2           0x29
   34 #define W83L784R_CONFIG         0x40
   35 #define W83L784R_FANDIV         0x49
   36 #define W83L784R_T23ADDR        0x4b
   37 #define W83L784R_CHIPID         0x4e
   38 
   39 #define W83L784R_TEMP23         0x00
   40 
   41 /* W83L785R registers */
   42 #define W83L785R_2_5V           0x21
   43 #define W83L785R_1_5V           0x22
   44 #define W83L785R_VCC            0x23
   45 #define W83L785R_TEMP2          0x26
   46 #define W83L785R_FANDIV         0x47
   47 
   48 /* Chip IDs */
   49 #define WBENV_CHIPID_W83L784R           0x50
   50 #define WBENV_CHIPID_W83L785R           0x60
   51 #define WBENV_CHIPID_W83L785TS_L        0x70
   52 
   53 #define WBENV_MAX_SENSORS  9
   54 
   55 /*
   56  * The W83L784R/W83L785R can measure voltages up to 4.096/2.048 V.
   57  * To measure higher voltages the input is attenuated with (external)
   58  * resistors.  So we have to convert the sensor values back to real
   59  * voltages by applying the appropriate resistor factor.
   60  */
   61 #define RFACT_NONE      10000
   62 #define RFACT(x, y)     (RFACT_NONE * ((x) + (y)) / (y))
   63 
   64 struct wbenv_softc;
   65 
   66 struct wbenv_sensor {
   67         char *desc;
   68         enum sensor_type type;
   69         u_int8_t reg;
   70         void (*refresh)(struct wbenv_softc *, int);
   71         int rfact;
   72 };
   73 
   74 struct wbenv_softc {
   75         struct device sc_dev;
   76 
   77         i2c_tag_t sc_tag;
   78         i2c_addr_t sc_addr[3];
   79         u_int8_t sc_chip_id;
   80 
   81         struct ksensor sc_sensors[WBENV_MAX_SENSORS];
   82         struct ksensordev sc_sensordev;
   83         struct wbenv_sensor *sc_wbenv_sensors;
   84         int sc_numsensors;
   85 };
   86 
   87 int     wbenv_match(struct device *, void *, void *);
   88 void    wbenv_attach(struct device *, struct device *, void *);
   89 
   90 void    wbenv_setup_sensors(struct wbenv_softc *, struct wbenv_sensor *);
   91 void    wbenv_refresh(void *);
   92 
   93 void    w83l784r_refresh_volt(struct wbenv_softc *, int);
   94 void    w83l785r_refresh_volt(struct wbenv_softc *, int);
   95 void    wbenv_refresh_temp(struct wbenv_softc *, int);
   96 void    w83l784r_refresh_temp(struct wbenv_softc *, int);
   97 void    w83l784r_refresh_fanrpm(struct wbenv_softc *, int);
   98 void    w83l785r_refresh_fanrpm(struct wbenv_softc *, int);
   99 
  100 u_int8_t wbenv_readreg(struct wbenv_softc *, u_int8_t);
  101 void    wbenv_writereg(struct wbenv_softc *, u_int8_t, u_int8_t);
  102 
  103 struct cfattach wbenv_ca = {
  104         sizeof(struct wbenv_softc), wbenv_match, wbenv_attach
  105 };
  106 
  107 struct cfdriver wbenv_cd = {
  108         NULL, "wbenv", DV_DULL
  109 };
  110 
  111 struct wbenv_sensor w83l784r_sensors[] =
  112 {
  113         { "VCore", SENSOR_VOLTS_DC, W83L784R_VCORE, w83l784r_refresh_volt, RFACT_NONE },
  114         { "VBAT", SENSOR_VOLTS_DC, W83L784R_VBAT, w83l784r_refresh_volt, RFACT(232, 99) },
  115         { "+3.3V", SENSOR_VOLTS_DC, W83L784R_3_3V, w83l784r_refresh_volt, RFACT_NONE },
  116         { "+5V", SENSOR_VOLTS_DC, W83L784R_VCC, w83l784r_refresh_volt, RFACT(50, 34) },
  117         { "", SENSOR_TEMP, W83L784R_TEMP1, wbenv_refresh_temp },
  118         { "", SENSOR_TEMP, 1, w83l784r_refresh_temp },
  119         { "", SENSOR_TEMP, 2, w83l784r_refresh_temp },
  120         { "", SENSOR_FANRPM, W83L784R_FAN1, w83l784r_refresh_fanrpm },
  121         { "", SENSOR_FANRPM, W83L784R_FAN2, w83l784r_refresh_fanrpm },
  122 
  123         { NULL }
  124 };
  125 
  126 struct wbenv_sensor w83l785r_sensors[] =
  127 {
  128         { "VCore", SENSOR_VOLTS_DC, W83L784R_VCORE, w83l785r_refresh_volt, RFACT_NONE },
  129         { "+2.5V", SENSOR_VOLTS_DC, W83L785R_2_5V, w83l785r_refresh_volt, RFACT(100, 100) },
  130         { "+1.5V", SENSOR_VOLTS_DC, W83L785R_1_5V, w83l785r_refresh_volt, RFACT_NONE },
  131         { "+3.3V", SENSOR_VOLTS_DC, W83L785R_VCC, w83l785r_refresh_volt, RFACT(20, 40) },
  132         { "", SENSOR_TEMP, W83L784R_TEMP1, wbenv_refresh_temp },
  133         { "", SENSOR_TEMP, W83L785R_TEMP2, wbenv_refresh_temp },
  134         { "", SENSOR_FANRPM, W83L784R_FAN1, w83l785r_refresh_fanrpm },
  135         { "", SENSOR_FANRPM, W83L784R_FAN2, w83l785r_refresh_fanrpm },
  136 
  137         { NULL }
  138 };
  139 
  140 struct wbenv_sensor w83l785ts_l_sensors[] =
  141 {
  142         { "", SENSOR_TEMP, W83L784R_TEMP1, wbenv_refresh_temp },
  143 
  144         { NULL }
  145 };
  146 
  147 int
  148 wbenv_match(struct device *parent, void *match, void *aux)
  149 {
  150         struct i2c_attach_args *ia = aux;
  151 
  152         if (strcmp(ia->ia_name, "w83l784r") == 0 ||
  153             strcmp(ia->ia_name, "w83l785r") == 0 ||
  154             strcmp(ia->ia_name, "w83l785ts-l") == 0)
  155                 return (1);
  156         return (0);
  157 }
  158 
  159 void
  160 wbenv_attach(struct device *parent, struct device *self, void *aux)
  161 {
  162         struct wbenv_softc *sc = (struct wbenv_softc *)self;
  163         struct i2c_attach_args *ia = aux;
  164         u_int8_t cmd, data, config;
  165         int i;
  166 
  167         sc->sc_tag = ia->ia_tag;
  168         sc->sc_addr[0] = ia->ia_addr;
  169 
  170         iic_acquire_bus(sc->sc_tag, 0);
  171 
  172         cmd = W83L784R_CHIPID;
  173         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  174             sc->sc_addr[0], &cmd, sizeof cmd, &data, sizeof data, 0)) {
  175                 iic_release_bus(sc->sc_tag, 0);
  176                 printf(": cannot read chip ID register\n");
  177                 return;
  178         }
  179 
  180         iic_release_bus(sc->sc_tag, 0);
  181 
  182         sc->sc_chip_id = data;
  183 
  184         switch (sc->sc_chip_id) {
  185         case WBENV_CHIPID_W83L784R:
  186                 printf(": W83L784R\n");
  187                 wbenv_setup_sensors(sc, w83l784r_sensors);
  188                 break;
  189         case WBENV_CHIPID_W83L785R:
  190                 printf(": W83L785R\n");
  191                 wbenv_setup_sensors(sc, w83l785r_sensors);
  192                 goto start;
  193         case WBENV_CHIPID_W83L785TS_L:
  194                 printf(": W83L785TS-L\n");
  195                 wbenv_setup_sensors(sc, w83l785ts_l_sensors);
  196                 goto start;
  197         default:
  198                 printf(": unknown Winbond chip (ID 0x%x)\n", sc->sc_chip_id);
  199                 return;
  200         }
  201 
  202         iic_acquire_bus(sc->sc_tag, 0);
  203 
  204         cmd = W83L784R_T23ADDR;
  205         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  206             sc->sc_addr[0], &cmd, sizeof cmd, &data, sizeof data, 0)) {
  207                 iic_release_bus(sc->sc_tag, 0);
  208                 printf(": cannot read address register\n");
  209                 return;
  210         }
  211 
  212         iic_release_bus(sc->sc_tag, 0);
  213 
  214         sc->sc_addr[1] = 0x48 + (data & 0x7);
  215         sc->sc_addr[2] = 0x48 + ((data >> 4) & 0x7);
  216 
  217         /* Make the bus scan ignore the satellites. */
  218         iic_ignore_addr(sc->sc_addr[1]);
  219         iic_ignore_addr(sc->sc_addr[2]);
  220 
  221  start:
  222         if (sensor_task_register(sc, wbenv_refresh, 5) == NULL) {
  223                 printf("%s: unable to register update task\n",
  224                     sc->sc_dev.dv_xname);
  225                 return;
  226         }
  227 
  228         /* Start the monitoring loop */
  229         config = wbenv_readreg(sc, W83L784R_CONFIG);
  230         wbenv_writereg(sc, W83L784R_CONFIG, config | 0x01);
  231 
  232         /* Add sensors */
  233         for (i = 0; i < sc->sc_numsensors; ++i)
  234                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
  235         sensordev_install(&sc->sc_sensordev);
  236 }
  237 
  238 void
  239 wbenv_setup_sensors(struct wbenv_softc *sc, struct wbenv_sensor *sensors)
  240 {
  241         int i;
  242 
  243         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
  244             sizeof(sc->sc_sensordev.xname));
  245 
  246         for (i = 0; sensors[i].desc; i++) {
  247                 sc->sc_sensors[i].type = sensors[i].type;
  248                 strlcpy(sc->sc_sensors[i].desc, sensors[i].desc,
  249                     sizeof(sc->sc_sensors[i].desc));
  250                 sc->sc_numsensors++;
  251         }
  252         sc->sc_wbenv_sensors = sensors;
  253 }
  254 
  255 void
  256 wbenv_refresh(void *arg)
  257 {
  258         struct wbenv_softc *sc = arg;
  259         int i;
  260 
  261         iic_acquire_bus(sc->sc_tag, 0);
  262 
  263         for (i = 0; i < sc->sc_numsensors; i++)
  264                 sc->sc_wbenv_sensors[i].refresh(sc, i);
  265 
  266         iic_release_bus(sc->sc_tag, 0);
  267 }
  268 
  269 void
  270 w83l784r_refresh_volt(struct wbenv_softc *sc, int n)
  271 {
  272         struct ksensor *sensor = &sc->sc_sensors[n];
  273         int data, reg = sc->sc_wbenv_sensors[n].reg;
  274 
  275         data = wbenv_readreg(sc, reg);
  276         sensor->value = (data << 4); /* 16 mV LSB */
  277         sensor->value *= sc->sc_wbenv_sensors[n].rfact;
  278         sensor->value /= 10;
  279 }
  280 
  281 void
  282 w83l785r_refresh_volt(struct wbenv_softc *sc, int n)
  283 {
  284         struct ksensor *sensor = &sc->sc_sensors[n];
  285         int data, reg = sc->sc_wbenv_sensors[n].reg;
  286 
  287         data = wbenv_readreg(sc, reg);
  288         sensor->value = (data << 3); /* 8 mV LSB */
  289         sensor->value *= sc->sc_wbenv_sensors[n].rfact;
  290         sensor->value /= 10;
  291 }
  292 
  293 void
  294 wbenv_refresh_temp(struct wbenv_softc *sc, int n)
  295 {
  296         struct ksensor *sensor = &sc->sc_sensors[n];
  297         int sdata;
  298 
  299         sdata = wbenv_readreg(sc, sc->sc_wbenv_sensors[n].reg);
  300         if (sdata & 0x80)
  301                 sdata -= 0x100;
  302         sensor->value = sdata * 1000000 + 273150000;
  303 }
  304 
  305 void
  306 w83l784r_refresh_temp(struct wbenv_softc *sc, int n)
  307 {
  308         struct ksensor *sensor = &sc->sc_sensors[n];
  309         int16_t sdata;
  310         u_int8_t cmd = 0;
  311 
  312         iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  313             sc->sc_addr[sc->sc_wbenv_sensors[n].reg],
  314             &cmd, sizeof cmd, &sdata, sizeof sdata, 0);
  315         sensor->value = (sdata >> 7) * 500000 + 273150000;
  316 }
  317 
  318 void
  319 w83l784r_refresh_fanrpm(struct wbenv_softc *sc, int n)
  320 {
  321         struct ksensor *sensor = &sc->sc_sensors[n];
  322         int data, divisor;
  323 
  324         data = wbenv_readreg(sc, W83L784R_FANDIV);
  325         if (sc->sc_wbenv_sensors[n].reg == W83L784R_FAN1)
  326                 divisor = data & 0x07;
  327         else
  328                 divisor = (data >> 4) & 0x07;
  329 
  330         data = wbenv_readreg(sc, sc->sc_wbenv_sensors[n].reg);
  331         if (data == 0xff || data == 0x00) {
  332                 sensor->flags |= SENSOR_FINVALID;
  333                 sensor->value = 0;
  334         } else {
  335                 sensor->flags &= ~SENSOR_FINVALID;
  336                 sensor->value = 1350000 / (data << divisor);
  337         }
  338 }
  339 
  340 void
  341 w83l785r_refresh_fanrpm(struct wbenv_softc *sc, int n)
  342 {
  343         struct ksensor *sensor = &sc->sc_sensors[n];
  344         int data, divisor;
  345 
  346         data = wbenv_readreg(sc, W83L785R_FANDIV);
  347         if (sc->sc_wbenv_sensors[n].reg == W83L784R_FAN1)
  348                 divisor = data & 0x07;
  349         else
  350                 divisor = (data >> 4) & 0x07;
  351 
  352         data = wbenv_readreg(sc, sc->sc_wbenv_sensors[n].reg);
  353         if (data == 0xff || data == 0x00) {
  354                 sensor->flags |= SENSOR_FINVALID;
  355                 sensor->value = 0;
  356         } else {
  357                 sensor->flags &= ~SENSOR_FINVALID;
  358                 sensor->value = 1350000 / (data << divisor);
  359         }
  360 }
  361 
  362 u_int8_t
  363 wbenv_readreg(struct wbenv_softc *sc, u_int8_t reg)
  364 {
  365         u_int8_t data;
  366 
  367         iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  368             sc->sc_addr[0], &reg, sizeof reg, &data, sizeof data, 0);
  369 
  370         return data;
  371 }
  372 
  373 void
  374 wbenv_writereg(struct wbenv_softc *sc, u_int8_t reg, u_int8_t data)
  375 {
  376         iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
  377             sc->sc_addr[0], &reg, sizeof reg, &data, sizeof data, 0);
  378 }

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