aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorLee Jones <lee.jones@linaro.org>2015-04-09 10:47:33 -0400
committerLee Jones <lee.jones@linaro.org>2015-04-30 08:21:31 -0400
commitb5b2bdfc2893910fdc02d21ec5c535635c896ff7 (patch)
tree97f216688c9ae61c8e9175bd8c38f53571451dbc /drivers/rtc
parent5cb69745da35c372b3db001efbd3967b633ba0d1 (diff)
rtc: st: Add new driver for ST's LPC RTC
ST's Low Power Controller (LPC) controls two devices; watchdog and RTC. Only one of the devices can be used at any one time. This is enforced by the correlating MFD driver. This portion of the driver-set controls the Real Time Clock. Cc: Alessandro Zummo <a.zummo@towertech.it> Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig11
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-st-lpc.c354
3 files changed, 366 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 6149ae01e11f..8b8b332efaed 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1510,6 +1510,17 @@ config RTC_DRV_SIRFSOC
1510 Say "yes" here to support the real time clock on SiRF SOC chips. 1510 Say "yes" here to support the real time clock on SiRF SOC chips.
1511 This driver can also be built as a module called rtc-sirfsoc. 1511 This driver can also be built as a module called rtc-sirfsoc.
1512 1512
1513config RTC_DRV_ST_LPC
1514 tristate "STMicroelectronics LPC RTC"
1515 depends on ARCH_STI
1516 depends on OF
1517 help
1518 Say Y here to include STMicroelectronics Low Power Controller
1519 (LPC) based RTC support.
1520
1521 To compile this driver as a module, choose M here: the
1522 module will be called rtc-st-lpc.
1523
1513config RTC_DRV_MOXART 1524config RTC_DRV_MOXART
1514 tristate "MOXA ART RTC" 1525 tristate "MOXA ART RTC"
1515 depends on ARCH_MOXART || COMPILE_TEST 1526 depends on ARCH_MOXART || COMPILE_TEST
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index c31731c29762..411e630f36b9 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -153,4 +153,5 @@ obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
153obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o 153obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
154obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o 154obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o
155obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o 155obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
156obj-$(CONFIG_RTC_DRV_ST_LPC) += rtc-st-lpc.o
156obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o 157obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c
new file mode 100644
index 000000000000..3f9d0acb81c7
--- /dev/null
+++ b/drivers/rtc/rtc-st-lpc.c
@@ -0,0 +1,354 @@
1/*
2 * rtc-st-lpc.c - ST's LPC RTC, powered by the Low Power Timer
3 *
4 * Copyright (C) 2014 STMicroelectronics Limited
5 *
6 * Author: David Paris <david.paris@st.com> for STMicroelectronics
7 * Lee Jones <lee.jones@linaro.org> for STMicroelectronics
8 *
9 * Based on the original driver written by Stuart Menefy.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public Licence
13 * as published by the Free Software Foundation; either version
14 * 2 of the Licence, or (at your option) any later version.
15 */
16
17#include <linux/clk.h>
18#include <linux/delay.h>
19#include <linux/init.h>
20#include <linux/io.h>
21#include <linux/irq.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/of.h>
25#include <linux/of_irq.h>
26#include <linux/platform_device.h>
27#include <linux/rtc.h>
28
29#include <dt-bindings/mfd/st-lpc.h>
30
31/* Low Power Timer */
32#define LPC_LPT_LSB_OFF 0x400
33#define LPC_LPT_MSB_OFF 0x404
34#define LPC_LPT_START_OFF 0x408
35
36/* Low Power Alarm */
37#define LPC_LPA_LSB_OFF 0x410
38#define LPC_LPA_MSB_OFF 0x414
39#define LPC_LPA_START_OFF 0x418
40
41/* LPC as WDT */
42#define LPC_WDT_OFF 0x510
43#define LPC_WDT_FLAG_OFF 0x514
44
45struct st_rtc {
46 struct rtc_device *rtc_dev;
47 struct rtc_wkalrm alarm;
48 struct resource *res;
49 struct clk *clk;
50 unsigned long clkrate;
51 void __iomem *ioaddr;
52 bool irq_enabled:1;
53 spinlock_t lock;
54 short irq;
55};
56
57static void st_rtc_set_hw_alarm(struct st_rtc *rtc,
58 unsigned long msb, unsigned long lsb)
59{
60 unsigned long flags;
61
62 spin_lock_irqsave(&rtc->lock, flags);
63
64 writel_relaxed(1, rtc->ioaddr + LPC_WDT_OFF);
65
66 writel_relaxed(msb, rtc->ioaddr + LPC_LPA_MSB_OFF);
67 writel_relaxed(lsb, rtc->ioaddr + LPC_LPA_LSB_OFF);
68 writel_relaxed(1, rtc->ioaddr + LPC_LPA_START_OFF);
69
70 writel_relaxed(0, rtc->ioaddr + LPC_WDT_OFF);
71
72 spin_unlock_irqrestore(&rtc->lock, flags);
73}
74
75static irqreturn_t st_rtc_handler(int this_irq, void *data)
76{
77 struct st_rtc *rtc = (struct st_rtc *)data;
78
79 rtc_update_irq(rtc->rtc_dev, 1, RTC_AF);
80
81 return IRQ_HANDLED;
82}
83
84static int st_rtc_read_time(struct device *dev, struct rtc_time *tm)
85{
86 struct st_rtc *rtc = dev_get_drvdata(dev);
87 unsigned long lpt_lsb, lpt_msb;
88 unsigned long long lpt;
89 unsigned long flags;
90
91 spin_lock_irqsave(&rtc->lock, flags);
92
93 do {
94 lpt_msb = readl_relaxed(rtc->ioaddr + LPC_LPT_MSB_OFF);
95 lpt_lsb = readl_relaxed(rtc->ioaddr + LPC_LPT_LSB_OFF);
96 } while (readl_relaxed(rtc->ioaddr + LPC_LPT_MSB_OFF) != lpt_msb);
97
98 spin_unlock_irqrestore(&rtc->lock, flags);
99
100 lpt = ((unsigned long long)lpt_msb << 32) | lpt_lsb;
101 do_div(lpt, rtc->clkrate);
102 rtc_time_to_tm(lpt, tm);
103
104 return 0;
105}
106
107static int st_rtc_set_time(struct device *dev, struct rtc_time *tm)
108{
109 struct st_rtc *rtc = dev_get_drvdata(dev);
110 unsigned long long lpt;
111 unsigned long secs, flags;
112 int ret;
113
114 ret = rtc_tm_to_time(tm, &secs);
115 if (ret)
116 return ret;
117
118 lpt = (unsigned long long)secs * rtc->clkrate;
119
120 spin_lock_irqsave(&rtc->lock, flags);
121
122 writel_relaxed(lpt >> 32, rtc->ioaddr + LPC_LPT_MSB_OFF);
123 writel_relaxed(lpt, rtc->ioaddr + LPC_LPT_LSB_OFF);
124 writel_relaxed(1, rtc->ioaddr + LPC_LPT_START_OFF);
125
126 spin_unlock_irqrestore(&rtc->lock, flags);
127
128 return 0;
129}
130
131static int st_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
132{
133 struct st_rtc *rtc = dev_get_drvdata(dev);
134 unsigned long flags;
135
136 spin_lock_irqsave(&rtc->lock, flags);
137
138 memcpy(wkalrm, &rtc->alarm, sizeof(struct rtc_wkalrm));
139
140 spin_unlock_irqrestore(&rtc->lock, flags);
141
142 return 0;
143}
144
145static int st_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
146{
147 struct st_rtc *rtc = dev_get_drvdata(dev);
148
149 if (enabled && !rtc->irq_enabled) {
150 enable_irq(rtc->irq);
151 rtc->irq_enabled = true;
152 } else if (!enabled && rtc->irq_enabled) {
153 disable_irq(rtc->irq);
154 rtc->irq_enabled = false;
155 }
156
157 return 0;
158}
159
160static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
161{
162 struct st_rtc *rtc = dev_get_drvdata(dev);
163 struct rtc_time now;
164 unsigned long now_secs;
165 unsigned long alarm_secs;
166 unsigned long long lpa;
167
168 st_rtc_read_time(dev, &now);
169 rtc_tm_to_time(&now, &now_secs);
170 rtc_tm_to_time(&t->time, &alarm_secs);
171
172 /* Invalid alarm time */
173 if (now_secs > alarm_secs)
174 return -EINVAL;
175
176 memcpy(&rtc->alarm, t, sizeof(struct rtc_wkalrm));
177
178 /* Now many secs to fire */
179 alarm_secs -= now_secs;
180 lpa = (unsigned long long)alarm_secs * rtc->clkrate;
181
182 st_rtc_set_hw_alarm(rtc, lpa >> 32, lpa);
183 st_rtc_alarm_irq_enable(dev, t->enabled);
184
185 return 0;
186}
187
188static struct rtc_class_ops st_rtc_ops = {
189 .read_time = st_rtc_read_time,
190 .set_time = st_rtc_set_time,
191 .read_alarm = st_rtc_read_alarm,
192 .set_alarm = st_rtc_set_alarm,
193 .alarm_irq_enable = st_rtc_alarm_irq_enable,
194};
195
196static int st_rtc_probe(struct platform_device *pdev)
197{
198 struct device_node *np = pdev->dev.of_node;
199 struct st_rtc *rtc;
200 struct resource *res;
201 struct rtc_time tm_check;
202 uint32_t mode;
203 int ret = 0;
204
205 ret = of_property_read_u32(np, "st,lpc-mode", &mode);
206 if (ret) {
207 dev_err(&pdev->dev, "An LPC mode must be provided\n");
208 return -EINVAL;
209 }
210
211 /* LPC can either run in RTC or WDT mode */
212 if (mode != ST_LPC_MODE_RTC)
213 return -ENODEV;
214
215 rtc = devm_kzalloc(&pdev->dev, sizeof(struct st_rtc), GFP_KERNEL);
216 if (!rtc)
217 return -ENOMEM;
218
219 spin_lock_init(&rtc->lock);
220
221 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
222 rtc->ioaddr = devm_ioremap_resource(&pdev->dev, res);
223 if (IS_ERR(rtc->ioaddr))
224 return PTR_ERR(rtc->ioaddr);
225
226 rtc->irq = irq_of_parse_and_map(np, 0);
227 if (!rtc->irq) {
228 dev_err(&pdev->dev, "IRQ missing or invalid\n");
229 return -EINVAL;
230 }
231
232 ret = devm_request_irq(&pdev->dev, rtc->irq, st_rtc_handler, 0,
233 pdev->name, rtc);
234 if (ret) {
235 dev_err(&pdev->dev, "Failed to request irq %i\n", rtc->irq);
236 return ret;
237 }
238
239 enable_irq_wake(rtc->irq);
240 disable_irq(rtc->irq);
241
242 rtc->clk = clk_get(&pdev->dev, NULL);
243 if (IS_ERR(rtc->clk)) {
244 dev_err(&pdev->dev, "Unable to request clock\n");
245 return PTR_ERR(rtc->clk);
246 }
247
248 clk_prepare_enable(rtc->clk);
249
250 rtc->clkrate = clk_get_rate(rtc->clk);
251 if (!rtc->clkrate) {
252 dev_err(&pdev->dev, "Unable to fetch clock rate\n");
253 return -EINVAL;
254 }
255
256 device_set_wakeup_capable(&pdev->dev, 1);
257
258 platform_set_drvdata(pdev, rtc);
259
260 /*
261 * The RTC-LPC is able to manage date.year > 2038
262 * but currently the kernel can not manage this date!
263 * If the RTC-LPC has a date.year > 2038 then
264 * it's set to the epoch "Jan 1st 2000"
265 */
266 st_rtc_read_time(&pdev->dev, &tm_check);
267
268 if (tm_check.tm_year >= (2038 - 1900)) {
269 memset(&tm_check, 0, sizeof(tm_check));
270 tm_check.tm_year = 100;
271 tm_check.tm_mday = 1;
272 st_rtc_set_time(&pdev->dev, &tm_check);
273 }
274
275 rtc->rtc_dev = rtc_device_register("st-lpc-rtc", &pdev->dev,
276 &st_rtc_ops, THIS_MODULE);
277 if (IS_ERR(rtc->rtc_dev)) {
278 clk_disable_unprepare(rtc->clk);
279 return PTR_ERR(rtc->rtc_dev);
280 }
281
282 return 0;
283}
284
285static int st_rtc_remove(struct platform_device *pdev)
286{
287 struct st_rtc *rtc = platform_get_drvdata(pdev);
288
289 if (likely(rtc->rtc_dev))
290 rtc_device_unregister(rtc->rtc_dev);
291
292 return 0;
293}
294
295#ifdef CONFIG_PM_SLEEP
296static int st_rtc_suspend(struct device *dev)
297{
298 struct st_rtc *rtc = dev_get_drvdata(dev);
299
300 if (device_may_wakeup(dev))
301 return 0;
302
303 writel_relaxed(1, rtc->ioaddr + LPC_WDT_OFF);
304 writel_relaxed(0, rtc->ioaddr + LPC_LPA_START_OFF);
305 writel_relaxed(0, rtc->ioaddr + LPC_WDT_OFF);
306
307 return 0;
308}
309
310static int st_rtc_resume(struct device *dev)
311{
312 struct st_rtc *rtc = dev_get_drvdata(dev);
313
314 rtc_alarm_irq_enable(rtc->rtc_dev, 0);
315
316 /*
317 * clean 'rtc->alarm' to allow a new
318 * .set_alarm to the upper RTC layer
319 */
320 memset(&rtc->alarm, 0, sizeof(struct rtc_wkalrm));
321
322 writel_relaxed(0, rtc->ioaddr + LPC_LPA_MSB_OFF);
323 writel_relaxed(0, rtc->ioaddr + LPC_LPA_LSB_OFF);
324 writel_relaxed(1, rtc->ioaddr + LPC_WDT_OFF);
325 writel_relaxed(1, rtc->ioaddr + LPC_LPA_START_OFF);
326 writel_relaxed(0, rtc->ioaddr + LPC_WDT_OFF);
327
328 return 0;
329}
330#endif
331
332static SIMPLE_DEV_PM_OPS(st_rtc_pm_ops, st_rtc_suspend, st_rtc_resume);
333
334static const struct of_device_id st_rtc_match[] = {
335 { .compatible = "st,stih407-lpc" },
336 {}
337};
338MODULE_DEVICE_TABLE(of, st_rtc_match);
339
340static struct platform_driver st_rtc_platform_driver = {
341 .driver = {
342 .name = "st-lpc-rtc",
343 .pm = &st_rtc_pm_ops,
344 .of_match_table = st_rtc_match,
345 },
346 .probe = st_rtc_probe,
347 .remove = st_rtc_remove,
348};
349
350module_platform_driver(st_rtc_platform_driver);
351
352MODULE_DESCRIPTION("STMicroelectronics LPC RTC driver");
353MODULE_AUTHOR("David Paris <david.paris@st.com>");
354MODULE_LICENSE("GPL");