10c86edc0SAlessandro Zummo /* 20c86edc0SAlessandro Zummo * RTC subsystem, interface functions 30c86edc0SAlessandro Zummo * 40c86edc0SAlessandro Zummo * Copyright (C) 2005 Tower Technologies 50c86edc0SAlessandro Zummo * Author: Alessandro Zummo <a.zummo@towertech.it> 60c86edc0SAlessandro Zummo * 70c86edc0SAlessandro Zummo * based on arch/arm/common/rtctime.c 80c86edc0SAlessandro Zummo * 90c86edc0SAlessandro Zummo * This program is free software; you can redistribute it and/or modify 100c86edc0SAlessandro Zummo * it under the terms of the GNU General Public License version 2 as 110c86edc0SAlessandro Zummo * published by the Free Software Foundation. 120c86edc0SAlessandro Zummo */ 130c86edc0SAlessandro Zummo 140c86edc0SAlessandro Zummo #include <linux/rtc.h> 15d43c36dcSAlexey Dobriyan #include <linux/sched.h> 1697144c67SDavid Brownell #include <linux/log2.h> 176610e089SJohn Stultz #include <linux/workqueue.h> 186610e089SJohn Stultz 196610e089SJohn Stultz static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) 206610e089SJohn Stultz { 216610e089SJohn Stultz int err; 226610e089SJohn Stultz if (!rtc->ops) 236610e089SJohn Stultz err = -ENODEV; 246610e089SJohn Stultz else if (!rtc->ops->read_time) 256610e089SJohn Stultz err = -EINVAL; 266610e089SJohn Stultz else { 276610e089SJohn Stultz memset(tm, 0, sizeof(struct rtc_time)); 286610e089SJohn Stultz err = rtc->ops->read_time(rtc->dev.parent, tm); 296610e089SJohn Stultz } 306610e089SJohn Stultz return err; 316610e089SJohn Stultz } 320c86edc0SAlessandro Zummo 33ab6a2d70SDavid Brownell int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) 340c86edc0SAlessandro Zummo { 350c86edc0SAlessandro Zummo int err; 360c86edc0SAlessandro Zummo 370c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock); 380c86edc0SAlessandro Zummo if (err) 39b68bb263SDavid Brownell return err; 400c86edc0SAlessandro Zummo 416610e089SJohn Stultz err = __rtc_read_time(rtc, tm); 420c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 430c86edc0SAlessandro Zummo return err; 440c86edc0SAlessandro Zummo } 450c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_read_time); 460c86edc0SAlessandro Zummo 47ab6a2d70SDavid Brownell int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) 480c86edc0SAlessandro Zummo { 490c86edc0SAlessandro Zummo int err; 500c86edc0SAlessandro Zummo 510c86edc0SAlessandro Zummo err = rtc_valid_tm(tm); 520c86edc0SAlessandro Zummo if (err != 0) 530c86edc0SAlessandro Zummo return err; 540c86edc0SAlessandro Zummo 550c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock); 560c86edc0SAlessandro Zummo if (err) 57b68bb263SDavid Brownell return err; 580c86edc0SAlessandro Zummo 590c86edc0SAlessandro Zummo if (!rtc->ops) 600c86edc0SAlessandro Zummo err = -ENODEV; 61bbccf83fSAlessandro Zummo else if (rtc->ops->set_time) 62cd966209SDavid Brownell err = rtc->ops->set_time(rtc->dev.parent, tm); 63bbccf83fSAlessandro Zummo else if (rtc->ops->set_mmss) { 64bbccf83fSAlessandro Zummo unsigned long secs; 65bbccf83fSAlessandro Zummo err = rtc_tm_to_time(tm, &secs); 66bbccf83fSAlessandro Zummo if (err == 0) 67bbccf83fSAlessandro Zummo err = rtc->ops->set_mmss(rtc->dev.parent, secs); 68bbccf83fSAlessandro Zummo } else 69bbccf83fSAlessandro Zummo err = -EINVAL; 700c86edc0SAlessandro Zummo 710c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 720c86edc0SAlessandro Zummo return err; 730c86edc0SAlessandro Zummo } 740c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_set_time); 750c86edc0SAlessandro Zummo 76ab6a2d70SDavid Brownell int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) 770c86edc0SAlessandro Zummo { 780c86edc0SAlessandro Zummo int err; 790c86edc0SAlessandro Zummo 800c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock); 810c86edc0SAlessandro Zummo if (err) 82b68bb263SDavid Brownell return err; 830c86edc0SAlessandro Zummo 840c86edc0SAlessandro Zummo if (!rtc->ops) 850c86edc0SAlessandro Zummo err = -ENODEV; 860c86edc0SAlessandro Zummo else if (rtc->ops->set_mmss) 87cd966209SDavid Brownell err = rtc->ops->set_mmss(rtc->dev.parent, secs); 880c86edc0SAlessandro Zummo else if (rtc->ops->read_time && rtc->ops->set_time) { 890c86edc0SAlessandro Zummo struct rtc_time new, old; 900c86edc0SAlessandro Zummo 91cd966209SDavid Brownell err = rtc->ops->read_time(rtc->dev.parent, &old); 920c86edc0SAlessandro Zummo if (err == 0) { 930c86edc0SAlessandro Zummo rtc_time_to_tm(secs, &new); 940c86edc0SAlessandro Zummo 950c86edc0SAlessandro Zummo /* 960c86edc0SAlessandro Zummo * avoid writing when we're going to change the day of 970c86edc0SAlessandro Zummo * the month. We will retry in the next minute. This 980c86edc0SAlessandro Zummo * basically means that if the RTC must not drift 990c86edc0SAlessandro Zummo * by more than 1 minute in 11 minutes. 1000c86edc0SAlessandro Zummo */ 1010c86edc0SAlessandro Zummo if (!((old.tm_hour == 23 && old.tm_min == 59) || 1020c86edc0SAlessandro Zummo (new.tm_hour == 23 && new.tm_min == 59))) 103cd966209SDavid Brownell err = rtc->ops->set_time(rtc->dev.parent, 104ab6a2d70SDavid Brownell &new); 1050c86edc0SAlessandro Zummo } 1060c86edc0SAlessandro Zummo } 1070c86edc0SAlessandro Zummo else 1080c86edc0SAlessandro Zummo err = -EINVAL; 1090c86edc0SAlessandro Zummo 1100c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 1110c86edc0SAlessandro Zummo 1120c86edc0SAlessandro Zummo return err; 1130c86edc0SAlessandro Zummo } 1140c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_set_mmss); 1150c86edc0SAlessandro Zummo 1166610e089SJohn Stultz int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 1170c86edc0SAlessandro Zummo { 1180c86edc0SAlessandro Zummo int err; 1190c86edc0SAlessandro Zummo 1200c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock); 1210c86edc0SAlessandro Zummo if (err) 122b68bb263SDavid Brownell return err; 1236610e089SJohn Stultz alarm->enabled = rtc->aie_timer.enabled; 1246610e089SJohn Stultz if (alarm->enabled) 1256610e089SJohn Stultz alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires); 1260c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 1270e36a9a4SMark Lord 1280e36a9a4SMark Lord return 0; 1290e36a9a4SMark Lord } 1300c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_read_alarm); 1310c86edc0SAlessandro Zummo 1326610e089SJohn Stultz int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 1336610e089SJohn Stultz { 1346610e089SJohn Stultz struct rtc_time tm; 1356610e089SJohn Stultz long now, scheduled; 1366610e089SJohn Stultz int err; 1376610e089SJohn Stultz 1386610e089SJohn Stultz err = rtc_valid_tm(&alarm->time); 1396610e089SJohn Stultz if (err) 1406610e089SJohn Stultz return err; 1416610e089SJohn Stultz rtc_tm_to_time(&alarm->time, &scheduled); 1426610e089SJohn Stultz 1436610e089SJohn Stultz /* Make sure we're not setting alarms in the past */ 1446610e089SJohn Stultz err = __rtc_read_time(rtc, &tm); 1456610e089SJohn Stultz rtc_tm_to_time(&tm, &now); 1466610e089SJohn Stultz if (scheduled <= now) 1476610e089SJohn Stultz return -ETIME; 1486610e089SJohn Stultz /* 1496610e089SJohn Stultz * XXX - We just checked to make sure the alarm time is not 1506610e089SJohn Stultz * in the past, but there is still a race window where if 1516610e089SJohn Stultz * the is alarm set for the next second and the second ticks 1526610e089SJohn Stultz * over right here, before we set the alarm. 1536610e089SJohn Stultz */ 1546610e089SJohn Stultz 1556610e089SJohn Stultz if (!rtc->ops) 1566610e089SJohn Stultz err = -ENODEV; 1576610e089SJohn Stultz else if (!rtc->ops->set_alarm) 1586610e089SJohn Stultz err = -EINVAL; 1596610e089SJohn Stultz else 1606610e089SJohn Stultz err = rtc->ops->set_alarm(rtc->dev.parent, alarm); 1616610e089SJohn Stultz 1626610e089SJohn Stultz return err; 1636610e089SJohn Stultz } 1646610e089SJohn Stultz 165ab6a2d70SDavid Brownell int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 1660c86edc0SAlessandro Zummo { 1670c86edc0SAlessandro Zummo int err; 1680c86edc0SAlessandro Zummo 169f8245c26SDavid Brownell err = rtc_valid_tm(&alarm->time); 170f8245c26SDavid Brownell if (err != 0) 171f8245c26SDavid Brownell return err; 172f8245c26SDavid Brownell 1730c86edc0SAlessandro Zummo err = mutex_lock_interruptible(&rtc->ops_lock); 1740c86edc0SAlessandro Zummo if (err) 175b68bb263SDavid Brownell return err; 1766610e089SJohn Stultz if (rtc->aie_timer.enabled) { 177*96c8f06aSThomas Gleixner rtc_timer_remove(rtc, &rtc->aie_timer); 1786610e089SJohn Stultz rtc->aie_timer.enabled = 0; 1796610e089SJohn Stultz } 1806610e089SJohn Stultz rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); 1816610e089SJohn Stultz rtc->aie_timer.period = ktime_set(0, 0); 1826610e089SJohn Stultz if (alarm->enabled) { 1836610e089SJohn Stultz rtc->aie_timer.enabled = 1; 184*96c8f06aSThomas Gleixner rtc_timer_enqueue(rtc, &rtc->aie_timer); 1856610e089SJohn Stultz } 1860c86edc0SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 1876610e089SJohn Stultz return 0; 1880c86edc0SAlessandro Zummo } 1890c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_set_alarm); 1900c86edc0SAlessandro Zummo 191099e6576SAlessandro Zummo int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) 192099e6576SAlessandro Zummo { 193099e6576SAlessandro Zummo int err = mutex_lock_interruptible(&rtc->ops_lock); 194099e6576SAlessandro Zummo if (err) 195099e6576SAlessandro Zummo return err; 196099e6576SAlessandro Zummo 1976610e089SJohn Stultz if (rtc->aie_timer.enabled != enabled) { 1986610e089SJohn Stultz if (enabled) { 1996610e089SJohn Stultz rtc->aie_timer.enabled = 1; 200*96c8f06aSThomas Gleixner rtc_timer_enqueue(rtc, &rtc->aie_timer); 2016610e089SJohn Stultz } else { 202*96c8f06aSThomas Gleixner rtc_timer_remove(rtc, &rtc->aie_timer); 2036610e089SJohn Stultz rtc->aie_timer.enabled = 0; 2046610e089SJohn Stultz } 2056610e089SJohn Stultz } 2066610e089SJohn Stultz 207099e6576SAlessandro Zummo if (!rtc->ops) 208099e6576SAlessandro Zummo err = -ENODEV; 209099e6576SAlessandro Zummo else if (!rtc->ops->alarm_irq_enable) 210099e6576SAlessandro Zummo err = -EINVAL; 211099e6576SAlessandro Zummo else 212099e6576SAlessandro Zummo err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled); 213099e6576SAlessandro Zummo 214099e6576SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 215099e6576SAlessandro Zummo return err; 216099e6576SAlessandro Zummo } 217099e6576SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable); 218099e6576SAlessandro Zummo 219099e6576SAlessandro Zummo int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) 220099e6576SAlessandro Zummo { 221099e6576SAlessandro Zummo int err = mutex_lock_interruptible(&rtc->ops_lock); 222099e6576SAlessandro Zummo if (err) 223099e6576SAlessandro Zummo return err; 224099e6576SAlessandro Zummo 2256610e089SJohn Stultz /* make sure we're changing state */ 2266610e089SJohn Stultz if (rtc->uie_rtctimer.enabled == enabled) 2276610e089SJohn Stultz goto out; 2286610e089SJohn Stultz 2296610e089SJohn Stultz if (enabled) { 2306610e089SJohn Stultz struct rtc_time tm; 2316610e089SJohn Stultz ktime_t now, onesec; 2326610e089SJohn Stultz 2336610e089SJohn Stultz __rtc_read_time(rtc, &tm); 2346610e089SJohn Stultz onesec = ktime_set(1, 0); 2356610e089SJohn Stultz now = rtc_tm_to_ktime(tm); 2366610e089SJohn Stultz rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); 2376610e089SJohn Stultz rtc->uie_rtctimer.period = ktime_set(1, 0); 2386610e089SJohn Stultz rtc->uie_rtctimer.enabled = 1; 239*96c8f06aSThomas Gleixner rtc_timer_enqueue(rtc, &rtc->uie_rtctimer); 2406610e089SJohn Stultz } else { 241*96c8f06aSThomas Gleixner rtc_timer_remove(rtc, &rtc->uie_rtctimer); 2426610e089SJohn Stultz rtc->uie_rtctimer.enabled = 0; 243099e6576SAlessandro Zummo } 244099e6576SAlessandro Zummo 2456610e089SJohn Stultz out: 246099e6576SAlessandro Zummo mutex_unlock(&rtc->ops_lock); 247099e6576SAlessandro Zummo return err; 2486610e089SJohn Stultz 249099e6576SAlessandro Zummo } 250099e6576SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_update_irq_enable); 251099e6576SAlessandro Zummo 2526610e089SJohn Stultz 253d728b1e6SDavid Brownell /** 2546610e089SJohn Stultz * rtc_handle_legacy_irq - AIE, UIE and PIE event hook 2556610e089SJohn Stultz * @rtc: pointer to the rtc device 2566610e089SJohn Stultz * 2576610e089SJohn Stultz * This function is called when an AIE, UIE or PIE mode interrupt 2586610e089SJohn Stultz * has occured (or been emulated). 2596610e089SJohn Stultz * 2606610e089SJohn Stultz * Triggers the registered irq_task function callback. 2616610e089SJohn Stultz */ 2626610e089SJohn Stultz static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) 2636610e089SJohn Stultz { 2646610e089SJohn Stultz unsigned long flags; 2656610e089SJohn Stultz 2666610e089SJohn Stultz /* mark one irq of the appropriate mode */ 2676610e089SJohn Stultz spin_lock_irqsave(&rtc->irq_lock, flags); 2686610e089SJohn Stultz rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode); 2696610e089SJohn Stultz spin_unlock_irqrestore(&rtc->irq_lock, flags); 2706610e089SJohn Stultz 2716610e089SJohn Stultz /* call the task func */ 2726610e089SJohn Stultz spin_lock_irqsave(&rtc->irq_task_lock, flags); 2736610e089SJohn Stultz if (rtc->irq_task) 2746610e089SJohn Stultz rtc->irq_task->func(rtc->irq_task->private_data); 2756610e089SJohn Stultz spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 2766610e089SJohn Stultz 2776610e089SJohn Stultz wake_up_interruptible(&rtc->irq_queue); 2786610e089SJohn Stultz kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); 2796610e089SJohn Stultz } 2806610e089SJohn Stultz 2816610e089SJohn Stultz 2826610e089SJohn Stultz /** 2836610e089SJohn Stultz * rtc_aie_update_irq - AIE mode rtctimer hook 2846610e089SJohn Stultz * @private: pointer to the rtc_device 2856610e089SJohn Stultz * 2866610e089SJohn Stultz * This functions is called when the aie_timer expires. 2876610e089SJohn Stultz */ 2886610e089SJohn Stultz void rtc_aie_update_irq(void *private) 2896610e089SJohn Stultz { 2906610e089SJohn Stultz struct rtc_device *rtc = (struct rtc_device *)private; 2916610e089SJohn Stultz rtc_handle_legacy_irq(rtc, 1, RTC_AF); 2926610e089SJohn Stultz } 2936610e089SJohn Stultz 2946610e089SJohn Stultz 2956610e089SJohn Stultz /** 2966610e089SJohn Stultz * rtc_uie_update_irq - UIE mode rtctimer hook 2976610e089SJohn Stultz * @private: pointer to the rtc_device 2986610e089SJohn Stultz * 2996610e089SJohn Stultz * This functions is called when the uie_timer expires. 3006610e089SJohn Stultz */ 3016610e089SJohn Stultz void rtc_uie_update_irq(void *private) 3026610e089SJohn Stultz { 3036610e089SJohn Stultz struct rtc_device *rtc = (struct rtc_device *)private; 3046610e089SJohn Stultz rtc_handle_legacy_irq(rtc, 1, RTC_UF); 3056610e089SJohn Stultz } 3066610e089SJohn Stultz 3076610e089SJohn Stultz 3086610e089SJohn Stultz /** 3096610e089SJohn Stultz * rtc_pie_update_irq - PIE mode hrtimer hook 3106610e089SJohn Stultz * @timer: pointer to the pie mode hrtimer 3116610e089SJohn Stultz * 3126610e089SJohn Stultz * This function is used to emulate PIE mode interrupts 3136610e089SJohn Stultz * using an hrtimer. This function is called when the periodic 3146610e089SJohn Stultz * hrtimer expires. 3156610e089SJohn Stultz */ 3166610e089SJohn Stultz enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) 3176610e089SJohn Stultz { 3186610e089SJohn Stultz struct rtc_device *rtc; 3196610e089SJohn Stultz ktime_t period; 3206610e089SJohn Stultz int count; 3216610e089SJohn Stultz rtc = container_of(timer, struct rtc_device, pie_timer); 3226610e089SJohn Stultz 3236610e089SJohn Stultz period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); 3246610e089SJohn Stultz count = hrtimer_forward_now(timer, period); 3256610e089SJohn Stultz 3266610e089SJohn Stultz rtc_handle_legacy_irq(rtc, count, RTC_PF); 3276610e089SJohn Stultz 3286610e089SJohn Stultz return HRTIMER_RESTART; 3296610e089SJohn Stultz } 3306610e089SJohn Stultz 3316610e089SJohn Stultz /** 3326610e089SJohn Stultz * rtc_update_irq - Triggered when a RTC interrupt occurs. 333ab6a2d70SDavid Brownell * @rtc: the rtc device 334d728b1e6SDavid Brownell * @num: how many irqs are being reported (usually one) 335d728b1e6SDavid Brownell * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF 336e6229becSAtsushi Nemoto * Context: any 337d728b1e6SDavid Brownell */ 338ab6a2d70SDavid Brownell void rtc_update_irq(struct rtc_device *rtc, 3390c86edc0SAlessandro Zummo unsigned long num, unsigned long events) 3400c86edc0SAlessandro Zummo { 3416610e089SJohn Stultz schedule_work(&rtc->irqwork); 3420c86edc0SAlessandro Zummo } 3430c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_update_irq); 3440c86edc0SAlessandro Zummo 34571da8905SDave Young static int __rtc_match(struct device *dev, void *data) 34671da8905SDave Young { 34771da8905SDave Young char *name = (char *)data; 34871da8905SDave Young 349d4afc76cSKay Sievers if (strcmp(dev_name(dev), name) == 0) 35071da8905SDave Young return 1; 35171da8905SDave Young return 0; 35271da8905SDave Young } 35371da8905SDave Young 354ab6a2d70SDavid Brownell struct rtc_device *rtc_class_open(char *name) 3550c86edc0SAlessandro Zummo { 356cd966209SDavid Brownell struct device *dev; 357ab6a2d70SDavid Brownell struct rtc_device *rtc = NULL; 3580c86edc0SAlessandro Zummo 359695794aeSGreg Kroah-Hartman dev = class_find_device(rtc_class, NULL, name, __rtc_match); 360cd966209SDavid Brownell if (dev) 361cd966209SDavid Brownell rtc = to_rtc_device(dev); 3620c86edc0SAlessandro Zummo 363ab6a2d70SDavid Brownell if (rtc) { 364ab6a2d70SDavid Brownell if (!try_module_get(rtc->owner)) { 365cd966209SDavid Brownell put_device(dev); 366ab6a2d70SDavid Brownell rtc = NULL; 367ab6a2d70SDavid Brownell } 3680c86edc0SAlessandro Zummo } 3690c86edc0SAlessandro Zummo 370ab6a2d70SDavid Brownell return rtc; 3710c86edc0SAlessandro Zummo } 3720c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_class_open); 3730c86edc0SAlessandro Zummo 374ab6a2d70SDavid Brownell void rtc_class_close(struct rtc_device *rtc) 3750c86edc0SAlessandro Zummo { 376ab6a2d70SDavid Brownell module_put(rtc->owner); 377cd966209SDavid Brownell put_device(&rtc->dev); 3780c86edc0SAlessandro Zummo } 3790c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_class_close); 3800c86edc0SAlessandro Zummo 381ab6a2d70SDavid Brownell int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) 3820c86edc0SAlessandro Zummo { 3830c86edc0SAlessandro Zummo int retval = -EBUSY; 3840c86edc0SAlessandro Zummo 3850c86edc0SAlessandro Zummo if (task == NULL || task->func == NULL) 3860c86edc0SAlessandro Zummo return -EINVAL; 3870c86edc0SAlessandro Zummo 388d691eb90SAlessandro Zummo /* Cannot register while the char dev is in use */ 389372a302eSJiri Kosina if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags)) 390d691eb90SAlessandro Zummo return -EBUSY; 391d691eb90SAlessandro Zummo 392d728b1e6SDavid Brownell spin_lock_irq(&rtc->irq_task_lock); 3930c86edc0SAlessandro Zummo if (rtc->irq_task == NULL) { 3940c86edc0SAlessandro Zummo rtc->irq_task = task; 3950c86edc0SAlessandro Zummo retval = 0; 3960c86edc0SAlessandro Zummo } 397d728b1e6SDavid Brownell spin_unlock_irq(&rtc->irq_task_lock); 3980c86edc0SAlessandro Zummo 399372a302eSJiri Kosina clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags); 400d691eb90SAlessandro Zummo 4010c86edc0SAlessandro Zummo return retval; 4020c86edc0SAlessandro Zummo } 4030c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_irq_register); 4040c86edc0SAlessandro Zummo 405ab6a2d70SDavid Brownell void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) 4060c86edc0SAlessandro Zummo { 407d728b1e6SDavid Brownell spin_lock_irq(&rtc->irq_task_lock); 4080c86edc0SAlessandro Zummo if (rtc->irq_task == task) 4090c86edc0SAlessandro Zummo rtc->irq_task = NULL; 410d728b1e6SDavid Brownell spin_unlock_irq(&rtc->irq_task_lock); 4110c86edc0SAlessandro Zummo } 4120c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_irq_unregister); 4130c86edc0SAlessandro Zummo 41497144c67SDavid Brownell /** 41597144c67SDavid Brownell * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs 41697144c67SDavid Brownell * @rtc: the rtc device 41797144c67SDavid Brownell * @task: currently registered with rtc_irq_register() 41897144c67SDavid Brownell * @enabled: true to enable periodic IRQs 41997144c67SDavid Brownell * Context: any 42097144c67SDavid Brownell * 42197144c67SDavid Brownell * Note that rtc_irq_set_freq() should previously have been used to 42297144c67SDavid Brownell * specify the desired frequency of periodic IRQ task->func() callbacks. 42397144c67SDavid Brownell */ 424ab6a2d70SDavid Brownell int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) 4250c86edc0SAlessandro Zummo { 4260c86edc0SAlessandro Zummo int err = 0; 4270c86edc0SAlessandro Zummo unsigned long flags; 4280c86edc0SAlessandro Zummo 4290c86edc0SAlessandro Zummo spin_lock_irqsave(&rtc->irq_task_lock, flags); 430d691eb90SAlessandro Zummo if (rtc->irq_task != NULL && task == NULL) 431d691eb90SAlessandro Zummo err = -EBUSY; 4320c86edc0SAlessandro Zummo if (rtc->irq_task != task) 433d691eb90SAlessandro Zummo err = -EACCES; 4340c86edc0SAlessandro Zummo 4356610e089SJohn Stultz if (enabled) { 4366610e089SJohn Stultz ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); 4376610e089SJohn Stultz hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL); 4386610e089SJohn Stultz } else { 4396610e089SJohn Stultz hrtimer_cancel(&rtc->pie_timer); 4406610e089SJohn Stultz } 4416610e089SJohn Stultz rtc->pie_enabled = enabled; 4426610e089SJohn Stultz spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 4430c86edc0SAlessandro Zummo 4440c86edc0SAlessandro Zummo return err; 4450c86edc0SAlessandro Zummo } 4460c86edc0SAlessandro Zummo EXPORT_SYMBOL_GPL(rtc_irq_set_state); 4470c86edc0SAlessandro Zummo 44897144c67SDavid Brownell /** 44997144c67SDavid Brownell * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ 45097144c67SDavid Brownell * @rtc: the rtc device 45197144c67SDavid Brownell * @task: currently registered with rtc_irq_register() 45297144c67SDavid Brownell * @freq: positive frequency with which task->func() will be called 45397144c67SDavid Brownell * Context: any 45497144c67SDavid Brownell * 45597144c67SDavid Brownell * Note that rtc_irq_set_state() is used to enable or disable the 45697144c67SDavid Brownell * periodic IRQs. 45797144c67SDavid Brownell */ 458ab6a2d70SDavid Brownell int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) 4590c86edc0SAlessandro Zummo { 46056f10c63SAlessandro Zummo int err = 0; 4610c86edc0SAlessandro Zummo unsigned long flags; 4620c86edc0SAlessandro Zummo 4630c86edc0SAlessandro Zummo spin_lock_irqsave(&rtc->irq_task_lock, flags); 464d691eb90SAlessandro Zummo if (rtc->irq_task != NULL && task == NULL) 465d691eb90SAlessandro Zummo err = -EBUSY; 4660c86edc0SAlessandro Zummo if (rtc->irq_task != task) 467d691eb90SAlessandro Zummo err = -EACCES; 4680c86edc0SAlessandro Zummo if (err == 0) { 4690c86edc0SAlessandro Zummo rtc->irq_freq = freq; 4706610e089SJohn Stultz if (rtc->pie_enabled) { 4716610e089SJohn Stultz ktime_t period; 4726610e089SJohn Stultz hrtimer_cancel(&rtc->pie_timer); 4736610e089SJohn Stultz period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); 4746610e089SJohn Stultz hrtimer_start(&rtc->pie_timer, period, 4756610e089SJohn Stultz HRTIMER_MODE_REL); 4760c86edc0SAlessandro Zummo } 4776610e089SJohn Stultz } 4786610e089SJohn Stultz spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 4790c86edc0SAlessandro Zummo return err; 4800c86edc0SAlessandro Zummo } 4812601a464SDavid Brownell EXPORT_SYMBOL_GPL(rtc_irq_set_freq); 4826610e089SJohn Stultz 4836610e089SJohn Stultz /** 484*96c8f06aSThomas Gleixner * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue 4856610e089SJohn Stultz * @rtc rtc device 4866610e089SJohn Stultz * @timer timer being added. 4876610e089SJohn Stultz * 4886610e089SJohn Stultz * Enqueues a timer onto the rtc devices timerqueue and sets 4896610e089SJohn Stultz * the next alarm event appropriately. 4906610e089SJohn Stultz * 4916610e089SJohn Stultz * Must hold ops_lock for proper serialization of timerqueue 4926610e089SJohn Stultz */ 493*96c8f06aSThomas Gleixner void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) 4946610e089SJohn Stultz { 4956610e089SJohn Stultz timerqueue_add(&rtc->timerqueue, &timer->node); 4966610e089SJohn Stultz if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) { 4976610e089SJohn Stultz struct rtc_wkalrm alarm; 4986610e089SJohn Stultz int err; 4996610e089SJohn Stultz alarm.time = rtc_ktime_to_tm(timer->node.expires); 5006610e089SJohn Stultz alarm.enabled = 1; 5016610e089SJohn Stultz err = __rtc_set_alarm(rtc, &alarm); 5026610e089SJohn Stultz if (err == -ETIME) 5036610e089SJohn Stultz schedule_work(&rtc->irqwork); 5046610e089SJohn Stultz } 5056610e089SJohn Stultz } 5066610e089SJohn Stultz 5076610e089SJohn Stultz /** 508*96c8f06aSThomas Gleixner * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue 5096610e089SJohn Stultz * @rtc rtc device 5106610e089SJohn Stultz * @timer timer being removed. 5116610e089SJohn Stultz * 5126610e089SJohn Stultz * Removes a timer onto the rtc devices timerqueue and sets 5136610e089SJohn Stultz * the next alarm event appropriately. 5146610e089SJohn Stultz * 5156610e089SJohn Stultz * Must hold ops_lock for proper serialization of timerqueue 5166610e089SJohn Stultz */ 517*96c8f06aSThomas Gleixner void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) 5186610e089SJohn Stultz { 5196610e089SJohn Stultz struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); 5206610e089SJohn Stultz timerqueue_del(&rtc->timerqueue, &timer->node); 5216610e089SJohn Stultz 5226610e089SJohn Stultz if (next == &timer->node) { 5236610e089SJohn Stultz struct rtc_wkalrm alarm; 5246610e089SJohn Stultz int err; 5256610e089SJohn Stultz next = timerqueue_getnext(&rtc->timerqueue); 5266610e089SJohn Stultz if (!next) 5276610e089SJohn Stultz return; 5286610e089SJohn Stultz alarm.time = rtc_ktime_to_tm(next->expires); 5296610e089SJohn Stultz alarm.enabled = 1; 5306610e089SJohn Stultz err = __rtc_set_alarm(rtc, &alarm); 5316610e089SJohn Stultz if (err == -ETIME) 5326610e089SJohn Stultz schedule_work(&rtc->irqwork); 5336610e089SJohn Stultz } 5346610e089SJohn Stultz } 5356610e089SJohn Stultz 5366610e089SJohn Stultz /** 537*96c8f06aSThomas Gleixner * rtc_timer_do_work - Expires rtc timers 5386610e089SJohn Stultz * @rtc rtc device 5396610e089SJohn Stultz * @timer timer being removed. 5406610e089SJohn Stultz * 5416610e089SJohn Stultz * Expires rtc timers. Reprograms next alarm event if needed. 5426610e089SJohn Stultz * Called via worktask. 5436610e089SJohn Stultz * 5446610e089SJohn Stultz * Serializes access to timerqueue via ops_lock mutex 5456610e089SJohn Stultz */ 546*96c8f06aSThomas Gleixner void rtc_timer_do_work(struct work_struct *work) 5476610e089SJohn Stultz { 5486610e089SJohn Stultz struct rtc_timer *timer; 5496610e089SJohn Stultz struct timerqueue_node *next; 5506610e089SJohn Stultz ktime_t now; 5516610e089SJohn Stultz struct rtc_time tm; 5526610e089SJohn Stultz 5536610e089SJohn Stultz struct rtc_device *rtc = 5546610e089SJohn Stultz container_of(work, struct rtc_device, irqwork); 5556610e089SJohn Stultz 5566610e089SJohn Stultz mutex_lock(&rtc->ops_lock); 5576610e089SJohn Stultz again: 5586610e089SJohn Stultz __rtc_read_time(rtc, &tm); 5596610e089SJohn Stultz now = rtc_tm_to_ktime(tm); 5606610e089SJohn Stultz while ((next = timerqueue_getnext(&rtc->timerqueue))) { 5616610e089SJohn Stultz if (next->expires.tv64 > now.tv64) 5626610e089SJohn Stultz break; 5636610e089SJohn Stultz 5646610e089SJohn Stultz /* expire timer */ 5656610e089SJohn Stultz timer = container_of(next, struct rtc_timer, node); 5666610e089SJohn Stultz timerqueue_del(&rtc->timerqueue, &timer->node); 5676610e089SJohn Stultz timer->enabled = 0; 5686610e089SJohn Stultz if (timer->task.func) 5696610e089SJohn Stultz timer->task.func(timer->task.private_data); 5706610e089SJohn Stultz 5716610e089SJohn Stultz /* Re-add/fwd periodic timers */ 5726610e089SJohn Stultz if (ktime_to_ns(timer->period)) { 5736610e089SJohn Stultz timer->node.expires = ktime_add(timer->node.expires, 5746610e089SJohn Stultz timer->period); 5756610e089SJohn Stultz timer->enabled = 1; 5766610e089SJohn Stultz timerqueue_add(&rtc->timerqueue, &timer->node); 5776610e089SJohn Stultz } 5786610e089SJohn Stultz } 5796610e089SJohn Stultz 5806610e089SJohn Stultz /* Set next alarm */ 5816610e089SJohn Stultz if (next) { 5826610e089SJohn Stultz struct rtc_wkalrm alarm; 5836610e089SJohn Stultz int err; 5846610e089SJohn Stultz alarm.time = rtc_ktime_to_tm(next->expires); 5856610e089SJohn Stultz alarm.enabled = 1; 5866610e089SJohn Stultz err = __rtc_set_alarm(rtc, &alarm); 5876610e089SJohn Stultz if (err == -ETIME) 5886610e089SJohn Stultz goto again; 5896610e089SJohn Stultz } 5906610e089SJohn Stultz 5916610e089SJohn Stultz mutex_unlock(&rtc->ops_lock); 5926610e089SJohn Stultz } 5936610e089SJohn Stultz 5946610e089SJohn Stultz 595*96c8f06aSThomas Gleixner /* rtc_timer_init - Initializes an rtc_timer 5966610e089SJohn Stultz * @timer: timer to be intiialized 5976610e089SJohn Stultz * @f: function pointer to be called when timer fires 5986610e089SJohn Stultz * @data: private data passed to function pointer 5996610e089SJohn Stultz * 6006610e089SJohn Stultz * Kernel interface to initializing an rtc_timer. 6016610e089SJohn Stultz */ 602*96c8f06aSThomas Gleixner void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) 6036610e089SJohn Stultz { 6046610e089SJohn Stultz timerqueue_init(&timer->node); 6056610e089SJohn Stultz timer->enabled = 0; 6066610e089SJohn Stultz timer->task.func = f; 6076610e089SJohn Stultz timer->task.private_data = data; 6086610e089SJohn Stultz } 6096610e089SJohn Stultz 610*96c8f06aSThomas Gleixner /* rtc_timer_start - Sets an rtc_timer to fire in the future 6116610e089SJohn Stultz * @ rtc: rtc device to be used 6126610e089SJohn Stultz * @ timer: timer being set 6136610e089SJohn Stultz * @ expires: time at which to expire the timer 6146610e089SJohn Stultz * @ period: period that the timer will recur 6156610e089SJohn Stultz * 6166610e089SJohn Stultz * Kernel interface to set an rtc_timer 6176610e089SJohn Stultz */ 618*96c8f06aSThomas Gleixner int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, 6196610e089SJohn Stultz ktime_t expires, ktime_t period) 6206610e089SJohn Stultz { 6216610e089SJohn Stultz int ret = 0; 6226610e089SJohn Stultz mutex_lock(&rtc->ops_lock); 6236610e089SJohn Stultz if (timer->enabled) 624*96c8f06aSThomas Gleixner rtc_timer_remove(rtc, timer); 6256610e089SJohn Stultz 6266610e089SJohn Stultz timer->node.expires = expires; 6276610e089SJohn Stultz timer->period = period; 6286610e089SJohn Stultz 6296610e089SJohn Stultz timer->enabled = 1; 630*96c8f06aSThomas Gleixner rtc_timer_enqueue(rtc, timer); 6316610e089SJohn Stultz 6326610e089SJohn Stultz mutex_unlock(&rtc->ops_lock); 6336610e089SJohn Stultz return ret; 6346610e089SJohn Stultz } 6356610e089SJohn Stultz 636*96c8f06aSThomas Gleixner /* rtc_timer_cancel - Stops an rtc_timer 6376610e089SJohn Stultz * @ rtc: rtc device to be used 6386610e089SJohn Stultz * @ timer: timer being set 6396610e089SJohn Stultz * 6406610e089SJohn Stultz * Kernel interface to cancel an rtc_timer 6416610e089SJohn Stultz */ 642*96c8f06aSThomas Gleixner int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) 6436610e089SJohn Stultz { 6446610e089SJohn Stultz int ret = 0; 6456610e089SJohn Stultz mutex_lock(&rtc->ops_lock); 6466610e089SJohn Stultz if (timer->enabled) 647*96c8f06aSThomas Gleixner rtc_timer_remove(rtc, timer); 6486610e089SJohn Stultz timer->enabled = 0; 6496610e089SJohn Stultz mutex_unlock(&rtc->ops_lock); 6506610e089SJohn Stultz return ret; 6516610e089SJohn Stultz } 6526610e089SJohn Stultz 6536610e089SJohn Stultz 654