Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0 2 : : #include <linux/rtc.h> 3 : : #include <linux/time.h> 4 : : 5 : : /** 6 : : * rtc_set_ntp_time - Save NTP synchronized time to the RTC 7 : : * @now: Current time of day 8 : : * @target_nsec: pointer for desired now->tv_nsec value 9 : : * 10 : : * Replacement for the NTP platform function update_persistent_clock64 11 : : * that stores time for later retrieval by rtc_hctosys. 12 : : * 13 : : * Returns 0 on successful RTC update, -ENODEV if a RTC update is not 14 : : * possible at all, and various other -errno for specific temporary failure 15 : : * cases. 16 : : * 17 : : * -EPROTO is returned if now.tv_nsec is not close enough to *target_nsec. 18 : : * 19 : : * If temporary failure is indicated the caller should try again 'soon' 20 : : */ 21 : 0 : int rtc_set_ntp_time(struct timespec64 now, unsigned long *target_nsec) 22 : : { 23 : 0 : struct rtc_device *rtc; 24 : 0 : struct rtc_time tm; 25 : 0 : struct timespec64 to_set; 26 : 0 : int err = -ENODEV; 27 : 0 : bool ok; 28 : : 29 : 0 : rtc = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE); 30 [ # # ]: 0 : if (!rtc) 31 : 0 : goto out_err; 32 : : 33 [ # # # # ]: 0 : if (!rtc->ops || !rtc->ops->set_time) 34 : 0 : goto out_close; 35 : : 36 : : /* Compute the value of tv_nsec we require the caller to supply in 37 : : * now.tv_nsec. This is the value such that (now + 38 : : * set_offset_nsec).tv_nsec == 0. 39 : : */ 40 : 0 : set_normalized_timespec64(&to_set, 0, -rtc->set_offset_nsec); 41 : 0 : *target_nsec = to_set.tv_nsec; 42 : : 43 : : /* The ntp code must call this with the correct value in tv_nsec, if 44 : : * it does not we update target_nsec and return EPROTO to make the ntp 45 : : * code try again later. 46 : : */ 47 : 0 : ok = rtc_tv_nsec_ok(rtc->set_offset_nsec, &to_set, &now); 48 [ # # ]: 0 : if (!ok) { 49 : 0 : err = -EPROTO; 50 : 0 : goto out_close; 51 : : } 52 : : 53 : 0 : rtc_time64_to_tm(to_set.tv_sec, &tm); 54 : : 55 : 0 : err = rtc_set_time(rtc, &tm); 56 : : 57 : 0 : out_close: 58 : 0 : rtc_class_close(rtc); 59 : 0 : out_err: 60 : 0 : return err; 61 : : }