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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [rtc/] [rtc-bfin.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 * Blackfin On-Chip Real Time Clock Driver
3
 *  Supports BF53[123]/BF53[467]/BF54[2489]
4
 *
5
 * Copyright 2004-2007 Analog Devices Inc.
6
 *
7
 * Enter bugs at http://blackfin.uclinux.org/
8
 *
9
 * Licensed under the GPL-2 or later.
10
 */
11
 
12
/* The biggest issue we deal with in this driver is that register writes are
13
 * synced to the RTC frequency of 1Hz.  So if you write to a register and
14
 * attempt to write again before the first write has completed, the new write
15
 * is simply discarded.  This can easily be troublesome if userspace disables
16
 * one event (say periodic) and then right after enables an event (say alarm).
17
 * Since all events are maintained in the same interrupt mask register, if
18
 * we wrote to it to disable the first event and then wrote to it again to
19
 * enable the second event, that second event would not be enabled as the
20
 * write would be discarded and things quickly fall apart.
21
 *
22
 * To keep this delay from significantly degrading performance (we, in theory,
23
 * would have to sleep for up to 1 second everytime we wanted to write a
24
 * register), we only check the write pending status before we start to issue
25
 * a new write.  We bank on the idea that it doesnt matter when the sync
26
 * happens so long as we don't attempt another write before it does.  The only
27
 * time userspace would take this penalty is when they try and do multiple
28
 * operations right after another ... but in this case, they need to take the
29
 * sync penalty, so we should be OK.
30
 *
31
 * Also note that the RTC_ISTAT register does not suffer this penalty; its
32
 * writes to clear status registers complete immediately.
33
 */
34
 
35
#include <linux/module.h>
36
#include <linux/kernel.h>
37
#include <linux/bcd.h>
38
#include <linux/rtc.h>
39
#include <linux/init.h>
40
#include <linux/platform_device.h>
41
#include <linux/seq_file.h>
42
#include <linux/interrupt.h>
43
#include <linux/spinlock.h>
44
#include <linux/delay.h>
45
 
46
#include <asm/blackfin.h>
47
 
48
#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __FUNCTION__, __LINE__, ## args)
49
#define stampit() stamp("here i am")
50
 
51
struct bfin_rtc {
52
        struct rtc_device *rtc_dev;
53
        struct rtc_time rtc_alarm;
54
        spinlock_t lock;
55
};
56
 
57
/* Bit values for the ISTAT / ICTL registers */
58
#define RTC_ISTAT_WRITE_COMPLETE  0x8000
59
#define RTC_ISTAT_WRITE_PENDING   0x4000
60
#define RTC_ISTAT_ALARM_DAY       0x0040
61
#define RTC_ISTAT_24HR            0x0020
62
#define RTC_ISTAT_HOUR            0x0010
63
#define RTC_ISTAT_MIN             0x0008
64
#define RTC_ISTAT_SEC             0x0004
65
#define RTC_ISTAT_ALARM           0x0002
66
#define RTC_ISTAT_STOPWATCH       0x0001
67
 
68
/* Shift values for RTC_STAT register */
69
#define DAY_BITS_OFF    17
70
#define HOUR_BITS_OFF   12
71
#define MIN_BITS_OFF    6
72
#define SEC_BITS_OFF    0
73
 
74
/* Some helper functions to convert between the common RTC notion of time
75
 * and the internal Blackfin notion that is stored in 32bits.
76
 */
77
static inline u32 rtc_time_to_bfin(unsigned long now)
78
{
79
        u32 sec  = (now % 60);
80
        u32 min  = (now % (60 * 60)) / 60;
81
        u32 hour = (now % (60 * 60 * 24)) / (60 * 60);
82
        u32 days = (now / (60 * 60 * 24));
83
        return (sec  << SEC_BITS_OFF) +
84
               (min  << MIN_BITS_OFF) +
85
               (hour << HOUR_BITS_OFF) +
86
               (days << DAY_BITS_OFF);
87
}
88
static inline unsigned long rtc_bfin_to_time(u32 rtc_bfin)
89
{
90
        return (((rtc_bfin >> SEC_BITS_OFF)  & 0x003F)) +
91
               (((rtc_bfin >> MIN_BITS_OFF)  & 0x003F) * 60) +
92
               (((rtc_bfin >> HOUR_BITS_OFF) & 0x001F) * 60 * 60) +
93
               (((rtc_bfin >> DAY_BITS_OFF)  & 0x7FFF) * 60 * 60 * 24);
94
}
95
static inline void rtc_bfin_to_tm(u32 rtc_bfin, struct rtc_time *tm)
96
{
97
        rtc_time_to_tm(rtc_bfin_to_time(rtc_bfin), tm);
98
}
99
 
100
/* Wait for the previous write to a RTC register to complete.
101
 * Unfortunately, we can't sleep here as that introduces a race condition when
102
 * turning on interrupt events.  Consider this:
103
 *  - process sets alarm
104
 *  - process enables alarm
105
 *  - process sleeps while waiting for rtc write to sync
106
 *  - interrupt fires while process is sleeping
107
 *  - interrupt acks the event by writing to ISTAT
108
 *  - interrupt sets the WRITE PENDING bit
109
 *  - interrupt handler finishes
110
 *  - process wakes up, sees WRITE PENDING bit set, goes to sleep
111
 *  - interrupt fires while process is sleeping
112
 * If anyone can point out the obvious solution here, i'm listening :).  This
113
 * shouldn't be an issue on an SMP or preempt system as this function should
114
 * only be called with the rtc lock held.
115
 */
116
static void rtc_bfin_sync_pending(void)
117
{
118
        stampit();
119
        while (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_COMPLETE)) {
120
                if (!(bfin_read_RTC_ISTAT() & RTC_ISTAT_WRITE_PENDING))
121
                        break;
122
        }
123
        bfin_write_RTC_ISTAT(RTC_ISTAT_WRITE_COMPLETE);
124
}
125
 
