root/dev/i2c/fintek.c

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

DEFINITIONS

This source file includes following definitions.
  1. fintek_match
  2. fintek_read_reg
  3. fintek_write_reg
  4. fintek_attach
  5. fintek_refresh
  6. fintek_fullspeed

    1 /*      $OpenBSD: fintek.c,v 1.6 2007/06/24 05:34:35 dlg Exp $ */
    2 /*
    3  * Copyright (c) 2006 Dale Rahn <drahn@openbsd.org>
    4  *
    5  * Permission to use, copy, modify, and distribute this software for any
    6  * purpose with or without fee is hereby granted, provided that the above
    7  * copyright notice and this permission notice appear in all copies.
    8  *
    9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16  */
   17 
   18 #include <sys/param.h>
   19 #include <sys/systm.h>
   20 #include <sys/device.h>
   21 #include <sys/sensors.h>
   22 
   23 #include <dev/i2c/i2cvar.h>
   24 
   25 /* Sensors */
   26 #define F_VCC   0
   27 #define F_V1    1
   28 #define F_V2    2
   29 #define F_V3    3
   30 #define F_TEMP1 4
   31 #define F_TEMP2 5
   32 #define F_FAN1  6
   33 #define F_FAN2  7
   34 #define F_NUM_SENSORS   8
   35 
   36 struct fintek_softc {
   37         struct device sc_dev;
   38         i2c_tag_t sc_tag;
   39         i2c_addr_t sc_addr;
   40 
   41         struct ksensor sc_sensor[F_NUM_SENSORS];
   42         struct ksensordev sc_sensordev;
   43 };
   44 
   45 int     fintek_match(struct device *, void *, void *);
   46 void    fintek_attach(struct device *, struct device *, void *);
   47 
   48 void    fintek_refresh(void *);
   49 int     fintek_read_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
   50             size_t size);
   51 int     fintek_write_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
   52             size_t size);
   53 void    fintek_fullspeed(struct fintek_softc *sc);
   54 
   55 struct cfattach fintek_ca = {
   56         sizeof(struct fintek_softc), fintek_match, fintek_attach
   57 };
   58 
   59 struct cfdriver fintek_cd = {
   60         NULL, "fintek", DV_DULL
   61 };
   62 
   63 #define FINTEK_CONFIG1          0x01
   64 #define  FINTEK_FAN1_LINEAR_MODE        0x10
   65 #define  FINTEK_FAN2_LINEAR_MODE        0x20
   66 #define FINTEK_VOLT0            0x10
   67 #define FINTEK_VOLT1            0x11
   68 #define FINTEK_VOLT2            0x12
   69 #define FINTEK_VOLT3            0x13
   70 #define FINTEK_TEMP1            0x14
   71 #define FINTEK_TEMP2            0x15
   72 #define FINTEK_FAN1             0x16
   73 #define FINTEK_FAN2             0x18
   74 #define FINTEK_VERSION          0x5c
   75 #define FINTEK_RSTCR            0x60
   76 #define  FINTEK_FAN1_MODE_MANUAL        0x30
   77 #define  FINTEK_FAN2_MODE_MANUAL        0xc0
   78 #define FINTEK_PWM_DUTY1        0x76
   79 #define FINTEK_PWM_DUTY2        0x86
   80 
   81 /* Options passed via the 'flags' config keyword. */
   82 #define FINTEK_OPTION_FULLSPEED 0x0001
   83 
   84 int
   85 fintek_match(struct device *parent, void *match, void *aux)
   86 {
   87         struct i2c_attach_args *ia = aux;
   88 
   89         if (strcmp(ia->ia_name, "f75375") == 0)
   90                 return (1);
   91         return (0);
   92 }
   93 
   94 int
   95 fintek_read_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
   96     size_t size)
   97 {
   98         return iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
   99             sc->sc_addr, &cmd, sizeof cmd, data, size, 0);
  100 }
  101 
  102 int
  103 fintek_write_reg(struct fintek_softc *sc, u_int8_t cmd, u_int8_t *data,
  104     size_t size)
  105 {
  106         return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
  107             sc->sc_addr, &cmd, sizeof cmd, data, size, 0);
  108 }
  109 
  110 void
  111 fintek_attach(struct device *parent, struct device *self, void *aux)
  112 {
  113         struct fintek_softc *sc = (struct fintek_softc *)self;
  114         struct i2c_attach_args *ia = aux;
  115         u_int8_t cmd, data;
  116         int i;
  117 
  118         sc->sc_tag = ia->ia_tag;
  119         sc->sc_addr = ia->ia_addr;
  120 
  121         iic_acquire_bus(sc->sc_tag, 0);
  122 
  123         cmd = FINTEK_VERSION;
  124         if (fintek_read_reg(sc, cmd, &data, sizeof data))
  125                 goto failread;
  126 
  127         printf(": F75375 rev %d.%d", data>> 4, data & 0xf);
  128 
  129         /*
  130          * It seems the fan in the Thecus n2100 doesn't provide a
  131          * reliable fan count.  As a result the automatic fan
  132          * controlling mode that the chip comes up in after reset
  133          * doesn't work reliably.  So we have a flag to drive the fan
  134          * at maximum voltage such that the box doesn't overheat.
  135          */
  136         if (sc->sc_dev.dv_cfdata->cf_flags & FINTEK_OPTION_FULLSPEED)
  137                 fintek_fullspeed(sc);
  138 
  139         iic_release_bus(sc->sc_tag, 0);
  140 
  141         strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
  142             sizeof(sc->sc_sensordev.xname));
  143 
  144         sc->sc_sensor[F_VCC].type = SENSOR_VOLTS_DC;
  145         strlcpy(sc->sc_sensor[F_VCC].desc, "Vcc",
  146             sizeof(sc->sc_sensor[F_VCC].desc));
  147 
  148         sc->sc_sensor[F_V1].type = SENSOR_VOLTS_DC;
  149         sc->sc_sensor[F_V2].type = SENSOR_VOLTS_DC;
  150         sc->sc_sensor[F_V3].type = SENSOR_VOLTS_DC;
  151 
  152         sc->sc_sensor[F_TEMP1].type = SENSOR_TEMP;
  153         sc->sc_sensor[F_TEMP2].type = SENSOR_TEMP;
  154 
  155         sc->sc_sensor[F_FAN1].type = SENSOR_FANRPM;
  156         sc->sc_sensor[F_FAN2].type = SENSOR_FANRPM;
  157 
  158         if (sensor_task_register(sc, fintek_refresh, 5) == NULL) {
  159                 printf(", unable to register update task\n");
  160                 return;
  161         }
  162 
  163         for (i = 0; i < F_NUM_SENSORS; i++) {
  164                 sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
  165                 sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
  166         }
  167         sensordev_install(&sc->sc_sensordev);
  168 
  169         printf("\n");
  170         return;
  171 
  172 failread:
  173         printf("unable to read reg %d\n", cmd);
  174         iic_release_bus(sc->sc_tag, 0);
  175         return;
  176 }
  177 
  178 
  179 struct {
  180         char            sensor;
  181         u_int8_t        cmd;
  182 } fintek_worklist[] = {
  183         { F_VCC, FINTEK_VOLT0 },
  184         { F_V1, FINTEK_VOLT1 },
  185         { F_V2, FINTEK_VOLT2 },
  186         { F_V3, FINTEK_VOLT3 },
  187         { F_TEMP1, FINTEK_TEMP1 },
  188         { F_TEMP2, FINTEK_TEMP2 },
  189         { F_FAN1, FINTEK_FAN1 },
  190         { F_FAN2, FINTEK_FAN2 }
  191 };
  192 #define FINTEK_WORKLIST_SZ (sizeof(fintek_worklist) / sizeof(fintek_worklist[0]))
  193 
  194 void
  195 fintek_refresh(void *arg)
  196 {
  197         struct fintek_softc *sc =  arg;
  198         u_int8_t cmd, data, data2;
  199         int i;
  200 
  201         iic_acquire_bus(sc->sc_tag, 0);
  202 
  203         for (i = 0; i < FINTEK_WORKLIST_SZ; i++){
  204                 cmd = fintek_worklist[i].cmd;
  205                 if (fintek_read_reg(sc, cmd, &data, sizeof data)) {
  206                         sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  207                         continue;
  208                 }
  209                 sc->sc_sensor[i].flags &= ~SENSOR_FINVALID;
  210                 switch (fintek_worklist[i].sensor) {
  211                 case  F_VCC:
  212                         sc->sc_sensor[i].value = data * 16000;
  213                         break;
  214                 case  F_V1:
  215                         /* FALLTHROUGH */
  216                 case  F_V2:
  217                         /* FALLTHROUGH */
  218                 case  F_V3:
  219                         sc->sc_sensor[i].value = data * 8000;
  220                         break;
  221                 case  F_TEMP1:
  222                         /* FALLTHROUGH */
  223                 case  F_TEMP2:
  224                         sc->sc_sensor[i].value = 273150000 + data * 1000000;
  225                         break;
  226                 case  F_FAN1:
  227                         /* FALLTHROUGH */
  228                 case  F_FAN2:
  229                         /* FANx LSB follows FANx MSB */
  230                         cmd = fintek_worklist[i].cmd + 1;
  231                         if (fintek_read_reg(sc, cmd, &data2, sizeof data2)) {
  232                                 sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  233                                 continue;
  234                         }
  235                         if ((data == 0xff && data2 == 0xff) ||
  236                             (data == 0 && data2 == 0))
  237                                 sc->sc_sensor[i].value = 0;
  238                         else
  239                                 sc->sc_sensor[i].value = 1500000 /
  240                                     (data << 8 | data2);
  241                         break;
  242                 default:
  243                         sc->sc_sensor[i].flags |= SENSOR_FINVALID;
  244                         break;
  245                 }
  246         }
  247 
  248         iic_release_bus(sc->sc_tag, 0);
  249 }
  250 
  251 void
  252 fintek_fullspeed(struct fintek_softc *sc)
  253 {
  254         u_int8_t data;
  255 
  256         data = FINTEK_FAN1_LINEAR_MODE | FINTEK_FAN2_LINEAR_MODE;
  257         fintek_write_reg(sc, FINTEK_CONFIG1, &data, sizeof data);
  258 
  259         data = FINTEK_FAN1_MODE_MANUAL | FINTEK_FAN2_MODE_MANUAL;
  260         fintek_write_reg(sc, FINTEK_RSTCR, &data, sizeof data);
  261 
  262         data = 0xff;            /* Maximum voltage */
  263         fintek_write_reg(sc, FINTEK_PWM_DUTY1, &data, sizeof data);
  264         fintek_write_reg(sc, FINTEK_PWM_DUTY2, &data, sizeof data);
  265 }       

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