2 * drivers/rtc/rtc-pl031.c
4 * Real Time Clock interface for ARM AMBA PrimeCell 031 RTC
6 * Author: Deepak Saxena <dsaxena@plexity.net>
8 * Copyright 2006 (c) MontaVista Software, Inc.
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
16 #include <linux/platform_device.h>
17 #include <linux/module.h>
18 #include <linux/rtc.h>
19 #include <linux/init.h>
21 #include <linux/interrupt.h>
22 #include <linux/string.h>
25 #include <linux/amba/bus.h>
28 #include <asm/bitops.h>
29 #include <asm/hardware.h>
34 * Register definitions
36 #define RTC_DR 0x00 /* Data read register */
37 #define RTC_MR 0x04 /* Match register */
38 #define RTC_LR 0x08 /* Data load register */
39 #define RTC_CR 0x0c /* Control register */
40 #define RTC_IMSC 0x10 /* Interrupt mask and set register */
41 #define RTC_RIS 0x14 /* Raw interrupt status register */
42 #define RTC_MIS 0x18 /* Masked interrupt status register */
43 #define RTC_ICR 0x1c /* Interrupt clear register */
46 struct rtc_device
*rtc
;
50 static irqreturn_t
pl031_interrupt(int irq
, void *dev_id
)
52 struct rtc_device
*rtc
= dev_id
;
54 rtc_update_irq(rtc
, 1, RTC_AF
);
59 static int pl031_open(struct device
*dev
)
62 * We request IRQ in pl031_probe, so nothing to do here...
67 static void pl031_release(struct device
*dev
)
71 static int pl031_ioctl(struct device
*dev
, unsigned int cmd
, unsigned long arg
)
73 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
77 __raw_writel(1, ldata
->base
+ RTC_MIS
);
80 __raw_writel(0, ldata
->base
+ RTC_MIS
);
87 static int pl031_read_time(struct device
*dev
, struct rtc_time
*tm
)
89 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
91 rtc_time_to_tm(__raw_readl(ldata
->base
+ RTC_DR
), tm
);
96 static int pl031_set_time(struct device
*dev
, struct rtc_time
*tm
)
99 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
101 rtc_tm_to_time(tm
, &time
);
102 __raw_writel(time
, ldata
->base
+ RTC_LR
);
107 static int pl031_read_alarm(struct device
*dev
, struct rtc_wkalrm
*alarm
)
109 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
111 rtc_time_to_tm(__raw_readl(ldata
->base
+ RTC_MR
), &alarm
->time
);
112 alarm
->pending
= __raw_readl(ldata
->base
+ RTC_RIS
);
113 alarm
->enabled
= __raw_readl(ldata
->base
+ RTC_IMSC
);
118 static int pl031_set_alarm(struct device
*dev
, struct rtc_wkalrm
*alarm
)
120 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
123 rtc_tm_to_time(&alarm
->time
, &time
);
125 __raw_writel(time
, ldata
->base
+ RTC_MR
);
126 __raw_writel(!alarm
->enabled
, ldata
->base
+ RTC_MIS
);
131 static const struct rtc_class_ops pl031_ops
= {
133 .release
= pl031_release
,
134 .ioctl
= pl031_ioctl
,
135 .read_time
= pl031_read_time
,
136 .set_time
= pl031_set_time
,
137 .read_alarm
= pl031_read_alarm
,
138 .set_alarm
= pl031_set_alarm
,
141 static int pl031_remove(struct amba_device
*adev
)
143 struct pl031_local
*ldata
= dev_get_drvdata(&adev
->dev
);
146 dev_set_drvdata(&adev
->dev
, NULL
);
147 free_irq(adev
->irq
[0], ldata
->rtc
);
148 rtc_device_unregister(ldata
->rtc
);
149 iounmap(ldata
->base
);
156 static int pl031_probe(struct amba_device
*adev
, void *id
)
159 struct pl031_local
*ldata
;
162 ldata
= kmalloc(sizeof(struct pl031_local
), GFP_KERNEL
);
167 dev_set_drvdata(&adev
->dev
, ldata
);
169 ldata
->base
= ioremap(adev
->res
.start
,
170 adev
->res
.end
- adev
->res
.start
+ 1);
176 if (request_irq(adev
->irq
[0], pl031_interrupt
, IRQF_DISABLED
,
177 "rtc-pl031", ldata
->rtc
)) {
182 ldata
->rtc
= rtc_device_register("pl031", &adev
->dev
, &pl031_ops
,
184 if (IS_ERR(ldata
->rtc
)) {
185 ret
= PTR_ERR(ldata
->rtc
);
192 free_irq(adev
->irq
[0], ldata
->rtc
);
194 iounmap(ldata
->base
);
196 dev_set_drvdata(&adev
->dev
, NULL
);
202 static struct amba_id pl031_ids
[] __initdata
= {
205 .mask
= 0x000fffff, },
209 static struct amba_driver pl031_driver
= {
213 .id_table
= pl031_ids
,
214 .probe
= pl031_probe
,
215 .remove
= pl031_remove
,
218 static int __init
pl031_init(void)
220 return amba_driver_register(&pl031_driver
);
223 static void __exit
pl031_exit(void)
225 amba_driver_unregister(&pl031_driver
);
228 module_init(pl031_init
);
229 module_exit(pl031_exit
);
231 MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
232 MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
233 MODULE_LICENSE("GPL");