2 * RTC driver for NXP LPC178x/18xx/43xx Real-Time Clock (RTC)
4 * Copyright (C) 2011 NXP Semiconductors
5 * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
14 #include <linux/clk.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
19 #include <linux/of_device.h>
20 #include <linux/platform_device.h>
21 #include <linux/rtc.h>
23 /* LPC24xx RTC register offsets and bits */
24 #define LPC24XX_ILR 0x00
25 #define LPC24XX_RTCCIF BIT(0)
26 #define LPC24XX_RTCALF BIT(1)
27 #define LPC24XX_CTC 0x04
28 #define LPC24XX_CCR 0x08
29 #define LPC24XX_CLKEN BIT(0)
30 #define LPC178X_CCALEN BIT(4)
31 #define LPC24XX_CIIR 0x0c
32 #define LPC24XX_AMR 0x10
33 #define LPC24XX_ALARM_DISABLE 0xff
34 #define LPC24XX_CTIME0 0x14
35 #define LPC24XX_CTIME1 0x18
36 #define LPC24XX_CTIME2 0x1c
37 #define LPC24XX_SEC 0x20
38 #define LPC24XX_MIN 0x24
39 #define LPC24XX_HOUR 0x28
40 #define LPC24XX_DOM 0x2c
41 #define LPC24XX_DOW 0x30
42 #define LPC24XX_DOY 0x34
43 #define LPC24XX_MONTH 0x38
44 #define LPC24XX_YEAR 0x3c
45 #define LPC24XX_ALSEC 0x60
46 #define LPC24XX_ALMIN 0x64
47 #define LPC24XX_ALHOUR 0x68
48 #define LPC24XX_ALDOM 0x6c
49 #define LPC24XX_ALDOW 0x70
50 #define LPC24XX_ALDOY 0x74
51 #define LPC24XX_ALMON 0x78
52 #define LPC24XX_ALYEAR 0x7c
54 /* Macros to read fields in consolidated time (CT) registers */
55 #define CT0_SECS(x) (((x) >> 0) & 0x3f)
56 #define CT0_MINS(x) (((x) >> 8) & 0x3f)
57 #define CT0_HOURS(x) (((x) >> 16) & 0x1f)
58 #define CT0_DOW(x) (((x) >> 24) & 0x07)
59 #define CT1_DOM(x) (((x) >> 0) & 0x1f)
60 #define CT1_MONTH(x) (((x) >> 8) & 0x0f)
61 #define CT1_YEAR(x) (((x) >> 16) & 0xfff)
62 #define CT2_DOY(x) (((x) >> 0) & 0xfff)
64 #define rtc_readl(dev, reg) readl((dev)->rtc_base + (reg))
65 #define rtc_writel(dev, reg, val) writel((val), (dev)->rtc_base + (reg))
68 void __iomem
*rtc_base
;
69 struct rtc_device
*rtc
;
74 static int lpc24xx_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
76 struct lpc24xx_rtc
*rtc
= dev_get_drvdata(dev
);
78 /* Disable RTC during update */
79 rtc_writel(rtc
, LPC24XX_CCR
, LPC178X_CCALEN
);
81 rtc_writel(rtc
, LPC24XX_SEC
, tm
->tm_sec
);
82 rtc_writel(rtc
, LPC24XX_MIN
, tm
->tm_min
);
83 rtc_writel(rtc
, LPC24XX_HOUR
, tm
->tm_hour
);
84 rtc_writel(rtc
, LPC24XX_DOW
, tm
->tm_wday
);
85 rtc_writel(rtc
, LPC24XX_DOM
, tm
->tm_mday
);
86 rtc_writel(rtc
, LPC24XX_DOY
, tm
->tm_yday
);
87 rtc_writel(rtc
, LPC24XX_MONTH
, tm
->tm_mon
);
88 rtc_writel(rtc
, LPC24XX_YEAR
, tm
->tm_year
);
90 rtc_writel(rtc
, LPC24XX_CCR
, LPC24XX_CLKEN
| LPC178X_CCALEN
);
95 static int lpc24xx_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
97 struct lpc24xx_rtc
*rtc
= dev_get_drvdata(dev
);
100 ct0
= rtc_readl(rtc
, LPC24XX_CTIME0
);
101 ct1
= rtc_readl(rtc
, LPC24XX_CTIME1
);
102 ct2
= rtc_readl(rtc
, LPC24XX_CTIME2
);
104 tm
->tm_sec
= CT0_SECS(ct0
);
105 tm
->tm_min
= CT0_MINS(ct0
);
106 tm
->tm_hour
= CT0_HOURS(ct0
);
107 tm
->tm_wday
= CT0_DOW(ct0
);
108 tm
->tm_mon
= CT1_MONTH(ct1
);
109 tm
->tm_mday
= CT1_DOM(ct1
);
110 tm
->tm_year
= CT1_YEAR(ct1
);
111 tm
->tm_yday
= CT2_DOY(ct2
);
113 return rtc_valid_tm(tm
);
116 static int lpc24xx_rtc_read_alarm(struct device
*dev
, struct rtc_wkalrm
*wkalrm
)
118 struct lpc24xx_rtc
*rtc
= dev_get_drvdata(dev
);
119 struct rtc_time
*tm
= &wkalrm
->time
;
121 tm
->tm_sec
= rtc_readl(rtc
, LPC24XX_ALSEC
);
122 tm
->tm_min
= rtc_readl(rtc
, LPC24XX_ALMIN
);
123 tm
->tm_hour
= rtc_readl(rtc
, LPC24XX_ALHOUR
);
124 tm
->tm_mday
= rtc_readl(rtc
, LPC24XX_ALDOM
);
125 tm
->tm_wday
= rtc_readl(rtc
, LPC24XX_ALDOW
);
126 tm
->tm_yday
= rtc_readl(rtc
, LPC24XX_ALDOY
);
127 tm
->tm_mon
= rtc_readl(rtc
, LPC24XX_ALMON
);
128 tm
->tm_year
= rtc_readl(rtc
, LPC24XX_ALYEAR
);
130 wkalrm
->enabled
= rtc_readl(rtc
, LPC24XX_AMR
) == 0;
131 wkalrm
->pending
= !!(rtc_readl(rtc
, LPC24XX_ILR
) & LPC24XX_RTCCIF
);
133 return rtc_valid_tm(&wkalrm
->time
);
136 static int lpc24xx_rtc_set_alarm(struct device
*dev
, struct rtc_wkalrm
*wkalrm
)
138 struct lpc24xx_rtc
*rtc
= dev_get_drvdata(dev
);
139 struct rtc_time
*tm
= &wkalrm
->time
;
141 /* Disable alarm irq during update */
142 rtc_writel(rtc
, LPC24XX_AMR
, LPC24XX_ALARM_DISABLE
);
144 rtc_writel(rtc
, LPC24XX_ALSEC
, tm
->tm_sec
);
145 rtc_writel(rtc
, LPC24XX_ALMIN
, tm
->tm_min
);
146 rtc_writel(rtc
, LPC24XX_ALHOUR
, tm
->tm_hour
);
147 rtc_writel(rtc
, LPC24XX_ALDOM
, tm
->tm_mday
);
148 rtc_writel(rtc
, LPC24XX_ALDOW
, tm
->tm_wday
);
149 rtc_writel(rtc
, LPC24XX_ALDOY
, tm
->tm_yday
);
150 rtc_writel(rtc
, LPC24XX_ALMON
, tm
->tm_mon
);
151 rtc_writel(rtc
, LPC24XX_ALYEAR
, tm
->tm_year
);
154 rtc_writel(rtc
, LPC24XX_AMR
, 0);
159 static int lpc24xx_rtc_alarm_irq_enable(struct device
*dev
, unsigned int enable
)
161 struct lpc24xx_rtc
*rtc
= dev_get_drvdata(dev
);
164 rtc_writel(rtc
, LPC24XX_AMR
, 0);
166 rtc_writel(rtc
, LPC24XX_AMR
, LPC24XX_ALARM_DISABLE
);
171 static irqreturn_t
lpc24xx_rtc_interrupt(int irq
, void *data
)
173 unsigned long events
= RTC_IRQF
;
174 struct lpc24xx_rtc
*rtc
= data
;
177 /* Check interrupt cause */
178 rtc_iir
= rtc_readl(rtc
, LPC24XX_ILR
);
179 if (rtc_iir
& LPC24XX_RTCALF
) {
181 rtc_writel(rtc
, LPC24XX_AMR
, LPC24XX_ALARM_DISABLE
);
184 /* Clear interrupt status and report event */
185 rtc_writel(rtc
, LPC24XX_ILR
, rtc_iir
);
186 rtc_update_irq(rtc
->rtc
, 1, events
);
191 static const struct rtc_class_ops lpc24xx_rtc_ops
= {
192 .read_time
= lpc24xx_rtc_read_time
,
193 .set_time
= lpc24xx_rtc_set_time
,
194 .read_alarm
= lpc24xx_rtc_read_alarm
,
195 .set_alarm
= lpc24xx_rtc_set_alarm
,
196 .alarm_irq_enable
= lpc24xx_rtc_alarm_irq_enable
,
199 static int lpc24xx_rtc_probe(struct platform_device
*pdev
)
201 struct lpc24xx_rtc
*rtc
;
202 struct resource
*res
;
205 rtc
= devm_kzalloc(&pdev
->dev
, sizeof(*rtc
), GFP_KERNEL
);
209 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
210 rtc
->rtc_base
= devm_ioremap_resource(&pdev
->dev
, res
);
211 if (IS_ERR(rtc
->rtc_base
))
212 return PTR_ERR(rtc
->rtc_base
);
214 irq
= platform_get_irq(pdev
, 0);
216 dev_warn(&pdev
->dev
, "can't get interrupt resource\n");
220 rtc
->clk_rtc
= devm_clk_get(&pdev
->dev
, "rtc");
221 if (IS_ERR(rtc
->clk_rtc
)) {
222 dev_err(&pdev
->dev
, "error getting rtc clock\n");
223 return PTR_ERR(rtc
->clk_rtc
);
226 rtc
->clk_reg
= devm_clk_get(&pdev
->dev
, "reg");
227 if (IS_ERR(rtc
->clk_reg
)) {
228 dev_err(&pdev
->dev
, "error getting reg clock\n");
229 return PTR_ERR(rtc
->clk_reg
);
232 ret
= clk_prepare_enable(rtc
->clk_rtc
);
234 dev_err(&pdev
->dev
, "unable to enable rtc clock\n");
238 ret
= clk_prepare_enable(rtc
->clk_reg
);
240 dev_err(&pdev
->dev
, "unable to enable reg clock\n");
241 goto disable_rtc_clk
;
244 platform_set_drvdata(pdev
, rtc
);
246 /* Clear any pending interrupts */
247 rtc_writel(rtc
, LPC24XX_ILR
, LPC24XX_RTCCIF
| LPC24XX_RTCALF
);
249 /* Enable RTC count */
250 rtc_writel(rtc
, LPC24XX_CCR
, LPC24XX_CLKEN
| LPC178X_CCALEN
);
252 ret
= devm_request_irq(&pdev
->dev
, irq
, lpc24xx_rtc_interrupt
, 0,
255 dev_warn(&pdev
->dev
, "can't request interrupt\n");
259 rtc
->rtc
= devm_rtc_device_register(&pdev
->dev
, "lpc24xx-rtc",
260 &lpc24xx_rtc_ops
, THIS_MODULE
);
261 if (IS_ERR(rtc
->rtc
)) {
262 dev_err(&pdev
->dev
, "can't register rtc device\n");
263 ret
= PTR_ERR(rtc
->rtc
);
270 clk_disable_unprepare(rtc
->clk_reg
);
272 clk_disable_unprepare(rtc
->clk_rtc
);
276 static int lpc24xx_rtc_remove(struct platform_device
*pdev
)
278 struct lpc24xx_rtc
*rtc
= platform_get_drvdata(pdev
);
280 /* Ensure all interrupt sources are masked */
281 rtc_writel(rtc
, LPC24XX_AMR
, LPC24XX_ALARM_DISABLE
);
282 rtc_writel(rtc
, LPC24XX_CIIR
, 0);
284 rtc_writel(rtc
, LPC24XX_CCR
, LPC178X_CCALEN
);
286 clk_disable_unprepare(rtc
->clk_rtc
);
287 clk_disable_unprepare(rtc
->clk_reg
);
292 static const struct of_device_id lpc24xx_rtc_match
[] = {
293 { .compatible
= "nxp,lpc1788-rtc" },
296 MODULE_DEVICE_TABLE(of
, lpc24xx_rtc_match
);
298 static struct platform_driver lpc24xx_rtc_driver
= {
299 .probe
= lpc24xx_rtc_probe
,
300 .remove
= lpc24xx_rtc_remove
,
302 .name
= "lpc24xx-rtc",
303 .of_match_table
= lpc24xx_rtc_match
,
306 module_platform_driver(lpc24xx_rtc_driver
);
308 MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com>");
309 MODULE_DESCRIPTION("RTC driver for the LPC178x/18xx/408x/43xx SoCs");
310 MODULE_LICENSE("GPL");