summaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorGregory CLEMENT <gregory.clement@free-electrons.com>2015-02-13 17:41:11 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-14 00:21:43 -0500
commita3a42806920ad12ec831fb2de4f63e251778300f (patch)
tree2c47af59c1f6ddcd2acb39c5061ed88201d0b444 /drivers/rtc
parentbb624047de21993622bc616eceaae94a096d9256 (diff)
drivers/rtc/rtc-armada38x: add a new RTC driver for recent mvebu SoCs
The new mvebu SoCs come with a new RTC driver. This patch adds the support for this new IP which is currently found in the Armada 38x SoCs. This RTC provides two alarms, but only the first one is used in the driver. The RTC also allows using periodic interrupts. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Reviewed-by: Arnaud Ebalard <arno@natisbad.org> Cc: Alessandro Zummo <a.zummo@towertech.it> Cc: Jason Cooper <jason@lakedaemon.net> Cc: Andrew Lunn <andrew@lunn.ch> Cc: Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> Cc: Thomas Petazzoni <thomas.petazzoni@free-electrons.com> Cc: Ezequiel Garcia <ezequiel.garcia@free-electrons.com> Cc: Maxime Ripard <maxime.ripard@free-electrons.com> Cc: Boris BREZILLON <boris.brezillon@free-electrons.com> Cc: Lior Amsalem <alior@marvell.com> Cc: Tawfik Bayouk <tawfik@marvell.com> Cc: Nadav Haklai <nadavh@marvell.com> Cc: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-armada38x.c320
3 files changed, 331 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 1b19f327f35f..3bc9ddbe5cf7 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1280,6 +1280,16 @@ config RTC_DRV_MV
1280 This driver can also be built as a module. If so, the module 1280 This driver can also be built as a module. If so, the module
1281 will be called rtc-mv. 1281 will be called rtc-mv.
1282 1282
1283config RTC_DRV_ARMADA38X
1284 tristate "Armada 38x Marvell SoC RTC"
1285 depends on ARCH_MVEBU
1286 help
1287 If you say yes here you will get support for the in-chip RTC
1288 that can be found in the Armada 38x Marvell's SoC device
1289
1290 This driver can also be built as a module. If so, the module
1291 will be called armada38x-rtc.
1292
1283config RTC_DRV_PS3 1293config RTC_DRV_PS3
1284 tristate "PS3 RTC" 1294 tristate "PS3 RTC"
1285 depends on PPC_PS3 1295 depends on PPC_PS3
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 855c4e364058..99ded8b75e95 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
25obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o 25obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
26obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o 26obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
27obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o 27obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
28obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
28obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o 29obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
29obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o 30obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
30obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o 31obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c
new file mode 100644
index 000000000000..43e04af39e09
--- /dev/null
+++ b/drivers/rtc/rtc-armada38x.c
@@ -0,0 +1,320 @@
1/*
2 * RTC driver for the Armada 38x Marvell SoCs
3 *
4 * Copyright (C) 2015 Marvell
5 *
6 * Gregory Clement <gregory.clement@free-electrons.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 */
14
15#include <linux/delay.h>
16#include <linux/io.h>
17#include <linux/module.h>
18#include <linux/of.h>
19#include <linux/platform_device.h>
20#include <linux/rtc.h>
21
22#define RTC_STATUS 0x0
23#define RTC_STATUS_ALARM1 BIT(0)
24#define RTC_STATUS_ALARM2 BIT(1)
25#define RTC_IRQ1_CONF 0x4
26#define RTC_IRQ1_AL_EN BIT(0)
27#define RTC_IRQ1_FREQ_EN BIT(1)
28#define RTC_IRQ1_FREQ_1HZ BIT(2)
29#define RTC_TIME 0xC
30#define RTC_ALARM1 0x10
31
32#define SOC_RTC_INTERRUPT 0x8
33#define SOC_RTC_ALARM1 BIT(0)
34#define SOC_RTC_ALARM2 BIT(1)
35#define SOC_RTC_ALARM1_MASK BIT(2)
36#define SOC_RTC_ALARM2_MASK BIT(3)
37
38struct armada38x_rtc {
39 struct rtc_device *rtc_dev;
40 void __iomem *regs;
41 void __iomem *regs_soc;
42 spinlock_t lock;
43 int irq;
44};
45
46/*
47 * According to the datasheet, the OS should wait 5us after every
48 * register write to the RTC hard macro so that the required update
49 * can occur without holding off the system bus
50 */
51static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
52{
53 writel(val, rtc->regs + offset);
54 udelay(5);
55}
56
57static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
58{
59 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
60 unsigned long time, time_check, flags;
61
62 spin_lock_irqsave(&rtc->lock, flags);
63
64 time = readl(rtc->regs + RTC_TIME);
65 /*
66 * WA for failing time set attempts. As stated in HW ERRATA if
67 * more than one second between two time reads is detected
68 * then read once again.
69 */
70 time_check = readl(rtc->regs + RTC_TIME);
71 if ((time_check - time) > 1)
72 time_check = readl(rtc->regs + RTC_TIME);
73
74 spin_unlock_irqrestore(&rtc->lock, flags);
75
76 rtc_time_to_tm(time_check, tm);
77
78 return 0;
79}
80
81static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
82{
83 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
84 int ret = 0;
85 unsigned long time, flags;
86
87 ret = rtc_tm_to_time(tm, &time);
88
89 if (ret)
90 goto out;
91 /*
92 * Setting the RTC time not always succeeds. According to the
93 * errata we need to first write on the status register and
94 * then wait for 100ms before writing to the time register to be
95 * sure that the data will be taken into account.
96 */
97 spin_lock_irqsave(&rtc->lock, flags);
98
99 rtc_delayed_write(0, rtc, RTC_STATUS);
100
101 spin_unlock_irqrestore(&rtc->lock, flags);
102
103 msleep(100);
104
105 spin_lock_irqsave(&rtc->lock, flags);
106
107 rtc_delayed_write(time, rtc, RTC_TIME);
108
109 spin_unlock_irqrestore(&rtc->lock, flags);
110out:
111 return ret;
112}
113
114static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
115{
116 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
117 unsigned long time, flags;
118 u32 val;
119
120 spin_lock_irqsave(&rtc->lock, flags);
121
122 time = readl(rtc->regs + RTC_ALARM1);
123 val = readl(rtc->regs + RTC_IRQ1_CONF) & RTC_IRQ1_AL_EN;
124
125 spin_unlock_irqrestore(&rtc->lock, flags);
126
127 alrm->enabled = val ? 1 : 0;
128 rtc_time_to_tm(time, &alrm->time);
129
130 return 0;
131}
132
133static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
134{
135 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
136 unsigned long time, flags;
137 int ret = 0;
138 u32 val;
139
140 ret = rtc_tm_to_time(&alrm->time, &time);
141
142 if (ret)
143 goto out;
144
145 spin_lock_irqsave(&rtc->lock, flags);
146
147 rtc_delayed_write(time, rtc, RTC_ALARM1);
148
149 if (alrm->enabled) {
150 rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
151 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
152 writel(val | SOC_RTC_ALARM1_MASK,
153 rtc->regs_soc + SOC_RTC_INTERRUPT);
154 }
155
156 spin_unlock_irqrestore(&rtc->lock, flags);
157
158out:
159 return ret;
160}
161
162static int armada38x_rtc_alarm_irq_enable(struct device *dev,
163 unsigned int enabled)
164{
165 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
166 unsigned long flags;
167
168 spin_lock_irqsave(&rtc->lock, flags);
169
170 if (enabled)
171 rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
172 else
173 rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
174
175 spin_unlock_irqrestore(&rtc->lock, flags);
176
177 return 0;
178}
179
180static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
181{
182 struct armada38x_rtc *rtc = data;
183 u32 val;
184 int event = RTC_IRQF | RTC_AF;
185
186 dev_dbg(&rtc->rtc_dev->dev, "%s:irq(%d)\n", __func__, irq);
187
188 spin_lock(&rtc->lock);
189
190 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
191
192 writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT);
193 val = readl(rtc->regs + RTC_IRQ1_CONF);
194 /* disable all the interrupts for alarm 1 */
195 rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
196 /* Ack the event */
197 rtc_delayed_write(RTC_STATUS_ALARM1, rtc, RTC_STATUS);
198
199 spin_unlock(&rtc->lock);
200
201 if (val & RTC_IRQ1_FREQ_EN) {
202 if (val & RTC_IRQ1_FREQ_1HZ)
203 event |= RTC_UF;
204 else
205 event |= RTC_PF;
206 }
207
208 rtc_update_irq(rtc->rtc_dev, 1, event);
209
210 return IRQ_HANDLED;
211}
212
213static struct rtc_class_ops armada38x_rtc_ops = {
214 .read_time = armada38x_rtc_read_time,
215 .set_time = armada38x_rtc_set_time,
216 .read_alarm = armada38x_rtc_read_alarm,
217 .set_alarm = armada38x_rtc_set_alarm,
218 .alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
219};
220
221static __init int armada38x_rtc_probe(struct platform_device *pdev)
222{
223 struct resource *res;
224 struct armada38x_rtc *rtc;
225 int ret;
226
227 rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc),
228 GFP_KERNEL);
229 if (!rtc)
230 return -ENOMEM;
231
232 spin_lock_init(&rtc->lock);
233
234 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
235 rtc->regs = devm_ioremap_resource(&pdev->dev, res);
236 if (IS_ERR(rtc->regs))
237 return PTR_ERR(rtc->regs);
238 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc-soc");
239 rtc->regs_soc = devm_ioremap_resource(&pdev->dev, res);
240 if (IS_ERR(rtc->regs_soc))
241 return PTR_ERR(rtc->regs_soc);
242
243 rtc->irq = platform_get_irq(pdev, 0);
244
245 if (rtc->irq < 0) {
246 dev_err(&pdev->dev, "no irq\n");
247 return rtc->irq;
248 }
249 if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq,
250 0, pdev->name, rtc) < 0) {
251 dev_warn(&pdev->dev, "Interrupt not available.\n");
252 rtc->irq = -1;
253 /*
254 * If there is no interrupt available then we can't
255 * use the alarm
256 */
257 armada38x_rtc_ops.set_alarm = NULL;
258 armada38x_rtc_ops.alarm_irq_enable = NULL;
259 }
260 platform_set_drvdata(pdev, rtc);
261 if (rtc->irq != -1)
262 device_init_wakeup(&pdev->dev, 1);
263
264 rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
265 &armada38x_rtc_ops, THIS_MODULE);
266 if (IS_ERR(rtc->rtc_dev)) {
267 ret = PTR_ERR(rtc->rtc_dev);
268 dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
269 return ret;
270 }
271 return 0;
272}
273
274#ifdef CONFIG_PM_SLEEP
275static int armada38x_rtc_suspend(struct device *dev)
276{
277 if (device_may_wakeup(dev)) {
278 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
279
280 return enable_irq_wake(rtc->irq);
281 }
282
283 return 0;
284}
285
286static int armada38x_rtc_resume(struct device *dev)
287{
288 if (device_may_wakeup(dev)) {
289 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
290
291 return disable_irq_wake(rtc->irq);
292 }
293
294 return 0;
295}
296#endif
297
298static SIMPLE_DEV_PM_OPS(armada38x_rtc_pm_ops,
299 armada38x_rtc_suspend, armada38x_rtc_resume);
300
301#ifdef CONFIG_OF
302static const struct of_device_id armada38x_rtc_of_match_table[] = {
303 { .compatible = "marvell,armada-380-rtc", },
304 {}
305};
306#endif
307
308static struct platform_driver armada38x_rtc_driver = {
309 .driver = {
310 .name = "armada38x-rtc",
311 .pm = &armada38x_rtc_pm_ops,
312 .of_match_table = of_match_ptr(armada38x_rtc_of_match_table),
313 },
314};
315
316module_platform_driver_probe(armada38x_rtc_driver, armada38x_rtc_probe);
317
318MODULE_DESCRIPTION("Marvell Armada 38x RTC driver");
319MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
320MODULE_LICENSE("GPL");