[BACK]Return to si70xx.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / i2c

Annotation of src/sys/dev/i2c/si70xx.c, Revision 1.6.4.1

1.6.4.1 ! thorpej     1: /*     $NetBSD: si70xx.c,v 1.7 2021/06/15 04:39:49 mlelstv Exp $       */
1.1       christos    2:
                      3: /*
                      4:  * Copyright (c) 2017 Brad Spencer <brad@anduin.eldar.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/cdefs.h>
1.6.4.1 ! thorpej    20: __KERNEL_RCSID(0, "$NetBSD: si70xx.c,v 1.7 2021/06/15 04:39:49 mlelstv Exp $");
1.1       christos   21:
                     22: /*
                     23:   Driver for the Silicon Labs SI7013/SI7020/SI7021
                     24: */
                     25:
                     26: #include <sys/param.h>
                     27: #include <sys/systm.h>
                     28: #include <sys/kernel.h>
                     29: #include <sys/device.h>
                     30: #include <sys/module.h>
                     31: #include <sys/sysctl.h>
                     32: #include <sys/mutex.h>
                     33:
                     34: #include <dev/sysmon/sysmonvar.h>
                     35: #include <dev/i2c/i2cvar.h>
                     36: #include <dev/i2c/si70xxreg.h>
                     37: #include <dev/i2c/si70xxvar.h>
                     38:
                     39:
                     40: static uint8_t         si70xx_crc(uint8_t *, size_t);
                     41: static int     si70xx_poke(i2c_tag_t, i2c_addr_t, bool);
                     42: static int     si70xx_match(device_t, cfdata_t, void *);
                     43: static void    si70xx_attach(device_t, device_t, void *);
                     44: static int     si70xx_detach(device_t, int);
                     45: static void    si70xx_refresh(struct sysmon_envsys *, envsys_data_t *);
                     46: static int     si70xx_update_status(struct si70xx_sc *);
                     47: static int     si70xx_set_heateron(struct si70xx_sc *);
                     48: static int     si70xx_set_resolution(struct si70xx_sc *, size_t);
                     49: static int     si70xx_set_heatervalue(struct si70xx_sc *, size_t);
                     50: static int     si70xx_verify_sysctl(SYSCTLFN_ARGS);
                     51: static int     si70xx_verify_sysctl_resolution(SYSCTLFN_ARGS);
                     52: static int     si70xx_verify_sysctl_heateron(SYSCTLFN_ARGS);
                     53: static int     si70xx_verify_sysctl_heatervalue(SYSCTLFN_ARGS);
                     54:
                     55: #define SI70XX_DEBUG
                     56: #ifdef SI70XX_DEBUG
                     57: #define DPRINTF(s, l, x) \
                     58:     do { \
                     59:        if (l <= s->sc_si70xxdebug) \
                     60:            printf x; \
                     61:     } while (/*CONSTCOND*/0)
                     62: #else
                     63: #define DPRINTF(s, l, x)
                     64: #endif
                     65:
                     66: CFATTACH_DECL_NEW(si70xxtemp, sizeof(struct si70xx_sc),
                     67:     si70xx_match, si70xx_attach, si70xx_detach, NULL);
                     68:
                     69: static struct si70xx_sensor si70xx_sensors[] = {
                     70:        {
                     71:                .desc = "humidity",
                     72:                .type = ENVSYS_SRELHUMIDITY,
                     73:        },
                     74:        {
                     75:                .desc = "temperature",
                     76:                .type = ENVSYS_STEMP,
                     77:        }
                     78: };
                     79:
                     80: static struct si70xx_resolution si70xx_resolutions[] = {
                     81:        {
                     82:                .text = "12bit/14bit",
                     83:                .num = 0x00,
                     84:        },
                     85:        {
                     86:                .text = "8bit/12bit",
                     87:                .num = 0x01,
                     88:        },
                     89:        {
                     90:                .text = "10bit/13bit",
                     91:                .num = 0x80,
                     92:        },
                     93:        {
                     94:                .text = "11bit/11bit",
                     95:                .num = 0x81,
                     96:        }
                     97: };
                     98:
                     99: static const char si70xx_resolution_names[] =
                    100:     "12bit/14bit, 8bit/12bit, 10bit/13bit, 11bit/11bit";
                    101:
                    102: static const int si70xx_heatervalues[] = {
                    103:     0xdeadbeef, 0x00, 0x01, 0x02, 0x04, 0x08, 0x0f
                    104: };
                    105:
                    106: int
                    107: si70xx_verify_sysctl(SYSCTLFN_ARGS)
                    108: {
                    109:        int error, t;
                    110:        struct sysctlnode node;
                    111:
                    112:        node = *rnode;
                    113:        t = *(int *)rnode->sysctl_data;
                    114:        node.sysctl_data = &t;
                    115:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
                    116:        if (error || newp == NULL)
                    117:                return error;
                    118:
                    119:        if (t < 0)
                    120:                return EINVAL;
                    121:
                    122:        *(int *)rnode->sysctl_data = t;
                    123:
                    124:        return 0;
                    125: }
                    126:
                    127: int
                    128: si70xx_verify_sysctl_resolution(SYSCTLFN_ARGS)
                    129: {
                    130:        char buf[SI70XX_RES_NAME];
                    131:        struct si70xx_sc *sc;
                    132:        struct sysctlnode node;
                    133:        int error = 0;
                    134:        size_t i;
                    135:
                    136:        node = *rnode;
                    137:        sc = node.sysctl_data;
                    138:        (void) memcpy(buf, sc->sc_resolution, SI70XX_RES_NAME);
                    139:        node.sysctl_data = buf;
                    140:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
                    141:        if (error || newp == NULL)
                    142:                return error;
                    143:
                    144:        for (i = 0; i < __arraycount(si70xx_resolutions); i++) {
                    145:                if (memcmp(node.sysctl_data, si70xx_resolutions[i].text,
                    146:                    SI70XX_RES_NAME) == 0)
                    147:                        break;
                    148:        }
                    149:
                    150:        if (i == __arraycount(si70xx_resolutions))
                    151:                return EINVAL;
                    152:        (void) memcpy(sc->sc_resolution, node.sysctl_data, SI70XX_RES_NAME);
                    153:
                    154:        error = si70xx_set_resolution(sc, i);
                    155:
                    156:        return error;
                    157: }
                    158:
                    159: int
                    160: si70xx_verify_sysctl_heateron(SYSCTLFN_ARGS)
                    161: {
                    162:        int             error;
                    163:        bool            t;
                    164:        struct si70xx_sc *sc;
                    165:        struct sysctlnode node;
                    166:
                    167:        node = *rnode;
                    168:        sc = node.sysctl_data;
                    169:        t = sc->sc_heateron;
                    170:        node.sysctl_data = &t;
                    171:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
                    172:        if (error || newp == NULL)
                    173:                return error;
                    174:
                    175:        sc->sc_heateron = t;
                    176:        error = si70xx_set_heateron(sc);
                    177:
                    178:        return error;
                    179: }
                    180:
                    181: int
                    182: si70xx_verify_sysctl_heatervalue(SYSCTLFN_ARGS)
                    183: {
                    184:        int             error = 0, t;
                    185:        struct si70xx_sc *sc;
                    186:        struct sysctlnode node;
                    187:
                    188:        node = *rnode;
                    189:        sc = node.sysctl_data;
                    190:        t = sc->sc_heaterval;
                    191:        node.sysctl_data = &t;
                    192:        error = sysctl_lookup(SYSCTLFN_CALL(&node));
                    193:        if (error || newp == NULL)
                    194:                return (error);
                    195:
                    196:        if (t < 1 || t >= __arraycount(si70xx_heatervalues))
                    197:                return (EINVAL);
                    198:
                    199:        sc->sc_heaterval = t;
                    200:        error = si70xx_set_heatervalue(sc, t);
                    201:
                    202:        return error;
                    203: }
                    204:
