2 * Real Time Clock interface for Linux on the BVME6000
4 * Based on the PC driver by Paul Gortmaker.
7 #define RTC_VERSION "1.00"
9 #include <linux/types.h>
10 #include <linux/errno.h>
11 #include <linux/miscdevice.h>
12 #include <linux/malloc.h>
13 #include <linux/ioport.h>
14 #include <linux/fcntl.h>
15 #include <linux/init.h>
16 #include <linux/poll.h>
17 #include <linux/mc146818rtc.h> /* For struct rtc_time and ioctls, etc */
18 #include <asm/bvme6000hw.h>
21 #include <asm/uaccess.h>
22 #include <asm/system.h>
23 #include <asm/setup.h>
26 * We sponge a minor off of the misc major. No need slurping
27 * up another valuable major dev number for this. If you add
28 * an ioctl, make sure you don't conflict with SPARC's RTC
32 #define BCD2BIN(val) (((val)&15) + ((val)>>4)*10)
33 #define BIN2BCD(val) ((((val)/10)<<4) + (val)%10)
35 static unsigned char days_in_mo
[] =
36 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
38 static char rtc_status
= 0;
40 static int rtc_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
,
43 volatile RtcPtr_t rtc
= (RtcPtr_t
)BVME_RTC_BASE
;
46 struct rtc_time wtime
;
49 case RTC_RD_TIME
: /* Read the time/date from RTC */
53 /* Ensure clock and real-time-mode-register are accessible */
54 msr
= rtc
->msr
& 0xc0;
57 wtime
.tm_sec
= BCD2BIN(rtc
->bcd_sec
);
58 wtime
.tm_min
= BCD2BIN(rtc
->bcd_min
);
59 wtime
.tm_hour
= BCD2BIN(rtc
->bcd_hr
);
60 wtime
.tm_mday
= BCD2BIN(rtc
->bcd_dom
);
61 wtime
.tm_mon
= BCD2BIN(rtc
->bcd_mth
)-1;
62 wtime
.tm_year
= BCD2BIN(rtc
->bcd_year
);
63 if (wtime
.tm_year
< 70)
65 wtime
.tm_wday
= BCD2BIN(rtc
->bcd_dow
)-1;
66 } while (wtime
.tm_sec
!= BCD2BIN(rtc
->bcd_sec
));
69 return copy_to_user((void *)arg
, &wtime
, sizeof wtime
) ?
72 case RTC_SET_TIME
: /* Set the RTC */
74 unsigned char leap_yr
;
75 struct rtc_time rtc_tm
;
80 if (copy_from_user(&rtc_tm
, (struct rtc_time
*)arg
,
81 sizeof(struct rtc_time
)))
84 leap_yr
= ((!(rtc_tm
.tm_year
% 4) && (rtc_tm
.tm_year
% 100)) || !(rtc_tm
.tm_year
% 400));
86 if ((rtc_tm
.tm_mon
> 12) || (rtc_tm
.tm_mday
== 0))
89 if (rtc_tm
.tm_mday
> (days_in_mo
[rtc_tm
.tm_mon
] + ((rtc_tm
.tm_mon
== 2) && leap_yr
)))
92 if ((rtc_tm
.tm_hour
>= 24) || (rtc_tm
.tm_min
>= 60) || (rtc_tm
.tm_sec
>= 60))
97 /* Ensure clock and real-time-mode-register are accessible */
98 msr
= rtc
->msr
& 0xc0;
101 rtc
->t0cr_rtmr
= rtc_tm
.tm_year
%4;
103 rtc
->bcd_sec
= BIN2BCD(rtc_tm
.tm_sec
);
104 rtc
->bcd_min
= BIN2BCD(rtc_tm
.tm_min
);
105 rtc
->bcd_hr
= BIN2BCD(rtc_tm
.tm_hour
);
106 rtc
->bcd_dom
= BIN2BCD(rtc_tm
.tm_mday
);
107 rtc
->bcd_mth
= BIN2BCD(rtc_tm
.tm_mon
+ 1);
108 rtc
->bcd_year
= BIN2BCD(rtc_tm
.tm_year
%100);
109 if (rtc_tm
.tm_wday
>= 0)
110 rtc
->bcd_dow
= BIN2BCD(rtc_tm
.tm_wday
+1);
111 rtc
->t0cr_rtmr
= rtc_tm
.tm_year
%4 | 0x08;
114 restore_flags(flags
);
123 * We enforce only one user at a time here with the open/close.
124 * Also clear the previous interrupt data on an open, and clean
125 * up things on a close.
128 static int rtc_open(struct inode
*inode
, struct file
*file
)
137 static int rtc_release(struct inode
*inode
, struct file
*file
)
144 * The various file operations we support.
147 static struct file_operations rtc_fops
= {
151 NULL
, /* No readdir */
160 static struct miscdevice rtc_dev
=
167 __initfunc(int rtc_DP8570A_init(void))
169 if (!MACH_IS_BVME6000
)
172 printk(KERN_INFO
"DP8570A Real Time Clock Driver v%s\n", RTC_VERSION
);
173 misc_register(&rtc_dev
);