Blame view

drivers/rtc/interface.c 22.6 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
73
74
75
76
  
  	mutex_unlock(&rtc->ops_lock);
  	return err;
  }
  EXPORT_SYMBOL_GPL(rtc_set_time);
ab6a2d70d   David Brownell   rtc: rtc interfac...
77
  int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
78
79
  {
  	int err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
80
81
82
  
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
b68bb2632   David Brownell   rtc: don't return...
83
  		return err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
84
85
86
87
  
  	if (!rtc->ops)
  		err = -ENODEV;
  	else if (rtc->ops->set_mmss)
cd9662094   David Brownell   rtc: remove rest ...
88
  		err = rtc->ops->set_mmss(rtc->dev.parent, secs);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
89
90
  	else if (rtc->ops->read_time && rtc->ops->set_time) {
  		struct rtc_time new, old;
cd9662094   David Brownell   rtc: remove rest ...
91
  		err = rtc->ops->read_time(rtc->dev.parent, &old);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
92
93
94
95
96
97
98
99
100
101
102
  		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 ...
103
  				err = rtc->ops->set_time(rtc->dev.parent,
ab6a2d70d   David Brownell   rtc: rtc interfac...
104
  						&new);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
105
106
107
108
109
110
111
112
113
114
  		}
  	}
  	else
  		err = -EINVAL;
  
  	mutex_unlock(&rtc->ops_lock);
  
  	return err;
  }
  EXPORT_SYMBOL_GPL(rtc_set_mmss);
f44f7f96a   John Stultz   RTC: Initialize k...
115
116
117
118
119
120
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
  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...
226
  	if (alarm->time.tm_mday < 1 || alarm->time.tm_mday > 31) {
f44f7f96a   John Stultz   RTC: Initialize k...
227
228
229
  		alarm->time.tm_mday = now.tm_mday;
  		missing = day;
  	}
e74a8f2ed   Ben Hutchings   drivers/rtc/inter...
230
  	if ((unsigned)alarm->time.tm_mon >= 12) {
f44f7f96a   John Stultz   RTC: Initialize k...
231
232
233
234
235
236
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
  		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...
298
  int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
299
300
  {
  	int err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
301
302
303
  
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
b68bb2632   David Brownell   rtc: don't return...
304
  		return err;
d5553a556   John Stultz   RTC: Properly han...
305
306
307
308
309
310
311
  	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...
312
  		alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires);
d5553a556   John Stultz   RTC: Properly han...
313
  	}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
314
  	mutex_unlock(&rtc->ops_lock);
6610e0893   John Stultz   RTC: Rework RTC c...
315

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

d576fe49c   Mark Brown   rtc: Staticize no...
320
  static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
0e36a9a4a   Mark Lord   rtc: fix readback...
321
  {
6610e0893   John Stultz   RTC: Rework RTC c...
322
323
  	struct rtc_time tm;
  	long now, scheduled;
0e36a9a4a   Mark Lord   rtc: fix readback...
324
  	int err;
0e36a9a4a   Mark Lord   rtc: fix readback...
325

6610e0893   John Stultz   RTC: Rework RTC c...
326
327
  	err = rtc_valid_tm(&alarm->time);
  	if (err)
0e36a9a4a   Mark Lord   rtc: fix readback...
328
  		return err;
6610e0893   John Stultz   RTC: Rework RTC c...
329
  	rtc_tm_to_time(&alarm->time, &scheduled);
a01cc6570   David Brownell   rtc: rtc_read_ala...
330

6610e0893   John Stultz   RTC: Rework RTC c...
331
332
333
334
335
336
337
338
339
340
  	/* 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...
341
  	 */
a01cc6570   David Brownell   rtc: rtc_read_ala...
342

157e8bf8b   Linus Torvalds   Revert "rtc: Disa...
343
344
345
346
347
348
349
350
  	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...
351
  }
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
352

ab6a2d70d   David Brownell   rtc: rtc interfac...
353
  int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
