2 * Real Time Clock interface for Linux on the MVME16x
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/mvme16xhw.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 MK48T08ptr_t rtc
= (MK48T08ptr_t
)MVME_RTC_BASE
;
45 struct rtc_time wtime
;
48 case RTC_RD_TIME
: /* Read the time/date from RTC */
52 /* Ensure clock and real-time-mode-register are accessible */
54 wtime
.tm_sec
= BCD2BIN(rtc
->bcd_sec
);
55 wtime
.tm_min
= BCD2BIN(rtc
->bcd_min
);
56 wtime
.tm_hour
= BCD2BIN(rtc
->bcd_hr
);
57 wtime
.tm_mday
= BCD2BIN(rtc
->bcd_dom
);
58 wtime
.tm_mon
= BCD2BIN(rtc
->bcd_mth
)-1;
59 wtime
.tm_year
= BCD2BIN(rtc
->bcd_year
);
60 if (wtime
.tm_year
< 70)
62 wtime
.tm_wday
= BCD2BIN(rtc
->bcd_dow
)-1;
65 return copy_to_user((void *)arg
, &wtime
, sizeof wtime
) ?
68 case RTC_SET_TIME
: /* Set the RTC */
70 unsigned char leap_yr
;
71 struct rtc_time rtc_tm
;
76 if (copy_from_user(&rtc_tm
, (struct rtc_time
*)arg
,
77 sizeof(struct rtc_time
)))
80 leap_yr
= ((!(rtc_tm
.tm_year
% 4) && (rtc_tm
.tm_year
% 100)) || !(rtc_tm
.tm_year
% 400));
82 if ((rtc_tm
.tm_mon
> 12) || (rtc_tm
.tm_mday
== 0))
85 if (rtc_tm
.tm_mday
> (days_in_mo
[rtc_tm
.tm_mon
] + ((rtc_tm
.tm_mon
== 2) && leap_yr
)))
88 if ((rtc_tm
.tm_hour
>= 24) || (rtc_tm
.tm_min
>= 60) || (rtc_tm
.tm_sec
>= 60))
93 rtc
->ctrl
= RTC_WRITE
;
95 rtc
->bcd_sec
= BIN2BCD(rtc_tm
.tm_sec
);
96 rtc
->bcd_min
= BIN2BCD(rtc_tm
.tm_min
);
97 rtc
->bcd_hr
= BIN2BCD(rtc_tm
.tm_hour
);
98 rtc
->bcd_dom
= BIN2BCD(rtc_tm
.tm_mday
);
99 rtc
->bcd_mth
= BIN2BCD(rtc_tm
.tm_mon
+ 1);
100 rtc
->bcd_year
= BIN2BCD(rtc_tm
.tm_year
%100);
101 if (rtc_tm
.tm_wday
>= 0)
102 rtc
->bcd_dow
= BIN2BCD(rtc_tm
.tm_wday
+1);
105 restore_flags(flags
);
114 * We enforce only one user at a time here with the open/close.
115 * Also clear the previous interrupt data on an open, and clean
116 * up things on a close.
119 static int rtc_open(struct inode
*inode
, struct file
*file
)
128 static int rtc_release(struct inode
*inode
, struct file
*file
)
135 * The various file operations we support.
138 static struct file_operations rtc_fops
= {
142 NULL
, /* No readdir */
151 static struct miscdevice rtc_dev
=
158 __initfunc(int rtc_MK48T08_init(void))
160 if (!MACH_IS_MVME16x
)
163 printk(KERN_INFO
"MK48T08 Real Time Clock Driver v%s\n", RTC_VERSION
);
164 misc_register(&rtc_dev
);