Author: ian
Date: Sun Jul 30 18:46:38 2017
New Revision: 321726
URL: https://svnweb.freebsd.org/changeset/base/321726

Log:
  Bugfixes and enhancements...
  
  Don't enable the oscillator when it is found to be stopped at init time,
  just let the first setting of valid time start it.  But still report a dead
  battery if it's stopped at init time.
  
  Don't force the chip into 24hr mode, just cope with whatever mode it is
  already in.
  
  Align the RTC clock to top of second when setting it.

Modified:
  head/sys/dev/iicbus/ds1307.c
  head/sys/dev/iicbus/ds1307reg.h

Modified: head/sys/dev/iicbus/ds1307.c
==============================================================================
--- head/sys/dev/iicbus/ds1307.c        Sun Jul 30 18:38:05 2017        
(r321725)
+++ head/sys/dev/iicbus/ds1307.c        Sun Jul 30 18:46:38 2017        
(r321726)
@@ -56,20 +56,20 @@ __FBSDID("$FreeBSD$");
 
 struct ds1307_softc {
        device_t        sc_dev;
-       int             sc_year0;
-       struct intr_config_hook enum_hook;
-       uint16_t        sc_addr;        /* DS1307 slave address. */
+       struct intr_config_hook
+                       enum_hook;
        uint8_t         sc_ctrl;
-       int             sc_mcp7941x;
+       bool            sc_mcp7941x;
+       bool            sc_use_ampm;
 };
 
 static void ds1307_start(void *);
 
 #ifdef FDT
 static const struct ofw_compat_data ds1307_compat_data[] = {
-    {"dallas,ds1307", (uintptr_t)"Maxim DS1307 RTC"},
-    {"maxim,ds1307", (uintptr_t)"Maxim DS1307 RTC"},
-    {"microchip,mcp7941x", (uintptr_t)"Microchip MCP7941x RTC"},
+    {"dallas,ds1307",          (uintptr_t)"Dallas DS1307 RTC"},
+    {"maxim,ds1307",           (uintptr_t)"Maxim DS1307 RTC"},
+    {"microchip,mcp7941x",     (uintptr_t)"Microchip MCP7941x RTC"},
     { NULL, 0 }
 };
 #endif
@@ -118,48 +118,6 @@ ds1307_ctrl_write(struct ds1307_softc *sc)
 }
 
 static int
-ds1307_osc_enable(struct ds1307_softc *sc)
-{
-       int error;
-       uint8_t secs;
-
-       error = ds1307_read1(sc->sc_dev, DS1307_SECS, &secs);
-       if (error) {
-               device_printf(sc->sc_dev, "cannot read from RTC.\n");
-               return (error);
-       }
-       /* Check if the oscillator is disabled. */
-       if ((secs & DS1307_SECS_CH) == 0)
-               return (0);
-       device_printf(sc->sc_dev, "clock was halted, check the battery.\n");
-       secs &= DS1307_SECS_MASK;
-       error = ds1307_write1(sc->sc_dev, DS1307_SECS, secs);
-       if (error != 0)
-               device_printf(sc->sc_dev, "cannot write to RTC.\n");
-
-       return (error);
-}
-
-static int
-ds1307_set_24hrs_mode(struct ds1307_softc *sc)
-{
-       int error;
-       uint8_t hour;
-
-       error = ds1307_read1(sc->sc_dev, DS1307_HOUR, &hour);
-       if (error) {
-               device_printf(sc->sc_dev, "cannot read from RTC.\n");
-               return (error);
-       }
-       hour &= DS1307_HOUR_MASK;
-       error = ds1307_write1(sc->sc_dev, DS1307_HOUR, hour);
-       if (error != 0)
-               device_printf(sc->sc_dev, "cannot write to RTC.\n");
-
-       return (error);
-}
-
-static int
 ds1307_sqwe_sysctl(SYSCTL_HANDLER_ARGS)
 {
        int sqwe, error, newv, sqwe_bit;
@@ -268,7 +226,7 @@ ds1307_probe(device_t dev)
 #else
        device_set_desc(dev, "Maxim DS1307 RTC");
 
-       return (BUS_PROBE_DEFAULT);
+       return (BUS_PROBE_NOWILDCARD);
 #endif
 }
 
