diff --git a/MAINTAINERS b/MAINTAINERS index 69a5bc3768..d9f80325f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -678,6 +678,7 @@ S: Maintained T: git https://gitlab.denx.de/u-boot/custodians/u-boot-efi.git F: doc/api/efi.rst F: doc/uefi/* +F: drivers/rtc/emul_rtc.c F: include/capitalization.h F: include/charset.h F: include/cp1250.h diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 63662001c2..d06d272e14 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -63,6 +63,17 @@ config RTC_DS3232 Support for Dallas Semiconductor (now Maxim) DS3232 compatible Real Time Clock devices. +config RTC_EMULATION + bool "Enable emulated RTC" + depends on DM_RTC + help + On a board without hardware clock this software real time clock can be + used. The build time is used to initialize the RTC. So you will have + to adjust the time either manually using the 'date' command or use + the 'sntp' to update the RTC with the time from a network time server. + See CONFIG_CMD_SNTP and CONFIG_BOOTP_NTPSERVER. The RTC time is + advanced according to CPU ticks. + config RTC_ISL1208 bool "Enable ISL1208 driver" depends on DM_RTC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 12eb449583..ef66dc4bf0 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_RTC_DS164x) += ds164x.o obj-$(CONFIG_RTC_DS174x) += ds174x.o obj-$(CONFIG_RTC_DS3231) += ds3231.o obj-$(CONFIG_RTC_DS3232) += ds3232.o +obj-$(CONFIG_RTC_EMULATION) += emul_rtc.o obj-$(CONFIG_RTC_FTRTC010) += ftrtc010.o obj-$(CONFIG_SANDBOX) += i2c_rtc_emul.o obj-$(CONFIG_RTC_IMXDI) += imxdi.o diff --git a/drivers/rtc/emul_rtc.c b/drivers/rtc/emul_rtc.c new file mode 100644 index 0000000000..c98c24bbb3 --- /dev/null +++ b/drivers/rtc/emul_rtc.c @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020, Heinrich Schuchardt + * + * This driver emulates a real time clock based on timer ticks. + */ + +#include +#include +#include +#include +#include + +/** + * struct emul_rtc - private data for emulated RTC driver + */ +struct emul_rtc { + /** + * @offset_us: microseconds from 1970-01-01 to timer_get_us() base + */ + u64 offset_us; + /** + * @isdst: daylight saving time + */ + int isdst; +}; + +static int emul_rtc_get(struct udevice *dev, struct rtc_time *time) +{ + struct emul_rtc *priv = dev_get_priv(dev); + u64 now; + + if (!priv->offset_us) { + /* Use the build date as initial time */ + priv->offset_us = U_BOOT_EPOCH * 1000000ULL - timer_get_us(); + priv->isdst = -1; + } + + now = timer_get_us() + priv->offset_us; + do_div(now, 1000000); + rtc_to_tm(now, time); + time->tm_isdst = priv->isdst; + + return 0; +} + +static int emul_rtc_set(struct udevice *dev, const struct rtc_time *time) +{ + struct emul_rtc *priv = dev_get_priv(dev); + + if (time->tm_year < 1970) + return -EINVAL; + + priv->offset_us = rtc_mktime(time) * 1000000ULL - timer_get_us(); + + if (time->tm_isdst > 0) + priv->isdst = 1; + else if (time->tm_isdst < 0) + priv->isdst = -1; + else + priv->isdst = 0; + + return 0; +} + +static const struct rtc_ops emul_rtc_ops = { + .get = emul_rtc_get, + .set = emul_rtc_set, +}; + +U_BOOT_DRIVER(rtc_emul) = { + .name = "rtc_emul", + .id = UCLASS_RTC, + .ops = &emul_rtc_ops, + .priv_auto_alloc_size = sizeof(struct emul_rtc), +}; + +U_BOOT_DEVICE(rtc_emul) = { + .name = "rtc_emul", +};