1 // SPDX-License-Identifier: GPL-2.0+
5 * Joshua Henderson <joshua.henderson@microchip.com>
6 * Copyright (C) 2016 Microchip Technology Inc. All rights reserved.
9 #include <linux/init.h>
10 #include <linux/module.h>
12 #include <linux/platform_device.h>
14 #include <linux/slab.h>
15 #include <linux/clk.h>
16 #include <linux/rtc.h>
17 #include <linux/bcd.h>
19 #include <asm/mach-pic32/pic32.h>
21 #define PIC32_RTCCON 0x00
22 #define PIC32_RTCCON_ON BIT(15)
23 #define PIC32_RTCCON_SIDL BIT(13)
24 #define PIC32_RTCCON_RTCCLKSEL (3 << 9)
25 #define PIC32_RTCCON_RTCCLKON BIT(6)
26 #define PIC32_RTCCON_RTCWREN BIT(3)
27 #define PIC32_RTCCON_RTCSYNC BIT(2)
28 #define PIC32_RTCCON_HALFSEC BIT(1)
29 #define PIC32_RTCCON_RTCOE BIT(0)
31 #define PIC32_RTCALRM 0x10
32 #define PIC32_RTCALRM_ALRMEN BIT(15)
33 #define PIC32_RTCALRM_CHIME BIT(14)
34 #define PIC32_RTCALRM_PIV BIT(13)
35 #define PIC32_RTCALRM_ALARMSYNC BIT(12)
36 #define PIC32_RTCALRM_AMASK 0x0F00
37 #define PIC32_RTCALRM_ARPT 0xFF
39 #define PIC32_RTCHOUR 0x23
40 #define PIC32_RTCMIN 0x22
41 #define PIC32_RTCSEC 0x21
42 #define PIC32_RTCYEAR 0x33
43 #define PIC32_RTCMON 0x32
44 #define PIC32_RTCDAY 0x31
46 #define PIC32_ALRMTIME 0x40
47 #define PIC32_ALRMDATE 0x50
49 #define PIC32_ALRMHOUR 0x43
50 #define PIC32_ALRMMIN 0x42
51 #define PIC32_ALRMSEC 0x41
52 #define PIC32_ALRMYEAR 0x53
53 #define PIC32_ALRMMON 0x52
54 #define PIC32_ALRMDAY 0x51
56 struct pic32_rtc_dev
{
57 struct rtc_device
*rtc
;
58 void __iomem
*reg_base
;
60 spinlock_t alarm_lock
;
62 bool alarm_clk_enabled
;
65 static void pic32_rtc_alarm_clk_enable(struct pic32_rtc_dev
*pdata
,
70 spin_lock_irqsave(&pdata
->alarm_lock
, flags
);
72 if (!pdata
->alarm_clk_enabled
) {
73 clk_enable(pdata
->clk
);
74 pdata
->alarm_clk_enabled
= true;
77 if (pdata
->alarm_clk_enabled
) {
78 clk_disable(pdata
->clk
);
79 pdata
->alarm_clk_enabled
= false;
82 spin_unlock_irqrestore(&pdata
->alarm_lock
, flags
);
85 static irqreturn_t
pic32_rtc_alarmirq(int irq
, void *id
)
87 struct pic32_rtc_dev
*pdata
= (struct pic32_rtc_dev
*)id
;
89 clk_enable(pdata
->clk
);
90 rtc_update_irq(pdata
->rtc
, 1, RTC_AF
| RTC_IRQF
);
91 clk_disable(pdata
->clk
);
93 pic32_rtc_alarm_clk_enable(pdata
, false);
98 static int pic32_rtc_setaie(struct device
*dev
, unsigned int enabled
)
100 struct pic32_rtc_dev
*pdata
= dev_get_drvdata(dev
);
101 void __iomem
*base
= pdata
->reg_base
;
103 clk_enable(pdata
->clk
);
105 writel(PIC32_RTCALRM_ALRMEN
,
106 base
+ (enabled
? PIC32_SET(PIC32_RTCALRM
) :
107 PIC32_CLR(PIC32_RTCALRM
)));
109 clk_disable(pdata
->clk
);
111 pic32_rtc_alarm_clk_enable(pdata
, enabled
);
116 static int pic32_rtc_setfreq(struct device
*dev
, int freq
)
118 struct pic32_rtc_dev
*pdata
= dev_get_drvdata(dev
);
119 void __iomem
*base
= pdata
->reg_base
;
121 clk_enable(pdata
->clk
);
123 writel(PIC32_RTCALRM_AMASK
, base
+ PIC32_CLR(PIC32_RTCALRM
));
124 writel(freq
<< 8, base
+ PIC32_SET(PIC32_RTCALRM
));
125 writel(PIC32_RTCALRM_CHIME
, base
+ PIC32_SET(PIC32_RTCALRM
));
127 clk_disable(pdata
->clk
);
132 static int pic32_rtc_gettime(struct device
*dev
, struct rtc_time
*rtc_tm
)
134 struct pic32_rtc_dev
*pdata
= dev_get_drvdata(dev
);
135 void __iomem
*base
= pdata
->reg_base
;
136 unsigned int tries
= 0;
138 clk_enable(pdata
->clk
);
141 rtc_tm
->tm_hour
= readb(base
+ PIC32_RTCHOUR
);
142 rtc_tm
->tm_min
= readb(base
+ PIC32_RTCMIN
);
143 rtc_tm
->tm_mon
= readb(base
+ PIC32_RTCMON
);
144 rtc_tm
->tm_mday
= readb(base
+ PIC32_RTCDAY
);
145 rtc_tm
->tm_year
= readb(base
+ PIC32_RTCYEAR
);
146 rtc_tm
->tm_sec
= readb(base
+ PIC32_RTCSEC
);
149 * The only way to work out whether the system was mid-update
150 * when we read it is to check the second counter, and if it
151 * is zero, then we re-try the entire read.
154 } while (rtc_tm
->tm_sec
== 0 && tries
< 2);
156 rtc_tm
->tm_sec
= bcd2bin(rtc_tm
->tm_sec
);
157 rtc_tm
->tm_min
= bcd2bin(rtc_tm
->tm_min
);
158 rtc_tm
->tm_hour
= bcd2bin(rtc_tm
->tm_hour
);
159 rtc_tm
->tm_mday
= bcd2bin(rtc_tm
->tm_mday
);
160 rtc_tm
->tm_mon
= bcd2bin(rtc_tm
->tm_mon
) - 1;
161 rtc_tm
->tm_year
= bcd2bin(rtc_tm
->tm_year
);
163 rtc_tm
->tm_year
+= 100;
165 dev_dbg(dev
, "read time %ptR\n", rtc_tm
);
167 clk_disable(pdata
->clk
);
171 static int pic32_rtc_settime(struct device
*dev
, struct rtc_time
*tm
)
173 struct pic32_rtc_dev
*pdata
= dev_get_drvdata(dev
);
174 void __iomem
*base
= pdata
->reg_base
;
176 dev_dbg(dev
, "set time %ptR\n", tm
);
178 clk_enable(pdata
->clk
);
179 writeb(bin2bcd(tm
->tm_sec
), base
+ PIC32_RTCSEC
);
180 writeb(bin2bcd(tm
->tm_min
), base
+ PIC32_RTCMIN
);
181 writeb(bin2bcd(tm
->tm_hour
), base
+ PIC32_RTCHOUR
);
182 writeb(bin2bcd(tm
->tm_mday
), base
+ PIC32_RTCDAY
);
183 writeb(bin2bcd(tm
->tm_mon
+ 1), base
+ PIC32_RTCMON
);
184 writeb(bin2bcd(tm
->tm_year
- 100), base
+ PIC32_RTCYEAR
);
185 clk_disable(pdata
->clk
);
190 static int pic32_rtc_getalarm(struct device
*dev
, struct rtc_wkalrm
*alrm
)
192 struct pic32_rtc_dev
*pdata
= dev_get_drvdata(dev
);
193 struct rtc_time
*alm_tm
= &alrm
->time
;
194 void __iomem
*base
= pdata
->reg_base
;
197 clk_enable(pdata
->clk
);
198 alm_tm
->tm_sec
= readb(base
+ PIC32_ALRMSEC
);
199 alm_tm
->tm_min
= readb(base
+ PIC32_ALRMMIN
);
200 alm_tm
->tm_hour
= readb(base
+ PIC32_ALRMHOUR
);
201 alm_tm
->tm_mon
= readb(base
+ PIC32_ALRMMON
);
202 alm_tm
->tm_mday
= readb(base
+ PIC32_ALRMDAY
);
203 alm_tm
->tm_year
= readb(base
+ PIC32_ALRMYEAR
);
205 alm_en
= readb(base
+ PIC32_RTCALRM
);
207 alrm
->enabled
= (alm_en
& PIC32_RTCALRM_ALRMEN
) ? 1 : 0;
209 dev_dbg(dev
, "getalarm: %d, %ptR\n", alm_en
, alm_tm
);
211 alm_tm
->tm_sec
= bcd2bin(alm_tm
->tm_sec
);
212 alm_tm
->tm_min
= bcd2bin(alm_tm
->tm_min
);
213 alm_tm
->tm_hour
= bcd2bin(alm_tm
->tm_hour
);
214 alm_tm
->tm_mday
= bcd2bin(alm_tm
->tm_mday
);
215 alm_tm
->tm_mon
= bcd2bin(alm_tm
->tm_mon
) - 1;
216 alm_tm
->tm_year
= bcd2bin(alm_tm
->tm_year
);
218 clk_disable(pdata
->clk
);
222 static int pic32_rtc_setalarm(struct device
*dev
, struct rtc_wkalrm
*alrm
)
224 struct pic32_rtc_dev
*pdata
= dev_get_drvdata(dev
);
225 struct rtc_time
*tm
= &alrm
->time
;
226 void __iomem
*base
= pdata
->reg_base
;
228 clk_enable(pdata
->clk
);
229 dev_dbg(dev
, "setalarm: %d, %ptR\n", alrm
->enabled
, tm
);
231 writel(0x00, base
+ PIC32_ALRMTIME
);
232 writel(0x00, base
+ PIC32_ALRMDATE
);
234 pic32_rtc_setaie(dev
, alrm
->enabled
);
236 clk_disable(pdata
->clk
);
240 static int pic32_rtc_proc(struct device
*dev
, struct seq_file
*seq
)
242 struct pic32_rtc_dev
*pdata
= dev_get_drvdata(dev
);
243 void __iomem
*base
= pdata
->reg_base
;
246 clk_enable(pdata
->clk
);
248 repeat
= readw(base
+ PIC32_RTCALRM
);
249 repeat
&= PIC32_RTCALRM_ARPT
;
250 seq_printf(seq
, "periodic_IRQ\t: %s\n", repeat
? "yes" : "no");
252 clk_disable(pdata
->clk
);
256 static const struct rtc_class_ops pic32_rtcops
= {
257 .read_time
= pic32_rtc_gettime
,
258 .set_time
= pic32_rtc_settime
,
259 .read_alarm
= pic32_rtc_getalarm
,
260 .set_alarm
= pic32_rtc_setalarm
,
261 .proc
= pic32_rtc_proc
,
262 .alarm_irq_enable
= pic32_rtc_setaie
,
265 static void pic32_rtc_enable(struct pic32_rtc_dev
*pdata
, int en
)
267 void __iomem
*base
= pdata
->reg_base
;
272 clk_enable(pdata
->clk
);
274 writel(PIC32_RTCCON_ON
, base
+ PIC32_CLR(PIC32_RTCCON
));
276 pic32_syskey_unlock();
278 writel(PIC32_RTCCON_RTCWREN
, base
+ PIC32_SET(PIC32_RTCCON
));
279 writel(3 << 9, base
+ PIC32_CLR(PIC32_RTCCON
));
281 if (!(readl(base
+ PIC32_RTCCON
) & PIC32_RTCCON_ON
))
282 writel(PIC32_RTCCON_ON
, base
+ PIC32_SET(PIC32_RTCCON
));
284 clk_disable(pdata
->clk
);
287 static int pic32_rtc_remove(struct platform_device
*pdev
)
289 struct pic32_rtc_dev
*pdata
= platform_get_drvdata(pdev
);
291 pic32_rtc_setaie(&pdev
->dev
, 0);
292 clk_unprepare(pdata
->clk
);
298 static int pic32_rtc_probe(struct platform_device
*pdev
)
300 struct pic32_rtc_dev
*pdata
;
301 struct resource
*res
;
304 pdata
= devm_kzalloc(&pdev
->dev
, sizeof(*pdata
), GFP_KERNEL
);
308 platform_set_drvdata(pdev
, pdata
);
310 pdata
->alarm_irq
= platform_get_irq(pdev
, 0);
311 if (pdata
->alarm_irq
< 0) {
312 dev_err(&pdev
->dev
, "no irq for alarm\n");
313 return pdata
->alarm_irq
;
316 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
317 pdata
->reg_base
= devm_ioremap_resource(&pdev
->dev
, res
);
318 if (IS_ERR(pdata
->reg_base
))
319 return PTR_ERR(pdata
->reg_base
);
321 pdata
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
322 if (IS_ERR(pdata
->clk
)) {
323 dev_err(&pdev
->dev
, "failed to find rtc clock source\n");
324 ret
= PTR_ERR(pdata
->clk
);
329 spin_lock_init(&pdata
->alarm_lock
);
331 clk_prepare_enable(pdata
->clk
);
333 pic32_rtc_enable(pdata
, 1);
335 device_init_wakeup(&pdev
->dev
, 1);
337 pdata
->rtc
= devm_rtc_allocate_device(&pdev
->dev
);
338 if (IS_ERR(pdata
->rtc
))
339 return PTR_ERR(pdata
->rtc
);
341 pdata
->rtc
->ops
= &pic32_rtcops
;
342 pdata
->rtc
->range_min
= RTC_TIMESTAMP_BEGIN_2000
;
343 pdata
->rtc
->range_max
= RTC_TIMESTAMP_END_2099
;
345 ret
= rtc_register_device(pdata
->rtc
);
349 pdata
->rtc
->max_user_freq
= 128;
351 pic32_rtc_setfreq(&pdev
->dev
, 1);
352 ret
= devm_request_irq(&pdev
->dev
, pdata
->alarm_irq
,
353 pic32_rtc_alarmirq
, 0,
354 dev_name(&pdev
->dev
), pdata
);
357 "IRQ %d error %d\n", pdata
->alarm_irq
, ret
);
361 clk_disable(pdata
->clk
);
366 pic32_rtc_enable(pdata
, 0);
367 clk_disable_unprepare(pdata
->clk
);
372 static const struct of_device_id pic32_rtc_dt_ids
[] = {
373 { .compatible
= "microchip,pic32mzda-rtc" },
376 MODULE_DEVICE_TABLE(of
, pic32_rtc_dt_ids
);
378 static struct platform_driver pic32_rtc_driver
= {
379 .probe
= pic32_rtc_probe
,
380 .remove
= pic32_rtc_remove
,
383 .of_match_table
= of_match_ptr(pic32_rtc_dt_ids
),
386 module_platform_driver(pic32_rtc_driver
);
388 MODULE_DESCRIPTION("Microchip PIC32 RTC Driver");
389 MODULE_AUTHOR("Joshua Henderson <joshua.henderson@microchip.com>");
390 MODULE_LICENSE("GPL");