Blame view

drivers/rtc/interface.c 23.5 KB
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * RTC subsystem, interface functions
   *
   * Copyright (C) 2005 Tower Technologies
   * Author: Alessandro Zummo <a.zummo@towertech.it>
   *
   * based on arch/arm/common/rtctime.c
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
  */
  
  #include <linux/rtc.h>
d43c36dc6   Alexey Dobriyan   headers: remove s...
15
  #include <linux/sched.h>
2113852b2   Paul Gortmaker   rtc: Add module.h...
16
  #include <linux/module.h>
97144c675   David Brownell   rtc_irq_set_freq(...
17
  #include <linux/log2.h>
6610e0893   John Stultz   RTC: Rework RTC c...
18
  #include <linux/workqueue.h>
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
19

aa0be0f46   John Stultz   RTC: Propagate er...
20
21
  static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
  static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
6610e0893   John Stultz   RTC: Rework RTC c...
22
  static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
23
24
  {
  	int err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
25
26
27
28
29
30
  	if (!rtc->ops)
  		err = -ENODEV;
  	else if (!rtc->ops->read_time)
  		err = -EINVAL;
  	else {
  		memset(tm, 0, sizeof(struct rtc_time));
cd9662094   David Brownell   rtc: remove rest ...
31
  		err = rtc->ops->read_time(rtc->dev.parent, tm);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
32
  	}
6610e0893   John Stultz   RTC: Rework RTC c...
33
34
35
36
37
38
  	return err;
  }
  
  int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
  {
  	int err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
39

6610e0893   John Stultz   RTC: Rework RTC c...
40
41
42
43
44
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
  		return err;
  
  	err = __rtc_read_time(rtc, tm);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
45
46
47
48
  	mutex_unlock(&rtc->ops_lock);
  	return err;
  }
  EXPORT_SYMBOL_GPL(rtc_read_time);
ab6a2d70d   David Brownell   rtc: rtc interfac...
49
  int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
50
51
  {
  	int err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
52
53
54
55
56
57
58
  
  	err = rtc_valid_tm(tm);
  	if (err != 0)
  		return err;
  
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
b68bb2632   David Brownell   rtc: don't return...
59
  		return err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
60
61
62
  
  	if (!rtc->ops)
  		err = -ENODEV;
bbccf83f6   Alessandro Zummo   rtc: use set_mmss...
63
  	else if (rtc->ops->set_time)
cd9662094   David Brownell   rtc: remove rest ...
64
  		err = rtc->ops->set_time(rtc->dev.parent, tm);
bbccf83f6   Alessandro Zummo   rtc: use set_mmss...
65
66
67
68
69
70
71
  	else if (rtc->ops->set_mmss) {
  		unsigned long secs;
  		err = rtc_tm_to_time(tm, &secs);
  		if (err == 0)
  			err = rtc->ops->set_mmss(rtc->dev.parent, secs);
  	} else
  		err = -EINVAL;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
72

14d0e347e   Zoran Markovic   rtc: Keep system ...
73
  	pm_stay_awake(rtc->dev.parent);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
74
  	mutex_unlock(&rtc->ops_lock);
5f9679d29   NeilBrown   rtc: Expire alarm...
75
76
  	/* A timer might have just expired */
  	schedule_work(&rtc->irqwork);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
77
78
79
  	return err;
  }
  EXPORT_SYMBOL_GPL(rtc_set_time);
ab6a2d70d   David Brownell   rtc: rtc interfac...
80
  int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
81
82
  {
  	int err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
83
84
85
  
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
b68bb2632   David Brownell   rtc: don't return...
86
  		return err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
87
88
89
90
  
  	if (!rtc->ops)
  		err = -ENODEV;
  	else if (rtc->ops->set_mmss)
cd9662094   David Brownell   rtc: remove rest ...
91
  		err = rtc->ops->set_mmss(rtc->dev.parent, secs);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
92
93
  	else if (rtc->ops->read_time && rtc->ops->set_time) {
  		struct rtc_time new, old;
cd9662094   David Brownell   rtc: remove rest ...
94
  		err = rtc->ops->read_time(rtc->dev.parent, &old);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
95
96
97
98
99
100
101
102
103
104
105
  		if (err == 0) {
  			rtc_time_to_tm(secs, &new);
  
  			/*
  			 * avoid writing when we're going to change the day of
  			 * the month. We will retry in the next minute. This
  			 * basically means that if the RTC must not drift
  			 * by more than 1 minute in 11 minutes.
  			 */
  			if (!((old.tm_hour == 23 && old.tm_min == 59) ||
  				(new.tm_hour == 23 && new.tm_min == 59)))
cd9662094   David Brownell   rtc: remove rest ...
106
  				err = rtc->ops->set_time(rtc->dev.parent,
ab6a2d70d   David Brownell   rtc: rtc interfac...
107
  						&new);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
108
  		}
3ff2e13ce   Sachin Kamat   drivers/rtc/inter...
109
  	} else {
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
110
  		err = -EINVAL;
3ff2e13ce   Sachin Kamat   drivers/rtc/inter...
111
  	}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
112

14d0e347e   Zoran Markovic   rtc: Keep system ...
113
  	pm_stay_awake(rtc->dev.parent);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
114
  	mutex_unlock(&rtc->ops_lock);
5f9679d29   NeilBrown   rtc: Expire alarm...
115
116
  	/* A timer might have just expired */
  	schedule_work(&rtc->irqwork);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
117
118
119
120
  
  	return err;
  }
  EXPORT_SYMBOL_GPL(rtc_set_mmss);
f44f7f96a   John Stultz   RTC: Initialize k...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
  {
  	int err;
  
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
  		return err;
  
  	if (rtc->ops == NULL)
  		err = -ENODEV;
  	else if (!rtc->ops->read_alarm)
  		err = -EINVAL;
  	else {
  		memset(alarm, 0, sizeof(struct rtc_wkalrm));
  		err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
  	}
  
  	mutex_unlock(&rtc->ops_lock);
  	return err;
  }
  
  int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
  {
  	int err;
  	struct rtc_time before, now;
  	int first_time = 1;
  	unsigned long t_now, t_alm;
  	enum { none, day, month, year } missing = none;
  	unsigned days;
  
  	/* The lower level RTC driver may return -1 in some fields,
  	 * creating invalid alarm->time values, for reasons like:
  	 *
  	 *   - The hardware may not be capable of filling them in;
  	 *     many alarms match only on time-of-day fields, not
  	 *     day/month/year calendar data.
  	 *
  	 *   - Some hardware uses illegal values as "wildcard" match
  	 *     values, which non-Linux firmware (like a BIOS) may try
  	 *     to set up as e.g. "alarm 15 minutes after each hour".
  	 *     Linux uses only oneshot alarms.
  	 *
  	 * When we see that here, we deal with it by using values from
  	 * a current RTC timestamp for any missing (-1) values.  The
  	 * RTC driver prevents "periodic alarm" modes.
  	 *
  	 * But this can be racey, because some fields of the RTC timestamp
  	 * may have wrapped in the interval since we read the RTC alarm,
  	 * which would lead to us inserting inconsistent values in place
  	 * of the -1 fields.
  	 *
  	 * Reading the alarm and timestamp in the reverse sequence
  	 * would have the same race condition, and not solve the issue.
  	 *
  	 * So, we must first read the RTC timestamp,
  	 * then read the RTC alarm value,
  	 * and then read a second RTC timestamp.
  	 *
  	 * If any fields of the second timestamp have changed
  	 * when compared with the first timestamp, then we know
  	 * our timestamp may be inconsistent with that used by
  	 * the low-level rtc_read_alarm_internal() function.
  	 *
  	 * So, when the two timestamps disagree, we just loop and do
  	 * the process again to get a fully consistent set of values.
  	 *
  	 * This could all instead be done in the lower level driver,
  	 * but since more than one lower level RTC implementation needs it,
  	 * then it's probably best best to do it here instead of there..
  	 */
  
  	/* Get the "before" timestamp */
  	err = rtc_read_time(rtc, &before);
  	if (err < 0)
  		return err;
  	do {
  		if (!first_time)
  			memcpy(&before, &now, sizeof(struct rtc_time));
  		first_time = 0;
  
  		/* get the RTC alarm values, which may be incomplete */
  		err = rtc_read_alarm_internal(rtc, alarm);
  		if (err)
  			return err;
  
  		/* full-function RTCs won't have such missing fields */
  		if (rtc_valid_tm(&alarm->time) == 0)
  			return 0;
  
  		/* get the "after" timestamp, to detect wrapped fields */
  		err = rtc_read_time(rtc, &now);
  		if (err < 0)
  			return err;
  
  		/* note that tm_sec is a "don't care" value here: */
  	} while (   before.tm_min   != now.tm_min
  		 || before.tm_hour  != now.tm_hour
  		 || before.tm_mon   != now.tm_mon
  		 || before.tm_year  != now.tm_year);
  
  	/* Fill in the missing alarm fields using the timestamp; we
  	 * know there's at least one since alarm->time is invalid.
  	 */
  	if (alarm->time.tm_sec == -1)
  		alarm->time.tm_sec = now.tm_sec;
  	if (alarm->time.tm_min == -1)
  		alarm->time.tm_min = now.tm_min;
  	if (alarm->time.tm_hour == -1)
  		alarm->time.tm_hour = now.tm_hour;
  
  	/* For simplicity, only support date rollover for now */
e74a8f2ed   Ben Hutchings   drivers/rtc/inter...
232
  	if (alarm->time.tm_mday < 1 || alarm->time.tm_mday > 31) {
f44f7f96a   John Stultz   RTC: Initialize k...
233
234
235
  		alarm->time.tm_mday = now.tm_mday;
  		missing = day;
  	}
e74a8f2ed   Ben Hutchings   drivers/rtc/inter...
236
  	if ((unsigned)alarm->time.tm_mon >= 12) {
f44f7f96a   John Stultz   RTC: Initialize k...
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
  		alarm->time.tm_mon = now.tm_mon;
  		if (missing == none)
  			missing = month;
  	}
  	if (alarm->time.tm_year == -1) {
  		alarm->time.tm_year = now.tm_year;
  		if (missing == none)
  			missing = year;
  	}
  
  	/* with luck, no rollover is needed */
  	rtc_tm_to_time(&now, &t_now);
  	rtc_tm_to_time(&alarm->time, &t_alm);
  	if (t_now < t_alm)
  		goto done;
  
  	switch (missing) {
  
  	/* 24 hour rollover ... if it's now 10am Monday, an alarm that
  	 * that will trigger at 5am will do so at 5am Tuesday, which
  	 * could also be in the next month or year.  This is a common
  	 * case, especially for PCs.
  	 */
  	case day:
  		dev_dbg(&rtc->dev, "alarm rollover: %s
  ", "day");
  		t_alm += 24 * 60 * 60;
  		rtc_time_to_tm(t_alm, &alarm->time);
  		break;
  
  	/* Month rollover ... if it's the 31th, an alarm on the 3rd will
  	 * be next month.  An alarm matching on the 30th, 29th, or 28th
  	 * may end up in the month after that!  Many newer PCs support
  	 * this type of alarm.
  	 */
  	case month:
  		dev_dbg(&rtc->dev, "alarm rollover: %s
  ", "month");
  		do {
  			if (alarm->time.tm_mon < 11)
  				alarm->time.tm_mon++;
  			else {
  				alarm->time.tm_mon = 0;
  				alarm->time.tm_year++;
  			}
  			days = rtc_month_days(alarm->time.tm_mon,
  					alarm->time.tm_year);
  		} while (days < alarm->time.tm_mday);
  		break;
  
  	/* Year rollover ... easy except for leap years! */
  	case year:
  		dev_dbg(&rtc->dev, "alarm rollover: %s
  ", "year");
  		do {
  			alarm->time.tm_year++;
  		} while (rtc_valid_tm(&alarm->time) != 0);
  		break;
  
  	default:
  		dev_warn(&rtc->dev, "alarm rollover not handled
  ");
  	}
  
  done:
  	return 0;
  }
6610e0893   John Stultz   RTC: Rework RTC c...
304
  int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
305
306
  {
  	int err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
307
308
309
  
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
b68bb2632   David Brownell   rtc: don't return...
310
  		return err;
d5553a556   John Stultz   RTC: Properly han...
311
312
313
314
315
316
317
  	if (rtc->ops == NULL)
  		err = -ENODEV;
  	else if (!rtc->ops->read_alarm)
  		err = -EINVAL;
  	else {
  		memset(alarm, 0, sizeof(struct rtc_wkalrm));
  		alarm->enabled = rtc->aie_timer.enabled;
6610e0893   John Stultz   RTC: Rework RTC c...
318
  		alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires);
d5553a556   John Stultz   RTC: Properly han...
319
  	}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
320
  	mutex_unlock(&rtc->ops_lock);
6610e0893   John Stultz   RTC: Rework RTC c...
321

d5553a556   John Stultz   RTC: Properly han...
322
  	return err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
323
  }
6610e0893   John Stultz   RTC: Rework RTC c...
324
  EXPORT_SYMBOL_GPL(rtc_read_alarm);
0e36a9a4a   Mark Lord   rtc: fix readback...
325

d576fe49c   Mark Brown   rtc: Staticize no...
326
  static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
0e36a9a4a   Mark Lord   rtc: fix readback...
327
  {
6610e0893   John Stultz   RTC: Rework RTC c...
328
329
  	struct rtc_time tm;
  	long now, scheduled;
0e36a9a4a   Mark Lord   rtc: fix readback...
330
  	int err;
0e36a9a4a   Mark Lord   rtc: fix readback...
331

6610e0893   John Stultz   RTC: Rework RTC c...
332
333
  	err = rtc_valid_tm(&alarm->time);
  	if (err)
0e36a9a4a   Mark Lord   rtc: fix readback...
334
  		return err;
6610e0893   John Stultz   RTC: Rework RTC c...
335
  	rtc_tm_to_time(&alarm->time, &scheduled);
a01cc6570   David Brownell   rtc: rtc_read_ala...
336

6610e0893   John Stultz   RTC: Rework RTC c...
337
338
339
340
341
342
343
344
345
346
  	/* Make sure we're not setting alarms in the past */
  	err = __rtc_read_time(rtc, &tm);
  	rtc_tm_to_time(&tm, &now);
  	if (scheduled <= now)
  		return -ETIME;
  	/*
  	 * XXX - We just checked to make sure the alarm time is not
  	 * in the past, but there is still a race window where if
  	 * the is alarm set for the next second and the second ticks
  	 * over right here, before we set the alarm.
a01cc6570   David Brownell   rtc: rtc_read_ala...
347
  	 */
a01cc6570   David Brownell   rtc: rtc_read_ala...
348

157e8bf8b   Linus Torvalds   Revert "rtc: Disa...
349
350
351
352
353
354
355
356
  	if (!rtc->ops)
  		err = -ENODEV;
  	else if (!rtc->ops->set_alarm)
  		err = -EINVAL;
  	else
  		err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
  
  	return err;
0e36a9a4a   Mark Lord   rtc: fix readback...
357
  }
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
358

ab6a2d70d   David Brownell   rtc: rtc interfac...
359
  int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
360
361
  {
  	int err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
362

f8245c268   David Brownell   rtc: remove "RTC_...
363
364
365
  	err = rtc_valid_tm(&alarm->time);
  	if (err != 0)
  		return err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
366
367
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
b68bb2632   David Brownell   rtc: don't return...
368
  		return err;
3ff2e13ce   Sachin Kamat   drivers/rtc/inter...
369
  	if (rtc->aie_timer.enabled)
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
370
  		rtc_timer_remove(rtc, &rtc->aie_timer);
3ff2e13ce   Sachin Kamat   drivers/rtc/inter...
371

6610e0893   John Stultz   RTC: Rework RTC c...
372
373
  	rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
  	rtc->aie_timer.period = ktime_set(0, 0);
3ff2e13ce   Sachin Kamat   drivers/rtc/inter...
374
  	if (alarm->enabled)
aa0be0f46   John Stultz   RTC: Propagate er...
375
  		err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
3ff2e13ce   Sachin Kamat   drivers/rtc/inter...
376

0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
377
  	mutex_unlock(&rtc->ops_lock);
aa0be0f46   John Stultz   RTC: Propagate er...
378
  	return err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
379
380
  }
  EXPORT_SYMBOL_GPL(rtc_set_alarm);
f6d5b3312   John Stultz   RTC: Fix early ir...
381
382
383
384
  /* Called once per device from rtc_device_register */
  int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
  {
  	int err;
bd729d72b   John Stultz   rtc: Avoid settin...
385
  	struct rtc_time now;
f6d5b3312   John Stultz   RTC: Fix early ir...
386
387
388
389
  
  	err = rtc_valid_tm(&alarm->time);
  	if (err != 0)
  		return err;
bd729d72b   John Stultz   rtc: Avoid settin...
390
391
392
  	err = rtc_read_time(rtc, &now);
  	if (err)
  		return err;
f6d5b3312   John Stultz   RTC: Fix early ir...
393
394
395
396
397
398
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
  		return err;
  
  	rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
  	rtc->aie_timer.period = ktime_set(0, 0);
bd729d72b   John Stultz   rtc: Avoid settin...
399
400
401
402
  
  	/* Alarm has to be enabled & in the futrure for us to enqueue it */
  	if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 <
  			 rtc->aie_timer.node.expires.tv64)) {
f6d5b3312   John Stultz   RTC: Fix early ir...
403
404
405
406
407
408
409
  		rtc->aie_timer.enabled = 1;
  		timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node);
  	}
  	mutex_unlock(&rtc->ops_lock);
  	return err;
  }
  EXPORT_SYMBOL_GPL(rtc_initialize_alarm);
099e65762   Alessandro Zummo   rtc: add alarm/up...
410
411
412
413
414
  int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
  {
  	int err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
  		return err;
6610e0893   John Stultz   RTC: Rework RTC c...
415
  	if (rtc->aie_timer.enabled != enabled) {
aa0be0f46   John Stultz   RTC: Propagate er...
416
417
418
  		if (enabled)
  			err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
  		else
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
419
  			rtc_timer_remove(rtc, &rtc->aie_timer);
6610e0893   John Stultz   RTC: Rework RTC c...
420
  	}
aa0be0f46   John Stultz   RTC: Propagate er...
421
  	if (err)
516373b8b   Uwe Kleine-König   RTC: Release mute...
422
423
  		/* nothing */;
  	else if (!rtc->ops)
099e65762   Alessandro Zummo   rtc: add alarm/up...
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
  		err = -ENODEV;
  	else if (!rtc->ops->alarm_irq_enable)
  		err = -EINVAL;
  	else
  		err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
  
  	mutex_unlock(&rtc->ops_lock);
  	return err;
  }
  EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
  
  int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
  {
  	int err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
  		return err;
456d66ecd   John Stultz   RTC: Re-enable UI...
440
441
442
443
444
445
  #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
  	if (enabled == 0 && rtc->uie_irq_active) {
  		mutex_unlock(&rtc->ops_lock);
  		return rtc_dev_update_irq_enable_emul(rtc, 0);
  	}
  #endif
6610e0893   John Stultz   RTC: Rework RTC c...
446
447
448
  	/* make sure we're changing state */
  	if (rtc->uie_rtctimer.enabled == enabled)
  		goto out;
4a649903f   John Stultz   rtc: Provide flag...
449
450
451
452
  	if (rtc->uie_unsupported) {
  		err = -EINVAL;
  		goto out;
  	}
6610e0893   John Stultz   RTC: Rework RTC c...
453
454
455
456
457
458
459
460
461
  	if (enabled) {
  		struct rtc_time tm;
  		ktime_t now, onesec;
  
  		__rtc_read_time(rtc, &tm);
  		onesec = ktime_set(1, 0);
  		now = rtc_tm_to_ktime(tm);
  		rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
  		rtc->uie_rtctimer.period = ktime_set(1, 0);
aa0be0f46   John Stultz   RTC: Propagate er...
462
463
  		err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
  	} else
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
464
  		rtc_timer_remove(rtc, &rtc->uie_rtctimer);
099e65762   Alessandro Zummo   rtc: add alarm/up...
465

6610e0893   John Stultz   RTC: Rework RTC c...
466
  out:
099e65762   Alessandro Zummo   rtc: add alarm/up...
467
  	mutex_unlock(&rtc->ops_lock);
456d66ecd   John Stultz   RTC: Re-enable UI...
468
469
470
471
472
473
474
475
476
477
  #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
  	/*
  	 * Enable emulation if the driver did not provide
  	 * the update_irq_enable function pointer or if returned
  	 * -EINVAL to signal that it has been configured without
  	 * interrupts or that are not available at the moment.
  	 */
  	if (err == -EINVAL)
  		err = rtc_dev_update_irq_enable_emul(rtc, enabled);
  #endif
099e65762   Alessandro Zummo   rtc: add alarm/up...
478
  	return err;
6610e0893   John Stultz   RTC: Rework RTC c...
479

099e65762   Alessandro Zummo   rtc: add alarm/up...
480
481
  }
  EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
6610e0893   John Stultz   RTC: Rework RTC c...
482

d728b1e69   David Brownell   [PATCH] rtc class...
483
  /**
6610e0893   John Stultz   RTC: Rework RTC c...
484
485
486
487
   * rtc_handle_legacy_irq - AIE, UIE and PIE event hook
   * @rtc: pointer to the rtc device
   *
   * This function is called when an AIE, UIE or PIE mode interrupt
25985edce   Lucas De Marchi   Fix common misspe...
488
   * has occurred (or been emulated).
6610e0893   John Stultz   RTC: Rework RTC c...
489
490
   *
   * Triggers the registered irq_task function callback.
d728b1e69   David Brownell   [PATCH] rtc class...
491
   */
456d66ecd   John Stultz   RTC: Re-enable UI...
492
  void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
493
  {
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
494
  	unsigned long flags;
6610e0893   John Stultz   RTC: Rework RTC c...
495
  	/* mark one irq of the appropriate mode */
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
496
  	spin_lock_irqsave(&rtc->irq_lock, flags);
6610e0893   John Stultz   RTC: Rework RTC c...
497
  	rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode);
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
498
  	spin_unlock_irqrestore(&rtc->irq_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
499

6610e0893   John Stultz   RTC: Rework RTC c...
500
  	/* call the task func */
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
501
  	spin_lock_irqsave(&rtc->irq_task_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
502
503
  	if (rtc->irq_task)
  		rtc->irq_task->func(rtc->irq_task->private_data);
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
504
  	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
505
506
507
508
  
  	wake_up_interruptible(&rtc->irq_queue);
  	kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
  }
6610e0893   John Stultz   RTC: Rework RTC c...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  
  
  /**
   * rtc_aie_update_irq - AIE mode rtctimer hook
   * @private: pointer to the rtc_device
   *
   * This functions is called when the aie_timer expires.
   */
  void rtc_aie_update_irq(void *private)
  {
  	struct rtc_device *rtc = (struct rtc_device *)private;
  	rtc_handle_legacy_irq(rtc, 1, RTC_AF);
  }
  
  
  /**
   * rtc_uie_update_irq - UIE mode rtctimer hook
   * @private: pointer to the rtc_device
   *
   * This functions is called when the uie_timer expires.
   */
  void rtc_uie_update_irq(void *private)
  {
  	struct rtc_device *rtc = (struct rtc_device *)private;
  	rtc_handle_legacy_irq(rtc, 1,  RTC_UF);
  }
  
  
  /**
   * rtc_pie_update_irq - PIE mode hrtimer hook
   * @timer: pointer to the pie mode hrtimer
   *
   * This function is used to emulate PIE mode interrupts
   * using an hrtimer. This function is called when the periodic
   * hrtimer expires.
   */
  enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
  {
  	struct rtc_device *rtc;
  	ktime_t period;
  	int count;
  	rtc = container_of(timer, struct rtc_device, pie_timer);
  
  	period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq);
  	count = hrtimer_forward_now(timer, period);
  
  	rtc_handle_legacy_irq(rtc, count, RTC_PF);
  
  	return HRTIMER_RESTART;
  }
  
  /**
   * rtc_update_irq - Triggered when a RTC interrupt occurs.
   * @rtc: the rtc device
   * @num: how many irqs are being reported (usually one)
   * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
   * Context: any
   */
  void rtc_update_irq(struct rtc_device *rtc,
  		unsigned long num, unsigned long events)
  {
131c9cc83   Alessandro Zummo   rtc: verify a cri...
570
571
  	if (unlikely(IS_ERR_OR_NULL(rtc)))
  		return;
7523ceed4   NeilBrown   RTC: Avoid races ...
572
  	pm_stay_awake(rtc->dev.parent);
6610e0893   John Stultz   RTC: Rework RTC c...
573
574
  	schedule_work(&rtc->irqwork);
  }
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
575
  EXPORT_SYMBOL_GPL(rtc_update_irq);
9f3b795a6   MichaÅ‚ MirosÅ‚aw   driver-core: cons...
576
  static int __rtc_match(struct device *dev, const void *data)
71da89050   Dave Young   rtc: use class it...
577
  {
9f3b795a6   MichaÅ‚ MirosÅ‚aw   driver-core: cons...
578
  	const char *name = data;
71da89050   Dave Young   rtc: use class it...
579

d4afc76c0   Kay Sievers   rtc: struct devic...
580
  	if (strcmp(dev_name(dev), name) == 0)
71da89050   Dave Young   rtc: use class it...
581
582
583
  		return 1;
  	return 0;
  }
9f3b795a6   MichaÅ‚ MirosÅ‚aw   driver-core: cons...
584
  struct rtc_device *rtc_class_open(const char *name)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
585
  {
cd9662094   David Brownell   rtc: remove rest ...
586
  	struct device *dev;
ab6a2d70d   David Brownell   rtc: rtc interfac...
587
  	struct rtc_device *rtc = NULL;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
588

695794ae0   Greg Kroah-Hartman   Driver Core: add ...
589
  	dev = class_find_device(rtc_class, NULL, name, __rtc_match);
71da89050   Dave Young   rtc: use class it...
590
591
  	if (dev)
  		rtc = to_rtc_device(dev);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
592

ab6a2d70d   David Brownell   rtc: rtc interfac...
593
594
  	if (rtc) {
  		if (!try_module_get(rtc->owner)) {
cd9662094   David Brownell   rtc: remove rest ...
595
  			put_device(dev);
ab6a2d70d   David Brownell   rtc: rtc interfac...
596
597
  			rtc = NULL;
  		}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
598
  	}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
599

ab6a2d70d   David Brownell   rtc: rtc interfac...
600
  	return rtc;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
601
602
  }
  EXPORT_SYMBOL_GPL(rtc_class_open);
ab6a2d70d   David Brownell   rtc: rtc interfac...
603
  void rtc_class_close(struct rtc_device *rtc)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
604
  {
ab6a2d70d   David Brownell   rtc: rtc interfac...
605
  	module_put(rtc->owner);
cd9662094   David Brownell   rtc: remove rest ...
606
  	put_device(&rtc->dev);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
607
608
  }
  EXPORT_SYMBOL_GPL(rtc_class_close);
ab6a2d70d   David Brownell   rtc: rtc interfac...
609
  int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
610
611
  {
  	int retval = -EBUSY;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
612
613
614
  
  	if (task == NULL || task->func == NULL)
  		return -EINVAL;
d691eb901   Alessandro Zummo   RTC: periodic irq...
615
  	/* Cannot register while the char dev is in use */
372a302e9   Jiri Kosina   RTC: assure prope...
616
  	if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
d691eb901   Alessandro Zummo   RTC: periodic irq...
617
  		return -EBUSY;
d728b1e69   David Brownell   [PATCH] rtc class...
618
  	spin_lock_irq(&rtc->irq_task_lock);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
619
620
621
622
  	if (rtc->irq_task == NULL) {
  		rtc->irq_task = task;
  		retval = 0;
  	}
d728b1e69   David Brownell   [PATCH] rtc class...
623
  	spin_unlock_irq(&rtc->irq_task_lock);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
624

372a302e9   Jiri Kosina   RTC: assure prope...
625
  	clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
d691eb901   Alessandro Zummo   RTC: periodic irq...
626

0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
627
628
629
  	return retval;
  }
  EXPORT_SYMBOL_GPL(rtc_irq_register);
ab6a2d70d   David Brownell   rtc: rtc interfac...
630
  void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
631
  {
d728b1e69   David Brownell   [PATCH] rtc class...
632
  	spin_lock_irq(&rtc->irq_task_lock);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
633
634
  	if (rtc->irq_task == task)
  		rtc->irq_task = NULL;
d728b1e69   David Brownell   [PATCH] rtc class...
635
  	spin_unlock_irq(&rtc->irq_task_lock);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
636
637
  }
  EXPORT_SYMBOL_GPL(rtc_irq_unregister);
3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
  static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
  {
  	/*
  	 * We always cancel the timer here first, because otherwise
  	 * we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
  	 * when we manage to start the timer before the callback
  	 * returns HRTIMER_RESTART.
  	 *
  	 * We cannot use hrtimer_cancel() here as a running callback
  	 * could be blocked on rtc->irq_task_lock and hrtimer_cancel()
  	 * would spin forever.
  	 */
  	if (hrtimer_try_to_cancel(&rtc->pie_timer) < 0)
  		return -1;
  
  	if (enabled) {
  		ktime_t period = ktime_set(0, NSEC_PER_SEC / rtc->irq_freq);
  
  		hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
  	}
  	return 0;
  }
97144c675   David Brownell   rtc_irq_set_freq(...
660
661
662
663
664
665
666
667
668
669
  /**
   * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
   * @rtc: the rtc device
   * @task: currently registered with rtc_irq_register()
   * @enabled: true to enable periodic IRQs
   * Context: any
   *
   * Note that rtc_irq_set_freq() should previously have been used to
   * specify the desired frequency of periodic IRQ task->func() callbacks.
   */
ab6a2d70d   David Brownell   rtc: rtc interfac...
670
  int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
671
672
673
  {
  	int err = 0;
  	unsigned long flags;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
674

3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
675
  retry:
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
676
  	spin_lock_irqsave(&rtc->irq_task_lock, flags);
d691eb901   Alessandro Zummo   RTC: periodic irq...
677
678
  	if (rtc->irq_task != NULL && task == NULL)
  		err = -EBUSY;
0734e27f0   Chris Brand   drivers/rtc/inter...
679
  	else if (rtc->irq_task != task)
d691eb901   Alessandro Zummo   RTC: periodic irq...
680
  		err = -EACCES;
0734e27f0   Chris Brand   drivers/rtc/inter...
681
  	else {
3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
682
683
684
685
686
687
  		if (rtc_update_hrtimer(rtc, enabled) < 0) {
  			spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
  			cpu_relax();
  			goto retry;
  		}
  		rtc->pie_enabled = enabled;
6610e0893   John Stultz   RTC: Rework RTC c...
688
  	}
6610e0893   John Stultz   RTC: Rework RTC c...
689
  	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
690
691
692
  	return err;
  }
  EXPORT_SYMBOL_GPL(rtc_irq_set_state);
97144c675   David Brownell   rtc_irq_set_freq(...
693
694
695
696
697
698
699
700
701
702
  /**
   * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
   * @rtc: the rtc device
   * @task: currently registered with rtc_irq_register()
   * @freq: positive frequency with which task->func() will be called
   * Context: any
   *
   * Note that rtc_irq_set_state() is used to enable or disable the
   * periodic IRQs.
   */
ab6a2d70d   David Brownell   rtc: rtc interfac...
703
  int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
704
  {
56f10c634   Alessandro Zummo   [PATCH] rtc subsy...
705
  	int err = 0;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
706
  	unsigned long flags;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
707

6e7a333ea   Thomas Gleixner   rtc: Limit RTC PI...
708
  	if (freq <= 0 || freq > RTC_MAX_FREQ)
83a06bf50   Marcelo Roberto Jimenez   RTC: Prevents a d...
709
  		return -EINVAL;
3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
710
  retry:
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
711
  	spin_lock_irqsave(&rtc->irq_task_lock, flags);
d691eb901   Alessandro Zummo   RTC: periodic irq...
712
713
  	if (rtc->irq_task != NULL && task == NULL)
  		err = -EBUSY;
0734e27f0   Chris Brand   drivers/rtc/inter...
714
  	else if (rtc->irq_task != task)
d691eb901   Alessandro Zummo   RTC: periodic irq...
715
  		err = -EACCES;
0734e27f0   Chris Brand   drivers/rtc/inter...
716
  	else {
6610e0893   John Stultz   RTC: Rework RTC c...
717
  		rtc->irq_freq = freq;
3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
718
719
720
721
  		if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) {
  			spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
  			cpu_relax();
  			goto retry;
6610e0893   John Stultz   RTC: Rework RTC c...
722
  		}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
723
  	}
6610e0893   John Stultz   RTC: Rework RTC c...
724
  	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
725
726
  	return err;
  }
2601a4647   David Brownell   [PATCH] rtc frame...
727
  EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
6610e0893   John Stultz   RTC: Rework RTC c...
728
729
  
  /**
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
730
   * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue
6610e0893   John Stultz   RTC: Rework RTC c...
731
732
733
734
735
736
   * @rtc rtc device
   * @timer timer being added.
   *
   * Enqueues a timer onto the rtc devices timerqueue and sets
   * the next alarm event appropriately.
   *
aa0be0f46   John Stultz   RTC: Propagate er...
737
738
   * Sets the enabled bit on the added timer.
   *
6610e0893   John Stultz   RTC: Rework RTC c...
739
740
   * Must hold ops_lock for proper serialization of timerqueue
   */
aa0be0f46   John Stultz   RTC: Propagate er...
741
  static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
6610e0893   John Stultz   RTC: Rework RTC c...
742
  {
aa0be0f46   John Stultz   RTC: Propagate er...
743
  	timer->enabled = 1;
6610e0893   John Stultz   RTC: Rework RTC c...
744
745
746
747
748
749
750
  	timerqueue_add(&rtc->timerqueue, &timer->node);
  	if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
  		struct rtc_wkalrm alarm;
  		int err;
  		alarm.time = rtc_ktime_to_tm(timer->node.expires);
  		alarm.enabled = 1;
  		err = __rtc_set_alarm(rtc, &alarm);
14d0e347e   Zoran Markovic   rtc: Keep system ...
751
752
  		if (err == -ETIME) {
  			pm_stay_awake(rtc->dev.parent);
6610e0893   John Stultz   RTC: Rework RTC c...
753
  			schedule_work(&rtc->irqwork);
14d0e347e   Zoran Markovic   rtc: Keep system ...
754
  		} else if (err) {
aa0be0f46   John Stultz   RTC: Propagate er...
755
756
757
758
  			timerqueue_del(&rtc->timerqueue, &timer->node);
  			timer->enabled = 0;
  			return err;
  		}
6610e0893   John Stultz   RTC: Rework RTC c...
759
  	}
aa0be0f46   John Stultz   RTC: Propagate er...
760
  	return 0;
6610e0893   John Stultz   RTC: Rework RTC c...
761
  }
41c7f7424   Rabin Vincent   rtc: Disable the ...
762
763
764
765
766
767
768
  static void rtc_alarm_disable(struct rtc_device *rtc)
  {
  	if (!rtc->ops || !rtc->ops->alarm_irq_enable)
  		return;
  
  	rtc->ops->alarm_irq_enable(rtc->dev.parent, false);
  }
6610e0893   John Stultz   RTC: Rework RTC c...
769
  /**
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
770
   * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
6610e0893   John Stultz   RTC: Rework RTC c...
771
772
773
774
775
776
   * @rtc rtc device
   * @timer timer being removed.
   *
   * Removes a timer onto the rtc devices timerqueue and sets
   * the next alarm event appropriately.
   *
aa0be0f46   John Stultz   RTC: Propagate er...
777
778
   * Clears the enabled bit on the removed timer.
   *
6610e0893   John Stultz   RTC: Rework RTC c...
779
780
   * Must hold ops_lock for proper serialization of timerqueue
   */
aa0be0f46   John Stultz   RTC: Propagate er...
781
  static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
6610e0893   John Stultz   RTC: Rework RTC c...
782
783
784
  {
  	struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
  	timerqueue_del(&rtc->timerqueue, &timer->node);
aa0be0f46   John Stultz   RTC: Propagate er...
785
  	timer->enabled = 0;
6610e0893   John Stultz   RTC: Rework RTC c...
786
787
788
789
  	if (next == &timer->node) {
  		struct rtc_wkalrm alarm;
  		int err;
  		next = timerqueue_getnext(&rtc->timerqueue);
41c7f7424   Rabin Vincent   rtc: Disable the ...
790
791
  		if (!next) {
  			rtc_alarm_disable(rtc);
6610e0893   John Stultz   RTC: Rework RTC c...
792
  			return;
41c7f7424   Rabin Vincent   rtc: Disable the ...
793
  		}
6610e0893   John Stultz   RTC: Rework RTC c...
794
795
796
  		alarm.time = rtc_ktime_to_tm(next->expires);
  		alarm.enabled = 1;
  		err = __rtc_set_alarm(rtc, &alarm);
14d0e347e   Zoran Markovic   rtc: Keep system ...
797
798
  		if (err == -ETIME) {
  			pm_stay_awake(rtc->dev.parent);
6610e0893   John Stultz   RTC: Rework RTC c...
799
  			schedule_work(&rtc->irqwork);
14d0e347e   Zoran Markovic   rtc: Keep system ...
800
  		}
6610e0893   John Stultz   RTC: Rework RTC c...
801
802
803
804
  	}
  }
  
  /**
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
805
   * rtc_timer_do_work - Expires rtc timers
6610e0893   John Stultz   RTC: Rework RTC c...
806
807
808
809
810
811
812
813
   * @rtc rtc device
   * @timer timer being removed.
   *
   * Expires rtc timers. Reprograms next alarm event if needed.
   * Called via worktask.
   *
   * Serializes access to timerqueue via ops_lock mutex
   */
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
814
  void rtc_timer_do_work(struct work_struct *work)
6610e0893   John Stultz   RTC: Rework RTC c...
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  {
  	struct rtc_timer *timer;
  	struct timerqueue_node *next;
  	ktime_t now;
  	struct rtc_time tm;
  
  	struct rtc_device *rtc =
  		container_of(work, struct rtc_device, irqwork);
  
  	mutex_lock(&rtc->ops_lock);
  again:
  	__rtc_read_time(rtc, &tm);
  	now = rtc_tm_to_ktime(tm);
  	while ((next = timerqueue_getnext(&rtc->timerqueue))) {
  		if (next->expires.tv64 > now.tv64)
  			break;
  
  		/* expire timer */
  		timer = container_of(next, struct rtc_timer, node);
  		timerqueue_del(&rtc->timerqueue, &timer->node);
  		timer->enabled = 0;
  		if (timer->task.func)
  			timer->task.func(timer->task.private_data);
  
  		/* Re-add/fwd periodic timers */
  		if (ktime_to_ns(timer->period)) {
  			timer->node.expires = ktime_add(timer->node.expires,
  							timer->period);
  			timer->enabled = 1;
  			timerqueue_add(&rtc->timerqueue, &timer->node);
  		}
  	}
  
  	/* Set next alarm */
  	if (next) {
  		struct rtc_wkalrm alarm;
  		int err;
  		alarm.time = rtc_ktime_to_tm(next->expires);
  		alarm.enabled = 1;
  		err = __rtc_set_alarm(rtc, &alarm);
  		if (err == -ETIME)
  			goto again;
41c7f7424   Rabin Vincent   rtc: Disable the ...
857
858
  	} else
  		rtc_alarm_disable(rtc);
6610e0893   John Stultz   RTC: Rework RTC c...
859

14d0e347e   Zoran Markovic   rtc: Keep system ...
860
  	pm_relax(rtc->dev.parent);
6610e0893   John Stultz   RTC: Rework RTC c...
861
862
  	mutex_unlock(&rtc->ops_lock);
  }
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
863
  /* rtc_timer_init - Initializes an rtc_timer
6610e0893   John Stultz   RTC: Rework RTC c...
864
865
866
867
868
869
   * @timer: timer to be intiialized
   * @f: function pointer to be called when timer fires
   * @data: private data passed to function pointer
   *
   * Kernel interface to initializing an rtc_timer.
   */
3ff2e13ce   Sachin Kamat   drivers/rtc/inter...
870
  void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data)
