summaryrefslogtreecommitdiff
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig8
-rw-r--r--drivers/rtc/Makefile4
-rw-r--r--drivers/rtc/at91sam9_rtt.c5
-rw-r--r--drivers/rtc/bfin_rtc.c5
-rw-r--r--drivers/rtc/date.c38
-rw-r--r--drivers/rtc/ds1306.c5
-rw-r--r--drivers/rtc/ds1374.c6
-rw-r--r--drivers/rtc/ftrtc010.c5
-rw-r--r--drivers/rtc/i2c_rtc_emul.c236
-rw-r--r--drivers/rtc/imxdi.c5
-rw-r--r--drivers/rtc/mc13xxx-rtc.c5
-rw-r--r--drivers/rtc/mcfrtc.c2
-rw-r--r--drivers/rtc/mpc8xx.c5
-rw-r--r--drivers/rtc/mx27rtc.c5
-rw-r--r--drivers/rtc/mxsrtc.c5
-rw-r--r--drivers/rtc/pl031.c5
-rw-r--r--drivers/rtc/rtc-uclass.c96
-rw-r--r--drivers/rtc/sandbox_rtc.c106
18 files changed, 497 insertions, 49 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e69de29bb2d..bd63621e371 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -0,0 +1,8 @@
+config DM_RTC
+ bool "Enable Driver Model for RTC drivers"
+ depends on DM
+ help
+ Enable drver model for real-time-clock drivers. The RTC uclass
+ then provides the rtc_get()/rtc_set() interface, delegating to
+ drivers to perform the actual functions. See rtc.h for a
+ description of the API.
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index fdcbc002953..3092de1d9c6 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -7,6 +7,8 @@
#ccflags-y += -DDEBUG
+obj-$(CONFIG_DM_RTC) += rtc-uclass.o
+
obj-$(CONFIG_RTC_AT91SAM9_RTT) += at91sam9_rtt.o
obj-$(CONFIG_RTC_BFIN) += bfin_rtc.o
obj-y += date.o
@@ -24,6 +26,7 @@ obj-$(CONFIG_RTC_DS164x) += ds164x.o
obj-$(CONFIG_RTC_DS174x) += ds174x.o
obj-$(CONFIG_RTC_DS3231) += ds3231.o
obj-$(CONFIG_RTC_FTRTC010) += ftrtc010.o
+obj-$(CONFIG_SANDBOX) += i2c_rtc_emul.o
obj-$(CONFIG_RTC_IMXDI) += imxdi.o
obj-$(CONFIG_RTC_ISL1208) += isl1208.o
obj-$(CONFIG_RTC_M41T11) += m41t11.o
@@ -49,4 +52,5 @@ obj-$(CONFIG_RTC_RTC4543) += rtc4543.o
obj-$(CONFIG_RTC_RV3029) += rv3029.o
obj-$(CONFIG_RTC_RX8025) += rx8025.o
obj-$(CONFIG_RTC_S3C24X0) += s3c24x0_rtc.o
+obj-$(CONFIG_SANDBOX) += sandbox_rtc.o
obj-$(CONFIG_RTC_X1205) += x1205.o
diff --git a/drivers/rtc/at91sam9_rtt.c b/drivers/rtc/at91sam9_rtt.c
index 714dd2a34f5..a684ad6a6f7 100644
--- a/drivers/rtc/at91sam9_rtt.c
+++ b/drivers/rtc/at91sam9_rtt.c
@@ -44,7 +44,7 @@ int rtc_get (struct rtc_time *tmp)
} while (tim!=tim2);
off = readl(&gpbr->reg[AT91_GPBR_INDEX_TIMEOFF]);
/* off==0 means time is invalid, but we ignore that */
- to_tm (tim+off, tmp);
+ rtc_to_tm(tim+off, tmp);
return 0;
}
@@ -54,8 +54,7 @@ int rtc_set (struct rtc_time *tmp)
at91_gpbr_t *gpbr = (at91_gpbr_t *) ATMEL_BASE_GPBR;
ulong tim;
- tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ tim = rtc_mktime(tmp);
/* clear alarm, set prescaler to 32768, clear counter */
writel(32768+AT91_RTT_RTTRST, &rtt->mr);
diff --git a/drivers/rtc/bfin_rtc.c b/drivers/rtc/bfin_rtc.c
index 4cf2d834b21..a079a1d4723 100644
--- a/drivers/rtc/bfin_rtc.c
+++ b/drivers/rtc/bfin_rtc.c
@@ -67,8 +67,7 @@ int rtc_set(struct rtc_time *tmp)
wait_for_complete();
/* Calculate number of seconds this incoming time represents */
- remain = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ remain = rtc_mktime(tmp);
/* Figure out how many days since epoch */
days = remain / NUM_SECS_IN_DAY;
@@ -114,7 +113,7 @@ int rtc_get(struct rtc_time *tmp)
/* Calculate the total number of seconds since epoch */
time_in_sec = (tm_sec) + MIN_TO_SECS(tm_min) + HRS_TO_SECS(tm_hr) + DAYS_TO_SECS(tm_day);
- to_tm(time_in_sec, tmp);
+ rtc_to_tm(time_in_sec, tmp);
return 0;
}
diff --git a/drivers/rtc/date.c b/drivers/rtc/date.c
index 15e6db06b2d..8c643a0b460 100644
--- a/drivers/rtc/date.c
+++ b/drivers/rtc/date.c
@@ -11,6 +11,7 @@
#include <common.h>
#include <command.h>
+#include <errno.h>
#include <rtc.h>
#if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
@@ -30,13 +31,15 @@ static int month_days[12] = {
/*
* This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
*/
-void GregorianDay(struct rtc_time * tm)
+int rtc_calc_weekday(struct rtc_time *tm)
{
int leapsToDate;
int lastYear;
int day;
int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
+ if (tm->tm_year < 1753)
+ return -EINVAL;
lastYear=tm->tm_year-1;
/*
@@ -64,9 +67,11 @@ void GregorianDay(struct rtc_time * tm)
day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday;
tm->tm_wday=day%7;
+
+ return 0;
}
-void to_tm(int tim, struct rtc_time * tm)
+int rtc_to_tm(int tim, struct rtc_time *tm)
{
register int i;
register long hms, day;
@@ -98,10 +103,14 @@ void to_tm(int tim, struct rtc_time * tm)
/* Days are what is left over (+1) from all that. */
tm->tm_mday = day + 1;
+ /* Zero unused fields */
+ tm->tm_yday = 0;
+ tm->tm_isdst = 0;
+
/*
* Determine the day of week
*/
- GregorianDay(tm);
+ return rtc_calc_weekday(tm);
}
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -119,22 +128,23 @@ void to_tm(int tim, struct rtc_time * tm)
* machines were long is 32-bit! (However, as time_t is signed, we
* will already get problems at other places on 2038-01-19 03:14:08)
*/
-unsigned long
-mktime (unsigned int year, unsigned int mon,
- unsigned int day, unsigned int hour,
- unsigned int min, unsigned int sec)
+unsigned long rtc_mktime(const struct rtc_time *tm)
{
- if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */
+ int mon = tm->tm_mon;
+ int year = tm->tm_year;
+ int days, hours;
+
+ mon -= 2;
+ if (0 >= (int)mon) { /* 1..12 -> 11,12,1..10 */
mon += 12; /* Puts Feb last since it has leap day */
year -= 1;
}
- return (((
- (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
- year*365 - 719499
- )*24 + hour /* now have hours */
- )*60 + min /* now have minutes */
- )*60 + sec; /* finally seconds */
+ days = (unsigned long)(year / 4 - year / 100 + year / 400 +
+ 367 * mon / 12 + tm->tm_mday) +
+ year * 365 - 719499;
+ hours = days * 24 + tm->tm_hour;
+ return (hours * 60 + tm->tm_min) * 60 + tm->tm_sec;
}
#endif
diff --git a/drivers/rtc/ds1306.c b/drivers/rtc/ds1306.c
index 1ec1837cb4e..7dd3e19028e 100644
--- a/drivers/rtc/ds1306.c
+++ b/drivers/rtc/ds1306.c
@@ -110,7 +110,7 @@ int rtc_get (struct rtc_time *tmp)
immap->im_cpm.cp_pbdat &= ~PB_SPI_CE; /* Disable DS1306 Chip */
udelay (10);
- GregorianDay (tmp); /* Determine the day of week */
+ rtc_calc_weekday(tmp); /* Determine the day of week */
debug ("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -180,8 +180,7 @@ int rtc_set (struct rtc_time *tmp)
{
ulong tim;
- tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ tim = rtc_mktime(tmp);
immap->im_sitk.sitk_rtck = KAPWR_KEY;
immap->im_sit.sit_rtc = tim;
diff --git a/drivers/rtc/ds1374.c b/drivers/rtc/ds1374.c
index 427b1eb8d0a..78473570b9d 100644
--- a/drivers/rtc/ds1374.c
+++ b/drivers/rtc/ds1374.c
@@ -118,7 +118,7 @@ int rtc_get (struct rtc_time *tm){
DEBUGR ("Get RTC s since 1.1.1970: %ld\n", time1);
- to_tm(time1, tm); /* To Gregorian Date */
+ rtc_to_tm(time1, tm); /* To Gregorian Date */
if (rtc_read(RTC_SR_ADDR) & RTC_SR_BIT_OSF) {
printf ("### Warning: RTC oscillator has stopped\n");
@@ -147,9 +147,7 @@ int rtc_set (struct rtc_time *tmp){
if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
printf("WARNING: year should be between 1970 and 2069!\n");
- time = mktime(tmp->tm_year, tmp->tm_mon,
- tmp->tm_mday, tmp->tm_hour,
- tmp->tm_min, tmp->tm_sec);
+ time = rtc_mktime(tmp);
DEBUGR ("Set RTC s since 1.1.1970: %ld (0x%02lx)\n", time, time);
diff --git a/drivers/rtc/ftrtc010.c b/drivers/rtc/ftrtc010.c
index 713dad274f1..7d0cfb3ba8c 100644
--- a/drivers/rtc/ftrtc010.c
+++ b/drivers/rtc/ftrtc010.c
@@ -86,7 +86,7 @@ int rtc_get(struct rtc_time *tmp)
now = ftrtc010_time() + readl(&rtc->record);
#endif
- to_tm(now, tmp);
+ rtc_to_tm(now, tmp);
return 0;
}
@@ -104,8 +104,7 @@ int rtc_set(struct rtc_time *tmp)
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
- new = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_hour,
- tmp->tm_min, tmp->tm_sec);
+ new = rtc_mktime(tmp);
now = ftrtc010_time();
diff --git a/drivers/rtc/i2c_rtc_emul.c b/drivers/rtc/i2c_rtc_emul.c
new file mode 100644
index 00000000000..20827fdff13
--- /dev/null
+++ b/drivers/rtc/i2c_rtc_emul.c
@@ -0,0 +1,236 @@
+/*
+ * Simulate an I2C real time clock
+ *
+ * Copyright (c) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/*
+ * This is a test driver. It starts off with the current time of the machine,
+ * but also supports setting the time, using an offset from the current
+ * clock. This driver is only intended for testing, not accurate
+ * time-keeping. It does not change the system time.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <os.h>
+#include <rtc.h>
+#include <asm/rtc.h>
+#include <asm/test.h>
+
+#ifdef DEBUG
+#define debug_buffer print_buffer
+#else
+#define debug_buffer(x, ...)
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct sandbox_i2c_rtc_plat_data - platform data for the RTC
+ *
+ * @base_time: Base system time when RTC device was bound
+ * @offset: RTC offset from current system time
+ * @use_system_time: true to use system time, false to use @base_time
+ * @reg: Register values
+ */
+struct sandbox_i2c_rtc_plat_data {
+ long base_time;
+ long offset;
+ bool use_system_time;
+ u8 reg[REG_COUNT];
+};
+
+struct sandbox_i2c_rtc {
+ unsigned int offset_secs;
+};
+
+long sandbox_i2c_rtc_set_offset(struct udevice *dev, bool use_system_time,
+ int offset)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+ long old_offset;
+
+ old_offset = plat->offset;
+ plat->use_system_time = use_system_time;
+ if (offset != -1)
+ plat->offset = offset;
+
+ return old_offset;
+}
+
+long sandbox_i2c_rtc_get_set_base_time(struct udevice *dev, long base_time)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+ long old_base_time;
+
+ old_base_time = plat->base_time;
+ if (base_time != -1)
+ plat->base_time = base_time;
+
+ return old_base_time;
+}
+
+static void reset_time(struct udevice *dev)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+ struct rtc_time now;
+
+ os_localtime(&now);
+ plat->base_time = rtc_mktime(&now);
+ plat->offset = 0;
+ plat->use_system_time = true;
+}
+
+static int sandbox_i2c_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+ struct rtc_time tm_now;
+ long now;
+
+ if (plat->use_system_time) {
+ os_localtime(&tm_now);
+ now = rtc_mktime(&tm_now);
+ } else {
+ now = plat->base_time;
+ }
+
+ return rtc_to_tm(now + plat->offset, time);
+}
+
+static int sandbox_i2c_rtc_set(struct udevice *dev, const struct rtc_time *time)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(dev);
+ struct rtc_time tm_now;
+ long now;
+
+ if (plat->use_system_time) {
+ os_localtime(&tm_now);
+ now = rtc_mktime(&tm_now);
+ } else {
+ now = plat->base_time;
+ }
+ plat->offset = rtc_mktime(time) - now;
+
+ return 0;
+}
+
+/* Update the current time in the registers */
+static int sandbox_i2c_rtc_prepare_read(struct udevice *emul)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
+ struct rtc_time time;
+ int ret;
+
+ ret = sandbox_i2c_rtc_get(emul, &time);
+ if (ret)
+ return ret;
+
+ plat->reg[REG_SEC] = time.tm_sec;
+ plat->reg[REG_MIN] = time.tm_min;
+ plat->reg[REG_HOUR] = time.tm_hour;
+ plat->reg[REG_MDAY] = time.tm_mday;
+ plat->reg[REG_MON] = time.tm_mon;
+ plat->reg[REG_YEAR] = time.tm_year - 1900;
+ plat->reg[REG_WDAY] = time.tm_wday;
+
+ return 0;
+}
+
+static int sandbox_i2c_rtc_complete_write(struct udevice *emul)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
+ struct rtc_time time;
+ int ret;
+
+ time.tm_sec = plat->reg[REG_SEC];
+ time.tm_min = plat->reg[REG_MIN];
+ time.tm_hour = plat->reg[REG_HOUR];
+ time.tm_mday = plat->reg[REG_MDAY];
+ time.tm_mon = plat->reg[REG_MON];
+ time.tm_year = plat->reg[REG_YEAR] + 1900;
+ time.tm_wday = plat->reg[REG_WDAY];
+
+ ret = sandbox_i2c_rtc_set(emul, &time);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int sandbox_i2c_rtc_xfer(struct udevice *emul, struct i2c_msg *msg,
+ int nmsgs)
+{
+ struct sandbox_i2c_rtc_plat_data *plat = dev_get_platdata(emul);
+ uint offset = 0;
+ int ret;
+
+ debug("\n%s\n", __func__);
+ ret = sandbox_i2c_rtc_prepare_read(emul);
+ if (ret)
+ return ret;
+ for (; nmsgs > 0; nmsgs--, msg++) {
+ int len;
+ u8 *ptr;
+
+ len = msg->len;
+ debug(" %s: msg->len=%d",
+ msg->flags & I2C_M_RD ? "read" : "write",
+ msg->len);
+ if (msg->flags & I2C_M_RD) {
+ debug(", offset %x, len %x: ", offset, len);
+
+ /* Read the register */
+ memcpy(msg->buf, plat->reg + offset, len);
+ memset(msg->buf + len, '\xff', msg->len - len);
+ debug_buffer(0, msg->buf, 1, msg->len, 0);
+ } else if (len >= 1) {
+ ptr = msg->buf;
+ offset = *ptr++ & (REG_COUNT - 1);
+ len--;
+ debug(", set offset %x: ", offset);
+ debug_buffer(0, msg->buf, 1, msg->len, 0);
+
+ /* Write the register */
+ memcpy(plat->reg + offset, ptr, len);
+ if (offset == REG_RESET)
+ reset_time(emul);
+ }
+ }
+ ret = sandbox_i2c_rtc_complete_write(emul);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct dm_i2c_ops sandbox_i2c_rtc_emul_ops = {
+ .xfer = sandbox_i2c_rtc_xfer,
+};
+
+static int sandbox_i2c_rtc_bind(struct udevice *dev)
+{
+ reset_time(dev);
+
+ return 0;
+}
+
+static const struct udevice_id sandbox_i2c_rtc_ids[] = {
+ { .compatible = "sandbox,i2c-rtc" },
+ { }
+};
+
+U_BOOT_DRIVER(sandbox_i2c_rtc_emul) = {
+ .name = "sandbox_i2c_rtc_emul",
+ .id = UCLASS_I2C_EMUL,
+ .of_match = sandbox_i2c_rtc_ids,
+ .bind = sandbox_i2c_rtc_bind,
+ .priv_auto_alloc_size = sizeof(struct sandbox_i2c_rtc),
+ .platdata_auto_alloc_size = sizeof(struct sandbox_i2c_rtc_plat_data),
+ .ops = &sandbox_i2c_rtc_emul_ops,
+};
diff --git a/drivers/rtc/imxdi.c b/drivers/rtc/imxdi.c
index 0d7d736eff5..17519ce2c05 100644
--- a/drivers/rtc/imxdi.c
+++ b/drivers/rtc/imxdi.c
@@ -192,7 +192,7 @@ int rtc_get(struct rtc_time *tmp)
}
now = __raw_readl(&data.regs->dtcmr);
- to_tm(now, tmp);
+ rtc_to_tm(now, tmp);
err:
return rc;
@@ -209,8 +209,7 @@ int rtc_set(struct rtc_time *tmp)
goto err;
}
- now = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ now = rtc_mktime(tmp);
/* zero the fractional part first */
rc = DI_WRITE_WAIT(0, dtclr);
if (rc == 0)
diff --git a/drivers/rtc/mc13xxx-rtc.c b/drivers/rtc/mc13xxx-rtc.c
index 528247ac86e..3e463368b09 100644
--- a/drivers/rtc/mc13xxx-rtc.c
+++ b/drivers/rtc/mc13xxx-rtc.c
@@ -36,7 +36,7 @@ int rtc_get(struct rtc_time *rtc)
tim = day1 * 86400 + time;
- to_tm(tim, rtc);
+ rtc_to_tm(tim, rtc);
rtc->tm_yday = 0;
rtc->tm_isdst = 0;
@@ -51,8 +51,7 @@ int rtc_set(struct rtc_time *rtc)
if (!p)
return -1;
- time = mktime(rtc->tm_year, rtc->tm_mon, rtc->tm_mday,
- rtc->tm_hour, rtc->tm_min, rtc->tm_sec);
+ time = rtc_mktime(rtc);
day = time / 86400;
time %= 86400;
diff --git a/drivers/rtc/mcfrtc.c b/drivers/rtc/mcfrtc.c
index 8961ca4f8b6..e02e29793e0 100644
--- a/drivers/rtc/mcfrtc.c
+++ b/drivers/rtc/mcfrtc.c
@@ -38,7 +38,7 @@ int rtc_get(struct rtc_time *tmp)
tim = (tim * 60) + rtc_mins;
tim = (tim * 60) + rtc->seconds;
- to_tm(tim, tmp);
+ rtc_to_tm(tim, tmp);
tmp->tm_yday = 0;
tmp->tm_isdst = 0;
diff --git a/drivers/rtc/mpc8xx.c b/drivers/rtc/mpc8xx.c
index d239daee1b0..147a225c6b0 100644
--- a/drivers/rtc/mpc8xx.c
+++ b/drivers/rtc/mpc8xx.c
@@ -26,7 +26,7 @@ int rtc_get (struct rtc_time *tmp)
tim = immr->im_sit.sit_rtc;
- to_tm (tim, tmp);
+ rtc_to_tm(tim, tmp);
debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
@@ -44,8 +44,7 @@ int rtc_set (struct rtc_time *tmp)
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
- tim = mktime (tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ tim = rtc_mktime(tmp);
immr->im_sitk.sitk_rtck = KAPWR_KEY;
immr->im_sit.sit_rtc = tim;
diff --git a/drivers/rtc/mx27rtc.c b/drivers/rtc/mx27rtc.c
index ae6595b8603..29ccdf17301 100644
--- a/drivers/rtc/mx27rtc.c
+++ b/drivers/rtc/mx27rtc.c
@@ -30,7 +30,7 @@ int rtc_get(struct rtc_time *time)
sec += min * 60 + hour * 3600 + day * 24 * 3600;
- to_tm(sec, time);
+ rtc_to_tm(sec, time);
return 0;
}
@@ -40,8 +40,7 @@ int rtc_set(struct rtc_time *time)
struct rtc_regs *rtc_regs = (struct rtc_regs *)IMX_RTC_BASE;
uint32_t day, hour, min, sec;
- sec = mktime(time->tm_year, time->tm_mon, time->tm_mday,
- time->tm_hour, time->tm_min, time->tm_sec);
+ sec = rtc_mktime(time);
day = sec / (24 * 3600);
sec = sec % (24 * 3600);
diff --git a/drivers/rtc/mxsrtc.c b/drivers/rtc/mxsrtc.c
index 32ba8a3062c..6e32154f47b 100644
--- a/drivers/rtc/mxsrtc.c
+++ b/drivers/rtc/mxsrtc.c
@@ -43,7 +43,7 @@ int rtc_get(struct rtc_time *time)
uint32_t secs;
secs = readl(&rtc_regs->hw_rtc_seconds);
- to_tm(secs, time);
+ rtc_to_tm(secs, time);
return 0;
}
@@ -52,8 +52,7 @@ int rtc_set(struct rtc_time *time)
{
uint32_t secs;
- secs = mktime(time->tm_year, time->tm_mon, time->tm_mday,
- time->tm_hour, time->tm_min, time->tm_sec);
+ secs = rtc_mktime(time);
return mxs_rtc_set_time(secs);
}
diff --git a/drivers/rtc/pl031.c b/drivers/rtc/pl031.c
index c4d1259a898..fc83049ecd2 100644
--- a/drivers/rtc/pl031.c
+++ b/drivers/rtc/pl031.c
@@ -72,8 +72,7 @@ int rtc_set(struct rtc_time *tmp)
}
/* Calculate number of seconds this incoming time represents */
- tim = mktime(tmp->tm_year, tmp->tm_mon, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ tim = rtc_mktime(tmp);
RTC_WRITE_REG(RTC_LR, tim);
@@ -97,7 +96,7 @@ int rtc_get(struct rtc_time *tmp)
tim = RTC_READ_REG(RTC_DR);
- to_tm (tim, tmp);
+ rtc_to_tm(tim, tmp);
debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
diff --git a/drivers/rtc/rtc-uclass.c b/drivers/rtc/rtc-uclass.c
new file mode 100644
index 00000000000..fe74c69f97e
--- /dev/null
+++ b/drivers/rtc/rtc-uclass.c
@@ -0,0 +1,96 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <rtc.h>
+
+int dm_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (!ops->get)
+ return -ENOSYS;
+ return ops->get(dev, time);
+}
+
+int dm_rtc_set(struct udevice *dev, struct rtc_time *time)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (!ops->set)
+ return -ENOSYS;
+ return ops->set(dev, time);
+}
+
+int dm_rtc_reset(struct udevice *dev)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (!ops->reset)
+ return -ENOSYS;
+ return ops->reset(dev);
+}
+
+int rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (!ops->read8)
+ return -ENOSYS;
+ return ops->read8(dev, reg);
+}
+
+int rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ struct rtc_ops *ops = rtc_get_ops(dev);
+
+ assert(ops);
+ if (!ops->write8)
+ return -ENOSYS;
+ return ops->write8(dev, reg, val);
+}
+
+int rtc_read32(struct udevice *dev, unsigned int reg, u32 *valuep)
+{
+ u32 value = 0;
+ int ret;
+ int i;
+
+ for (i = 0; i < sizeof(value); i++) {
+ ret = rtc_read8(dev, reg + i);
+ if (ret)
+ return ret;
+ value |= ret << (i << 3);
+ }
+
+ *valuep = value;
+ return 0;
+}
+
+int rtc_write32(struct udevice *dev, unsigned int reg, u32 value)
+{
+ int i, ret;
+
+ for (i = 0; i < sizeof(value); i++) {
+ ret = rtc_write8(dev, reg + i, (value >> (i << 3)) & 0xff);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+UCLASS_DRIVER(rtc) = {
+ .name = "rtc",
+ .id = UCLASS_RTC,
+};
diff --git a/drivers/rtc/sandbox_rtc.c b/drivers/rtc/sandbox_rtc.c
new file mode 100644
index 00000000000..f292fbe9b66
--- /dev/null
+++ b/drivers/rtc/sandbox_rtc.c
@@ -0,0 +1,106 @@
+/*
+ * (C) Copyright 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2c.h>
+#include <rtc.h>
+#include <asm/rtc.h>
+
+#define REG_COUNT 0x80
+
+static int sandbox_rtc_get(struct udevice *dev, struct rtc_time *time)
+{
+ time->tm_sec = dm_i2c_reg_read(dev, REG_SEC);
+ if (time->tm_sec < 0)
+ return time->tm_sec;
+ time->tm_min = dm_i2c_reg_read(dev, REG_MIN);
+ if (time->tm_min < 0)
+ return time->tm_min;
+ time->tm_hour = dm_i2c_reg_read(dev, REG_HOUR);
+ if (time->tm_hour < 0)
+ return time->tm_hour;
+ time->tm_mday = dm_i2c_reg_read(dev, REG_MDAY);
+ if (time->tm_mday < 0)
+ return time->tm_mday;
+ time->tm_mon = dm_i2c_reg_read(dev, REG_MON);
+ if (time->tm_mon < 0)
+ return time->tm_mon;
+ time->tm_year = dm_i2c_reg_read(dev, REG_YEAR);
+ if (time->tm_year < 0)
+ return time->tm_year;
+ time->tm_year += 1900;
+ time->tm_wday = dm_i2c_reg_read(dev, REG_WDAY);
+ if (time->tm_wday < 0)
+ return time->tm_wday;
+
+ return 0;
+}
+
+static int sandbox_rtc_set(struct udevice *dev, const struct rtc_time *time)
+{
+ int ret;
+
+ ret = dm_i2c_reg_write(dev, REG_SEC, time->tm_sec);
+ if (ret < 0)
+ return ret;
+ ret = dm_i2c_reg_write(dev, REG_MIN, time->tm_min);
+ if (ret < 0)
+ return ret;
+ ret = dm_i2c_reg_write(dev, REG_HOUR, time->tm_hour);
+ if (ret < 0)
+ return ret;
+ ret = dm_i2c_reg_write(dev, REG_MDAY, time->tm_mday);
+ if (ret < 0)
+ return ret;
+ ret = dm_i2c_reg_write(dev, REG_MON, time->tm_mon);
+ if (ret < 0)
+ return ret;
+ ret = dm_i2c_reg_write(dev, REG_YEAR, time->tm_year - 1900);
+ if (ret < 0)
+ return ret;
+ ret = dm_i2c_reg_write(dev, REG_WDAY, time->tm_wday);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int sandbox_rtc_reset(struct udevice *dev)
+{
+ return dm_i2c_reg_write(dev, REG_RESET, 0);
+}
+
+static int sandbox_rtc_read8(struct udevice *dev, unsigned int reg)
+{
+ return dm_i2c_reg_read(dev, reg);
+}
+
+static int sandbox_rtc_write8(struct udevice *dev, unsigned int reg, int val)
+{
+ return dm_i2c_reg_write(dev, reg, val);
+}
+
+static const struct rtc_ops sandbox_rtc_ops = {
+ .get = sandbox_rtc_get,
+ .set = sandbox_rtc_set,
+ .reset = sandbox_rtc_reset,
+ .read8 = sandbox_rtc_read8,
+ .write8 = sandbox_rtc_write8,
+};
+
+static const struct udevice_id sandbox_rtc_ids[] = {
+ { .compatible = "sandbox-rtc" },
+ { }
+};
+
+U_BOOT_DRIVER(rtc_sandbox) = {
+ .name = "rtc-sandbox",
+ .id = UCLASS_RTC,
+ .of_match = sandbox_rtc_ids,
+ .ops = &sandbox_rtc_ops,
+};