diff options
-rw-r--r-- | arch/sparc64/Kconfig | 1 | ||||
-rw-r--r-- | arch/sparc64/kernel/time.c | 293 |
2 files changed, 9 insertions, 285 deletions
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig index 16149ce8a416..4a90809b40fb 100644 --- a/arch/sparc64/Kconfig +++ b/arch/sparc64/Kconfig | |||
@@ -24,6 +24,7 @@ config SPARC64 | |||
24 | select RTC_DRV_CMOS | 24 | select RTC_DRV_CMOS |
25 | select RTC_DRV_BQ4802 | 25 | select RTC_DRV_BQ4802 |
26 | select RTC_DRV_SUN4V | 26 | select RTC_DRV_SUN4V |
27 | select RTC_DRV_STARFIRE | ||
27 | 28 | ||
28 | config GENERIC_TIME | 29 | config GENERIC_TIME |
29 | bool | 30 | bool |
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 */ | ||
407 | static 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 | |||
419 | static 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 | |||
427 | unsigned long cmos_regs; | 406 | unsigned long cmos_regs; |
428 | EXPORT_SYMBOL(cmos_regs); | 407 | EXPORT_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 | ||
589 | static struct platform_device rtc_starfire_device = { | ||
590 | .name = "rtc-starfire", | ||
591 | .id = -1, | ||
592 | }; | ||
593 | |||
610 | static int __init clock_init(void) | 594 | static 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 */ | ||
896 | static 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 | |||
907 | static 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 | */ | ||
914 | static 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 | |||
942 | static 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 | */ | ||
980 | static 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 | |||
989 | static 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 | |||
998 | struct mini_rtc_ops { | ||
999 | void (*get_rtc_time)(struct rtc_time *); | ||
1000 | int (*set_rtc_time)(struct rtc_time *); | ||
1001 | }; | ||
1002 | |||
1003 | static 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 | |||
1008 | static struct mini_rtc_ops *mini_rtc_ops; | ||
1009 | |||
1010 | static 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 | |||
1019 | static 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 | |||
1031 | static 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 | |||
1091 | static 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 | |||
1105 | static int mini_rtc_release(struct inode *inode, struct file *file) | ||
1106 | { | ||
1107 | mini_rtc_status &= ~RTC_IS_OPEN; | ||
1108 | return 0; | ||
1109 | } | ||
1110 | |||
1111 | |||
1112 | static 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 | |||
1119 | static struct miscdevice rtc_mini_dev = | ||
1120 | { | ||
1121 | .minor = RTC_MINOR, | ||
1122 | .name = "rtc", | ||
1123 | .fops = &mini_rtc_fops, | ||
1124 | }; | ||
1125 | |||
1126 | static 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 | |||
1144 | static void __exit rtc_mini_exit(void) | ||
1145 | { | ||
1146 | misc_deregister(&rtc_mini_dev); | ||
1147 | } | ||
1148 | |||
1149 | int __devinit read_current_timer(unsigned long *timer_val) | 875 | int __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 | |||
1155 | module_init(rtc_mini_init); | ||
1156 | module_exit(rtc_mini_exit); | ||