OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [rtc/] [interface.c] - Blame information for rev 78

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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
#include <linux/log2.h>
16
 
17
int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
18
{
19
        int err;
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(rtc->dev.parent, tm);
32
        }
33
 
34
        mutex_unlock(&rtc->ops_lock);
35
        return err;
36
}
37
EXPORT_SYMBOL_GPL(rtc_read_time);
38
 
39
int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
40
{
41
        int err;
42
 
43
        err = rtc_valid_tm(tm);
44
        if (err != 0)
45
                return err;
46
 
47
        err = mutex_lock_interruptible(&rtc->ops_lock);
48
        if (err)
49
                return -EBUSY;
50
 
51
        if (!rtc->ops)
52
                err = -ENODEV;
53
        else if (!rtc->ops->set_time)
54
                err = -EINVAL;
55
        else
56
                err = rtc->ops->set_time(rtc->dev.parent, tm);
57
 
58
        mutex_unlock(&rtc->ops_lock);
59
        return err;
60
}
61
EXPORT_SYMBOL_GPL(rtc_set_time);
62
 
63
int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
64
{
65
        int err;
66
 
67
        err = mutex_lock_interruptible(&rtc->ops_lock);
68
        if (err)
69
                return -EBUSY;
70
 
71
        if (!rtc->ops)
72
                err = -ENODEV;
73
        else if (rtc->ops->set_mmss)
74
                err = rtc->ops->set_mmss(rtc->dev.parent, secs);
75
        else if (rtc->ops->read_time && rtc->ops->set_time) {
76
                struct rtc_time new, old;
77
 
78
                err = rtc->ops->read_time(rtc->dev.parent, &old);
79
                if (err == 0) {
80
                        rtc_time_to_tm(secs, &new);
81
 
82
                        /*
83
                         * avoid writing when we're going to change the day of
84
                         * the month. We will retry in the next minute. This
85
                         * basically means that if the RTC must not drift
86
                         * by more than 1 minute in 11 minutes.
87
                         */
88
                        if (!((old.tm_hour == 23 && old.tm_min == 59) ||
89
                                (new.tm_hour == 23 && new.tm_min == 59)))
90
                                err = rtc->ops->set_time(rtc->dev.parent,
91
                                                &new);
92
                }
93
        }
94
        else
95
                err = -EINVAL;
96
 
97
        mutex_unlock(&rtc->ops_lock);
98
 
99
        return err;
100
}
101
EXPORT_SYMBOL_GPL(rtc_set_mmss);
102
 
103
static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
104
{
105
        int err;
106
 
107
        err = mutex_lock_interruptible(&rtc->ops_lock);
108
        if (err)
109
                return -EBUSY;
110
 
111
        if (rtc->ops == NULL)
112
                err = -ENODEV;
113
        else if (!rtc->ops->read_alarm)
114
                err = -EINVAL;
115
        else {
116
                memset(alarm, 0, sizeof(struct rtc_wkalrm));
117
                err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
118
        }
119
 
120
        mutex_unlock(&rtc->ops_lock);
121
        return err;
122
}
123
 
