summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/rtc/Kconfig11
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-aspeed.c136
3 files changed, 148 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index dc0d66e80038..fd1321875cb1 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1841,6 +1841,17 @@ config RTC_DRV_RTD119X
1841 If you say yes here, you get support for the RTD1295 SoC 1841 If you say yes here, you get support for the RTD1295 SoC
1842 Real Time Clock. 1842 Real Time Clock.
1843 1843
1844config RTC_DRV_ASPEED
1845 tristate "ASPEED RTC"
1846 depends on OF
1847 depends on ARCH_ASPEED || COMPILE_TEST
1848 help
1849 If you say yes here you get support for the ASPEED BMC SoC real time
1850 clocks.
1851
1852 This driver can also be built as a module, if so, the module
1853 will be called "rtc-aspeed".
1854
1844comment "HID Sensor RTC drivers" 1855comment "HID Sensor RTC drivers"
1845 1856
1846config RTC_DRV_HID_SENSOR_TIME 1857config RTC_DRV_HID_SENSOR_TIME
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index fe3962496685..9d997faa2c26 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o
34obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o 34obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
35obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o 35obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
36obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o 36obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
37obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o
37obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o 38obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
38obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o 39obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
39obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o 40obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
diff --git a/drivers/rtc/rtc-aspeed.c b/drivers/rtc/rtc-aspeed.c
new file mode 100644
index 000000000000..af3eb676d7c3
--- /dev/null
+++ b/drivers/rtc/rtc-aspeed.c
@@ -0,0 +1,136 @@
1// SPDX-License-Identifier: GPL-2.0+
2// Copyright 2015 IBM Corp.
3
4#include <linux/module.h>
5#include <linux/of.h>
6#include <linux/platform_device.h>
7#include <linux/rtc.h>
8#include <linux/io.h>
9
10struct aspeed_rtc {
11 struct rtc_device *rtc_dev;
12 void __iomem *base;
13};
14
15#define RTC_TIME 0x00
16#define RTC_YEAR 0x04
17#define RTC_CTRL 0x10
18
19#define RTC_UNLOCK BIT(1)
20#define RTC_ENABLE BIT(0)
21
22static int aspeed_rtc_read_time(struct device *dev, struct rtc_time *tm)
23{
24 struct aspeed_rtc *rtc = dev_get_drvdata(dev);
25 unsigned int cent, year;
26 u32 reg1, reg2;
27
28 if (!(readl(rtc->base + RTC_CTRL) & RTC_ENABLE)) {
29 dev_dbg(dev, "%s failing as rtc disabled\n", __func__);
30 return -EINVAL;
31 }
32
33 do {
34 reg2 = readl(rtc->base + RTC_YEAR);
35 reg1 = readl(rtc->base + RTC_TIME);
36 } while (reg2 != readl(rtc->base + RTC_YEAR));
37
38 tm->tm_mday = (reg1 >> 24) & 0x1f;
39 tm->tm_hour = (reg1 >> 16) & 0x1f;
40 tm->tm_min = (reg1 >> 8) & 0x3f;
41 tm->tm_sec = (reg1 >> 0) & 0x3f;
42
43 cent = (reg2 >> 16) & 0x1f;
44 year = (reg2 >> 8) & 0x7f;
45 tm->tm_mon = ((reg2 >> 0) & 0x0f) - 1;
46 tm->tm_year = year + (cent * 100) - 1900;
47
48 dev_dbg(dev, "%s %ptR", __func__, tm);
49
50 return 0;
51}
52
53static int aspeed_rtc_set_time(struct device *dev, struct rtc_time *tm)
54{
55 struct aspeed_rtc *rtc = dev_get_drvdata(dev);
56 u32 reg1, reg2, ctrl;
57 int year, cent;
58
59 cent = (tm->tm_year + 1900) / 100;
60 year = tm->tm_year % 100;
61
62 reg1 = (tm->tm_mday << 24) | (tm->tm_hour << 16) | (tm->tm_min << 8) |
63 tm->tm_sec;
64
65 reg2 = ((cent & 0x1f) << 16) | ((year & 0x7f) << 8) |
66 ((tm->tm_mon + 1) & 0xf);
67
68 ctrl = readl(rtc->base + RTC_CTRL);
69 writel(ctrl | RTC_UNLOCK, rtc->base + RTC_CTRL);
70
71 writel(reg1, rtc->base + RTC_TIME);
72 writel(reg2, rtc->base + RTC_YEAR);
73
74 /* Re-lock and ensure enable is set now that a time is programmed */
75 writel(ctrl | RTC_ENABLE, rtc->base + RTC_CTRL);
76
77 return 0;
78}
79
80static const struct rtc_class_ops aspeed_rtc_ops = {
81 .read_time = aspeed_rtc_read_time,
82 .set_time = aspeed_rtc_set_time,
83};
84
85static int aspeed_rtc_probe(struct platform_device *pdev)
86{
87 struct aspeed_rtc *rtc;
88 struct resource *res;
89 int ret;
90
91 rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
92 if (!rtc)
93 return -ENOMEM;
94
95 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
96 rtc->base = devm_ioremap_resource(&pdev->dev, res);
97 if (IS_ERR(rtc->base))
98 return PTR_ERR(rtc->base);
99
100 rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
101 if (IS_ERR(rtc->rtc_dev))
102 return PTR_ERR(rtc->rtc_dev);
103
104 platform_set_drvdata(pdev, rtc);
105
106 rtc->rtc_dev->ops = &aspeed_rtc_ops;
107 rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
108 rtc->rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */
109
110 ret = rtc_register_device(rtc->rtc_dev);
111 if (ret)
112 return ret;
113
114 return 0;
115}
116
117static const struct of_device_id aspeed_rtc_match[] = {
118 { .compatible = "aspeed,ast2400-rtc", },
119 { .compatible = "aspeed,ast2500-rtc", },
120 { .compatible = "aspeed,ast2600-rtc", },
121 {}
122};
123MODULE_DEVICE_TABLE(of, aspeed_rtc_match);
124
125static struct platform_driver aspeed_rtc_driver = {
126 .driver = {
127 .name = "aspeed-rtc",
128 .of_match_table = of_match_ptr(aspeed_rtc_match),
129 },
130};
131
132module_platform_driver_probe(aspeed_rtc_driver, aspeed_rtc_probe);
133
134MODULE_DESCRIPTION("ASPEED RTC driver");
135MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
136MODULE_LICENSE("GPL");