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 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 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 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 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 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 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 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 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, 259f44f7f96SJohn Stultz * then it's probably best 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 */ 277fd6792bbSAlexandre Belloni if (rtc_valid_tm(&alarm->time) == 0) { 278fd6792bbSAlexandre Belloni rtc_add_offset(rtc, &alarm->time); 279f44f7f96SJohn Stultz return 0; 280fd6792bbSAlexandre Belloni } 281f44f7f96SJohn Stultz 282f44f7f96SJohn Stultz /* get the "after" timestamp, to detect wrapped fields */ 283f44f7f96SJohn Stultz err = rtc_read_time(rtc, &now); 284f44f7f96SJohn Stultz if (err < 0) 285f44f7f96SJohn Stultz return err; 286f44f7f96SJohn Stultz 287f44f7f96SJohn Stultz /* note that tm_sec is a "don't care" value here: */ 288606cc43cSAlexandre Belloni } while (before.tm_min != now.tm_min || 289606cc43cSAlexandre Belloni before.tm_hour != now.tm_hour || 290606cc43cSAlexandre Belloni before.tm_mon != now.tm_mon || 291606cc43cSAlexandre Belloni before.tm_year != now.tm_year); 292f44f7f96SJohn Stultz 293f44f7f96SJohn Stultz /* Fill in the missing alarm fields using the timestamp; we 294f44f7f96SJohn Stultz * know there's at least one since alarm->time is invalid. 295f44f7f96SJohn Stultz */ 296f44f7f96SJohn Stultz if (alarm->time.tm_sec == -1) 297f44f7f96SJohn Stultz alarm->time.tm_sec = now.tm_sec; 298f44f7f96SJohn Stultz if (alarm->time.tm_min == -1) 299f44f7f96SJohn Stultz alarm->time.tm_min = now.tm_min; 300f44f7f96SJohn Stultz if (alarm->time.tm_hour == -1) 301f44f7f96SJohn Stultz alarm->time.tm_hour = now.tm_hour; 302f44f7f96SJohn Stultz 303f44f7f96SJohn Stultz /* For simplicity, only support date rollover for now */ 304e74a8f2eSBen Hutchings if (alarm->time.tm_mday < 1 || alarm->time.tm_mday > 31) { 305f44f7f96SJohn Stultz alarm->time.tm_mday = now.tm_mday; 306f44f7f96SJohn Stultz missing = day; 307f44f7f96SJohn Stultz } 308606cc43cSAlexandre Belloni if ((unsigned int)alarm->time.tm_mon >= 12) { 309f44f7f96SJohn Stultz alarm->time.tm_mon = now.tm_mon; 310f44f7f96SJohn Stultz if (missing == none) 311f44f7f96SJohn Stultz missing = month; 312f44f7f96SJohn Stultz } 313f44f7f96SJohn Stultz if (alarm->time.tm_year == -1) { 314f44f7f96SJohn Stultz alarm->time.tm_year = now.tm_year; 315f44f7f96SJohn Stultz if (missing == none) 316f44f7f96SJohn Stultz missing = year; 317f44f7f96SJohn Stultz } 318f44f7f96SJohn Stultz 319da96aea0SVaibhav Jain /* Can't proceed if alarm is still invalid after replacing 320da96aea0SVaibhav Jain * missing fields. 321da96aea0SVaibhav Jain */ 322da96aea0SVaibhav Jain err = rtc_valid_tm(&alarm->time); 323da96aea0SVaibhav Jain if (err) 324da96aea0SVaibhav Jain goto done; 325da96aea0SVaibhav Jain 326f44f7f96SJohn Stultz /* with luck, no rollover is needed */ 327bc10aa93SXunlei Pang t_now = rtc_tm_to_time64(&now); 328bc10aa93SXunlei Pang t_alm = rtc_tm_to_time64(&alarm->time); 329f44f7f96SJohn Stultz if (t_now < t_alm) 330f44f7f96SJohn Stultz goto done; 331f44f7f96SJohn Stultz 332f44f7f96SJohn Stultz switch (missing) { 333f44f7f96SJohn Stultz /* 24 hour rollover ... if it's now 10am Monday, an alarm that 334f44f7f96SJohn Stultz * that will trigger at 5am will do so at 5am Tuesday, which 335f44f7f96SJohn Stultz * could also be in the next month or year. This is a common 336f44f7f96SJohn Stultz * case, especially for PCs. 337f44f7f96SJohn Stultz */ 338f44f7f96SJohn Stultz case day: 339f44f7f96SJohn Stultz dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day"); 340f44f7f96SJohn Stultz t_alm += 24 * 60 * 60; 341bc10aa93SXunlei Pang rtc_time64_to_tm(t_alm, &alarm->time); 342f44f7f96SJohn Stultz break; 343f44f7f96SJohn Stultz 344f44f7f96SJohn Stultz /* Month rollover ... if it's the 31th, an alarm on the 3rd will 345f44f7f96SJohn Stultz * be next month. An alarm matching on the 30th, 29th, or 28th 346f44f7f96SJohn Stultz * may end up in the month after that! Many newer PCs support 347f44f7f96SJohn Stultz * this type of alarm. 348f44f7f96SJohn Stultz */ 349f44f7f96SJohn Stultz case month: 350f44f7f96SJohn Stultz dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month"); 351f44f7f96SJohn Stultz do { 352606cc43cSAlexandre Belloni if (alarm->time.tm_mon < 11) { 353f44f7f96SJohn Stultz alarm->time.tm_mon++; 354606cc43cSAlexandre Belloni } else { 355f44f7f96SJohn Stultz alarm->time.tm_mon = 0; 356f44f7f96SJohn Stultz alarm->time.tm_year++; 357f44f7f96SJohn Stultz } 358f44f7f96SJohn Stultz days = rtc_month_days(alarm->time.tm_mon, 359f44f7f96SJohn Stultz alarm->time.tm_year); 360f44f7f96SJohn Stultz } while (days < alarm->time.tm_mday); 361f44f7f96SJohn Stultz break; 362f44f7f96SJohn Stultz 363f44f7f96SJohn Stultz /* Year rollover ... easy except for leap years! */ 364f44f7f96SJohn Stultz case year: 365f44f7f96SJohn Stultz dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year"); 366f44f7f96SJohn Stultz do { 367f44f7f96SJohn Stultz alarm->time.tm_year++; 368606cc43cSAlexandre Belloni } while (!is_leap_year(alarm->time.tm_year + 1900) && 369606cc43cSAlexandre Belloni rtc_valid_tm(&alarm->time) != 0); 370f44f7f96SJohn Stultz break; 371f44f7f96SJohn Stultz 372f44f7f96SJohn Stultz default: 373f44f7f96SJohn Stultz dev_warn(&rtc->dev, "alarm rollover not handled\n"); 374f44f7f96SJohn Stultz } 375f44f7f96SJohn Stultz 376ee1d9014SAles Novak err = rtc_valid_tm(&alarm->time); 377ee1d9014SAles Novak 378da96aea0SVaibhav Jain done: 3795548cbf7SAndy Shevchenko if (err) 380606cc43cSAlexandre Belloni dev_warn(&rtc->dev, "invalid alarm value: %ptR\n", 381606cc43cSAlexandre Belloni &alarm->time); 382ee1d9014SAles Novak 383ee1d9014SAles Novak return err; 384f44f7f96SJohn Stultz } 385f44f7f96SJohn Stultz 3866610e089SJohn Stultz int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 3870c86edc0SAlessandro Zummo { 3880c86edc0SAlessandro Zummo int err; 3890c86edc0SAlessandro Zummo 3900c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock); 3910c86edc0SAlessandro Zummo if (err) 392b68bb263SDavid Brownell return err; 393606cc43cSAlexandre Belloni if (!rtc->ops) { 394d5553a55SJohn Stultz err = -ENODEV; 3957ae41220SAlexandre Belloni } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) { 396d5553a55SJohn Stultz err = -EINVAL; 397606cc43cSAlexandre Belloni } else { 398d5553a55SJohn Stultz memset(alarm, 0, sizeof(struct rtc_wkalrm)); 3996610e089SJohn Stultz alarm->enabled = rtc->aie_timer.enabled; 4006610e089SJohn Stultz alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires); 401d5553a55SJohn Stultz } 4020c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 4030e36a9a4SMark Lord 40429a1f599SBaolin Wang trace_rtc_read_alarm(rtc_tm_to_time64(&alarm->time), err); 405d5553a55SJohn Stultz return err; 4060e36a9a4SMark Lord } 4070c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_read_alarm); 4080c86edc0SAlessandro Zummo 409d576fe49SMark Brown static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 4106610e089SJohn Stultz { 4116610e089SJohn Stultz struct rtc_time tm; 412bc10aa93SXunlei Pang time64_t now, scheduled; 4136610e089SJohn Stultz int err; 4146610e089SJohn Stultz 4156610e089SJohn Stultz err = rtc_valid_tm(&alarm->time); 4166610e089SJohn Stultz if (err) 4176610e089SJohn Stultz return err; 41898951564SBaolin Wang 419bc10aa93SXunlei Pang scheduled = rtc_tm_to_time64(&alarm->time); 4206610e089SJohn Stultz 4216610e089SJohn Stultz /* Make sure we're not setting alarms in the past */ 4226610e089SJohn Stultz err = __rtc_read_time(rtc, &tm); 423ca6dc2daSHyogi Gim if (err) 424ca6dc2daSHyogi Gim return err; 425bc10aa93SXunlei Pang now = rtc_tm_to_time64(&tm); 426*d87f741dSAlexandre Belloni 4276610e089SJohn Stultz if (scheduled <= now) 4286610e089SJohn Stultz return -ETIME; 4296610e089SJohn Stultz /* 4306610e089SJohn Stultz * XXX - We just checked to make sure the alarm time is not 4316610e089SJohn Stultz * in the past, but there is still a race window where if 4326610e089SJohn Stultz * the is alarm set for the next second and the second ticks 4336610e089SJohn Stultz * over right here, before we set the alarm. 4346610e089SJohn Stultz */ 4356610e089SJohn Stultz 436fd6792bbSAlexandre Belloni rtc_subtract_offset(rtc, &alarm->time); 437fd6792bbSAlexandre Belloni 438157e8bf8SLinus Torvalds if (!rtc->ops) 439157e8bf8SLinus Torvalds err = -ENODEV; 4407ae41220SAlexandre Belloni else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) 441157e8bf8SLinus Torvalds err = -EINVAL; 442157e8bf8SLinus Torvalds else 443157e8bf8SLinus Torvalds err = rtc->ops->set_alarm(rtc->dev.parent, alarm); 444157e8bf8SLinus Torvalds 44529a1f599SBaolin Wang trace_rtc_set_alarm(rtc_tm_to_time64(&alarm->time), err); 446157e8bf8SLinus Torvalds return err; 4476610e089SJohn Stultz } 4486610e089SJohn Stultz 449ab6a2d70SDavid Brownell int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 4500c86edc0SAlessandro Zummo { 451*d87f741dSAlexandre Belloni ktime_t alarm_time; 4520c86edc0SAlessandro Zummo int err; 4530c86edc0SAlessandro Zummo 454abfdff44SAlexandre Belloni if (!rtc->ops) 455abfdff44SAlexandre Belloni return -ENODEV; 4567ae41220SAlexandre Belloni else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) 457abfdff44SAlexandre Belloni return -EINVAL; 458abfdff44SAlexandre Belloni 459f8245c26SDavid Brownell err = rtc_valid_tm(&alarm->time); 460f8245c26SDavid Brownell if (err != 0) 461f8245c26SDavid Brownell return err; 462f8245c26SDavid Brownell 4634c4e5df1SBaolin Wang err = rtc_valid_range(rtc, &alarm->time); 4644c4e5df1SBaolin Wang if (err) 4654c4e5df1SBaolin Wang return err; 46671db049eSAlexandre Belloni 4670c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock); 4680c86edc0SAlessandro Zummo if (err) 469b68bb263SDavid Brownell return err; 4703ff2e13cSSachin Kamat if (rtc->aie_timer.enabled) 47196c8f06aSThomas Gleixner rtc_timer_remove(rtc, &rtc->aie_timer); 4723ff2e13cSSachin Kamat 473*d87f741dSAlexandre Belloni alarm_time = rtc_tm_to_ktime(alarm->time); 474*d87f741dSAlexandre Belloni /* 475*d87f741dSAlexandre Belloni * Round down so we never miss a deadline, checking for past deadline is 476*d87f741dSAlexandre Belloni * done in __rtc_set_alarm 477*d87f741dSAlexandre Belloni */ 478*d87f741dSAlexandre Belloni if (test_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features)) 479*d87f741dSAlexandre Belloni alarm_time = ktime_sub_ns(alarm_time, (u64)alarm->time.tm_sec * NSEC_PER_SEC); 480*d87f741dSAlexandre Belloni 481*d87f741dSAlexandre Belloni rtc->aie_timer.node.expires = alarm_time; 4828b0e1953SThomas Gleixner rtc->aie_timer.period = 0; 4833ff2e13cSSachin Kamat if (alarm->enabled) 484aa0be0f4SJohn Stultz err = rtc_timer_enqueue(rtc, &rtc->aie_timer); 4853ff2e13cSSachin Kamat 4860c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 48798951564SBaolin Wang 488aa0be0f4SJohn Stultz return err; 4890c86edc0SAlessandro Zummo } 4900c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_set_alarm); 4910c86edc0SAlessandro Zummo 492f6d5b331SJohn Stultz /* Called once per device from rtc_device_register */ 493f6d5b331SJohn Stultz int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 494f6d5b331SJohn Stultz { 495f6d5b331SJohn Stultz int err; 496bd729d72SJohn Stultz struct rtc_time now; 497f6d5b331SJohn Stultz 498f6d5b331SJohn Stultz err = rtc_valid_tm(&alarm->time); 499f6d5b331SJohn Stultz if (err != 0) 500f6d5b331SJohn Stultz return err; 501f6d5b331SJohn Stultz 502bd729d72SJohn Stultz err = rtc_read_time(rtc, &now); 503bd729d72SJohn Stultz if (err) 504bd729d72SJohn Stultz return err; 505bd729d72SJohn Stultz 506f6d5b331SJohn Stultz err = mutex_lock_interruptible(&rtc->ops_lock); 507f6d5b331SJohn Stultz if (err) 508f6d5b331SJohn Stultz return err; 509f6d5b331SJohn Stultz 510f6d5b331SJohn Stultz rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); 5118b0e1953SThomas Gleixner rtc->aie_timer.period = 0; 512bd729d72SJohn Stultz 5136785b3b6SUwe Kleine-König /* Alarm has to be enabled & in the future for us to enqueue it */ 5142456e855SThomas Gleixner if (alarm->enabled && (rtc_tm_to_ktime(now) < 5152456e855SThomas Gleixner rtc->aie_timer.node.expires)) { 516f6d5b331SJohn Stultz rtc->aie_timer.enabled = 1; 517f6d5b331SJohn Stultz timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); 51829a1f599SBaolin Wang trace_rtc_timer_enqueue(&rtc->aie_timer); 519f6d5b331SJohn Stultz } 520f6d5b331SJohn Stultz mutex_unlock(&rtc->ops_lock); 521f6d5b331SJohn Stultz return err; 522f6d5b331SJohn Stultz } 523f6d5b331SJohn Stultz EXPORT_SYMBOL_GPL(rtc_initialize_alarm); 524f6d5b331SJohn Stultz 525099e6576SAlessandro Zummo int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) 526099e6576SAlessandro Zummo { 527606cc43cSAlexandre Belloni int err; 528606cc43cSAlexandre Belloni 529606cc43cSAlexandre Belloni err = mutex_lock_interruptible(&rtc->ops_lock); 530099e6576SAlessandro Zummo if (err) 531099e6576SAlessandro Zummo return err; 532099e6576SAlessandro Zummo 5336610e089SJohn Stultz if (rtc->aie_timer.enabled != enabled) { 534aa0be0f4SJohn Stultz if (enabled) 535aa0be0f4SJohn Stultz err = rtc_timer_enqueue(rtc, &rtc->aie_timer); 536aa0be0f4SJohn Stultz else 53796c8f06aSThomas Gleixner rtc_timer_remove(rtc, &rtc->aie_timer); 5386610e089SJohn Stultz } 539aa0be0f4SJohn Stultz 540aa0be0f4SJohn Stultz if (err) 541516373b8SUwe Kleine-König /* nothing */; 542516373b8SUwe Kleine-König else if (!rtc->ops) 543099e6576SAlessandro Zummo err = -ENODEV; 5447ae41220SAlexandre Belloni else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->alarm_irq_enable) 545099e6576SAlessandro Zummo err = -EINVAL; 546099e6576SAlessandro Zummo else 547099e6576SAlessandro Zummo err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled); 548099e6576SAlessandro Zummo 549099e6576SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 55029a1f599SBaolin Wang 55129a1f599SBaolin Wang trace_rtc_alarm_irq_enable(enabled, err); 552099e6576SAlessandro Zummo return err; 553099e6576SAlessandro Zummo } 554099e6576SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable); 555099e6576SAlessandro Zummo 556099e6576SAlessandro Zummo int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) 557099e6576SAlessandro Zummo { 558c55c3a51SAlexandre Belloni int err; 559606cc43cSAlexandre Belloni 560606cc43cSAlexandre Belloni err = mutex_lock_interruptible(&rtc->ops_lock); 561099e6576SAlessandro Zummo if (err) 562099e6576SAlessandro Zummo return err; 563099e6576SAlessandro Zummo 564456d66ecSJohn Stultz #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL 565456d66ecSJohn Stultz if (enabled == 0 && rtc->uie_irq_active) { 566456d66ecSJohn Stultz mutex_unlock(&rtc->ops_lock); 567456d66ecSJohn Stultz return rtc_dev_update_irq_enable_emul(rtc, 0); 568456d66ecSJohn Stultz } 569456d66ecSJohn Stultz #endif 5706610e089SJohn Stultz /* make sure we're changing state */ 5716610e089SJohn Stultz if (rtc->uie_rtctimer.enabled == enabled) 5726610e089SJohn Stultz goto out; 5736610e089SJohn Stultz 574adb17a05SAlexandre Belloni if (!test_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features) || 575adb17a05SAlexandre Belloni !test_bit(RTC_FEATURE_ALARM, rtc->features)) { 576c55c3a51SAlexandre Belloni mutex_unlock(&rtc->ops_lock); 577c55c3a51SAlexandre Belloni #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL 578c55c3a51SAlexandre Belloni return rtc_dev_update_irq_enable_emul(rtc, enabled); 579c55c3a51SAlexandre Belloni #else 580c55c3a51SAlexandre Belloni return -EINVAL; 581c55c3a51SAlexandre Belloni #endif 5824a649903SJohn Stultz } 5834a649903SJohn Stultz 5846610e089SJohn Stultz if (enabled) { 5856610e089SJohn Stultz struct rtc_time tm; 5866610e089SJohn Stultz ktime_t now, onesec; 5876610e089SJohn Stultz 588c55c3a51SAlexandre Belloni err = __rtc_read_time(rtc, &tm); 589c55c3a51SAlexandre Belloni if (err) 5903e74ddaaSAlexandre Belloni goto out; 5916610e089SJohn Stultz onesec = ktime_set(1, 0); 5926610e089SJohn Stultz now = rtc_tm_to_ktime(tm); 5936610e089SJohn Stultz rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); 5946610e089SJohn Stultz rtc->uie_rtctimer.period = ktime_set(1, 0); 595aa0be0f4SJohn Stultz err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer); 596606cc43cSAlexandre Belloni } else { 59796c8f06aSThomas Gleixner rtc_timer_remove(rtc, &rtc->uie_rtctimer); 598606cc43cSAlexandre Belloni } 599099e6576SAlessandro Zummo 6006610e089SJohn Stultz out: 601099e6576SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 6023e74ddaaSAlexandre Belloni 603099e6576SAlessandro Zummo return err; 604099e6576SAlessandro Zummo } 605099e6576SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_update_irq_enable); 606099e6576SAlessandro Zummo 607d728b1e6SDavid Brownell /** 6086610e089SJohn Stultz * rtc_handle_legacy_irq - AIE, UIE and PIE event hook 6096610e089SJohn Stultz * @rtc: pointer to the rtc device 61055dcf7a2SAlexandre Belloni * @num: number of occurence of the event 61155dcf7a2SAlexandre Belloni * @mode: type of the event, RTC_AF, RTC_UF of RTC_PF 6126610e089SJohn Stultz * 6136610e089SJohn Stultz * This function is called when an AIE, UIE or PIE mode interrupt 61425985edcSLucas De Marchi * has occurred (or been emulated). 6156610e089SJohn Stultz * 6166610e089SJohn Stultz */ 617456d66ecSJohn Stultz void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) 6186610e089SJohn Stultz { 6196610e089SJohn Stultz unsigned long flags; 6206610e089SJohn Stultz 6216610e089SJohn Stultz /* mark one irq of the appropriate mode */ 6226610e089SJohn Stultz spin_lock_irqsave(&rtc->irq_lock, flags); 6236610e089SJohn Stultz rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF | mode); 6246610e089SJohn Stultz spin_unlock_irqrestore(&rtc->irq_lock, flags); 6256610e089SJohn Stultz 6266610e089SJohn Stultz wake_up_interruptible(&rtc->irq_queue); 6276610e089SJohn Stultz kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); 6286610e089SJohn Stultz } 6296610e089SJohn Stultz 6306610e089SJohn Stultz /** 6316610e089SJohn Stultz * rtc_aie_update_irq - AIE mode rtctimer hook 6329a032011SAlexandre Belloni * @rtc: pointer to the rtc_device 6336610e089SJohn Stultz * 6346610e089SJohn Stultz * This functions is called when the aie_timer expires. 6356610e089SJohn Stultz */ 6369a032011SAlexandre Belloni void rtc_aie_update_irq(struct rtc_device *rtc) 6376610e089SJohn Stultz { 6386610e089SJohn Stultz rtc_handle_legacy_irq(rtc, 1, RTC_AF); 6396610e089SJohn Stultz } 6406610e089SJohn Stultz 6416610e089SJohn Stultz /** 6426610e089SJohn Stultz * rtc_uie_update_irq - UIE mode rtctimer hook 6439a032011SAlexandre Belloni * @rtc: pointer to the rtc_device 6446610e089SJohn Stultz * 6456610e089SJohn Stultz * This functions is called when the uie_timer expires. 6466610e089SJohn Stultz */ 6479a032011SAlexandre Belloni void rtc_uie_update_irq(struct rtc_device *rtc) 6486610e089SJohn Stultz { 6496610e089SJohn Stultz rtc_handle_legacy_irq(rtc, 1, RTC_UF); 6506610e089SJohn Stultz } 6516610e089SJohn Stultz 6526610e089SJohn Stultz /** 6536610e089SJohn Stultz * rtc_pie_update_irq - PIE mode hrtimer hook 6546610e089SJohn Stultz * @timer: pointer to the pie mode hrtimer 6556610e089SJohn Stultz * 6566610e089SJohn Stultz * This function is used to emulate PIE mode interrupts 6576610e089SJohn Stultz * using an hrtimer. This function is called when the periodic 6586610e089SJohn Stultz * hrtimer expires. 6596610e089SJohn Stultz */ 6606610e089SJohn Stultz enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) 6616610e089SJohn Stultz { 6626610e089SJohn Stultz struct rtc_device *rtc; 6636610e089SJohn Stultz ktime_t period; 6643126790dSPuranjay Mohan u64 count; 665606cc43cSAlexandre Belloni 6666610e089SJohn Stultz rtc = container_of(timer, struct rtc_device, pie_timer); 6676610e089SJohn Stultz 6688b0e1953SThomas Gleixner period = NSEC_PER_SEC / rtc->irq_freq; 6696610e089SJohn Stultz count = hrtimer_forward_now(timer, period); 6706610e089SJohn Stultz 6716610e089SJohn Stultz rtc_handle_legacy_irq(rtc, count, RTC_PF); 6726610e089SJohn Stultz 6736610e089SJohn Stultz return HRTIMER_RESTART; 6746610e089SJohn Stultz } 6756610e089SJohn Stultz 6766610e089SJohn Stultz /** 6776610e089SJohn Stultz * rtc_update_irq - Triggered when a RTC interrupt occurs. 678ab6a2d70SDavid Brownell * @rtc: the rtc device 679d728b1e6SDavid Brownell * @num: how many irqs are being reported (usually one) 680d728b1e6SDavid Brownell * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF 681e6229becSAtsushi Nemoto * Context: any 682d728b1e6SDavid Brownell */ 683ab6a2d70SDavid Brownell void rtc_update_irq(struct rtc_device *rtc, 6840c86edc0SAlessandro Zummo unsigned long num, unsigned long events) 6850c86edc0SAlessandro Zummo { 686e7cba884Sviresh kumar if (IS_ERR_OR_NULL(rtc)) 687131c9cc8SAlessandro Zummo return; 688131c9cc8SAlessandro Zummo 6897523ceedSNeilBrown pm_stay_awake(rtc->dev.parent); 6906610e089SJohn Stultz schedule_work(&rtc->irqwork); 6910c86edc0SAlessandro Zummo } 6920c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_update_irq); 6930c86edc0SAlessandro Zummo 6949f3b795aSMichał Mirosław struct rtc_device *rtc_class_open(const char *name) 6950c86edc0SAlessandro Zummo { 696cd966209SDavid Brownell struct device *dev; 697ab6a2d70SDavid Brownell struct rtc_device *rtc = NULL; 6980c86edc0SAlessandro Zummo 6996cda08a2SSuzuki K Poulose dev = class_find_device_by_name(rtc_class, name); 700cd966209SDavid Brownell if (dev) 701cd966209SDavid Brownell rtc = to_rtc_device(dev); 7020c86edc0SAlessandro Zummo 703ab6a2d70SDavid Brownell if (rtc) { 704ab6a2d70SDavid Brownell if (!try_module_get(rtc->owner)) { 705cd966209SDavid Brownell put_device(dev); 706ab6a2d70SDavid Brownell rtc = NULL; 707ab6a2d70SDavid Brownell } 7080c86edc0SAlessandro Zummo } 7090c86edc0SAlessandro Zummo 710ab6a2d70SDavid Brownell return rtc; 7110c86edc0SAlessandro Zummo } 7120c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_class_open); 7130c86edc0SAlessandro Zummo 714ab6a2d70SDavid Brownell void rtc_class_close(struct rtc_device *rtc) 7150c86edc0SAlessandro Zummo { 716ab6a2d70SDavid Brownell module_put(rtc->owner); 717cd966209SDavid Brownell put_device(&rtc->dev); 7180c86edc0SAlessandro Zummo } 7190c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_class_close); 7200c86edc0SAlessandro Zummo 7213c8bb90eSThomas Gleixner static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled) 7223c8bb90eSThomas Gleixner { 7233c8bb90eSThomas Gleixner /* 7243c8bb90eSThomas Gleixner * We always cancel the timer here first, because otherwise 7253c8bb90eSThomas Gleixner * we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK); 7263c8bb90eSThomas Gleixner * when we manage to start the timer before the callback 7273c8bb90eSThomas Gleixner * returns HRTIMER_RESTART. 7283c8bb90eSThomas Gleixner * 7293c8bb90eSThomas Gleixner * We cannot use hrtimer_cancel() here as a running callback 7303c8bb90eSThomas Gleixner * could be blocked on rtc->irq_task_lock and hrtimer_cancel() 7313c8bb90eSThomas Gleixner * would spin forever. 7323c8bb90eSThomas Gleixner */ 7333c8bb90eSThomas Gleixner if (hrtimer_try_to_cancel(&rtc->pie_timer) < 0) 7343c8bb90eSThomas Gleixner return -1; 7353c8bb90eSThomas Gleixner 7363c8bb90eSThomas Gleixner if (enabled) { 7378b0e1953SThomas Gleixner ktime_t period = NSEC_PER_SEC / rtc->irq_freq; 7383c8bb90eSThomas Gleixner 7393c8bb90eSThomas Gleixner hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL); 7403c8bb90eSThomas Gleixner } 7413c8bb90eSThomas Gleixner return 0; 7423c8bb90eSThomas Gleixner } 7433c8bb90eSThomas Gleixner 74497144c67SDavid Brownell /** 74597144c67SDavid Brownell * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs 74697144c67SDavid Brownell * @rtc: the rtc device 74797144c67SDavid Brownell * @enabled: true to enable periodic IRQs 74897144c67SDavid Brownell * Context: any 74997144c67SDavid Brownell * 75097144c67SDavid Brownell * Note that rtc_irq_set_freq() should previously have been used to 751acecb3adSAlexandre Belloni * specify the desired frequency of periodic IRQ. 75297144c67SDavid Brownell */ 7538719d3c9SAlexandre Belloni int rtc_irq_set_state(struct rtc_device *rtc, int enabled) 7540c86edc0SAlessandro Zummo { 7550c86edc0SAlessandro Zummo int err = 0; 7560c86edc0SAlessandro Zummo 757acecb3adSAlexandre Belloni while (rtc_update_hrtimer(rtc, enabled) < 0) 7583c8bb90eSThomas Gleixner cpu_relax(); 759acecb3adSAlexandre Belloni 7606610e089SJohn Stultz rtc->pie_enabled = enabled; 76129a1f599SBaolin Wang 76229a1f599SBaolin Wang trace_rtc_irq_set_state(enabled, err); 7630c86edc0SAlessandro Zummo return err; 7640c86edc0SAlessandro Zummo } 7650c86edc0SAlessandro Zummo 76697144c67SDavid Brownell /** 76797144c67SDavid Brownell * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ 76897144c67SDavid Brownell * @rtc: the rtc device 769acecb3adSAlexandre Belloni * @freq: positive frequency 77097144c67SDavid Brownell * Context: any 77197144c67SDavid Brownell * 77297144c67SDavid Brownell * Note that rtc_irq_set_state() is used to enable or disable the 77397144c67SDavid Brownell * periodic IRQs. 77497144c67SDavid Brownell */ 7758719d3c9SAlexandre Belloni int rtc_irq_set_freq(struct rtc_device *rtc, int freq) 7760c86edc0SAlessandro Zummo { 77756f10c63SAlessandro Zummo int err = 0; 7780c86edc0SAlessandro Zummo 7796e7a333eSThomas Gleixner if (freq <= 0 || freq > RTC_MAX_FREQ) 78083a06bf5SMarcelo Roberto Jimenez return -EINVAL; 781acecb3adSAlexandre Belloni 7820c86edc0SAlessandro Zummo rtc->irq_freq = freq; 783acecb3adSAlexandre Belloni while (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) 7843c8bb90eSThomas Gleixner cpu_relax(); 78529a1f599SBaolin Wang 78629a1f599SBaolin Wang trace_rtc_irq_set_freq(freq, err); 7870c86edc0SAlessandro Zummo return err; 7880c86edc0SAlessandro Zummo } 7896610e089SJohn Stultz 7906610e089SJohn Stultz /** 79196c8f06aSThomas Gleixner * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue 79255dcf7a2SAlexandre Belloni * @rtc: rtc device 79355dcf7a2SAlexandre Belloni * @timer: timer being added. 7946610e089SJohn Stultz * 7956610e089SJohn Stultz * Enqueues a timer onto the rtc devices timerqueue and sets 7966610e089SJohn Stultz * the next alarm event appropriately. 7976610e089SJohn Stultz * 798aa0be0f4SJohn Stultz * Sets the enabled bit on the added timer. 799aa0be0f4SJohn Stultz * 8006610e089SJohn Stultz * Must hold ops_lock for proper serialization of timerqueue 8016610e089SJohn Stultz */ 802aa0be0f4SJohn Stultz static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) 8036610e089SJohn Stultz { 8042b2f5ff0SColin Ian King struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); 8052b2f5ff0SColin Ian King struct rtc_time tm; 8062b2f5ff0SColin Ian King ktime_t now; 8072b2f5ff0SColin Ian King 808aa0be0f4SJohn Stultz timer->enabled = 1; 8092b2f5ff0SColin Ian King __rtc_read_time(rtc, &tm); 8102b2f5ff0SColin Ian King now = rtc_tm_to_ktime(tm); 8112b2f5ff0SColin Ian King 8122b2f5ff0SColin Ian King /* Skip over expired timers */ 8132b2f5ff0SColin Ian King while (next) { 8142456e855SThomas Gleixner if (next->expires >= now) 8152b2f5ff0SColin Ian King break; 8162b2f5ff0SColin Ian King next = timerqueue_iterate_next(next); 8172b2f5ff0SColin Ian King } 8182b2f5ff0SColin Ian King 8196610e089SJohn Stultz timerqueue_add(&rtc->timerqueue, &timer->node); 82029a1f599SBaolin Wang trace_rtc_timer_enqueue(timer); 82174717b28SAlexandre Belloni if (!next || ktime_before(timer->node.expires, next->expires)) { 8226610e089SJohn Stultz struct rtc_wkalrm alarm; 8236610e089SJohn Stultz int err; 824606cc43cSAlexandre Belloni 8256610e089SJohn Stultz alarm.time = rtc_ktime_to_tm(timer->node.expires); 8266610e089SJohn Stultz alarm.enabled = 1; 8276610e089SJohn Stultz err = __rtc_set_alarm(rtc, &alarm); 82814d0e347SZoran Markovic if (err == -ETIME) { 82914d0e347SZoran Markovic pm_stay_awake(rtc->dev.parent); 8306610e089SJohn Stultz schedule_work(&rtc->irqwork); 83114d0e347SZoran Markovic } else if (err) { 832aa0be0f4SJohn Stultz timerqueue_del(&rtc->timerqueue, &timer->node); 83329a1f599SBaolin Wang trace_rtc_timer_dequeue(timer); 834aa0be0f4SJohn Stultz timer->enabled = 0; 835aa0be0f4SJohn Stultz return err; 8366610e089SJohn Stultz } 8376610e089SJohn Stultz } 838aa0be0f4SJohn Stultz return 0; 839aa0be0f4SJohn Stultz } 8406610e089SJohn Stultz 84141c7f742SRabin Vincent static void rtc_alarm_disable(struct rtc_device *rtc) 84241c7f742SRabin Vincent { 8437ae41220SAlexandre Belloni if (!rtc->ops || !test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->alarm_irq_enable) 84441c7f742SRabin Vincent return; 84541c7f742SRabin Vincent 84641c7f742SRabin Vincent rtc->ops->alarm_irq_enable(rtc->dev.parent, false); 84729a1f599SBaolin Wang trace_rtc_alarm_irq_enable(0, 0); 84841c7f742SRabin Vincent } 84941c7f742SRabin Vincent 8506610e089SJohn Stultz /** 85196c8f06aSThomas Gleixner * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue 85255dcf7a2SAlexandre Belloni * @rtc: rtc device 85355dcf7a2SAlexandre Belloni * @timer: timer being removed. 8546610e089SJohn Stultz * 8556610e089SJohn Stultz * Removes a timer onto the rtc devices timerqueue and sets 8566610e089SJohn Stultz * the next alarm event appropriately. 8576610e089SJohn Stultz * 858aa0be0f4SJohn Stultz * Clears the enabled bit on the removed timer. 859aa0be0f4SJohn Stultz * 8606610e089SJohn Stultz * Must hold ops_lock for proper serialization of timerqueue 8616610e089SJohn Stultz */ 862aa0be0f4SJohn Stultz static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) 8636610e089SJohn Stultz { 8646610e089SJohn Stultz struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); 865606cc43cSAlexandre Belloni 8666610e089SJohn Stultz timerqueue_del(&rtc->timerqueue, &timer->node); 86729a1f599SBaolin Wang trace_rtc_timer_dequeue(timer); 868aa0be0f4SJohn Stultz timer->enabled = 0; 8696610e089SJohn Stultz if (next == &timer->node) { 8706610e089SJohn Stultz struct rtc_wkalrm alarm; 8716610e089SJohn Stultz int err; 872606cc43cSAlexandre Belloni 8736610e089SJohn Stultz next = timerqueue_getnext(&rtc->timerqueue); 87441c7f742SRabin Vincent if (!next) { 87541c7f742SRabin Vincent rtc_alarm_disable(rtc); 8766610e089SJohn Stultz return; 87741c7f742SRabin Vincent } 8786610e089SJohn Stultz alarm.time = rtc_ktime_to_tm(next->expires); 8796610e089SJohn Stultz alarm.enabled = 1; 8806610e089SJohn Stultz err = __rtc_set_alarm(rtc, &alarm); 88114d0e347SZoran Markovic if (err == -ETIME) { 88214d0e347SZoran Markovic pm_stay_awake(rtc->dev.parent); 8836610e089SJohn Stultz schedule_work(&rtc->irqwork); 8846610e089SJohn Stultz } 8856610e089SJohn Stultz } 88614d0e347SZoran Markovic } 8876610e089SJohn Stultz 8886610e089SJohn Stultz /** 88996c8f06aSThomas Gleixner * rtc_timer_do_work - Expires rtc timers 89055dcf7a2SAlexandre Belloni * @work: work item 8916610e089SJohn Stultz * 8926610e089SJohn Stultz * Expires rtc timers. Reprograms next alarm event if needed. 8936610e089SJohn Stultz * Called via worktask. 8946610e089SJohn Stultz * 8956610e089SJohn Stultz * Serializes access to timerqueue via ops_lock mutex 8966610e089SJohn Stultz */ 89796c8f06aSThomas Gleixner void rtc_timer_do_work(struct work_struct *work) 8986610e089SJohn Stultz { 8996610e089SJohn Stultz struct rtc_timer *timer; 9006610e089SJohn Stultz struct timerqueue_node *next; 9016610e089SJohn Stultz ktime_t now; 9026610e089SJohn Stultz struct rtc_time tm; 9036610e089SJohn Stultz 9046610e089SJohn Stultz struct rtc_device *rtc = 9056610e089SJohn Stultz container_of(work, struct rtc_device, irqwork); 9066610e089SJohn Stultz 9076610e089SJohn Stultz mutex_lock(&rtc->ops_lock); 9086610e089SJohn Stultz again: 9096610e089SJohn Stultz __rtc_read_time(rtc, &tm); 9106610e089SJohn Stultz now = rtc_tm_to_ktime(tm); 9116610e089SJohn Stultz while ((next = timerqueue_getnext(&rtc->timerqueue))) { 9122456e855SThomas Gleixner if (next->expires > now) 9136610e089SJohn Stultz break; 9146610e089SJohn Stultz 9156610e089SJohn Stultz /* expire timer */ 9166610e089SJohn Stultz timer = container_of(next, struct rtc_timer, node); 9176610e089SJohn Stultz timerqueue_del(&rtc->timerqueue, &timer->node); 91829a1f599SBaolin Wang trace_rtc_timer_dequeue(timer); 9196610e089SJohn Stultz timer->enabled = 0; 9205a5ba10fSAlexandre Belloni if (timer->func) 9219a032011SAlexandre Belloni timer->func(timer->rtc); 9226610e089SJohn Stultz 92329a1f599SBaolin Wang trace_rtc_timer_fired(timer); 9246610e089SJohn Stultz /* Re-add/fwd periodic timers */ 9256610e089SJohn Stultz if (ktime_to_ns(timer->period)) { 9266610e089SJohn Stultz timer->node.expires = ktime_add(timer->node.expires, 9276610e089SJohn Stultz timer->period); 9286610e089SJohn Stultz timer->enabled = 1; 9296610e089SJohn Stultz timerqueue_add(&rtc->timerqueue, &timer->node); 93029a1f599SBaolin Wang trace_rtc_timer_enqueue(timer); 9316610e089SJohn Stultz } 9326610e089SJohn Stultz } 9336610e089SJohn Stultz 9346610e089SJohn Stultz /* Set next alarm */ 9356610e089SJohn Stultz if (next) { 9366610e089SJohn Stultz struct rtc_wkalrm alarm; 9376610e089SJohn Stultz int err; 9386528b889SXunlei Pang int retry = 3; 9396528b889SXunlei Pang 9406610e089SJohn Stultz alarm.time = rtc_ktime_to_tm(next->expires); 9416610e089SJohn Stultz alarm.enabled = 1; 9426528b889SXunlei Pang reprogram: 9436610e089SJohn Stultz err = __rtc_set_alarm(rtc, &alarm); 944606cc43cSAlexandre Belloni if (err == -ETIME) { 9456610e089SJohn Stultz goto again; 946606cc43cSAlexandre Belloni } else if (err) { 9476528b889SXunlei Pang if (retry-- > 0) 9486528b889SXunlei Pang goto reprogram; 9496528b889SXunlei Pang 9506528b889SXunlei Pang timer = container_of(next, struct rtc_timer, node); 9516528b889SXunlei Pang timerqueue_del(&rtc->timerqueue, &timer->node); 95229a1f599SBaolin Wang trace_rtc_timer_dequeue(timer); 9536528b889SXunlei Pang timer->enabled = 0; 9546528b889SXunlei Pang dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err); 9556528b889SXunlei Pang goto again; 9566528b889SXunlei Pang } 957606cc43cSAlexandre Belloni } else { 95841c7f742SRabin Vincent rtc_alarm_disable(rtc); 959606cc43cSAlexandre Belloni } 9606610e089SJohn Stultz 96114d0e347SZoran Markovic pm_relax(rtc->dev.parent); 9626610e089SJohn Stultz mutex_unlock(&rtc->ops_lock); 9636610e089SJohn Stultz } 9646610e089SJohn Stultz 96596c8f06aSThomas Gleixner /* rtc_timer_init - Initializes an rtc_timer 9666610e089SJohn Stultz * @timer: timer to be intiialized 9676610e089SJohn Stultz * @f: function pointer to be called when timer fires 9689a032011SAlexandre Belloni * @rtc: pointer to the rtc_device 9696610e089SJohn Stultz * 9706610e089SJohn Stultz * Kernel interface to initializing an rtc_timer. 9716610e089SJohn Stultz */ 9729a032011SAlexandre Belloni void rtc_timer_init(struct rtc_timer *timer, void (*f)(struct rtc_device *r), 9739a032011SAlexandre Belloni struct rtc_device *rtc) 9746610e089SJohn Stultz { 9756610e089SJohn Stultz timerqueue_init(&timer->node); 9766610e089SJohn Stultz timer->enabled = 0; 9775a5ba10fSAlexandre Belloni timer->func = f; 9789a032011SAlexandre Belloni timer->rtc = rtc; 9796610e089SJohn Stultz } 9806610e089SJohn Stultz 98196c8f06aSThomas Gleixner /* rtc_timer_start - Sets an rtc_timer to fire in the future 9826610e089SJohn Stultz * @ rtc: rtc device to be used 9836610e089SJohn Stultz * @ timer: timer being set 9846610e089SJohn Stultz * @ expires: time at which to expire the timer 9856610e089SJohn Stultz * @ period: period that the timer will recur 9866610e089SJohn Stultz * 9876610e089SJohn Stultz * Kernel interface to set an rtc_timer 9886610e089SJohn Stultz */ 98996c8f06aSThomas Gleixner int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer, 9906610e089SJohn Stultz ktime_t expires, ktime_t period) 9916610e089SJohn Stultz { 9926610e089SJohn Stultz int ret = 0; 993606cc43cSAlexandre Belloni 9946610e089SJohn Stultz mutex_lock(&rtc->ops_lock); 9956610e089SJohn Stultz if (timer->enabled) 99696c8f06aSThomas Gleixner rtc_timer_remove(rtc, timer); 9976610e089SJohn Stultz 9986610e089SJohn Stultz timer->node.expires = expires; 9996610e089SJohn Stultz timer->period = period; 10006610e089SJohn Stultz 1001aa0be0f4SJohn Stultz ret = rtc_timer_enqueue(rtc, timer); 10026610e089SJohn Stultz 10036610e089SJohn Stultz mutex_unlock(&rtc->ops_lock); 10046610e089SJohn Stultz return ret; 10056610e089SJohn Stultz } 10066610e089SJohn Stultz 100796c8f06aSThomas Gleixner /* rtc_timer_cancel - Stops an rtc_timer 10086610e089SJohn Stultz * @ rtc: rtc device to be used 10096610e089SJohn Stultz * @ timer: timer being set 10106610e089SJohn Stultz * 10116610e089SJohn Stultz * Kernel interface to cancel an rtc_timer 10126610e089SJohn Stultz */ 101373744a64SKrzysztof Kozlowski void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer) 10146610e089SJohn Stultz { 10156610e089SJohn Stultz mutex_lock(&rtc->ops_lock); 10166610e089SJohn Stultz if (timer->enabled) 101796c8f06aSThomas Gleixner rtc_timer_remove(rtc, timer); 10186610e089SJohn Stultz mutex_unlock(&rtc->ops_lock); 10196610e089SJohn Stultz } 10206610e089SJohn Stultz 1021b3967067SJoshua Clayton /** 1022b3967067SJoshua Clayton * rtc_read_offset - Read the amount of rtc offset in parts per billion 1023b3967067SJoshua Clayton * @rtc: rtc device to be used 1024b3967067SJoshua Clayton * @offset: the offset in parts per billion 1025b3967067SJoshua Clayton * 1026b3967067SJoshua Clayton * see below for details. 1027b3967067SJoshua Clayton * 1028b3967067SJoshua Clayton * Kernel interface to read rtc clock offset 1029b3967067SJoshua Clayton * Returns 0 on success, or a negative number on error. 1030b3967067SJoshua Clayton * If read_offset() is not implemented for the rtc, return -EINVAL 1031b3967067SJoshua Clayton */ 1032b3967067SJoshua Clayton int rtc_read_offset(struct rtc_device *rtc, long *offset) 1033b3967067SJoshua Clayton { 1034b3967067SJoshua Clayton int ret; 10356610e089SJohn Stultz 1036b3967067SJoshua Clayton if (!rtc->ops) 1037b3967067SJoshua Clayton return -ENODEV; 1038b3967067SJoshua Clayton 1039b3967067SJoshua Clayton if (!rtc->ops->read_offset) 1040b3967067SJoshua Clayton return -EINVAL; 1041b3967067SJoshua Clayton 1042b3967067SJoshua Clayton mutex_lock(&rtc->ops_lock); 1043b3967067SJoshua Clayton ret = rtc->ops->read_offset(rtc->dev.parent, offset); 1044b3967067SJoshua Clayton mutex_unlock(&rtc->ops_lock); 104529a1f599SBaolin Wang 104629a1f599SBaolin Wang trace_rtc_read_offset(*offset, ret); 1047b3967067SJoshua Clayton return ret; 1048b3967067SJoshua Clayton } 1049b3967067SJoshua Clayton 1050b3967067SJoshua Clayton /** 1051b3967067SJoshua Clayton * rtc_set_offset - Adjusts the duration of the average second 1052b3967067SJoshua Clayton * @rtc: rtc device to be used 1053b3967067SJoshua Clayton * @offset: the offset in parts per billion 1054b3967067SJoshua Clayton * 1055b3967067SJoshua Clayton * Some rtc's allow an adjustment to the average duration of a second 1056b3967067SJoshua Clayton * to compensate for differences in the actual clock rate due to temperature, 1057b3967067SJoshua Clayton * the crystal, capacitor, etc. 1058b3967067SJoshua Clayton * 10598a25c8f6SRussell King * The adjustment applied is as follows: 10608a25c8f6SRussell King * t = t0 * (1 + offset * 1e-9) 10618a25c8f6SRussell King * where t0 is the measured length of 1 RTC second with offset = 0 10628a25c8f6SRussell King * 1063b3967067SJoshua Clayton * Kernel interface to adjust an rtc clock offset. 1064b3967067SJoshua Clayton * Return 0 on success, or a negative number on error. 1065b3967067SJoshua Clayton * If the rtc offset is not setable (or not implemented), return -EINVAL 1066b3967067SJoshua Clayton */ 1067b3967067SJoshua Clayton int rtc_set_offset(struct rtc_device *rtc, long offset) 1068b3967067SJoshua Clayton { 1069b3967067SJoshua Clayton int ret; 1070b3967067SJoshua Clayton 1071b3967067SJoshua Clayton if (!rtc->ops) 1072b3967067SJoshua Clayton return -ENODEV; 1073b3967067SJoshua Clayton 1074b3967067SJoshua Clayton if (!rtc->ops->set_offset) 1075b3967067SJoshua Clayton return -EINVAL; 1076b3967067SJoshua Clayton 1077b3967067SJoshua Clayton mutex_lock(&rtc->ops_lock); 1078b3967067SJoshua Clayton ret = rtc->ops->set_offset(rtc->dev.parent, offset); 1079b3967067SJoshua Clayton mutex_unlock(&rtc->ops_lock); 108029a1f599SBaolin Wang 108129a1f599SBaolin Wang trace_rtc_set_offset(offset, ret); 1082b3967067SJoshua Clayton return ret; 1083b3967067SJoshua Clayton } 1084