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 AS3722 RTC.



details:   https://anonhg.NetBSD.org/src/rev/8756593cc590
branches:  trunk
changeset: 823418:8756593cc590
user:      jmcneill <jmcneill%NetBSD.org@localhost>
date:      Sat Apr 22 13:26:05 2017 +0000

description:
Add support for AS3722 RTC.

diffstat:

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

diffs (234 lines):

diff -r aa4e2ca2c5c5 -r 8756593cc590 sys/dev/i2c/as3722.c
--- a/sys/dev/i2c/as3722.c      Sat Apr 22 13:24:45 2017 +0000
+++ b/sys/dev/i2c/as3722.c      Sat Apr 22 13:26:05 2017 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: as3722.c,v 1.5 2016/07/23 19:14:36 jakllsch Exp $ */
+/* $NetBSD: as3722.c,v 1.6 2017/04/22 13:26:05 jmcneill Exp $ */
 
 /*-
  * Copyright (c) 2015 Jared D. McNeill <jmcneill%invisible.ca@localhost>
@@ -26,8 +26,10 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include "opt_fdt.h"
+
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: as3722.c,v 1.5 2016/07/23 19:14:36 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: as3722.c,v 1.6 2017/04/22 13:26:05 jmcneill Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -38,11 +40,19 @@
 #include <sys/kmem.h>
 #include <sys/wdog.h>
 
+#include <dev/clock_subr.h>
+
 #include <dev/sysmon/sysmonvar.h>
 
 #include <dev/i2c/i2cvar.h>
 #include <dev/i2c/as3722.h>
 
+#ifdef FDT
+#include <dev/fdt/fdtvar.h>
+#endif
+
+#define AS3722_START_YEAR              2000
+
 #define AS3722_GPIO0_CTRL_REG          0x08
 #define AS3722_GPIO0_CTRL_INVERT       __BIT(7)
 #define AS3722_GPIO0_CTRL_IOSF         __BITS(6,3)
@@ -66,6 +76,17 @@
 #define AS3722_WATCHDOG_SIGNAL_PWM_DIV __BITS(7,6)
 #define AS3722_WATCHDOG_SIGNAL_SW_SIG  __BIT(0)
 
+#define AS3722_RTC_CONTROL_REG         0x60
+#define AS3722_RTC_CONTROL_RTC_ON      __BIT(2)
+
+#define AS3722_RTC_SECOND_REG          0x61
+#define AS3722_RTC_MINUTE_REG          0x62
+#define AS3722_RTC_HOUR_REG            0x63
+#define AS3722_RTC_DAY_REG             0x64
+#define AS3722_RTC_MONTH_REG           0x65
+#define AS3722_RTC_YEAR_REG            0x66
+#define AS3722_RTC_ACCESS_REG          0x6f
+
 #define AS3722_ASIC_ID1_REG            0x90
 #define AS3722_ASIC_ID2_REG            0x91
 
@@ -73,8 +94,10 @@
        device_t        sc_dev;
        i2c_tag_t       sc_i2c;
        i2c_addr_t      sc_addr;
+       int             sc_phandle;
 
        struct sysmon_wdog sc_smw;
+       struct todr_chip_handle sc_todr;
 };
 
 #define AS3722_WATCHDOG_DEFAULT_PERIOD 10
@@ -82,9 +105,14 @@
 static int     as3722_match(device_t, cfdata_t, void *);
 static void    as3722_attach(device_t, device_t, void *);
 
+static void    as3722_wdt_attach(struct as3722_softc *);
 static int     as3722_wdt_setmode(struct sysmon_wdog *);
 static int     as3722_wdt_tickle(struct sysmon_wdog *);
 
+static void    as3722_rtc_attach(struct as3722_softc *);
+static int     as3722_rtc_gettime(todr_chip_handle_t, struct clock_ymdhms *);
+static int     as3722_rtc_settime(todr_chip_handle_t, struct clock_ymdhms *);
+
 static int     as3722_read(struct as3722_softc *, uint8_t, uint8_t *, int);
 static int     as3722_write(struct as3722_softc *, uint8_t, uint8_t, int);
 static int     as3722_set_clear(struct as3722_softc *, uint8_t, uint8_t,
@@ -126,15 +154,24 @@
 {
        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;
        sc->sc_addr = ia->ia_addr;
+       sc->sc_phandle = ia->ia_cookie;
 
        aprint_naive("\n");
        aprint_normal(": AMS AS3722\n");
 
+       as3722_wdt_attach(sc);
+       as3722_rtc_attach(sc);
+}
+
+static void
+as3722_wdt_attach(struct as3722_softc *sc)
+{
+       int error;
+
        iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
        error = as3722_write(sc, AS3722_GPIO0_CTRL_REG,
            __SHIFTIN(AS3722_GPIO0_CTRL_IOSF_GPIO,
@@ -146,20 +183,47 @@
            __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");
+       if (error) {
+               aprint_error_dev(sc->sc_dev, "couldn't setup watchdog\n");
+               return;
+       }
 
-       sc->sc_smw.smw_name = device_xname(self);
+       sc->sc_smw.smw_name = device_xname(sc->sc_dev);
        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",
+       aprint_normal_dev(sc->sc_dev, "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");
+               aprint_error_dev(sc->sc_dev, "couldn't register with sysmon\n");
+}
+
+static void
+as3722_rtc_attach(struct as3722_softc *sc)
+{
+       int error;
+
+       iic_acquire_bus(sc->sc_i2c, I2C_F_POLL);
+       error = as3722_set_clear(sc, AS3722_RTC_CONTROL_REG,
+           AS3722_RTC_CONTROL_RTC_ON, 0, I2C_F_POLL);
+       iic_release_bus(sc->sc_i2c, I2C_F_POLL);
+
+       if (error) {
+               aprint_error_dev(sc->sc_dev, "couldn't setup RTC\n");
+               return;
+       }
+
+       sc->sc_todr.todr_gettime_ymdhms = as3722_rtc_gettime;
+       sc->sc_todr.todr_settime_ymdhms = as3722_rtc_settime;
+       sc->sc_todr.cookie = sc;
+#ifdef FDT
+       fdtbus_todr_attach(sc->sc_dev, sc->sc_phandle, &sc->sc_todr);
+#else
+       todr_attach(&sc->sc_todr);
+#endif
 }
 
 static int
@@ -246,6 +310,69 @@
        return error;
 }
 
+static int
+as3722_rtc_gettime(todr_chip_handle_t tch, struct clock_ymdhms *dt)
+{
+       struct as3722_softc * const sc = tch->cookie;
+       uint8_t buf[6];
+       int error = 0;
+
+       const int flags = (cold ? I2C_F_POLL : 0);
+
+       iic_acquire_bus(sc->sc_i2c, flags);
+       error += as3722_read(sc, AS3722_RTC_SECOND_REG, &buf[0], flags);
+       error += as3722_read(sc, AS3722_RTC_MINUTE_REG, &buf[1], flags);
+       error += as3722_read(sc, AS3722_RTC_HOUR_REG, &buf[2], flags);
+       error += as3722_read(sc, AS3722_RTC_DAY_REG, &buf[3], flags);
+       error += as3722_read(sc, AS3722_RTC_MONTH_REG, &buf[4], flags);
+       error += as3722_read(sc, AS3722_RTC_YEAR_REG, &buf[5], flags);
+       iic_release_bus(sc->sc_i2c, flags);
+
+       if (error)
+               return error;
+
+       dt->dt_sec = bcdtobin(buf[0] & 0x7f);
+       dt->dt_min = bcdtobin(buf[1] & 0x7f);
+       dt->dt_hour = bcdtobin(buf[2] & 0x3f);
+       dt->dt_day = bcdtobin(buf[3] & 0x3f);
+       dt->dt_mon = bcdtobin(buf[4] & 0x1f) - 1;
+       dt->dt_year = AS3722_START_YEAR + bcdtobin(buf[5] & 0x7f);
+       dt->dt_wday = 0;
+
+       return 0;
+}
+
+static int
+as3722_rtc_settime(todr_chip_handle_t tch, struct clock_ymdhms *dt)
+{
+       struct as3722_softc * const sc = tch->cookie;
+       uint8_t buf[6];
+       int error = 0;
+
+       if (dt->dt_year < AS3722_START_YEAR)
+               return EINVAL;
+
+       buf[0] = bintobcd(dt->dt_sec) & 0x7f;
+       buf[1] = bintobcd(dt->dt_min) & 0x7f;
+       buf[2] = bintobcd(dt->dt_hour) & 0x3f;
+       buf[3] = bintobcd(dt->dt_day) & 0x3f;
+       buf[4] = bintobcd(dt->dt_mon + 1) & 0x1f;
+       buf[5] = bintobcd(dt->dt_year - AS3722_START_YEAR) & 0x7f;
+
+       const int flags = (cold ? I2C_F_POLL : 0);
+
+       iic_acquire_bus(sc->sc_i2c, flags);
+       error += as3722_write(sc, AS3722_RTC_SECOND_REG, buf[0], flags);
+       error += as3722_write(sc, AS3722_RTC_MINUTE_REG, buf[1], flags);
+       error += as3722_write(sc, AS3722_RTC_HOUR_REG, buf[2], flags);
+       error += as3722_write(sc, AS3722_RTC_DAY_REG, buf[3], flags);
+       error += as3722_write(sc, AS3722_RTC_MONTH_REG, buf[4], flags);
+       error += as3722_write(sc, AS3722_RTC_YEAR_REG, buf[5], flags);
+       iic_release_bus(sc->sc_i2c, flags);
+
+       return error;
+}
+
 int
 as3722_poweroff(device_t dev)
 {



Home | Main Index | Thread Index | Old Index