354
355
  {
  	int err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
356

f8245c268   David Brownell   rtc: remove "RTC_...
357
358
359
  	err = rtc_valid_tm(&alarm->time);
  	if (err != 0)
  		return err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
360
361
  	err = mutex_lock_interruptible(&rtc->ops_lock);
  	if (err)
b68bb2632   David Brownell   rtc: don't return...
362
  		return err;
6610e0893   John Stultz   RTC: Rework RTC c...
363
  	if (rtc->aie_timer.enabled) {
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
364
  		rtc_timer_remove(rtc, &rtc->aie_timer);
6610e0893   John Stultz   RTC: Rework RTC c...
365
366
367
368
  	}
  	rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
  	rtc->aie_timer.period = ktime_set(0, 0);
  	if (alarm->enabled) {
aa0be0f46   John Stultz   RTC: Propagate er...
369
  		err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
6610e0893   John Stultz   RTC: Rework RTC c...
370
  	}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
371
  	mutex_unlock(&rtc->ops_lock);
aa0be0f46   John Stultz   RTC: Propagate er...
372
  	return err;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
373
374
  }
  EXPORT_SYMBOL_GPL(rtc_set_alarm);
f6d5b3312   John Stultz   RTC: Fix early ir...
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  /* Called once per device from rtc_device_register */
  int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
  {
  	int err;
  
  	err = rtc_valid_tm(&alarm->time);
  	if (err != 0)
  		return err;
  
  	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);
  	if (alarm->enabled) {
  		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...
398
399
400
401
402
  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...
403
  	if (rtc->aie_timer.enabled != enabled) {
aa0be0f46   John Stultz   RTC: Propagate er...
404
405
406
  		if (enabled)
  			err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
  		else
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
407
  			rtc_timer_remove(rtc, &rtc->aie_timer);
6610e0893   John Stultz   RTC: Rework RTC c...
408
  	}
aa0be0f46   John Stultz   RTC: Propagate er...
409
  	if (err)
516373b8b   Uwe Kleine-König   RTC: Release mute...
410
411
  		/* nothing */;
  	else if (!rtc->ops)
099e65762   Alessandro Zummo   rtc: add alarm/up...
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  		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...
428
429
430
431
432
433
  #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...
434
435
436
437
438
439
440
441
442
443
444
445
446
  	/* make sure we're changing state */
  	if (rtc->uie_rtctimer.enabled == enabled)
  		goto out;
  
  	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...
447
448
  		err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
  	} else
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
449
  		rtc_timer_remove(rtc, &rtc->uie_rtctimer);
099e65762   Alessandro Zummo   rtc: add alarm/up...
450

6610e0893   John Stultz   RTC: Rework RTC c...
451
  out:
099e65762   Alessandro Zummo   rtc: add alarm/up...
452
  	mutex_unlock(&rtc->ops_lock);
456d66ecd   John Stultz   RTC: Re-enable UI...
453
454
455
456
457
458
459
460
461
462
  #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...
463
  	return err;
6610e0893   John Stultz   RTC: Rework RTC c...
464

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

d728b1e69   David Brownell   [PATCH] rtc class...
468
  /**
6610e0893   John Stultz   RTC: Rework RTC c...
469
470
471
472
   * 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...
473
   * has occurred (or been emulated).
6610e0893   John Stultz   RTC: Rework RTC c...
474
475
   *
   * Triggers the registered irq_task function callback.
d728b1e69   David Brownell   [PATCH] rtc class...
476
   */
456d66ecd   John Stultz   RTC: Re-enable UI...
477
  void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