6610e0893   John Stultz   RTC: Rework RTC c...
871
872
873
874
875
876
  {
  	timerqueue_init(&timer->node);
  	timer->enabled = 0;
  	timer->task.func = f;
  	timer->task.private_data = data;
  }
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
877
  /* rtc_timer_start - Sets an rtc_timer to fire in the future
6610e0893   John Stultz   RTC: Rework RTC c...
878
879
880
881
882
883
884
   * @ rtc: rtc device to be used
   * @ timer: timer being set
   * @ expires: time at which to expire the timer
   * @ period: period that the timer will recur
   *
   * Kernel interface to set an rtc_timer
   */
3ff2e13ce   Sachin Kamat   drivers/rtc/inter...
885
  int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
6610e0893   John Stultz   RTC: Rework RTC c...
886
887
888
889
890
  			ktime_t expires, ktime_t period)
  {
  	int ret = 0;
  	mutex_lock(&rtc->ops_lock);
  	if (timer->enabled)
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
891
  		rtc_timer_remove(rtc, timer);
6610e0893   John Stultz   RTC: Rework RTC c...
892
893
894
  
  	timer->node.expires = expires;
  	timer->period = period;
aa0be0f46   John Stultz   RTC: Propagate er...
895
  	ret = rtc_timer_enqueue(rtc, timer);
6610e0893   John Stultz   RTC: Rework RTC c...
896
897
898
899
  
  	mutex_unlock(&rtc->ops_lock);
  	return ret;
  }
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
900
  /* rtc_timer_cancel - Stops an rtc_timer
6610e0893   John Stultz   RTC: Rework RTC c...
901
902
903
904
905
   * @ rtc: rtc device to be used
   * @ timer: timer being set
   *
   * Kernel interface to cancel an rtc_timer
   */
3ff2e13ce   Sachin Kamat   drivers/rtc/inter...
906
  int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
6610e0893   John Stultz   RTC: Rework RTC c...
907
908
909
910
  {
  	int ret = 0;
  	mutex_lock(&rtc->ops_lock);
  	if (timer->enabled)
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
911
  		rtc_timer_remove(rtc, timer);
6610e0893   John Stultz   RTC: Rework RTC c...
912
913
914
  	mutex_unlock(&rtc->ops_lock);
  	return ret;
  }