Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/i2c Add sysctl knobs to set temperature limit and hy...



details:   https://anonhg.NetBSD.org/src/rev/6da8445d3289
branches:  trunk
changeset: 790500:6da8445d3289
user:      rkujawa <rkujawa%NetBSD.org@localhost>
date:      Tue Oct 15 13:42:52 2013 +0000

description:
Add sysctl knobs to set temperature limit and hysteresis. Reaching the limit
causes alert line of the chip to be asserted. These limits could be tied to
critical limit set in envsys, but it's more versatile to keep it as separate
value.

diffstat:

 sys/dev/i2c/mcp980x.c |  137 +++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 135 insertions(+), 2 deletions(-)

diffs (208 lines):

diff -r 5fd046a6602d -r 6da8445d3289 sys/dev/i2c/mcp980x.c
--- a/sys/dev/i2c/mcp980x.c     Tue Oct 15 13:00:52 2013 +0000
+++ b/sys/dev/i2c/mcp980x.c     Tue Oct 15 13:42:52 2013 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: mcp980x.c,v 1.3 2013/10/15 10:27:55 rkujawa Exp $ */
+/*     $NetBSD: mcp980x.c,v 1.4 2013/10/15 13:42:52 rkujawa Exp $ */
 
 /*-
  * Copyright (c) 2013 The NetBSD Foundation, Inc.
@@ -32,11 +32,13 @@
 /*
  * Microchip MCP9800/1/2/3 2-Wire High-Accuracy Temperature Sensor driver.
  *
+ * TODO: better error checking, particurarly in user settable limits.
+ *
  * Note: MCP9805 is different and is supported by the sdtemp(4) driver.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mcp980x.c,v 1.3 2013/10/15 10:27:55 rkujawa Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mcp980x.c,v 1.4 2013/10/15 13:42:52 rkujawa Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -60,6 +62,8 @@
        i2c_addr_t              sc_addr;
 
        int                     sc_res;
+       int                     sc_hyst;
+       int                     sc_limit;
 
        /* envsys(4) stuff */
        struct sysmon_envsys    *sc_sme;
@@ -78,6 +82,14 @@
 static uint8_t mcp980x_resolution_get(struct mcp980x_softc *);
 static void mcp980x_resolution_set(struct mcp980x_softc *, uint8_t);
 
+static int8_t mcp980x_hysteresis_get(struct mcp980x_softc *);
+static void mcp980x_hysteresis_set(struct mcp980x_softc *, int8_t);
+static int8_t mcp980x_templimit_get(struct mcp980x_softc *);
+static void mcp980x_templimit_set(struct mcp980x_softc *, int8_t);
+
+static int8_t mcp980x_s8b_get(struct mcp980x_softc *, uint8_t);
+static void mcp980x_s8b_set(struct mcp980x_softc *, uint8_t, int8_t);
+
 static uint32_t mcp980x_temperature(struct mcp980x_softc *);
 
 static void mcp980x_envsys_register(struct mcp980x_softc *);
@@ -85,6 +97,8 @@
 
 static void mcp980x_setup_sysctl(struct mcp980x_softc *);
 static int sysctl_mcp980x_res(SYSCTLFN_ARGS);
+static int sysctl_mcp980x_hysteresis(SYSCTLFN_ARGS);
+static int sysctl_mcp980x_templimit(SYSCTLFN_ARGS);
 
 CFATTACH_DECL_NEW(mcp980x, sizeof (struct mcp980x_softc),
     mcp980x_match, mcp980x_attach, NULL, NULL);
@@ -115,6 +129,9 @@
        sc->sc_res = MCP980X_CONFIG_ADC_RES_12BIT;
        mcp980x_resolution_set(sc, sc->sc_res);
 
+       sc->sc_hyst = mcp980x_hysteresis_get(sc);
+       sc->sc_limit = mcp980x_templimit_get(sc);
+
        mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
 
        mcp980x_setup_sysctl(sc);
@@ -164,6 +181,27 @@
 }
 
 static void