478
  {
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
479
  	unsigned long flags;
6610e0893   John Stultz   RTC: Rework RTC c...
480
  	/* mark one irq of the appropriate mode */
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
481
  	spin_lock_irqsave(&rtc->irq_lock, flags);
6610e0893   John Stultz   RTC: Rework RTC c...
482
  	rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode);
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
483
  	spin_unlock_irqrestore(&rtc->irq_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
484

6610e0893   John Stultz   RTC: Rework RTC c...
485
  	/* call the task func */
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
486
  	spin_lock_irqsave(&rtc->irq_task_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
487
488
  	if (rtc->irq_task)
  		rtc->irq_task->func(rtc->irq_task->private_data);
e6229bec2   Atsushi Nemoto   rtc: make rtc_upd...
489
  	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
490
491
492
493
  
  	wake_up_interruptible(&rtc->irq_queue);
  	kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
  }
6610e0893   John Stultz   RTC: Rework RTC c...
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
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
  
  
  /**
   * 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)
  {
  	schedule_work(&rtc->irqwork);
  }
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
557
  EXPORT_SYMBOL_GPL(rtc_update_irq);
71da89050   Dave Young   rtc: use class it...
558
559
560
  static int __rtc_match(struct device *dev, void *data)
  {
  	char *name = (char *)data;
d4afc76c0   Kay Sievers   rtc: struct devic...
561
  	if (strcmp(dev_name(dev), name) == 0)
71da89050   Dave Young   rtc: use class it...
562
563
564
  		return 1;
  	return 0;
  }
ab6a2d70d   David Brownell   rtc: rtc interfac...
565
  struct rtc_device *rtc_class_open(char *name)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
566
  {
cd9662094   David Brownell   rtc: remove rest ...
567
  	struct device *dev;
ab6a2d70d   David Brownell   rtc: rtc interfac...
568
  	struct rtc_device *rtc = NULL;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
569

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

ab6a2d70d   David Brownell   rtc: rtc interfac...
574
575
  	if (rtc) {
  		if (!try_module_get(rtc->owner)) {
cd9662094   David Brownell   rtc: remove rest ...
576
  			put_device(dev);
ab6a2d70d   David Brownell   rtc: rtc interfac...
577
578
  			rtc = NULL;
  		}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
579
  	}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
580

ab6a2d70d   David Brownell   rtc: rtc interfac...
581
  	return rtc;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
582
583
  }
  EXPORT_SYMBOL_GPL(rtc_class_open);
ab6a2d70d   David Brownell   rtc: rtc interfac...
584
  void rtc_class_close(struct rtc_device *rtc)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
585
  {
ab6a2d70d   David Brownell   rtc: rtc interfac...
586
  	module_put(rtc->owner);
cd9662094   David Brownell   rtc: remove rest ...
587
  	put_device(&rtc->dev);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
588
589
  }
  EXPORT_SYMBOL_GPL(rtc_class_close);
ab6a2d70d   David Brownell   rtc: rtc interfac...
590
  int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
591
592
  {
  	int retval = -EBUSY;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
593
594
595
  
  	if (task == NULL || task->func == NULL)
  		return -EINVAL;
d691eb901   Alessandro Zummo   RTC: periodic irq...
596
  	/* Cannot register while the char dev is in use */
372a302e9   Jiri Kosina   RTC: assure prope...
597
  	if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
d691eb901   Alessandro Zummo   RTC: periodic irq...
598
  		return -EBUSY;
d728b1e69   David Brownell   [PATCH] rtc class...
599
  	spin_lock_irq(&rtc->irq_task_lock);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
600
601
602
603
  	if (rtc->irq_task == NULL) {
  		rtc->irq_task = task;
  		retval = 0;
  	}
d728b1e69   David Brownell   [PATCH] rtc class...
604
  	spin_unlock_irq(&rtc->irq_task_lock);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
605

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

0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
608
609
610
  	return retval;
  }
  EXPORT_SYMBOL_GPL(rtc_irq_register);
ab6a2d70d   David Brownell   rtc: rtc interfac...
611
  void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
612
  {
d728b1e69   David Brownell   [PATCH] rtc class...
613
  	spin_lock_irq(&rtc->irq_task_lock);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
614
615
  	if (rtc->irq_task == task)
  		rtc->irq_task = NULL;
d728b1e69   David Brownell   [PATCH] rtc class...
616
  	spin_unlock_irq(&rtc->irq_task_lock);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
617
618
  }
  EXPORT_SYMBOL_GPL(rtc_irq_unregister);
