aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sparc64/kernel/time.c')
-rw-r--r--arch/sparc64/kernel/time.c293
1 files changed, 8 insertions, 285 deletions
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 15d16dbca1db..ea05038a8c16 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -403,27 +403,6 @@ int update_persistent_clock(struct timespec now)
403 return -1; 403 return -1;
404} 404}
405 405
406/* davem suggests we keep this within the 4M locked kernel image */
407static u32 starfire_get_time(void)
408{
409 static char obp_gettod[32];
410 static u32 unix_tod;
411
412 sprintf(obp_gettod, "h# %08x unix-gettod",
413 (unsigned int) (long) &unix_tod);
414 prom_feval(obp_gettod);
415
416 return unix_tod;
417}
418
419static int starfire_set_time(u32 val)
420{
421 /* Do nothing, time is set using the service processor
422 * console on this platform.
423 */
424 return 0;
425}
426
427unsigned long cmos_regs; 406unsigned long cmos_regs;
428EXPORT_SYMBOL(cmos_regs); 407EXPORT_SYMBOL(cmos_regs);
429 408
@@ -607,15 +586,16 @@ static struct platform_device rtc_sun4v_device = {
607 .id = -1, 586 .id = -1,
608}; 587};
609 588
589static struct platform_device rtc_starfire_device = {
590 .name = "rtc-starfire",
591 .id = -1,
592};
593
610static int __init clock_init(void) 594static int __init clock_init(void)
611{ 595{
612 if (this_is_starfire) { 596 if (this_is_starfire)
613 xtime.tv_sec = starfire_get_time(); 597 return platform_device_register(&rtc_starfire_device);
614 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ); 598
615 set_normalized_timespec(&wall_to_monotonic,
616 -xtime.tv_sec, -xtime.tv_nsec);
617 return 0;
618 }
619 if (tlb_type == hypervisor) 599 if (tlb_type == hypervisor)
620 return platform_device_register(&rtc_sun4v_device); 600 return platform_device_register(&rtc_sun4v_device);
621 601
@@ -892,265 +872,8 @@ unsigned long long sched_clock(void)
892 >> SPARC64_NSEC_PER_CYC_SHIFT; 872 >> SPARC64_NSEC_PER_CYC_SHIFT;
893} 873}
894 874
895#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
896static unsigned char mini_rtc_status; /* bitmapped status byte. */
897
898#define FEBRUARY 2
899#define STARTOFTIME 1970
900#define SECDAY 86400L
901#define SECYR (SECDAY * 365)
902#define leapyear(year) ((year) % 4 == 0 && \
903 ((year) % 100 != 0 || (year) % 400 == 0))
904#define days_in_year(a) (leapyear(a) ? 366 : 365)
905#define days_in_month(a) (month_days[(a) - 1])
906
907static int month_days[12] = {
908 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
909};
910
911/*
912 * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
913 */
914static void GregorianDay(struct rtc_time * tm)
915{
916 int leapsToDate;
917 int lastYear;
918 int day;
919 int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
920
921 lastYear = tm->tm_year - 1;
922
923 /*
924 * Number of leap corrections to apply up to end of last year
925 */
926 leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;
927
928 /*
929 * This year is a leap year if it is divisible by 4 except when it is
930 * divisible by 100 unless it is divisible by 400
931 *
932 * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was
933 */
934 day = tm->tm_mon > 2 && leapyear(tm->tm_year);
935
936 day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +
937 tm->tm_mday;
938
939 tm->tm_wday = day % 7;
940}
941
942static void to_tm(int tim, struct rtc_time *tm)
943{
944 register int i;
945 register long hms, day;
946
947 day = tim / SECDAY;
948 hms = tim % SECDAY;
949
950 /* Hours, minutes, seconds are easy */
951 tm->tm_hour = hms / 3600;
952 tm->tm_min = (hms % 3600) / 60;
953 tm->tm_sec = (hms % 3600) % 60;
954
955 /* Number of years in days */
956 for (i = STARTOFTIME; day >= days_in_year(i); i++)
957 day -= days_in_year(i);
958 tm->tm_year = i;
959
960 /* Number of months in days left */
961 if (leapyear(tm->tm_year))
962 days_in_month(FEBRUARY) = 29;
963 for (i = 1; day >= days_in_month(i); i++)
964 day -= days_in_month(i);
965 days_in_month(FEBRUARY) = 28;
966 tm->tm_mon = i;
967
968 /* Days are what is left over (+1) from all that. */
969 tm->tm_mday = day + 1;
970
971 /*
972 * Determine the day of week
973 */
974 GregorianDay(tm);
975}
976
977/* Both Starfire and SUN4V give us seconds since Jan 1st, 1970,
978 * aka Unix time. So we have to convert to/from rtc_time.
979 */
980static void starfire_get_rtc_time(struct rtc_time *time)
981{
982 u32 seconds = starfire_get_time();
983
984 to_tm(seconds, time);
985 time->tm_year -= 1900;
986 time->tm_mon -= 1;
987}
988
989static int starfire_set_rtc_time(struct rtc_time *time)
990{
991 u32 seconds = mktime(time->tm_year + 1900, time->tm_mon + 1,
992 time->tm_mday, time->tm_hour,
993 time->tm_min, time->tm_sec);
994
995 return starfire_set_time(seconds);
996}
997
998struct mini_rtc_ops {
999 void (*get_rtc_time)(struct rtc_time *);
1000 int (*set_rtc_time)(struct rtc_time *);
1001};
1002
1003static struct mini_rtc_ops starfire_rtc_ops = {
1004 .get_rtc_time = starfire_get_rtc_time,
1005 .set_rtc_time = starfire_set_rtc_time,
1006};
1007
1008static struct mini_rtc_ops *mini_rtc_ops;
1009
1010static inline void mini_get_rtc_time(struct rtc_time *time)
1011{
1012 unsigned long flags;
1013
1014 spin_lock_irqsave(&rtc_lock, flags);
1015 mini_rtc_ops->get_rtc_time(time);
1016 spin_unlock_irqrestore(&rtc_lock, flags);
1017}
1018
1019static inline int mini_set_rtc_time(struct rtc_time *time)
1020{
1021 unsigned long flags;
1022 int err;
1023
1024 spin_lock_irqsave(&rtc_lock, flags);
1025 err = mini_rtc_ops->set_rtc_time(time);
1026 spin_unlock_irqrestore(&rtc_lock, flags);
1027
1028 return err;
1029}
1030
1031static int mini_rtc_ioctl(struct inode *inode, struct file *file,
1032 unsigned int cmd, unsigned long arg)
1033{
1034 struct rtc_time wtime;
1035 void __user *argp = (void __user *)arg;
1036
1037 switch (cmd) {
1038
1039 case RTC_PLL_GET:
1040 return -EINVAL;
1041
1042 case RTC_PLL_SET:
1043 return -EINVAL;
1044
1045 case RTC_UIE_OFF: /* disable ints from RTC updates. */
1046 return 0;
1047
1048 case RTC_UIE_ON: /* enable ints for RTC updates. */
1049 return -EINVAL;
1050
1051 case RTC_RD_TIME: /* Read the time/date from RTC */
1052 /* this doesn't get week-day, who cares */
1053 memset(&wtime, 0, sizeof(wtime));
1054 mini_get_rtc_time(&wtime);
1055
1056 return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0;
1057
1058 case RTC_SET_TIME: /* Set the RTC */
1059 {
1060 int year, days;
1061
1062 if (!capable(CAP_SYS_TIME))
1063 return -EACCES;
1064
1065 if (copy_from_user(&wtime, argp, sizeof(wtime)))
1066 return -EFAULT;
1067
1068 year = wtime.tm_year + 1900;
1069 days = month_days[wtime.tm_mon] +
1070 ((wtime.tm_mon == 1) && leapyear(year));
1071
1072 if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) ||
1073 (wtime.tm_mday < 1))
1074 return -EINVAL;
1075
1076 if (wtime.tm_mday < 0 || wtime.tm_mday > days)
1077 return -EINVAL;
1078
1079 if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
1080 wtime.tm_min < 0 || wtime.tm_min >= 60 ||
1081 wtime.tm_sec < 0 || wtime.tm_sec >= 60)
1082 return -EINVAL;
1083
1084 return mini_set_rtc_time(&wtime);
1085 }
1086 }
1087
1088 return -EINVAL;
1089}
1090
1091static int mini_rtc_open(struct inode *inode, struct file *file)
1092{
1093 lock_kernel();
1094 if (mini_rtc_status & RTC_IS_OPEN) {
1095 unlock_kernel();
1096 return -EBUSY;
1097 }
1098
1099 mini_rtc_status |= RTC_IS_OPEN;
1100 unlock_kernel();
1101
1102 return 0;
1103}
1104
1105static int mini_rtc_release(struct inode *inode, struct file *file)
1106{
1107 mini_rtc_status &= ~RTC_IS_OPEN;
1108 return 0;
1109}
1110
1111
1112static const struct file_operations mini_rtc_fops = {
1113 .owner = THIS_MODULE,
1114 .ioctl = mini_rtc_ioctl,
1115 .open = mini_rtc_open,
1116 .release = mini_rtc_release,
1117};
1118
1119static struct miscdevice rtc_mini_dev =
1120{
1121 .minor = RTC_MINOR,
1122 .name = "rtc",
1123 .fops = &mini_rtc_fops,
1124};
1125
1126static int __init rtc_mini_init(void)
1127{
1128 int retval;
1129
1130 if (this_is_starfire)
1131 mini_rtc_ops = &starfire_rtc_ops;
1132 else
1133 return -ENODEV;
1134
1135 printk(KERN_INFO "Mini RTC Driver\n");
1136
1137 retval = misc_register(&rtc_mini_dev);
1138 if (retval < 0)
1139 return retval;
1140
1141 return 0;
1142}
1143
1144static void __exit rtc_mini_exit(void)
1145{
1146 misc_deregister(&rtc_mini_dev);
1147}
1148
1149int __devinit read_current_timer(unsigned long *timer_val) 875int __devinit read_current_timer(unsigned long *timer_val)
1150{ 876{
1151 *timer_val = tick_ops->get_tick(); 877 *timer_val = tick_ops->get_tick();
1152 return 0; 878 return 0;
1153} 879}
1154
1155module_init(rtc_mini_init);
1156module_exit(rtc_mini_exit);