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