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 support for TPS65950 watchdog timer



details:   https://anonhg.NetBSD.org/src/rev/222fbf31c6ca
branches:  trunk
changeset: 783610:222fbf31c6ca
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Mon Dec 31 19:47:27 2012 +0000

description:
add support for TPS65950 watchdog timer

diffstat:

 sys/dev/i2c/files.i2c  |    4 +-
 sys/dev/i2c/tps65950.c |  107 +++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 102 insertions(+), 9 deletions(-)

diffs (237 lines):

diff -r 7fb5da01450a -r 222fbf31c6ca sys/dev/i2c/files.i2c
--- a/sys/dev/i2c/files.i2c     Mon Dec 31 18:47:41 2012 +0000
+++ b/sys/dev/i2c/files.i2c     Mon Dec 31 19:47:27 2012 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: files.i2c,v 1.46 2012/12/31 13:26:42 jmcneill Exp $
+#      $NetBSD: files.i2c,v 1.47 2012/12/31 19:47:27 jmcneill Exp $
 
 obsolete defflag       opt_i2cbus.h            I2C_SCAN
 define i2cbus { }
@@ -173,6 +173,6 @@
 file   dev/i2c/ibmhawk.c               ibmhawk
 
 # TI TPS65950 OMAP Power Management and System Companion Device
-device tps65950pm
+device tps65950pm: sysmon_wdog
 attach tps65950pm at iic
 file   dev/i2c/tps65950.c              tps65950pm
diff -r 7fb5da01450a -r 222fbf31c6ca sys/dev/i2c/tps65950.c
--- a/sys/dev/i2c/tps65950.c    Mon Dec 31 18:47:41 2012 +0000
+++ b/sys/dev/i2c/tps65950.c    Mon Dec 31 19:47:27 2012 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: tps65950.c,v 1.1 2012/12/31 13:26:42 jmcneill Exp $ */
+/* $NetBSD: tps65950.c,v 1.2 2012/12/31 19:47:27 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2012 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: tps65950.c,v 1.1 2012/12/31 13:26:42 jmcneill Exp $");
+__KERNEL_RCSID(0, "$NetBSD: tps65950.c,v 1.2 2012/12/31 19:47:27 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -40,9 +40,17 @@
 #include <sys/bus.h>
 #include <sys/kmem.h>
 #include <sys/sysctl.h>
+#include <sys/wdog.h>
 
 #include <dev/i2c/i2cvar.h>
 
+#include <dev/sysmon/sysmonvar.h>
+
+/* Default watchdog period, in seconds */
+#ifndef TPS65950_WDOG_DEFAULT_PERIOD
+#define TPS65950_WDOG_DEFAULT_PERIOD   30
+#endif
+
 /* I2C Bus Addressing */
 #define        TPS65950_ADDR_ID1               0x48    /* GP */
 #define TPS65950_ADDR_ID2              0x49    /* GP */
@@ -50,6 +58,7 @@
 #define TPS65950_ADDR_ID4              0x4b    /* GP */
 #define TPS65950_ADDR_ID5              0x12    /* SmartReflex */
 
+/* ID2 */
 #define TPS65950_ID2_IDCODE_7_0                0x85
 #define TPS65950_ID2_IDCODE_15_8       0x86
 #define TPS65950_ID2_IDCODE_23_16      0x87
@@ -57,20 +66,26 @@
 #define TPS65950_ID2_UNLOCK_TEST_REG   0x97
 #define TPS65950_ID2_UNLOCK_TEST_REG_MAGIC 0x49
 
+/* ID3 */
 #define TPS65950_LED_BASE              0xee
-
 #define        TPS65950_ID3_REG_LED            (TPS65950_LED_BASE + 0)
 #define        TPS65950_ID3_REG_LED_LEDAON     __BIT(0)
 #define        TPS65950_ID3_REG_LED_LEDBON     __BIT(1)
 #define TPS65950_ID3_REG_LED_LEDAPWM   __BIT(4)
 #define TPS65950_ID3_REG_LED_LEDBPWM   __BIT(5)
 
+/* ID4 */
+#define TPS65950_PM_RECEIVER_BASE      0x5b
+#define TPS65950_ID4_REG_WATCHDOG_CFG  (TPS65950_PM_RECEIVER_BASE + 3)
+
 struct tps65950_softc {
        device_t        sc_dev;
        i2c_tag_t       sc_i2c;
        i2c_addr_t      sc_addr;
 
        struct sysctllog *sc_sysctllog;
+       struct sysmon_wdog sc_smw;
+       uint8_t         sc_watchdog_cfg;
 };
 
 static int     tps65950_match(device_t, cfdata_t, void *);
@@ -80,6 +95,10 @@
 static int     tps65950_write_1(struct tps65950_softc *, uint8_t, uint8_t);
 
 static void    tps65950_sysctl_attach(struct tps65950_softc *);
+static void    tps65950_wdog_attach(struct tps65950_softc *);
+
+static int     tps65950_wdog_setmode(struct sysmon_wdog *);
+static int     tps65950_wdog_tickle(struct sysmon_wdog *);
 
 CFATTACH_DECL_NEW(tps65950pm, sizeof(struct tps65950_softc),
     tps65950_match, tps65950_attach, NULL, NULL);