+mcp980x_reg_write_2(struct mcp980x_softc *sc, uint8_t reg, uint16_t val)
+{
+       uint16_t beval;
+
+       beval = htobe16(val);
+
+        if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
+               aprint_error_dev(sc->sc_dev, "cannot acquire bus for write\n");
+               return;
+       }
+
+        if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, &reg,
+           1, &beval, 2, I2C_F_POLL)) {
+               aprint_error_dev(sc->sc_dev, "cannot execute operation\n");
+        }
+
+       iic_release_bus(sc->sc_tag, I2C_F_POLL);
+
+}
+
+static void
 mcp980x_reg_write_1(struct mcp980x_softc *sc, uint8_t reg, uint8_t val)
 {
         if (iic_acquire_bus(sc->sc_tag, I2C_F_POLL) != 0) {
@@ -180,6 +218,42 @@
 
 }
 
+static int8_t
+mcp980x_templimit_get(struct mcp980x_softc *sc)
+{
+       return mcp980x_s8b_get(sc, MCP980X_TEMP_LIMIT);
+}
+
+static void
+mcp980x_templimit_set(struct mcp980x_softc *sc, int8_t val)
+{
+       mcp980x_s8b_set(sc, MCP980X_TEMP_LIMIT, val);
+}
+
+static int8_t
+mcp980x_hysteresis_get(struct mcp980x_softc *sc)
+{
+       return mcp980x_s8b_get(sc, MCP980X_TEMP_HYSTERESIS);
+}
+
+static void
+mcp980x_hysteresis_set(struct mcp980x_softc *sc, int8_t val)
+{
+       mcp980x_s8b_set(sc, MCP980X_TEMP_HYSTERESIS, val);
+}
+
+static int8_t
+mcp980x_s8b_get(struct mcp980x_softc *sc, uint8_t reg) 
+{
+       return mcp980x_reg_read_2(sc, reg) >> MCP980X_TEMP_HYSTLIMIT_INT_SHIFT;
+}
+
+static void
+mcp980x_s8b_set(struct mcp980x_softc *sc, uint8_t reg, int8_t val)
+{
+       mcp980x_reg_write_2(sc, reg, val << MCP980X_TEMP_HYSTLIMIT_INT_SHIFT);
+}
+
 static uint8_t 
 mcp980x_resolution_get(struct mcp980x_softc *sc)
 {
@@ -292,6 +366,17 @@
            sysctl_mcp980x_res, 1, (void *)sc, 0,
            CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
        
+       sysctl_createv(NULL, 0, NULL, &node,
+           CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
+           CTLTYPE_INT, "hysteresis", "Temperature hysteresis",
+           sysctl_mcp980x_hysteresis, 1, (void *)sc, 0,
+           CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
+
+       sysctl_createv(NULL, 0, NULL, &node,
+           CTLFLAG_READWRITE | CTLFLAG_OWNDESC,
+           CTLTYPE_INT, "templimit", "Temperature limit",
+           sysctl_mcp980x_templimit, 1, (void *)sc, 0,
+           CTL_MACHDEP, me->sysctl_num, CTL_CREATE, CTL_EOL);
 }
 
 
@@ -329,3 +414,51 @@
        return err;
 }
 
+static int
+sysctl_mcp980x_hysteresis(SYSCTLFN_ARGS)
+{
+       struct sysctlnode node = *rnode;
+       struct mcp980x_softc *sc = node.sysctl_data;
+       int newhyst, err;
+
+       node.sysctl_data = &sc->sc_hyst;
+       if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0) 
+               return err;
+
+       if (newp) {
+               newhyst = *(int *)node.sysctl_data;
+               sc->sc_hyst = newhyst;
+               mcp980x_hysteresis_set(sc, sc->sc_hyst);
+               return 0;
+       } else {
+               sc->sc_hyst = mcp980x_hysteresis_get(sc);
+               node.sysctl_size = 4;
+       }
+
+       return err;
+}
+
+static int
+sysctl_mcp980x_templimit(SYSCTLFN_ARGS)
+{
+       struct sysctlnode node = *rnode;
+       struct mcp980x_softc *sc = node.sysctl_data;
+       int newlimit, err;
+
+       node.sysctl_data = &sc->sc_limit;
+       if ((err = (sysctl_lookup(SYSCTLFN_CALL(&node)))) != 0) 
+               return err;
+
+       if (newp) {
+               newlimit = *(int *)node.sysctl_data;
+               sc->sc_limit = newlimit;
+               mcp980x_templimit_set(sc, sc->sc_limit);
+               return 0;
+       } else {
+               sc->sc_limit = mcp980x_templimit_get(sc);
+               node.sysctl_size = 4;
+       }
+
+       return err;
+}
+



Home | Main Index | Thread Index | Old Index