1 /* 2 * arch/sh/boards/dreamcast/rtc.c 3 * 4 * Dreamcast AICA RTC routines. 5 * 6 * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org> 7 * Copyright (c) 2002 Paul Mundt <lethal@chaoticdreams.org> 8 * 9 * Released under the terms of the GNU GPL v2.0. 10 * 11 */ 12 13 #include <linux/time.h> 14 #include <asm/rtc.h> 15 #include <asm/io.h> 16 17 /* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in 18 seconds) to get the standard Unix Epoch when getting the time, and add 19 20 years when setting the time. */ 20 #define TWENTY_YEARS ((20 * 365LU + 5) * 86400) 21 22 /* The AICA RTC is represented by a 32-bit seconds counter stored in 2 16-bit 23 registers.*/ 24 #define AICA_RTC_SECS_H 0xa0710000 25 #define AICA_RTC_SECS_L 0xa0710004 26 27 /** 28 * aica_rtc_gettimeofday - Get the time from the AICA RTC 29 * @ts: pointer to resulting timespec 30 * 31 * Grabs the current RTC seconds counter and adjusts it to the Unix Epoch. 32 */ 33 static void aica_rtc_gettimeofday(struct timespec *ts) 34 { 35 unsigned long val1, val2; 36 37 do { 38 val1 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | 39 (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); 40 41 val2 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | 42 (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); 43 } while (val1 != val2); 44 45 ts->tv_sec = val1 - TWENTY_YEARS; 46 47 /* Can't get nanoseconds with just a seconds counter. */ 48 ts->tv_nsec = 0; 49 } 50 51 /** 52 * aica_rtc_settimeofday - Set the AICA RTC to the current time 53 * @secs: contains the time_t to set 54 * 55 * Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter. 56 */ 57 static int aica_rtc_settimeofday(const time_t secs) 58 { 59 unsigned long val1, val2; 60 unsigned long adj = secs + TWENTY_YEARS; 61 62 do { 63 ctrl_outl((adj & 0xffff0000) >> 16, AICA_RTC_SECS_H); 64 ctrl_outl((adj & 0xffff), AICA_RTC_SECS_L); 65 66 val1 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | 67 (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); 68 69 val2 = ((ctrl_inl(AICA_RTC_SECS_H) & 0xffff) << 16) | 70 (ctrl_inl(AICA_RTC_SECS_L) & 0xffff); 71 } while (val1 != val2); 72 73 return 0; 74 } 75 76 void aica_time_init(void) 77 { 78 rtc_sh_get_time = aica_rtc_gettimeofday; 79 rtc_sh_set_time = aica_rtc_settimeofday; 80 } 81 82