124
int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
125
{
126
        int err;
127
        struct rtc_time before, now;
128
        int first_time = 1;
129
 
130
        /* The lower level RTC driver may not be capable of filling
131
         * in all fields of the rtc_time struct (eg. rtc-cmos),
132
         * and so might instead return -1 in some fields.
133
         * We deal with that here by grabbing a current RTC timestamp
134
         * and using values from that for any missing (-1) values.
135
         *
136
         * But this can be racey, because some fields of the RTC timestamp
137
         * may have wrapped in the interval since we read the RTC alarm,
138
         * which would lead to us inserting inconsistent values in place
139
         * of the -1 fields.
140
         *
141
         * Reading the alarm and timestamp in the reverse sequence
142
         * would have the same race condition, and not solve the issue.
143
         *
144
         * So, we must first read the RTC timestamp,
145
         * then read the RTC alarm value,
146
         * and then read a second RTC timestamp.
147
         *
148
         * If any fields of the second timestamp have changed
149
         * when compared with the first timestamp, then we know
150
         * our timestamp may be inconsistent with that used by
151
         * the low-level rtc_read_alarm_internal() function.
152
         *
153
         * So, when the two timestamps disagree, we just loop and do
154
         * the process again to get a fully consistent set of values.
155
         *
156
         * This could all instead be done in the lower level driver,
157
         * but since more than one lower level RTC implementation needs it,
158
         * then it's probably best best to do it here instead of there..
159
         */
160
 
161
        /* Get the "before" timestamp */
162
        err = rtc_read_time(rtc, &before);
163
        if (err < 0)
164
                return err;
165
        do {
166
                if (!first_time)
167
                        memcpy(&before, &now, sizeof(struct rtc_time));
168
                first_time = 0;
169
 
170
                /* get the RTC alarm values, which may be incomplete */
171
                err = rtc_read_alarm_internal(rtc, alarm);
172
                if (err)
173
                        return err;
174
                if (!alarm->enabled)
175
                        return 0;
176
 
177
                /* get the "after" timestamp, to detect wrapped fields */
178
                err = rtc_read_time(rtc, &now);
179
                if (err < 0)
180
                        return err;
181
 
182
                /* note that tm_sec is a "don't care" value here: */
183
        } while (   before.tm_min   != now.tm_min
184
                 || before.tm_hour  != now.tm_hour
185
                 || before.tm_mon   != now.tm_mon
186
                 || before.tm_year  != now.tm_year
187
                 || before.tm_isdst != now.tm_isdst);
188
 
189
        /* Fill in any missing alarm fields using the timestamp */
190
        if (alarm->time.tm_sec == -1)
191
                alarm->time.tm_sec = now.tm_sec;
192
        if (alarm->time.tm_min == -1)
193
                alarm->time.tm_min = now.tm_min;
194
        if (alarm->time.tm_hour == -1)
195
                alarm->time.tm_hour = now.tm_hour;
196
        if (alarm->time.tm_mday == -1)
197
                alarm->time.tm_mday = now.tm_mday;
198
        if (alarm->time.tm_mon == -1)
199
                alarm->time.tm_mon = now.tm_mon;
200
        if (alarm->time.tm_year == -1)
201
                alarm->time.tm_year = now.tm_year;
202
        return 0;
203
}
204
EXPORT_SYMBOL_GPL(rtc_read_alarm);
205
 
206
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
207
{
208
        int err;
209
 
210
        err = rtc_valid_tm(&alarm->time);
211
        if (err != 0)
212
                return err;
213
 
214
        err = mutex_lock_interruptible(&rtc->ops_lock);
215
        if (err)
216
                return -EBUSY;
217
 
218
        if (!rtc->ops)
219
                err = -ENODEV;
220
        else if (!rtc->ops->set_alarm)
221
                err = -EINVAL;
222
        else
223
                err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
224
 
225
        mutex_unlock(&rtc->ops_lock);
226
        return err;
227
}
228
EXPORT_SYMBOL_GPL(rtc_set_alarm);
229
 
230
/**
231
 * rtc_update_irq - report RTC periodic, alarm, and/or update irqs
232
 * @rtc: the rtc device
233
 * @num: how many irqs are being reported (usually one)
234
 * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
235
 * Context: in_interrupt(), irqs blocked
236
 */
237
void rtc_update_irq(struct rtc_device *rtc,
238
                unsigned long num, unsigned long events)
239
{
240
        spin_lock(&rtc->irq_lock);
241
        rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
242
        spin_unlock(&rtc->irq_lock);
243
 
244
        spin_lock(&rtc->irq_task_lock);
245
        if (rtc->irq_task)
246
                rtc->irq_task->func(rtc->irq_task->private_data);
247
        spin_unlock(&rtc->irq_task_lock);
248
 
249
        wake_up_interruptible(&rtc->irq_queue);
250
        kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
251
}
252
EXPORT_SYMBOL_GPL(rtc_update_irq);
253
 