126
static void rtc_bfin_reset(struct bfin_rtc *rtc)
127
{
128
        /* Initialize the RTC. Enable pre-scaler to scale RTC clock
129
         * to 1Hz and clear interrupt/status registers. */
130
        spin_lock_irq(&rtc->lock);
131
        rtc_bfin_sync_pending();
132
        bfin_write_RTC_PREN(0x1);
133
        bfin_write_RTC_ICTL(0);
134
        bfin_write_RTC_SWCNT(0);
135
        bfin_write_RTC_ALARM(0);
136
        bfin_write_RTC_ISTAT(0xFFFF);
137
        spin_unlock_irq(&rtc->lock);
138
}
139
 
140
static irqreturn_t bfin_rtc_interrupt(int irq, void *dev_id)
141
{
142
        struct platform_device *pdev = to_platform_device(dev_id);
143
        struct bfin_rtc *rtc = platform_get_drvdata(pdev);
144
        unsigned long events = 0;
145
        u16 rtc_istat;
146
 
147
        stampit();
148
 
149
        spin_lock_irq(&rtc->lock);
150
 
151
        rtc_istat = bfin_read_RTC_ISTAT();
152
 
153
        if (rtc_istat & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY)) {
154
                bfin_write_RTC_ISTAT(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY);
155
                events |= RTC_AF | RTC_IRQF;
156
        }
157
 
158
        if (rtc_istat & RTC_ISTAT_STOPWATCH) {
159
                bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
160
                events |= RTC_PF | RTC_IRQF;
161
                bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
162
        }
163
 
164
        if (rtc_istat & RTC_ISTAT_SEC) {
165
                bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
166
                events |= RTC_UF | RTC_IRQF;
167
        }
168
 
169
        rtc_update_irq(rtc->rtc_dev, 1, events);
170
 
171
        spin_unlock_irq(&rtc->lock);
172
 
173
        return IRQ_HANDLED;
174
}
175
 
176
static int bfin_rtc_open(struct device *dev)
177
{
178
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
179
        int ret;
180
 
181
        stampit();
182
 
183
        ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, IRQF_DISABLED, "rtc-bfin", dev);
184
        if (unlikely(ret)) {
185
                dev_err(dev, "request RTC IRQ failed with %d\n", ret);
186
                return ret;
187
        }
188
 
189
        rtc_bfin_reset(rtc);
190
 
191
        return ret;
192
}
193
 
194
static void bfin_rtc_release(struct device *dev)
195
{
196
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
197
        stampit();
198
        rtc_bfin_reset(rtc);
199
        free_irq(IRQ_RTC, dev);
200
}
201
 
202
static int bfin_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
203
{
204
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
205
 
206
        stampit();
207
 
208
        switch (cmd) {
209
        case RTC_PIE_ON:
210
                stampit();
211
                spin_lock_irq(&rtc->lock);
212
                rtc_bfin_sync_pending();
213
                bfin_write_RTC_ISTAT(RTC_ISTAT_STOPWATCH);
214
                bfin_write_RTC_SWCNT(rtc->rtc_dev->irq_freq);
215
                bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_STOPWATCH);
216
                spin_unlock_irq(&rtc->lock);
217
                return 0;
218
        case RTC_PIE_OFF:
219
                stampit();
220
                spin_lock_irq(&rtc->lock);
221
                rtc_bfin_sync_pending();
222
                bfin_write_RTC_SWCNT(0);
223
                bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_STOPWATCH);
