1da2014a2SPaul Mundt /* 2da2014a2SPaul Mundt * arch/sh/boards/dreamcast/rtc.c 3da2014a2SPaul Mundt * 4da2014a2SPaul Mundt * Dreamcast AICA RTC routines. 5da2014a2SPaul Mundt * 6da2014a2SPaul Mundt * Copyright (c) 2001, 2002 M. R. Brown <mrbrown@0xd6.org> 7da2014a2SPaul Mundt * Copyright (c) 2002 Paul Mundt <lethal@chaoticdreams.org> 8da2014a2SPaul Mundt * 9da2014a2SPaul Mundt * Released under the terms of the GNU GPL v2.0. 10da2014a2SPaul Mundt * 11da2014a2SPaul Mundt */ 12da2014a2SPaul Mundt 13da2014a2SPaul Mundt #include <linux/time.h> 14*b0495e4bSArnd Bergmann #include <linux/rtc.h> 15*b0495e4bSArnd Bergmann #include <linux/io.h> 16*b0495e4bSArnd Bergmann #include <linux/platform_device.h> 17da2014a2SPaul Mundt 18da2014a2SPaul Mundt /* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in 19da2014a2SPaul Mundt seconds) to get the standard Unix Epoch when getting the time, and add 20da2014a2SPaul Mundt 20 years when setting the time. */ 21da2014a2SPaul Mundt #define TWENTY_YEARS ((20 * 365LU + 5) * 86400) 22da2014a2SPaul Mundt 23da2014a2SPaul Mundt /* The AICA RTC is represented by a 32-bit seconds counter stored in 2 16-bit 24da2014a2SPaul Mundt registers.*/ 25da2014a2SPaul Mundt #define AICA_RTC_SECS_H 0xa0710000 26da2014a2SPaul Mundt #define AICA_RTC_SECS_L 0xa0710004 27da2014a2SPaul Mundt 28da2014a2SPaul Mundt /** 29da2014a2SPaul Mundt * aica_rtc_gettimeofday - Get the time from the AICA RTC 30*b0495e4bSArnd Bergmann * @dev: the RTC device (ignored) 31*b0495e4bSArnd Bergmann * @tm: pointer to resulting RTC time structure 32da2014a2SPaul Mundt * 33da2014a2SPaul Mundt * Grabs the current RTC seconds counter and adjusts it to the Unix Epoch. 34da2014a2SPaul Mundt */ 35*b0495e4bSArnd Bergmann static int aica_rtc_gettimeofday(struct device *dev, struct rtc_time *tm) 36da2014a2SPaul Mundt { 37da2014a2SPaul Mundt unsigned long val1, val2; 38*b0495e4bSArnd Bergmann time64_t t; 39da2014a2SPaul Mundt 40da2014a2SPaul Mundt do { 419d56dd3bSPaul Mundt val1 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | 429d56dd3bSPaul Mundt (__raw_readl(AICA_RTC_SECS_L) & 0xffff); 43da2014a2SPaul Mundt 449d56dd3bSPaul Mundt val2 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | 459d56dd3bSPaul Mundt (__raw_readl(AICA_RTC_SECS_L) & 0xffff); 46da2014a2SPaul Mundt } while (val1 != val2); 47da2014a2SPaul Mundt 48*b0495e4bSArnd Bergmann /* normalize to 1970..2106 time range */ 49*b0495e4bSArnd Bergmann t = (u32)(val1 - TWENTY_YEARS); 50da2014a2SPaul Mundt 51*b0495e4bSArnd Bergmann rtc_time64_to_tm(t, tm); 52*b0495e4bSArnd Bergmann 53*b0495e4bSArnd Bergmann return 0; 54da2014a2SPaul Mundt } 55da2014a2SPaul Mundt 56da2014a2SPaul Mundt /** 57da2014a2SPaul Mundt * aica_rtc_settimeofday - Set the AICA RTC to the current time 58*b0495e4bSArnd Bergmann * @dev: the RTC device (ignored) 59*b0495e4bSArnd Bergmann * @tm: pointer to new RTC time structure 60da2014a2SPaul Mundt * 61da2014a2SPaul Mundt * Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter. 62da2014a2SPaul Mundt */ 63*b0495e4bSArnd Bergmann static int aica_rtc_settimeofday(struct device *dev, struct rtc_time *tm) 64da2014a2SPaul Mundt { 65da2014a2SPaul Mundt unsigned long val1, val2; 66*b0495e4bSArnd Bergmann time64_t secs = rtc_tm_to_time64(tm); 67*b0495e4bSArnd Bergmann u32 adj = secs + TWENTY_YEARS; 68da2014a2SPaul Mundt 69da2014a2SPaul Mundt do { 709d56dd3bSPaul Mundt __raw_writel((adj & 0xffff0000) >> 16, AICA_RTC_SECS_H); 719d56dd3bSPaul Mundt __raw_writel((adj & 0xffff), AICA_RTC_SECS_L); 72da2014a2SPaul Mundt 739d56dd3bSPaul Mundt val1 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | 749d56dd3bSPaul Mundt (__raw_readl(AICA_RTC_SECS_L) & 0xffff); 75da2014a2SPaul Mundt 769d56dd3bSPaul Mundt val2 = ((__raw_readl(AICA_RTC_SECS_H) & 0xffff) << 16) | 779d56dd3bSPaul Mundt (__raw_readl(AICA_RTC_SECS_L) & 0xffff); 78da2014a2SPaul Mundt } while (val1 != val2); 79da2014a2SPaul Mundt 80da2014a2SPaul Mundt return 0; 81da2014a2SPaul Mundt } 82da2014a2SPaul Mundt 83*b0495e4bSArnd Bergmann static const struct rtc_class_ops rtc_generic_ops = { 84*b0495e4bSArnd Bergmann .read_time = aica_rtc_gettimeofday, 85*b0495e4bSArnd Bergmann .set_time = aica_rtc_settimeofday, 86*b0495e4bSArnd Bergmann }; 87da2014a2SPaul Mundt 88*b0495e4bSArnd Bergmann static int __init aica_time_init(void) 89*b0495e4bSArnd Bergmann { 90*b0495e4bSArnd Bergmann struct platform_device *pdev; 91*b0495e4bSArnd Bergmann 92*b0495e4bSArnd Bergmann pdev = platform_device_register_data(NULL, "rtc-generic", -1, 93*b0495e4bSArnd Bergmann &rtc_generic_ops, 94*b0495e4bSArnd Bergmann sizeof(rtc_generic_ops)); 95*b0495e4bSArnd Bergmann 96*b0495e4bSArnd Bergmann return PTR_ERR_OR_ZERO(pdev); 97*b0495e4bSArnd Bergmann } 98*b0495e4bSArnd Bergmann arch_initcall(aica_time_init); 99