254
struct rtc_device *rtc_class_open(char *name)
255
{
256
        struct device *dev;
257
        struct rtc_device *rtc = NULL;
258
 
259
        down(&rtc_class->sem);
260
        list_for_each_entry(dev, &rtc_class->devices, node) {
261
                if (strncmp(dev->bus_id, name, BUS_ID_SIZE) == 0) {
262
                        dev = get_device(dev);
263
                        if (dev)
264
                                rtc = to_rtc_device(dev);
265
                        break;
266
                }
267
        }
268
 
269
        if (rtc) {
270
                if (!try_module_get(rtc->owner)) {
271
                        put_device(dev);
272
                        rtc = NULL;
273
                }
274
        }
275
        up(&rtc_class->sem);
276
 
277
        return rtc;
278
}
279
EXPORT_SYMBOL_GPL(rtc_class_open);
280
 
281
void rtc_class_close(struct rtc_device *rtc)
282
{
283
        module_put(rtc->owner);
284
        put_device(&rtc->dev);
285
}
286
EXPORT_SYMBOL_GPL(rtc_class_close);
287
 
288
int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
289
{
290
        int retval = -EBUSY;
291
 
292
        if (task == NULL || task->func == NULL)
293
                return -EINVAL;
294
 
295
        /* Cannot register while the char dev is in use */
296
        if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
297
                return -EBUSY;
298
 
299
        spin_lock_irq(&rtc->irq_task_lock);
300
        if (rtc->irq_task == NULL) {
301
                rtc->irq_task = task;
302
                retval = 0;
303
        }
304
        spin_unlock_irq(&rtc->irq_task_lock);
305
 
306
        clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
307
 
308
        return retval;
309
}
310
EXPORT_SYMBOL_GPL(rtc_irq_register);
311
 
312
void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
313
{
314
        spin_lock_irq(&rtc->irq_task_lock);
315
        if (rtc->irq_task == task)
316
                rtc->irq_task = NULL;
317
        spin_unlock_irq(&rtc->irq_task_lock);
318
}
319
EXPORT_SYMBOL_GPL(rtc_irq_unregister);
320
 
321
/**
322
 * rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
323
 * @rtc: the rtc device
324
 * @task: currently registered with rtc_irq_register()
325
 * @enabled: true to enable periodic IRQs
326
 * Context: any
327
 *
328
 * Note that rtc_irq_set_freq() should previously have been used to
329
 * specify the desired frequency of periodic IRQ task->func() callbacks.
330
 */
331
int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
332
{
333
        int err = 0;
334
        unsigned long flags;
335
 
336
        if (rtc->ops->irq_set_state == NULL)
337
                return -ENXIO;
338
 
339
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
340
        if (rtc->irq_task != NULL && task == NULL)
341
                err = -EBUSY;
342
        if (rtc->irq_task != task)
343
                err = -EACCES;
344
        spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
345
 
346
        if (err == 0)
347
                err = rtc->ops->irq_set_state(rtc->dev.parent, enabled);
348
 
349
        return err;
350
}
351
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
352
 
353
/**
354
 * rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
355
 * @rtc: the rtc device
356
 * @task: currently registered with rtc_irq_register()
357
 * @freq: positive frequency with which task->func() will be called
358
 * Context: any
359
 *
360
 * Note that rtc_irq_set_state() is used to enable or disable the
361
 * periodic IRQs.
362
 */
363
int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
364
{
365
        int err = 0;
366
        unsigned long flags;
367
 
368
        if (rtc->ops->irq_set_freq == NULL)
369
                return -ENXIO;
370
 
371
        if (!is_power_of_2(freq))
372
                return -EINVAL;
373
 
374
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
375
        if (rtc->irq_task != NULL && task == NULL)
376
                err = -EBUSY;
377
        if (rtc->irq_task != task)
378
                err = -EACCES;
379
        spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
380
 
381
        if (err == 0) {
382
                err = rtc->ops->irq_set_freq(rtc->dev.parent, freq);
383
                if (err == 0)
384
                        rtc->irq_freq = freq;
385
        }
386
        return err;
387
}
388
EXPORT_SYMBOL_GPL(rtc_irq_set_freq);

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.