224
                spin_unlock_irq(&rtc->lock);
225
                return 0;
226
 
227
        case RTC_UIE_ON:
228
                stampit();
229
                spin_lock_irq(&rtc->lock);
230
                rtc_bfin_sync_pending();
231
                bfin_write_RTC_ISTAT(RTC_ISTAT_SEC);
232
                bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | RTC_ISTAT_SEC);
233
                spin_unlock_irq(&rtc->lock);
234
                return 0;
235
        case RTC_UIE_OFF:
236
                stampit();
237
                spin_lock_irq(&rtc->lock);
238
                rtc_bfin_sync_pending();
239
                bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~RTC_ISTAT_SEC);
240
                spin_unlock_irq(&rtc->lock);
241
                return 0;
242
 
243
        case RTC_AIE_ON: {
244
                unsigned long rtc_alarm;
245
                u16 which_alarm;
246
                int ret = 0;
247
 
248
                stampit();
249
 
250
                spin_lock_irq(&rtc->lock);
251
 
252
                rtc_bfin_sync_pending();
253
                if (rtc->rtc_alarm.tm_yday == -1) {
254
                        struct rtc_time now;
255
                        rtc_bfin_to_tm(bfin_read_RTC_STAT(), &now);
256
                        now.tm_sec = rtc->rtc_alarm.tm_sec;
257
                        now.tm_min = rtc->rtc_alarm.tm_min;
258
                        now.tm_hour = rtc->rtc_alarm.tm_hour;
259
                        ret = rtc_tm_to_time(&now, &rtc_alarm);
260
                        which_alarm = RTC_ISTAT_ALARM;
261
                } else {
262
                        ret = rtc_tm_to_time(&rtc->rtc_alarm, &rtc_alarm);
263
                        which_alarm = RTC_ISTAT_ALARM_DAY;
264
                }
265
                if (ret == 0) {
266
                        bfin_write_RTC_ISTAT(which_alarm);
267
                        bfin_write_RTC_ALARM(rtc_time_to_bfin(rtc_alarm));
268
                        bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() | which_alarm);
269
                }
270
 
271
                spin_unlock_irq(&rtc->lock);
272
 
273
                return ret;
274
        }
275
        case RTC_AIE_OFF:
276
                stampit();
277
                spin_lock_irq(&rtc->lock);
278
                rtc_bfin_sync_pending();
279
                bfin_write_RTC_ICTL(bfin_read_RTC_ICTL() & ~(RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
280
                spin_unlock_irq(&rtc->lock);
281
                return 0;
282
        }
283
 
284
        return -ENOIOCTLCMD;
285
}
286
 
287
static int bfin_rtc_read_time(struct device *dev, struct rtc_time *tm)
288
{
289
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
290
 
291
        stampit();
292
 
293
        spin_lock_irq(&rtc->lock);
294
        rtc_bfin_sync_pending();
295
        rtc_bfin_to_tm(bfin_read_RTC_STAT(), tm);
296
        spin_unlock_irq(&rtc->lock);
297
 
298
        return 0;
299
}
300
 
301
static int bfin_rtc_set_time(struct device *dev, struct rtc_time *tm)
302
{
303
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
304
        int ret;
305
        unsigned long now;
306
 
307
        stampit();
308
 
309
        spin_lock_irq(&rtc->lock);
310
 
311
        ret = rtc_tm_to_time(tm, &now);
312
        if (ret == 0) {
313
                rtc_bfin_sync_pending();
314
                bfin_write_RTC_STAT(rtc_time_to_bfin(now));
315
        }
316
 
317
        spin_unlock_irq(&rtc->lock);
318
 
319
        return ret;
320
}
321
 
322
static int bfin_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
323
{
324
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
325
        stampit();
326
        memcpy(&alrm->time, &rtc->rtc_alarm, sizeof(struct rtc_time));
327
        alrm->pending = !!(bfin_read_RTC_ICTL() & (RTC_ISTAT_ALARM | RTC_ISTAT_ALARM_DAY));
328
        return 0;
329
}
330
 
331
static int bfin_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
332
{
333
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
334
        stampit();
335
        memcpy(&rtc->rtc_alarm, &alrm->time, sizeof(struct rtc_time));
336
        return 0;
337
}
338
 
