18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Machine dependent access functions for RTC registers. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#ifndef __ASM_MC146818_TIME_H 98c2ecf20Sopenharmony_ci#define __ASM_MC146818_TIME_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/bcd.h> 128c2ecf20Sopenharmony_ci#include <linux/mc146818rtc.h> 138c2ecf20Sopenharmony_ci#include <linux/time.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * For check timing call set_rtc_mmss() 500ms; used in timer interrupt. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci#define USEC_AFTER 500000 198c2ecf20Sopenharmony_ci#define USEC_BEFORE 500000 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* 228c2ecf20Sopenharmony_ci * In order to set the CMOS clock precisely, set_rtc_mmss has to be 238c2ecf20Sopenharmony_ci * called 500 ms after the second nowtime has started, because when 248c2ecf20Sopenharmony_ci * nowtime is written into the registers of the CMOS clock, it will 258c2ecf20Sopenharmony_ci * jump to the next second precisely 500 ms later. Check the Motorola 268c2ecf20Sopenharmony_ci * MC146818A or Dallas DS12887 data sheet for details. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * BUG: This routine does not handle hour overflow properly; it just 298c2ecf20Sopenharmony_ci * sets the minutes. Usually you'll only notice that after reboot! 308c2ecf20Sopenharmony_ci */ 318c2ecf20Sopenharmony_cistatic inline int mc146818_set_rtc_mmss(unsigned long nowtime) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci int real_seconds, real_minutes, cmos_minutes; 348c2ecf20Sopenharmony_ci unsigned char save_control, save_freq_select; 358c2ecf20Sopenharmony_ci int retval = 0; 368c2ecf20Sopenharmony_ci unsigned long flags; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci spin_lock_irqsave(&rtc_lock, flags); 398c2ecf20Sopenharmony_ci save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */ 408c2ecf20Sopenharmony_ci CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */ 438c2ecf20Sopenharmony_ci CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci cmos_minutes = CMOS_READ(RTC_MINUTES); 468c2ecf20Sopenharmony_ci if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) 478c2ecf20Sopenharmony_ci cmos_minutes = bcd2bin(cmos_minutes); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* 508c2ecf20Sopenharmony_ci * since we're only adjusting minutes and seconds, 518c2ecf20Sopenharmony_ci * don't interfere with hour overflow. This avoids 528c2ecf20Sopenharmony_ci * messing with unknown time zones but requires your 538c2ecf20Sopenharmony_ci * RTC not to be off by more than 15 minutes 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci real_seconds = nowtime % 60; 568c2ecf20Sopenharmony_ci real_minutes = nowtime / 60; 578c2ecf20Sopenharmony_ci if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1) 588c2ecf20Sopenharmony_ci real_minutes += 30; /* correct for half hour time zone */ 598c2ecf20Sopenharmony_ci real_minutes %= 60; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (abs(real_minutes - cmos_minutes) < 30) { 628c2ecf20Sopenharmony_ci if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 638c2ecf20Sopenharmony_ci real_seconds = bin2bcd(real_seconds); 648c2ecf20Sopenharmony_ci real_minutes = bin2bcd(real_minutes); 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci CMOS_WRITE(real_seconds, RTC_SECONDS); 678c2ecf20Sopenharmony_ci CMOS_WRITE(real_minutes, RTC_MINUTES); 688c2ecf20Sopenharmony_ci } else { 698c2ecf20Sopenharmony_ci printk_once(KERN_NOTICE 708c2ecf20Sopenharmony_ci "set_rtc_mmss: can't update from %d to %d\n", 718c2ecf20Sopenharmony_ci cmos_minutes, real_minutes); 728c2ecf20Sopenharmony_ci retval = -1; 738c2ecf20Sopenharmony_ci } 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* The following flags have to be released exactly in this order, 768c2ecf20Sopenharmony_ci * otherwise the DS12887 (popular MC146818A clone with integrated 778c2ecf20Sopenharmony_ci * battery and quartz) will not reset the oscillator and will not 788c2ecf20Sopenharmony_ci * update precisely 500 ms later. You won't find this mentioned in 798c2ecf20Sopenharmony_ci * the Dallas Semiconductor data sheets, but who believes data 808c2ecf20Sopenharmony_ci * sheets anyway ... -- Markus Kuhn 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_ci CMOS_WRITE(save_control, RTC_CONTROL); 838c2ecf20Sopenharmony_ci CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); 848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rtc_lock, flags); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci return retval; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic inline time64_t mc146818_get_cmos_time(void) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci unsigned int year, mon, day, hour, min, sec; 928c2ecf20Sopenharmony_ci unsigned long flags; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci spin_lock_irqsave(&rtc_lock, flags); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci do { 978c2ecf20Sopenharmony_ci sec = CMOS_READ(RTC_SECONDS); 988c2ecf20Sopenharmony_ci min = CMOS_READ(RTC_MINUTES); 998c2ecf20Sopenharmony_ci hour = CMOS_READ(RTC_HOURS); 1008c2ecf20Sopenharmony_ci day = CMOS_READ(RTC_DAY_OF_MONTH); 1018c2ecf20Sopenharmony_ci mon = CMOS_READ(RTC_MONTH); 1028c2ecf20Sopenharmony_ci year = CMOS_READ(RTC_YEAR); 1038c2ecf20Sopenharmony_ci } while (sec != CMOS_READ(RTC_SECONDS)); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 1068c2ecf20Sopenharmony_ci sec = bcd2bin(sec); 1078c2ecf20Sopenharmony_ci min = bcd2bin(min); 1088c2ecf20Sopenharmony_ci hour = bcd2bin(hour); 1098c2ecf20Sopenharmony_ci day = bcd2bin(day); 1108c2ecf20Sopenharmony_ci mon = bcd2bin(mon); 1118c2ecf20Sopenharmony_ci year = bcd2bin(year); 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&rtc_lock, flags); 1148c2ecf20Sopenharmony_ci year = mc146818_decode_year(year); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return mktime64(year, mon, day, hour, min, sec); 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci#endif /* __ASM_MC146818_TIME_H */ 120