forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge tag 'rtc-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git…
…/abelloni/linux Pull RTC updates from Alexandre Belloni: "The broken down time conversion is similar to what is done in the time subsystem since v5.14. The rest is fairly straightforward. Subsystem: - Switch to Neri and Schneider time conversion algorithm Drivers: - rx8025: add rx8035 support - s5m: modernize driver and set range" * tag 'rtc-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: rtc: rx8010: select REGMAP_I2C dt-bindings: rtc: add Epson RX-8025 and RX-8035 rtc: rx8025: implement RX-8035 support rtc: cmos: remove stale REVISIT comments rtc: tps65910: Correct driver module alias rtc: move RTC_LIB_KUNIT_TEST to proper location rtc: lib_test: add MODULE_LICENSE rtc: Improve performance of rtc_time64_to_tm(). Add tests. rtc: s5m: set range rtc: s5m: enable wakeup only when available rtc: s5m: signal the core when alarm are not available rtc: s5m: switch to devm_rtc_allocate_device
- Loading branch information
Showing
9 changed files
with
243 additions
and
64 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,8 @@ | |
* Author: Alessandro Zummo <[email protected]> | ||
* | ||
* based on arch/arm/common/rtctime.c and other bits | ||
* | ||
* Author: Cassio Neri <[email protected]> (rtc_time64_to_tm) | ||
*/ | ||
|
||
#include <linux/export.h> | ||
|
@@ -22,8 +24,6 @@ static const unsigned short rtc_ydays[2][13] = { | |
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | ||
}; | ||
|
||
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400) | ||
|
||
/* | ||
* The number of days in the month. | ||
*/ | ||
|
@@ -42,42 +42,95 @@ int rtc_year_days(unsigned int day, unsigned int month, unsigned int year) | |
} | ||
EXPORT_SYMBOL(rtc_year_days); | ||
|
||
/* | ||
* rtc_time64_to_tm - Converts time64_t to rtc_time. | ||
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date. | ||
/** | ||
* rtc_time64_to_tm - converts time64_t to rtc_time. | ||
* | ||
* @time: The number of seconds since 01-01-1970 00:00:00. | ||
* (Must be positive.) | ||
* @tm: Pointer to the struct rtc_time. | ||
*/ | ||
void rtc_time64_to_tm(time64_t time, struct rtc_time *tm) | ||
{ | ||
unsigned int month, year, secs; | ||
unsigned int secs; | ||
int days; | ||
|
||
u64 u64tmp; | ||
u32 u32tmp, udays, century, day_of_century, year_of_century, year, | ||
day_of_year, month, day; | ||
bool is_Jan_or_Feb, is_leap_year; | ||
|
||
/* time must be positive */ | ||
days = div_s64_rem(time, 86400, &secs); | ||
|
||
/* day of the week, 1970-01-01 was a Thursday */ | ||
tm->tm_wday = (days + 4) % 7; | ||
|
||
year = 1970 + days / 365; | ||
days -= (year - 1970) * 365 | ||
+ LEAPS_THRU_END_OF(year - 1) | ||
- LEAPS_THRU_END_OF(1970 - 1); | ||
while (days < 0) { | ||
year -= 1; | ||
days += 365 + is_leap_year(year); | ||
} | ||
tm->tm_year = year - 1900; | ||
tm->tm_yday = days + 1; | ||
|
||
for (month = 0; month < 11; month++) { | ||
int newdays; | ||
|
||
newdays = days - rtc_month_days(month, year); | ||
if (newdays < 0) | ||
break; | ||
days = newdays; | ||
} | ||
tm->tm_mon = month; | ||
tm->tm_mday = days + 1; | ||
/* | ||
* The following algorithm is, basically, Proposition 6.3 of Neri | ||
* and Schneider [1]. In a few words: it works on the computational | ||
* (fictitious) calendar where the year starts in March, month = 2 | ||
* (*), and finishes in February, month = 13. This calendar is | ||
* mathematically convenient because the day of the year does not | ||
* depend on whether the year is leap or not. For instance: | ||
* | ||
* March 1st 0-th day of the year; | ||
* ... | ||
* April 1st 31-st day of the year; | ||
* ... | ||
* January 1st 306-th day of the year; (Important!) | ||
* ... | ||
* February 28th 364-th day of the year; | ||
* February 29th 365-th day of the year (if it exists). | ||
* | ||
* After having worked out the date in the computational calendar | ||
* (using just arithmetics) it's easy to convert it to the | ||
* corresponding date in the Gregorian calendar. | ||
* | ||
* [1] "Euclidean Affine Functions and Applications to Calendar | ||
* Algorithms". https://arxiv.org/abs/2102.06959 | ||
* | ||
* (*) The numbering of months follows rtc_time more closely and | ||
* thus, is slightly different from [1]. | ||
*/ | ||
|
||
udays = ((u32) days) + 719468; | ||
|
||
u32tmp = 4 * udays + 3; | ||
century = u32tmp / 146097; | ||
day_of_century = u32tmp % 146097 / 4; | ||
|
||
u32tmp = 4 * day_of_century + 3; | ||
u64tmp = 2939745ULL * u32tmp; | ||
year_of_century = upper_32_bits(u64tmp); | ||
day_of_year = lower_32_bits(u64tmp) / 2939745 / 4; | ||
|
||
year = 100 * century + year_of_century; | ||
is_leap_year = year_of_century != 0 ? | ||
year_of_century % 4 == 0 : century % 4 == 0; | ||
|
||
u32tmp = 2141 * day_of_year + 132377; | ||
month = u32tmp >> 16; | ||
day = ((u16) u32tmp) / 2141; | ||
|
||
/* | ||
* Recall that January 01 is the 306-th day of the year in the | ||
* computational (not Gregorian) calendar. | ||
*/ | ||
is_Jan_or_Feb = day_of_year >= 306; | ||
|
||
/* Converts to the Gregorian calendar. */ | ||
year = year + is_Jan_or_Feb; | ||
month = is_Jan_or_Feb ? month - 12 : month; | ||
day = day + 1; | ||
|
||
day_of_year = is_Jan_or_Feb ? | ||
day_of_year - 306 : day_of_year + 31 + 28 + is_leap_year; | ||
|
||
/* Converts to rtc_time's format. */ | ||
tm->tm_year = (int) (year - 1900); | ||
tm->tm_mon = (int) month; | ||
tm->tm_mday = (int) day; | ||
tm->tm_yday = (int) day_of_year + 1; | ||
|
||
tm->tm_hour = secs / 3600; | ||
secs -= tm->tm_hour * 3600; | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
// SPDX-License-Identifier: LGPL-2.1+ | ||
|
||
#include <kunit/test.h> | ||
#include <linux/rtc.h> | ||
|
||
/* | ||
* Advance a date by one day. | ||
*/ | ||
static void advance_date(int *year, int *month, int *mday, int *yday) | ||
{ | ||
if (*mday != rtc_month_days(*month - 1, *year)) { | ||
++*mday; | ||
++*yday; | ||
return; | ||
} | ||
|
||
*mday = 1; | ||
if (*month != 12) { | ||
++*month; | ||
++*yday; | ||
return; | ||
} | ||
|
||
*month = 1; | ||
*yday = 1; | ||
++*year; | ||
} | ||
|
||
/* | ||
* Checks every day in a 160000 years interval starting on 1970-01-01 | ||
* against the expected result. | ||
*/ | ||
static void rtc_time64_to_tm_test_date_range(struct kunit *test) | ||
{ | ||
/* | ||
* 160000 years = (160000 / 400) * 400 years | ||
* = (160000 / 400) * 146097 days | ||
* = (160000 / 400) * 146097 * 86400 seconds | ||
*/ | ||
time64_t total_secs = ((time64_t) 160000) / 400 * 146097 * 86400; | ||
|
||
int year = 1970; | ||
int month = 1; | ||
int mday = 1; | ||
int yday = 1; | ||
|
||
struct rtc_time result; | ||
time64_t secs; | ||
s64 days; | ||
|
||
for (secs = 0; secs <= total_secs; secs += 86400) { | ||
|
||
rtc_time64_to_tm(secs, &result); | ||
|
||
days = div_s64(secs, 86400); | ||
|
||
#define FAIL_MSG "%d/%02d/%02d (%2d) : %ld", \ | ||
year, month, mday, yday, days | ||
|
||
KUNIT_ASSERT_EQ_MSG(test, year - 1900, result.tm_year, FAIL_MSG); | ||
KUNIT_ASSERT_EQ_MSG(test, month - 1, result.tm_mon, FAIL_MSG); | ||
KUNIT_ASSERT_EQ_MSG(test, mday, result.tm_mday, FAIL_MSG); | ||
KUNIT_ASSERT_EQ_MSG(test, yday, result.tm_yday, FAIL_MSG); | ||
|
||
advance_date(&year, &month, &mday, &yday); | ||
} | ||
} | ||
|
||
static struct kunit_case rtc_lib_test_cases[] = { | ||
KUNIT_CASE(rtc_time64_to_tm_test_date_range), | ||
{} | ||
}; | ||
|
||
static struct kunit_suite rtc_lib_test_suite = { | ||
.name = "rtc_lib_test_cases", | ||
.test_cases = rtc_lib_test_cases, | ||
}; | ||
|
||
kunit_test_suite(rtc_lib_test_suite); | ||
|
||
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.