3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
  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(...
641
642
643
644
645
646
647
648
649
650
  /**
   * 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...
651
  int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
652
653
654
  {
  	int err = 0;
  	unsigned long flags;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
655

3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
656
  retry:
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
657
  	spin_lock_irqsave(&rtc->irq_task_lock, flags);
d691eb901   Alessandro Zummo   RTC: periodic irq...
658
659
  	if (rtc->irq_task != NULL && task == NULL)
  		err = -EBUSY;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
660
  	if (rtc->irq_task != task)
d691eb901   Alessandro Zummo   RTC: periodic irq...
661
  		err = -EACCES;
3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
662
663
664
665
666
667
668
  	if (!err) {
  		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...
669
  	}
6610e0893   John Stultz   RTC: Rework RTC c...
670
  	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
671
672
673
  	return err;
  }
  EXPORT_SYMBOL_GPL(rtc_irq_set_state);
97144c675   David Brownell   rtc_irq_set_freq(...
674
675
676
677
678
679
680
681
682
683
  /**
   * 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...
684
  int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
685
  {
56f10c634   Alessandro Zummo   [PATCH] rtc subsy...
686
  	int err = 0;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
687
  	unsigned long flags;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
688

6e7a333ea   Thomas Gleixner   rtc: Limit RTC PI...
689
  	if (freq <= 0 || freq > RTC_MAX_FREQ)
83a06bf50   Marcelo Roberto Jimenez   RTC: Prevents a d...
690
  		return -EINVAL;
3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
691
  retry:
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
692
  	spin_lock_irqsave(&rtc->irq_task_lock, flags);
d691eb901   Alessandro Zummo   RTC: periodic irq...
693
694
  	if (rtc->irq_task != NULL && task == NULL)
  		err = -EBUSY;
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
695
  	if (rtc->irq_task != task)
d691eb901   Alessandro Zummo   RTC: periodic irq...
696
  		err = -EACCES;
3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
697
  	if (!err) {
6610e0893   John Stultz   RTC: Rework RTC c...
698
  		rtc->irq_freq = freq;
3c8bb90ef   Thomas Gleixner   rtc: Fix hrtimer ...
699
700
701
702
  		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...
703
  		}
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
704
  	}
6610e0893   John Stultz   RTC: Rework RTC c...
705
  	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
0c86edc0d   Alessandro Zummo   [PATCH] RTC subsy...
706
707
  	return err;
  }
2601a4647   David Brownell   [PATCH] rtc frame...
708
  EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
6610e0893   John Stultz   RTC: Rework RTC c...
709
710
  
  /**
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
711
   * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue
6610e0893   John Stultz   RTC: Rework RTC c...
712
713
714
715
716
717
   * @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...
718
719
   * Sets the enabled bit on the added timer.
   *
6610e0893   John Stultz   RTC: Rework RTC c...
720
721
   * Must hold ops_lock for proper serialization of timerqueue
   */
aa0be0f46   John Stultz   RTC: Propagate er...
722
  static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
6610e0893   John Stultz   RTC: Rework RTC c...
723
  {
aa0be0f46   John Stultz   RTC: Propagate er...
724
  	timer->enabled = 1;
6610e0893   John Stultz   RTC: Rework RTC c...
725
726
727
728
729
730
731
732
733
  	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);
  		if (err == -ETIME)
  			schedule_work(&rtc->irqwork);
aa0be0f46   John Stultz   RTC: Propagate er...
734
735
736
737
738
  		else if (err) {
  			timerqueue_del(&rtc->timerqueue, &timer->node);
  			timer->enabled = 0;
  			return err;
  		}
6610e0893   John Stultz   RTC: Rework RTC c...
739
  	}
aa0be0f46   John Stultz   RTC: Propagate er...
740
  	return 0;
6610e0893   John Stultz   RTC: Rework RTC c...
741
742
743
  }
  
  /**
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
744
   * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
6610e0893   John Stultz   RTC: Rework RTC c...
745
746
747
748
749
750
   * @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...
751
752
   * Clears the enabled bit on the removed timer.
   *
6610e0893   John Stultz   RTC: Rework RTC c...
753
754
   * Must hold ops_lock for proper serialization of timerqueue
   */
