diff options
Diffstat (limited to 'include/linux/rtc.h')
-rw-r--r-- | include/linux/rtc.h | 43 |
1 files changed, 42 insertions, 1 deletions
diff --git a/include/linux/rtc.h b/include/linux/rtc.h index e6d0f9c1cafd..5b13fa029fd6 100644 --- a/include/linux/rtc.h +++ b/include/linux/rtc.h | |||
@@ -135,6 +135,14 @@ struct rtc_device { | |||
135 | /* Some hardware can't support UIE mode */ | 135 | /* Some hardware can't support UIE mode */ |
136 | int uie_unsupported; | 136 | int uie_unsupported; |
137 | 137 | ||
138 | /* Number of nsec it takes to set the RTC clock. This influences when | ||
139 | * the set ops are called. An offset: | ||
140 | * - of 0.5 s will call RTC set for wall clock time 10.0 s at 9.5 s | ||
141 | * - of 1.5 s will call RTC set for wall clock time 10.0 s at 8.5 s | ||
142 | * - of -0.5 s will call RTC set for wall clock time 10.0 s at 10.5 s | ||
143 | */ | ||
144 | long set_offset_nsec; | ||
145 | |||
138 | bool registered; | 146 | bool registered; |
139 | 147 | ||
140 | struct nvmem_config *nvmem_config; | 148 | struct nvmem_config *nvmem_config; |
@@ -172,7 +180,7 @@ extern void devm_rtc_device_unregister(struct device *dev, | |||
172 | 180 | ||
173 | extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); | 181 | extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); |
174 | extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); | 182 | extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); |
175 | extern int rtc_set_ntp_time(struct timespec64 now); | 183 | extern int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec); |
176 | int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm); | 184 | int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm); |
177 | extern int rtc_read_alarm(struct rtc_device *rtc, | 185 | extern int rtc_read_alarm(struct rtc_device *rtc, |
178 | struct rtc_wkalrm *alrm); | 186 | struct rtc_wkalrm *alrm); |
@@ -221,6 +229,39 @@ static inline bool is_leap_year(unsigned int year) | |||
221 | return (!(year % 4) && (year % 100)) || !(year % 400); | 229 | return (!(year % 4) && (year % 100)) || !(year % 400); |
222 | } | 230 | } |
223 | 231 | ||
232 | /* Determine if we can call to driver to set the time. Drivers can only be | ||
233 | * called to set a second aligned time value, and the field set_offset_nsec | ||
234 | * specifies how far away from the second aligned time to call the driver. | ||
235 | * | ||
236 | * This also computes 'to_set' which is the time we are trying to set, and has | ||
237 | * a zero in tv_nsecs, such that: | ||
238 | * to_set - set_delay_nsec == now +/- FUZZ | ||
239 | * | ||
240 | */ | ||
241 | static inline bool rtc_tv_nsec_ok(s64 set_offset_nsec, | ||
242 | struct timespec64 *to_set, | ||
243 | const struct timespec64 *now) | ||
244 | { | ||
245 | /* Allowed error in tv_nsec, arbitarily set to 5 jiffies in ns. */ | ||
246 | const unsigned long TIME_SET_NSEC_FUZZ = TICK_NSEC * 5; | ||
247 | struct timespec64 delay = {.tv_sec = 0, | ||
248 | .tv_nsec = set_offset_nsec}; | ||
249 | |||
250 | *to_set = timespec64_add(*now, delay); | ||
251 | |||
252 | if (to_set->tv_nsec < TIME_SET_NSEC_FUZZ) { | ||
253 | to_set->tv_nsec = 0; | ||
254 | return true; | ||
255 | } | ||
256 | |||
257 | if (to_set->tv_nsec > NSEC_PER_SEC - TIME_SET_NSEC_FUZZ) { | ||
258 | to_set->tv_sec++; | ||
259 | to_set->tv_nsec = 0; | ||
260 | return true; | ||
261 | } | ||
262 | return false; | ||
263 | } | ||
264 | |||
224 | #define rtc_register_device(device) \ | 265 | #define rtc_register_device(device) \ |
225 | __rtc_register_device(THIS_MODULE, device) | 266 | __rtc_register_device(THIS_MODULE, device) |
226 | 267 | ||