root/dev/i2c/adt7460.c

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

DEFINITIONS

This source file includes following definitions.
  1. adt_match
  2. adt_attach
  3. adt_refresh

    1 /*      $OpenBSD: adt7460.c,v 1.18 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 /* ADT7460 registers */
   27 #define ADT7460_2_5V            0x20
   28 #define ADT7460_VCCP            0x21
   29 #define ADT7460_VCC             0x22
   30 #define ADT7460_V5              0x23
   31 #define ADT7460_V12             0x24
   32 #define ADT7460_REM1_TEMP       0x25
   33 #define ADT7460_LOCAL_TEMP      0x26
   34 #define ADT7460_REM2_TEMP       0x27
   35 #define ADT7460_TACH1L          0x28
   36 #define ADT7460_TACH1H          0x29
   37 #define ADT7460_TACH2L          0x2a
   38 #define ADT7460_TACH2H          0x2b
   39 #define ADT7460_TACH3L          0x2c
   40 #define ADT7460_TACH3H          0x2d
   41 #define ADT7460_TACH4L          0x2e
   42 #define ADT7460_TACH4H          0x2f
   43 #define ADT7460_REVISION        0x3f
   44 #define ADT7460_CONFIG          0x40
   45 #define ADT7460_CONFIG_Vcc      0x80
   46 
   47 /* Sensors */
   48 #define ADT_2_5V                0
   49 #define ADT_VCCP                1
   50 #define ADT_VCC                 2
   51 #define ADT_V5                  3
   52 #define ADT_V12                 4
   53 #define ADT_REM1_TEMP           5
   54 #define ADT_LOCAL_TEMP          6
   55 #define ADT_REM2_TEMP           7
   56 #define ADT_TACH1               8
   57 #define ADT_TACH2               9
   58 #define ADT_TACH3               10
   59 #define ADT_TACH4               11
   60 #define ADT_NUM_SENSORS         12
   61 
   62 struct adt_chip {
   63         const char      *name;
   64         short           ratio[5];
   65         int             type;
   66         short           vcc;
   67 } adt_chips[] = {
   68         /* register     0x20  0x21  0x22  0x23  0x24    type    */
   69         /*              2.5v  vccp   vcc    5v   12v            */
   70 
   71         { "adt7460",    { 2500,    0, 3300,    0,     0 },      7460,   5000 },
   72         { "adt7467",    { 2500, 2250, 3300, 5000, 12000 },      7467,   5000 },
   73         { "adt7475",    {    0, 2250, 3300,    0,     0 },      7475,      0 },
   74         { "adt7476",    { 2500, 2250, 3300, 5000, 12000 },      7476,      0 },
   75         { "adm1027",    { 2500, 2250, 3300, 5000, 12000 },      1027,   5000 },
   76         { "lm85",       { 2500, 2250, 3300, 5000, 12000 },      7467,      0 },
   77         { "emc6d100",   { 2500, 2250, 3300, 5000, 12000 },      6100,      0 },
   78         { "emc6w201",   { 2500, 2250, 3300, 5000, 12000 },      6201,      0 },
   79         { "lm96000",    { 2500, 2250, 3300, 5000, 12000 },      96000,     0 },
   80         { "sch5017",    { 5000, 2250, 3300, 5000, 12000 },      5017,      0 }
   81 };
   82 
   83 struct {
   84         char            sensor;
   85         u_int8_t        cmd;
   86         u_short         index;
   87 } worklist[] = {
   88         { ADT_2_5V, ADT7460_2_5V, 32768 + 0 },
   89         { ADT_VCCP, ADT7460_VCCP, 32768 + 1 },
   90         { ADT_VCC, ADT7460_VCC, 32768 + 2 },
   91         { ADT_V5, ADT7460_V5, 32768 + 3 },
   92         { ADT_V12, ADT7460_V12, 32768 + 4 },
   93         { ADT_REM1_TEMP, ADT7460_REM1_TEMP },
   94         { ADT_LOCAL_TEMP, ADT7460_LOCAL_TEMP },
   95         { ADT_REM2_TEMP, ADT7460_REM2_TEMP },
   96         { ADT_TACH1, ADT7460_TACH1L },
   97         { ADT_TACH2, ADT7460_TACH2L },
   98         { ADT_TACH3, ADT7460_TACH3L },
   99         { ADT_TACH4, ADT7460_TACH4L },
  100 };
  101 
  102 struct adt_softc {
  103         struct device sc_dev;
  104         i2c_tag_t sc_tag;
  105         i2c_addr_t sc_addr;
  106         u_int8_t sc_conf;
  107         struct adt_chip *chip;
  108 
  109         struct ksensor sc_sensor[ADT_NUM_SENSORS];
  110         struct ksensordev sc_sensordev;
  111 };
  112 
  113 int     adt_match(struct device *, void *, void *);
  114 void    adt_attach(struct device *, struct device *, void *);
  115 
  116 void    adt_refresh(void *);
  117 
  118 struct cfattach adt_ca = {
  119         sizeof(struct adt_softc), adt_match, adt_attach
  120 };
  121 
  122 struct cfdriver adt_cd = {
  123         NULL, "adt", DV_DULL
  124 };
  125 
  126 int
  127 adt_match(struct device *parent, void *match, void *aux)
  128 {
  129         struct i2c_attach_args *ia = aux;
  130         int i;
  131 
  132         for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++)
  133                 if (strcmp(ia->ia_name, adt_chips[i].name) == 0)
  134                         return (1);
  135         return (0);
  136 }
  137 
  138 void
  139 adt_attach(struct device *parent, struct device *self, void *aux)
  140 {
  141         struct adt_softc *sc = (struct adt_softc *)self;
  142         struct i2c_attach_args *ia = aux;
  143         u_int8_t cmd, rev, data;
  144         int i;
  145 
  146         sc->sc_tag = ia->ia_tag;
  147         sc->sc_addr = ia->ia_addr;
  148 
  149         iic_acquire_bus(sc->sc_tag, 0);
  150 
  151         for (i = 0; i < sizeof(adt_chips) / sizeof(adt_chips[0]); i++) {
  152                 if (strcmp(ia->ia_name, adt_chips[i].name) == 0) {
  153                         sc->chip = &adt_chips[i];
  154                         break;
  155                 }
  156         }
  157 
  158         cmd = ADT7460_REVISION;
  159         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  160             sc->sc_addr, &cmd, sizeof cmd, &rev, sizeof rev, 0)) {
  161                 iic_release_bus(sc->sc_tag, 0);
  162                 printf(": cannot read REV register\n");
  163                 return;
  164         }
  165 
  166         cmd = ADT7460_CONFIG;
  167         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  168             sc->sc_addr, &cmd, sizeof cmd, &sc->sc_conf, sizeof sc->sc_conf, 0)) {
  169                 iic_release_bus(sc->sc_tag, 0);
  170                 printf(": cannot read config register\n");
  171                 return;
  172         }
  173 
  174         if (sc->chip->type == 7460) {
  175                 data = 1;
  176                 cmd = ADT7460_CONFIG;
  177                 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
  178                     sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  179                         iic_release_bus(sc->sc_tag, 0);
  180                         printf(": cannot set control register\n");
  181                         return;
  182                 }
  183         }
  184 
  185         iic_release_bus(sc->sc_tag, 0);
  186 
  187         printf(": %s rev 0x%02x", ia->ia_name, rev);
  188 
  189         /* Initialize sensor data. */
  190         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
  191             sizeof(sc->sc_sensordev.xname));
  192 
  193         sc->sc_sensor[ADT_2_5V].type = SENSOR_VOLTS_DC;
  194         strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+2.5Vin",
  195             sizeof(sc->sc_sensor[ADT_2_5V].desc));
  196                 
  197         if (sc->chip->type == 5017)
  198                 strlcpy(sc->sc_sensor[ADT_2_5V].desc, "+5VTR",
  199                     sizeof(sc->sc_sensor[ADT_2_5V].desc));
  200 
  201         sc->sc_sensor[ADT_VCCP].type = SENSOR_VOLTS_DC;
  202         strlcpy(sc->sc_sensor[ADT_VCCP].desc, "Vccp",
  203             sizeof(sc->sc_sensor[ADT_VCCP].desc));
  204 
  205         sc->sc_sensor[ADT_VCC].type = SENSOR_VOLTS_DC;
  206         strlcpy(sc->sc_sensor[ADT_VCC].desc, "Vcc",
  207             sizeof(sc->sc_sensor[ADT_VCC].desc));
  208 
  209         sc->sc_sensor[ADT_V5].type = SENSOR_VOLTS_DC;
  210         strlcpy(sc->sc_sensor[ADT_V5].desc, "+5V",
  211             sizeof(sc->sc_sensor[ADT_V5].desc));
  212 
  213         sc->sc_sensor[ADT_V12].type = SENSOR_VOLTS_DC;
  214         strlcpy(sc->sc_sensor[ADT_V12].desc, "+12V",
  215             sizeof(sc->sc_sensor[ADT_V12].desc));
  216 
  217         sc->sc_sensor[ADT_REM1_TEMP].type = SENSOR_TEMP;
  218         strlcpy(sc->sc_sensor[ADT_REM1_TEMP].desc, "Remote",
  219             sizeof(sc->sc_sensor[ADT_REM1_TEMP].desc));
  220 
  221         sc->sc_sensor[ADT_LOCAL_TEMP].type = SENSOR_TEMP;
  222         strlcpy(sc->sc_sensor[ADT_LOCAL_TEMP].desc, "Internal",
  223             sizeof(sc->sc_sensor[ADT_LOCAL_TEMP].desc));
  224 
  225         sc->sc_sensor[ADT_REM2_TEMP].type = SENSOR_TEMP;
  226         strlcpy(sc->sc_sensor[ADT_REM2_TEMP].desc, "Remote",
  227             sizeof(sc->sc_sensor[ADT_REM2_TEMP].desc));
  228 
  229         sc->sc_sensor[ADT_TACH1].type = SENSOR_FANRPM;
  230         sc->sc_sensor[ADT_TACH2].type = SENSOR_FANRPM;
  231         sc->sc_sensor[ADT_TACH3].type = SENSOR_FANRPM;
  232         sc->sc_sensor[ADT_TACH4].type = SENSOR_FANRPM;
  233 
  234         if (sensor_task_register(sc, adt_refresh, 5) == NULL) {
  235                 printf(", unable to register update task\n");
  236                 return;
  237         }
  238 
  239         for (i = 0; i < ADT_NUM_SENSORS; i++) {
  240                 if (worklist[i].index >= 32768 &&
  241                     sc->chip->ratio[worklist[i].index - 32768] == 0)
  242                         continue;
  243                 sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
  244                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
  245         }
  246         sensordev_install(&sc->sc_sensordev);
  247 
  248 
  249         printf("\n");
  250 }
  251 
  252 void
  253 adt_refresh(void *arg)
  254 {
  255         struct adt_softc *sc = arg;
  256         u_int8_t cmd, data, data2;
  257         u_int16_t fan;
  258         int i, ratio;
  259 
  260         iic_acquire_bus(sc->sc_tag, 0);
  261 
  262         for (i = 0; i < sizeof worklist / sizeof(worklist[0]); i++) {
  263 
  264                 if (worklist[i].index >= 32768) {
  265                         ratio = sc->chip->ratio[worklist[i].index - 32768];
  266                         if (ratio == 0) /* do not read a dead register */
  267                                 continue;
  268                 }
  269                 cmd = worklist[i].cmd;
  270                 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  271                     sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
  272                         sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  273                         continue;
  274                 }
  275 
  276                 sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
  277                 switch (worklist[i].sensor) {
  278                 case ADT_VCC:
  279                         if (sc->chip->vcc && (sc->sc_conf & ADT7460_CONFIG_Vcc))
  280                                 ratio = sc->chip->vcc;
  281                         /* FALLTHROUGH */
  282                 case ADT_2_5V:
  283                 case ADT_VCCP:
  284                 case ADT_V5:
  285                 case ADT_V12:
  286                         sc->sc_sensor[i].value = ratio * 1000 * (u_int)data / 192;
  287                         break;
  288                 case ADT_LOCAL_TEMP:
  289                 case ADT_REM1_TEMP:
  290                 case ADT_REM2_TEMP:
  291                         if (data == 0x80)
  292                                 sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  293                         else
  294                                 sc->sc_sensor[i].value =
  295                                     (int8_t)data * 1000000 + 273150000;
  296                         break;
  297                 case ADT_TACH1:
  298                 case ADT_TACH2:
  299                 case ADT_TACH3:
  300                 case ADT_TACH4:
  301                         cmd = worklist[i].cmd + 1; /* TACHnH follows TACHnL */
  302                         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  303                             sc->sc_addr, &cmd, sizeof cmd, &data2, sizeof data2, 0)) {
  304                                 sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  305                                 continue;
  306                         }
  307 
  308                         fan = data + (data2 << 8);
  309                         if (fan == 0 || fan == 0xffff)
  310                                 sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  311                         else
  312                                 sc->sc_sensor[i].value = (90000 * 60) / fan;
  313                         break;
  314                 default:
  315                         sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  316                         break;
  317                 }
  318         }
  319 
  320         iic_release_bus(sc->sc_tag, 0);
  321 }

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