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.
15 #include <linux/module.h>
16 #include <linux/rtc.h>
17 #include <linux/init.h>
18 #include <linux/interrupt.h>
19 #include <linux/amba/bus.h>
23 * Register definitions
25 #define RTC_DR 0x00 /* Data read register */
26 #define RTC_MR 0x04 /* Match register */
27 #define RTC_LR 0x08 /* Data load register */
28 #define RTC_CR 0x0c /* Control register */
29 #define RTC_IMSC 0x10 /* Interrupt mask and set register */
30 #define RTC_RIS 0x14 /* Raw interrupt status register */
31 #define RTC_MIS 0x18 /* Masked interrupt status register */
32 #define RTC_ICR 0x1c /* Interrupt clear register */
35 struct rtc_device
*rtc
;
39 static irqreturn_t
pl031_interrupt(int irq
, void *dev_id
)
41 struct rtc_device
*rtc
= dev_id
;
43 rtc_update_irq(rtc
, 1, RTC_AF
);
48 static int pl031_ioctl(struct device
*dev
, unsigned int cmd
, unsigned long arg
)
50 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
54 __raw_writel(1, ldata
->base
+ RTC_MIS
);
57 __raw_writel(0, ldata
->base
+ RTC_MIS
);
64 static int pl031_read_time(struct device
*dev
, struct rtc_time
*tm
)
66 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
68 rtc_time_to_tm(__raw_readl(ldata
->base
+ RTC_DR
), tm
);
73 static int pl031_set_time(struct device
*dev
, struct rtc_time
*tm
)
76 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
78 rtc_tm_to_time(tm
, &time
);
79 __raw_writel(time
, ldata
->base
+ RTC_LR
);
84 static int pl031_read_alarm(struct device
*dev
, struct rtc_wkalrm
*alarm
)
86 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
88 rtc_time_to_tm(__raw_readl(ldata
->base
+ RTC_MR
), &alarm
->time
);
89 alarm
->pending
= __raw_readl(ldata
->base
+ RTC_RIS
);
90 alarm
->enabled
= __raw_readl(ldata
->base
+ RTC_IMSC
);
95 static int pl031_set_alarm(struct device
*dev
, struct rtc_wkalrm
*alarm
)
97 struct pl031_local
*ldata
= dev_get_drvdata(dev
);
100 rtc_tm_to_time(&alarm
->time
, &time
);
102 __raw_writel(time
, ldata
->base
+ RTC_MR
);
103 __raw_writel(!alarm
->enabled
, ldata
->base
+ RTC_MIS
);
108 static const struct rtc_class_ops pl031_ops
= {
109 .ioctl
= pl031_ioctl
,
110 .read_time
= pl031_read_time
,
111 .set_time
= pl031_set_time
,
112 .read_alarm
= pl031_read_alarm
,
113 .set_alarm
= pl031_set_alarm
,
116 static int pl031_remove(struct amba_device
*adev
)
118 struct pl031_local
*ldata
= dev_get_drvdata(&adev
->dev
);
120 amba_set_drvdata(adev
, NULL
);
121 free_irq(adev
->irq
[0], ldata
->rtc
);
122 rtc_device_unregister(ldata
->rtc
);
123 iounmap(ldata
->base
);
125 amba_release_regions(adev
);
130 static int pl031_probe(struct amba_device
*adev
, struct amba_id
*id
)
133 struct pl031_local
*ldata
;
135 ret
= amba_request_regions(adev
, NULL
);
139 ldata
= kmalloc(sizeof(struct pl031_local
), GFP_KERNEL
);
145 ldata
->base
= ioremap(adev
->res
.start
,
146 adev
->res
.end
- adev
->res
.start
+ 1);
152 amba_set_drvdata(adev
, ldata
);
154 if (request_irq(adev
->irq
[0], pl031_interrupt
, IRQF_DISABLED
,
155 "rtc-pl031", ldata
->rtc
)) {
160 ldata
->rtc
= rtc_device_register("pl031", &adev
->dev
, &pl031_ops
,
162 if (IS_ERR(ldata
->rtc
)) {
163 ret
= PTR_ERR(ldata
->rtc
);
170 free_irq(adev
->irq
[0], ldata
->rtc
);
172 iounmap(ldata
->base
);
173 amba_set_drvdata(adev
, NULL
);
177 amba_release_regions(adev
);
182 static struct amba_id pl031_ids
[] __initdata
= {
185 .mask
= 0x000fffff, },
189 static struct amba_driver pl031_driver
= {
193 .id_table
= pl031_ids
,
194 .probe
= pl031_probe
,
195 .remove
= pl031_remove
,
198 static int __init
pl031_init(void)
200 return amba_driver_register(&pl031_driver
);
203 static void __exit
pl031_exit(void)
205 amba_driver_unregister(&pl031_driver
);
208 module_init(pl031_init
);
209 module_exit(pl031_exit
);
211 MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net");
212 MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver");
213 MODULE_LICENSE("GPL");