339
static int bfin_rtc_proc(struct device *dev, struct seq_file *seq)
340
{
341
#define yesno(x) (x ? "yes" : "no")
342
        u16 ictl = bfin_read_RTC_ICTL();
343
        stampit();
344
        seq_printf(seq, "alarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM));
345
        seq_printf(seq, "wkalarm_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_ALARM_DAY));
346
        seq_printf(seq, "seconds_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_SEC));
347
        seq_printf(seq, "periodic_IRQ\t: %s\n", yesno(ictl & RTC_ISTAT_STOPWATCH));
348
#ifdef DEBUG
349
        seq_printf(seq, "RTC_STAT\t: 0x%08X\n", bfin_read_RTC_STAT());
350
        seq_printf(seq, "RTC_ICTL\t: 0x%04X\n", bfin_read_RTC_ICTL());
351
        seq_printf(seq, "RTC_ISTAT\t: 0x%04X\n", bfin_read_RTC_ISTAT());
352
        seq_printf(seq, "RTC_SWCNT\t: 0x%04X\n", bfin_read_RTC_SWCNT());
353
        seq_printf(seq, "RTC_ALARM\t: 0x%08X\n", bfin_read_RTC_ALARM());
354
        seq_printf(seq, "RTC_PREN\t: 0x%04X\n", bfin_read_RTC_PREN());
355
#endif
356
        return 0;
357
}
358
 
359
static int bfin_irq_set_freq(struct device *dev, int freq)
360
{
361
        struct bfin_rtc *rtc = dev_get_drvdata(dev);
362
        stampit();
363
        rtc->rtc_dev->irq_freq = freq;
364
        return 0;
365
}
366
 
367
static struct rtc_class_ops bfin_rtc_ops = {
368
        .open          = bfin_rtc_open,
369
        .release       = bfin_rtc_release,
370
        .ioctl         = bfin_rtc_ioctl,
371
        .read_time     = bfin_rtc_read_time,
372
        .set_time      = bfin_rtc_set_time,
373
        .read_alarm    = bfin_rtc_read_alarm,
374
        .set_alarm     = bfin_rtc_set_alarm,
375
        .proc          = bfin_rtc_proc,
376
        .irq_set_freq  = bfin_irq_set_freq,
377
};
378
 
379
static int __devinit bfin_rtc_probe(struct platform_device *pdev)
380
{
381
        struct bfin_rtc *rtc;
382
        int ret = 0;
383
 
384
        stampit();
385
 
386
        rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
387
        if (unlikely(!rtc))
388
                return -ENOMEM;
389
 
390
        spin_lock_init(&rtc->lock);
391
 
392
        rtc->rtc_dev = rtc_device_register(pdev->name, &pdev->dev, &bfin_rtc_ops, THIS_MODULE);
393
        if (unlikely(IS_ERR(rtc))) {
394
                ret = PTR_ERR(rtc->rtc_dev);
395
                goto err;
396
        }
397
        rtc->rtc_dev->irq_freq = 0;
398
        rtc->rtc_dev->max_user_freq = (2 << 16); /* stopwatch is an unsigned 16 bit reg */
399
 
400
        platform_set_drvdata(pdev, rtc);
401
 
402
        return 0;
403
 
404
err:
405
        kfree(rtc);
406
        return ret;
407
}
408
 
409
static int __devexit bfin_rtc_remove(struct platform_device *pdev)
410
{
411
        struct bfin_rtc *rtc = platform_get_drvdata(pdev);
412
 
413
        rtc_device_unregister(rtc->rtc_dev);
414
        platform_set_drvdata(pdev, NULL);
415
        kfree(rtc);
416
 
417
        return 0;
418
}
419
 
420
static struct platform_driver bfin_rtc_driver = {
421
        .driver         = {
422
                .name   = "rtc-bfin",
423
                .owner  = THIS_MODULE,
424
        },
425
        .probe          = bfin_rtc_probe,
426
        .remove         = __devexit_p(bfin_rtc_remove),
427
};
428
 
429
static int __init bfin_rtc_init(void)
430
{
431
        stampit();
432
        return platform_driver_register(&bfin_rtc_driver);
433
}
434
 
435
static void __exit bfin_rtc_exit(void)
436
{
437
        platform_driver_unregister(&bfin_rtc_driver);
438
}
439
 
440
module_init(bfin_rtc_init);
441
module_exit(bfin_rtc_exit);
442
 
443
MODULE_DESCRIPTION("Blackfin On-Chip Real Time Clock Driver");
444
MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>");
445
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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