1.3       christos  205: static uint8_t
                    206: si70xx_dir(uint8_t cmd, size_t len)
1.1       christos  207: {
1.3       christos  208:        switch (cmd) {
1.1       christos  209:        case SI70XX_READ_USER_REG_1:
                    210:        case SI70XX_READ_HEATER_REG:
                    211:        case SI70XX_READ_ID_PT1A:
                    212:        case SI70XX_READ_ID_PT1B:
                    213:        case SI70XX_READ_ID_PT2A:
                    214:        case SI70XX_READ_ID_PT2B:
                    215:        case SI70XX_READ_FW_VERA:
                    216:        case SI70XX_READ_FW_VERB:
1.3       christos  217:                return I2C_OP_READ_WITH_STOP;
1.1       christos  218:        case SI70XX_WRITE_USER_REG_1:
                    219:        case SI70XX_WRITE_HEATER_REG:
                    220:        case SI70XX_RESET:
1.3       christos  221:                return I2C_OP_WRITE_WITH_STOP;
1.1       christos  222:        case SI70XX_MEASURE_RH_NOHOLD:
                    223:        case SI70XX_MEASURE_TEMP_NOHOLD:
1.3       christos  224:                return len == 0 ? I2C_OP_READ : I2C_OP_READ_WITH_STOP;
1.1       christos  225:        default:
1.3       christos  226:                panic("%s: bad command %#x\n", __func__, cmd);
                    227:                return 0;
1.1       christos  228:        }
1.3       christos  229: }
                    230:
                    231: static int
                    232: si70xx_cmd(i2c_tag_t tag, i2c_addr_t addr, uint8_t *cmd,
                    233:     uint8_t clen, uint8_t *buf, size_t blen)
                    234: {
                    235:        uint8_t dir;
                    236:        if (clen == 0)
                    237:                dir = blen == 0 ? I2C_OP_READ : I2C_OP_READ_WITH_STOP;
                    238:        else
                    239:                dir = si70xx_dir(cmd[0], blen);
                    240:
                    241:        if (dir == I2C_OP_READ || dir == I2C_OP_READ_WITH_STOP)
                    242:                memset(buf, 0, blen);
1.1       christos  243:
                    244:        return iic_exec(tag, dir, addr, cmd, clen, buf, blen, 0);
                    245: }
                    246:
                    247: static int
                    248: si70xx_cmd0(struct si70xx_sc *sc, uint8_t *buf, size_t blen)
                    249: {
                    250:        return si70xx_cmd(sc->sc_tag, sc->sc_addr, NULL, 0, buf, blen);
                    251: }
                    252:
                    253: static int
                    254: si70xx_cmd1(struct si70xx_sc *sc, uint8_t cmd, uint8_t *buf, size_t blen)
                    255: {
                    256:        return si70xx_cmd(sc->sc_tag, sc->sc_addr, &cmd, 1, buf, blen);
                    257: }
                    258:
                    259: static int
                    260: si70xx_cmd2(struct si70xx_sc *sc, uint8_t cmd1, uint8_t cmd2, uint8_t *buf,
                    261:     size_t blen)
                    262: {
                    263:        uint8_t cmd[] = { cmd1, cmd2 };
                    264:        return si70xx_cmd(sc->sc_tag, sc->sc_addr, cmd, __arraycount(cmd),
                    265:            buf, blen);
                    266: }
                    267:
                    268: static int
                    269: si70xx_set_heateron(struct si70xx_sc * sc)
                    270: {
                    271:        int error;
                    272:        uint8_t userregister;
                    273:
                    274:        error = iic_acquire_bus(sc->sc_tag, 0);
                    275:        if (error) {
                    276:                DPRINTF(sc, 2, ("%s:%s: Failed to acquire bus: %d\n",
                    277:                    device_xname(sc->sc_dev), __func__, error));
                    278:                return error;
                    279:        }
                    280:
                    281:        error = si70xx_cmd1(sc, SI70XX_READ_USER_REG_1, &userregister, 1);
                    282:        if (error) {
                    283:                DPRINTF(sc, 2, ("%s: Failed to read user register 1: %d\n",
                    284:                    device_xname(sc->sc_dev), error));
                    285:                goto out;
                    286:        }
                    287:
                    288:        DPRINTF(sc, 2, ("%s:%s: reg 1 values before: %#x\n",
                    289:            device_xname(sc->sc_dev), __func__, userregister));
                    290:        if (sc->sc_heateron) {
                    291:                userregister |= SI70XX_HTRE_MASK;
                    292:        } else {
                    293:                userregister &= ~SI70XX_HTRE_MASK;
                    294:        }
                    295:        DPRINTF(sc, 2, ("%s:%s: user reg 1 values after: %#x\n",
                    296:            device_xname(sc->sc_dev), __func__, userregister));
                    297:
                    298:        error = si70xx_cmd1(sc, SI70XX_WRITE_USER_REG_1, &userregister, 1);
                    299:        if (error) {
                    300:                DPRINTF(sc, 2, ("%s: Failed to write user register 1: %d\n",
                    301:                    device_xname(sc->sc_dev), error));
                    302:        }
                    303: out:
                    304:        iic_release_bus(sc->sc_tag, 0);
                    305:        return error;
                    306: }
                    307:
                    308: static int
                    309: si70xx_set_resolution(struct si70xx_sc * sc, size_t index)
                    310: {
                    311:        int error;
                    312:        uint8_t userregister;
                    313:
                    314:        error = iic_acquire_bus(sc->sc_tag, 0);
                    315:        if (error) {
                    316:                DPRINTF(sc, 2, ("%s: Failed to acquire bus: %d\n",
                    317:                    device_xname(sc->sc_dev), error));
                    318:                return error;
                    319:        }
                    320:
                    321:        error = si70xx_cmd1(sc, SI70XX_READ_USER_REG_1, &userregister, 1);
                    322:        if (error) {
                    323:                DPRINTF(sc, 2, ("%s: Failed to read user register 1: %d\n",
                    324:                    device_xname(sc->sc_dev), error));
                    325:                goto out;
                    326:        }
                    327:
                    328:        DPRINTF(sc, 2, ("%s:%s: reg 1 values before: %#x\n",
                    329:            device_xname(sc->sc_dev), __func__, userregister));
                    330:        userregister &= (~SI70XX_RESOLUTION_MASK);
                    331:        userregister |= si70xx_resolutions[index].num;
                    332:        DPRINTF(sc, 2, ("%s:%s: reg 1 values after: %#x\n",
                    333:            device_xname(sc->sc_dev), __func__, userregister));
                    334:
                    335:        error = si70xx_cmd1(sc, SI70XX_WRITE_USER_REG_1, &userregister, 1);
                    336:        if (error) {
                    337:                DPRINTF(sc, 2, ("%s: Failed to write user register 1: %d\n",
                    338:                    device_xname(sc->sc_dev), error));
                    339:        }
                    340: out:
                    341:        iic_release_bus(sc->sc_tag, 0);
                    342:        return error;
                    343: }
                    344:
                    345: static int
                    346: si70xx_set_heatervalue(struct si70xx_sc * sc, size_t index)
                    347: {
                    348:        int error;
                    349:        uint8_t heaterregister;
                    350:
                    351:        error = iic_acquire_bus(sc->sc_tag, 0);
                    352:        if (error) {
                    353:                DPRINTF(sc, 2, ("%s: Failed to acquire bus: %d\n",
                    354:                    device_xname(sc->sc_dev), error));
                    355:                return error;
                    356:        }
                    357:        error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1);
                    358:        if (error) {
                    359:                DPRINTF(sc, 2, ("%s: Failed to read heater register: %d\n",
                    360:                    device_xname(sc->sc_dev), error));
                    361:                goto out;
                    362:        }
                    363:
                    364:        DPRINTF(sc, 2, ("%s:%s: heater values before: %#x\n",
                    365:            device_xname(sc->sc_dev), __func__, heaterregister));
                    366:        heaterregister &= ~SI70XX_HEATER_MASK;
                    367:        heaterregister |= si70xx_heatervalues[index];
                    368:        DPRINTF(sc, 2, ("%s:%s: heater values after: %#x\n",
                    369:            device_xname(sc->sc_dev), __func__, heaterregister));
                    370:
