at v2.6.22 6.0 kB view raw
1/* 2 * RTC subsystem, interface functions 3 * 4 * Copyright (C) 2005 Tower Technologies 5 * Author: Alessandro Zummo <a.zummo@towertech.it> 6 * 7 * based on arch/arm/common/rtctime.c 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12*/ 13 14#include <linux/rtc.h> 15 16int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) 17{ 18 int err; 19 20 err = mutex_lock_interruptible(&rtc->ops_lock); 21 if (err) 22 return -EBUSY; 23 24 if (!rtc->ops) 25 err = -ENODEV; 26 else if (!rtc->ops->read_time) 27 err = -EINVAL; 28 else { 29 memset(tm, 0, sizeof(struct rtc_time)); 30 err = rtc->ops->read_time(rtc->dev.parent, tm); 31 } 32 33 mutex_unlock(&rtc->ops_lock); 34 return err; 35} 36EXPORT_SYMBOL_GPL(rtc_read_time); 37 38int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) 39{ 40 int err; 41 42 err = rtc_valid_tm(tm); 43 if (err != 0) 44 return err; 45 46 err = mutex_lock_interruptible(&rtc->ops_lock); 47 if (err) 48 return -EBUSY; 49 50 if (!rtc->ops) 51 err = -ENODEV; 52 else if (!rtc->ops->set_time) 53 err = -EINVAL; 54 else 55 err = rtc->ops->set_time(rtc->dev.parent, tm); 56 57 mutex_unlock(&rtc->ops_lock); 58 return err; 59} 60EXPORT_SYMBOL_GPL(rtc_set_time); 61 62int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) 63{ 64 int err; 65 66 err = mutex_lock_interruptible(&rtc->ops_lock); 67 if (err) 68 return -EBUSY; 69 70 if (!rtc->ops) 71 err = -ENODEV; 72 else if (rtc->ops->set_mmss) 73 err = rtc->ops->set_mmss(rtc->dev.parent, secs); 74 else if (rtc->ops->read_time && rtc->ops->set_time) { 75 struct rtc_time new, old; 76 77 err = rtc->ops->read_time(rtc->dev.parent, &old); 78 if (err == 0) { 79 rtc_time_to_tm(secs, &new); 80 81 /* 82 * avoid writing when we're going to change the day of 83 * the month. We will retry in the next minute. This 84 * basically means that if the RTC must not drift 85 * by more than 1 minute in 11 minutes. 86 */ 87 if (!((old.tm_hour == 23 && old.tm_min == 59) || 88 (new.tm_hour == 23 && new.tm_min == 59))) 89 err = rtc->ops->set_time(rtc->dev.parent, 90 &new); 91 } 92 } 93 else 94 err = -EINVAL; 95 96 mutex_unlock(&rtc->ops_lock); 97 98 return err; 99} 100EXPORT_SYMBOL_GPL(rtc_set_mmss); 101 102int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 103{ 104 int err; 105 106 err = mutex_lock_interruptible(&rtc->ops_lock); 107 if (err) 108 return -EBUSY; 109 110 if (rtc->ops == NULL) 111 err = -ENODEV; 112 else if (!rtc->ops->read_alarm) 113 err = -EINVAL; 114 else { 115 memset(alarm, 0, sizeof(struct rtc_wkalrm)); 116 err = rtc->ops->read_alarm(rtc->dev.parent, alarm); 117 } 118 119 mutex_unlock(&rtc->ops_lock); 120 return err; 121} 122EXPORT_SYMBOL_GPL(rtc_read_alarm); 123 124int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 125{ 126 int err; 127 128 err = rtc_valid_tm(&alarm->time); 129 if (err != 0) 130 return err; 131 132 err = mutex_lock_interruptible(&rtc->ops_lock); 133 if (err) 134 return -EBUSY; 135 136 if (!rtc->ops) 137 err = -ENODEV; 138 else if (!rtc->ops->set_alarm) 139 err = -EINVAL; 140 else 141 err = rtc->ops->set_alarm(rtc->dev.parent, alarm); 142 143 mutex_unlock(&rtc->ops_lock); 144 return err; 145} 146EXPORT_SYMBOL_GPL(rtc_set_alarm); 147 148/** 149 * rtc_update_irq - report RTC periodic, alarm, and/or update irqs 150 * @rtc: the rtc device 151 * @num: how many irqs are being reported (usually one) 152 * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF 153 * Context: in_interrupt(), irqs blocked 154 */ 155void rtc_update_irq(struct rtc_device *rtc, 156 unsigned long num, unsigned long events) 157{ 158 spin_lock(&rtc->irq_lock); 159 rtc->irq_data = (rtc->irq_data + (num << 8)) | events; 160 spin_unlock(&rtc->irq_lock); 161 162 spin_lock(&rtc->irq_task_lock); 163 if (rtc->irq_task) 164 rtc->irq_task->func(rtc->irq_task->private_data); 165 spin_unlock(&rtc->irq_task_lock); 166 167 wake_up_interruptible(&rtc->irq_queue); 168 kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); 169} 170EXPORT_SYMBOL_GPL(rtc_update_irq); 171 172struct rtc_device *rtc_class_open(char *name) 173{ 174 struct device *dev; 175 struct rtc_device *rtc = NULL; 176 177 down(&rtc_class->sem); 178 list_for_each_entry(dev, &rtc_class->devices, node) { 179 if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) { 180 dev = get_device(dev); 181 if (dev) 182 rtc = to_rtc_device(dev); 183 break; 184 } 185 } 186 187 if (rtc) { 188 if (!try_module_get(rtc->owner)) { 189 put_device(dev); 190 rtc = NULL; 191 } 192 } 193 up(&rtc_class->sem); 194 195 return rtc; 196} 197EXPORT_SYMBOL_GPL(rtc_class_open); 198 199void rtc_class_close(struct rtc_device *rtc) 200{ 201 module_put(rtc->owner); 202 put_device(&rtc->dev); 203} 204EXPORT_SYMBOL_GPL(rtc_class_close); 205 206int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task) 207{ 208 int retval = -EBUSY; 209 210 if (task == NULL || task->func == NULL) 211 return -EINVAL; 212 213 spin_lock_irq(&rtc->irq_task_lock); 214 if (rtc->irq_task == NULL) { 215 rtc->irq_task = task; 216 retval = 0; 217 } 218 spin_unlock_irq(&rtc->irq_task_lock); 219 220 return retval; 221} 222EXPORT_SYMBOL_GPL(rtc_irq_register); 223 224void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task) 225{ 226 227 spin_lock_irq(&rtc->irq_task_lock); 228 if (rtc->irq_task == task) 229 rtc->irq_task = NULL; 230 spin_unlock_irq(&rtc->irq_task_lock); 231} 232EXPORT_SYMBOL_GPL(rtc_irq_unregister); 233 234int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled) 235{ 236 int err = 0; 237 unsigned long flags; 238 239 if (rtc->ops->irq_set_state == NULL) 240 return -ENXIO; 241 242 spin_lock_irqsave(&rtc->irq_task_lock, flags); 243 if (rtc->irq_task != task) 244 err = -ENXIO; 245 spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 246 247 if (err == 0) 248 err = rtc->ops->irq_set_state(rtc->dev.parent, enabled); 249 250 return err; 251} 252EXPORT_SYMBOL_GPL(rtc_irq_set_state); 253 254int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) 255{ 256 int err = 0; 257 unsigned long flags; 258 259 if (rtc->ops->irq_set_freq == NULL) 260 return -ENXIO; 261 262 spin_lock_irqsave(&rtc->irq_task_lock, flags); 263 if (rtc->irq_task != task) 264 err = -ENXIO; 265 spin_unlock_irqrestore(&rtc->irq_task_lock, flags); 266 267 if (err == 0) { 268 err = rtc->ops->irq_set_freq(rtc->dev.parent, freq); 269 if (err == 0) 270 rtc->irq_freq = freq; 271 } 272 return err; 273} 274EXPORT_SYMBOL_GPL(rtc_irq_set_freq);