rtc-ls1x.c (5160B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2011 Zhao Zhang <zhzhl555@gmail.com> 4 * 5 * Derived from driver/rtc/rtc-au1xxx.c 6 */ 7 8#include <linux/module.h> 9#include <linux/kernel.h> 10#include <linux/rtc.h> 11#include <linux/init.h> 12#include <linux/platform_device.h> 13#include <linux/delay.h> 14#include <linux/types.h> 15#include <linux/io.h> 16#include <loongson1.h> 17 18#define LS1X_RTC_REG_OFFSET (LS1X_RTC_BASE + 0x20) 19#define LS1X_RTC_REGS(x) \ 20 ((void __iomem *)KSEG1ADDR(LS1X_RTC_REG_OFFSET + (x))) 21 22/*RTC programmable counters 0 and 1*/ 23#define SYS_COUNTER_CNTRL (LS1X_RTC_REGS(0x20)) 24#define SYS_CNTRL_ERS (1 << 23) 25#define SYS_CNTRL_RTS (1 << 20) 26#define SYS_CNTRL_RM2 (1 << 19) 27#define SYS_CNTRL_RM1 (1 << 18) 28#define SYS_CNTRL_RM0 (1 << 17) 29#define SYS_CNTRL_RS (1 << 16) 30#define SYS_CNTRL_BP (1 << 14) 31#define SYS_CNTRL_REN (1 << 13) 32#define SYS_CNTRL_BRT (1 << 12) 33#define SYS_CNTRL_TEN (1 << 11) 34#define SYS_CNTRL_BTT (1 << 10) 35#define SYS_CNTRL_E0 (1 << 8) 36#define SYS_CNTRL_ETS (1 << 7) 37#define SYS_CNTRL_32S (1 << 5) 38#define SYS_CNTRL_TTS (1 << 4) 39#define SYS_CNTRL_TM2 (1 << 3) 40#define SYS_CNTRL_TM1 (1 << 2) 41#define SYS_CNTRL_TM0 (1 << 1) 42#define SYS_CNTRL_TS (1 << 0) 43 44/* Programmable Counter 0 Registers */ 45#define SYS_TOYTRIM (LS1X_RTC_REGS(0)) 46#define SYS_TOYWRITE0 (LS1X_RTC_REGS(4)) 47#define SYS_TOYWRITE1 (LS1X_RTC_REGS(8)) 48#define SYS_TOYREAD0 (LS1X_RTC_REGS(0xC)) 49#define SYS_TOYREAD1 (LS1X_RTC_REGS(0x10)) 50#define SYS_TOYMATCH0 (LS1X_RTC_REGS(0x14)) 51#define SYS_TOYMATCH1 (LS1X_RTC_REGS(0x18)) 52#define SYS_TOYMATCH2 (LS1X_RTC_REGS(0x1C)) 53 54/* Programmable Counter 1 Registers */ 55#define SYS_RTCTRIM (LS1X_RTC_REGS(0x40)) 56#define SYS_RTCWRITE0 (LS1X_RTC_REGS(0x44)) 57#define SYS_RTCREAD0 (LS1X_RTC_REGS(0x48)) 58#define SYS_RTCMATCH0 (LS1X_RTC_REGS(0x4C)) 59#define SYS_RTCMATCH1 (LS1X_RTC_REGS(0x50)) 60#define SYS_RTCMATCH2 (LS1X_RTC_REGS(0x54)) 61 62#define LS1X_SEC_OFFSET (4) 63#define LS1X_MIN_OFFSET (10) 64#define LS1X_HOUR_OFFSET (16) 65#define LS1X_DAY_OFFSET (21) 66#define LS1X_MONTH_OFFSET (26) 67 68 69#define LS1X_SEC_MASK (0x3f) 70#define LS1X_MIN_MASK (0x3f) 71#define LS1X_HOUR_MASK (0x1f) 72#define LS1X_DAY_MASK (0x1f) 73#define LS1X_MONTH_MASK (0x3f) 74#define LS1X_YEAR_MASK (0xffffffff) 75 76#define ls1x_get_sec(t) (((t) >> LS1X_SEC_OFFSET) & LS1X_SEC_MASK) 77#define ls1x_get_min(t) (((t) >> LS1X_MIN_OFFSET) & LS1X_MIN_MASK) 78#define ls1x_get_hour(t) (((t) >> LS1X_HOUR_OFFSET) & LS1X_HOUR_MASK) 79#define ls1x_get_day(t) (((t) >> LS1X_DAY_OFFSET) & LS1X_DAY_MASK) 80#define ls1x_get_month(t) (((t) >> LS1X_MONTH_OFFSET) & LS1X_MONTH_MASK) 81 82#define RTC_CNTR_OK (SYS_CNTRL_E0 | SYS_CNTRL_32S) 83 84static int ls1x_rtc_read_time(struct device *dev, struct rtc_time *rtm) 85{ 86 unsigned long v; 87 time64_t t; 88 89 v = readl(SYS_TOYREAD0); 90 t = readl(SYS_TOYREAD1); 91 92 memset(rtm, 0, sizeof(struct rtc_time)); 93 t = mktime64((t & LS1X_YEAR_MASK), ls1x_get_month(v), 94 ls1x_get_day(v), ls1x_get_hour(v), 95 ls1x_get_min(v), ls1x_get_sec(v)); 96 rtc_time64_to_tm(t, rtm); 97 98 return 0; 99} 100 101static int ls1x_rtc_set_time(struct device *dev, struct rtc_time *rtm) 102{ 103 unsigned long v, t, c; 104 int ret = -ETIMEDOUT; 105 106 v = ((rtm->tm_mon + 1) << LS1X_MONTH_OFFSET) 107 | (rtm->tm_mday << LS1X_DAY_OFFSET) 108 | (rtm->tm_hour << LS1X_HOUR_OFFSET) 109 | (rtm->tm_min << LS1X_MIN_OFFSET) 110 | (rtm->tm_sec << LS1X_SEC_OFFSET); 111 112 writel(v, SYS_TOYWRITE0); 113 c = 0x10000; 114 /* add timeout check counter, for more safe */ 115 while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c) 116 usleep_range(1000, 3000); 117 118 if (!c) { 119 dev_err(dev, "set time timeout!\n"); 120 goto err; 121 } 122 123 t = rtm->tm_year + 1900; 124 writel(t, SYS_TOYWRITE1); 125 c = 0x10000; 126 while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TS) && --c) 127 usleep_range(1000, 3000); 128 129 if (!c) { 130 dev_err(dev, "set time timeout!\n"); 131 goto err; 132 } 133 return 0; 134err: 135 return ret; 136} 137 138static const struct rtc_class_ops ls1x_rtc_ops = { 139 .read_time = ls1x_rtc_read_time, 140 .set_time = ls1x_rtc_set_time, 141}; 142 143static int ls1x_rtc_probe(struct platform_device *pdev) 144{ 145 struct rtc_device *rtcdev; 146 unsigned long v; 147 148 v = readl(SYS_COUNTER_CNTRL); 149 if (!(v & RTC_CNTR_OK)) { 150 dev_err(&pdev->dev, "rtc counters not working\n"); 151 return -ENODEV; 152 } 153 154 /* set to 1 HZ if needed */ 155 if (readl(SYS_TOYTRIM) != 32767) { 156 v = 0x100000; 157 while ((readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) && --v) 158 usleep_range(1000, 3000); 159 160 if (!v) { 161 dev_err(&pdev->dev, "time out\n"); 162 return -ETIMEDOUT; 163 } 164 writel(32767, SYS_TOYTRIM); 165 } 166 /* this loop coundn't be endless */ 167 while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS) 168 usleep_range(1000, 3000); 169 170 rtcdev = devm_rtc_allocate_device(&pdev->dev); 171 if (IS_ERR(rtcdev)) 172 return PTR_ERR(rtcdev); 173 174 platform_set_drvdata(pdev, rtcdev); 175 rtcdev->ops = &ls1x_rtc_ops; 176 rtcdev->range_min = RTC_TIMESTAMP_BEGIN_1900; 177 rtcdev->range_max = RTC_TIMESTAMP_END_2099; 178 179 return devm_rtc_register_device(rtcdev); 180} 181 182static struct platform_driver ls1x_rtc_driver = { 183 .driver = { 184 .name = "ls1x-rtc", 185 }, 186 .probe = ls1x_rtc_probe, 187}; 188 189module_platform_driver(ls1x_rtc_driver); 190 191MODULE_AUTHOR("zhao zhang <zhzhl555@gmail.com>"); 192MODULE_LICENSE("GPL");