1.3       christos  371:        error = si70xx_cmd1(sc, SI70XX_WRITE_HEATER_REG, &heaterregister, 1);
1.1       christos  372:        if (error) {
                    373:                DPRINTF(sc, 2, ("%s: Failed to write heater register: %d\n",
                    374:                    device_xname(sc->sc_dev), error));
                    375:        }
                    376: out:
                    377:        iic_release_bus(sc->sc_tag, 0);
                    378:        return error;
                    379: }
                    380:
                    381: static int
                    382: si70xx_update_heater(struct si70xx_sc *sc)
                    383: {
                    384:        size_t i;
                    385:        int error;
                    386:        uint8_t heaterregister;
                    387:
                    388:        error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1);
                    389:        if (error) {
                    390:                DPRINTF(sc, 2, ("%s: Failed to read heater register: %d\n",
                    391:                    device_xname(sc->sc_dev), error));
                    392:                return error;
                    393:        }
                    394:
                    395:        DPRINTF(sc, 2, ("%s: read heater reg values: %02x\n",
                    396:            device_xname(sc->sc_dev), heaterregister));
                    397:
                    398:        uint8_t heat = heaterregister & SI70XX_HEATER_MASK;
                    399:        for (i = 0; i < __arraycount(si70xx_heatervalues); i++) {
                    400:                if (si70xx_heatervalues[i] == heat)
                    401:                        break;
                    402:        }
                    403:        sc->sc_heaterval = i != __arraycount(si70xx_heatervalues) ? i : 0;
                    404:        return 0;
                    405: }
                    406:
                    407: static int
                    408: si70xx_update_user(struct si70xx_sc *sc)
                    409: {
                    410:        size_t i;
                    411:        int error;
                    412:        uint8_t userregister;
                    413:
                    414:        error = si70xx_cmd1(sc, SI70XX_READ_USER_REG_1, &userregister, 1);
                    415:        if (error) {
                    416:                DPRINTF(sc, 2, ("%s: Failed to read user register 1: %d\n",
                    417:                    device_xname(sc->sc_dev), error));
                    418:                return error;
                    419:        }
                    420:        DPRINTF(sc, 2, ("%s: read user reg 1 values: %#x\n",
                    421:            device_xname(sc->sc_dev), userregister));
                    422:
                    423:        uint8_t res = userregister & SI70XX_RESOLUTION_MASK;
                    424:        for (i = 0; i < __arraycount(si70xx_resolutions); i++) {
                    425:                if (si70xx_resolutions[i].num == res)
                    426:                        break;
                    427:        }
                    428:
                    429:        if (i != __arraycount(si70xx_resolutions)) {
                    430:                memcpy(sc->sc_resolution, si70xx_resolutions[i].text,
                    431:                    SI70XX_RES_NAME);
                    432:        } else {
                    433:                snprintf(sc->sc_resolution, SI70XX_RES_NAME, "%02x", res);
                    434:        }
                    435:
                    436:        sc->sc_vddok = (userregister & SI70XX_VDDS_MASK) == 0;
                    437:        sc->sc_heaterval = userregister & SI70XX_HTRE_MASK;
                    438:        return 0;
                    439: }
                    440:
                    441: static int
                    442: si70xx_update_status(struct si70xx_sc *sc)
                    443: {
                    444:        int error1 = si70xx_update_user(sc);
                    445:        int error2 = si70xx_update_heater(sc);
                    446:        return error1 ? error1 : error2;
                    447: }
                    448:
                    449: static uint8_t
                    450: si70xx_crc(uint8_t * data, size_t size)
                    451: {
                    452:        uint8_t crc = 0;
                    453:
                    454:        for (size_t i = 0; i < size; i++) {
                    455:                crc ^= data[i];
                    456:                for (size_t j = 8; j > 0; j--) {
                    457:                        if (crc & 0x80)
                    458:                                crc = (crc << 1) ^ 0x131;
                    459:                        else
                    460:                                crc <<= 1;
                    461:                }
                    462:        }
                    463:        return crc;
                    464: }
                    465:
                    466: static int
                    467: si70xx_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
                    468: {
                    469:        uint8_t reg = SI70XX_READ_USER_REG_1;
                    470:        uint8_t buf;
                    471:        int error;
                    472:
                    473:        error = si70xx_cmd(tag, addr, &reg, 1, &buf, 1);
                    474:        if (matchdebug) {
                    475:                printf("poke X 1: %d\n", error);
                    476:        }
                    477:        return error;
                    478: }
                    479:
                    480: static int
                    481: si70xx_sysctl_init(struct si70xx_sc *sc)
                    482: {
                    483:        int error;
                    484:        const struct sysctlnode *cnode;
                    485:        int sysctlroot_num;
                    486:
                    487:        if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    488:            0, CTLTYPE_NODE, device_xname(sc->sc_dev),
                    489:            SYSCTL_DESCR("si70xx controls"), NULL, 0, NULL, 0, CTL_HW,
                    490:            CTL_CREATE, CTL_EOL)) != 0)
                    491:                return error;
                    492:
                    493:        sysctlroot_num = cnode->sysctl_num;
                    494:
                    495: #ifdef SI70XX_DEBUG
                    496:        if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    497:            CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
                    498:            SYSCTL_DESCR("Debug level"), si70xx_verify_sysctl, 0,
                    499:            &sc->sc_si70xxdebug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
                    500:            CTL_EOL)) != 0)
                    501:                return error;
                    502:
                    503: #endif
                    504:
                    505: #ifdef HAVE_I2C_EXECV
                    506:        if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    507:            CTLFLAG_READWRITE, CTLTYPE_INT, "clockstretch",
                    508:            SYSCTL_DESCR("Clockstretch value"), si70xx_verify_sysctl, 0,
                    509:            &sc->sc_clockstretch, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
                    510:            CTL_EOL)) != 0)
                    511:                return error;
                    512: #endif
                    513:
                    514:
                    515:        if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    516:            CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
                    517:            SYSCTL_DESCR("The number of times to attempt to read the values"),
                    518:            si70xx_verify_sysctl, 0, &sc->sc_readattempts, 0, CTL_HW,
                    519:            sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
                    520:                return error;
                    521:
                    522:
                    523:        if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    524:            CTLFLAG_READONLY, CTLTYPE_STRING, "resolutions",
                    525:            SYSCTL_DESCR("Valid resolutions"), 0, 0,
                    526:            __UNCONST(si70xx_resolution_names),
                    527:            sizeof(si70xx_resolution_names) + 1,
                    528:            CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
                    529:                return error;
                    530:
                    531:        if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    532:            CTLFLAG_READWRITE, CTLTYPE_STRING, "resolution",
                    533:            SYSCTL_DESCR("Resolution of RH and Temp"),
                    534:            si70xx_verify_sysctl_resolution, 0, (void *) sc,
                    535:            SI70XX_RES_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
                    536:                return error;
                    537:
                    538:        if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    539:            CTLFLAG_READWRITE, CTLTYPE_BOOL, "ignorecrc",
                    540:            SYSCTL_DESCR("Ignore the CRC byte"), NULL, 0, &sc->sc_ignorecrc,
                    541:            0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
                    542:                return error;
                    543:
                    544:        if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    545:            CTLFLAG_READONLY, CTLTYPE_BOOL, "vddok",
                    546:            SYSCTL_DESCR("Vdd at least 1.9v"), NULL, 0, &sc->sc_vddok, 0,
                    547:            CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
                    548:                return error;
                    549:
                    550:        if ((error = sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    551:            CTLFLAG_READWRITE, CTLTYPE_BOOL, "heateron",
                    552:            SYSCTL_DESCR("Heater on"), si70xx_verify_sysctl_heateron, 0,
                    553:            (void *)sc, 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
                    554:                return error;
                    555:
                    556:        return sysctl_createv(&sc->sc_si70xxlog, 0, NULL, &cnode,
                    557:            CTLFLAG_READWRITE, CTLTYPE_INT, "heaterstrength",
                    558:            SYSCTL_DESCR("Heater strength 1 to 6"),
                    559:            si70xx_verify_sysctl_heatervalue, 0, (void *)sc, 0, CTL_HW,
                    560:            sysctlroot_num, CTL_CREATE, CTL_EOL);
                    561: }
                    562:
                    563: static int
                    564: si70xx_match(device_t parent, cfdata_t match, void *aux)
                    565: {
1.4       thorpej   566:        struct i2c_attach_args *ia = aux;
                    567:        int error, match_result;
1.1       christos  568:        const bool matchdebug = false;
                    569:
1.4       thorpej   570:        if (iic_use_direct_match(ia, match, NULL, &match_result))
                    571:                return match_result;
1.1       christos  572:
1.4       thorpej   573:        /* indirect config - check for configured address */
                    574:        if (ia->ia_addr != SI70XX_TYPICAL_ADDR)
                    575:                return 0;
1.1       christos  576:
                    577:        /*
                    578:         * Check to see if something is really at this i2c address. This will
                    579:         * keep phantom devices from appearing
                    580:         */
                    581:        if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
                    582:                if (matchdebug)
                    583:                        printf("in match acquire bus failed\n");
                    584:                return 0;
                    585:        }
                    586:
                    587:        error = si70xx_poke(ia->ia_tag, ia->ia_addr, matchdebug);
                    588:        iic_release_bus(ia->ia_tag, 0);
                    589:
1.4       thorpej   590:        return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
1.1       christos  591: }
                    592:
                    593: static void
                    594: si70xx_attach(device_t parent, device_t self, void *aux)
                    595: {
                    596:        struct si70xx_sc *sc;
                    597:        struct i2c_attach_args *ia;
                    598:        int error, i;
                    599:        int ecount = 0;
                    600:        uint8_t buf[8];
                    601:        uint8_t testcrcpt1[4];
                    602:        uint8_t testcrcpt2[4];
                    603:        uint8_t crc1 = 0, crc2 = 0;
                    604:        uint8_t readcrc1 = 0, readcrc2 = 0;
                    605:        uint8_t fwversion, model;
                    606:
                    607:        ia = aux;
                    608:        sc = device_private(self);
                    609:
                    610:        sc->sc_dev = self;
                    611:        sc->sc_tag = ia->ia_tag;
                    612:        sc->sc_addr = ia->ia_addr;
                    613:        sc->sc_si70xxdebug = 0;
                    614: #ifdef HAVE_I2C_EXECV
                    615:        sc->sc_clockstretch = 2048;
                    616: #endif
1.3       christos  617:        sc->sc_readattempts = 25;
1.1       christos  618:        sc->sc_ignorecrc = false;
                    619:        sc->sc_sme = NULL;
                    620:
                    621:        aprint_normal("\n");
                    622:
                    623:        mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
                    624:        sc->sc_numsensors = __arraycount(si70xx_sensors);
                    625:
                    626:        if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
                    627:                aprint_error_dev(self,
                    628:                    "Unable to create sysmon structure\n");
                    629:                sc->sc_sme = NULL;
                    630:                return;
                    631:        }
                    632:        if ((error = si70xx_sysctl_init(sc)) != 0) {
                    633:                aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error);
                    634:                goto out;
                    635:        }
                    636:
                    637:        error = iic_acquire_bus(sc->sc_tag, 0);
                    638:        if (error) {
                    639:                aprint_error_dev(self, "Could not acquire iic bus: %d\n",
                    640:                    error);
                    641:                goto out;
                    642:        }
                    643:        error = si70xx_cmd1(sc, SI70XX_RESET, NULL, 0);
                    644:        if (error != 0)
                    645:                aprint_error_dev(self, "Reset failed: %d\n", error);
                    646:
                    647:        delay(15000);   /* 15 ms max */
                    648:
                    649:        error = si70xx_cmd2(sc, SI70XX_READ_ID_PT1A, SI70XX_READ_ID_PT1B,
                    650:            buf, 8);
                    651:        if (error) {
                    652:                aprint_error_dev(self, "Failed to read first part of ID: %d\n",
                    653:                    error);
                    654:                ecount++;
                    655:        }
                    656:        testcrcpt1[0] = buf[0];
                    657:        testcrcpt1[1] = buf[2];
                    658:        testcrcpt1[2] = buf[4];
                    659:        testcrcpt1[3] = buf[6];
                    660:        readcrc1 = buf[7];
                    661:        crc1 = si70xx_crc(testcrcpt1, 4);
                    662:
                    663:        DPRINTF(sc, 2, ("%s: read 1 values: %02x%02x%02x%02x%02x%02x%02x%02x "
                    664:            "- %02x\n", device_xname(sc->sc_dev), buf[0], buf[1],
                    665:            buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
                    666:            crc1));
                    667:
                    668:        error = si70xx_cmd2(sc, SI70XX_READ_ID_PT2A, SI70XX_READ_ID_PT2B,
                    669:            buf, 8);
                    670:        if (error != 0) {
                    671:                aprint_error_dev(self, "Failed to read second part of ID: %d\n",
                    672:                    error);
                    673:                ecount++;
                    674:        }
                    675:        model = testcrcpt2[0] = buf[0];
                    676:        testcrcpt2[1] = buf[1];
                    677:        testcrcpt2[2] = buf[3];
                    678:        testcrcpt2[3] = buf[4];
                    679:        readcrc2 = buf[5];
                    680:        crc2 = si70xx_crc(testcrcpt2, 4);
                    681:
                    682:        DPRINTF(sc, 2, ("%s: read 2 values: %02x%02x%02x%02x%02x%02x - %02x\n",
                    683:            device_xname(sc->sc_dev), buf[0], buf[1], buf[2],
                    684:            buf[3], buf[4], buf[5], crc2));
                    685:
                    686:        error = si70xx_cmd2(sc, SI70XX_READ_FW_VERA, SI70XX_READ_FW_VERB,
                    687:            buf, 8);
                    688:
                    689:        if (error) {
                    690:                aprint_error_dev(self, "Failed to read firware version: %d\n",
                    691:                    error);
                    692:                ecount++;
                    693:        }
                    694:        fwversion = buf[0];
                    695:        DPRINTF(sc, 2, ("%s: read fw values: %#x\n", device_xname(sc->sc_dev),
                    696:            fwversion));
                    697:
                    698:        error = si70xx_update_status(sc);
                    699:        iic_release_bus(sc->sc_tag, 0);
                    700:        if (error != 0) {
                    701:                aprint_error_dev(self, "Failed to update status: %x\n", error);
                    702:                aprint_error_dev(self, "Unable to setup device\n");
                    703:                goto out;
                    704:        }
                    705:
                    706:        for (i = 0; i < sc->sc_numsensors; i++) {
                    707:                strlcpy(sc->sc_sensors[i].desc, si70xx_sensors[i].desc,
                    708:                    sizeof(sc->sc_sensors[i].desc));
                    709:
                    710:                sc->sc_sensors[i].units = si70xx_sensors[i].type;
                    711:                sc->sc_sensors[i].state = ENVSYS_SINVALID;
                    712:
                    713:                DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i,
                    714:                    sc->sc_sensors[i].desc));
                    715:
                    716:                error = sysmon_envsys_sensor_attach(sc->sc_sme,
                    717:                    &sc->sc_sensors[i]);
                    718:                if (error) {
                    719:                        aprint_error_dev(self,
                    720:                            "Unable to attach sensor %d: %d\n", i, error);
1.6       jdc       721:                        sc->sc_sme = NULL;
1.1       christos  722:                        goto out;
                    723:                }
                    724:        }
                    725:
                    726:        sc->sc_sme->sme_name = device_xname(sc->sc_dev);
                    727:        sc->sc_sme->sme_cookie = sc;
                    728:        sc->sc_sme->sme_refresh = si70xx_refresh;
                    729:
                    730:        DPRINTF(sc, 2, ("si70xx_attach: registering with envsys\n"));
                    731:
                    732:        if (sysmon_envsys_register(sc->sc_sme)) {
                    733:                aprint_error_dev(self,
                    734:                        "unable to register with sysmon\n");
                    735:                sysmon_envsys_destroy(sc->sc_sme);
                    736:                sc->sc_sme = NULL;
                    737:                return;
                    738:        }
                    739:        if (ecount != 0) {
                    740:                aprint_normal_dev(self, "Could not read model, "
                    741:                    "probably an HTU21D\n");
                    742:                return;
                    743:        }
                    744:
                    745:        char modelstr[64];
                    746:        switch (model) {
                    747:        case 0:
                    748:        case 0xff:
                    749:                snprintf(modelstr, sizeof(modelstr), "Engineering Sample");
1.5       mrg       750:                break;
1.1       christos  751:        case 13:
                    752:        case 20:
                    753:        case 21:
                    754:                snprintf(modelstr, sizeof(modelstr), "SI70%d", model);
                    755:                break;
                    756:        default:
                    757:                snprintf(modelstr, sizeof(modelstr), "Unknown SI70%d", model);
                    758:                break;
                    759:        }
                    760:
                    761:        const char *fwversionstr;
                    762:        switch (fwversion) {
                    763:        case 0xff:
                    764:                fwversionstr = "1.0";
                    765:                break;
                    766:        case 0x20:
                    767:                fwversionstr = "2.0";
                    768:                break;
                    769:        default:
                    770:                fwversionstr = "unknown";
                    771:                break;
                    772:        }
                    773:
                    774:        aprint_normal_dev(self, "Silicon Labs Model: %s, "
                    775:            "Firmware version: %s, "
                    776:            "Serial number: %02x%02x%02x%02x%02x%02x%02x%02x%s",
                    777:            modelstr, fwversionstr, testcrcpt1[0], testcrcpt1[1],
                    778:            testcrcpt1[2], testcrcpt1[3], testcrcpt2[0], testcrcpt2[1],
                    779:            testcrcpt2[2], testcrcpt2[3],
                    780:            (crc1 == readcrc1 && crc2 == readcrc2) ? "\n" : " (bad crc)\n");
                    781:        return;
                    782: out:
                    783:        sysmon_envsys_destroy(sc->sc_sme);
                    784:        sc->sc_sme = NULL;
                    785: }
                    786:
                    787: static int
                    788: si70xx_exec(struct si70xx_sc *sc, uint8_t cmd, envsys_data_t *edata)
                    789: {
                    790:        int error;
                    791:        int xdelay;
                    792:        const char *name;
                    793:        int64_t mul, offs;
                    794:        uint8_t buf[3];
                    795:
                    796:        switch (cmd) {
                    797:        case SI70XX_MEASURE_RH_NOHOLD:
                    798:                /*
                    799:                 * The published conversion for RH is: %RH =
                    800:                 * ((125 * RHCODE) / 65536) - 6
                    801:                 *
                    802:                 * The sysmon infrastructure for RH wants %RH *
                    803:                 * 10^6 The result will fit in 32 bits, but
                    804:                 * the intermediate values will not.
                    805:                 */
                    806:                mul = 125000000;
                    807:                offs = -6000000;
                    808:                /*
                    809:                 * Conversion times for %RH in ms
                    810:                 *
                    811:                 *              Typical Max
                    812:                 * 12-bit       10.0    12.0
                    813:                 * 11-bit        5.8     7.0
                    814:                 * 10-bit        3.7     4.5
                    815:                 *  8-bit        2.6     3.1
                    816:                 *
                    817:                 * A call to read %RH will also read temperature.  The
                    818:                 * conversion time will be the amount of time above
                    819:                 * plus the amount of time for temperature below
                    820:                 */
                    821:                xdelay = 10500;
                    822:                name = "RH";
                    823:                break;
                    824:        case SI70XX_MEASURE_TEMP_NOHOLD:
                    825:                /*
                    826:                 * The published conversion for temp is:
                    827:                 * degree C = ((175.72 * TEMPCODE) / 65536) -
                    828:                 * 46.85
                    829:                 *
                    830:                 * The sysmon infrastructure for temp wants
                    831:                 * microkelvin.  This is simple, as degree C
                    832:                 * converts directly with K with simple
                    833:                 * addition. The result will fit in 32 bits,
                    834:                 * but the intermediate values will not.
                    835:                 */
                    836:                mul = 175720000;
                    837:                offs = 226300000;
                    838:                /*
                    839:                 * Conversion times for temperature in ms
                    840:                 *
                    841:                 *              Typical Max
                    842:                 * 14-bit       7.0     10.8
                    843:                 * 13-bit       4.0      6.2
                    844:                 * 12-bit       2.4      3.8
                    845:                 * 11-bit       1.5      2.4
                    846:                 */
                    847:                xdelay = 4750;
                    848:                name = "TEMP";
                    849:                break;
                    850:        default:
                    851:                return EINVAL;
                    852:        }
                    853:
                    854: #if HAVE_I2C_EXECV
                    855:        memset(buf, 0, sizeof(buf));
                    856:        error = iic_execv(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr,
                    857:            &cmd, 1, buf, sizeof(buf), 0, I2C_ATTR_CLOCKSTRETCH,
                    858:            sc->sc_clockstretch, I2C_ATTR_EOL);
                    859: #else
                    860:        /*
                    861:         * The lower level driver must support the ability to
                    862:         * do a zero length read, otherwise this breaks
                    863:         */
                    864:        error = si70xx_cmd1(sc, cmd, buf, 0);
                    865:        if (error) {
                    866:                DPRINTF(sc, 2, ("%s: Failed to read NO HOLD %s %d %d\n",
                    867:                    device_xname(sc->sc_dev), name, 1, error));
                    868:                return error;
                    869:        }
                    870:
                    871:        /*
                    872:         * It will probably be at least this long... we would
                    873:         * not have to do this sort of thing if clock
                    874:         * stretching worked.  Even this is a problem for the
                    875:         * RPI without a patch to remove a [apparently] not
                    876:         * needed KASSERT()
                    877:         */
                    878:        delay(xdelay);
                    879:
                    880:        for (int aint = 0; aint < sc->sc_readattempts; aint++) {
                    881:                error = si70xx_cmd0(sc, buf, sizeof(buf));
                    882:                if (error == 0)
                    883:                        break;
                    884:                DPRINTF(sc, 2, ("%s: Failed to read NO HOLD RH"
                    885:                    " %d %d\n", device_xname(sc->sc_dev), 2, error));
1.3       christos  886:                delay(1000);
1.1       christos  887:        }
                    888: #endif
                    889:
                    890:        DPRINTF(sc, 2, ("%s: %s values: %02x%02x%02x - %02x\n",
                    891:            device_xname(sc->sc_dev), name, buf[0], buf[1], buf[2],
                    892:            si70xx_crc(buf, 2)));
                    893:
                    894:        uint8_t crc;
                    895:        if (sc->sc_ignorecrc) {
                    896:                crc = buf[2];
                    897:        } else {
                    898:                crc = si70xx_crc(buf, 2);
                    899:        }
                    900:
                    901:        if (crc != buf[2]) {
                    902:                DPRINTF(sc, 2, ("%s: Bad CRC for %s: %#x and %#x\n",
                    903:                    device_xname(sc->sc_dev), name, crc, buf[2]));
                    904:                return EINVAL;
                    905:        }
                    906:
                    907:        uint16_t val16 = (buf[0] << 8) | buf[1];
                    908:        uint64_t val64 = ((mul * val16) >> 16) + offs;
                    909:        DPRINTF(sc, 2, ("%s: %s calculated values: %x %#jx\n",
                    910:            device_xname(sc->sc_dev), name, val16, (uintmax_t)val64));
                    911:        edata->value_cur = (uint32_t) val64;
                    912:        edata->state = ENVSYS_SVALID;
                    913:        return 0;
                    914: }
                    915:
                    916: static void
                    917: si70xx_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
                    918: {
                    919:        struct si70xx_sc *sc;
                    920:        int             error;
                    921:
                    922:        sc = sme->sme_cookie;
                    923:        edata->state = ENVSYS_SINVALID;
                    924:
                    925:        mutex_enter(&sc->sc_mutex);
                    926:        error = iic_acquire_bus(sc->sc_tag, 0);
                    927:        if (error) {
                    928:                DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
                    929:                    device_xname(sc->sc_dev), error));
                    930:                goto out;
                    931:        }
                    932:        error = si70xx_update_status(sc);
                    933:        if (error) {
                    934:                DPRINTF(sc, 2, ("%s: Failed to update status in refresh %d\n",
                    935:                    device_xname(sc->sc_dev), error));
                    936:                goto out1;
                    937:        }
                    938:        switch (edata->sensor) {
                    939:        case SI70XX_HUMIDITY_SENSOR:
1.3       christos  940:                error = si70xx_exec(sc, SI70XX_MEASURE_RH_NOHOLD, edata);
1.1       christos  941:                break;
                    942:
                    943:        case SI70XX_TEMP_SENSOR:
1.3       christos  944:                error = si70xx_exec(sc, SI70XX_MEASURE_TEMP_NOHOLD, edata);
1.1       christos  945:                break;
                    946:        default:
                    947:                error = EINVAL;
                    948:                break;
                    949:        }
                    950:
                    951:        if (error) {
                    952:                DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d\n",
                    953:                    device_xname(sc->sc_dev), error));
                    954:        }
                    955: out1:
                    956:        iic_release_bus(sc->sc_tag, 0);
                    957: out:
                    958:        mutex_exit(&sc->sc_mutex);
                    959: }
                    960:
                    961: static int
                    962: si70xx_detach(device_t self, int flags)
                    963: {
                    964:        struct si70xx_sc *sc;
                    965:
                    966:        sc = device_private(self);
                    967:
                    968:        mutex_enter(&sc->sc_mutex);
                    969:
                    970:        /* Remove the sensors */
1.6.4.1 ! thorpej   971:        if (sc->sc_sme != NULL)
1.1       christos  972:                sysmon_envsys_unregister(sc->sc_sme);
                    973:        mutex_exit(&sc->sc_mutex);
                    974:
                    975:        /* Remove the sysctl tree */
                    976:        sysctl_teardown(&sc->sc_si70xxlog);
                    977:
                    978:        /* Remove the mutex */
                    979:        mutex_destroy(&sc->sc_mutex);
                    980:
                    981:        return 0;
                    982: }
                    983:
                    984: MODULE(MODULE_CLASS_DRIVER, si70xxtemp, "i2cexec,sysmon_envsys");
                    985:
                    986: #ifdef _MODULE
                    987: #include "ioconf.c"
                    988: #endif
                    989:
                    990: static int
                    991: si70xxtemp_modcmd(modcmd_t cmd, void *opaque)
                    992: {
                    993:
                    994:        switch (cmd) {
                    995:        case MODULE_CMD_INIT:
                    996: #ifdef _MODULE
                    997:                return config_init_component(cfdriver_ioconf_si70xxtemp,
                    998:                    cfattach_ioconf_si70xxtemp, cfdata_ioconf_si70xxtemp);
                    999: #else
                   1000:                return 0;
                   1001: #endif
                   1002:        case MODULE_CMD_FINI:
                   1003: #ifdef _MODULE
1.2       christos 1004:                return config_fini_component(cfdriver_ioconf_si70xxtemp,
1.1       christos 1005:                      cfattach_ioconf_si70xxtemp, cfdata_ioconf_si70xxtemp);
                   1006: #else
                   1007:                return 0;
                   1008: #endif
                   1009:        default:
                   1010:                return ENOTTY;
                   1011:        }
                   1012: }

CVSweb <webmaster@jp.NetBSD.org>