blob: b2a8e2ed71cabbf6b440a5da28d793f4027e1e71 [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>
Gregory CLEMENT75faea92017-02-20 18:38:48 +010019#include <linux/of_device.h>
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080020#include <linux/platform_device.h>
21#include <linux/rtc.h>
22
23#define RTC_STATUS 0x0
24#define RTC_STATUS_ALARM1 BIT(0)
25#define RTC_STATUS_ALARM2 BIT(1)
26#define RTC_IRQ1_CONF 0x4
Gregory CLEMENT75faea92017-02-20 18:38:48 +010027#define RTC_IRQ_AL_EN BIT(0)
28#define RTC_IRQ_FREQ_EN BIT(1)
29#define RTC_IRQ_FREQ_1HZ BIT(2)
30
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080031#define RTC_TIME 0xC
32#define RTC_ALARM1 0x10
Gregory CLEMENT75faea92017-02-20 18:38:48 +010033#define RTC_38X_BRIDGE_TIMING_CTL 0x0
34#define RTC_38X_PERIOD_OFFS 0
35#define RTC_38X_PERIOD_MASK (0x3FF << RTC_38X_PERIOD_OFFS)
36#define RTC_38X_READ_DELAY_OFFS 26
37#define RTC_38X_READ_DELAY_MASK (0x1F << RTC_38X_READ_DELAY_OFFS)
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080038
Gregory CLEMENT75faea92017-02-20 18:38:48 +010039#define SOC_RTC_INTERRUPT 0x8
40#define SOC_RTC_ALARM1 BIT(0)
41#define SOC_RTC_ALARM2 BIT(1)
42#define SOC_RTC_ALARM1_MASK BIT(2)
43#define SOC_RTC_ALARM2_MASK BIT(3)
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080044
Gregory CLEMENT844a3072016-12-21 11:28:16 +010045#define SAMPLE_NR 100
46
47struct value_to_freq {
48 u32 value;
49 u8 freq;
50};
51
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080052struct armada38x_rtc {
53 struct rtc_device *rtc_dev;
54 void __iomem *regs;
55 void __iomem *regs_soc;
56 spinlock_t lock;
57 int irq;
Gregory CLEMENT844a3072016-12-21 11:28:16 +010058 struct value_to_freq *val_to_freq;
Gregory CLEMENT75faea92017-02-20 18:38:48 +010059 struct armada38x_rtc_data *data;
60};
61
62#define ALARM1 0
63#define ALARM_REG(base, alarm) ((base) + (alarm) * sizeof(u32))
64
65struct armada38x_rtc_data {
66 /* Initialize the RTC-MBUS bridge timing */
67 void (*update_mbus_timing)(struct armada38x_rtc *rtc);
68 u32 (*read_rtc_reg)(struct armada38x_rtc *rtc, u8 rtc_reg);
69 void (*clear_isr)(struct armada38x_rtc *rtc);
70 void (*unmask_interrupt)(struct armada38x_rtc *rtc);
71 u32 alarm;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080072};
73
74/*
75 * According to the datasheet, the OS should wait 5us after every
76 * register write to the RTC hard macro so that the required update
77 * can occur without holding off the system bus
Gregory CLEMENT844a3072016-12-21 11:28:16 +010078 * According to errata RES-3124064, Write to any RTC register
79 * may fail. As a workaround, before writing to RTC
80 * register, issue a dummy write of 0x0 twice to RTC Status
81 * register.
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080082 */
Gregory CLEMENT844a3072016-12-21 11:28:16 +010083
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080084static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
85{
Gregory CLEMENT844a3072016-12-21 11:28:16 +010086 writel(0, rtc->regs + RTC_STATUS);
87 writel(0, rtc->regs + RTC_STATUS);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -080088 writel(val, rtc->regs + offset);
89 udelay(5);
90}
91
Gregory CLEMENT844a3072016-12-21 11:28:16 +010092/* Update RTC-MBUS bridge timing parameters */
Gregory CLEMENT75faea92017-02-20 18:38:48 +010093static void rtc_update_38x_mbus_timing_params(struct armada38x_rtc *rtc)
Gregory CLEMENT844a3072016-12-21 11:28:16 +010094{
95 u32 reg;
96
Gregory CLEMENT75faea92017-02-20 18:38:48 +010097 reg = readl(rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
98 reg &= ~RTC_38X_PERIOD_MASK;
99 reg |= 0x3FF << RTC_38X_PERIOD_OFFS; /* Maximum value */
100 reg &= ~RTC_38X_READ_DELAY_MASK;
101 reg |= 0x1F << RTC_38X_READ_DELAY_OFFS; /* Maximum value */
102 writel(reg, rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100103}
104
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100105static u32 read_rtc_register_38x_wa(struct armada38x_rtc *rtc, u8 rtc_reg)
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100106{
107 int i, index_max = 0, max = 0;
108
109 for (i = 0; i < SAMPLE_NR; i++) {
110 rtc->val_to_freq[i].value = readl(rtc->regs + rtc_reg);
111 rtc->val_to_freq[i].freq = 0;
112 }
113
114 for (i = 0; i < SAMPLE_NR; i++) {
115 int j = 0;
116 u32 value = rtc->val_to_freq[i].value;
117
118 while (rtc->val_to_freq[j].freq) {
119 if (rtc->val_to_freq[j].value == value) {
120 rtc->val_to_freq[j].freq++;
121 break;
122 }
123 j++;
124 }
125
126 if (!rtc->val_to_freq[j].freq) {
127 rtc->val_to_freq[j].value = value;
128 rtc->val_to_freq[j].freq = 1;
129 }
130
131 if (rtc->val_to_freq[j].freq > max) {
132 index_max = j;
133 max = rtc->val_to_freq[j].freq;
134 }
135
136 /*
137 * If a value already has half of the sample this is the most
138 * frequent one and we can stop the research right now
139 */
140 if (max > SAMPLE_NR / 2)
141 break;
142 }
143
144 return rtc->val_to_freq[index_max].value;
145}
146
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100147static void armada38x_clear_isr(struct armada38x_rtc *rtc)
148{
149 u32 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
150
151 writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT);
152}
153
154static void armada38x_unmask_interrupt(struct armada38x_rtc *rtc)
155{
156 u32 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
157
158 writel(val | SOC_RTC_ALARM1_MASK, rtc->regs_soc + SOC_RTC_INTERRUPT);
159}
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800160static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
161{
162 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100163 unsigned long time, flags;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800164
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200165 spin_lock_irqsave(&rtc->lock, flags);
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100166 time = rtc->data->read_rtc_reg(rtc, RTC_TIME);
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200167 spin_unlock_irqrestore(&rtc->lock, flags);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800168
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100169 rtc_time_to_tm(time, tm);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800170
171 return 0;
172}
173
174static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
175{
176 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
177 int ret = 0;
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200178 unsigned long time, flags;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800179
180 ret = rtc_tm_to_time(tm, &time);
181
182 if (ret)
183 goto out;
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100184
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200185 spin_lock_irqsave(&rtc->lock, flags);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800186 rtc_delayed_write(time, rtc, RTC_TIME);
Nadav Haklai0c6e7182015-08-06 17:18:48 +0200187 spin_unlock_irqrestore(&rtc->lock, flags);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800188
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800189out:
190 return ret;
191}
192
193static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
194{
195 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
196 unsigned long time, flags;
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100197 u32 reg = ALARM_REG(RTC_ALARM1, rtc->data->alarm);
198 u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800199 u32 val;
200
201 spin_lock_irqsave(&rtc->lock, flags);
202
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100203 time = rtc->data->read_rtc_reg(rtc, reg);
204 val = rtc->data->read_rtc_reg(rtc, reg_irq) & RTC_IRQ_AL_EN;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800205
206 spin_unlock_irqrestore(&rtc->lock, flags);
207
208 alrm->enabled = val ? 1 : 0;
209 rtc_time_to_tm(time, &alrm->time);
210
211 return 0;
212}
213
214static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
215{
216 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100217 u32 reg = ALARM_REG(RTC_ALARM1, rtc->data->alarm);
218 u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800219 unsigned long time, flags;
220 int ret = 0;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800221
222 ret = rtc_tm_to_time(&alrm->time, &time);
223
224 if (ret)
225 goto out;
226
227 spin_lock_irqsave(&rtc->lock, flags);
228
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100229 rtc_delayed_write(time, rtc, reg);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800230
231 if (alrm->enabled) {
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100232 rtc_delayed_write(RTC_IRQ_AL_EN, rtc, reg_irq);
233 rtc->data->unmask_interrupt(rtc);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800234 }
235
236 spin_unlock_irqrestore(&rtc->lock, flags);
237
238out:
239 return ret;
240}
241
242static int armada38x_rtc_alarm_irq_enable(struct device *dev,
243 unsigned int enabled)
244{
245 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100246 u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800247 unsigned long flags;
248
249 spin_lock_irqsave(&rtc->lock, flags);
250
251 if (enabled)
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100252 rtc_delayed_write(RTC_IRQ_AL_EN, rtc, reg_irq);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800253 else
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100254 rtc_delayed_write(0, rtc, reg_irq);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800255
256 spin_unlock_irqrestore(&rtc->lock, flags);
257
258 return 0;
259}
260
261static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
262{
263 struct armada38x_rtc *rtc = data;
264 u32 val;
265 int event = RTC_IRQF | RTC_AF;
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100266 u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800267
268 dev_dbg(&rtc->rtc_dev->dev, "%s:irq(%d)\n", __func__, irq);
269
270 spin_lock(&rtc->lock);
271
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100272 rtc->data->clear_isr(rtc);
273 val = rtc->data->read_rtc_reg(rtc, reg_irq);
274 /* disable all the interrupts for alarm*/
275 rtc_delayed_write(0, rtc, reg_irq);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800276 /* Ack the event */
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100277 rtc_delayed_write(1 << rtc->data->alarm, rtc, RTC_STATUS);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800278
279 spin_unlock(&rtc->lock);
280
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100281 if (val & RTC_IRQ_FREQ_EN) {
282 if (val & RTC_IRQ_FREQ_1HZ)
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800283 event |= RTC_UF;
284 else
285 event |= RTC_PF;
286 }
287
288 rtc_update_irq(rtc->rtc_dev, 1, event);
289
290 return IRQ_HANDLED;
291}
292
Russell Kingd748c982017-01-11 10:16:58 +0000293static const struct rtc_class_ops armada38x_rtc_ops = {
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800294 .read_time = armada38x_rtc_read_time,
295 .set_time = armada38x_rtc_set_time,
296 .read_alarm = armada38x_rtc_read_alarm,
297 .set_alarm = armada38x_rtc_set_alarm,
298 .alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
299};
300
Russell Kingd748c982017-01-11 10:16:58 +0000301static const struct rtc_class_ops armada38x_rtc_ops_noirq = {
302 .read_time = armada38x_rtc_read_time,
303 .set_time = armada38x_rtc_set_time,
304 .read_alarm = armada38x_rtc_read_alarm,
305};
306
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100307static const struct armada38x_rtc_data armada38x_data = {
308 .update_mbus_timing = rtc_update_38x_mbus_timing_params,
309 .read_rtc_reg = read_rtc_register_38x_wa,
310 .clear_isr = armada38x_clear_isr,
311 .unmask_interrupt = armada38x_unmask_interrupt,
312 .alarm = ALARM1,
313};
314
315#ifdef CONFIG_OF
316static const struct of_device_id armada38x_rtc_of_match_table[] = {
317 {
318 .compatible = "marvell,armada-380-rtc",
319 .data = &armada38x_data,
320 },
321 {}
322};
323MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table);
324#endif
325
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800326static __init int armada38x_rtc_probe(struct platform_device *pdev)
327{
Russell Kingd748c982017-01-11 10:16:58 +0000328 const struct rtc_class_ops *ops;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800329 struct resource *res;
330 struct armada38x_rtc *rtc;
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100331 const struct of_device_id *match;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800332 int ret;
333
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100334 match = of_match_device(armada38x_rtc_of_match_table, &pdev->dev);
335 if (!match)
336 return -ENODEV;
337
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800338 rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc),
339 GFP_KERNEL);
340 if (!rtc)
341 return -ENOMEM;
342
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100343 rtc->val_to_freq = devm_kcalloc(&pdev->dev, SAMPLE_NR,
344 sizeof(struct value_to_freq), GFP_KERNEL);
345 if (!rtc->val_to_freq)
346 return -ENOMEM;
347
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800348 spin_lock_init(&rtc->lock);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800349
350 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
351 rtc->regs = devm_ioremap_resource(&pdev->dev, res);
352 if (IS_ERR(rtc->regs))
353 return PTR_ERR(rtc->regs);
354 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc-soc");
355 rtc->regs_soc = devm_ioremap_resource(&pdev->dev, res);
356 if (IS_ERR(rtc->regs_soc))
357 return PTR_ERR(rtc->regs_soc);
358
359 rtc->irq = platform_get_irq(pdev, 0);
360
361 if (rtc->irq < 0) {
362 dev_err(&pdev->dev, "no irq\n");
363 return rtc->irq;
364 }
365 if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq,
366 0, pdev->name, rtc) < 0) {
367 dev_warn(&pdev->dev, "Interrupt not available.\n");
368 rtc->irq = -1;
Russell Kingd748c982017-01-11 10:16:58 +0000369 }
370 platform_set_drvdata(pdev, rtc);
371
372 if (rtc->irq != -1) {
373 device_init_wakeup(&pdev->dev, 1);
374 ops = &armada38x_rtc_ops;
375 } else {
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800376 /*
377 * If there is no interrupt available then we can't
378 * use the alarm
379 */
Russell Kingd748c982017-01-11 10:16:58 +0000380 ops = &armada38x_rtc_ops_noirq;
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800381 }
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100382 rtc->data = (struct armada38x_rtc_data *)match->data;
383
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800384
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100385 /* Update RTC-MBUS bridge timing parameters */
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100386 rtc->data->update_mbus_timing(rtc);
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100387
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800388 rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
Russell Kingd748c982017-01-11 10:16:58 +0000389 ops, THIS_MODULE);
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800390 if (IS_ERR(rtc->rtc_dev)) {
391 ret = PTR_ERR(rtc->rtc_dev);
392 dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
393 return ret;
394 }
395 return 0;
396}
397
398#ifdef CONFIG_PM_SLEEP
399static int armada38x_rtc_suspend(struct device *dev)
400{
401 if (device_may_wakeup(dev)) {
402 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
403
404 return enable_irq_wake(rtc->irq);
405 }
406
407 return 0;
408}
409
410static int armada38x_rtc_resume(struct device *dev)
411{
412 if (device_may_wakeup(dev)) {
413 struct armada38x_rtc *rtc = dev_get_drvdata(dev);
414
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100415 /* Update RTC-MBUS bridge timing parameters */
Gregory CLEMENT75faea92017-02-20 18:38:48 +0100416 rtc->data->update_mbus_timing(rtc);
Gregory CLEMENT844a3072016-12-21 11:28:16 +0100417
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800418 return disable_irq_wake(rtc->irq);
419 }
420
421 return 0;
422}
423#endif
424
425static SIMPLE_DEV_PM_OPS(armada38x_rtc_pm_ops,
426 armada38x_rtc_suspend, armada38x_rtc_resume);
427
Gregory CLEMENTa3a42802015-02-13 14:41:11 -0800428static struct platform_driver armada38x_rtc_driver = {
429 .driver = {
430 .name = "armada38x-rtc",
431 .pm = &armada38x_rtc_pm_ops,
432 .of_match_table = of_match_ptr(armada38x_rtc_of_match_table),
433 },
434};
435
436module_platform_driver_probe(armada38x_rtc_driver, armada38x_rtc_probe);
437
438MODULE_DESCRIPTION("Marvell Armada 38x RTC driver");
439MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
440MODULE_LICENSE("GPL");