Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/i2c PR/52848: Brad Spencer: Two environment sensor d...



details:   https://anonhg.NetBSD.org/src/rev/bae26ddc60da
branches:  trunk
changeset: 828728:bae26ddc60da
user:      christos <christos%NetBSD.org@localhost>
date:      Thu Dec 28 23:23:47 2017 +0000

description:
PR/52848: Brad Spencer: Two environment sensor drivers: AM2315 and SI70xx
XXX: Please check that my refactoring did not break them!

diffstat:

 sys/dev/i2c/am2315.c    |   531 ++++++++++++++++++++++++
 sys/dev/i2c/am2315reg.h |    60 ++
 sys/dev/i2c/am2315var.h |    47 ++
 sys/dev/i2c/files.i2c   |    12 +-
 sys/dev/i2c/si70xx.c    |  1010 +++++++++++++++++++++++++++++++++++++++++++++++
 sys/dev/i2c/si70xxreg.h |    44 ++
 sys/dev/i2c/si70xxvar.h |    58 ++
 7 files changed, 1761 insertions(+), 1 deletions(-)

diffs (truncated from 1800 to 300 lines):

diff -r bc5f20f34357 -r bae26ddc60da sys/dev/i2c/am2315.c
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/sys/dev/i2c/am2315.c      Thu Dec 28 23:23:47 2017 +0000
@@ -0,0 +1,531 @@
+/*     $NetBSD: am2315.c,v 1.1 2017/12/28 23:23:47 christos Exp $      */
+
+/*
+ * Copyright (c) 2017 Brad Spencer <brad%anduin.eldar.org@localhost>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: am2315.c,v 1.1 2017/12/28 23:23:47 christos Exp $");
+
+/*
+ * Driver for the Aosong AM2315
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/condvar.h>
+#include <sys/mutex.h>
+#include <sys/time.h>
+
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/am2315reg.h>
+#include <dev/i2c/am2315var.h>
+
+static uint16_t am2315_crc(uint8_t *, size_t);
+static int     am2315_poke(struct am2315_sc *);
+static int     am2315_poke_m(i2c_tag_t, i2c_addr_t, const char *, bool);
+static int     am2315_match(device_t, cfdata_t, void *);
+static void    am2315_attach(device_t, device_t, void *);
+static int     am2315_detach(device_t, int);
+static void    am2315_refresh(struct sysmon_envsys *, envsys_data_t *);
+static int     am2315_verify_sysctl(SYSCTLFN_ARGS);
+
+#define AM2315_DEBUG
+#ifdef AM2315_DEBUG
+#define DPRINTF(s, l, x) \
+    do { \
+       if (l <= s->sc_am2315debug) \
+       printf x; \
+    } while (/*CONSTCOND*/0)
+#else
+#define DPRINTF(s, l, x)
+#endif
+
+CFATTACH_DECL_NEW(am2315temp, sizeof(struct am2315_sc),
+    am2315_match, am2315_attach, am2315_detach, NULL);
+
+static struct am2315_sensor am2315_sensors[] = {
+       {
+               .desc = "humidity",
+               .type = ENVSYS_SRELHUMIDITY,
+       },
+       {
+               .desc = "temperature",
+               .type = ENVSYS_STEMP,
+       }
+};
+
+static uint16_t
+am2315_crc(uint8_t *data, size_t len)
+{
+       uint16_t crc = 0xffff;
+
+       for (size_t j = 0; j < len; j++) {
+               crc ^= data[j];
+               for (size_t i = 0; i < 8; i++) {
+                       if (crc & 0x01) {
+                               crc >>= 1;
+                               crc ^= 0xA001;
+                       } else {
+                               crc >>= 1;
+                       }
+               }
+       }
+
+       return crc;
+}
+
+int 
+am2315_verify_sysctl(SYSCTLFN_ARGS)
+{
+       int error, t;
+       struct sysctlnode node;
+
+       node = *rnode;
+       t = *(int *)rnode->sysctl_data;
+       node.sysctl_data = &t;
+       error = sysctl_lookup(SYSCTLFN_CALL(&node));
+       if (error || newp == NULL)
+               return error;
+
+       if (t < 0)
+               return EINVAL;
+
+       *(int *) rnode->sysctl_data = t;
+
+       return 0;
+}
+
+static int
+am2315_cmd(i2c_tag_t tag, i2c_addr_t addr, uint8_t dir, uint8_t cmd,
+    uint8_t clen, uint8_t *buf, size_t blen)
+{
+       uint8_t command[] = { dir, cmd, clen };
+       if (buf)
+               memset(buf, 0xff, blen);
+       uint8_t reg = dir == AM2315_READ_REGISTERS ?
+           I2C_OP_READ_WITH_STOP : I2C_OP_WRITE_WITH_STOP;
+
+       return iic_exec(tag, reg, addr, command,
+           __arraycount(command), buf, blen, 0);
+}
+
+static int
+am2315_read_regs(struct am2315_sc *sc, uint8_t cmd, uint8_t clen, uint8_t *buf,
+    size_t blen)
+{
+       return am2315_cmd(sc->sc_tag, sc->sc_addr, AM2315_READ_REGISTERS,
+           cmd, clen, buf, blen);
+}
+
+static int
+am2315_poke(struct am2315_sc *sc)
+{
+       return am2315_poke_m(sc->sc_tag, sc->sc_addr, device_xname(sc->sc_dev),
+           sc->sc_am2315debug >= 2);
+}
+
+static int
+am2315_poke_m(i2c_tag_t tag, i2c_addr_t addr, const char *name, bool debug)
+{
+       uint8_t buf[5];
+       int error;
+
+       error = am2315_cmd(tag, addr, AM2315_WRITE_REGISTERS,
+           AM2315_REGISTER_HIGH_USER1, 1, NULL, 0);
+       if (debug)
+               printf("%s: poke 1: %d\n", name, error);
+
+       if (error != 0)
+               delay(2800);
+
+       error = am2315_cmd(tag, addr, AM2315_READ_REGISTERS,
+           AM2315_REGISTER_STATUS, 1, buf, __arraycount(buf));
+       if (debug)
+           printf("%s: poke 2: %d %02x %02x %02x %02x%02x\n", name, error,
+               buf[0], buf[1], buf[2], buf[3], buf[4]);
+
+       if (error != 0)
+               delay(2800);
+       return error;
+}
+
+static int
+am2315_match(device_t parent, cfdata_t match, void *aux)
+{
+       struct i2c_attach_args *ia;
+       int rv;
+       const bool matchdebug = false;
+
+       ia = aux;
+
+       if (ia->ia_name) {
+               /* direct config - check name */
+               if (strcmp(ia->ia_name, "am2315temp") != 0)
+                       return 0;
+       } else {
+               /* indirect config - check for configured address */
+               if (ia->ia_addr != AM2315_TYPICAL_ADDR)
+                       return 0;
+       }
+
+       /*
+        * Check to see if something is really at this i2c address. This will
+        * keep phantom devices from appearing
+        */
+       if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
+               if (matchdebug)
+                       printf("in match acquire bus failed\n");
+               return 0;
+       }
+
+       if ((rv = am2315_poke_m(ia->ia_tag, ia->ia_addr, __func__, matchdebug))
+           != 0) {
+               if (matchdebug)
+                       printf("match rv poke %d\n", rv);
+               iic_release_bus(ia->ia_tag, 0);
+               return 0;
+       }
+
+       return 1;
+}
+
+static void
+am2315_attach(device_t parent, device_t self, void *aux)
+{
+       struct am2315_sc *sc = device_private(self);
+       struct i2c_attach_args *ia = aux;
+       uint8_t buf[11];
+       int error;
+       uint16_t crc, readcrc, model;
+       uint8_t chipver;
+       uint32_t id;
+       bool modelgood, chipvergood, idgood;
+
+       sc->sc_dev = self;
+       sc->sc_tag = ia->ia_tag;
+       sc->sc_addr = ia->ia_addr;
+       sc->sc_am2315debug = 0;
+       sc->sc_readcount = 2;
+       sc->sc_readticks = 100;
+       sc->sc_sme = NULL;
+
+       aprint_normal("\n");
+
+       mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
+       mutex_init(&sc->sc_waitmutex, MUTEX_DEFAULT, IPL_NONE);
+       cv_init(&sc->sc_condwait, "am2315wait");
+
+       sc->sc_numsensors = __arraycount(am2315_sensors);
+
+       if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
+               aprint_error_dev(self, "unable to create sysmon structure\n");
+               return;
+       }
+
+       /* XXX: sysctl's not destroyed on failure */
+       const struct sysctlnode *cnode;
+       int sysctlroot_num;
+       if ((error = sysctl_createv(&sc->sc_am2315log, 0, NULL, &cnode, 0,
+           CTLTYPE_NODE, device_xname(self),
+           SYSCTL_DESCR("am2315 controls"), NULL, 0, NULL, 0, CTL_HW,
+           CTL_CREATE, CTL_EOL)) != 0)
+               goto badsysctl;
+       sysctlroot_num = cnode->sysctl_num;
+
+#ifdef AM2315_DEBUG
+       if ((error = sysctl_createv(&sc->sc_am2315log, 0, NULL, &cnode,
+           CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
+           SYSCTL_DESCR("Debug level"), am2315_verify_sysctl, 0,
+           &sc->sc_am2315debug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
+           CTL_EOL)) != 0)
+               goto badsysctl;
+
+#endif
+
+       if ((error = sysctl_createv(&sc->sc_am2315log, 0, NULL, &cnode,
+           CTLFLAG_READWRITE, CTLTYPE_INT, "readcount",
+           SYSCTL_DESCR("Number of times to read the sensor"),
+           am2315_verify_sysctl, 0, &sc->sc_readcount, 0, CTL_HW,
+           sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+               goto badsysctl;
+
+       if ((error = sysctl_createv(&sc->sc_am2315log, 0, NULL, &cnode,
+           CTLFLAG_READWRITE, CTLTYPE_INT, "readticks",
+           SYSCTL_DESCR("Number of ticks between reads"),
+           am2315_verify_sysctl, 0, &sc->sc_readticks, 0, CTL_HW,
+           sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+               goto badsysctl;
+
+       if ((error = iic_acquire_bus(sc->sc_tag, 0)) != 0) {
+               aprint_error_dev(self,
+                   "Could not acquire iic bus: %d\n", error);
+               return;
+       }
+       am2315_poke(sc);
+
+#define DUMP(a) \
+    DPRINTF(sc, 2, ("%s: read cmd+len+%s+crcl+crch values: %02x %02x " \
+       "%02x%02x %02x%02x -- %02x%02x%02x%02x%02x -- %04x %04x\n", a, \
+       device_xname(self), buf[0], buf[1], buf[2], buf[3], \
+       buf[4], buf[5], buf[6], buf[7], buf[8], buf[9], \
+       buf[10], crc, readcrc))
+
+       error = am2315_read_regs(sc, AM2315_REGISTER_HIGH_MODEL, 2, buf, 6);
+       if (error)
+               aprint_error_dev(sc->sc_dev, "read model: %d\n", error);
+       readcrc = buf[5] << 8 | buf[4];
+       crc = am2315_crc(buf, 4);
+       DUMP("modh+modl");



Home | Main Index | Thread Index | Old Index