[BACK]Return to w83l784r.c CVS log [TXT][DIR] Up to [local] / sys / dev / i2c

Annotation of sys/dev/i2c/w83l784r.c, Revision 1.1

1.1     ! nbrk        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: }

CVSweb