1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (c) 2008-2009 Nuvoton technology corporation.
5 * Wan ZongShun <mcuos.com@gmail.com>
8 #include <linux/module.h>
9 #include <linux/init.h>
10 #include <linux/platform_device.h>
11 #include <linux/slab.h>
12 #include <linux/rtc.h>
13 #include <linux/delay.h>
15 #include <linux/bcd.h>
17 /* RTC Control Registers */
18 #define REG_RTC_INIR 0x00
19 #define REG_RTC_AER 0x04
20 #define REG_RTC_FCR 0x08
21 #define REG_RTC_TLR 0x0C
22 #define REG_RTC_CLR 0x10
23 #define REG_RTC_TSSR 0x14
24 #define REG_RTC_DWR 0x18
25 #define REG_RTC_TAR 0x1C
26 #define REG_RTC_CAR 0x20
27 #define REG_RTC_LIR 0x24
28 #define REG_RTC_RIER 0x28
29 #define REG_RTC_RIIR 0x2C
30 #define REG_RTC_TTR 0x30
33 #define AERRWENB 0x10000
34 #define INIRRESET 0xa5eb1357
35 #define AERPOWERON 0xA965
36 #define AERPOWEROFF 0x0000
37 #define LEAPYEAR 0x0001
39 #define TICKINTENB 0x0002
40 #define ALARMINTENB 0x0001
45 void __iomem
*rtc_reg
;
46 struct rtc_device
*rtcdev
;
49 struct nuc900_bcd_time
{
58 static irqreturn_t
nuc900_rtc_interrupt(int irq
, void *_rtc
)
60 struct nuc900_rtc
*rtc
= _rtc
;
61 unsigned long events
= 0, rtc_irq
;
63 rtc_irq
= __raw_readl(rtc
->rtc_reg
+ REG_RTC_RIIR
);
65 if (rtc_irq
& ALARMINTENB
) {
66 rtc_irq
&= ~ALARMINTENB
;
67 __raw_writel(rtc_irq
, rtc
->rtc_reg
+ REG_RTC_RIIR
);
68 events
|= RTC_AF
| RTC_IRQF
;
71 if (rtc_irq
& TICKINTENB
) {
72 rtc_irq
&= ~TICKINTENB
;
73 __raw_writel(rtc_irq
, rtc
->rtc_reg
+ REG_RTC_RIIR
);
74 events
|= RTC_UF
| RTC_IRQF
;
77 rtc_update_irq(rtc
->rtcdev
, 1, events
);
82 static int *check_rtc_access_enable(struct nuc900_rtc
*nuc900_rtc
)
84 unsigned int timeout
= 0x1000;
85 __raw_writel(INIRRESET
, nuc900_rtc
->rtc_reg
+ REG_RTC_INIR
);
89 __raw_writel(AERPOWERON
, nuc900_rtc
->rtc_reg
+ REG_RTC_AER
);
91 while (!(__raw_readl(nuc900_rtc
->rtc_reg
+ REG_RTC_AER
) & AERRWENB
)
96 return ERR_PTR(-EPERM
);
101 static void nuc900_rtc_bcd2bin(unsigned int timereg
,
102 unsigned int calreg
, struct rtc_time
*tm
)
104 tm
->tm_mday
= bcd2bin(calreg
>> 0);
105 tm
->tm_mon
= bcd2bin(calreg
>> 8);
106 tm
->tm_year
= bcd2bin(calreg
>> 16) + 100;
108 tm
->tm_sec
= bcd2bin(timereg
>> 0);
109 tm
->tm_min
= bcd2bin(timereg
>> 8);
110 tm
->tm_hour
= bcd2bin(timereg
>> 16);
113 static void nuc900_rtc_bin2bcd(struct device
*dev
, struct rtc_time
*settm
,
114 struct nuc900_bcd_time
*gettm
)
116 gettm
->bcd_mday
= bin2bcd(settm
->tm_mday
) << 0;
117 gettm
->bcd_mon
= bin2bcd(settm
->tm_mon
) << 8;
119 if (settm
->tm_year
< 100) {
120 dev_warn(dev
, "The year will be between 1970-1999, right?\n");
121 gettm
->bcd_year
= bin2bcd(settm
->tm_year
) << 16;
123 gettm
->bcd_year
= bin2bcd(settm
->tm_year
- 100) << 16;
126 gettm
->bcd_sec
= bin2bcd(settm
->tm_sec
) << 0;
127 gettm
->bcd_min
= bin2bcd(settm
->tm_min
) << 8;
128 gettm
->bcd_hour
= bin2bcd(settm
->tm_hour
) << 16;
131 static int nuc900_alarm_irq_enable(struct device
*dev
, unsigned int enabled
)
133 struct nuc900_rtc
*rtc
= dev_get_drvdata(dev
);
136 __raw_writel(__raw_readl(rtc
->rtc_reg
+ REG_RTC_RIER
)|
137 (ALARMINTENB
), rtc
->rtc_reg
+ REG_RTC_RIER
);
139 __raw_writel(__raw_readl(rtc
->rtc_reg
+ REG_RTC_RIER
)&
140 (~ALARMINTENB
), rtc
->rtc_reg
+ REG_RTC_RIER
);
145 static int nuc900_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
147 struct nuc900_rtc
*rtc
= dev_get_drvdata(dev
);
148 unsigned int timeval
, clrval
;
150 timeval
= __raw_readl(rtc
->rtc_reg
+ REG_RTC_TLR
);
151 clrval
= __raw_readl(rtc
->rtc_reg
+ REG_RTC_CLR
);
153 nuc900_rtc_bcd2bin(timeval
, clrval
, tm
);
158 static int nuc900_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
160 struct nuc900_rtc
*rtc
= dev_get_drvdata(dev
);
161 struct nuc900_bcd_time gettm
;
165 nuc900_rtc_bin2bcd(dev
, tm
, &gettm
);
167 err
= check_rtc_access_enable(rtc
);
171 val
= gettm
.bcd_mday
| gettm
.bcd_mon
| gettm
.bcd_year
;
172 __raw_writel(val
, rtc
->rtc_reg
+ REG_RTC_CLR
);
174 val
= gettm
.bcd_sec
| gettm
.bcd_min
| gettm
.bcd_hour
;
175 __raw_writel(val
, rtc
->rtc_reg
+ REG_RTC_TLR
);
180 static int nuc900_rtc_read_alarm(struct device
*dev
, struct rtc_wkalrm
*alrm
)
182 struct nuc900_rtc
*rtc
= dev_get_drvdata(dev
);
183 unsigned int timeval
, carval
;
185 timeval
= __raw_readl(rtc
->rtc_reg
+ REG_RTC_TAR
);
186 carval
= __raw_readl(rtc
->rtc_reg
+ REG_RTC_CAR
);
188 nuc900_rtc_bcd2bin(timeval
, carval
, &alrm
->time
);
190 return rtc_valid_tm(&alrm
->time
);
193 static int nuc900_rtc_set_alarm(struct device
*dev
, struct rtc_wkalrm
*alrm
)
195 struct nuc900_rtc
*rtc
= dev_get_drvdata(dev
);
196 struct nuc900_bcd_time tm
;
200 nuc900_rtc_bin2bcd(dev
, &alrm
->time
, &tm
);
202 err
= check_rtc_access_enable(rtc
);
206 val
= tm
.bcd_mday
| tm
.bcd_mon
| tm
.bcd_year
;
207 __raw_writel(val
, rtc
->rtc_reg
+ REG_RTC_CAR
);
209 val
= tm
.bcd_sec
| tm
.bcd_min
| tm
.bcd_hour
;
210 __raw_writel(val
, rtc
->rtc_reg
+ REG_RTC_TAR
);
215 static const struct rtc_class_ops nuc900_rtc_ops
= {
216 .read_time
= nuc900_rtc_read_time
,
217 .set_time
= nuc900_rtc_set_time
,
218 .read_alarm
= nuc900_rtc_read_alarm
,
219 .set_alarm
= nuc900_rtc_set_alarm
,
220 .alarm_irq_enable
= nuc900_alarm_irq_enable
,
223 static int __init
nuc900_rtc_probe(struct platform_device
*pdev
)
225 struct resource
*res
;
226 struct nuc900_rtc
*nuc900_rtc
;
228 nuc900_rtc
= devm_kzalloc(&pdev
->dev
, sizeof(struct nuc900_rtc
),
233 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
234 nuc900_rtc
->rtc_reg
= devm_ioremap_resource(&pdev
->dev
, res
);
235 if (IS_ERR(nuc900_rtc
->rtc_reg
))
236 return PTR_ERR(nuc900_rtc
->rtc_reg
);
238 platform_set_drvdata(pdev
, nuc900_rtc
);
240 nuc900_rtc
->rtcdev
= devm_rtc_device_register(&pdev
->dev
, pdev
->name
,
241 &nuc900_rtc_ops
, THIS_MODULE
);
242 if (IS_ERR(nuc900_rtc
->rtcdev
)) {
243 dev_err(&pdev
->dev
, "rtc device register failed\n");
244 return PTR_ERR(nuc900_rtc
->rtcdev
);
247 __raw_writel(__raw_readl(nuc900_rtc
->rtc_reg
+ REG_RTC_TSSR
) | MODE24
,
248 nuc900_rtc
->rtc_reg
+ REG_RTC_TSSR
);
250 nuc900_rtc
->irq_num
= platform_get_irq(pdev
, 0);
251 if (devm_request_irq(&pdev
->dev
, nuc900_rtc
->irq_num
,
252 nuc900_rtc_interrupt
, 0, "nuc900rtc", nuc900_rtc
)) {
253 dev_err(&pdev
->dev
, "NUC900 RTC request irq failed\n");
260 static struct platform_driver nuc900_rtc_driver
= {
262 .name
= "nuc900-rtc",
266 module_platform_driver_probe(nuc900_rtc_driver
, nuc900_rtc_probe
);
268 MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
269 MODULE_DESCRIPTION("nuc910/nuc920 RTC driver");
270 MODULE_LICENSE("GPL");
271 MODULE_ALIAS("platform:nuc900-rtc");