svn commit: r321726 - head/sys/dev/iicbus

Ian Lepore ian at FreeBSD.org
Sun Jul 30 18:46:39 UTC 2017


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


More information about the svn-src-all mailing list