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