diff options
Diffstat (limited to 'drivers/rtc/class.c')
-rw-r--r-- | drivers/rtc/class.c | 48 |
1 files changed, 33 insertions, 15 deletions
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 565562ba6ac9..4194e59e14cd 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/kdev_t.h> | 16 | #include <linux/kdev_t.h> |
17 | #include <linux/idr.h> | 17 | #include <linux/idr.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/workqueue.h> | ||
19 | 20 | ||
20 | #include "rtc-core.h" | 21 | #include "rtc-core.h" |
21 | 22 | ||
@@ -40,26 +41,21 @@ static void rtc_device_release(struct device *dev) | |||
40 | * system's wall clock; restore it on resume(). | 41 | * system's wall clock; restore it on resume(). |
41 | */ | 42 | */ |
42 | 43 | ||
43 | static struct timespec delta; | ||
44 | static time_t oldtime; | 44 | static time_t oldtime; |
45 | static struct timespec oldts; | ||
45 | 46 | ||
46 | static int rtc_suspend(struct device *dev, pm_message_t mesg) | 47 | static int rtc_suspend(struct device *dev, pm_message_t mesg) |
47 | { | 48 | { |
48 | struct rtc_device *rtc = to_rtc_device(dev); | 49 | struct rtc_device *rtc = to_rtc_device(dev); |
49 | struct rtc_time tm; | 50 | struct rtc_time tm; |
50 | struct timespec ts = current_kernel_time(); | ||
51 | 51 | ||
52 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) | 52 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) |
53 | return 0; | 53 | return 0; |
54 | 54 | ||
55 | rtc_read_time(rtc, &tm); | 55 | rtc_read_time(rtc, &tm); |
56 | ktime_get_ts(&oldts); | ||
56 | rtc_tm_to_time(&tm, &oldtime); | 57 | rtc_tm_to_time(&tm, &oldtime); |
57 | 58 | ||
58 | /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */ | ||
59 | set_normalized_timespec(&delta, | ||
60 | ts.tv_sec - oldtime, | ||
61 | ts.tv_nsec - (NSEC_PER_SEC >> 1)); | ||
62 | |||
63 | return 0; | 59 | return 0; |
64 | } | 60 | } |
65 | 61 | ||
@@ -69,10 +65,12 @@ static int rtc_resume(struct device *dev) | |||
69 | struct rtc_time tm; | 65 | struct rtc_time tm; |
70 | time_t newtime; | 66 | time_t newtime; |
71 | struct timespec time; | 67 | struct timespec time; |
68 | struct timespec newts; | ||
72 | 69 | ||
73 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) | 70 | if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0) |
74 | return 0; | 71 | return 0; |
75 | 72 | ||
73 | ktime_get_ts(&newts); | ||
76 | rtc_read_time(rtc, &tm); | 74 | rtc_read_time(rtc, &tm); |
77 | if (rtc_valid_tm(&tm) != 0) { | 75 | if (rtc_valid_tm(&tm) != 0) { |
78 | pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); | 76 | pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); |
@@ -84,15 +82,13 @@ static int rtc_resume(struct device *dev) | |||
84 | pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); | 82 | pr_debug("%s: time travel!\n", dev_name(&rtc->dev)); |
85 | return 0; | 83 | return 0; |
86 | } | 84 | } |
85 | /* calculate the RTC time delta */ | ||
86 | set_normalized_timespec(&time, newtime - oldtime, 0); | ||
87 | 87 | ||
88 | /* restore wall clock using delta against this RTC; | 88 | /* subtract kernel time between rtc_suspend to rtc_resume */ |
89 | * adjust again for avg 1/2 second RTC sampling error | 89 | time = timespec_sub(time, timespec_sub(newts, oldts)); |
90 | */ | ||
91 | set_normalized_timespec(&time, | ||
92 | newtime + delta.tv_sec, | ||
93 | (NSEC_PER_SEC >> 1) + delta.tv_nsec); | ||
94 | do_settimeofday(&time); | ||
95 | 90 | ||
91 | timekeeping_inject_sleeptime(&time); | ||
96 | return 0; | 92 | return 0; |
97 | } | 93 | } |
98 | 94 | ||
@@ -116,6 +112,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, | |||
116 | struct module *owner) | 112 | struct module *owner) |
117 | { | 113 | { |
118 | struct rtc_device *rtc; | 114 | struct rtc_device *rtc; |
115 | struct rtc_wkalrm alrm; | ||
119 | int id, err; | 116 | int id, err; |
120 | 117 | ||
121 | if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) { | 118 | if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) { |
@@ -142,6 +139,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, | |||
142 | rtc->id = id; | 139 | rtc->id = id; |
143 | rtc->ops = ops; | 140 | rtc->ops = ops; |
144 | rtc->owner = owner; | 141 | rtc->owner = owner; |
142 | rtc->irq_freq = 1; | ||
145 | rtc->max_user_freq = 64; | 143 | rtc->max_user_freq = 64; |
146 | rtc->dev.parent = dev; | 144 | rtc->dev.parent = dev; |
147 | rtc->dev.class = rtc_class; | 145 | rtc->dev.class = rtc_class; |
@@ -152,14 +150,34 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, | |||
152 | spin_lock_init(&rtc->irq_task_lock); | 150 | spin_lock_init(&rtc->irq_task_lock); |
153 | init_waitqueue_head(&rtc->irq_queue); | 151 | init_waitqueue_head(&rtc->irq_queue); |
154 | 152 | ||
153 | /* Init timerqueue */ | ||
154 | timerqueue_init_head(&rtc->timerqueue); | ||
155 | INIT_WORK(&rtc->irqwork, rtc_timer_do_work); | ||
156 | /* Init aie timer */ | ||
157 | rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc); | ||
158 | /* Init uie timer */ | ||
159 | rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc); | ||
160 | /* Init pie timer */ | ||
161 | hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
162 | rtc->pie_timer.function = rtc_pie_update_irq; | ||
163 | rtc->pie_enabled = 0; | ||
164 | |||
165 | /* Check to see if there is an ALARM already set in hw */ | ||
166 | err = __rtc_read_alarm(rtc, &alrm); | ||
167 | |||
168 | if (!err && !rtc_valid_tm(&alrm.time)) | ||
169 | rtc_initialize_alarm(rtc, &alrm); | ||
170 | |||
155 | strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); | 171 | strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); |
156 | dev_set_name(&rtc->dev, "rtc%d", id); | 172 | dev_set_name(&rtc->dev, "rtc%d", id); |
157 | 173 | ||
158 | rtc_dev_prepare(rtc); | 174 | rtc_dev_prepare(rtc); |
159 | 175 | ||
160 | err = device_register(&rtc->dev); | 176 | err = device_register(&rtc->dev); |
161 | if (err) | 177 | if (err) { |
178 | put_device(&rtc->dev); | ||
162 | goto exit_kfree; | 179 | goto exit_kfree; |
180 | } | ||
163 | 181 | ||
164 | rtc_dev_add_device(rtc); | 182 | rtc_dev_add_device(rtc); |
165 | rtc_sysfs_add_device(rtc); | 183 | rtc_sysfs_add_device(rtc); |