1 // SPDX-License-Identifier: GPL-2.0+
3 * APM X-Gene SoC Real Time Clock Driver
5 * Copyright (c) 2014, Applied Micro Circuits Corporation
6 * Author: Rameshwar Prasad Sahu <rsahu@apm.com>
10 #include <linux/clk.h>
11 #include <linux/delay.h>
12 #include <linux/init.h>
14 #include <linux/module.h>
16 #include <linux/platform_device.h>
17 #include <linux/rtc.h>
18 #include <linux/slab.h>
20 /* RTC CSR Registers */
25 #define RTC_CCR_IE BIT(0)
26 #define RTC_CCR_MASK BIT(1)
27 #define RTC_CCR_EN BIT(2)
28 #define RTC_CCR_WEN BIT(3)
30 #define RTC_STAT_BIT BIT(0)
31 #define RTC_RSTAT 0x14
35 struct xgene_rtc_dev
{
36 struct rtc_device
*rtc
;
38 void __iomem
*csr_base
;
40 unsigned int irq_wake
;
41 unsigned int irq_enabled
;
44 static int xgene_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
46 struct xgene_rtc_dev
*pdata
= dev_get_drvdata(dev
);
48 rtc_time64_to_tm(readl(pdata
->csr_base
+ RTC_CCVR
), tm
);
52 static int xgene_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
54 struct xgene_rtc_dev
*pdata
= dev_get_drvdata(dev
);
57 * NOTE: After the following write, the RTC_CCVR is only reflected
58 * after the update cycle of 1 seconds.
60 writel((u32
)rtc_tm_to_time64(tm
), pdata
->csr_base
+ RTC_CLR
);
61 readl(pdata
->csr_base
+ RTC_CLR
); /* Force a barrier */
66 static int xgene_rtc_read_alarm(struct device
*dev
, struct rtc_wkalrm
*alrm
)
68 struct xgene_rtc_dev
*pdata
= dev_get_drvdata(dev
);
70 /* If possible, CMR should be read here */
71 rtc_time64_to_tm(0, &alrm
->time
);
72 alrm
->enabled
= readl(pdata
->csr_base
+ RTC_CCR
) & RTC_CCR_IE
;
77 static int xgene_rtc_alarm_irq_enable(struct device
*dev
, u32 enabled
)
79 struct xgene_rtc_dev
*pdata
= dev_get_drvdata(dev
);
82 ccr
= readl(pdata
->csr_base
+ RTC_CCR
);
90 writel(ccr
, pdata
->csr_base
+ RTC_CCR
);
95 static int xgene_rtc_alarm_irq_enabled(struct device
*dev
)
97 struct xgene_rtc_dev
*pdata
= dev_get_drvdata(dev
);
99 return readl(pdata
->csr_base
+ RTC_CCR
) & RTC_CCR_IE
? 1 : 0;
102 static int xgene_rtc_set_alarm(struct device
*dev
, struct rtc_wkalrm
*alrm
)
104 struct xgene_rtc_dev
*pdata
= dev_get_drvdata(dev
);
106 writel((u32
)rtc_tm_to_time64(&alrm
->time
), pdata
->csr_base
+ RTC_CMR
);
108 xgene_rtc_alarm_irq_enable(dev
, alrm
->enabled
);
113 static const struct rtc_class_ops xgene_rtc_ops
= {
114 .read_time
= xgene_rtc_read_time
,
115 .set_time
= xgene_rtc_set_time
,
116 .read_alarm
= xgene_rtc_read_alarm
,
117 .set_alarm
= xgene_rtc_set_alarm
,
118 .alarm_irq_enable
= xgene_rtc_alarm_irq_enable
,
121 static irqreturn_t
xgene_rtc_interrupt(int irq
, void *id
)
123 struct xgene_rtc_dev
*pdata
= id
;
125 /* Check if interrupt asserted */
126 if (!(readl(pdata
->csr_base
+ RTC_STAT
) & RTC_STAT_BIT
))
129 /* Clear interrupt */
130 readl(pdata
->csr_base
+ RTC_EOI
);
132 rtc_update_irq(pdata
->rtc
, 1, RTC_IRQF
| RTC_AF
);
137 static int xgene_rtc_probe(struct platform_device
*pdev
)
139 struct xgene_rtc_dev
*pdata
;
140 struct resource
*res
;
144 pdata
= devm_kzalloc(&pdev
->dev
, sizeof(*pdata
), GFP_KERNEL
);
147 platform_set_drvdata(pdev
, pdata
);
148 pdata
->dev
= &pdev
->dev
;
150 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
151 pdata
->csr_base
= devm_ioremap_resource(&pdev
->dev
, res
);
152 if (IS_ERR(pdata
->csr_base
))
153 return PTR_ERR(pdata
->csr_base
);
155 pdata
->rtc
= devm_rtc_allocate_device(&pdev
->dev
);
156 if (IS_ERR(pdata
->rtc
))
157 return PTR_ERR(pdata
->rtc
);
159 irq
= platform_get_irq(pdev
, 0);
161 dev_err(&pdev
->dev
, "No IRQ resource\n");
164 ret
= devm_request_irq(&pdev
->dev
, irq
, xgene_rtc_interrupt
, 0,
165 dev_name(&pdev
->dev
), pdata
);
167 dev_err(&pdev
->dev
, "Could not request IRQ\n");
171 pdata
->clk
= devm_clk_get(&pdev
->dev
, NULL
);
172 if (IS_ERR(pdata
->clk
)) {
173 dev_err(&pdev
->dev
, "Couldn't get the clock for RTC\n");
176 ret
= clk_prepare_enable(pdata
->clk
);
180 /* Turn on the clock and the crystal */
181 writel(RTC_CCR_EN
, pdata
->csr_base
+ RTC_CCR
);
183 ret
= device_init_wakeup(&pdev
->dev
, 1);
185 clk_disable_unprepare(pdata
->clk
);
189 /* HW does not support update faster than 1 seconds */
190 pdata
->rtc
->uie_unsupported
= 1;
191 pdata
->rtc
->ops
= &xgene_rtc_ops
;
192 pdata
->rtc
->range_max
= U32_MAX
;
194 ret
= rtc_register_device(pdata
->rtc
);
196 clk_disable_unprepare(pdata
->clk
);
203 static int xgene_rtc_remove(struct platform_device
*pdev
)
205 struct xgene_rtc_dev
*pdata
= platform_get_drvdata(pdev
);
207 xgene_rtc_alarm_irq_enable(&pdev
->dev
, 0);
208 device_init_wakeup(&pdev
->dev
, 0);
209 clk_disable_unprepare(pdata
->clk
);
213 static int __maybe_unused
xgene_rtc_suspend(struct device
*dev
)
215 struct platform_device
*pdev
= to_platform_device(dev
);
216 struct xgene_rtc_dev
*pdata
= platform_get_drvdata(pdev
);
219 irq
= platform_get_irq(pdev
, 0);
222 * If this RTC alarm will be used for waking the system up,
223 * don't disable it of course. Else we just disable the alarm
224 * and await suspension.
226 if (device_may_wakeup(&pdev
->dev
)) {
227 if (!enable_irq_wake(irq
))
230 pdata
->irq_enabled
= xgene_rtc_alarm_irq_enabled(dev
);
231 xgene_rtc_alarm_irq_enable(dev
, 0);
232 clk_disable_unprepare(pdata
->clk
);
237 static int __maybe_unused
xgene_rtc_resume(struct device
*dev
)
239 struct platform_device
*pdev
= to_platform_device(dev
);
240 struct xgene_rtc_dev
*pdata
= platform_get_drvdata(pdev
);
244 irq
= platform_get_irq(pdev
, 0);
246 if (device_may_wakeup(&pdev
->dev
)) {
247 if (pdata
->irq_wake
) {
248 disable_irq_wake(irq
);
252 rc
= clk_prepare_enable(pdata
->clk
);
254 dev_err(dev
, "Unable to enable clock error %d\n", rc
);
257 xgene_rtc_alarm_irq_enable(dev
, pdata
->irq_enabled
);
263 static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops
, xgene_rtc_suspend
, xgene_rtc_resume
);
266 static const struct of_device_id xgene_rtc_of_match
[] = {
267 {.compatible
= "apm,xgene-rtc" },
270 MODULE_DEVICE_TABLE(of
, xgene_rtc_of_match
);
273 static struct platform_driver xgene_rtc_driver
= {
274 .probe
= xgene_rtc_probe
,
275 .remove
= xgene_rtc_remove
,
278 .pm
= &xgene_rtc_pm_ops
,
279 .of_match_table
= of_match_ptr(xgene_rtc_of_match
),
283 module_platform_driver(xgene_rtc_driver
);
285 MODULE_DESCRIPTION("APM X-Gene SoC RTC driver");
286 MODULE_AUTHOR("Rameshwar Sahu <rsahu@apm.com>");
287 MODULE_LICENSE("GPL");