blob: 7cb5b27189db16710e07685e477cc9579a4e6b76 [file] [log] [blame]
Gregory CLEMENTa3a42802015-02-13 14:41:11 -08001/*
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
Gregory CLEMENT844a3072016-12-21 11:28:16 +010032#define SOC_RTC_BRIDGE_TIMING_CTL 0x0
33#define SOC_RTC_PERIOD_OFFS 0
34#define SOC_RTC_PERIOD_MASK (0x3FF << SOC_RTC_PERIOD_OFFS)
35#define SOC_RTC_READ_DELAY_OFFS 26
36#define SOC_RTC_READ_DELAY_MASK (0x1F << SOC_RTC_READ_DELAY_OFFS)
37
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080038#define SOC_RTC_INTERRUPT 0x8
39#define SOC_RTC_ALARM1 BIT(0)
40#define SOC_RTC_ALARM2 BIT(1)
41#define SOC_RTC_ALARM1_MASK BIT(2)
42#define SOC_RTC_ALARM2_MASK BIT(3)
43
Gregory CLEMENT844a3072016-12-21 11:28:16 +010044#define SAMPLE_NR 100
45
46struct value_to_freq {
47 u32 value;
48 u8 freq;
49};
50
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080051struct armada38x_rtc {
52 struct rtc_device *rtc_dev;
53 void __iomem *regs;
54 void __iomem *regs_soc;
55 spinlock_t lock;
56 int irq;
Gregory CLEMENT844a3072016-12-21 11:28:16 +010057 struct value_to_freq *val_to_freq;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080058};
59
60/*
61 * According to the datasheet, the OS should wait 5us after every
62 * register write to the RTC hard macro so that the required update
63 * can occur without holding off the system bus
Gregory CLEMENT844a3072016-12-21 11:28:16 +010064 * According to errata RES-3124064, Write to any RTC register
65 * may fail. As a workaround, before writing to RTC
66 * register, issue a dummy write of 0x0 twice to RTC Status
67 * register.
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080068 */
Gregory CLEMENT844a3072016-12-21 11:28:16 +010069
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080070static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
71{
Gregory CLEMENT844a3072016-12-21 11:28:16 +010072 writel(0, rtc->regs + RTC_STATUS);
73 writel(0, rtc->regs + RTC_STATUS);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080074 writel(val, rtc->regs + offset);
75 udelay(5);
76}
77
Gregory CLEMENT844a3072016-12-21 11:28:16 +010078/* Update RTC-MBUS bridge timing parameters */
79static void rtc_update_mbus_timing_params(struct armada38x_rtc *rtc)
80{
81 u32 reg;
82
83 reg = readl(rtc->regs_soc + SOC_RTC_BRIDGE_TIMING_CTL);
84 reg &= ~SOC_RTC_PERIOD_MASK;
85 reg |= 0x3FF << SOC_RTC_PERIOD_OFFS; /* Maximum value */
86 reg &= ~SOC_RTC_READ_DELAY_MASK;
87 reg |= 0x1F << SOC_RTC_READ_DELAY_OFFS; /* Maximum value */
88 writel(reg, rtc->regs_soc + SOC_RTC_BRIDGE_TIMING_CTL);
89}
90
91static u32 read_rtc_register_wa(struct armada38x_rtc *rtc, u8 rtc_reg)
92{
93 int i, index_max = 0, max = 0;
94
95 for (i = 0; i < SAMPLE_NR; i++) {
96 rtc->val_to_freq[i].value = readl(rtc->regs + rtc_reg);
97 rtc->val_to_freq[i].freq = 0;
98 }
99
100 for (i = 0; i < SAMPLE_NR; i++) {
101 int j = 0;
102 u32 value = rtc->val_to_freq[i].value;
103
104 while (rtc->val_to_freq[j].freq) {
105 if (rtc->val_to_freq[j].value == value) {
106 rtc->val_to_freq[j].freq++;
107 break;
108 }
109 j++;
110 }
111
112 if (!rtc->val_to_freq[j].freq) {
113 rtc->val_to_freq[j].value = value;
114 rtc->val_to_freq[j].freq = 1;
115 }
116
117 if (rtc->val_to_freq[j].freq > max) {
118 index_max = j;
119 max = rtc->val_to_freq[j].freq;
120 }
121
122 /*
123 * If a value already has half of the sample this is the most
124 * frequent one and we can stop the research right now
125 */
126 if (max > SAMPLE_NR / 2)
127 break;
128 }
129
130 return rtc->val_to_freq[index_max].value;
131}
132
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800133static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
134{
135 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100136 unsigned long time, flags;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800137
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200138 spin_lock_irqsave(&rtc->lock, flags);
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100139 time = read_rtc_register_wa(rtc, RTC_TIME);
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200140 spin_unlock_irqrestore(&rtc->lock, flags);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800141
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100142 rtc_time_to_tm(time, tm);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800143
144 return 0;
145}
146
147static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
148{
149 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
150 int ret = 0;
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200151 unsigned long time, flags;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800152
153 ret = rtc_tm_to_time(tm, &time);
154
155 if (ret)
156 goto out;
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100157
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200158 spin_lock_irqsave(&rtc->lock, flags);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800159 rtc_delayed_write(time, rtc, RTC_TIME);
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200160 spin_unlock_irqrestore(&rtc->lock, flags);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800161
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800162out:
163 return ret;
164}
165
166static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
167{
168 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
169 unsigned long time, flags;
170 u32 val;
171
172 spin_lock_irqsave(&rtc->lock, flags);
173
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100174 time = read_rtc_register_wa(rtc, RTC_ALARM1);
175 val = read_rtc_register_wa(rtc, RTC_IRQ1_CONF) & RTC_IRQ1_AL_EN;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800176
177 spin_unlock_irqrestore(&rtc->lock, flags);
178
179 alrm->enabled = val ? 1 : 0;
180 rtc_time_to_tm(time, &alrm->time);
181
182 return 0;
183}
184
185static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
186{
187 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
188 unsigned long time, flags;
189 int ret = 0;
190 u32 val;
191
192 ret = rtc_tm_to_time(&alrm->time, &time);
193
194 if (ret)
195 goto out;
196
197 spin_lock_irqsave(&rtc->lock, flags);
198
199 rtc_delayed_write(time, rtc, RTC_ALARM1);
200
201 if (alrm->enabled) {
202 rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
203 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
204 writel(val | SOC_RTC_ALARM1_MASK,
205 rtc->regs_soc + SOC_RTC_INTERRUPT);
206 }
207
208 spin_unlock_irqrestore(&rtc->lock, flags);
209
210out:
211 return ret;
212}
213
214static int armada38x_rtc_alarm_irq_enable(struct device *dev,
215 unsigned int enabled)
216{
217 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
218 unsigned long flags;
219
220 spin_lock_irqsave(&rtc->lock, flags);
221
222 if (enabled)
223 rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
224 else
225 rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
226
227 spin_unlock_irqrestore(&rtc->lock, flags);
228
229 return 0;
230}
231
232static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
233{
234 struct armada38x_rtc *rtc = data;
235 u32 val;
236 int event = RTC_IRQF | RTC_AF;
237
238 dev_dbg(&rtc->rtc_dev->dev, "%s:irq(%d)\n", __func__, irq);
239
240 spin_lock(&rtc->lock);
241
242 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
243
244 writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT);
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100245 val = read_rtc_register_wa(rtc, RTC_IRQ1_CONF);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800246 /* disable all the interrupts for alarm 1 */
247 rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
248 /* Ack the event */
249 rtc_delayed_write(RTC_STATUS_ALARM1, rtc, RTC_STATUS);
250
251 spin_unlock(&rtc->lock);
252
253 if (val & RTC_IRQ1_FREQ_EN) {
254 if (val & RTC_IRQ1_FREQ_1HZ)
255 event |= RTC_UF;
256 else
257 event |= RTC_PF;
258 }
259
260 rtc_update_irq(rtc->rtc_dev, 1, event);
261
262 return IRQ_HANDLED;
263}
264
Russell Kingd748c982017-01-11 10:16:58 +0000265static const struct rtc_class_ops armada38x_rtc_ops = {
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800266 .read_time = armada38x_rtc_read_time,
267 .set_time = armada38x_rtc_set_time,
268 .read_alarm = armada38x_rtc_read_alarm,
269 .set_alarm = armada38x_rtc_set_alarm,
270 .alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
271};
272
Russell Kingd748c982017-01-11 10:16:58 +0000273static const struct rtc_class_ops armada38x_rtc_ops_noirq = {
274 .read_time = armada38x_rtc_read_time,
275 .set_time = armada38x_rtc_set_time,
276 .read_alarm = armada38x_rtc_read_alarm,
277};
278
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800279static __init int armada38x_rtc_probe(struct platform_device *pdev)
280{
Russell Kingd748c982017-01-11 10:16:58 +0000281 const struct rtc_class_ops *ops;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800282 struct resource *res;
283 struct armada38x_rtc *rtc;
284 int ret;
285
286 rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc),
287 GFP_KERNEL);
288 if (!rtc)
289 return -ENOMEM;
290
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100291 rtc->val_to_freq = devm_kcalloc(&pdev->dev, SAMPLE_NR,
292 sizeof(struct value_to_freq), GFP_KERNEL);
293 if (!rtc->val_to_freq)
294 return -ENOMEM;
295
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800296 spin_lock_init(&rtc->lock);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800297
298 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
299 rtc->regs = devm_ioremap_resource(&pdev->dev, res);
300 if (IS_ERR(rtc->regs))
301 return PTR_ERR(rtc->regs);
302 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc-soc");
303 rtc->regs_soc = devm_ioremap_resource(&pdev->dev, res);
304 if (IS_ERR(rtc->regs_soc))
305 return PTR_ERR(rtc->regs_soc);
306
307 rtc->irq = platform_get_irq(pdev, 0);
308
309 if (rtc->irq < 0) {
310 dev_err(&pdev->dev, "no irq\n");
311 return rtc->irq;
312 }
313 if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq,
314 0, pdev->name, rtc) < 0) {
315 dev_warn(&pdev->dev, "Interrupt not available.\n");
316 rtc->irq = -1;
Russell Kingd748c982017-01-11 10:16:58 +0000317 }
318 platform_set_drvdata(pdev, rtc);
319
320 if (rtc->irq != -1) {
321 device_init_wakeup(&pdev->dev, 1);
322 ops = &armada38x_rtc_ops;
323 } else {
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800324 /*
325 * If there is no interrupt available then we can't
326 * use the alarm
327 */
Russell Kingd748c982017-01-11 10:16:58 +0000328 ops = &armada38x_rtc_ops_noirq;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800329 }
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800330
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100331 /* Update RTC-MBUS bridge timing parameters */
332 rtc_update_mbus_timing_params(rtc);
333
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800334 rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
Russell Kingd748c982017-01-11 10:16:58 +0000335 ops, THIS_MODULE);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800336 if (IS_ERR(rtc->rtc_dev)) {
337 ret = PTR_ERR(rtc->rtc_dev);
338 dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
339 return ret;
340 }
341 return 0;
342}
343
344#ifdef CONFIG_PM_SLEEP
345static int armada38x_rtc_suspend(struct device *dev)
346{
347 if (device_may_wakeup(dev)) {
348 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
349
350 return enable_irq_wake(rtc->irq);
351 }
352
353 return 0;
354}
355
356static int armada38x_rtc_resume(struct device *dev)
357{
358 if (device_may_wakeup(dev)) {
359 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
360
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100361 /* Update RTC-MBUS bridge timing parameters */
362 rtc_update_mbus_timing_params(rtc);
363
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800364 return disable_irq_wake(rtc->irq);
365 }
366
367 return 0;
368}
369#endif
370
371static SIMPLE_DEV_PM_OPS(armada38x_rtc_pm_ops,
372 armada38x_rtc_suspend, armada38x_rtc_resume);
373
374#ifdef CONFIG_OF
375static const struct of_device_id armada38x_rtc_of_match_table[] = {
376 { .compatible = "marvell,armada-380-rtc", },
377 {}
378};
Javier Martinez Canillas73798d52015-08-27 13:52:02 +0200379MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800380#endif
381
382static struct platform_driver armada38x_rtc_driver = {
383 .driver = {
384 .name = "armada38x-rtc",
385 .pm = &armada38x_rtc_pm_ops,
386 .of_match_table = of_match_ptr(armada38x_rtc_of_match_table),
387 },
388};
389
390module_platform_driver_probe(armada38x_rtc_driver, armada38x_rtc_probe);
391
392MODULE_DESCRIPTION("Marvell Armada 38x RTC driver");
393MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
394MODULE_LICENSE("GPL");