[BACK]Return to pcf8591_ofw.c CVS log [TXT][DIR] Up to [local] / sys / arch / sparc64 / dev

Annotation of sys/arch/sparc64/dev/pcf8591_ofw.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pcf8591_ofw.c,v 1.4 2007/06/24 05:34:35 dlg Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2006 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/ofw/openfirm.h>
        !            25: #include <dev/i2c/i2cvar.h>
        !            26:
        !            27: #define PCF8591_CHANNELS       4
        !            28:
        !            29: struct pcfadc_channel {
        !            30:        u_int           chan_num;
        !            31:        struct ksensor  chan_sensor;
        !            32: };
        !            33:
        !            34: struct pcfadc_softc {
        !            35:        struct device           sc_dev;
        !            36:        i2c_tag_t               sc_tag;
        !            37:        i2c_addr_t              sc_addr;
        !            38:        u_char                  sc_xlate[256];
        !            39:        u_int                   sc_nchan;
        !            40:        struct pcfadc_channel   sc_channels[PCF8591_CHANNELS];
        !            41:        struct ksensordev       sc_sensordev;
        !            42: };
        !            43:
        !            44: int    pcfadc_match(struct device *, void *, void *);
        !            45: void   pcfadc_attach(struct device *, struct device *, void *);
        !            46: void   pcfadc_refresh(void *);
        !            47:
        !            48: struct cfattach pcfadc_ca = {
        !            49:        sizeof(struct pcfadc_softc), pcfadc_match, pcfadc_attach
        !            50: };
        !            51:
        !            52: struct cfdriver pcfadc_cd = {
        !            53:        NULL, "pcfadc", DV_DULL
        !            54: };
        !            55:
        !            56: int
        !            57: pcfadc_match(struct device *parent, void *match, void *aux)
        !            58: {
        !            59:        struct i2c_attach_args *ia = aux;
        !            60:
        !            61:        if (strcmp(ia->ia_name, "i2cpcf,8591") != 0)
        !            62:                return (0);
        !            63:
        !            64:        return (1);
        !            65: }
        !            66:
        !            67: void
        !            68: pcfadc_attach(struct device *parent, struct device *self, void *aux)
        !            69: {
        !            70:        struct pcfadc_softc *sc = (struct pcfadc_softc *)self;
        !            71:        u_char chanuse[PCF8591_CHANNELS * 4], desc[PCF8591_CHANNELS * 32];
        !            72:        u_char *cp;
        !            73:        u_int8_t junk[PCF8591_CHANNELS + 1];
        !            74:        u_int32_t transinfo[PCF8591_CHANNELS * 4];
        !            75:        struct i2c_attach_args *ia = aux;
        !            76:        int dlen, clen, tlen, node = *(int *)ia->ia_cookie;
        !            77:        u_int i;
        !            78:
        !            79:        if ((dlen = OF_getprop(node, "channels-description", desc,
        !            80:            sizeof(desc))) < 0) {
        !            81:                printf(": couldn't find \"channels-description\" property\n");
        !            82:                return;
        !            83:        }
        !            84:        if (dlen > sizeof(desc) || desc[dlen - 1] != '\0') {
        !            85:                printf(": bad \"channels-description\" property\n");
        !            86:                return;
        !            87:        }
        !            88:        if ((clen = OF_getprop(node, "channels-in-use", chanuse,
        !            89:            sizeof(chanuse))) < 0) {
        !            90:                printf(": couldn't find \"channels-in-use\" property\n");
        !            91:                return;
        !            92:        }
        !            93:        if ((clen % 4) != 0) {
        !            94:                printf(": invalid \"channels-in-use\" length %d\n", clen);
        !            95:                return;
        !            96:        }
        !            97:        sc->sc_nchan = clen / 4;
        !            98:        if (sc->sc_nchan > PCF8591_CHANNELS) {
        !            99:                printf(": invalid number of channels (%d)\n", sc->sc_nchan);
        !           100:                return;
        !           101:        }
        !           102:
        !           103:        if ((tlen = OF_getprop(node, "tables", sc->sc_xlate,
        !           104:            sizeof(sc->sc_xlate))) < 0) {
        !           105:                printf(": couldn't find \"tables\" property\n");
        !           106:                return;
        !           107:        }
        !           108:        /* We only support complete, single width tables */
        !           109:        if (tlen != 256) {
        !           110:                printf(": invalid \"tables\" length %d\n", tlen);
        !           111:                return;
        !           112:        }
        !           113:
        !           114:        if ((tlen = OF_getprop(node, "translation", transinfo,
        !           115:            sizeof(transinfo))) < 0) {
        !           116:                printf(": couldn't find \"translation\" property\n");
        !           117:                return;
        !           118:        }
        !           119:        if (tlen != (sc->sc_nchan * 4 * 4)) {
        !           120:                printf(": invalid \"translation\" length %d\n", tlen);
        !           121:                return;
        !           122:        }
        !           123:
        !           124:        cp = desc;
        !           125:        for (i = 0; i < sc->sc_nchan; i++) {
        !           126:                struct pcfadc_channel *chp = &sc->sc_channels[i];
        !           127:
        !           128:                chp->chan_sensor.type = SENSOR_TEMP;
        !           129:
        !           130:                if (cp >= desc + dlen) {
        !           131:                        printf(": invalid \"channels-description\"\n");
        !           132:                        return;
        !           133:                }
        !           134:                strlcpy(chp->chan_sensor.desc, cp,
        !           135:                    sizeof(chp->chan_sensor.desc));
        !           136:                cp += strlen(cp) + 1;
        !           137:
        !           138:                /*
        !           139:                 * We only support input temperature channels, with
        !           140:                 * valid channel numbers, and basic (unscaled) translation
        !           141:                 *
        !           142:                 * XXX TODO: support voltage (type 2) channels and type 4
        !           143:                 * (scaled) translation tables
        !           144:                 */
        !           145:                if (chanuse[(i * 4)] > PCF8591_CHANNELS || /* channel # */
        !           146:                    chanuse[(i * 4) + 1] != 0 ||        /* dir == input */
        !           147:                    chanuse[(i * 4) + 2] != 1 ||        /* type == temp */
        !           148:                    transinfo[(i * 4)] != 3 ||          /* xlate == table */
        !           149:                    transinfo[(i * 4) + 2] != 0 ||      /* no xlate offset */
        !           150:                    transinfo[(i * 4) + 3] != 0x100) {  /* xlate tbl length */
        !           151:                        printf(": unsupported sensor %d\n", i);
        !           152:                        return;
        !           153:                }
        !           154:                chp->chan_num = chanuse[(i * 4)];
        !           155:        }
        !           156:
        !           157:        sc->sc_tag = ia->ia_tag;
        !           158:        sc->sc_addr = ia->ia_addr;
        !           159:
        !           160:        iic_acquire_bus(sc->sc_tag, 0);
        !           161:
        !           162:        /* Try a read now, so we can fail if it doesn't work */
        !           163:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
        !           164:            NULL, 0, junk, sc->sc_nchan + 1, 0)) {
        !           165:                printf(": read failed\n");
        !           166:                iic_release_bus(sc->sc_tag, 0);
        !           167:                return;
        !           168:        }
        !           169:
        !           170:        iic_release_bus(sc->sc_tag, 0);
        !           171:
        !           172:        /* Initialize sensor data. */
        !           173:        strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
        !           174:            sizeof(sc->sc_sensordev.xname));
        !           175:
        !           176:        for (i = 0; i < sc->sc_nchan; i++)
        !           177:                if (!(sc->sc_channels[i].chan_sensor.flags & SENSOR_FINVALID))
        !           178:                        sensor_attach(&sc->sc_sensordev,
        !           179:                            &sc->sc_channels[i].chan_sensor);
        !           180:
        !           181:        if (sensor_task_register(sc, pcfadc_refresh, 5) == NULL) {
        !           182:                printf(": unable to register update task\n");
        !           183:                return;
        !           184:        }
        !           185:
        !           186:        sensordev_install(&sc->sc_sensordev);
        !           187:
        !           188:        printf("\n");
        !           189: }
        !           190:
        !           191: void
        !           192: pcfadc_refresh(void *arg)
        !           193: {
        !           194:        struct pcfadc_softc *sc = arg;
        !           195:        u_int i;
        !           196:        u_int8_t data[PCF8591_CHANNELS + 1];
        !           197:
        !           198:        iic_acquire_bus(sc->sc_tag, 0);
        !           199:        /* NB: first byte out is stale, so read num_channels + 1 */
        !           200:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
        !           201:            NULL, 0, data, PCF8591_CHANNELS + 1, 0)) {
        !           202:                iic_release_bus(sc->sc_tag, 0);
        !           203:                return;
        !           204:        }
        !           205:        iic_release_bus(sc->sc_tag, 0);
        !           206:
        !           207:        /* XXX: so far this only supports temperature channels */
        !           208:        for (i = 0; i < sc->sc_nchan; i++) {
        !           209:                struct pcfadc_channel *chp = &sc->sc_channels[i];
        !           210:
        !           211:                if ((chp->chan_sensor.flags & SENSOR_FINVALID) != 0)
        !           212:                        continue;
        !           213:                chp->chan_sensor.value = 273150000 + 1000000 *
        !           214:                    sc->sc_xlate[data[1 + chp->chan_num]];
        !           215:        }
        !           216: }
        !           217:

CVSweb