xref: /rk3399_rockchip-uboot/drivers/rtc/ds1307.c (revision 4f66e09bb9fbc47b73f67c3cc08ee2663e8fcdb1)
10c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
20c698dcaSJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2001, 2002, 2003
30c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
40c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Keith Outwater, keith_outwater@mvis.com`
50c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Steven Scholz, steven.scholz@imc-berlin.de
60c698dcaSJean-Christophe PLAGNIOL-VILLARD  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
80c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
90c698dcaSJean-Christophe PLAGNIOL-VILLARD 
100c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
110c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Date & Time support (no alarms) for Dallas Semiconductor (now Maxim)
12412921d2SMarkus Niebel  * DS1307 and DS1338/9 Real Time Clock (RTC).
130c698dcaSJean-Christophe PLAGNIOL-VILLARD  *
140c698dcaSJean-Christophe PLAGNIOL-VILLARD  * based on ds1337.c
150c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
160c698dcaSJean-Christophe PLAGNIOL-VILLARD 
170c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
180c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <command.h>
19*d425d605SChris Packham #include <dm.h>
200c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <rtc.h>
210c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <i2c.h>
220c698dcaSJean-Christophe PLAGNIOL-VILLARD 
23*d425d605SChris Packham enum ds_type {
24*d425d605SChris Packham 	ds_1307,
25*d425d605SChris Packham 	ds_1337,
26*d425d605SChris Packham 	ds_1340,
27*d425d605SChris Packham 	mcp794xx,
28*d425d605SChris Packham };
290c698dcaSJean-Christophe PLAGNIOL-VILLARD 
300c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
310c698dcaSJean-Christophe PLAGNIOL-VILLARD  * RTC register addresses
320c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
330c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_SEC_REG_ADDR	0x00
340c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_MIN_REG_ADDR	0x01
350c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_HR_REG_ADDR		0x02
360c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_DAY_REG_ADDR	0x03
370c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_DATE_REG_ADDR	0x04
380c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_MON_REG_ADDR	0x05
390c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_YR_REG_ADDR		0x06
400c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_CTL_REG_ADDR	0x07
410c698dcaSJean-Christophe PLAGNIOL-VILLARD 
420c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_SEC_BIT_CH		0x80	/* Clock Halt (in Register 0)   */
430c698dcaSJean-Christophe PLAGNIOL-VILLARD 
440c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_CTL_BIT_RS0		0x01	/* Rate select 0                */
450c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_CTL_BIT_RS1		0x02	/* Rate select 1                */
460c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_CTL_BIT_SQWE	0x10	/* Square Wave Enable           */
470c698dcaSJean-Christophe PLAGNIOL-VILLARD #define RTC_CTL_BIT_OUT		0x80	/* Output Control               */
480c698dcaSJean-Christophe PLAGNIOL-VILLARD 
49c79e1c1cSAndy Fleming /* MCP7941X-specific bits */
50c79e1c1cSAndy Fleming #define MCP7941X_BIT_ST		0x80
51c79e1c1cSAndy Fleming #define MCP7941X_BIT_VBATEN	0x08
52c79e1c1cSAndy Fleming 
53*d425d605SChris Packham #ifndef CONFIG_DM_RTC
54*d425d605SChris Packham 
55*d425d605SChris Packham #if defined(CONFIG_CMD_DATE)
56*d425d605SChris Packham 
57*d425d605SChris Packham /*---------------------------------------------------------------------*/
58*d425d605SChris Packham #undef DEBUG_RTC
59*d425d605SChris Packham 
60*d425d605SChris Packham #ifdef DEBUG_RTC
61*d425d605SChris Packham #define DEBUGR(fmt, args...) printf(fmt, ##args)
62*d425d605SChris Packham #else
63*d425d605SChris Packham #define DEBUGR(fmt, args...)
64*d425d605SChris Packham #endif
65*d425d605SChris Packham /*---------------------------------------------------------------------*/
66*d425d605SChris Packham 
67*d425d605SChris Packham #ifndef CONFIG_SYS_I2C_RTC_ADDR
68*d425d605SChris Packham # define CONFIG_SYS_I2C_RTC_ADDR	0x68
69*d425d605SChris Packham #endif
70*d425d605SChris Packham 
71*d425d605SChris Packham #if defined(CONFIG_RTC_DS1307) && (CONFIG_SYS_I2C_SPEED > 100000)
72*d425d605SChris Packham # error The DS1307 is specified only up to 100kHz!
73*d425d605SChris Packham #endif
74*d425d605SChris Packham 
750c698dcaSJean-Christophe PLAGNIOL-VILLARD static uchar rtc_read (uchar reg);
760c698dcaSJean-Christophe PLAGNIOL-VILLARD static void rtc_write (uchar reg, uchar val);
770c698dcaSJean-Christophe PLAGNIOL-VILLARD 
780c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
790c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Get the current time from the RTC
800c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
rtc_get(struct rtc_time * tmp)81b73a19e1SYuri Tikhonov int rtc_get (struct rtc_time *tmp)
820c698dcaSJean-Christophe PLAGNIOL-VILLARD {
83b73a19e1SYuri Tikhonov 	int rel = 0;
840c698dcaSJean-Christophe PLAGNIOL-VILLARD 	uchar sec, min, hour, mday, wday, mon, year;
850c698dcaSJean-Christophe PLAGNIOL-VILLARD 
86c79e1c1cSAndy Fleming #ifdef CONFIG_RTC_MCP79411
87c79e1c1cSAndy Fleming read_rtc:
88c79e1c1cSAndy Fleming #endif
890c698dcaSJean-Christophe PLAGNIOL-VILLARD 	sec = rtc_read (RTC_SEC_REG_ADDR);
900c698dcaSJean-Christophe PLAGNIOL-VILLARD 	min = rtc_read (RTC_MIN_REG_ADDR);
910c698dcaSJean-Christophe PLAGNIOL-VILLARD 	hour = rtc_read (RTC_HR_REG_ADDR);
920c698dcaSJean-Christophe PLAGNIOL-VILLARD 	wday = rtc_read (RTC_DAY_REG_ADDR);
930c698dcaSJean-Christophe PLAGNIOL-VILLARD 	mday = rtc_read (RTC_DATE_REG_ADDR);
940c698dcaSJean-Christophe PLAGNIOL-VILLARD 	mon = rtc_read (RTC_MON_REG_ADDR);
950c698dcaSJean-Christophe PLAGNIOL-VILLARD 	year = rtc_read (RTC_YR_REG_ADDR);
960c698dcaSJean-Christophe PLAGNIOL-VILLARD 
970c698dcaSJean-Christophe PLAGNIOL-VILLARD 	DEBUGR ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
980c698dcaSJean-Christophe PLAGNIOL-VILLARD 		"hr: %02x min: %02x sec: %02x\n",
990c698dcaSJean-Christophe PLAGNIOL-VILLARD 		year, mon, mday, wday, hour, min, sec);
1000c698dcaSJean-Christophe PLAGNIOL-VILLARD 
101c79e1c1cSAndy Fleming #ifdef CONFIG_RTC_DS1307
1020c698dcaSJean-Christophe PLAGNIOL-VILLARD 	if (sec & RTC_SEC_BIT_CH) {
1030c698dcaSJean-Christophe PLAGNIOL-VILLARD 		printf ("### Warning: RTC oscillator has stopped\n");
1040c698dcaSJean-Christophe PLAGNIOL-VILLARD 		/* clear the CH flag */
1050c698dcaSJean-Christophe PLAGNIOL-VILLARD 		rtc_write (RTC_SEC_REG_ADDR,
1060c698dcaSJean-Christophe PLAGNIOL-VILLARD 			   rtc_read (RTC_SEC_REG_ADDR) & ~RTC_SEC_BIT_CH);
107b73a19e1SYuri Tikhonov 		rel = -1;
1080c698dcaSJean-Christophe PLAGNIOL-VILLARD 	}
109c79e1c1cSAndy Fleming #endif
110c79e1c1cSAndy Fleming 
111c79e1c1cSAndy Fleming #ifdef CONFIG_RTC_MCP79411
112c79e1c1cSAndy Fleming 	/* make sure that the backup battery is enabled */
113c79e1c1cSAndy Fleming 	if (!(wday & MCP7941X_BIT_VBATEN)) {
114c79e1c1cSAndy Fleming 		rtc_write(RTC_DAY_REG_ADDR,
115c79e1c1cSAndy Fleming 			  wday | MCP7941X_BIT_VBATEN);
116c79e1c1cSAndy Fleming 	}
117c79e1c1cSAndy Fleming 
118c79e1c1cSAndy Fleming 	/* clock halted?  turn it on, so clock can tick. */
119c79e1c1cSAndy Fleming 	if (!(sec & MCP7941X_BIT_ST)) {
120c79e1c1cSAndy Fleming 		rtc_write(RTC_SEC_REG_ADDR, MCP7941X_BIT_ST);
121c79e1c1cSAndy Fleming 		printf("Started RTC\n");
122c79e1c1cSAndy Fleming 		goto read_rtc;
123c79e1c1cSAndy Fleming 	}
124c79e1c1cSAndy Fleming #endif
125c79e1c1cSAndy Fleming 
1260c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1270c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp->tm_sec  = bcd2bin (sec & 0x7F);
1280c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp->tm_min  = bcd2bin (min & 0x7F);
1290c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp->tm_hour = bcd2bin (hour & 0x3F);
1300c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp->tm_mday = bcd2bin (mday & 0x3F);
1310c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp->tm_mon  = bcd2bin (mon & 0x1F);
1320c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp->tm_year = bcd2bin (year) + ( bcd2bin (year) >= 70 ? 1900 : 2000);
1330c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp->tm_wday = bcd2bin ((wday - 1) & 0x07);
1340c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp->tm_yday = 0;
1350c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp->tm_isdst= 0;
1360c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1370c698dcaSJean-Christophe PLAGNIOL-VILLARD 	DEBUGR ("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
1380c698dcaSJean-Christophe PLAGNIOL-VILLARD 		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
1390c698dcaSJean-Christophe PLAGNIOL-VILLARD 		tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
140b73a19e1SYuri Tikhonov 
141b73a19e1SYuri Tikhonov 	return rel;
1420c698dcaSJean-Christophe PLAGNIOL-VILLARD }
1430c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1440c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1450c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
1460c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Set the RTC
1470c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
rtc_set(struct rtc_time * tmp)148d1e23194SJean-Christophe PLAGNIOL-VILLARD int rtc_set (struct rtc_time *tmp)
1490c698dcaSJean-Christophe PLAGNIOL-VILLARD {
1500c698dcaSJean-Christophe PLAGNIOL-VILLARD 	DEBUGR ("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
1510c698dcaSJean-Christophe PLAGNIOL-VILLARD 		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
1520c698dcaSJean-Christophe PLAGNIOL-VILLARD 		tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
1530c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1540c698dcaSJean-Christophe PLAGNIOL-VILLARD 	if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
1550c698dcaSJean-Christophe PLAGNIOL-VILLARD 		printf("WARNING: year should be between 1970 and 2069!\n");
1560c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1570c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_write (RTC_YR_REG_ADDR, bin2bcd (tmp->tm_year % 100));
1580c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_write (RTC_MON_REG_ADDR, bin2bcd (tmp->tm_mon));
159c79e1c1cSAndy Fleming #ifdef CONFIG_RTC_MCP79411
160c79e1c1cSAndy Fleming 	rtc_write (RTC_DAY_REG_ADDR,
161c79e1c1cSAndy Fleming 		   bin2bcd (tmp->tm_wday + 1) | MCP7941X_BIT_VBATEN);
162c79e1c1cSAndy Fleming #else
1630c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_write (RTC_DAY_REG_ADDR, bin2bcd (tmp->tm_wday + 1));
164c79e1c1cSAndy Fleming #endif
1650c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_write (RTC_DATE_REG_ADDR, bin2bcd (tmp->tm_mday));
1660c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_write (RTC_HR_REG_ADDR, bin2bcd (tmp->tm_hour));
1670c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_write (RTC_MIN_REG_ADDR, bin2bcd (tmp->tm_min));
168c79e1c1cSAndy Fleming #ifdef CONFIG_RTC_MCP79411
169c79e1c1cSAndy Fleming 	rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec) | MCP7941X_BIT_ST);
170c79e1c1cSAndy Fleming #else
1710c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_write (RTC_SEC_REG_ADDR, bin2bcd (tmp->tm_sec));
172c79e1c1cSAndy Fleming #endif
173d1e23194SJean-Christophe PLAGNIOL-VILLARD 
174d1e23194SJean-Christophe PLAGNIOL-VILLARD 	return 0;
1750c698dcaSJean-Christophe PLAGNIOL-VILLARD }
1760c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1770c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1780c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
1790c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Reset the RTC. We setting the date back to 1970-01-01.
1800c698dcaSJean-Christophe PLAGNIOL-VILLARD  * We also enable the oscillator output on the SQW/OUT pin and program
1810c698dcaSJean-Christophe PLAGNIOL-VILLARD  * it for 32,768 Hz output. Note that according to the datasheet, turning
1820c698dcaSJean-Christophe PLAGNIOL-VILLARD  * on the square wave output increases the current drain on the backup
1830c698dcaSJean-Christophe PLAGNIOL-VILLARD  * battery to something between 480nA and 800nA.
1840c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
rtc_reset(void)1850c698dcaSJean-Christophe PLAGNIOL-VILLARD void rtc_reset (void)
1860c698dcaSJean-Christophe PLAGNIOL-VILLARD {
1870c698dcaSJean-Christophe PLAGNIOL-VILLARD 	struct rtc_time tmp;
1880c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1890c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_write (RTC_SEC_REG_ADDR, 0x00);	/* clearing Clock Halt	*/
1900c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_write (RTC_CTL_REG_ADDR, RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 | RTC_CTL_BIT_RS0);
1910c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1920c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp.tm_year = 1970;
1930c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp.tm_mon = 1;
1940c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp.tm_mday= 1;
1950c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp.tm_hour = 0;
1960c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp.tm_min = 0;
1970c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tmp.tm_sec = 0;
1980c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1990c698dcaSJean-Christophe PLAGNIOL-VILLARD 	rtc_set(&tmp);
2000c698dcaSJean-Christophe PLAGNIOL-VILLARD 
2010c698dcaSJean-Christophe PLAGNIOL-VILLARD 	printf ( "RTC:   %4d-%02d-%02d %2d:%02d:%02d UTC\n",
2020c698dcaSJean-Christophe PLAGNIOL-VILLARD 		tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
2030c698dcaSJean-Christophe PLAGNIOL-VILLARD 		tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
2040c698dcaSJean-Christophe PLAGNIOL-VILLARD 
2050c698dcaSJean-Christophe PLAGNIOL-VILLARD 	return;
2060c698dcaSJean-Christophe PLAGNIOL-VILLARD }
2070c698dcaSJean-Christophe PLAGNIOL-VILLARD 
2080c698dcaSJean-Christophe PLAGNIOL-VILLARD 
2090c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
2100c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Helper functions
2110c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
2120c698dcaSJean-Christophe PLAGNIOL-VILLARD 
2130c698dcaSJean-Christophe PLAGNIOL-VILLARD static
rtc_read(uchar reg)2140c698dcaSJean-Christophe PLAGNIOL-VILLARD uchar rtc_read (uchar reg)
2150c698dcaSJean-Christophe PLAGNIOL-VILLARD {
2166d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	return (i2c_reg_read (CONFIG_SYS_I2C_RTC_ADDR, reg));
2170c698dcaSJean-Christophe PLAGNIOL-VILLARD }
2180c698dcaSJean-Christophe PLAGNIOL-VILLARD 
2190c698dcaSJean-Christophe PLAGNIOL-VILLARD 
rtc_write(uchar reg,uchar val)2200c698dcaSJean-Christophe PLAGNIOL-VILLARD static void rtc_write (uchar reg, uchar val)
2210c698dcaSJean-Christophe PLAGNIOL-VILLARD {
2226d0f6bcfSJean-Christophe PLAGNIOL-VILLARD 	i2c_reg_write (CONFIG_SYS_I2C_RTC_ADDR, reg, val);
2230c698dcaSJean-Christophe PLAGNIOL-VILLARD }
224*d425d605SChris Packham 
225*d425d605SChris Packham #endif /* CONFIG_CMD_DATE*/
226*d425d605SChris Packham 
227*d425d605SChris Packham #endif /* !CONFIG_DM_RTC */
228*d425d605SChris Packham 
229*d425d605SChris Packham #ifdef CONFIG_DM_RTC
ds1307_rtc_set(struct udevice * dev,const struct rtc_time * tm)230*d425d605SChris Packham static int ds1307_rtc_set(struct udevice *dev, const struct rtc_time *tm)
231*d425d605SChris Packham {
232*d425d605SChris Packham 	int ret;
233*d425d605SChris Packham 	uchar buf[7];
234*d425d605SChris Packham 	enum ds_type type = dev_get_driver_data(dev);
235*d425d605SChris Packham 
236*d425d605SChris Packham 	debug("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
237*d425d605SChris Packham 	      tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
238*d425d605SChris Packham 	      tm->tm_hour, tm->tm_min, tm->tm_sec);
239*d425d605SChris Packham 
240*d425d605SChris Packham 	if (tm->tm_year < 1970 || tm->tm_year > 2069)
241*d425d605SChris Packham 		printf("WARNING: year should be between 1970 and 2069!\n");
242*d425d605SChris Packham 
243*d425d605SChris Packham 	buf[RTC_YR_REG_ADDR] = bin2bcd(tm->tm_year % 100);
244*d425d605SChris Packham 	buf[RTC_MON_REG_ADDR] = bin2bcd(tm->tm_mon);
245*d425d605SChris Packham 	buf[RTC_DAY_REG_ADDR] = bin2bcd(tm->tm_wday + 1);
246*d425d605SChris Packham 	buf[RTC_DATE_REG_ADDR] = bin2bcd(tm->tm_mday);
247*d425d605SChris Packham 	buf[RTC_HR_REG_ADDR] = bin2bcd(tm->tm_hour);
248*d425d605SChris Packham 	buf[RTC_MIN_REG_ADDR] = bin2bcd(tm->tm_min);
249*d425d605SChris Packham 	buf[RTC_SEC_REG_ADDR] = bin2bcd(tm->tm_sec);
250*d425d605SChris Packham 
251*d425d605SChris Packham 	if (type == mcp794xx) {
252*d425d605SChris Packham 		buf[RTC_DAY_REG_ADDR] |= MCP7941X_BIT_VBATEN;
253*d425d605SChris Packham 		buf[RTC_SEC_REG_ADDR] |= MCP7941X_BIT_ST;
254*d425d605SChris Packham 	}
255*d425d605SChris Packham 
256*d425d605SChris Packham 	ret = dm_i2c_write(dev, 0, buf, sizeof(buf));
257*d425d605SChris Packham 	if (ret < 0)
258*d425d605SChris Packham 		return ret;
259*d425d605SChris Packham 
260*d425d605SChris Packham 	return 0;
261*d425d605SChris Packham }
262*d425d605SChris Packham 
ds1307_rtc_get(struct udevice * dev,struct rtc_time * tm)263*d425d605SChris Packham static int ds1307_rtc_get(struct udevice *dev, struct rtc_time *tm)
264*d425d605SChris Packham {
265*d425d605SChris Packham 	int ret;
266*d425d605SChris Packham 	uchar buf[7];
267*d425d605SChris Packham 	enum ds_type type = dev_get_driver_data(dev);
268*d425d605SChris Packham 
269*d425d605SChris Packham read_rtc:
270*d425d605SChris Packham 	ret = dm_i2c_read(dev, 0, buf, sizeof(buf));
271*d425d605SChris Packham 	if (ret < 0)
272*d425d605SChris Packham 		return ret;
273*d425d605SChris Packham 
274*d425d605SChris Packham 	if (type == ds_1307) {
275*d425d605SChris Packham 		if (buf[RTC_SEC_REG_ADDR] & RTC_SEC_BIT_CH) {
276*d425d605SChris Packham 			printf("### Warning: RTC oscillator has stopped\n");
277*d425d605SChris Packham 			/* clear the CH flag */
278*d425d605SChris Packham 			buf[RTC_SEC_REG_ADDR] &= ~RTC_SEC_BIT_CH;
279*d425d605SChris Packham 			dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR,
280*d425d605SChris Packham 					 buf[RTC_SEC_REG_ADDR]);
281*d425d605SChris Packham 			return -1;
282*d425d605SChris Packham 		}
283*d425d605SChris Packham 	}
284*d425d605SChris Packham 
285*d425d605SChris Packham 	if (type == mcp794xx) {
286*d425d605SChris Packham 		/* make sure that the backup battery is enabled */
287*d425d605SChris Packham 		if (!(buf[RTC_DAY_REG_ADDR] & MCP7941X_BIT_VBATEN)) {
288*d425d605SChris Packham 			dm_i2c_reg_write(dev, RTC_DAY_REG_ADDR,
289*d425d605SChris Packham 					 buf[RTC_DAY_REG_ADDR] |
290*d425d605SChris Packham 					 MCP7941X_BIT_VBATEN);
291*d425d605SChris Packham 		}
292*d425d605SChris Packham 
293*d425d605SChris Packham 		/* clock halted?  turn it on, so clock can tick. */
294*d425d605SChris Packham 		if (!(buf[RTC_SEC_REG_ADDR] & MCP7941X_BIT_ST)) {
295*d425d605SChris Packham 			dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR,
296*d425d605SChris Packham 					 MCP7941X_BIT_ST);
297*d425d605SChris Packham 			printf("Started RTC\n");
298*d425d605SChris Packham 			goto read_rtc;
299*d425d605SChris Packham 		}
300*d425d605SChris Packham 	}
301*d425d605SChris Packham 
302*d425d605SChris Packham 	tm->tm_sec  = bcd2bin(buf[RTC_SEC_REG_ADDR] & 0x7F);
303*d425d605SChris Packham 	tm->tm_min  = bcd2bin(buf[RTC_MIN_REG_ADDR] & 0x7F);
304*d425d605SChris Packham 	tm->tm_hour = bcd2bin(buf[RTC_HR_REG_ADDR] & 0x3F);
305*d425d605SChris Packham 	tm->tm_mday = bcd2bin(buf[RTC_DATE_REG_ADDR] & 0x3F);
306*d425d605SChris Packham 	tm->tm_mon  = bcd2bin(buf[RTC_MON_REG_ADDR] & 0x1F);
307*d425d605SChris Packham 	tm->tm_year = bcd2bin(buf[RTC_YR_REG_ADDR]) +
308*d425d605SChris Packham 			      (bcd2bin(buf[RTC_YR_REG_ADDR]) >= 70 ?
309*d425d605SChris Packham 			       1900 : 2000);
310*d425d605SChris Packham 	tm->tm_wday = bcd2bin((buf[RTC_DAY_REG_ADDR] - 1) & 0x07);
311*d425d605SChris Packham 	tm->tm_yday = 0;
312*d425d605SChris Packham 	tm->tm_isdst = 0;
313*d425d605SChris Packham 
314*d425d605SChris Packham 	debug("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
315*d425d605SChris Packham 	      tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
316*d425d605SChris Packham 	      tm->tm_hour, tm->tm_min, tm->tm_sec);
317*d425d605SChris Packham 
318*d425d605SChris Packham 	return 0;
319*d425d605SChris Packham }
320*d425d605SChris Packham 
ds1307_rtc_reset(struct udevice * dev)321*d425d605SChris Packham static int ds1307_rtc_reset(struct udevice *dev)
322*d425d605SChris Packham {
323*d425d605SChris Packham 	int ret;
324*d425d605SChris Packham 	struct rtc_time tmp = {
325*d425d605SChris Packham 		.tm_year = 1970,
326*d425d605SChris Packham 		.tm_mon = 1,
327*d425d605SChris Packham 		.tm_mday = 1,
328*d425d605SChris Packham 		.tm_hour = 0,
329*d425d605SChris Packham 		.tm_min = 0,
330*d425d605SChris Packham 		.tm_sec = 0,
331*d425d605SChris Packham 	};
332*d425d605SChris Packham 
333*d425d605SChris Packham 	/* clear Clock Halt */
334*d425d605SChris Packham 	ret = dm_i2c_reg_write(dev, RTC_SEC_REG_ADDR, 0x00);
335*d425d605SChris Packham 	if (ret < 0)
336*d425d605SChris Packham 		return ret;
337*d425d605SChris Packham 	ret = dm_i2c_reg_write(dev, RTC_CTL_REG_ADDR,
338*d425d605SChris Packham 			       RTC_CTL_BIT_SQWE | RTC_CTL_BIT_RS1 |
339*d425d605SChris Packham 			       RTC_CTL_BIT_RS0);
340*d425d605SChris Packham 	if (ret < 0)
341*d425d605SChris Packham 		return ret;
342*d425d605SChris Packham 
343*d425d605SChris Packham 	ret = ds1307_rtc_set(dev, &tmp);
344*d425d605SChris Packham 	if (ret < 0)
345*d425d605SChris Packham 		return ret;
346*d425d605SChris Packham 
347*d425d605SChris Packham 	debug("RTC:   %4d-%02d-%02d %2d:%02d:%02d UTC\n",
348*d425d605SChris Packham 	      tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
349*d425d605SChris Packham 	      tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
350*d425d605SChris Packham 
351*d425d605SChris Packham 	return 0;
352*d425d605SChris Packham }
353*d425d605SChris Packham 
ds1307_probe(struct udevice * dev)354*d425d605SChris Packham static int ds1307_probe(struct udevice *dev)
355*d425d605SChris Packham {
356*d425d605SChris Packham 	i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS |
357*d425d605SChris Packham 			   DM_I2C_CHIP_WR_ADDRESS);
358*d425d605SChris Packham 
359*d425d605SChris Packham 	return 0;
360*d425d605SChris Packham }
361*d425d605SChris Packham 
362*d425d605SChris Packham static const struct rtc_ops ds1307_rtc_ops = {
363*d425d605SChris Packham 	.get = ds1307_rtc_get,
364*d425d605SChris Packham 	.set = ds1307_rtc_set,
365*d425d605SChris Packham 	.reset = ds1307_rtc_reset,
366*d425d605SChris Packham };
367*d425d605SChris Packham 
368*d425d605SChris Packham static const struct udevice_id ds1307_rtc_ids[] = {
369*d425d605SChris Packham 	{ .compatible = "dallas,ds1307", .data = ds_1307 },
370*d425d605SChris Packham 	{ .compatible = "dallas,ds1337", .data = ds_1337 },
371*d425d605SChris Packham 	{ .compatible = "dallas,ds1340", .data = ds_1340 },
372*d425d605SChris Packham 	{ .compatible = "microchip,mcp7941x", .data = mcp794xx },
373*d425d605SChris Packham 	{ }
374*d425d605SChris Packham };
375*d425d605SChris Packham 
376*d425d605SChris Packham U_BOOT_DRIVER(rtc_ds1307) = {
377*d425d605SChris Packham 	.name	= "rtc-ds1307",
378*d425d605SChris Packham 	.id	= UCLASS_RTC,
379*d425d605SChris Packham 	.probe	= ds1307_probe,
380*d425d605SChris Packham 	.of_match = ds1307_rtc_ids,
381*d425d605SChris Packham 	.ops	= &ds1307_rtc_ops,
382*d425d605SChris Packham };
383*d425d605SChris Packham #endif /* CONFIG_DM_RTC */
384