root/dev/i2c/asb100.c

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

DEFINITIONS

This source file includes following definitions.
  1. asbtm_match
  2. asbtm_banksel
  3. asbtm_attach
  4. fanval
  5. asbtm_refresh

    1 /*      $OpenBSD: asb100.c,v 1.10 2007/06/24 05:34:35 dlg Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2005 Damien Miller <djm@openbsd.org>
    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 /* Apparently the ASB100 always lives here */
   27 #define ASB100_ADDR                     0x2d
   28 
   29 /* ASB100 registers */
   30 #define ASB100_TEMP3                    0x17
   31 #define ASB100_TEMP3_MAX                0x18
   32 #define ASB100_TEMP3_HYST               0x19
   33 #define ASB100_VIN0                     0x20
   34 #define ASB100_VIN1                     0x21
   35 #define ASB100_VIN2                     0x22
   36 #define ASB100_VIN3                     0x23
   37 #define ASB100_VIN4                     0x24
   38 #define ASB100_VIN5                     0x25
   39 #define ASB100_VIN6                     0x26
   40 #define ASB100_TEMP0                    0x27
   41 #define ASB100_FAN0                     0x28
   42 #define ASB100_FAN1                     0x29
   43 #define ASB100_FAN2                     0x30
   44 #define ASB100_VIN0_MIN                 0x2b
   45 #define ASB100_VIN0_MAX                 0x2c
   46 #define ASB100_VIN1_MIN                 0x2d
   47 #define ASB100_VIN1_MAX                 0x2e
   48 #define ASB100_VIN2_MIN                 0x2f
   49 #define ASB100_VIN2_MAX                 0x30
   50 #define ASB100_VIN3_MIN                 0x31
   51 #define ASB100_VIN3_MAX                 0x32
   52 #define ASB100_VIN4_MIN                 0x33
   53 #define ASB100_VIN4_MAX                 0x34
   54 #define ASB100_VIN5_MIN                 0x35
   55 #define ASB100_VIN5_MAX                 0x36
   56 #define ASB100_VIN6_MIN                 0x37
   57 #define ASB100_VIN6_MAX                 0x38
   58 #define ASB100_TEMP0_MAX                0x39
   59 #define ASB100_TEMP0_HYST               0x3a
   60 #define ASB100_FAN0_MIN                 0x3b
   61 #define ASB100_FAN1_MIN                 0x3c
   62 #define ASB100_FAN2_MIN                 0x3d
   63 #define ASB100_CONFIG                   0x40
   64 #define ASB100_ALARM1                   0x41
   65 #define ASB100_ALARM2                   0x42
   66 #define ASB100_SMIM1                    0x43
   67 #define ASB100_SMIM2                    0x44
   68 #define ASB100_VID_FANDIV01             0x47 /* 0-3 vid, 4-5 fan0, 6-7 fan1 */
   69 #define ASB100_I2C_ADDR                 0x48
   70 #define ASB100_CHIPID                   0x49
   71 #define ASB100_I2C_SUBADDR              0x4a
   72 #define ASB100_PIN_FANDIV2              0x4b /* 6-7 fan2 */
   73 #define ASB100_IRQ                      0x4c
   74 #define ASB100_BANK                     0x4e
   75 #define ASB100_CHIPMAN                  0x4f
   76 #define ASB100_VID_CHIPID               0x58 /* 0 vid highbit, 1-7 chipid */
   77 #define ASB100_PWM                      0x59 /* 0-3 duty cycle, 7 enable */
   78 
   79 /* TEMP1/2 sensors live on other chips, pointed to by the I2C_SUBADDR reg */
   80 #define ASB100_SUB1_TEMP1               0x50 /* LM75 format */
   81 #define ASB100_SUB1_TEMP1_HYST          0x53
   82 #define ASB100_SUB1_TEMP1_MAX           0x55
   83 #define ASB100_SUB2_TEMP2               0x50 /* LM75 format */
   84 #define ASB100_SUB2_TEMP2_HYST          0x53
   85 #define ASB100_SUB2_TEMP2_MAX           0x55
   86 
   87 /* Sensors */
   88 #define ASB100_SENSOR_VIN0      0
   89 #define ASB100_SENSOR_VIN1      1
   90 #define ASB100_SENSOR_VIN2      2
   91 #define ASB100_SENSOR_VIN3      3
   92 #define ASB100_SENSOR_VIN4      4
   93 #define ASB100_SENSOR_VIN5      5
   94 #define ASB100_SENSOR_VIN6      6
   95 #define ASB100_SENSOR_FAN0      7
   96 #define ASB100_SENSOR_FAN1      8
   97 #define ASB100_SENSOR_FAN2      9
   98 #define ASB100_SENSOR_TEMP0     10
   99 #define ASB100_SENSOR_TEMP1     11
  100 #define ASB100_SENSOR_TEMP2     12
  101 #define ASB100_SENSOR_TEMP3     13
  102 #define ASB100_NUM_SENSORS      14
  103 
  104 struct asbtm_softc {
  105         struct device   sc_dev;
  106         i2c_tag_t       sc_tag;
  107         i2c_addr_t      sc_addr;
  108 
  109         struct ksensor  sc_sensor[ASB100_NUM_SENSORS];
  110         struct ksensordev sc_sensordev;
  111         int             sc_fanmul[3];
  112         int             sc_satellite[2];
  113 };
  114 
  115 int     asbtm_banksel(struct asbtm_softc *, u_int8_t, u_int8_t *);
  116 int     asbtm_match(struct device *, void *, void *);
  117 void    asbtm_attach(struct device *, struct device *, void *);
  118 void    asbtm_refresh(void *);
  119 
  120 struct cfattach asbtm_ca = {
  121         sizeof(struct asbtm_softc), asbtm_match, asbtm_attach
  122 };
  123 
  124 struct cfdriver asbtm_cd = {
  125         NULL, "asbtm", DV_DULL
  126 };
  127 
  128 int
  129 asbtm_match(struct device *parent, void *match, void *aux)
  130 {
  131         struct i2c_attach_args *ia = aux;
  132 
  133         if (strcmp(ia->ia_name, "asb100") == 0)
  134                 return (1);
  135 
  136         return (0);
  137 }
  138 
  139 int
  140 asbtm_banksel(struct asbtm_softc *sc, u_int8_t new_bank, u_int8_t *orig_bank)
  141 {
  142         u_int8_t cmd, data;
  143 
  144         new_bank &= 0xf;
  145 
  146         cmd = ASB100_BANK;
  147         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  148             &cmd, sizeof cmd, &data, sizeof data, 0))
  149                 return (-1);
  150 
  151         if (orig_bank != NULL)
  152                 *orig_bank = data & 0x0f;
  153 
  154         if ((data & 0xf) != new_bank) {
  155                 cmd = ASB100_BANK;
  156                 data = new_bank | (data & 0xf0);
  157                 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr,
  158                     &cmd, sizeof cmd, &data, sizeof data, 0))
  159                         return (-1);
  160         }
  161 
  162         return (0);
  163 }
  164 
  165 void
  166 asbtm_attach(struct device *parent, struct device *self, void *aux)
  167 {
  168         struct asbtm_softc *sc = (struct asbtm_softc *)self;
  169         struct i2c_attach_args *ia = aux;
  170         u_int8_t orig_bank, cmd, data;
  171         int i;
  172 
  173         sc->sc_tag = ia->ia_tag;
  174         sc->sc_addr = ia->ia_addr;
  175 
  176         iic_acquire_bus(sc->sc_tag, 0);
  177 
  178         if (asbtm_banksel(sc, 0, &orig_bank) == -1) {
  179                 printf(": cannot get/set register bank\n");
  180                 iic_release_bus(sc->sc_tag, 0);
  181                 return;
  182         }
  183 
  184         cmd = ASB100_VID_FANDIV01;
  185         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  186             &cmd, sizeof cmd, &data, sizeof data, 0)) {
  187                 printf(": cannot get fan01 register\n");
  188                 iic_release_bus(sc->sc_tag, 0);
  189                 return;
  190         }
  191         sc->sc_fanmul[0] = (1 << (data >> 4) & 0x3);
  192         sc->sc_fanmul[1] = (1 << (data >> 6) & 0x3);
  193 
  194         cmd = ASB100_PIN_FANDIV2;
  195         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  196             &cmd, sizeof cmd, &data, sizeof data, 0)) {
  197                 printf(": cannot get fan2 register\n");
  198                 iic_release_bus(sc->sc_tag, 0);
  199                 return;
  200         }
  201         sc->sc_fanmul[0] = (1 << (data >> 6) & 0x3);
  202 
  203         cmd = ASB100_I2C_SUBADDR;
  204         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  205             &cmd, sizeof cmd, &data, sizeof data, 0)) {
  206                 printf(": cannot get satellite chip address register\n");
  207                 iic_release_bus(sc->sc_tag, 0);
  208                 return;
  209         }
  210         /* Maybe a relative address of zero means "not present" here... */
  211         sc->sc_satellite[0] = 0x48 + (data & 0xf);
  212         sc->sc_satellite[1] = 0x48 + ((data >> 4) & 0xf);
  213 
  214         iic_ignore_addr(sc->sc_satellite[0]);
  215         iic_ignore_addr(sc->sc_satellite[1]);
  216         if (sc->sc_satellite[0] == sc->sc_satellite[1])
  217                 sc->sc_satellite[1] = -1;
  218 
  219         if (asbtm_banksel(sc, orig_bank, NULL) == -1) {
  220                 printf(": cannot restore saved bank %d\n", orig_bank);
  221                 iic_release_bus(sc->sc_tag, 0);
  222                 return;
  223         }
  224 
  225         iic_release_bus(sc->sc_tag, 0);
  226 
  227         /* Initialize sensor data. */
  228         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
  229             sizeof(sc->sc_sensordev.xname));
  230 
  231         sc->sc_sensor[ASB100_SENSOR_VIN0].type = SENSOR_VOLTS_DC;
  232         sc->sc_sensor[ASB100_SENSOR_VIN1].type = SENSOR_VOLTS_DC;
  233         sc->sc_sensor[ASB100_SENSOR_VIN2].type = SENSOR_VOLTS_DC;
  234         sc->sc_sensor[ASB100_SENSOR_VIN3].type = SENSOR_VOLTS_DC;
  235         sc->sc_sensor[ASB100_SENSOR_VIN4].type = SENSOR_VOLTS_DC;
  236         sc->sc_sensor[ASB100_SENSOR_VIN5].type = SENSOR_VOLTS_DC;
  237         sc->sc_sensor[ASB100_SENSOR_VIN6].type = SENSOR_VOLTS_DC;
  238 
  239         sc->sc_sensor[ASB100_SENSOR_FAN0].type = SENSOR_FANRPM;
  240         sc->sc_sensor[ASB100_SENSOR_FAN1].type = SENSOR_FANRPM;
  241         sc->sc_sensor[ASB100_SENSOR_FAN2].type = SENSOR_FANRPM;
  242 
  243         sc->sc_sensor[ASB100_SENSOR_TEMP0].type = SENSOR_TEMP;
  244         strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP0].desc, "External",
  245             sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP0].desc));
  246 
  247         sc->sc_sensor[ASB100_SENSOR_TEMP1].type = SENSOR_TEMP;
  248         strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP1].desc, "Internal",
  249             sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP1].desc));
  250 
  251         sc->sc_sensor[ASB100_SENSOR_TEMP2].type = SENSOR_TEMP;
  252         strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP2].desc, "Internal",
  253             sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP2].desc));
  254         if (sc->sc_satellite[1] == -1)
  255                 sc->sc_sensor[ASB100_SENSOR_TEMP2].flags |= SENSOR_FINVALID;
  256 
  257         sc->sc_sensor[ASB100_SENSOR_TEMP3].type = SENSOR_TEMP;
  258         strlcpy(sc->sc_sensor[ASB100_SENSOR_TEMP3].desc, "External",
  259             sizeof(sc->sc_sensor[ASB100_SENSOR_TEMP3].desc));
  260 
  261         if (sensor_task_register(sc, asbtm_refresh, 5) == NULL) {
  262                 printf(", unable to register update task\n");
  263                 return;
  264         }
  265 
  266         for (i = 0; i < ASB100_NUM_SENSORS; i++)
  267                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
  268         sensordev_install(&sc->sc_sensordev);
  269 
  270         printf("\n");
  271 }
  272 
  273 static void
  274 fanval(struct ksensor *sens, int mul, u_int8_t data)
  275 {
  276         int tmp = data * mul;
  277 
  278         if (tmp == 0)
  279                 sens->flags |= SENSOR_FINVALID;
  280         else {
  281                 sens->value = 1350000 / tmp;
  282                 sens->flags &= ~SENSOR_FINVALID;
  283         }
  284 }
  285 
  286 void
  287 asbtm_refresh(void *arg)
  288 {
  289         struct asbtm_softc *sc = arg;
  290         u_int8_t orig_bank, cmd, data;
  291         int8_t sdata;
  292         u_int16_t sdata2;
  293 
  294         iic_acquire_bus(sc->sc_tag, 0);
  295 
  296         if (asbtm_banksel(sc, 0, &orig_bank) == -1) {
  297                 printf("%s: cannot get/set register bank\n",
  298                     sc->sc_dev.dv_xname);
  299                 iic_release_bus(sc->sc_tag, 0);
  300                 return;
  301         }
  302 
  303         cmd = ASB100_VIN0;
  304         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  305             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  306                 sc->sc_sensor[ASB100_SENSOR_VIN0].value = (data * 1000000) / 16;
  307 
  308         cmd = ASB100_VIN1;
  309         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  310             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  311                 sc->sc_sensor[ASB100_SENSOR_VIN1].value = (data * 1000000) / 16;
  312 
  313         cmd = ASB100_VIN2;
  314         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  315             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  316                 sc->sc_sensor[ASB100_SENSOR_VIN2].value = (data * 1000000) / 16;
  317 
  318         cmd = ASB100_VIN3;
  319         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  320             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  321                 sc->sc_sensor[ASB100_SENSOR_VIN3].value = (data * 1000000) / 16;
  322 
  323         cmd = ASB100_VIN4;
  324         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  325             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  326                 sc->sc_sensor[ASB100_SENSOR_VIN4].value = (data * 1000000) / 16;
  327 
  328         cmd = ASB100_VIN5;
  329         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  330             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  331                 sc->sc_sensor[ASB100_SENSOR_VIN5].value = (data * 1000000) / 16;
  332 
  333         cmd = ASB100_VIN6;
  334         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  335             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  336                 sc->sc_sensor[ASB100_SENSOR_VIN6].value = (data * 1000000) / 16;
  337 
  338         cmd = ASB100_FAN0;
  339         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  340             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  341                 fanval(&sc->sc_sensor[ASB100_SENSOR_FAN0],
  342                     sc->sc_fanmul[0], data);
  343 
  344         cmd = ASB100_FAN1;
  345         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  346             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  347                 fanval(&sc->sc_sensor[ASB100_SENSOR_FAN1],
  348                     sc->sc_fanmul[1], data);
  349 
  350         cmd = ASB100_FAN2;
  351         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  352             &cmd, sizeof cmd, &data, sizeof data, 0) == 0)
  353                 fanval(&sc->sc_sensor[ASB100_SENSOR_FAN2],
  354                     sc->sc_fanmul[2], data);
  355 
  356         cmd = ASB100_TEMP0;
  357         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  358             &cmd, sizeof cmd, &sdata, sizeof sdata, 0) == 0)
  359                 sc->sc_sensor[ASB100_SENSOR_TEMP0].value = 273150000 +
  360                     1000000 * sdata;
  361 
  362         cmd = ASB100_TEMP3;
  363         if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
  364             &cmd, sizeof cmd, &data, sizeof sdata, 0) == 0)
  365                 sc->sc_sensor[ASB100_SENSOR_TEMP3].value = 273150000 +
  366                     1000000 * sdata;
  367 
  368         /* Read satellite chips for TEMP1/TEMP2 */
  369         cmd = ASB100_SUB1_TEMP1;
  370         if (sc->sc_satellite[0] != -1) {
  371                 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  372                     sc->sc_satellite[0], &cmd, sizeof cmd, &sdata2,
  373                     sizeof sdata2, 0) == 0 && sdata2 != 0xffff) {
  374                         sc->sc_sensor[ASB100_SENSOR_TEMP1].value = 273150000 +
  375                             500000 * (swap16(sdata2) / 128);
  376                         sc->sc_sensor[ASB100_SENSOR_TEMP2].flags &=
  377                             ~SENSOR_FINVALID;
  378                 } else {
  379                         sc->sc_sensor[ASB100_SENSOR_TEMP2].flags |=
  380                             SENSOR_FINVALID;
  381                 }
  382         }
  383 
  384         cmd = ASB100_SUB2_TEMP2;
  385         if (sc->sc_satellite[1] != -1) {
  386                 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
  387                     sc->sc_satellite[1], &cmd, sizeof cmd, &sdata2,
  388                     sizeof sdata2, 0) == 0 && sdata2 != 0xffff) {
  389                         sc->sc_sensor[ASB100_SENSOR_TEMP2].value = 273150000 +
  390                             500000 * (swap16(sdata2) / 128);
  391                         sc->sc_sensor[ASB100_SENSOR_TEMP2].flags &=
  392                             ~SENSOR_FINVALID;
  393                 } else {
  394                         sc->sc_sensor[ASB100_SENSOR_TEMP2].flags |=
  395                             SENSOR_FINVALID;
  396                 }
  397         }
  398 
  399         asbtm_banksel(sc, orig_bank, NULL);
  400 
  401         iic_release_bus(sc->sc_tag, 0);
  402 }

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