aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig12
-rw-r--r--drivers/rtc/interface.c23
-rw-r--r--drivers/rtc/rtc-at91sam9.c2
-rw-r--r--drivers/rtc/rtc-dev.c104
-rw-r--r--drivers/rtc/rtc-ds3232.c14
-rw-r--r--drivers/rtc/rtc-s3c.c12
6 files changed, 152 insertions, 15 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index cdd97192dc69..4941cade319f 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -97,6 +97,18 @@ config RTC_INTF_DEV
97 97
98 If unsure, say Y. 98 If unsure, say Y.
99 99
100config RTC_INTF_DEV_UIE_EMUL
101 bool "RTC UIE emulation on dev interface"
102 depends on RTC_INTF_DEV
103 help
104 Provides an emulation for RTC_UIE if the underlying rtc chip
105 driver does not expose RTC_UIE ioctls. Those requests generate
106 once-per-second update interrupts, used for synchronization.
107
108 The emulation code will read the time from the hardware
109 clock several times per second, please enable this option
110 only if you know that you really need it.
111
100config RTC_DRV_TEST 112config RTC_DRV_TEST
101 tristate "Test driver/device" 113 tristate "Test driver/device"
102 help 114 help
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index a0c01967244d..cb2f0728fd70 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -209,9 +209,8 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
209 } 209 }
210 210
211 if (err) 211 if (err)
212 return err; 212 /* nothing */;
213 213 else if (!rtc->ops)
214 if (!rtc->ops)
215 err = -ENODEV; 214 err = -ENODEV;
216 else if (!rtc->ops->alarm_irq_enable) 215 else if (!rtc->ops->alarm_irq_enable)
217 err = -EINVAL; 216 err = -EINVAL;
@@ -229,6 +228,12 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
229 if (err) 228 if (err)
230 return err; 229 return err;
231 230
231#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
232 if (enabled == 0 && rtc->uie_irq_active) {
233 mutex_unlock(&rtc->ops_lock);
234 return rtc_dev_update_irq_enable_emul(rtc, 0);
235 }
236#endif
232 /* make sure we're changing state */ 237 /* make sure we're changing state */
233 if (rtc->uie_rtctimer.enabled == enabled) 238 if (rtc->uie_rtctimer.enabled == enabled)
234 goto out; 239 goto out;
@@ -248,6 +253,16 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
248 253
249out: 254out:
250 mutex_unlock(&rtc->ops_lock); 255 mutex_unlock(&rtc->ops_lock);
256#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
257 /*
258 * Enable emulation if the driver did not provide
259 * the update_irq_enable function pointer or if returned
260 * -EINVAL to signal that it has been configured without
261 * interrupts or that are not available at the moment.
262 */
263 if (err == -EINVAL)
264 err = rtc_dev_update_irq_enable_emul(rtc, enabled);
265#endif
251 return err; 266 return err;
252 267
253} 268}
@@ -263,7 +278,7 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
263 * 278 *
264 * Triggers the registered irq_task function callback. 279 * Triggers the registered irq_task function callback.
265 */ 280 */
266static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) 281void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
267{ 282{
268 unsigned long flags; 283 unsigned long flags;
269 284
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index c36749e4c926..5469c52cba3d 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -309,7 +309,7 @@ static const struct rtc_class_ops at91_rtc_ops = {
309 .read_alarm = at91_rtc_readalarm, 309 .read_alarm = at91_rtc_readalarm,
310 .set_alarm = at91_rtc_setalarm, 310 .set_alarm = at91_rtc_setalarm,
311 .proc = at91_rtc_proc, 311 .proc = at91_rtc_proc,
312 .alarm_irq_enabled = at91_rtc_alarm_irq_enable, 312 .alarm_irq_enable = at91_rtc_alarm_irq_enable,
313}; 313};
314 314
315/* 315/*
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 37c3cc1b3dd5..d0e06edb14c5 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -46,6 +46,105 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
46 return err; 46 return err;
47} 47}
48 48
49#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
50/*
51 * Routine to poll RTC seconds field for change as often as possible,
52 * after first RTC_UIE use timer to reduce polling
53 */
54static void rtc_uie_task(struct work_struct *work)
55{
56 struct rtc_device *rtc =
57 container_of(work, struct rtc_device, uie_task);
58 struct rtc_time tm;
59 int num = 0;
60 int err;
61
62 err = rtc_read_time(rtc, &tm);
63
64 spin_lock_irq(&rtc->irq_lock);
65 if (rtc->stop_uie_polling || err) {
66 rtc->uie_task_active = 0;
67 } else if (rtc->oldsecs != tm.tm_sec) {
68 num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
69 rtc->oldsecs = tm.tm_sec;
70 rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
71 rtc->uie_timer_active = 1;
72 rtc->uie_task_active = 0;
73 add_timer(&rtc->uie_timer);
74 } else if (schedule_work(&rtc->uie_task) == 0) {
75 rtc->uie_task_active = 0;
76 }
77 spin_unlock_irq(&rtc->irq_lock);
78 if (num)
79 rtc_handle_legacy_irq(rtc, num, RTC_UF);
80}
81static void rtc_uie_timer(unsigned long data)
82{
83 struct rtc_device *rtc = (struct rtc_device *)data;
84 unsigned long flags;
85
86 spin_lock_irqsave(&rtc->irq_lock, flags);
87 rtc->uie_timer_active = 0;
88 rtc->uie_task_active = 1;
89 if ((schedule_work(&rtc->uie_task) == 0))
90 rtc->uie_task_active = 0;
91 spin_unlock_irqrestore(&rtc->irq_lock, flags);
92}
93
94static int clear_uie(struct rtc_device *rtc)
95{
96 spin_lock_irq(&rtc->irq_lock);
97 if (rtc->uie_irq_active) {
98 rtc->stop_uie_polling = 1;
99 if (rtc->uie_timer_active) {
100 spin_unlock_irq(&rtc->irq_lock);
101 del_timer_sync(&rtc->uie_timer);
102 spin_lock_irq(&rtc->irq_lock);
103 rtc->uie_timer_active = 0;
104 }
105 if (rtc->uie_task_active) {
106 spin_unlock_irq(&rtc->irq_lock);
107 flush_scheduled_work();
108 spin_lock_irq(&rtc->irq_lock);
109 }
110 rtc->uie_irq_active = 0;
111 }
112 spin_unlock_irq(&rtc->irq_lock);
113 return 0;
114}
115
116static int set_uie(struct rtc_device *rtc)
117{
118 struct rtc_time tm;
119 int err;
120
121 err = rtc_read_time(rtc, &tm);
122 if (err)
123 return err;
124 spin_lock_irq(&rtc->irq_lock);
125 if (!rtc->uie_irq_active) {
126 rtc->uie_irq_active = 1;
127 rtc->stop_uie_polling = 0;
128 rtc->oldsecs = tm.tm_sec;
129 rtc->uie_task_active = 1;
130 if (schedule_work(&rtc->uie_task) == 0)
131 rtc->uie_task_active = 0;
132 }
133 rtc->irq_data = 0;
134 spin_unlock_irq(&rtc->irq_lock);
135 return 0;
136}
137
138int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled)
139{
140 if (enabled)
141 return set_uie(rtc);
142 else
143 return clear_uie(rtc);
144}
145EXPORT_SYMBOL(rtc_dev_update_irq_enable_emul);
146
147#endif /* CONFIG_RTC_INTF_DEV_UIE_EMUL */
49 148
50static ssize_t 149static ssize_t
51rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) 150rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
@@ -387,6 +486,11 @@ void rtc_dev_prepare(struct rtc_device *rtc)
387 486
388 rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id); 487 rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
389 488
489#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
490 INIT_WORK(&rtc->uie_task, rtc_uie_task);
491 setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
492#endif
493
390 cdev_init(&rtc->char_dev, &rtc_dev_fops); 494 cdev_init(&rtc->char_dev, &rtc_dev_fops);
391 rtc->char_dev.owner = rtc->owner; 495 rtc->char_dev.owner = rtc->owner;
392} 496}
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index 23a9ee19764c..950735415a7c 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C 2 * RTC client/driver for the Maxim/Dallas DS3232 Real-Time Clock over I2C
3 * 3 *
4 * Copyright (C) 2009-2010 Freescale Semiconductor. 4 * Copyright (C) 2009-2011 Freescale Semiconductor.
5 * Author: Jack Lan <jack.lan@freescale.com> 5 * Author: Jack Lan <jack.lan@freescale.com>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify it 7 * This program is free software; you can redistribute it and/or modify it
@@ -141,9 +141,11 @@ static int ds3232_read_time(struct device *dev, struct rtc_time *time)
141 time->tm_hour = bcd2bin(hour); 141 time->tm_hour = bcd2bin(hour);
142 } 142 }
143 143
144 time->tm_wday = bcd2bin(week); 144 /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
145 time->tm_wday = bcd2bin(week) - 1;
145 time->tm_mday = bcd2bin(day); 146 time->tm_mday = bcd2bin(day);
146 time->tm_mon = bcd2bin(month & 0x7F); 147 /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
148 time->tm_mon = bcd2bin(month & 0x7F) - 1;
147 if (century) 149 if (century)
148 add_century = 100; 150 add_century = 100;
149 151
@@ -162,9 +164,11 @@ static int ds3232_set_time(struct device *dev, struct rtc_time *time)
162 buf[0] = bin2bcd(time->tm_sec); 164 buf[0] = bin2bcd(time->tm_sec);
163 buf[1] = bin2bcd(time->tm_min); 165 buf[1] = bin2bcd(time->tm_min);
164 buf[2] = bin2bcd(time->tm_hour); 166 buf[2] = bin2bcd(time->tm_hour);
165 buf[3] = bin2bcd(time->tm_wday); /* Day of the week */ 167 /* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
168 buf[3] = bin2bcd(time->tm_wday + 1);
166 buf[4] = bin2bcd(time->tm_mday); /* Date */ 169 buf[4] = bin2bcd(time->tm_mday); /* Date */
167 buf[5] = bin2bcd(time->tm_mon); 170 /* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
171 buf[5] = bin2bcd(time->tm_mon + 1);
168 if (time->tm_year >= 100) { 172 if (time->tm_year >= 100) {
169 buf[5] |= 0x80; 173 buf[5] |= 0x80;
170 buf[6] = bin2bcd(time->tm_year - 100); 174 buf[6] = bin2bcd(time->tm_year - 100);
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index cf953ecbfca9..b80fa2882408 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -77,18 +77,20 @@ static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
77} 77}
78 78
79/* Update control registers */ 79/* Update control registers */
80static void s3c_rtc_setaie(int to) 80static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
81{ 81{
82 unsigned int tmp; 82 unsigned int tmp;
83 83
84 pr_debug("%s: aie=%d\n", __func__, to); 84 pr_debug("%s: aie=%d\n", __func__, enabled);
85 85
86 tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN; 86 tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
87 87
88 if (to) 88 if (enabled)
89 tmp |= S3C2410_RTCALM_ALMEN; 89 tmp |= S3C2410_RTCALM_ALMEN;
90 90
91 writeb(tmp, s3c_rtc_base + S3C2410_RTCALM); 91 writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
92
93 return 0;
92} 94}
93 95
94static int s3c_rtc_setpie(struct device *dev, int enabled) 96static int s3c_rtc_setpie(struct device *dev, int enabled)
@@ -308,7 +310,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
308 310
309 writeb(alrm_en, base + S3C2410_RTCALM); 311 writeb(alrm_en, base + S3C2410_RTCALM);
310 312
311 s3c_rtc_setaie(alrm->enabled); 313 s3c_rtc_setaie(dev, alrm->enabled);
312 314
313 return 0; 315 return 0;
314} 316}
@@ -440,7 +442,7 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)
440 rtc_device_unregister(rtc); 442 rtc_device_unregister(rtc);
441 443
442 s3c_rtc_setpie(&dev->dev, 0); 444 s3c_rtc_setpie(&dev->dev, 0);
443 s3c_rtc_setaie(0); 445 s3c_rtc_setaie(&dev->dev, 0);
444 446
445 clk_disable(rtc_clk); 447 clk_disable(rtc_clk);
446 clk_put(rtc_clk); 448 clk_put(rtc_clk);