interface.c revision 2601a46474db2dcbc08ee690e56f08a10abe65cb
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 class_device *class_dev, struct rtc_time *tm)
17{
18	int err;
19	struct rtc_device *rtc = to_rtc_device(class_dev);
20
21	err = mutex_lock_interruptible(&rtc->ops_lock);
22	if (err)
23		return -EBUSY;
24
25	if (!rtc->ops)
26		err = -ENODEV;
27	else if (!rtc->ops->read_time)
28		err = -EINVAL;
29	else {
30		memset(tm, 0, sizeof(struct rtc_time));
31		err = rtc->ops->read_time(class_dev->dev, tm);
32	}
33
34	mutex_unlock(&rtc->ops_lock);
35	return err;
36}
37EXPORT_SYMBOL_GPL(rtc_read_time);
38
39int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
40{
41	int err;
42	struct rtc_device *rtc = to_rtc_device(class_dev);
43
44	err = rtc_valid_tm(tm);
45	if (err != 0)
46		return err;
47
48	err = mutex_lock_interruptible(&rtc->ops_lock);
49	if (err)
50		return -EBUSY;
51
52	if (!rtc->ops)
53		err = -ENODEV;
54	else if (!rtc->ops->set_time)
55		err = -EINVAL;
56	else
57		err = rtc->ops->set_time(class_dev->dev, tm);
58
59	mutex_unlock(&rtc->ops_lock);
60	return err;
61}
62EXPORT_SYMBOL_GPL(rtc_set_time);
63
64int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
65{
66	int err;
67	struct rtc_device *rtc = to_rtc_device(class_dev);
68
69	err = mutex_lock_interruptible(&rtc->ops_lock);
70	if (err)
71		return -EBUSY;
72
73	if (!rtc->ops)
74		err = -ENODEV;
75	else if (rtc->ops->set_mmss)
76		err = rtc->ops->set_mmss(class_dev->dev, secs);
77	else if (rtc->ops->read_time && rtc->ops->set_time) {
78		struct rtc_time new, old;
79
80		err = rtc->ops->read_time(class_dev->dev, &old);
81		if (err == 0) {
82			rtc_time_to_tm(secs, &new);
83
84			/*
85			 * avoid writing when we're going to change the day of
86			 * the month. We will retry in the next minute. This
87			 * basically means that if the RTC must not drift
88			 * by more than 1 minute in 11 minutes.
89			 */
90			if (!((old.tm_hour == 23 && old.tm_min == 59) ||
91				(new.tm_hour == 23 && new.tm_min == 59)))
92				err = rtc->ops->set_time(class_dev->dev, &new);
93		}
94	}
95	else
96		err = -EINVAL;
97
98	mutex_unlock(&rtc->ops_lock);
99
100	return err;
101}
102EXPORT_SYMBOL_GPL(rtc_set_mmss);
103
104int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
105{
106	int err;
107	struct rtc_device *rtc = to_rtc_device(class_dev);
108
109	err = mutex_lock_interruptible(&rtc->ops_lock);
110	if (err)
111		return -EBUSY;
112
113	if (rtc->ops == NULL)
114		err = -ENODEV;
115	else if (!rtc->ops->read_alarm)
116		err = -EINVAL;
117	else {
118		memset(alarm, 0, sizeof(struct rtc_wkalrm));
119		err = rtc->ops->read_alarm(class_dev->dev, alarm);
120	}
121
122	mutex_unlock(&rtc->ops_lock);
123	return err;
124}
125EXPORT_SYMBOL_GPL(rtc_read_alarm);
126
127int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
128{
129	int err;
130	struct rtc_device *rtc = to_rtc_device(class_dev);
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(class_dev->dev, alarm);
142
143	mutex_unlock(&rtc->ops_lock);
144	return err;
145}
146EXPORT_SYMBOL_GPL(rtc_set_alarm);
147
148void rtc_update_irq(struct class_device *class_dev,
149		unsigned long num, unsigned long events)
150{
151	struct rtc_device *rtc = to_rtc_device(class_dev);
152
153	spin_lock(&rtc->irq_lock);
154	rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
155	spin_unlock(&rtc->irq_lock);
156
157	spin_lock(&rtc->irq_task_lock);
158	if (rtc->irq_task)
159		rtc->irq_task->func(rtc->irq_task->private_data);
160	spin_unlock(&rtc->irq_task_lock);
161
162	wake_up_interruptible(&rtc->irq_queue);
163	kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
164}
165EXPORT_SYMBOL_GPL(rtc_update_irq);
166
167struct class_device *rtc_class_open(char *name)
168{
169	struct class_device *class_dev = NULL,
170				*class_dev_tmp;
171
172	down(&rtc_class->sem);
173	list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
174		if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
175			class_dev = class_dev_tmp;
176			break;
177		}
178	}
179
180	if (class_dev) {
181		if (!try_module_get(to_rtc_device(class_dev)->owner))
182			class_dev = NULL;
183	}
184	up(&rtc_class->sem);
185
186	return class_dev;
187}
188EXPORT_SYMBOL_GPL(rtc_class_open);
189
190void rtc_class_close(struct class_device *class_dev)
191{
192	module_put(to_rtc_device(class_dev)->owner);
193}
194EXPORT_SYMBOL_GPL(rtc_class_close);
195
196int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
197{
198	int retval = -EBUSY;
199	struct rtc_device *rtc = to_rtc_device(class_dev);
200
201	if (task == NULL || task->func == NULL)
202		return -EINVAL;
203
204	spin_lock(&rtc->irq_task_lock);
205	if (rtc->irq_task == NULL) {
206		rtc->irq_task = task;
207		retval = 0;
208	}
209	spin_unlock(&rtc->irq_task_lock);
210
211	return retval;
212}
213EXPORT_SYMBOL_GPL(rtc_irq_register);
214
215void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
216{
217	struct rtc_device *rtc = to_rtc_device(class_dev);
218
219	spin_lock(&rtc->irq_task_lock);
220	if (rtc->irq_task == task)
221		rtc->irq_task = NULL;
222	spin_unlock(&rtc->irq_task_lock);
223}
224EXPORT_SYMBOL_GPL(rtc_irq_unregister);
225
226int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled)
227{
228	int err = 0;
229	unsigned long flags;
230	struct rtc_device *rtc = to_rtc_device(class_dev);
231
232	if (rtc->ops->irq_set_state == NULL)
233		return -ENXIO;
234
235	spin_lock_irqsave(&rtc->irq_task_lock, flags);
236	if (rtc->irq_task != task)
237		err = -ENXIO;
238	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
239
240	if (err == 0)
241		err = rtc->ops->irq_set_state(class_dev->dev, enabled);
242
243	return err;
244}
245EXPORT_SYMBOL_GPL(rtc_irq_set_state);
246
247int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
248{
249	int err = 0;
250	unsigned long flags;
251	struct rtc_device *rtc = to_rtc_device(class_dev);
252
253	if (rtc->ops->irq_set_freq == NULL)
254		return -ENXIO;
255
256	spin_lock_irqsave(&rtc->irq_task_lock, flags);
257	if (rtc->irq_task != task)
258		err = -ENXIO;
259	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
260
261	if (err == 0) {
262		err = rtc->ops->irq_set_freq(class_dev->dev, freq);
263		if (err == 0)
264			rtc->irq_freq = freq;
265	}
266	return err;
267}
268EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
269