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, ®, 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) {