aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorAlexey Charkov <alchark@gmail.com>2011-05-26 19:25:03 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-05-26 20:12:33 -0400
commitf77fbdf952d81ae20911edccea16693f9fb7c5a0 (patch)
tree2f66a9cf61b8174729c6fdf52ca06ac5b287830b /drivers/rtc
parent704f15ddb5fc2a7f25a12eb0913302d8ad9ffab3 (diff)
rtc: add support for the RTC in VIA VT8500 and compatibles
This adds a driver for the RTC devices in VIA and WonderMedia Systems-on-Chip. Alarm, 1Hz interrupts, reading and setting time are supported. Signed-off-by: Alexey Charkov <alchark@gmail.com> Cc: Lars-Peter Clausen <lars@metafoo.de> Cc: Alexey Charkov <alchark@gmail.com> Cc: Alessandro Zummo <a.zummo@towertech.it> 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/Kconfig7
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-vt8500.c366
3 files changed, 374 insertions, 0 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8e437e2f6281..3db52f01d458 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -884,6 +884,13 @@ config RTC_DRV_PXA
884 This RTC driver uses PXA RTC registers available since pxa27x 884 This RTC driver uses PXA RTC registers available since pxa27x
885 series (RDxR, RYxR) instead of legacy RCNR, RTAR. 885 series (RDxR, RYxR) instead of legacy RCNR, RTAR.
886 886
887config RTC_DRV_VT8500
888 tristate "VIA/WonderMedia 85xx SoC RTC"
889 depends on ARCH_VT8500
890 help
891 If you say Y here you will get access to the real time clock
892 built into your VIA VT8500 SoC or its relatives.
893
887 894
888config RTC_DRV_SUN4V 895config RTC_DRV_SUN4V
889 bool "SUN4V Hypervisor RTC" 896 bool "SUN4V Hypervisor RTC"
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 612f5a88a8ee..986f17e51df8 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -99,6 +99,7 @@ obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
99obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o 99obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
100obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o 100obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
101obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o 101obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
102obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o
102obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o 103obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
103obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o 104obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
104obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o 105obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c
new file mode 100644
index 000000000000..b8bc862903ae
--- /dev/null
+++ b/drivers/rtc/rtc-vt8500.c
@@ -0,0 +1,366 @@
1/*
2 * drivers/rtc/rtc-vt8500.c
3 *
4 * Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
5 *
6 * Based on rtc-pxa.c
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
17
18#include <linux/module.h>
19#include <linux/rtc.h>
20#include <linux/init.h>
21#include <linux/interrupt.h>
22#include <linux/io.h>
23#include <linux/bcd.h>
24#include <linux/platform_device.h>
25#include <linux/slab.h>
26
27/*
28 * Register definitions
29 */
30#define VT8500_RTC_TS 0x00 /* Time set */
31#define VT8500_RTC_DS 0x04 /* Date set */
32#define VT8500_RTC_AS 0x08 /* Alarm set */
33#define VT8500_RTC_CR 0x0c /* Control */
34#define VT8500_RTC_TR 0x10 /* Time read */
35#define VT8500_RTC_DR 0x14 /* Date read */
36#define VT8500_RTC_WS 0x18 /* Write status */
37#define VT8500_RTC_CL 0x20 /* Calibration */
38#define VT8500_RTC_IS 0x24 /* Interrupt status */
39#define VT8500_RTC_ST 0x28 /* Status */
40
41#define INVALID_TIME_BIT (1 << 31)
42
43#define DATE_CENTURY_S 19
44#define DATE_YEAR_S 11
45#define DATE_YEAR_MASK (0xff << DATE_YEAR_S)
46#define DATE_MONTH_S 6
47#define DATE_MONTH_MASK (0x1f << DATE_MONTH_S)
48#define DATE_DAY_MASK 0x3f
49
50#define TIME_DOW_S 20
51#define TIME_DOW_MASK (0x07 << TIME_DOW_S)
52#define TIME_HOUR_S 14
53#define TIME_HOUR_MASK (0x3f << TIME_HOUR_S)
54#define TIME_MIN_S 7
55#define TIME_MIN_MASK (0x7f << TIME_MIN_S)
56#define TIME_SEC_MASK 0x7f
57
58#define ALARM_DAY_S 20
59#define ALARM_DAY_MASK (0x3f << ALARM_DAY_S)
60
61#define ALARM_DAY_BIT (1 << 29)
62#define ALARM_HOUR_BIT (1 << 28)
63#define ALARM_MIN_BIT (1 << 27)
64#define ALARM_SEC_BIT (1 << 26)
65
66#define ALARM_ENABLE_MASK (ALARM_DAY_BIT \
67 | ALARM_HOUR_BIT \
68 | ALARM_MIN_BIT \
69 | ALARM_SEC_BIT)
70
71#define VT8500_RTC_CR_ENABLE (1 << 0) /* Enable RTC */
72#define VT8500_RTC_CR_24H (1 << 1) /* 24h time format */
73#define VT8500_RTC_CR_SM_ENABLE (1 << 2) /* Enable periodic irqs */
74#define VT8500_RTC_CR_SM_SEC (1 << 3) /* 0: 1Hz/60, 1: 1Hz */
75#define VT8500_RTC_CR_CALIB (1 << 4) /* Enable calibration */
76
77struct vt8500_rtc {
78 void __iomem *regbase;
79 struct resource *res;
80 int irq_alarm;
81 int irq_hz;
82 struct rtc_device *rtc;
83 spinlock_t lock; /* Protects this structure */
84};
85
86static irqreturn_t vt8500_rtc_irq(int irq, void *dev_id)
87{
88 struct vt8500_rtc *vt8500_rtc = dev_id;
89 u32 isr;
90 unsigned long events = 0;
91
92 spin_lock(&vt8500_rtc->lock);
93
94 /* clear interrupt sources */
95 isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS);
96 writel(isr, vt8500_rtc->regbase + VT8500_RTC_IS);
97
98 spin_unlock(&vt8500_rtc->lock);
99
100 if (isr & 1)
101 events |= RTC_AF | RTC_IRQF;
102
103 /* Only second/minute interrupts are supported */
104 if (isr & 2)
105 events |= RTC_UF | RTC_IRQF;
106
107 rtc_update_irq(vt8500_rtc->rtc, 1, events);
108
109 return IRQ_HANDLED;
110}
111
112static int vt8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
113{
114 struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
115 u32 date, time;
116
117 date = readl(vt8500_rtc->regbase + VT8500_RTC_DR);
118 time = readl(vt8500_rtc->regbase + VT8500_RTC_TR);
119
120 tm->tm_sec = bcd2bin(time & TIME_SEC_MASK);
121 tm->tm_min = bcd2bin((time & TIME_MIN_MASK) >> TIME_MIN_S);
122 tm->tm_hour = bcd2bin((time & TIME_HOUR_MASK) >> TIME_HOUR_S);
123 tm->tm_mday = bcd2bin(date & DATE_DAY_MASK);
124 tm->tm_mon = bcd2bin((date & DATE_MONTH_MASK) >> DATE_MONTH_S);
125 tm->tm_year = bcd2bin((date & DATE_YEAR_MASK) >> DATE_YEAR_S)
126 + ((date >> DATE_CENTURY_S) & 1 ? 200 : 100);
127 tm->tm_wday = (time & TIME_DOW_MASK) >> TIME_DOW_S;
128
129 return 0;
130}
131
132static int vt8500_rtc_set_time(struct device *dev, struct rtc_time *tm)
133{
134 struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
135
136 if (tm->tm_year < 100) {
137 dev_warn(dev, "Only years 2000-2199 are supported by the "
138 "hardware!\n");
139 return -EINVAL;
140 }
141
142 writel((bin2bcd(tm->tm_year - 100) << DATE_YEAR_S)
143 | (bin2bcd(tm->tm_mon) << DATE_MONTH_S)
144 | (bin2bcd(tm->tm_mday)),
145 vt8500_rtc->regbase + VT8500_RTC_DS);
146 writel((bin2bcd(tm->tm_wday) << TIME_DOW_S)
147 | (bin2bcd(tm->tm_hour) << TIME_HOUR_S)
148 | (bin2bcd(tm->tm_min) << TIME_MIN_S)
149 | (bin2bcd(tm->tm_sec)),
150 vt8500_rtc->regbase + VT8500_RTC_TS);
151
152 return 0;
153}
154
155static int vt8500_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
156{
157 struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
158 u32 isr, alarm;
159
160 alarm = readl(vt8500_rtc->regbase + VT8500_RTC_AS);
161 isr = readl(vt8500_rtc->regbase + VT8500_RTC_IS);
162
163 alrm->time.tm_mday = bcd2bin((alarm & ALARM_DAY_MASK) >> ALARM_DAY_S);
164 alrm->time.tm_hour = bcd2bin((alarm & TIME_HOUR_MASK) >> TIME_HOUR_S);
165 alrm->time.tm_min = bcd2bin((alarm & TIME_MIN_MASK) >> TIME_MIN_S);
166 alrm->time.tm_sec = bcd2bin((alarm & TIME_SEC_MASK));
167
168 alrm->enabled = (alarm & ALARM_ENABLE_MASK) ? 1 : 0;
169
170 alrm->pending = (isr & 1) ? 1 : 0;
171 return rtc_valid_tm(&alrm->time);
172}
173
174static int vt8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
175{
176 struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
177
178 writel((alrm->enabled ? ALARM_ENABLE_MASK : 0)
179 | (bin2bcd(alrm->time.tm_mday) << ALARM_DAY_S)
180 | (bin2bcd(alrm->time.tm_hour) << TIME_HOUR_S)
181 | (bin2bcd(alrm->time.tm_min) << TIME_MIN_S)
182 | (bin2bcd(alrm->time.tm_sec)),
183 vt8500_rtc->regbase + VT8500_RTC_AS);
184
185 return 0;
186}
187
188static int vt8500_alarm_irq_enable(struct device *dev, unsigned int enabled)
189{
190 struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
191 unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_AS);
192
193 if (enabled)
194 tmp |= ALARM_ENABLE_MASK;
195 else
196 tmp &= ~ALARM_ENABLE_MASK;
197
198 writel(tmp, vt8500_rtc->regbase + VT8500_RTC_AS);
199 return 0;
200}
201
202static int vt8500_update_irq_enable(struct device *dev, unsigned int enabled)
203{
204 struct vt8500_rtc *vt8500_rtc = dev_get_drvdata(dev);
205 unsigned long tmp = readl(vt8500_rtc->regbase + VT8500_RTC_CR);
206
207 if (enabled)
208 tmp |= VT8500_RTC_CR_SM_SEC | VT8500_RTC_CR_SM_ENABLE;
209 else
210 tmp &= ~VT8500_RTC_CR_SM_ENABLE;
211
212 writel(tmp, vt8500_rtc->regbase + VT8500_RTC_CR);
213 return 0;
214}
215
216static const struct rtc_class_ops vt8500_rtc_ops = {
217 .read_time = vt8500_rtc_read_time,
218 .set_time = vt8500_rtc_set_time,
219 .read_alarm = vt8500_rtc_read_alarm,
220 .set_alarm = vt8500_rtc_set_alarm,
221 .alarm_irq_enable = vt8500_alarm_irq_enable,
222 .update_irq_enable = vt8500_update_irq_enable,
223};
224
225static int __devinit vt8500_rtc_probe(struct platform_device *pdev)
226{
227 struct vt8500_rtc *vt8500_rtc;
228 int ret;
229
230 vt8500_rtc = kzalloc(sizeof(struct vt8500_rtc), GFP_KERNEL);
231 if (!vt8500_rtc)
232 return -ENOMEM;
233
234 spin_lock_init(&vt8500_rtc->lock);
235 platform_set_drvdata(pdev, vt8500_rtc);
236
237 vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
238 if (!vt8500_rtc->res) {
239 dev_err(&pdev->dev, "No I/O memory resource defined\n");
240 ret = -ENXIO;
241 goto err_free;
242 }
243
244 vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0);
245 if (vt8500_rtc->irq_alarm < 0) {
246 dev_err(&pdev->dev, "No alarm IRQ resource defined\n");
247 ret = -ENXIO;
248 goto err_free;
249 }
250
251 vt8500_rtc->irq_hz = platform_get_irq(pdev, 1);
252 if (vt8500_rtc->irq_hz < 0) {
253 dev_err(&pdev->dev, "No 1Hz IRQ resource defined\n");
254 ret = -ENXIO;
255 goto err_free;
256 }
257
258 vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start,
259 resource_size(vt8500_rtc->res),
260 "vt8500-rtc");
261 if (vt8500_rtc->res == NULL) {
262 dev_err(&pdev->dev, "failed to request I/O memory\n");
263 ret = -EBUSY;
264 goto err_free;
265 }
266
267 vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start,
268 resource_size(vt8500_rtc->res));
269 if (!vt8500_rtc->regbase) {
270 dev_err(&pdev->dev, "Unable to map RTC I/O memory\n");
271 ret = -EBUSY;
272 goto err_release;
273 }
274
275 /* Enable the second/minute interrupt generation and enable RTC */
276 writel(VT8500_RTC_CR_ENABLE | VT8500_RTC_CR_24H
277 | VT8500_RTC_CR_SM_ENABLE | VT8500_RTC_CR_SM_SEC,
278 vt8500_rtc->regbase + VT8500_RTC_CR);
279
280 vt8500_rtc->rtc = rtc_device_register("vt8500-rtc", &pdev->dev,
281 &vt8500_rtc_ops, THIS_MODULE);
282 if (IS_ERR(vt8500_rtc->rtc)) {
283 ret = PTR_ERR(vt8500_rtc->rtc);
284 dev_err(&pdev->dev,
285 "Failed to register RTC device -> %d\n", ret);
286 goto err_unmap;
287 }
288
289 ret = request_irq(vt8500_rtc->irq_hz, vt8500_rtc_irq, 0,
290 "rtc 1Hz", vt8500_rtc);
291 if (ret < 0) {
292 dev_err(&pdev->dev, "can't get irq %i, err %d\n",
293 vt8500_rtc->irq_hz, ret);
294 goto err_unreg;
295 }
296
297 ret = request_irq(vt8500_rtc->irq_alarm, vt8500_rtc_irq, 0,
298 "rtc alarm", vt8500_rtc);
299 if (ret < 0) {
300 dev_err(&pdev->dev, "can't get irq %i, err %d\n",
301 vt8500_rtc->irq_alarm, ret);
302 goto err_free_hz;
303 }
304
305 return 0;
306
307err_free_hz:
308 free_irq(vt8500_rtc->irq_hz, vt8500_rtc);
309err_unreg:
310 rtc_device_unregister(vt8500_rtc->rtc);
311err_unmap:
312 iounmap(vt8500_rtc->regbase);
313err_release:
314 release_mem_region(vt8500_rtc->res->start,
315 resource_size(vt8500_rtc->res));
316err_free:
317 kfree(vt8500_rtc);
318 return ret;
319}
320
321static int __devexit vt8500_rtc_remove(struct platform_device *pdev)
322{
323 struct vt8500_rtc *vt8500_rtc = platform_get_drvdata(pdev);
324
325 free_irq(vt8500_rtc->irq_alarm, vt8500_rtc);
326 free_irq(vt8500_rtc->irq_hz, vt8500_rtc);
327
328 rtc_device_unregister(vt8500_rtc->rtc);
329
330 /* Disable alarm matching */
331 writel(0, vt8500_rtc->regbase + VT8500_RTC_IS);
332 iounmap(vt8500_rtc->regbase);
333 release_mem_region(vt8500_rtc->res->start,
334 resource_size(vt8500_rtc->res));
335
336 kfree(vt8500_rtc);
337 platform_set_drvdata(pdev, NULL);
338
339 return 0;
340}
341
342static struct platform_driver vt8500_rtc_driver = {
343 .probe = vt8500_rtc_probe,
344 .remove = __devexit_p(vt8500_rtc_remove),
345 .driver = {
346 .name = "vt8500-rtc",
347 .owner = THIS_MODULE,
348 },
349};
350
351static int __init vt8500_rtc_init(void)
352{
353 return platform_driver_register(&vt8500_rtc_driver);
354}
355module_init(vt8500_rtc_init);
356
357static void __exit vt8500_rtc_exit(void)
358{
359 platform_driver_unregister(&vt8500_rtc_driver);
360}
361module_exit(vt8500_rtc_exit);
362
363MODULE_AUTHOR("Alexey Charkov <alchark@gmail.com>");
364MODULE_DESCRIPTION("VIA VT8500 SoC Realtime Clock Driver (RTC)");
365MODULE_LICENSE("GPL");
366MODULE_ALIAS("platform:vt8500-rtc");