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 watchdog support



details:   https://anonhg.NetBSD.org/src/rev/5b13e505492a
branches:  trunk
changeset: 341755:5b13e505492a
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Nov 21 10:56:40 2015 +0000

description:
add watchdog support

diffstat:

 sys/dev/i2c/as3722.c |  135 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 129 insertions(+), 6 deletions(-)

diffs (206 lines):

diff -r 235e62dd2652 -r 5b13e505492a sys/dev/i2c/as3722.c
--- a/sys/dev/i2c/as3722.c      Sat Nov 21 09:06:03 2015 +0000
+++ b/sys/dev/i2c/as3722.c      Sat Nov 21 10:56:40 2015 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: as3722.c,v 1.1 2015/11/11 12:35:22 jmcneill Exp $ */
+/* $NetBSD: as3722.c,v 1.2 2015/11/21 10:56:40 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -27,7 +27,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: as3722.c,v 1.1 2015/11/11 12:35:22 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: as3722.c,v 1.2 2015/11/21 10:56:40 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -36,13 +36,35 @@
 #include <sys/conf.h>
 #include <sys/bus.h>
 #include <sys/kmem.h>
+#include <sys/wdog.h>
+
+#include <dev/sysmon/sysmonvar.h>
 
 #include <dev/i2c/i2cvar.h>
 #include <dev/i2c/as3722.h>
 
+#define AS3722_GPIO0_CTRL_REG          0x08
+#define AS3722_GPIO0_CTRL_INVERT       __BIT(7)
+#define AS3722_GPIO0_CTRL_IOSF         __BITS(6,3)
+#define AS3722_GPIO0_CTRL_IOSF_GPIO    0
+#define AS3722_GPIO0_CTRL_IOSF_WATCHDOG        9
+#define AS3722_GPIO0_CTRL_MODE         __BITS(2,0)
+#define AS3722_GPIO0_CTRL_MODE_PULLDOWN        5
+
 #define AS3722_RESET_CTRL_REG          0x36
 #define AS3722_RESET_CTRL_POWER_OFF    __BIT(1)
 
+#define AS3722_WATCHDOG_CTRL_REG       0x38
+#define AS3722_WATCHDOG_CTRL_MODE      __BITS(2,1)
+#define AS3722_WATCHDOG_CTRL_ON                __BIT(0)
+
+#define AS3722_WATCHDOG_TIMER_REG      0x46
+#define AS3722_WATCHDOG_TIMER_TIMER    __BITS(6,0)
+
+#define AS3722_WATCHDOG_SIGNAL_REG     0x48
+#define AS3722_WATCHDOG_SIGNAL_PWM_DIV __BITS(7,6)
+#define AS3722_WATCHDOG_SIGNAL_SW_SIG  __BIT(0)
+
 #define AS3722_ASIC_ID1_REG            0x90
 #define AS3722_ASIC_ID2_REG            0x91
 
@@ -50,15 +72,22 @@
        device_t        sc_dev;
        i2c_tag_t       sc_i2c;
        i2c_addr_t      sc_addr;
+
+       struct sysmon_wdog sc_smw;
 };
 
+#define AS3722_WATCHDOG_DEFAULT_PERIOD 10
+
 static int     as3722_match(device_t, cfdata_t, void *);
 static void    as3722_attach(device_t, device_t, void *);
 
-#if 0
+static int     as3722_wdt_setmode(struct sysmon_wdog *);
+static int     as3722_wdt_tickle(struct sysmon_wdog *);
+
 static int     as3722_read(struct as3722_softc *, uint8_t, uint8_t *, int);
-#endif
 static int     as3722_write(struct as3722_softc *, uint8_t, uint8_t, int);
+static int     as3722_set_clear(struct as3722_softc *, uint8_t, uint8_t,
+                                uint8_t, int);
 
 CFATTACH_DECL_NEW(as3722pmic, sizeof(struct as3722_softc),
     as3722_match, as3722_attach, NULL, NULL);
@@ -87,6 +116,7 @@
 {
        struct as3722_softc * const sc = device_private(self);
        struct i2c_attach_args *ia = aux;
+       int error;
 
        sc->sc_dev = self;
        sc->sc_i2c = ia->ia_tag;
@@ -94,16 +124,40 @@
 
        aprint_naive("\n");
        aprint_normal(": AMS AS3822\n");
+
+       iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
+       error = as3722_write(sc, AS3722_GPIO0_CTRL_REG,
+           __SHIFTIN(AS3722_GPIO0_CTRL_IOSF_GPIO,
+                     AS3722_GPIO0_CTRL_IOSF) |
+           __SHIFTIN(AS3722_GPIO0_CTRL_MODE_PULLDOWN,
+                     AS3722_GPIO0_CTRL_MODE),
+           I2C_F_POLL);
+       error += as3722_set_clear(sc, AS3722_WATCHDOG_CTRL_REG,
+           __SHIFTIN(1, AS3722_WATCHDOG_CTRL_MODE), 0, I2C_F_POLL);
+       iic_release_bus(sc->sc_i2c, I2C_F_POLL);
+
+       if (error)
+               aprint_error_dev(self, "couldn't setup watchdog\n");
+
+       sc->sc_smw.smw_name = device_xname(self);
+       sc->sc_smw.smw_cookie = sc;
+       sc->sc_smw.smw_setmode = as3722_wdt_setmode;
+       sc->sc_smw.smw_tickle = as3722_wdt_tickle;
+       sc->sc_smw.smw_period = AS3722_WATCHDOG_DEFAULT_PERIOD;
+
+       aprint_normal_dev(self, "default watchdog period is %u seconds\n",
+           sc->sc_smw.smw_period);
+
+       if (sysmon_wdog_register(&sc->sc_smw) != 0)
+               aprint_error_dev(self, "couldn't register with sysmon\n");
 }
 
-#if 0
 static int
 as3722_read(struct as3722_softc *sc, uint8_t reg, uint8_t *val, int flags)
 {
        return iic_exec(sc->sc_i2c, I2C_OP_READ_WITH_STOP, sc->sc_addr,
            &reg, 1, val, 1, flags);
 }
-#endif
 
 static int
 as3722_write(struct as3722_softc *sc, uint8_t reg, uint8_t val, int flags)
@@ -113,6 +167,75 @@
            NULL, 0, buf, 2, flags);
 }
 
+static int
+as3722_set_clear(struct as3722_softc *sc, uint8_t reg, uint8_t set,
+    uint8_t clr, int flags)
+{
+       uint8_t old, new;
+       int error;
+
+       error = as3722_read(sc, reg, &old, flags);
+       if (error) {
+               return error;
+       }
+       new = set | (old & ~clr);
+
+       return as3722_write(sc, reg, new, flags);
+}
+
+static int
+as3722_wdt_setmode(struct sysmon_wdog *smw)
+{
+       struct as3722_softc * const sc = smw->smw_cookie;
+       int error;
+
+       const int flags = (cold ? I2C_F_POLL : 0);
+
+       if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
+               iic_acquire_bus(sc->sc_i2c, flags);
+               error = as3722_set_clear(sc, AS3722_WATCHDOG_CTRL_REG,
+                   0, AS3722_WATCHDOG_CTRL_ON, flags);
+               iic_release_bus(sc->sc_i2c, flags);
+               return error;
+       }
+
+       if (smw->smw_period == WDOG_PERIOD_DEFAULT) {
+               smw->smw_period = AS3722_WATCHDOG_DEFAULT_PERIOD;
+       }
+       if (smw->smw_period < 1 || smw->smw_period > 128) {
+               return EINVAL;
+       }
+       sc->sc_smw.smw_period = smw->smw_period;
+
+       iic_acquire_bus(sc->sc_i2c, flags);
+       error = as3722_set_clear(sc, AS3722_WATCHDOG_TIMER_REG,
+           __SHIFTIN(sc->sc_smw.smw_period - 1, AS3722_WATCHDOG_TIMER_TIMER),
+           AS3722_WATCHDOG_TIMER_TIMER, flags);
+       if (error == 0) {
+               error = as3722_set_clear(sc, AS3722_WATCHDOG_CTRL_REG,
+                   AS3722_WATCHDOG_CTRL_ON, 0, flags);
+       }
+       iic_release_bus(sc->sc_i2c, flags);
+
+       return error;
+}
+
+static int
+as3722_wdt_tickle(struct sysmon_wdog *smw)
+{
+       struct as3722_softc * const sc = smw->smw_cookie;
+       int error;
+
+       const int flags = (cold ? I2C_F_POLL : 0);
+
+       iic_acquire_bus(sc->sc_i2c, flags);
+       error = as3722_set_clear(sc, AS3722_WATCHDOG_SIGNAL_REG,
+           AS3722_WATCHDOG_SIGNAL_SW_SIG, 0, flags);
+       iic_release_bus(sc->sc_i2c, flags);
+
+       return error;
+}
+
 int
 as3722_poweroff(device_t dev)
 {



Home | Main Index | Thread Index | Old Index