aa0be0f46   John Stultz   RTC: Propagate er...
755
  static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
6610e0893   John Stultz   RTC: Rework RTC c...
756
757
758
  {
  	struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
  	timerqueue_del(&rtc->timerqueue, &timer->node);
aa0be0f46   John Stultz   RTC: Propagate er...
759
  	timer->enabled = 0;
6610e0893   John Stultz   RTC: Rework RTC c...
760
761
762
763
  	if (next == &timer->node) {
  		struct rtc_wkalrm alarm;
  		int err;
  		next = timerqueue_getnext(&rtc->timerqueue);
157e8bf8b   Linus Torvalds   Revert "rtc: Disa...
764
  		if (!next)
6610e0893   John Stultz   RTC: Rework RTC c...
765
766
767
768
769
770
771
772
773
774
  			return;
  		alarm.time = rtc_ktime_to_tm(next->expires);
  		alarm.enabled = 1;
  		err = __rtc_set_alarm(rtc, &alarm);
  		if (err == -ETIME)
  			schedule_work(&rtc->irqwork);
  	}
  }
  
  /**
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
775
   * rtc_timer_do_work - Expires rtc timers
6610e0893   John Stultz   RTC: Rework RTC c...
776
777
778
779
780
781
782
783
   * @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
784
  void rtc_timer_do_work(struct work_struct *work)
6610e0893   John Stultz   RTC: Rework RTC c...
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
  {
  	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;
157e8bf8b   Linus Torvalds   Revert "rtc: Disa...
827
  	}
6610e0893   John Stultz   RTC: Rework RTC c...
828
829
830
  
  	mutex_unlock(&rtc->ops_lock);
  }
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
831
  /* rtc_timer_init - Initializes an rtc_timer
6610e0893   John Stultz   RTC: Rework RTC c...
832
833
834
835
836
837
   * @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.
   */
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
838
  void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data)
6610e0893   John Stultz   RTC: Rework RTC c...
839
840
841
842
843
844
  {
  	timerqueue_init(&timer->node);
  	timer->enabled = 0;
  	timer->task.func = f;
  	timer->task.private_data = data;
  }
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
845
  /* rtc_timer_start - Sets an rtc_timer to fire in the future
6610e0893   John Stultz   RTC: Rework RTC c...
846
847
848
849
850
851
852
   * @ 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
   */
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
853
  int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
6610e0893   John Stultz   RTC: Rework RTC c...
854
855
856
857
858
  			ktime_t expires, ktime_t period)
  {
  	int ret = 0;
  	mutex_lock(&rtc->ops_lock);
  	if (timer->enabled)
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
859
  		rtc_timer_remove(rtc, timer);
6610e0893   John Stultz   RTC: Rework RTC c...
860
861
862
  
  	timer->node.expires = expires;
  	timer->period = period;
aa0be0f46   John Stultz   RTC: Propagate er...
863
  	ret = rtc_timer_enqueue(rtc, timer);
6610e0893   John Stultz   RTC: Rework RTC c...
864
865
866
867
  
  	mutex_unlock(&rtc->ops_lock);
  	return ret;
  }
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
868
  /* rtc_timer_cancel - Stops an rtc_timer
6610e0893   John Stultz   RTC: Rework RTC c...
869
870
871
872
873
   * @ rtc: rtc device to be used
   * @ timer: timer being set
   *
   * Kernel interface to cancel an rtc_timer
   */
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
874
  int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer)
6610e0893   John Stultz   RTC: Rework RTC c...
875
876
877
878
  {
  	int ret = 0;
  	mutex_lock(&rtc->ops_lock);
  	if (timer->enabled)
96c8f06a0   Thomas Gleixner   rtc: Namespace fixup
879
  		rtc_timer_remove(rtc, timer);
6610e0893   John Stultz   RTC: Rework RTC c...
880
881
882
  	mutex_unlock(&rtc->ops_lock);
  	return ret;
  }