Module Name:    src
Committed By:   jmcneill
Date:           Sat Nov 21 10:56:40 UTC 2015

Modified Files:
        src/sys/dev/i2c: as3722.c

Log Message:
add watchdog support


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/i2c/as3722.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/i2c/as3722.c
diff -u src/sys/dev/i2c/as3722.c:1.1 src/sys/dev/i2c/as3722.c:1.2
--- src/sys/dev/i2c/as3722.c:1.1	Wed Nov 11 12:35:22 2015
+++ src/sys/dev/i2c/as3722.c	Sat Nov 21 10:56:40 2015
@@ -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 <jmcne...@invisible.ca>
@@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: as3722.c,v 1
 #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 @@ struct as3722_softc {
 	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 @@ as3722_attach(device_t parent, device_t 
 {
 	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 @@ as3722_attach(device_t parent, device_t 
 
 	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 @@ as3722_write(struct as3722_softc *sc, ui
 	    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)
 {

Reply via email to