1cdf7545aSAlexandre Belloni // SPDX-License-Identifier: GPL-2.0
20c86edc0SAlessandro Zummo /*
30c86edc0SAlessandro Zummo * RTC subsystem, interface functions
40c86edc0SAlessandro Zummo *
50c86edc0SAlessandro Zummo * Copyright (C) 2005 Tower Technologies
60c86edc0SAlessandro Zummo * Author: Alessandro Zummo <a.zummo@towertech.it>
70c86edc0SAlessandro Zummo *
80c86edc0SAlessandro Zummo * based on arch/arm/common/rtctime.c
90c86edc0SAlessandro Zummo */
100c86edc0SAlessandro Zummo
110c86edc0SAlessandro Zummo #include <linux/rtc.h>
12d43c36dcSAlexey Dobriyan #include <linux/sched.h>
132113852bSPaul Gortmaker #include <linux/module.h>
1497144c67SDavid Brownell #include <linux/log2.h>
156610e089SJohn Stultz #include <linux/workqueue.h>
166610e089SJohn Stultz
1729a1f599SBaolin Wang #define CREATE_TRACE_POINTS
1829a1f599SBaolin Wang #include <trace/events/rtc.h>
1929a1f599SBaolin Wang
20aa0be0f4SJohn Stultz static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer);
21aa0be0f4SJohn Stultz static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer);
22aa0be0f4SJohn Stultz
rtc_add_offset(struct rtc_device * rtc,struct rtc_time * tm)2398951564SBaolin Wang static void rtc_add_offset(struct rtc_device *rtc, struct rtc_time *tm)
2498951564SBaolin Wang {
2598951564SBaolin Wang time64_t secs;
2698951564SBaolin Wang
2798951564SBaolin Wang if (!rtc->offset_secs)
2898951564SBaolin Wang return;
2998951564SBaolin Wang
3098951564SBaolin Wang secs = rtc_tm_to_time64(tm);
3198951564SBaolin Wang
3298951564SBaolin Wang /*
3398951564SBaolin Wang * Since the reading time values from RTC device are always in the RTC
3498951564SBaolin Wang * original valid range, but we need to skip the overlapped region
3598951564SBaolin Wang * between expanded range and original range, which is no need to add
3698951564SBaolin Wang * the offset.
3798951564SBaolin Wang */
3898951564SBaolin Wang if ((rtc->start_secs > rtc->range_min && secs >= rtc->start_secs) ||
3998951564SBaolin Wang (rtc->start_secs < rtc->range_min &&
4098951564SBaolin Wang secs <= (rtc->start_secs + rtc->range_max - rtc->range_min)))
4198951564SBaolin Wang return;
4298951564SBaolin Wang
4398951564SBaolin Wang rtc_time64_to_tm(secs + rtc->offset_secs, tm);
4498951564SBaolin Wang }
4598951564SBaolin Wang
rtc_subtract_offset(struct rtc_device * rtc,struct rtc_time * tm)4698951564SBaolin Wang static void rtc_subtract_offset(struct rtc_device *rtc, struct rtc_time *tm)
4798951564SBaolin Wang {
4898951564SBaolin Wang time64_t secs;
4998951564SBaolin Wang
5098951564SBaolin Wang if (!rtc->offset_secs)
5198951564SBaolin Wang return;
5298951564SBaolin Wang
5398951564SBaolin Wang secs = rtc_tm_to_time64(tm);
5498951564SBaolin Wang
5598951564SBaolin Wang /*
5698951564SBaolin Wang * If the setting time values are in the valid range of RTC hardware
5798951564SBaolin Wang * device, then no need to subtract the offset when setting time to RTC
5898951564SBaolin Wang * device. Otherwise we need to subtract the offset to make the time
5998951564SBaolin Wang * values are valid for RTC hardware device.
6098951564SBaolin Wang */
6198951564SBaolin Wang if (secs >= rtc->range_min && secs <= rtc->range_max)
6298951564SBaolin Wang return;
6398951564SBaolin Wang
6498951564SBaolin Wang rtc_time64_to_tm(secs - rtc->offset_secs, tm);
6598951564SBaolin Wang }
6698951564SBaolin Wang
rtc_valid_range(struct rtc_device * rtc,struct rtc_time * tm)674c4e5df1SBaolin Wang static int rtc_valid_range(struct rtc_device *rtc, struct rtc_time *tm)
684c4e5df1SBaolin Wang {
694c4e5df1SBaolin Wang if (rtc->range_min != rtc->range_max) {
704c4e5df1SBaolin Wang time64_t time = rtc_tm_to_time64(tm);
7198951564SBaolin Wang time64_t range_min = rtc->set_start_time ? rtc->start_secs :
7298951564SBaolin Wang rtc->range_min;
73eaa6ef56SEmmanuel Nicolet timeu64_t range_max = rtc->set_start_time ?
7498951564SBaolin Wang (rtc->start_secs + rtc->range_max - rtc->range_min) :
7598951564SBaolin Wang rtc->range_max;
764c4e5df1SBaolin Wang
7798951564SBaolin Wang if (time < range_min || time > range_max)
784c4e5df1SBaolin Wang return -ERANGE;
794c4e5df1SBaolin Wang }
804c4e5df1SBaolin Wang
814c4e5df1SBaolin Wang return 0;
824c4e5df1SBaolin Wang }
834c4e5df1SBaolin Wang
__rtc_read_time(struct rtc_device * rtc,struct rtc_time * tm)846610e089SJohn Stultz static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
856610e089SJohn Stultz {
866610e089SJohn Stultz int err;
87606cc43cSAlexandre Belloni
88606cc43cSAlexandre Belloni if (!rtc->ops) {
896610e089SJohn Stultz err = -ENODEV;
90606cc43cSAlexandre Belloni } else if (!rtc->ops->read_time) {
916610e089SJohn Stultz err = -EINVAL;
92606cc43cSAlexandre Belloni } else {
936610e089SJohn Stultz memset(tm, 0, sizeof(struct rtc_time));
946610e089SJohn Stultz err = rtc->ops->read_time(rtc->dev.parent, tm);
9516682c86SHyogi Gim if (err < 0) {
96d0bddb51SAaro Koskinen dev_dbg(&rtc->dev, "read_time: fail to read: %d\n",
97d0bddb51SAaro Koskinen err);
9816682c86SHyogi Gim return err;
9916682c86SHyogi Gim }
10016682c86SHyogi Gim
10198951564SBaolin Wang rtc_add_offset(rtc, tm);
10298951564SBaolin Wang
10316682c86SHyogi Gim err = rtc_valid_tm(tm);
10416682c86SHyogi Gim if (err < 0)
105d0bddb51SAaro Koskinen dev_dbg(&rtc->dev, "read_time: rtc_time isn't valid\n");
1066610e089SJohn Stultz }
1076610e089SJohn Stultz return err;
1086610e089SJohn Stultz }
1090c86edc0SAlessandro Zummo
rtc_read_time(struct rtc_device * rtc,struct rtc_time * tm)110ab6a2d70SDavid Brownell int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
1110c86edc0SAlessandro Zummo {
1120c86edc0SAlessandro Zummo int err;
1130c86edc0SAlessandro Zummo
1140c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock);
1150c86edc0SAlessandro Zummo if (err)
116b68bb263SDavid Brownell return err;
1170c86edc0SAlessandro Zummo
1186610e089SJohn Stultz err = __rtc_read_time(rtc, tm);
1190c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock);
12029a1f599SBaolin Wang
12129a1f599SBaolin Wang trace_rtc_read_time(rtc_tm_to_time64(tm), err);
1220c86edc0SAlessandro Zummo return err;
1230c86edc0SAlessandro Zummo }
1240c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_read_time);
1250c86edc0SAlessandro Zummo
rtc_set_time(struct rtc_device * rtc,struct rtc_time * tm)126ab6a2d70SDavid Brownell int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
1270c86edc0SAlessandro Zummo {
1287e7c005bSAlexandre Belloni int err, uie;
1290c86edc0SAlessandro Zummo
1300c86edc0SAlessandro Zummo err = rtc_valid_tm(tm);
1310c86edc0SAlessandro Zummo if (err != 0)
1320c86edc0SAlessandro Zummo return err;
1330c86edc0SAlessandro Zummo
1344c4e5df1SBaolin Wang err = rtc_valid_range(rtc, tm);
1354c4e5df1SBaolin Wang if (err)
1364c4e5df1SBaolin Wang return err;
13771db049eSAlexandre Belloni
13898951564SBaolin Wang rtc_subtract_offset(rtc, tm);
13998951564SBaolin Wang
1407e7c005bSAlexandre Belloni #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
1417e7c005bSAlexandre Belloni uie = rtc->uie_rtctimer.enabled || rtc->uie_irq_active;
1427e7c005bSAlexandre Belloni #else
1437e7c005bSAlexandre Belloni uie = rtc->uie_rtctimer.enabled;
1447e7c005bSAlexandre Belloni #endif
1457e7c005bSAlexandre Belloni if (uie) {
1467e7c005bSAlexandre Belloni err = rtc_update_irq_enable(rtc, 0);
1477e7c005bSAlexandre Belloni if (err)
1487e7c005bSAlexandre Belloni return err;
1497e7c005bSAlexandre Belloni }
1507e7c005bSAlexandre Belloni
1510c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock);
1520c86edc0SAlessandro Zummo if (err)
153b68bb263SDavid Brownell return err;
1540c86edc0SAlessandro Zummo
1550c86edc0SAlessandro Zummo if (!rtc->ops)
1560c86edc0SAlessandro Zummo err = -ENODEV;
157bbccf83fSAlessandro Zummo else if (rtc->ops->set_time)
158cd966209SDavid Brownell err = rtc->ops->set_time(rtc->dev.parent, tm);
159606cc43cSAlexandre Belloni else
160bbccf83fSAlessandro Zummo err = -EINVAL;
1610c86edc0SAlessandro Zummo
16214d0e347SZoran Markovic pm_stay_awake(rtc->dev.parent);
1630c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock);
1645f9679d2SNeilBrown /* A timer might have just expired */
1655f9679d2SNeilBrown schedule_work(&rtc->irqwork);
16629a1f599SBaolin Wang
1677e7c005bSAlexandre Belloni if (uie) {
1687e7c005bSAlexandre Belloni err = rtc_update_irq_enable(rtc, 1);
1697e7c005bSAlexandre Belloni if (err)
1707e7c005bSAlexandre Belloni return err;
1717e7c005bSAlexandre Belloni }
1727e7c005bSAlexandre Belloni
17329a1f599SBaolin Wang trace_rtc_set_time(rtc_tm_to_time64(tm), err);
1740c86edc0SAlessandro Zummo return err;
1750c86edc0SAlessandro Zummo }
1760c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_set_time);
1770c86edc0SAlessandro Zummo
rtc_read_alarm_internal(struct rtc_device * rtc,struct rtc_wkalrm * alarm)178606cc43cSAlexandre Belloni static int rtc_read_alarm_internal(struct rtc_device *rtc,
179606cc43cSAlexandre Belloni struct rtc_wkalrm *alarm)
180f44f7f96SJohn Stultz {
181f44f7f96SJohn Stultz int err;
182f44f7f96SJohn Stultz
183f44f7f96SJohn Stultz err = mutex_lock_interruptible(&rtc->ops_lock);
184f44f7f96SJohn Stultz if (err)
185f44f7f96SJohn Stultz return err;
186f44f7f96SJohn Stultz
187606cc43cSAlexandre Belloni if (!rtc->ops) {
188f44f7f96SJohn Stultz err = -ENODEV;
1897ae41220SAlexandre Belloni } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) {
190f44f7f96SJohn Stultz err = -EINVAL;
191606cc43cSAlexandre Belloni } else {
192d68778b8SUwe Kleine-König alarm->enabled = 0;
193d68778b8SUwe Kleine-König alarm->pending = 0;
194d68778b8SUwe Kleine-König alarm->time.tm_sec = -1;
195d68778b8SUwe Kleine-König alarm->time.tm_min = -1;
196d68778b8SUwe Kleine-König alarm->time.tm_hour = -1;
197d68778b8SUwe Kleine-König alarm->time.tm_mday = -1;
198d68778b8SUwe Kleine-König alarm->time.tm_mon = -1;
199d68778b8SUwe Kleine-König alarm->time.tm_year = -1;
200d68778b8SUwe Kleine-König alarm->time.tm_wday = -1;
201d68778b8SUwe Kleine-König alarm->time.tm_yday = -1;
202d68778b8SUwe Kleine-König alarm->time.tm_isdst = -1;
203f44f7f96SJohn Stultz err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
204f44f7f96SJohn Stultz }
205f44f7f96SJohn Stultz
206f44f7f96SJohn Stultz mutex_unlock(&rtc->ops_lock);
20729a1f599SBaolin Wang
20829a1f599SBaolin Wang trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
209f44f7f96SJohn Stultz return err;
210f44f7f96SJohn Stultz }
211f44f7f96SJohn Stultz
__rtc_read_alarm(struct rtc_device * rtc,struct rtc_wkalrm * alarm)212f44f7f96SJohn Stultz int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
213f44f7f96SJohn Stultz {
214f44f7f96SJohn Stultz int err;
215f44f7f96SJohn Stultz struct rtc_time before, now;
216f44f7f96SJohn Stultz int first_time = 1;
217bc10aa93SXunlei Pang time64_t t_now, t_alm;
218f44f7f96SJohn Stultz enum { none, day, month, year } missing = none;
219606cc43cSAlexandre Belloni unsigned int days;
220f44f7f96SJohn Stultz
221f44f7f96SJohn Stultz /* The lower level RTC driver may return -1 in some fields,
222f44f7f96SJohn Stultz * creating invalid alarm->time values, for reasons like:
223f44f7f96SJohn Stultz *
224f44f7f96SJohn Stultz * - The hardware may not be capable of filling them in;
225f44f7f96SJohn Stultz * many alarms match only on time-of-day fields, not
226f44f7f96SJohn Stultz * day/month/year calendar data.
227f44f7f96SJohn Stultz *
228f44f7f96SJohn Stultz * - Some hardware uses illegal values as "wildcard" match
229f44f7f96SJohn Stultz * values, which non-Linux firmware (like a BIOS) may try
230f44f7f96SJohn Stultz * to set up as e.g. "alarm 15 minutes after each hour".
231f44f7f96SJohn Stultz * Linux uses only oneshot alarms.
232f44f7f96SJohn Stultz *
233f44f7f96SJohn Stultz * When we see that here, we deal with it by using values from
234f44f7f96SJohn Stultz * a current RTC timestamp for any missing (-1) values. The
235f44f7f96SJohn Stultz * RTC driver prevents "periodic alarm" modes.
236f44f7f96SJohn Stultz *
237f44f7f96SJohn Stultz * But this can be racey, because some fields of the RTC timestamp
238f44f7f96SJohn Stultz * may have wrapped in the interval since we read the RTC alarm,
239f44f7f96SJohn Stultz * which would lead to us inserting inconsistent values in place
240f44f7f96SJohn Stultz * of the -1 fields.
241f44f7f96SJohn Stultz *
242f44f7f96SJohn Stultz * Reading the alarm and timestamp in the reverse sequence
243f44f7f96SJohn Stultz * would have the same race condition, and not solve the issue.
244f44f7f96SJohn Stultz *
245f44f7f96SJohn Stultz * So, we must first read the RTC timestamp,
246f44f7f96SJohn Stultz * then read the RTC alarm value,
247f44f7f96SJohn Stultz * and then read a second RTC timestamp.
248f44f7f96SJohn Stultz *
249f44f7f96SJohn Stultz * If any fields of the second timestamp have changed
250f44f7f96SJohn Stultz * when compared with the first timestamp, then we know
251f44f7f96SJohn Stultz * our timestamp may be inconsistent with that used by
252f44f7f96SJohn Stultz * the low-level rtc_read_alarm_internal() function.
253f44f7f96SJohn Stultz *
254f44f7f96SJohn Stultz * So, when the two timestamps disagree, we just loop and do
255f44f7f96SJohn Stultz * the process again to get a fully consistent set of values.
256f44f7f96SJohn Stultz *
257f44f7f96SJohn Stultz * This could all instead be done in the lower level driver,
258f44f7f96SJohn Stultz * but since more than one lower level RTC implementation needs it,
259b9354487Sshaomin Deng * then it's probably best to do it here instead of there..
260f44f7f96SJohn Stultz */
261f44f7f96SJohn Stultz
262f44f7f96SJohn Stultz /* Get the "before" timestamp */
263f44f7f96SJohn Stultz err = rtc_read_time(rtc, &before);
264f44f7f96SJohn Stultz if (err < 0)
265f44f7f96SJohn Stultz return err;
266f44f7f96SJohn Stultz do {
267f44f7f96SJohn Stultz if (!first_time)
268f44f7f96SJohn Stultz memcpy(&before, &now, sizeof(struct rtc_time));
269f44f7f96SJohn Stultz first_time = 0;
270f44f7f96SJohn Stultz
271f44f7f96SJohn Stultz /* get the RTC alarm values, which may be incomplete */
272f44f7f96SJohn Stultz err = rtc_read_alarm_internal(rtc, alarm);
273f44f7f96SJohn Stultz if (err)
274f44f7f96SJohn Stultz return err;
275f44f7f96SJohn Stultz
276f44f7f96SJohn Stultz /* full-function RTCs won't have such missing fields */
27799eb4449SCsókás, Bence err = rtc_valid_tm(&alarm->time);
27899eb4449SCsókás, Bence if (!err)
27999eb4449SCsókás, Bence goto done;
280f44f7f96SJohn Stultz
281f44f7f96SJohn Stultz /* get the "after" timestamp, to detect wrapped fields */
282f44f7f96SJohn Stultz err = rtc_read_time(rtc, &now);
283f44f7f96SJohn Stultz if (err < 0)
284f44f7f96SJohn Stultz return err;
285f44f7f96SJohn Stultz
286f44f7f96SJohn Stultz /* note that tm_sec is a "don't care" value here: */
287606cc43cSAlexandre Belloni } while (before.tm_min != now.tm_min ||
288606cc43cSAlexandre Belloni before.tm_hour != now.tm_hour ||
289606cc43cSAlexandre Belloni before.tm_mon != now.tm_mon ||
290606cc43cSAlexandre Belloni before.tm_year != now.tm_year);
291f44f7f96SJohn Stultz
292f44f7f96SJohn Stultz /* Fill in the missing alarm fields using the timestamp; we
293f44f7f96SJohn Stultz * know there's at least one since alarm->time is invalid.
294f44f7f96SJohn Stultz */
295f44f7f96SJohn Stultz if (alarm->time.tm_sec == -1)
296f44f7f96SJohn Stultz alarm->time.tm_sec = now.tm_sec;
297f44f7f96SJohn Stultz if (alarm->time.tm_min == -1)
298f44f7f96SJohn Stultz alarm->time.tm_min = now.tm_min;
299f44f7f96SJohn Stultz if (alarm->time.tm_hour == -1)
300f44f7f96SJohn Stultz alarm->time.tm_hour = now.tm_hour;
301f44f7f96SJohn Stultz
302f44f7f96SJohn Stultz /* For simplicity, only support date rollover for now */
303e74a8f2eSBen Hutchings if (alarm->time.tm_mday < 1 || alarm->time.tm_mday > 31) {
304f44f7f96SJohn Stultz alarm->time.tm_mday = now.tm_mday;
305f44f7f96SJohn Stultz missing = day;
306f44f7f96SJohn Stultz }
307606cc43cSAlexandre Belloni if ((unsigned int)alarm->time.tm_mon >= 12) {
308f44f7f96SJohn Stultz alarm->time.tm_mon = now.tm_mon;
309f44f7f96SJohn Stultz if (missing == none)
310f44f7f96SJohn Stultz missing = month;
311f44f7f96SJohn Stultz }
312f44f7f96SJohn Stultz if (alarm->time.tm_year == -1) {
313f44f7f96SJohn Stultz alarm->time.tm_year = now.tm_year;
314f44f7f96SJohn Stultz if (missing == none)
315f44f7f96SJohn Stultz missing = year;
316f44f7f96SJohn Stultz }
317f44f7f96SJohn Stultz
318da96aea0SVaibhav Jain /* Can't proceed if alarm is still invalid after replacing
319da96aea0SVaibhav Jain * missing fields.
320da96aea0SVaibhav Jain */
321da96aea0SVaibhav Jain err = rtc_valid_tm(&alarm->time);
322da96aea0SVaibhav Jain if (err)
323da96aea0SVaibhav Jain goto done;
324da96aea0SVaibhav Jain
325f44f7f96SJohn Stultz /* with luck, no rollover is needed */
326bc10aa93SXunlei Pang t_now = rtc_tm_to_time64(&now);
327bc10aa93SXunlei Pang t_alm = rtc_tm_to_time64(&alarm->time);
328f44f7f96SJohn Stultz if (t_now < t_alm)
329f44f7f96SJohn Stultz goto done;
330f44f7f96SJohn Stultz
331f44f7f96SJohn Stultz switch (missing) {
332f44f7f96SJohn Stultz /* 24 hour rollover ... if it's now 10am Monday, an alarm that
333f44f7f96SJohn Stultz * that will trigger at 5am will do so at 5am Tuesday, which
334f44f7f96SJohn Stultz * could also be in the next month or year. This is a common
335f44f7f96SJohn Stultz * case, especially for PCs.
336f44f7f96SJohn Stultz */
337f44f7f96SJohn Stultz case day:
338f44f7f96SJohn Stultz dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
339f44f7f96SJohn Stultz t_alm += 24 * 60 * 60;
340bc10aa93SXunlei Pang rtc_time64_to_tm(t_alm, &alarm->time);
341f44f7f96SJohn Stultz break;
342f44f7f96SJohn Stultz
343f44f7f96SJohn Stultz /* Month rollover ... if it's the 31th, an alarm on the 3rd will
344f44f7f96SJohn Stultz * be next month. An alarm matching on the 30th, 29th, or 28th
345f44f7f96SJohn Stultz * may end up in the month after that! Many newer PCs support
346f44f7f96SJohn Stultz * this type of alarm.
347f44f7f96SJohn Stultz */
348f44f7f96SJohn Stultz case month:
349f44f7f96SJohn Stultz dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
350f44f7f96SJohn Stultz do {
351606cc43cSAlexandre Belloni if (alarm->time.tm_mon < 11) {
352f44f7f96SJohn Stultz alarm->time.tm_mon++;
353606cc43cSAlexandre Belloni } else {
354f44f7f96SJohn Stultz alarm->time.tm_mon = 0;
355f44f7f96SJohn Stultz alarm->time.tm_year++;
356f44f7f96SJohn Stultz }
357f44f7f96SJohn Stultz days = rtc_month_days(alarm->time.tm_mon,
358f44f7f96SJohn Stultz alarm->time.tm_year);
359f44f7f96SJohn Stultz } while (days < alarm->time.tm_mday);
360f44f7f96SJohn Stultz break;
361f44f7f96SJohn Stultz
362f44f7f96SJohn Stultz /* Year rollover ... easy except for leap years! */
363f44f7f96SJohn Stultz case year:
364f44f7f96SJohn Stultz dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
365f44f7f96SJohn Stultz do {
366f44f7f96SJohn Stultz alarm->time.tm_year++;
367606cc43cSAlexandre Belloni } while (!is_leap_year(alarm->time.tm_year + 1900) &&
368606cc43cSAlexandre Belloni rtc_valid_tm(&alarm->time) != 0);
369f44f7f96SJohn Stultz break;
370f44f7f96SJohn Stultz
371f44f7f96SJohn Stultz default:
372f44f7f96SJohn Stultz dev_warn(&rtc->dev, "alarm rollover not handled\n");
373f44f7f96SJohn Stultz }
374f44f7f96SJohn Stultz
375ee1d9014SAles Novak err = rtc_valid_tm(&alarm->time);
376ee1d9014SAles Novak
377da96aea0SVaibhav Jain done:
378348c11a7SAlexandre Belloni if (err && alarm->enabled)
379606cc43cSAlexandre Belloni dev_warn(&rtc->dev, "invalid alarm value: %ptR\n",
380606cc43cSAlexandre Belloni &alarm->time);
38199eb4449SCsókás, Bence else
38299eb4449SCsókás, Bence rtc_add_offset(rtc, &alarm->time);
383ee1d9014SAles Novak
384ee1d9014SAles Novak return err;
385f44f7f96SJohn Stultz }
386f44f7f96SJohn Stultz
rtc_read_alarm(struct rtc_device * rtc,struct rtc_wkalrm * alarm)3876610e089SJohn Stultz int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
3880c86edc0SAlessandro Zummo {
3890c86edc0SAlessandro Zummo int err;
3900c86edc0SAlessandro Zummo
3910c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock);
3920c86edc0SAlessandro Zummo if (err)
393b68bb263SDavid Brownell return err;
394606cc43cSAlexandre Belloni if (!rtc->ops) {
395d5553a55SJohn Stultz err = -ENODEV;
396a783c962SAlexandre Belloni } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) {
397d5553a55SJohn Stultz err = -EINVAL;
398606cc43cSAlexandre Belloni } else {
399d5553a55SJohn Stultz memset(alarm, 0, sizeof(struct rtc_wkalrm));
4006610e089SJohn Stultz alarm->enabled = rtc->aie_timer.enabled;
4016610e089SJohn Stultz alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires);
402d5553a55SJohn Stultz }
4030c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock);
4040e36a9a4SMark Lord
40529a1f599SBaolin Wang trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err);
406d5553a55SJohn Stultz return err;
4070e36a9a4SMark Lord }
4080c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_read_alarm);
4090c86edc0SAlessandro Zummo
__rtc_set_alarm(struct rtc_device * rtc,struct rtc_wkalrm * alarm)410d576fe49SMark Brown static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
4116610e089SJohn Stultz {
4126610e089SJohn Stultz struct rtc_time tm;
413bc10aa93SXunlei Pang time64_t now, scheduled;
4146610e089SJohn Stultz int err;
4156610e089SJohn Stultz
4166610e089SJohn Stultz err = rtc_valid_tm(&alarm->time);
4176610e089SJohn Stultz if (err)
4186610e089SJohn Stultz return err;
41998951564SBaolin Wang
420bc10aa93SXunlei Pang scheduled = rtc_tm_to_time64(&alarm->time);
4216610e089SJohn Stultz
4226610e089SJohn Stultz /* Make sure we're not setting alarms in the past */
4236610e089SJohn Stultz err = __rtc_read_time(rtc, &tm);
424ca6dc2daSHyogi Gim if (err)
425ca6dc2daSHyogi Gim return err;
426bc10aa93SXunlei Pang now = rtc_tm_to_time64(&tm);
427d87f741dSAlexandre Belloni
4286610e089SJohn Stultz if (scheduled <= now)
4296610e089SJohn Stultz return -ETIME;
4306610e089SJohn Stultz /*
4316610e089SJohn Stultz * XXX - We just checked to make sure the alarm time is not
4326610e089SJohn Stultz * in the past, but there is still a race window where if
4336610e089SJohn Stultz * the is alarm set for the next second and the second ticks
4346610e089SJohn Stultz * over right here, before we set the alarm.
4356610e089SJohn Stultz */
4366610e089SJohn Stultz
437fd6792bbSAlexandre Belloni rtc_subtract_offset(rtc, &alarm->time);
438fd6792bbSAlexandre Belloni
439157e8bf8SLinus Torvalds if (!rtc->ops)
440157e8bf8SLinus Torvalds err = -ENODEV;
4417ae41220SAlexandre Belloni else if (!test_bit(RTC_FEATURE_ALARM, rtc->features))
442157e8bf8SLinus Torvalds err = -EINVAL;
443157e8bf8SLinus Torvalds else
444157e8bf8SLinus Torvalds err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
445157e8bf8SLinus Torvalds
44629a1f599SBaolin Wang trace_rtc_set_alarm(rtc_tm_to_time64(&alarm->time), err);
447157e8bf8SLinus Torvalds return err;
4486610e089SJohn Stultz }
4496610e089SJohn Stultz
rtc_set_alarm(struct rtc_device * rtc,struct rtc_wkalrm * alarm)450ab6a2d70SDavid Brownell int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
4510c86edc0SAlessandro Zummo {
452d87f741dSAlexandre Belloni ktime_t alarm_time;
4530c86edc0SAlessandro Zummo int err;
4540c86edc0SAlessandro Zummo
455abfdff44SAlexandre Belloni if (!rtc->ops)
456abfdff44SAlexandre Belloni return -ENODEV;
4577ae41220SAlexandre Belloni else if (!test_bit(RTC_FEATURE_ALARM, rtc->features))
458abfdff44SAlexandre Belloni return -EINVAL;
459abfdff44SAlexandre Belloni
460f8245c26SDavid Brownell err = rtc_valid_tm(&alarm->time);
461f8245c26SDavid Brownell if (err != 0)
462f8245c26SDavid Brownell return err;
463f8245c26SDavid Brownell
4644c4e5df1SBaolin Wang err = rtc_valid_range(rtc, &alarm->time);
4654c4e5df1SBaolin Wang if (err)
4664c4e5df1SBaolin Wang return err;
46771db049eSAlexandre Belloni
4680c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock);
4690c86edc0SAlessandro Zummo if (err)
470b68bb263SDavid Brownell return err;
4713ff2e13cSSachin Kamat if (rtc->aie_timer.enabled)
47296c8f06aSThomas Gleixner rtc_timer_remove(rtc, &rtc->aie_timer);
4733ff2e13cSSachin Kamat
474d87f741dSAlexandre Belloni alarm_time = rtc_tm_to_ktime(alarm->time);
475d87f741dSAlexandre Belloni /*
476d87f741dSAlexandre Belloni * Round down so we never miss a deadline, checking for past deadline is
477d87f741dSAlexandre Belloni * done in __rtc_set_alarm
478d87f741dSAlexandre Belloni */
479d87f741dSAlexandre Belloni if (test_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features))
480d87f741dSAlexandre Belloni alarm_time = ktime_sub_ns(alarm_time, (u64)alarm->time.tm_sec * NSEC_PER_SEC);
481d87f741dSAlexandre Belloni
482d87f741dSAlexandre Belloni rtc->aie_timer.node.expires = alarm_time;
4838b0e1953SThomas Gleixner rtc->aie_timer.period = 0;
4843ff2e13cSSachin Kamat if (alarm->enabled)
485aa0be0f4SJohn Stultz err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
4863ff2e13cSSachin Kamat
4870c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock);
48898951564SBaolin Wang
489aa0be0f4SJohn Stultz return err;
4900c86edc0SAlessandro Zummo }
4910c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_set_alarm);
4920c86edc0SAlessandro Zummo
493f6d5b331SJohn Stultz /* Called once per device from rtc_device_register */
rtc_initialize_alarm(struct rtc_device * rtc,struct rtc_wkalrm * alarm)494f6d5b331SJohn Stultz int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
495f6d5b331SJohn Stultz {
496f6d5b331SJohn Stultz int err;
497bd729d72SJohn Stultz struct rtc_time now;
498f6d5b331SJohn Stultz
499f6d5b331SJohn Stultz err = rtc_valid_tm(&alarm->time);
500f6d5b331SJohn Stultz if (err != 0)
501f6d5b331SJohn Stultz return err;
502f6d5b331SJohn Stultz
503bd729d72SJohn Stultz err = rtc_read_time(rtc, &now);
504bd729d72SJohn Stultz if (err)
505bd729d72SJohn Stultz return err;
506bd729d72SJohn Stultz
507f6d5b331SJohn Stultz err = mutex_lock_interruptible(&rtc->ops_lock);
508f6d5b331SJohn Stultz if (err)
509f6d5b331SJohn Stultz return err;
510f6d5b331SJohn Stultz
511f6d5b331SJohn Stultz rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
5128b0e1953SThomas Gleixner rtc->aie_timer.period = 0;
513bd729d72SJohn Stultz
5146785b3b6SUwe Kleine-König /* Alarm has to be enabled & in the future for us to enqueue it */
5152456e855SThomas Gleixner if (alarm->enabled && (rtc_tm_to_ktime(now) <
5162456e855SThomas Gleixner rtc->aie_timer.node.expires)) {
517f6d5b331SJohn Stultz rtc->aie_timer.enabled = 1;
518f6d5b331SJohn Stultz timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node);
51929a1f599SBaolin Wang trace_rtc_timer_enqueue(&rtc->aie_timer);
520f6d5b331SJohn Stultz }
521f6d5b331SJohn Stultz mutex_unlock(&rtc->ops_lock);
522f6d5b331SJohn Stultz return err;
523f6d5b331SJohn Stultz }
524f6d5b331SJohn Stultz EXPORT_SYMBOL_GPL(rtc_initialize_alarm);
525f6d5b331SJohn Stultz
rtc_alarm_irq_enable(struct rtc_device * rtc,unsigned int enabled)526099e6576SAlessandro Zummo int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
527099e6576SAlessandro Zummo {
528606cc43cSAlexandre Belloni int err;
529606cc43cSAlexandre Belloni
530606cc43cSAlexandre Belloni err = mutex_lock_interruptible(&rtc->ops_lock);
531099e6576SAlessandro Zummo if (err)
532099e6576SAlessandro Zummo return err;
533099e6576SAlessandro Zummo
5346610e089SJohn Stultz if (rtc->aie_timer.enabled != enabled) {
535aa0be0f4SJohn Stultz if (enabled)
536aa0be0f4SJohn Stultz err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
537aa0be0f4SJohn Stultz else
53896c8f06aSThomas Gleixner rtc_timer_remove(rtc, &rtc->aie_timer);
5396610e089SJohn Stultz }
540aa0be0f4SJohn Stultz
541aa0be0f4SJohn Stultz if (err)
542516373b8SUwe Kleine-König /* nothing */;
543516373b8SUwe Kleine-König else if (!rtc->ops)
544099e6576SAlessandro Zummo err = -ENODEV;
5457ae41220SAlexandre Belloni else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->alarm_irq_enable)
546099e6576SAlessandro Zummo err = -EINVAL;
547099e6576SAlessandro Zummo else
548099e6576SAlessandro Zummo err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
549099e6576SAlessandro Zummo
550099e6576SAlessandro Zummo mutex_unlock(&rtc->ops_lock);
55129a1f599SBaolin Wang
55229a1f599SBaolin Wang trace_rtc_alarm_irq_enable(enabled, err);
553099e6576SAlessandro Zummo return err;
554099e6576SAlessandro Zummo }
555099e6576SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
556099e6576SAlessandro Zummo
rtc_update_irq_enable(struct rtc_device * rtc,unsigned int enabled)557099e6576SAlessandro Zummo int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
558099e6576SAlessandro Zummo {
559c55c3a51SAlexandre Belloni int err;
560606cc43cSAlexandre Belloni
561606cc43cSAlexandre Belloni err = mutex_lock_interruptible(&rtc->ops_lock);
562099e6576SAlessandro Zummo if (err)
563099e6576SAlessandro Zummo return err;
564099e6576SAlessandro Zummo
565456d66ecSJohn Stultz #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
566456d66ecSJohn Stultz if (enabled == 0 && rtc->uie_irq_active) {
567456d66ecSJohn Stultz mutex_unlock(&rtc->ops_lock);
568456d66ecSJohn Stultz return rtc_dev_update_irq_enable_emul(rtc, 0);
569456d66ecSJohn Stultz }
570456d66ecSJohn Stultz #endif
5716610e089SJohn Stultz /* make sure we're changing state */
5726610e089SJohn Stultz if (rtc->uie_rtctimer.enabled == enabled)
5736610e089SJohn Stultz goto out;
5746610e089SJohn Stultz
575adb17a05SAlexandre Belloni if (!test_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features) ||
576adb17a05SAlexandre Belloni !test_bit(RTC_FEATURE_ALARM, rtc->features)) {
577c55c3a51SAlexandre Belloni mutex_unlock(&rtc->ops_lock);
578c55c3a51SAlexandre Belloni #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
579c55c3a51SAlexandre Belloni return rtc_dev_update_irq_enable_emul(rtc, enabled);
580c55c3a51SAlexandre Belloni #else
581c55c3a51SAlexandre Belloni return -EINVAL;
582c55c3a51SAlexandre Belloni #endif
5834a649903SJohn Stultz }
5844a649903SJohn Stultz
5856610e089SJohn Stultz if (enabled) {
5866610e089SJohn Stultz struct rtc_time tm;
5876610e089SJohn Stultz ktime_t now, onesec;
5886610e089SJohn Stultz
589c55c3a51SAlexandre Belloni err = __rtc_read_time(rtc, &tm);
590c55c3a51SAlexandre Belloni if (err)
5913e74ddaaSAlexandre Belloni goto out;
5926610e089SJohn Stultz onesec = ktime_set(1, 0);
5936610e089SJohn Stultz now = rtc_tm_to_ktime(tm);
5946610e089SJohn Stultz rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
5956610e089SJohn Stultz rtc->uie_rtctimer.period = ktime_set(1, 0);
596aa0be0f4SJohn Stultz err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
597606cc43cSAlexandre Belloni } else {
59896c8f06aSThomas Gleixner rtc_timer_remove(rtc, &rtc->uie_rtctimer);
599606cc43cSAlexandre Belloni }
600099e6576SAlessandro Zummo
6016610e089SJohn Stultz out:
602099e6576SAlessandro Zummo mutex_unlock(&rtc->ops_lock);
6033e74ddaaSAlexandre Belloni
604099e6576SAlessandro Zummo return err;
605099e6576SAlessandro Zummo }
606099e6576SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
607099e6576SAlessandro Zummo
608d728b1e6SDavid Brownell /**
6096610e089SJohn Stultz * rtc_handle_legacy_irq - AIE, UIE and PIE event hook
6106610e089SJohn Stultz * @rtc: pointer to the rtc device
61155dcf7a2SAlexandre Belloni * @num: number of occurence of the event
61255dcf7a2SAlexandre Belloni * @mode: type of the event, RTC_AF, RTC_UF of RTC_PF
6136610e089SJohn Stultz *
6146610e089SJohn Stultz * This function is called when an AIE, UIE or PIE mode interrupt
61525985edcSLucas De Marchi * has occurred (or been emulated).
6166610e089SJohn Stultz *
6176610e089SJohn Stultz */
rtc_handle_legacy_irq(struct rtc_device * rtc,int num,int mode)618456d66ecSJohn Stultz void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
6196610e089SJohn Stultz {
6206610e089SJohn Stultz unsigned long flags;
6216610e089SJohn Stultz
6226610e089SJohn Stultz /* mark one irq of the appropriate mode */
6236610e089SJohn Stultz spin_lock_irqsave(&rtc->irq_lock, flags);
6246610e089SJohn Stultz rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF | mode);
6256610e089SJohn Stultz spin_unlock_irqrestore(&rtc->irq_lock, flags);
6266610e089SJohn Stultz
6276610e089SJohn Stultz wake_up_interruptible(&rtc->irq_queue);
6286610e089SJohn Stultz kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
6296610e089SJohn Stultz }
6306610e089SJohn Stultz
6316610e089SJohn Stultz /**
6326610e089SJohn Stultz * rtc_aie_update_irq - AIE mode rtctimer hook
6339a032011SAlexandre Belloni * @rtc: pointer to the rtc_device
6346610e089SJohn Stultz *
6356610e089SJohn Stultz * This functions is called when the aie_timer expires.
6366610e089SJohn Stultz */
rtc_aie_update_irq(struct rtc_device * rtc)6379a032011SAlexandre Belloni void rtc_aie_update_irq(struct rtc_device *rtc)
6386610e089SJohn Stultz {
6396610e089SJohn Stultz rtc_handle_legacy_irq(rtc, 1, RTC_AF);
6406610e089SJohn Stultz }
6416610e089SJohn Stultz
6426610e089SJohn Stultz /**
6436610e089SJohn Stultz * rtc_uie_update_irq - UIE mode rtctimer hook
6449a032011SAlexandre Belloni * @rtc: pointer to the rtc_device
6456610e089SJohn Stultz *
6466610e089SJohn Stultz * This functions is called when the uie_timer expires.
6476610e089SJohn Stultz */
rtc_uie_update_irq(struct rtc_device * rtc)6489a032011SAlexandre Belloni void rtc_uie_update_irq(struct rtc_device *rtc)
6496610e089SJohn Stultz {
6506610e089SJohn Stultz rtc_handle_legacy_irq(rtc, 1, RTC_UF);
6516610e089SJohn Stultz }
6526610e089SJohn Stultz
6536610e089SJohn Stultz /**
6546610e089SJohn Stultz * rtc_pie_update_irq - PIE mode hrtimer hook
6556610e089SJohn Stultz * @timer: pointer to the pie mode hrtimer
6566610e089SJohn Stultz *
6576610e089SJohn Stultz * This function is used to emulate PIE mode interrupts
6586610e089SJohn Stultz * using an hrtimer. This function is called when the periodic
6596610e089SJohn Stultz * hrtimer expires.
6606610e089SJohn Stultz */
rtc_pie_update_irq(struct hrtimer * timer)6616610e089SJohn Stultz enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
6626610e089SJohn Stultz {
6636610e089SJohn Stultz struct rtc_device *rtc;
6646610e089SJohn Stultz ktime_t period;
6653126790dSPuranjay Mohan u64 count;
666606cc43cSAlexandre Belloni
6676610e089SJohn Stultz rtc = container_of(timer, struct rtc_device, pie_timer);
6686610e089SJohn Stultz
6698b0e1953SThomas Gleixner period = NSEC_PER_SEC / rtc->irq_freq;
6706610e089SJohn Stultz count = hrtimer_forward_now(timer, period);
6716610e089SJohn Stultz
6726610e089SJohn Stultz rtc_handle_legacy_irq(rtc, count, RTC_PF);
6736610e089SJohn Stultz
6746610e089SJohn Stultz return HRTIMER_RESTART;
6756610e089SJohn Stultz }
6766610e089SJohn Stultz
6776610e089SJohn Stultz /**
6786610e089SJohn Stultz * rtc_update_irq - Triggered when a RTC interrupt occurs.
679ab6a2d70SDavid Brownell * @rtc: the rtc device
680d728b1e6SDavid Brownell * @num: how many irqs are being reported (usually one)
681d728b1e6SDavid Brownell * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
682e6229becSAtsushi Nemoto * Context: any
683d728b1e6SDavid Brownell */
rtc_update_irq(struct rtc_device * rtc,unsigned long num,unsigned long events)684ab6a2d70SDavid Brownell void rtc_update_irq(struct rtc_device *rtc,
6850c86edc0SAlessandro Zummo unsigned long num, unsigned long events)
6860c86edc0SAlessandro Zummo {
687e7cba884Sviresh kumar if (IS_ERR_OR_NULL(rtc))
688131c9cc8SAlessandro Zummo return;
689131c9cc8SAlessandro Zummo
6907523ceedSNeilBrown pm_stay_awake(rtc->dev.parent);
6916610e089SJohn Stultz schedule_work(&rtc->irqwork);
6920c86edc0SAlessandro Zummo }
6930c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_update_irq);
6940c86edc0SAlessandro Zummo
rtc_class_open(const char * name)6959f3b795aSMichał Mirosław struct rtc_device *rtc_class_open(const char *name)
6960c86edc0SAlessandro Zummo {
697cd966209SDavid Brownell struct device *dev;
698ab6a2d70SDavid Brownell struct rtc_device *rtc = NULL;
6990c86edc0SAlessandro Zummo
7006cda08a2SSuzuki K Poulose dev = class_find_device_by_name(rtc_class, name);
701cd966209SDavid Brownell if (dev)
702cd966209SDavid Brownell rtc = to_rtc_device(dev);
7030c86edc0SAlessandro Zummo
704ab6a2d70SDavid Brownell if (rtc) {
705ab6a2d70SDavid Brownell if (!try_module_get(rtc->owner)) {
706cd966209SDavid Brownell put_device(dev);
707ab6a2d70SDavid Brownell rtc = NULL;
708ab6a2d70SDavid Brownell }
7090c86edc0SAlessandro Zummo }
7100c86edc0SAlessandro Zummo
711ab6a2d70SDavid Brownell return rtc;
7120c86edc0SAlessandro Zummo }
7130c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_class_open);
7140c86edc0SAlessandro Zummo
rtc_class_close(struct rtc_device * rtc)715ab6a2d70SDavid Brownell void rtc_class_close(struct rtc_device *rtc)
7160c86edc0SAlessandro Zummo {
717ab6a2d70SDavid Brownell module_put(rtc->owner);
718cd966209SDavid Brownell put_device(&rtc->dev);
7190c86edc0SAlessandro Zummo }
7200c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_class_close);
7210c86edc0SAlessandro Zummo
rtc_update_hrtimer(struct rtc_device * rtc,int enabled)7223c8bb90eSThomas Gleixner static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
7233c8bb90eSThomas Gleixner {
7243c8bb90eSThomas Gleixner /*
7253c8bb90eSThomas Gleixner * We always cancel the timer here first, because otherwise
7263c8bb90eSThomas Gleixner * we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
7273c8bb90eSThomas Gleixner * when we manage to start the timer before the callback
7283c8bb90eSThomas Gleixner * returns HRTIMER_RESTART.
7293c8bb90eSThomas Gleixner *
7303c8bb90eSThomas Gleixner * We cannot use hrtimer_cancel() here as a running callback
7313c8bb90eSThomas Gleixner * could be blocked on rtc->irq_task_lock and hrtimer_cancel()
7323c8bb90eSThomas Gleixner * would spin forever.
7333c8bb90eSThomas Gleixner */
7343c8bb90eSThomas Gleixner if (hrtimer_try_to_cancel(&rtc->pie_timer) < 0)
7353c8bb90eSThomas Gleixner return -1;
7363c8bb90eSThomas Gleixner
7373c8bb90eSThomas Gleixner if (enabled) {
7388b0e1953SThomas Gleixner ktime_t period = NSEC_PER_SEC / rtc->irq_freq;
7393c8bb90eSThomas Gleixner
7403c8bb90eSThomas Gleixner hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL);
7413c8bb90eSThomas Gleixner }
7423c8bb90eSThomas Gleixner return 0;
7433c8bb90eSThomas Gleixner }
7443c8bb90eSThomas Gleixner
74597144c67SDavid Brownell /**
74697144c67SDavid Brownell * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
74797144c67SDavid Brownell * @rtc: the rtc device
74897144c67SDavid Brownell * @enabled: true to enable periodic IRQs
74997144c67SDavid Brownell * Context: any
75097144c67SDavid Brownell *
75197144c67SDavid Brownell * Note that rtc_irq_set_freq() should previously have been used to
752acecb3adSAlexandre Belloni * specify the desired frequency of periodic IRQ.
75397144c67SDavid Brownell */
rtc_irq_set_state(struct rtc_device * rtc,int enabled)7548719d3c9SAlexandre Belloni int rtc_irq_set_state(struct rtc_device *rtc, int enabled)
7550c86edc0SAlessandro Zummo {
7560c86edc0SAlessandro Zummo int err = 0;
7570c86edc0SAlessandro Zummo
758acecb3adSAlexandre Belloni while (rtc_update_hrtimer(rtc, enabled) < 0)
7593c8bb90eSThomas Gleixner cpu_relax();
760acecb3adSAlexandre Belloni
7616610e089SJohn Stultz rtc->pie_enabled = enabled;
76229a1f599SBaolin Wang
76329a1f599SBaolin Wang trace_rtc_irq_set_state(enabled, err);
7640c86edc0SAlessandro Zummo return err;
7650c86edc0SAlessandro Zummo }
7660c86edc0SAlessandro Zummo
76797144c67SDavid Brownell /**
76897144c67SDavid Brownell * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
76997144c67SDavid Brownell * @rtc: the rtc device
770acecb3adSAlexandre Belloni * @freq: positive frequency
77197144c67SDavid Brownell * Context: any
77297144c67SDavid Brownell *
77397144c67SDavid Brownell * Note that rtc_irq_set_state() is used to enable or disable the
77497144c67SDavid Brownell * periodic IRQs.
77597144c67SDavid Brownell */
rtc_irq_set_freq(struct rtc_device * rtc,int freq)7768719d3c9SAlexandre Belloni int rtc_irq_set_freq(struct rtc_device *rtc, int freq)
7770c86edc0SAlessandro Zummo {
77856f10c63SAlessandro Zummo int err = 0;
7790c86edc0SAlessandro Zummo
7806e7a333eSThomas Gleixner if (freq <= 0 || freq > RTC_MAX_FREQ)
78183a06bf5SMarcelo Roberto Jimenez return -EINVAL;
782acecb3adSAlexandre Belloni
7830c86edc0SAlessandro Zummo rtc->irq_freq = freq;
784acecb3adSAlexandre Belloni while (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0)
7853c8bb90eSThomas Gleixner cpu_relax();
78629a1f599SBaolin Wang
78729a1f599SBaolin Wang trace_rtc_irq_set_freq(freq, err);
7880c86edc0SAlessandro Zummo return err;
7890c86edc0SAlessandro Zummo }
7906610e089SJohn Stultz
7916610e089SJohn Stultz /**
79296c8f06aSThomas Gleixner * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue
79355dcf7a2SAlexandre Belloni * @rtc: rtc device
79455dcf7a2SAlexandre Belloni * @timer: timer being added.
7956610e089SJohn Stultz *
7966610e089SJohn Stultz * Enqueues a timer onto the rtc devices timerqueue and sets
7976610e089SJohn Stultz * the next alarm event appropriately.
7986610e089SJohn Stultz *
799aa0be0f4SJohn Stultz * Sets the enabled bit on the added timer.
800aa0be0f4SJohn Stultz *
8016610e089SJohn Stultz * Must hold ops_lock for proper serialization of timerqueue
8026610e089SJohn Stultz */
rtc_timer_enqueue(struct rtc_device * rtc,struct rtc_timer * timer)803aa0be0f4SJohn Stultz static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
8046610e089SJohn Stultz {
8052b2f5ff0SColin Ian King struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
8062b2f5ff0SColin Ian King struct rtc_time tm;
8072b2f5ff0SColin Ian King ktime_t now;
808915593a7STom Rix int err;
809915593a7STom Rix
810915593a7STom Rix err = __rtc_read_time(rtc, &tm);
811915593a7STom Rix if (err)
812915593a7STom Rix return err;
8132b2f5ff0SColin Ian King
814aa0be0f4SJohn Stultz timer->enabled = 1;
8152b2f5ff0SColin Ian King now = rtc_tm_to_ktime(tm);
8162b2f5ff0SColin Ian King
8172b2f5ff0SColin Ian King /* Skip over expired timers */
8182b2f5ff0SColin Ian King while (next) {
8192456e855SThomas Gleixner if (next->expires >= now)
8202b2f5ff0SColin Ian King break;
8212b2f5ff0SColin Ian King next = timerqueue_iterate_next(next);
8222b2f5ff0SColin Ian King }
8232b2f5ff0SColin Ian King
8246610e089SJohn Stultz timerqueue_add(&rtc->timerqueue, &timer->node);
82529a1f599SBaolin Wang trace_rtc_timer_enqueue(timer);
82674717b28SAlexandre Belloni if (!next || ktime_before(timer->node.expires, next->expires)) {
8276610e089SJohn Stultz struct rtc_wkalrm alarm;
828606cc43cSAlexandre Belloni
8296610e089SJohn Stultz alarm.time = rtc_ktime_to_tm(timer->node.expires);
8306610e089SJohn Stultz alarm.enabled = 1;
8316610e089SJohn Stultz err = __rtc_set_alarm(rtc, &alarm);
83214d0e347SZoran Markovic if (err == -ETIME) {
83314d0e347SZoran Markovic pm_stay_awake(rtc->dev.parent);
8346610e089SJohn Stultz schedule_work(&rtc->irqwork);
83514d0e347SZoran Markovic } else if (err) {
836aa0be0f4SJohn Stultz timerqueue_del(&rtc->timerqueue, &timer->node);
83729a1f599SBaolin Wang trace_rtc_timer_dequeue(timer);
838aa0be0f4SJohn Stultz timer->enabled = 0;
839aa0be0f4SJohn Stultz return err;
8406610e089SJohn Stultz }
8416610e089SJohn Stultz }
842aa0be0f4SJohn Stultz return 0;
843aa0be0f4SJohn Stultz }
8446610e089SJohn Stultz
rtc_alarm_disable(struct rtc_device * rtc)84541c7f742SRabin Vincent static void rtc_alarm_disable(struct rtc_device *rtc)
84641c7f742SRabin Vincent {
8477ae41220SAlexandre Belloni if (!rtc->ops || !test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->alarm_irq_enable)
84841c7f742SRabin Vincent return;
84941c7f742SRabin Vincent
85041c7f742SRabin Vincent rtc->ops->alarm_irq_enable(rtc->dev.parent, false);
85129a1f599SBaolin Wang trace_rtc_alarm_irq_enable(0, 0);
85241c7f742SRabin Vincent }
85341c7f742SRabin Vincent
8546610e089SJohn Stultz /**
85596c8f06aSThomas Gleixner * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
85655dcf7a2SAlexandre Belloni * @rtc: rtc device
85755dcf7a2SAlexandre Belloni * @timer: timer being removed.
8586610e089SJohn Stultz *
8596610e089SJohn Stultz * Removes a timer onto the rtc devices timerqueue and sets
8606610e089SJohn Stultz * the next alarm event appropriately.
8616610e089SJohn Stultz *
862aa0be0f4SJohn Stultz * Clears the enabled bit on the removed timer.
863aa0be0f4SJohn Stultz *
8646610e089SJohn Stultz * Must hold ops_lock for proper serialization of timerqueue
8656610e089SJohn Stultz */
rtc_timer_remove(struct rtc_device * rtc,struct rtc_timer * timer)866aa0be0f4SJohn Stultz static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
8676610e089SJohn Stultz {
8686610e089SJohn Stultz struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
869606cc43cSAlexandre Belloni
8706610e089SJohn Stultz timerqueue_del(&rtc->timerqueue, &timer->node);
87129a1f599SBaolin Wang trace_rtc_timer_dequeue(timer);
872aa0be0f4SJohn Stultz timer->enabled = 0;
8736610e089SJohn Stultz if (next == &timer->node) {
8746610e089SJohn Stultz struct rtc_wkalrm alarm;
8756610e089SJohn Stultz int err;
876606cc43cSAlexandre Belloni
8776610e089SJohn Stultz next = timerqueue_getnext(&rtc->timerqueue);
87841c7f742SRabin Vincent if (!next) {
87941c7f742SRabin Vincent rtc_alarm_disable(rtc);
8806610e089SJohn Stultz return;
88141c7f742SRabin Vincent }
8826610e089SJohn Stultz alarm.time = rtc_ktime_to_tm(next->expires);
8836610e089SJohn Stultz alarm.enabled = 1;
8846610e089SJohn Stultz err = __rtc_set_alarm(rtc, &alarm);
88514d0e347SZoran Markovic if (err == -ETIME) {
88614d0e347SZoran Markovic pm_stay_awake(rtc->dev.parent);
8876610e089SJohn Stultz schedule_work(&rtc->irqwork);
8886610e089SJohn Stultz }
8896610e089SJohn Stultz }
89014d0e347SZoran Markovic }
8916610e089SJohn Stultz
8926610e089SJohn Stultz /**
89396c8f06aSThomas Gleixner * rtc_timer_do_work - Expires rtc timers
89455dcf7a2SAlexandre Belloni * @work: work item
8956610e089SJohn Stultz *
8966610e089SJohn Stultz * Expires rtc timers. Reprograms next alarm event if needed.
8976610e089SJohn Stultz * Called via worktask.
8986610e089SJohn Stultz *
8996610e089SJohn Stultz * Serializes access to timerqueue via ops_lock mutex
9006610e089SJohn Stultz */
rtc_timer_do_work(struct work_struct * work)90196c8f06aSThomas Gleixner void rtc_timer_do_work(struct work_struct *work)
9026610e089SJohn Stultz {
9036610e089SJohn Stultz struct rtc_timer *timer;
9046610e089SJohn Stultz struct timerqueue_node *next;
9056610e089SJohn Stultz ktime_t now;
9066610e089SJohn Stultz struct rtc_time tm;
907*dd4b1cbcSYongliang Gao int err;
9086610e089SJohn Stultz
9096610e089SJohn Stultz struct rtc_device *rtc =
9106610e089SJohn Stultz container_of(work, struct rtc_device, irqwork);
9116610e089SJohn Stultz
9126610e089SJohn Stultz mutex_lock(&rtc->ops_lock);
9136610e089SJohn Stultz again:
914*dd4b1cbcSYongliang Gao err = __rtc_read_time(rtc, &tm);
915*dd4b1cbcSYongliang Gao if (err) {
916*dd4b1cbcSYongliang Gao mutex_unlock(&rtc->ops_lock);
917*dd4b1cbcSYongliang Gao return;
918*dd4b1cbcSYongliang Gao }
9196610e089SJohn Stultz now = rtc_tm_to_ktime(tm);
9206610e089SJohn Stultz while ((next = timerqueue_getnext(&rtc->timerqueue))) {
9212456e855SThomas Gleixner if (next->expires > now)
9226610e089SJohn Stultz break;
9236610e089SJohn Stultz
9246610e089SJohn Stultz /* expire timer */
9256610e089SJohn Stultz timer = container_of(next, struct rtc_timer, node);
9266610e089SJohn Stultz timerqueue_del(&rtc->timerqueue, &timer->node);
92729a1f599SBaolin Wang trace_rtc_timer_dequeue(timer);
9286610e089SJohn Stultz timer->enabled = 0;
9295a5ba10fSAlexandre Belloni if (timer->func)
9309a032011SAlexandre Belloni timer->func(timer->rtc);
9316610e089SJohn Stultz
93229a1f599SBaolin Wang trace_rtc_timer_fired(timer);
9336610e089SJohn Stultz /* Re-add/fwd periodic timers */
9346610e089SJohn Stultz if (ktime_to_ns(timer->period)) {
9356610e089SJohn Stultz timer->node.expires = ktime_add(timer->node.expires,
9366610e089SJohn Stultz timer->period);
9376610e089SJohn Stultz timer->enabled = 1;
9386610e089SJohn Stultz timerqueue_add(&rtc->timerqueue, &timer->node);
93929a1f599SBaolin Wang trace_rtc_timer_enqueue(timer);
9406610e089SJohn Stultz }
9416610e089SJohn Stultz }
9426610e089SJohn Stultz
9436610e089SJohn Stultz /* Set next alarm */
9446610e089SJohn Stultz if (next) {
9456610e089SJohn Stultz struct rtc_wkalrm alarm;
9466610e089SJohn Stultz int err;
9476528b889SXunlei Pang int retry = 3;
9486528b889SXunlei Pang
9496610e089SJohn Stultz alarm.time = rtc_ktime_to_tm(next->expires);
9506610e089SJohn Stultz alarm.enabled = 1;
9516528b889SXunlei Pang reprogram:
9526610e089SJohn Stultz err = __rtc_set_alarm(rtc, &alarm);
953606cc43cSAlexandre Belloni if (err == -ETIME) {
9546610e089SJohn Stultz goto again;
955606cc43cSAlexandre Belloni } else if (err) {
9566528b889SXunlei Pang if (retry-- > 0)
9576528b889SXunlei Pang goto reprogram;
9586528b889SXunlei Pang
9596528b889SXunlei Pang timer = container_of(next, struct rtc_timer, node);
9606528b889SXunlei Pang timerqueue_del(&rtc->timerqueue, &timer->node);
96129a1f599SBaolin Wang trace_rtc_timer_dequeue(timer);
9626528b889SXunlei Pang timer->enabled = 0;
9636528b889SXunlei Pang dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err);
9646528b889SXunlei Pang goto again;
9656528b889SXunlei Pang }
966606cc43cSAlexandre Belloni } else {
96741c7f742SRabin Vincent rtc_alarm_disable(rtc);
968606cc43cSAlexandre Belloni }
9696610e089SJohn Stultz
97014d0e347SZoran Markovic pm_relax(rtc->dev.parent);
9716610e089SJohn Stultz mutex_unlock(&rtc->ops_lock);
9726610e089SJohn Stultz }
9736610e089SJohn Stultz
97496c8f06aSThomas Gleixner /* rtc_timer_init - Initializes an rtc_timer
9756610e089SJohn Stultz * @timer: timer to be intiialized
9766610e089SJohn Stultz * @f: function pointer to be called when timer fires
9779a032011SAlexandre Belloni * @rtc: pointer to the rtc_device
9786610e089SJohn Stultz *
9796610e089SJohn Stultz * Kernel interface to initializing an rtc_timer.
9806610e089SJohn Stultz */
rtc_timer_init(struct rtc_timer * timer,void (* f)(struct rtc_device * r),struct rtc_device * rtc)9819a032011SAlexandre Belloni void rtc_timer_init(struct rtc_timer *timer, void (*f)(struct rtc_device *r),
9829a032011SAlexandre Belloni struct rtc_device *rtc)
9836610e089SJohn Stultz {
9846610e089SJohn Stultz timerqueue_init(&timer->node);
9856610e089SJohn Stultz timer->enabled = 0;
9865a5ba10fSAlexandre Belloni timer->func = f;
9879a032011SAlexandre Belloni timer->rtc = rtc;
9886610e089SJohn Stultz }
9896610e089SJohn Stultz
99096c8f06aSThomas Gleixner /* rtc_timer_start - Sets an rtc_timer to fire in the future
9916610e089SJohn Stultz * @ rtc: rtc device to be used
9926610e089SJohn Stultz * @ timer: timer being set
9936610e089SJohn Stultz * @ expires: time at which to expire the timer
9946610e089SJohn Stultz * @ period: period that the timer will recur
9956610e089SJohn Stultz *
9966610e089SJohn Stultz * Kernel interface to set an rtc_timer
9976610e089SJohn Stultz */
rtc_timer_start(struct rtc_device * rtc,struct rtc_timer * timer,ktime_t expires,ktime_t period)99896c8f06aSThomas Gleixner int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
9996610e089SJohn Stultz ktime_t expires, ktime_t period)
10006610e089SJohn Stultz {
10016610e089SJohn Stultz int ret = 0;
1002606cc43cSAlexandre Belloni
10036610e089SJohn Stultz mutex_lock(&rtc->ops_lock);
10046610e089SJohn Stultz if (timer->enabled)
100596c8f06aSThomas Gleixner rtc_timer_remove(rtc, timer);
10066610e089SJohn Stultz
10076610e089SJohn Stultz timer->node.expires = expires;
10086610e089SJohn Stultz timer->period = period;
10096610e089SJohn Stultz
1010aa0be0f4SJohn Stultz ret = rtc_timer_enqueue(rtc, timer);
10116610e089SJohn Stultz
10126610e089SJohn Stultz mutex_unlock(&rtc->ops_lock);
10136610e089SJohn Stultz return ret;
10146610e089SJohn Stultz }
10156610e089SJohn Stultz
101696c8f06aSThomas Gleixner /* rtc_timer_cancel - Stops an rtc_timer
10176610e089SJohn Stultz * @ rtc: rtc device to be used
10186610e089SJohn Stultz * @ timer: timer being set
10196610e089SJohn Stultz *
10206610e089SJohn Stultz * Kernel interface to cancel an rtc_timer
10216610e089SJohn Stultz */
rtc_timer_cancel(struct rtc_device * rtc,struct rtc_timer * timer)102273744a64SKrzysztof Kozlowski void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
10236610e089SJohn Stultz {
10246610e089SJohn Stultz mutex_lock(&rtc->ops_lock);
10256610e089SJohn Stultz if (timer->enabled)
102696c8f06aSThomas Gleixner rtc_timer_remove(rtc, timer);
10276610e089SJohn Stultz mutex_unlock(&rtc->ops_lock);
10286610e089SJohn Stultz }
10296610e089SJohn Stultz
1030b3967067SJoshua Clayton /**
1031b3967067SJoshua Clayton * rtc_read_offset - Read the amount of rtc offset in parts per billion
1032b3967067SJoshua Clayton * @rtc: rtc device to be used
1033b3967067SJoshua Clayton * @offset: the offset in parts per billion
1034b3967067SJoshua Clayton *
1035b3967067SJoshua Clayton * see below for details.
1036b3967067SJoshua Clayton *
1037b3967067SJoshua Clayton * Kernel interface to read rtc clock offset
1038b3967067SJoshua Clayton * Returns 0 on success, or a negative number on error.
1039b3967067SJoshua Clayton * If read_offset() is not implemented for the rtc, return -EINVAL
1040b3967067SJoshua Clayton */
rtc_read_offset(struct rtc_device * rtc,long * offset)1041b3967067SJoshua Clayton int rtc_read_offset(struct rtc_device *rtc, long *offset)
1042b3967067SJoshua Clayton {
1043b3967067SJoshua Clayton int ret;
10446610e089SJohn Stultz
1045b3967067SJoshua Clayton if (!rtc->ops)
1046b3967067SJoshua Clayton return -ENODEV;
1047b3967067SJoshua Clayton
1048b3967067SJoshua Clayton if (!rtc->ops->read_offset)
1049b3967067SJoshua Clayton return -EINVAL;
1050b3967067SJoshua Clayton
1051b3967067SJoshua Clayton mutex_lock(&rtc->ops_lock);
1052b3967067SJoshua Clayton ret = rtc->ops->read_offset(rtc->dev.parent, offset);
1053b3967067SJoshua Clayton mutex_unlock(&rtc->ops_lock);
105429a1f599SBaolin Wang
105529a1f599SBaolin Wang trace_rtc_read_offset(*offset, ret);
1056b3967067SJoshua Clayton return ret;
1057b3967067SJoshua Clayton }
1058b3967067SJoshua Clayton
1059b3967067SJoshua Clayton /**
1060b3967067SJoshua Clayton * rtc_set_offset - Adjusts the duration of the average second
1061b3967067SJoshua Clayton * @rtc: rtc device to be used
1062b3967067SJoshua Clayton * @offset: the offset in parts per billion
1063b3967067SJoshua Clayton *
1064b3967067SJoshua Clayton * Some rtc's allow an adjustment to the average duration of a second
1065b3967067SJoshua Clayton * to compensate for differences in the actual clock rate due to temperature,
1066b3967067SJoshua Clayton * the crystal, capacitor, etc.
1067b3967067SJoshua Clayton *
10688a25c8f6SRussell King * The adjustment applied is as follows:
10698a25c8f6SRussell King * t = t0 * (1 + offset * 1e-9)
10708a25c8f6SRussell King * where t0 is the measured length of 1 RTC second with offset = 0
10718a25c8f6SRussell King *
1072b3967067SJoshua Clayton * Kernel interface to adjust an rtc clock offset.
1073b3967067SJoshua Clayton * Return 0 on success, or a negative number on error.
1074b3967067SJoshua Clayton * If the rtc offset is not setable (or not implemented), return -EINVAL
1075b3967067SJoshua Clayton */
rtc_set_offset(struct rtc_device * rtc,long offset)1076b3967067SJoshua Clayton int rtc_set_offset(struct rtc_device *rtc, long offset)
1077b3967067SJoshua Clayton {
1078b3967067SJoshua Clayton int ret;
1079b3967067SJoshua Clayton
1080b3967067SJoshua Clayton if (!rtc->ops)
1081b3967067SJoshua Clayton return -ENODEV;
1082b3967067SJoshua Clayton
1083b3967067SJoshua Clayton if (!rtc->ops->set_offset)
1084b3967067SJoshua Clayton return -EINVAL;
1085b3967067SJoshua Clayton
1086b3967067SJoshua Clayton mutex_lock(&rtc->ops_lock);
1087b3967067SJoshua Clayton ret = rtc->ops->set_offset(rtc->dev.parent, offset);
1088b3967067SJoshua Clayton mutex_unlock(&rtc->ops_lock);
108929a1f599SBaolin Wang
109029a1f599SBaolin Wang trace_rtc_set_offset(offset, ret);
1091b3967067SJoshua Clayton return ret;
1092b3967067SJoshua Clayton }
1093