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/e38f72ad50fc
branches: trunk
changeset: 358427:e38f72ad50fc
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 6f74e3d37a1b -r e38f72ad50fc 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