For use by the EFI loader RTC set time boot service, import rtc_calc_weekday() from U-Boot.
Signed-off-by: Ahmad Fatoum <[email protected]> --- drivers/rtc/rtc-lib.c | 48 +++++++++++++++++++++++++++++++++++++++++++ include/rtc.h | 11 ++++++++++ 2 files changed, 59 insertions(+) diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index 3709d46cbe16..4f2993ac12bd 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -73,6 +73,54 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) } EXPORT_SYMBOL(rtc_time_to_tm); +// SPDX-SnippetBegin +// SPDX-Snippet-Comment: Origin-URL: https://github.com/u-boot/u-boot/blob/467382ca03758e4f3f13107e3a83669e93a7461e/lib/date.c + +static int month_offset[] = { + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 +}; + +/* + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) + */ +int rtc_calc_weekday(struct rtc_time *tm) +{ + int leaps_to_date; + int last_year; + int day; + + if (tm->tm_year < 1753) + return -1; + last_year = tm->tm_year - 1; + + /* Number of leap corrections to apply up to end of last year */ + leaps_to_date = last_year / 4 - last_year / 100 + last_year / 400; + + /* + * This year is a leap year if it is divisible by 4 except when it is + * divisible by 100 unless it is divisible by 400 + * + * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 is. + */ + if (tm->tm_year % 4 == 0 && + ((tm->tm_year % 100 != 0) || (tm->tm_year % 400 == 0)) && + tm->tm_mon > 2) { + /* We are past Feb. 29 in a leap year */ + day = 1; + } else { + day = 0; + } + + day += last_year * 365 + leaps_to_date + month_offset[tm->tm_mon - 1] + + tm->tm_mday; + tm->tm_wday = day % 7; + + return 0; +} +EXPORT_SYMBOL(rtc_calc_weekday); + +// SPDX-SnippetEnd + /* * Does the rtc_time represent a valid date/time? */ diff --git a/include/rtc.h b/include/rtc.h index 0766f0408216..c3e277320557 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -54,4 +54,15 @@ static inline struct rtc_device *rtc_lookup(const char *name) const char *time_str(struct rtc_time *tm); +/** + * rtc_calc_weekday() - Work out the weekday from a time + * + * This only works for the Gregorian calendar - i.e. after 1752 (in the UK). + * It sets time->tm_wdaay to the correct day of the week. + * + * @time: Time to inspect. tm_wday is updated + * Return: 0 if OK, -EINVAL if the weekday could not be determined + */ +int rtc_calc_weekday(struct rtc_time *time); + #endif /* _RTC_H_ */ -- 2.47.3
