[U-Boot] [PATCH] drivers/rtc: add support for MCP7941x RTCs

Philip Paeps philip at paeps.cx
Thu Mar 6 23:26:32 CET 2014


The Microchip MCP7941x series of chips are very similar
to Maxim's DS1307 but have some important differences:

 o I2C address 0x6f rather than 0x68
 o The oscillator start bit logic is reversed
 o VBATEN bit to enable a power-fail time-stamp
 o SQWE is bit 6 of the control register, not bit 4

Adapt the DS1307 driver to support these chips.

Signed-off-by: Philip Paeps <philip at paeps.cx>
---
 README               |    1 +
 drivers/rtc/Makefile |    1 +
 drivers/rtc/ds1307.c |   49 ++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/README b/README
index 216f0c7..830379d 100644
--- a/README
+++ b/README
@@ -1111,6 +1111,7 @@ The following options need to be configured:
 		CONFIG_RTC_DS164x	- use Dallas DS164x RTC
 		CONFIG_RTC_ISL1208	- use Intersil ISL1208 RTC
 		CONFIG_RTC_MAX6900	- use Maxim, Inc. MAX6900 RTC
+		CONFIG_RTC_MCP7941X	- use Microchip MCP7941x RTC
 		CONFIG_SYS_RTC_DS1337_NOOSC	- Turn off the OSC output for DS1337
 		CONFIG_SYS_RV3029_TCR	- enable trickle charger on
 					  RV3029 RTC.
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 003d322..49451d9 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_RTC_DS1302) += ds1302.o
 obj-$(CONFIG_RTC_DS1306) += ds1306.o
 obj-$(CONFIG_RTC_DS1307) += ds1307.o
 obj-$(CONFIG_RTC_DS1338) += ds1307.o
+obj-$(CONFIG_RTC_MCP7941X) += ds1307.o
 obj-$(CONFIG_RTC_DS1337) += ds1337.o
 obj-$(CONFIG_RTC_DS1374) += ds1374.o
 obj-$(CONFIG_RTC_DS1388) += ds1337.o
diff --git a/drivers/rtc/ds1307.c b/drivers/rtc/ds1307.c
index 1a2bad3..cbbdf9c 100644
--- a/drivers/rtc/ds1307.c
+++ b/drivers/rtc/ds1307.c
@@ -32,13 +32,21 @@
 /*---------------------------------------------------------------------*/
 
 #ifndef CONFIG_SYS_I2C_RTC_ADDR
-# define CONFIG_SYS_I2C_RTC_ADDR	0x68
+# ifdef CONFIG_RTC_MCP7941X
+#  define CONFIG_SYS_I2C_RTC_ADDR	0x6f
+# else
+#  define CONFIG_SYS_I2C_RTC_ADDR	0x68
+# endif
 #endif
 
 #if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000)
 # error The DS1307 is specified only up to 100kHz!
 #endif
 
+#if defined(CONFIG_RTC_MCP7941X) && (CONFIG_SYS_I2C_SPEED > 400000)
+# error The MCP7941x is specified only up to 400kHz!
+#endif
+
 /*
  * RTC register addresses
  */
@@ -51,11 +59,20 @@
 #define RTC_YR_REG_ADDR		0x06
 #define RTC_CTL_REG_ADDR	0x07
 
+#ifdef CONFIG_RTC_MCP7941X
+#define RTC_SEC_BIT_ST		0x80	/* Oscillator start (in reg 0)	*/
+#define RTC_DAY_BIT_VBATEN	0x08	/* VBAT enable (in register 3)	*/
+#else
 #define RTC_SEC_BIT_CH		0x80	/* Clock Halt (in Register 0)   */
+#endif
 
 #define RTC_CTL_BIT_RS0		0x01	/* Rate select 0                */
 #define RTC_CTL_BIT_RS1		0x02	/* Rate select 1                */
+#ifdef CONFIG_RTC_MCP7941X
+#define RTC_CTL_BIT_SQWE	0x40	/* Square Wave Enable           */
+#else
 #define RTC_CTL_BIT_SQWE	0x10	/* Square Wave Enable           */
+#endif
 #define RTC_CTL_BIT_OUT		0x80	/* Output Control               */
 
 static uchar rtc_read (uchar reg);
@@ -81,6 +98,19 @@ int rtc_get (struct rtc_time *tmp)
 		"hr: %02x min: %02x sec: %02x\n",
 		year, mon, mday, wday, hour, min, sec);
 
+#ifdef CONFIG_RTC_MCP7941X
+	if (!(wday & RTC_DAY_BIT_VBATEN)) {
+		printf ("### Warning: VBAT not enabled - enabling\n");
+		rtc_write (RTC_DAY_REG_ADDR,
+			rtc_read (RTC_DAY_REG_ADDR) | RTC_DAY_BIT_VBATEN);
+	}
+	if (!(sec & RTC_SEC_BIT_ST)) {
+		printf ("### Warning: RTC oscillator has stopped\n");
+		rtc_write (RTC_SEC_REG_ADDR,
+			   rtc_read (RTC_SEC_REG_ADDR) | RTC_SEC_BIT_ST);
+		rel = -1;
+	}
+#else
 	if (sec & RTC_SEC_BIT_CH) {
 		printf ("### Warning: RTC oscillator has stopped\n");
 		/* clear the CH flag */
@@ -88,6 +118,7 @@ int rtc_get (struct rtc_time *tmp)
 			   rtc_read (RTC_SEC_REG_ADDR) & ~RTC_SEC_BIT_CH);
 		rel = -1;
 	}
+#endif
 
 	tmp->tm_sec  = bcd2bin (sec & 0x7F);
 	tmp->tm_min  = bcd2bin (min & 0x7F);
@@ -121,11 +152,21 @@ int rtc_set (struct rtc_time *tmp)
 
 	rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100));
 	rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon));
+#ifdef CONFIG_RTC_MCP7941X
+	/* Don't clobber the VBATEN bit. */
+	rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1) | RTC_DAY_BIT_VBATEN);
+#else
 	rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1));
+#endif
 	rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday));
 	rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour));
 	rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
+#ifdef CONFIG_RTC_MCP7941X
+	/* Don't clobber the ST bit. */
+	rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec) | RTC_SEC_BIT_ST);
+#else
 	rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
+#endif
 
 	return 0;
 }
@@ -142,7 +183,13 @@ void rtc_reset (void)
 {
 	struct rtc_time tmp;
 
+#ifdef CONFIG_RTC_MCP7941X
+	/* Set the oscillator start and VBATEN bits. */
+	rtc_write (RTC_SEC_REG_ADDR, RTC_SEC_BIT_ST);
+	rtc_write (RTC_DAY_REG_ADDR, RTC_DAY_BIT_VBATEN);
+#else
 	rtc_write (RTC_SEC_REG_ADDR, 0x00);	/* clearing Clock Halt	*/
+#endif
 	rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS0);
 
 	tmp.tm_year = 1970;
-- 
1.7.10.4



More information about the U-Boot mailing list