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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [m68k/] [bvme6000/] [rtc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *      Real Time Clock interface for Linux on the BVME6000
3
 *
4
 * Based on the PC driver by Paul Gortmaker.
5
 */
6
 
7
#define RTC_VERSION             "1.00"
8
 
9
#include <linux/types.h>
10
#include <linux/errno.h>
11
#include <linux/miscdevice.h>
12
#include <linux/slab.h>
13
#include <linux/ioport.h>
14
#include <linux/fcntl.h>
15
#include <linux/init.h>
16
#include <linux/poll.h>
17
#include <linux/rtc.h>  /* For struct rtc_time and ioctls, etc */
18
#include <linux/smp_lock.h>
19
#include <asm/bvme6000hw.h>
20
 
21
#include <asm/io.h>
22
#include <asm/uaccess.h>
23
#include <asm/system.h>
24
#include <asm/setup.h>
25
 
26
/*
27
 *      We sponge a minor off of the misc major. No need slurping
28
 *      up another valuable major dev number for this. If you add
29
 *      an ioctl, make sure you don't conflict with SPARC's RTC
30
 *      ioctls.
31
 */
32
 
33
#define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
34
#define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
35
 
36
static unsigned char days_in_mo[] =
37
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
38
 
39
static char rtc_status = 0;
40
 
41
static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
42
                     unsigned long arg)
43
{
44
        volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
45
        unsigned char msr;
46
        unsigned long flags;
47
        struct rtc_time wtime;
48
 
49
        switch (cmd) {
50
        case RTC_RD_TIME:       /* Read the time/date from RTC  */
51
        {
52
                save_flags(flags);
53
                cli();
54
                /* Ensure clock and real-time-mode-register are accessible */
55
                msr = rtc->msr & 0xc0;
56
                rtc->msr = 0x40;
57
                memset(&wtime, 0, sizeof(struct rtc_time));
58
                do {
59
                        wtime.tm_sec =  BCD2BIN(rtc->bcd_sec);
60
                        wtime.tm_min =  BCD2BIN(rtc->bcd_min);
61
                        wtime.tm_hour = BCD2BIN(rtc->bcd_hr);
62
                        wtime.tm_mday =  BCD2BIN(rtc->bcd_dom);
63
                        wtime.tm_mon =  BCD2BIN(rtc->bcd_mth)-1;
64
                        wtime.tm_year = BCD2BIN(rtc->bcd_year);
65
                        if (wtime.tm_year < 70)
66
                                wtime.tm_year += 100;
67
                        wtime.tm_wday = BCD2BIN(rtc->bcd_dow)-1;
68
                } while (wtime.tm_sec != BCD2BIN(rtc->bcd_sec));
69
                rtc->msr = msr;
70
                restore_flags(flags);
71
                return copy_to_user((void *)arg, &wtime, sizeof wtime) ?
72
                                                                -EFAULT : 0;
73
        }
74
        case RTC_SET_TIME:      /* Set the RTC */
75
        {
76
                struct rtc_time rtc_tm;
77
                unsigned char mon, day, hrs, min, sec, leap_yr;
78
                unsigned int yrs;
79
 
80
                if (!capable(CAP_SYS_ADMIN))
81
                        return -EACCES;
82
 
83
                if (copy_from_user(&rtc_tm, (struct rtc_time*)arg,
84
                                   sizeof(struct rtc_time)))
85
                        return -EFAULT;
86
 
87
                yrs = rtc_tm.tm_year;
88
                if (yrs < 1900)
89
                        yrs += 1900;
90
                mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
91
                day = rtc_tm.tm_mday;
92
                hrs = rtc_tm.tm_hour;
93
                min = rtc_tm.tm_min;
94
                sec = rtc_tm.tm_sec;
95
 
96
                leap_yr = ((!(yrs % 4) && (yrs % 100)) || !(yrs % 400));
97
 
98
                if ((mon > 12) || (mon < 1) || (day == 0))
99
                        return -EINVAL;
100
 
101
                if (day > (days_in_mo[mon] + ((mon == 2) && leap_yr)))
102
                        return -EINVAL;
103
 
104
                if ((hrs >= 24) || (min >= 60) || (sec >= 60))
105
                        return -EINVAL;
106
 
107
                if (yrs >= 2070)
108
                        return -EINVAL;
109
 
110
                save_flags(flags);
111
                cli();
112
                /* Ensure clock and real-time-mode-register are accessible */
113
                msr = rtc->msr & 0xc0;
114
                rtc->msr = 0x40;
115
 
116
                rtc->t0cr_rtmr = yrs%4;
117
                rtc->bcd_tenms = 0;
118
                rtc->bcd_sec   = BIN2BCD(sec);
119
                rtc->bcd_min   = BIN2BCD(min);
120
                rtc->bcd_hr    = BIN2BCD(hrs);
121
                rtc->bcd_dom   = BIN2BCD(day);
122
                rtc->bcd_mth   = BIN2BCD(mon);
123
                rtc->bcd_year  = BIN2BCD(yrs%100);
124
                if (rtc_tm.tm_wday >= 0)
125
                        rtc->bcd_dow = BIN2BCD(rtc_tm.tm_wday+1);
126
                rtc->t0cr_rtmr = yrs%4 | 0x08;
127
 
128
                rtc->msr = msr;
129
                restore_flags(flags);
130
                return 0;
131
        }
132
        default:
133
                return -EINVAL;
134
        }
135
}
136
 
137
/*
138
 *      We enforce only one user at a time here with the open/close.
139
 *      Also clear the previous interrupt data on an open, and clean
140
 *      up things on a close.
141
 */
142
 
143
static int rtc_open(struct inode *inode, struct file *file)
144
{
145
        if(rtc_status)
146
                return -EBUSY;
147
 
148
        rtc_status = 1;
149
        return 0;
150
}
151
 
152
static int rtc_release(struct inode *inode, struct file *file)
153
{
154
        lock_kernel();
155
        rtc_status = 0;
156
        unlock_kernel();
157
        return 0;
158
}
159
 
160
/*
161
 *      The various file operations we support.
162
 */
163
 
164
static struct file_operations rtc_fops = {
165
        ioctl:          rtc_ioctl,
166
        open:           rtc_open,
167
        release:        rtc_release,
168
};
169
 
170
static struct miscdevice rtc_dev=
171
{
172
        RTC_MINOR,
173
        "rtc",
174
        &rtc_fops
175
};
176
 
177
int __init rtc_DP8570A_init(void)
178
{
179
        if (!MACH_IS_BVME6000)
180
                return -ENODEV;
181
 
182
        printk(KERN_INFO "DP8570A Real Time Clock Driver v%s\n", RTC_VERSION);
183
        return misc_register(&rtc_dev);
184
}
185
 

powered by: WebSVN 2.1.0

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