@@ -118,22 +137,28 @@
        switch (sc->sc_addr) {
        case TPS65950_ADDR_ID2:
                memset(buf, 0, sizeof(buf));
+               iic_acquire_bus(sc->sc_i2c, 0);
                tps65950_write_1(sc, TPS65950_ID2_UNLOCK_TEST_REG,
                    TPS65950_ID2_UNLOCK_TEST_REG_MAGIC);
                tps65950_read_1(sc, TPS65950_ID2_IDCODE_7_0, &buf[0]);
                tps65950_read_1(sc, TPS65950_ID2_IDCODE_15_8, &buf[1]);
                tps65950_read_1(sc, TPS65950_ID2_IDCODE_23_16, &buf[2]);
                tps65950_read_1(sc, TPS65950_ID2_IDCODE_31_24, &buf[3]);
+               iic_release_bus(sc->sc_i2c, 0);
                idcode = (buf[0] << 0) | (buf[1] << 8) |
                         (buf[2] << 16) | (buf[3] << 24);
                aprint_normal(": IDCODE %08X\n", idcode);
                break;
        case TPS65950_ADDR_ID3:
-               aprint_normal(": group %02x\n", sc->sc_addr);
+               aprint_normal(": LED\n");
                tps65950_sysctl_attach(sc);
                break;
+       case TPS65950_ADDR_ID4:
+               aprint_normal(": WATCHDOG\n");
+               tps65950_wdog_attach(sc);
+               break;
        default:
-               aprint_normal(": group %02x\n", sc->sc_addr);
+               aprint_normal("\n");
                break;
        }
 }
@@ -164,7 +189,9 @@
 
        node = *rnode;
        sc = node.sysctl_data;
+       iic_acquire_bus(sc->sc_i2c, 0);
        error = tps65950_read_1(sc, TPS65950_ID3_REG_LED, &val);
+       iic_release_bus(sc->sc_i2c, 0);
        if (error)
                return error;
        leda = (val & TPS65950_ID3_REG_LED_LEDAON) ? 1 : 0;
@@ -178,7 +205,12 @@
        else
                val &= ~(TPS65950_ID3_REG_LED_LEDAON|TPS65950_ID3_REG_LED_LEDAPWM);
 
-       return tps65950_write_1(sc, TPS65950_ID3_REG_LED, val);
+       
+       iic_acquire_bus(sc->sc_i2c, 0);
+       error = tps65950_write_1(sc, TPS65950_ID3_REG_LED, val);
+       iic_release_bus(sc->sc_i2c, 0);
+
+       return error;
 }
 
 static int
@@ -192,7 +224,9 @@
 
        node = *rnode;
        sc = node.sysctl_data;
+       iic_acquire_bus(sc->sc_i2c, 0);
        error = tps65950_read_1(sc, TPS65950_ID3_REG_LED, &val);
+       iic_release_bus(sc->sc_i2c, 0);
        if (error)
                return error;
        ledb = (val & TPS65950_ID3_REG_LED_LEDBON) ? 1 : 0;
@@ -206,7 +240,11 @@
        else
                val &= ~(TPS65950_ID3_REG_LED_LEDBON|TPS65950_ID3_REG_LED_LEDBPWM);
 
-       return tps65950_write_1(sc, TPS65950_ID3_REG_LED, val);
+       iic_acquire_bus(sc->sc_i2c, 0);
+       error = tps65950_write_1(sc, TPS65950_ID3_REG_LED, val);
+       iic_release_bus(sc->sc_i2c, 0);
+
+       return error;
 }
 
 static void
@@ -241,3 +279,58 @@
        if (error)
                return;
 }
+
+static void
+tps65950_wdog_attach(struct tps65950_softc *sc)
+{
+       sc->sc_smw.smw_name = device_xname(sc->sc_dev);
+       sc->sc_smw.smw_cookie = sc;
+       sc->sc_smw.smw_setmode = tps65950_wdog_setmode;
+       sc->sc_smw.smw_tickle = tps65950_wdog_tickle;
+       sc->sc_smw.smw_period = TPS65950_WDOG_DEFAULT_PERIOD;
+
+       if (sysmon_wdog_register(&sc->sc_smw) != 0)
+               aprint_error_dev(sc->sc_dev, "couldn't register watchdog\n");
+
+       iic_acquire_bus(sc->sc_i2c, 0);
+       tps65950_write_1(sc, TPS65950_ID4_REG_WATCHDOG_CFG, 0);
+       iic_release_bus(sc->sc_i2c, 0);
+}
+
+static int
+tps65950_wdog_setmode(struct sysmon_wdog *smw)
+{
+       struct tps65950_softc *sc = smw->smw_cookie;
+       int error;
+
+       if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
+               iic_acquire_bus(sc->sc_i2c, 0);
+               error = tps65950_write_1(sc, TPS65950_ID4_REG_WATCHDOG_CFG, 0);
+               iic_release_bus(sc->sc_i2c, 0);
+       } else {
+               if (smw->smw_period == WDOG_PERIOD_DEFAULT) {
+                       smw->smw_period = TPS65950_WDOG_DEFAULT_PERIOD;
+               }
+               if (smw->smw_period > 30) {
+                       error = EINVAL;
+               } else {
+                       error = tps65950_wdog_tickle(smw);
+               }
+       }
+       return error;
+}
+
+static int
+tps65950_wdog_tickle(struct sysmon_wdog *smw)
+{
+       struct tps65950_softc *sc = smw->smw_cookie;
+       int error;
+
+       iic_acquire_bus(sc->sc_i2c, 0);
+       tps65950_write_1(sc, TPS65950_ID4_REG_WATCHDOG_CFG, 0);
+       error = tps65950_write_1(sc, TPS65950_ID4_REG_WATCHDOG_CFG,
+           smw->smw_period + 1);
+       iic_release_bus(sc->sc_i2c, 0);
+
+       return error;
+}



Home | Main Index | Thread Index | Old Index