@@ -279,8 +237,6 @@ ds1307_attach(device_t dev)
 
        sc = device_get_softc(dev);
        sc->sc_dev = dev;
-       sc->sc_addr = iicbus_get_addr(dev);
-       sc->sc_year0 = 1900;
        sc->enum_hook.ich_func = ds1307_start;
        sc->enum_hook.ich_arg = dev;
 
@@ -307,6 +263,7 @@ ds1307_start(void *xdev)
        struct sysctl_ctx_list *ctx;
        struct sysctl_oid *tree_node;
        struct sysctl_oid_list *tree;
+       uint8_t secs;
 
        dev = (device_t)xdev;
        sc = device_get_softc(dev);
@@ -315,12 +272,16 @@ ds1307_start(void *xdev)
        tree = SYSCTL_CHILDREN(tree_node);
 
        config_intrhook_disestablish(&sc->enum_hook);
-       /* Set the 24 hours mode. */
-       if (ds1307_set_24hrs_mode(sc) != 0)
+
+       /* Check if the oscillator is disabled. */
+       if (ds1307_read1(sc->sc_dev, DS1307_SECS, &secs) != 0) {
+               device_printf(sc->sc_dev, "cannot read from RTC.\n");
                return;
-       /* Enable the oscillator if halted. */
-       if (ds1307_osc_enable(sc) != 0)
-               return;
+       }
+       if ((secs & DS1307_SECS_CH) != 0) {
+               device_printf(sc->sc_dev,
+                   "WARNING: RTC clock stopped, check the battery.\n");
+       }
 
        /* Configuration parameters. */
        SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, "sqwe",
@@ -334,8 +295,8 @@ ds1307_start(void *xdev)
            CTLFLAG_RW | CTLTYPE_UINT | CTLFLAG_MPSAFE, sc, 0,
            ds1307_sqw_out_sysctl, "IU", "DS1307 square-wave output state");
 
-       /* 1 second resolution. */
-       clock_register(dev, 1000000);
+       /* Register as a clock with 1 second resolution. */
+       clock_register_flags(dev, 1000000, CLOCKF_SETTIME_NO_TS);
 }
 
 static int
@@ -344,7 +305,7 @@ ds1307_gettime(device_t dev, struct timespec *ts)
        int error;
        struct clocktime ct;
        struct ds1307_softc *sc;
-       uint8_t data[7];
+       uint8_t data[7], hourmask;
 
        sc = device_get_softc(dev);
        error = iicdev_readfrom(sc->sc_dev, DS1307_SECS, data, sizeof(data),
@@ -353,32 +314,72 @@ ds1307_gettime(device_t dev, struct timespec *ts)
                device_printf(dev, "cannot read from RTC.\n");
                return (error);
        }
+
+       /* If chip is in AM/PM mode remember that. */
+       if (data[DS1307_HOUR] & DS1307_HOUR_USE_AMPM) {
+               sc->sc_use_ampm = true;
+               hourmask = DS1307_HOUR_MASK_12HR;
+       } else
+               hourmask = DS1307_HOUR_MASK_24HR;
+
        ct.nsec = 0;
