aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/rtc.h
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2010-09-23 18:07:34 -0400
committerJohn Stultz <john.stultz@linaro.org>2010-12-11 01:24:24 -0500
commit6610e0893b8bc6f59b14fed7f089c5997f035f88 (patch)
treeb13f4f516fe8fd31a6f6fbb68dd0c520c4c19df7 /include/linux/rtc.h
parentb007c389d3e09b823eccda1503390fa2a9adca0d (diff)
RTC: Rework RTC code to use timerqueue for events
This patch reworks a large portion of the generic RTC code to in-effect virtualize the rtc interrupt code. The current RTC interface is very much a raw hardware interface. Via the proc, /dev/, or sysfs interfaces, applciations can set the hardware to trigger interrupts in one of three modes: AIE: Alarm interrupt UIE: Update interrupt (ie: once per second) PIE: Periodic interrupt (sub-second irqs) The problem with this interface is that it limits the RTC hardware so it can only be used by one application at a time. The purpose of this patch is to extend the RTC code so that we can multiplex multiple applications event needs onto a single RTC device. This is done by utilizing the timerqueue infrastructure to manage a list of events, which cause the RTC hardware to be programmed to fire an interrupt for the next event in the list. In order to preserve the functionality of the exsting proc,/dev/ and sysfs interfaces, we emulate the different interrupt modes as follows: AIE: We create a rtc_timer dedicated to AIE mode interrupts. There is only one per device, so we don't change existing interface semantics. UIE: Again, a dedicated rtc_timer, set for periodic mode, is used to emulate UIE interrupts. Again, only one per device. PIE: Since PIE mode interrupts fire faster then the RTC's clock read granularity, we emulate PIE mode interrupts using a hrtimer. Again, one per device. With this patch, the rtctest.c application in Documentation/rtc.txt passes fine on x86 hardware. However, there may very well still be bugs, so greatly I'd appreciate any feedback or testing! Signed-off-by: John Stultz <john.stultz@linaro.org> LKML Reference: <1290136329-18291-4-git-send-email-john.stultz@linaro.org> Acked-by: Alessandro Zummo <a.zummo@towertech.it> Reviewed-by: Thomas Gleixner <tglx@linutronix.de> CC: Alessandro Zummo <a.zummo@towertech.it> CC: Thomas Gleixner <tglx@linutronix.de> CC: Richard Cochran <richardcochran@gmail.com>
Diffstat (limited to 'include/linux/rtc.h')
-rw-r--r--include/linux/rtc.h43
1 files changed, 38 insertions, 5 deletions
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 14dbc83ded20..a3421abca703 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -107,12 +107,17 @@ extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year
107extern int rtc_valid_tm(struct rtc_time *tm); 107extern int rtc_valid_tm(struct rtc_time *tm);
108extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); 108extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
109extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm); 109extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
110ktime_t rtc_tm_to_ktime(struct rtc_time tm);
111struct rtc_time rtc_ktime_to_tm(ktime_t kt);
112
110 113
111#include <linux/device.h> 114#include <linux/device.h>
112#include <linux/seq_file.h> 115#include <linux/seq_file.h>
113#include <linux/cdev.h> 116#include <linux/cdev.h>
114#include <linux/poll.h> 117#include <linux/poll.h>
115#include <linux/mutex.h> 118#include <linux/mutex.h>
119#include <linux/timerqueue.h>
120#include <linux/workqueue.h>
116 121
117extern struct class *rtc_class; 122extern struct class *rtc_class;
118 123
@@ -151,7 +156,19 @@ struct rtc_class_ops {
151}; 156};
152 157
153#define RTC_DEVICE_NAME_SIZE 20 158#define RTC_DEVICE_NAME_SIZE 20
154struct rtc_task; 159typedef struct rtc_task {
160 void (*func)(void *private_data);
161 void *private_data;
162} rtc_task_t;
163
164
165struct rtc_timer {
166 struct rtc_task task;
167 struct timerqueue_node node;
168 ktime_t period;
169 int enabled;
170};
171
155 172
156/* flags */ 173/* flags */
157#define RTC_DEV_BUSY 0 174#define RTC_DEV_BUSY 0
@@ -179,6 +196,15 @@ struct rtc_device
179 spinlock_t irq_task_lock; 196 spinlock_t irq_task_lock;
180 int irq_freq; 197 int irq_freq;
181 int max_user_freq; 198 int max_user_freq;
199
200 struct timerqueue_head timerqueue;
201 struct rtc_timer aie_timer;
202 struct rtc_timer uie_rtctimer;
203 struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */
204 int pie_enabled;
205 struct work_struct irqwork;
206
207
182#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL 208#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
183 struct work_struct uie_task; 209 struct work_struct uie_task;
184 struct timer_list uie_timer; 210 struct timer_list uie_timer;
@@ -224,15 +250,22 @@ extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled);
224extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, 250extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc,
225 unsigned int enabled); 251 unsigned int enabled);
226 252
227typedef struct rtc_task { 253void rtc_aie_update_irq(void *private);
228 void (*func)(void *private_data); 254void rtc_uie_update_irq(void *private);
229 void *private_data; 255enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer);
230} rtc_task_t;
231 256
232int rtc_register(rtc_task_t *task); 257int rtc_register(rtc_task_t *task);
233int rtc_unregister(rtc_task_t *task); 258int rtc_unregister(rtc_task_t *task);
234int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); 259int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
235 260
261void rtctimer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
262void rtctimer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
263void rtctimer_init(struct rtc_timer *timer, void (*f)(void* p), void* data);
264int rtctimer_start(struct rtc_device *rtc, struct rtc_timer* timer,
265 ktime_t expires, ktime_t period);
266int rtctimer_cancel(struct rtc_device *rtc, struct rtc_timer* timer);
267void rtctimer_do_work(struct work_struct *work);
268
236static inline bool is_leap_year(unsigned int year) 269static inline bool is_leap_year(unsigned int year)
237{ 270{
238 return (!(year % 4) && (year % 100)) || !(year % 400); 271 return (!(year % 4) && (year % 100)) || !(year % 400);