-       ct.sec = FROMBCD(data[DS1307_SECS] & DS1307_SECS_MASK);
-       ct.min = FROMBCD(data[DS1307_MINS] & DS1307_MINS_MASK);
-       ct.hour = FROMBCD(data[DS1307_HOUR] & DS1307_HOUR_MASK);
-       ct.day = FROMBCD(data[DS1307_DATE] & DS1307_DATE_MASK);
-       ct.dow = data[DS1307_WEEKDAY] & DS1307_WEEKDAY_MASK;
-       ct.mon = FROMBCD(data[DS1307_MONTH] & DS1307_MONTH_MASK);
-       ct.year = FROMBCD(data[DS1307_YEAR] & DS1307_YEAR_MASK);
+       ct.sec  = FROMBCD(data[DS1307_SECS]  & DS1307_SECS_MASK);
+       ct.min  = FROMBCD(data[DS1307_MINS]  & DS1307_MINS_MASK);
+       ct.hour = FROMBCD(data[DS1307_HOUR]  & hourmask);
+       ct.day  = FROMBCD(data[DS1307_DATE]  & DS1307_DATE_MASK);
+       ct.mon  = FROMBCD(data[DS1307_MONTH] & DS1307_MONTH_MASK);
+       ct.year = FROMBCD(data[DS1307_YEAR]  & DS1307_YEAR_MASK);
 
+       if (sc->sc_use_ampm) {
+               if (ct.hour == 12)
+                       ct.hour = 0;
+               if (data[DS1307_HOUR] & DS1307_HOUR_IS_PM)
+                       ct.hour += 12;
+       }
+
        return (clock_ct_to_ts(&ct, ts));
 }
 
 static int
 ds1307_settime(device_t dev, struct timespec *ts)
 {
-       int error;
        struct clocktime ct;
        struct ds1307_softc *sc;
+       long waitns;
+       int error;
        uint8_t data[7];
+       uint8_t pmflags;
 
        sc = device_get_softc(dev);
+
+       /* Sleep until 1ms into the second, to align RTC's second to ours. */
+       getnanotime(ts);
+       waitns = 1000000 - ts->tv_nsec;
+       if (waitns < 0)
+               waitns += 1000000000;
+       pause_sbt("set1307", nstosbt(waitns), 0, C_PREL(31));
+
+       /* Grab a fresh post-sleep idea of the time. */
+       getnanotime(ts);
+       ts->tv_sec -= utc_offset();
        ts->tv_nsec = 0;
        clock_ts_to_ct(ts, &ct);
+
+       /* If the chip is in AM/PM mode, adjust hour and set flags as needed. */
+       if (sc->sc_use_ampm) {
+               pmflags = DS1307_HOUR_USE_AMPM;
+               if (ct.hour >= 12) {
+                       ct.hour -= 12;
+                       pmflags |= DS1307_HOUR_IS_PM;
+               }
+               if (ct.hour == 0)
+                       ct.hour = 12;
+       } else
+               pmflags = 0;
+
        data[DS1307_SECS]    = TOBCD(ct.sec);
        data[DS1307_MINS]    = TOBCD(ct.min);
-       data[DS1307_HOUR]    = TOBCD(ct.hour);
+       data[DS1307_HOUR]    = TOBCD(ct.hour) | pmflags;
        data[DS1307_DATE]    = TOBCD(ct.day);
        data[DS1307_WEEKDAY] = ct.dow;
        data[DS1307_MONTH]   = TOBCD(ct.mon);

Modified: head/sys/dev/iicbus/ds1307reg.h
==============================================================================
--- head/sys/dev/iicbus/ds1307reg.h     Sun Jul 30 18:38:05 2017        
(r321725)
+++ head/sys/dev/iicbus/ds1307reg.h     Sun Jul 30 18:46:38 2017        
(r321726)
@@ -39,7 +39,10 @@
 #define        DS1307_MINS             0x01
 #define        DS1307_MINS_MASK                0x7f
 #define        DS1307_HOUR             0x02
-#define        DS1307_HOUR_MASK                0x3f
+#define        DS1307_HOUR_MASK_12HR           0x1f
+#define        DS1307_HOUR_MASK_24HR           0x3f
+#define        DS1307_HOUR_IS_PM               0x20
+#define        DS1307_HOUR_USE_AMPM            0x40
 #define        DS1307_WEEKDAY          0x03
 #define        DS1307_WEEKDAY_MASK             0x07
 #define        DS1307_DATE             0x04
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to