1*85d0b3a5SRichard Henderson /* 2*85d0b3a5SRichard Henderson * linux/arch/alpha/kernel/rtc.c 3*85d0b3a5SRichard Henderson * 4*85d0b3a5SRichard Henderson * Copyright (C) 1991, 1992, 1995, 1999, 2000 Linus Torvalds 5*85d0b3a5SRichard Henderson * 6*85d0b3a5SRichard Henderson * This file contains date handling. 7*85d0b3a5SRichard Henderson */ 8*85d0b3a5SRichard Henderson #include <linux/errno.h> 9*85d0b3a5SRichard Henderson #include <linux/init.h> 10*85d0b3a5SRichard Henderson #include <linux/kernel.h> 11*85d0b3a5SRichard Henderson #include <linux/param.h> 12*85d0b3a5SRichard Henderson #include <linux/string.h> 13*85d0b3a5SRichard Henderson #include <linux/mc146818rtc.h> 14*85d0b3a5SRichard Henderson #include <linux/bcd.h> 15*85d0b3a5SRichard Henderson #include <linux/rtc.h> 16*85d0b3a5SRichard Henderson #include <linux/platform_device.h> 17*85d0b3a5SRichard Henderson 18*85d0b3a5SRichard Henderson #include <asm/rtc.h> 19*85d0b3a5SRichard Henderson 20*85d0b3a5SRichard Henderson #include "proto.h" 21*85d0b3a5SRichard Henderson 22*85d0b3a5SRichard Henderson 23*85d0b3a5SRichard Henderson /* 24*85d0b3a5SRichard Henderson * Support for the RTC device. 25*85d0b3a5SRichard Henderson * 26*85d0b3a5SRichard Henderson * We don't want to use the rtc-cmos driver, because we don't want to support 27*85d0b3a5SRichard Henderson * alarms, as that would be indistinguishable from timer interrupts. 28*85d0b3a5SRichard Henderson * 29*85d0b3a5SRichard Henderson * Further, generic code is really, really tied to a 1900 epoch. This is 30*85d0b3a5SRichard Henderson * true in __get_rtc_time as well as the users of struct rtc_time e.g. 31*85d0b3a5SRichard Henderson * rtc_tm_to_time. Thankfully all of the other epochs in use are later 32*85d0b3a5SRichard Henderson * than 1900, and so it's easy to adjust. 33*85d0b3a5SRichard Henderson */ 34*85d0b3a5SRichard Henderson 35*85d0b3a5SRichard Henderson static unsigned long rtc_epoch; 36*85d0b3a5SRichard Henderson 37*85d0b3a5SRichard Henderson static int __init 38*85d0b3a5SRichard Henderson specifiy_epoch(char *str) 39*85d0b3a5SRichard Henderson { 40*85d0b3a5SRichard Henderson unsigned long epoch = simple_strtoul(str, NULL, 0); 41*85d0b3a5SRichard Henderson if (epoch < 1900) 42*85d0b3a5SRichard Henderson printk("Ignoring invalid user specified epoch %lu\n", epoch); 43*85d0b3a5SRichard Henderson else 44*85d0b3a5SRichard Henderson rtc_epoch = epoch; 45*85d0b3a5SRichard Henderson return 1; 46*85d0b3a5SRichard Henderson } 47*85d0b3a5SRichard Henderson __setup("epoch=", specifiy_epoch); 48*85d0b3a5SRichard Henderson 49*85d0b3a5SRichard Henderson static void __init 50*85d0b3a5SRichard Henderson init_rtc_epoch(void) 51*85d0b3a5SRichard Henderson { 52*85d0b3a5SRichard Henderson int epoch, year, ctrl; 53*85d0b3a5SRichard Henderson 54*85d0b3a5SRichard Henderson if (rtc_epoch != 0) { 55*85d0b3a5SRichard Henderson /* The epoch was specified on the command-line. */ 56*85d0b3a5SRichard Henderson return; 57*85d0b3a5SRichard Henderson } 58*85d0b3a5SRichard Henderson 59*85d0b3a5SRichard Henderson /* Detect the epoch in use on this computer. */ 60*85d0b3a5SRichard Henderson ctrl = CMOS_READ(RTC_CONTROL); 61*85d0b3a5SRichard Henderson year = CMOS_READ(RTC_YEAR); 62*85d0b3a5SRichard Henderson if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) 63*85d0b3a5SRichard Henderson year = bcd2bin(year); 64*85d0b3a5SRichard Henderson 65*85d0b3a5SRichard Henderson /* PC-like is standard; used for year >= 70 */ 66*85d0b3a5SRichard Henderson epoch = 1900; 67*85d0b3a5SRichard Henderson if (year < 20) { 68*85d0b3a5SRichard Henderson epoch = 2000; 69*85d0b3a5SRichard Henderson } else if (year >= 20 && year < 48) { 70*85d0b3a5SRichard Henderson /* NT epoch */ 71*85d0b3a5SRichard Henderson epoch = 1980; 72*85d0b3a5SRichard Henderson } else if (year >= 48 && year < 70) { 73*85d0b3a5SRichard Henderson /* Digital UNIX epoch */ 74*85d0b3a5SRichard Henderson epoch = 1952; 75*85d0b3a5SRichard Henderson } 76*85d0b3a5SRichard Henderson rtc_epoch = epoch; 77*85d0b3a5SRichard Henderson 78*85d0b3a5SRichard Henderson printk(KERN_INFO "Using epoch %d for rtc year %d\n", epoch, year); 79*85d0b3a5SRichard Henderson } 80*85d0b3a5SRichard Henderson 81*85d0b3a5SRichard Henderson static int 82*85d0b3a5SRichard Henderson alpha_rtc_read_time(struct device *dev, struct rtc_time *tm) 83*85d0b3a5SRichard Henderson { 84*85d0b3a5SRichard Henderson __get_rtc_time(tm); 85*85d0b3a5SRichard Henderson 86*85d0b3a5SRichard Henderson /* Adjust for non-default epochs. It's easier to depend on the 87*85d0b3a5SRichard Henderson generic __get_rtc_time and adjust the epoch here than create 88*85d0b3a5SRichard Henderson a copy of __get_rtc_time with the edits we need. */ 89*85d0b3a5SRichard Henderson if (rtc_epoch != 1900) { 90*85d0b3a5SRichard Henderson int year = tm->tm_year; 91*85d0b3a5SRichard Henderson /* Undo the century adjustment made in __get_rtc_time. */ 92*85d0b3a5SRichard Henderson if (year >= 100) 93*85d0b3a5SRichard Henderson year -= 100; 94*85d0b3a5SRichard Henderson year += rtc_epoch - 1900; 95*85d0b3a5SRichard Henderson /* Redo the century adjustment with the epoch in place. */ 96*85d0b3a5SRichard Henderson if (year <= 69) 97*85d0b3a5SRichard Henderson year += 100; 98*85d0b3a5SRichard Henderson tm->tm_year = year; 99*85d0b3a5SRichard Henderson } 100*85d0b3a5SRichard Henderson 101*85d0b3a5SRichard Henderson return rtc_valid_tm(tm); 102*85d0b3a5SRichard Henderson } 103*85d0b3a5SRichard Henderson 104*85d0b3a5SRichard Henderson static int 105*85d0b3a5SRichard Henderson alpha_rtc_set_time(struct device *dev, struct rtc_time *tm) 106*85d0b3a5SRichard Henderson { 107*85d0b3a5SRichard Henderson struct rtc_time xtm; 108*85d0b3a5SRichard Henderson 109*85d0b3a5SRichard Henderson if (rtc_epoch != 1900) { 110*85d0b3a5SRichard Henderson xtm = *tm; 111*85d0b3a5SRichard Henderson xtm.tm_year -= rtc_epoch - 1900; 112*85d0b3a5SRichard Henderson tm = &xtm; 113*85d0b3a5SRichard Henderson } 114*85d0b3a5SRichard Henderson 115*85d0b3a5SRichard Henderson return __set_rtc_time(tm); 116*85d0b3a5SRichard Henderson } 117*85d0b3a5SRichard Henderson 118*85d0b3a5SRichard Henderson static int 119*85d0b3a5SRichard Henderson alpha_rtc_set_mmss(struct device *dev, unsigned long nowtime) 120*85d0b3a5SRichard Henderson { 121*85d0b3a5SRichard Henderson int retval = 0; 122*85d0b3a5SRichard Henderson int real_seconds, real_minutes, cmos_minutes; 123*85d0b3a5SRichard Henderson unsigned char save_control, save_freq_select; 124*85d0b3a5SRichard Henderson 125*85d0b3a5SRichard Henderson /* Note: This code only updates minutes and seconds. Comments 126*85d0b3a5SRichard Henderson indicate this was to avoid messing with unknown time zones, 127*85d0b3a5SRichard Henderson and with the epoch nonsense described above. In order for 128*85d0b3a5SRichard Henderson this to work, the existing clock cannot be off by more than 129*85d0b3a5SRichard Henderson 15 minutes. 130*85d0b3a5SRichard Henderson 131*85d0b3a5SRichard Henderson ??? This choice is may be out of date. The x86 port does 132*85d0b3a5SRichard Henderson not have problems with timezones, and the epoch processing has 133*85d0b3a5SRichard Henderson now been fixed in alpha_set_rtc_time. 134*85d0b3a5SRichard Henderson 135*85d0b3a5SRichard Henderson In either case, one can always force a full rtc update with 136*85d0b3a5SRichard Henderson the userland hwclock program, so surely 15 minute accuracy 137*85d0b3a5SRichard Henderson is no real burden. */ 138*85d0b3a5SRichard Henderson 139*85d0b3a5SRichard Henderson /* In order to set the CMOS clock precisely, we have to be called 140*85d0b3a5SRichard Henderson 500 ms after the second nowtime has started, because when 141*85d0b3a5SRichard Henderson nowtime is written into the registers of the CMOS clock, it will 142*85d0b3a5SRichard Henderson jump to the next second precisely 500 ms later. Check the Motorola 143*85d0b3a5SRichard Henderson MC146818A or Dallas DS12887 data sheet for details. */ 144*85d0b3a5SRichard Henderson 145*85d0b3a5SRichard Henderson /* irq are locally disabled here */ 146*85d0b3a5SRichard Henderson spin_lock(&rtc_lock); 147*85d0b3a5SRichard Henderson /* Tell the clock it's being set */ 148*85d0b3a5SRichard Henderson save_control = CMOS_READ(RTC_CONTROL); 149*85d0b3a5SRichard Henderson CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); 150*85d0b3a5SRichard Henderson 151*85d0b3a5SRichard Henderson /* Stop and reset prescaler */ 152*85d0b3a5SRichard Henderson save_freq_select = CMOS_READ(RTC_FREQ_SELECT); 153*85d0b3a5SRichard Henderson CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); 154*85d0b3a5SRichard Henderson 155*85d0b3a5SRichard Henderson cmos_minutes = CMOS_READ(RTC_MINUTES); 156*85d0b3a5SRichard Henderson if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) 157*85d0b3a5SRichard Henderson cmos_minutes = bcd2bin(cmos_minutes); 158*85d0b3a5SRichard Henderson 159*85d0b3a5SRichard Henderson real_seconds = nowtime % 60; 160*85d0b3a5SRichard Henderson real_minutes = nowtime / 60; 161*85d0b3a5SRichard Henderson if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) { 162*85d0b3a5SRichard Henderson /* correct for half hour time zone */ 163*85d0b3a5SRichard Henderson real_minutes += 30; 164*85d0b3a5SRichard Henderson } 165*85d0b3a5SRichard Henderson real_minutes %= 60; 166*85d0b3a5SRichard Henderson 167*85d0b3a5SRichard Henderson if (abs(real_minutes - cmos_minutes) < 30) { 168*85d0b3a5SRichard Henderson if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { 169*85d0b3a5SRichard Henderson real_seconds = bin2bcd(real_seconds); 170*85d0b3a5SRichard Henderson real_minutes = bin2bcd(real_minutes); 171*85d0b3a5SRichard Henderson } 172*85d0b3a5SRichard Henderson CMOS_WRITE(real_seconds,RTC_SECONDS); 173*85d0b3a5SRichard Henderson CMOS_WRITE(real_minutes,RTC_MINUTES); 174*85d0b3a5SRichard Henderson } else { 175*85d0b3a5SRichard Henderson printk_once(KERN_NOTICE 176*85d0b3a5SRichard Henderson "set_rtc_mmss: can't update from %d to %d\n", 177*85d0b3a5SRichard Henderson cmos_minutes, real_minutes); 178*85d0b3a5SRichard Henderson retval = -1; 179*85d0b3a5SRichard Henderson } 180*85d0b3a5SRichard Henderson 181*85d0b3a5SRichard Henderson /* The following flags have to be released exactly in this order, 182*85d0b3a5SRichard Henderson * otherwise the DS12887 (popular MC146818A clone with integrated 183*85d0b3a5SRichard Henderson * battery and quartz) will not reset the oscillator and will not 184*85d0b3a5SRichard Henderson * update precisely 500 ms later. You won't find this mentioned in 185*85d0b3a5SRichard Henderson * the Dallas Semiconductor data sheets, but who believes data 186*85d0b3a5SRichard Henderson * sheets anyway ... -- Markus Kuhn 187*85d0b3a5SRichard Henderson */ 188*85d0b3a5SRichard Henderson CMOS_WRITE(save_control, RTC_CONTROL); 189*85d0b3a5SRichard Henderson CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); 190*85d0b3a5SRichard Henderson spin_unlock(&rtc_lock); 191*85d0b3a5SRichard Henderson 192*85d0b3a5SRichard Henderson return retval; 193*85d0b3a5SRichard Henderson } 194*85d0b3a5SRichard Henderson 195*85d0b3a5SRichard Henderson static int 196*85d0b3a5SRichard Henderson alpha_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) 197*85d0b3a5SRichard Henderson { 198*85d0b3a5SRichard Henderson switch (cmd) { 199*85d0b3a5SRichard Henderson case RTC_EPOCH_READ: 200*85d0b3a5SRichard Henderson return put_user(rtc_epoch, (unsigned long __user *)arg); 201*85d0b3a5SRichard Henderson case RTC_EPOCH_SET: 202*85d0b3a5SRichard Henderson if (arg < 1900) 203*85d0b3a5SRichard Henderson return -EINVAL; 204*85d0b3a5SRichard Henderson rtc_epoch = arg; 205*85d0b3a5SRichard Henderson return 0; 206*85d0b3a5SRichard Henderson default: 207*85d0b3a5SRichard Henderson return -ENOIOCTLCMD; 208*85d0b3a5SRichard Henderson } 209*85d0b3a5SRichard Henderson } 210*85d0b3a5SRichard Henderson 211*85d0b3a5SRichard Henderson static const struct rtc_class_ops alpha_rtc_ops = { 212*85d0b3a5SRichard Henderson .read_time = alpha_rtc_read_time, 213*85d0b3a5SRichard Henderson .set_time = alpha_rtc_set_time, 214*85d0b3a5SRichard Henderson .set_mmss = alpha_rtc_set_mmss, 215*85d0b3a5SRichard Henderson .ioctl = alpha_rtc_ioctl, 216*85d0b3a5SRichard Henderson }; 217*85d0b3a5SRichard Henderson 218*85d0b3a5SRichard Henderson /* 219*85d0b3a5SRichard Henderson * Similarly, except do the actual CMOS access on the boot cpu only. 220*85d0b3a5SRichard Henderson * This requires marshalling the data across an interprocessor call. 221*85d0b3a5SRichard Henderson */ 222*85d0b3a5SRichard Henderson 223*85d0b3a5SRichard Henderson #if defined(CONFIG_SMP) && \ 224*85d0b3a5SRichard Henderson (defined(CONFIG_ALPHA_GENERIC) || defined(CONFIG_ALPHA_MARVEL)) 225*85d0b3a5SRichard Henderson # define HAVE_REMOTE_RTC 1 226*85d0b3a5SRichard Henderson 227*85d0b3a5SRichard Henderson union remote_data { 228*85d0b3a5SRichard Henderson struct rtc_time *tm; 229*85d0b3a5SRichard Henderson unsigned long now; 230*85d0b3a5SRichard Henderson long retval; 231*85d0b3a5SRichard Henderson }; 232*85d0b3a5SRichard Henderson 233*85d0b3a5SRichard Henderson static void 234*85d0b3a5SRichard Henderson do_remote_read(void *data) 235*85d0b3a5SRichard Henderson { 236*85d0b3a5SRichard Henderson union remote_data *x = data; 237*85d0b3a5SRichard Henderson x->retval = alpha_rtc_read_time(NULL, x->tm); 238*85d0b3a5SRichard Henderson } 239*85d0b3a5SRichard Henderson 240*85d0b3a5SRichard Henderson static int 241*85d0b3a5SRichard Henderson remote_read_time(struct device *dev, struct rtc_time *tm) 242*85d0b3a5SRichard Henderson { 243*85d0b3a5SRichard Henderson union remote_data x; 244*85d0b3a5SRichard Henderson if (smp_processor_id() != boot_cpuid) { 245*85d0b3a5SRichard Henderson x.tm = tm; 246*85d0b3a5SRichard Henderson smp_call_function_single(boot_cpuid, do_remote_read, &x, 1); 247*85d0b3a5SRichard Henderson return x.retval; 248*85d0b3a5SRichard Henderson } 249*85d0b3a5SRichard Henderson return alpha_rtc_read_time(NULL, tm); 250*85d0b3a5SRichard Henderson } 251*85d0b3a5SRichard Henderson 252*85d0b3a5SRichard Henderson static void 253*85d0b3a5SRichard Henderson do_remote_set(void *data) 254*85d0b3a5SRichard Henderson { 255*85d0b3a5SRichard Henderson union remote_data *x = data; 256*85d0b3a5SRichard Henderson x->retval = alpha_rtc_set_time(NULL, x->tm); 257*85d0b3a5SRichard Henderson } 258*85d0b3a5SRichard Henderson 259*85d0b3a5SRichard Henderson static int 260*85d0b3a5SRichard Henderson remote_set_time(struct device *dev, struct rtc_time *tm) 261*85d0b3a5SRichard Henderson { 262*85d0b3a5SRichard Henderson union remote_data x; 263*85d0b3a5SRichard Henderson if (smp_processor_id() != boot_cpuid) { 264*85d0b3a5SRichard Henderson x.tm = tm; 265*85d0b3a5SRichard Henderson smp_call_function_single(boot_cpuid, do_remote_set, &x, 1); 266*85d0b3a5SRichard Henderson return x.retval; 267*85d0b3a5SRichard Henderson } 268*85d0b3a5SRichard Henderson return alpha_rtc_set_time(NULL, tm); 269*85d0b3a5SRichard Henderson } 270*85d0b3a5SRichard Henderson 271*85d0b3a5SRichard Henderson static void 272*85d0b3a5SRichard Henderson do_remote_mmss(void *data) 273*85d0b3a5SRichard Henderson { 274*85d0b3a5SRichard Henderson union remote_data *x = data; 275*85d0b3a5SRichard Henderson x->retval = alpha_rtc_set_mmss(NULL, x->now); 276*85d0b3a5SRichard Henderson } 277*85d0b3a5SRichard Henderson 278*85d0b3a5SRichard Henderson static int 279*85d0b3a5SRichard Henderson remote_set_mmss(struct device *dev, unsigned long now) 280*85d0b3a5SRichard Henderson { 281*85d0b3a5SRichard Henderson union remote_data x; 282*85d0b3a5SRichard Henderson if (smp_processor_id() != boot_cpuid) { 283*85d0b3a5SRichard Henderson x.now = now; 284*85d0b3a5SRichard Henderson smp_call_function_single(boot_cpuid, do_remote_mmss, &x, 1); 285*85d0b3a5SRichard Henderson return x.retval; 286*85d0b3a5SRichard Henderson } 287*85d0b3a5SRichard Henderson return alpha_rtc_set_mmss(NULL, now); 288*85d0b3a5SRichard Henderson } 289*85d0b3a5SRichard Henderson 290*85d0b3a5SRichard Henderson static const struct rtc_class_ops remote_rtc_ops = { 291*85d0b3a5SRichard Henderson .read_time = remote_read_time, 292*85d0b3a5SRichard Henderson .set_time = remote_set_time, 293*85d0b3a5SRichard Henderson .set_mmss = remote_set_mmss, 294*85d0b3a5SRichard Henderson .ioctl = alpha_rtc_ioctl, 295*85d0b3a5SRichard Henderson }; 296*85d0b3a5SRichard Henderson #endif 297*85d0b3a5SRichard Henderson 298*85d0b3a5SRichard Henderson static int __init 299*85d0b3a5SRichard Henderson alpha_rtc_init(void) 300*85d0b3a5SRichard Henderson { 301*85d0b3a5SRichard Henderson const struct rtc_class_ops *ops; 302*85d0b3a5SRichard Henderson struct platform_device *pdev; 303*85d0b3a5SRichard Henderson struct rtc_device *rtc; 304*85d0b3a5SRichard Henderson const char *name; 305*85d0b3a5SRichard Henderson 306*85d0b3a5SRichard Henderson init_rtc_epoch(); 307*85d0b3a5SRichard Henderson name = "rtc-alpha"; 308*85d0b3a5SRichard Henderson ops = &alpha_rtc_ops; 309*85d0b3a5SRichard Henderson 310*85d0b3a5SRichard Henderson #ifdef HAVE_REMOTE_RTC 311*85d0b3a5SRichard Henderson if (alpha_mv.rtc_boot_cpu_only) 312*85d0b3a5SRichard Henderson ops = &remote_rtc_ops; 313*85d0b3a5SRichard Henderson #endif 314*85d0b3a5SRichard Henderson 315*85d0b3a5SRichard Henderson pdev = platform_device_register_simple(name, -1, NULL, 0); 316*85d0b3a5SRichard Henderson rtc = devm_rtc_device_register(&pdev->dev, name, ops, THIS_MODULE); 317*85d0b3a5SRichard Henderson if (IS_ERR(rtc)) 318*85d0b3a5SRichard Henderson return PTR_ERR(rtc); 319*85d0b3a5SRichard Henderson 320*85d0b3a5SRichard Henderson platform_set_drvdata(pdev, rtc); 321*85d0b3a5SRichard Henderson return 0; 322*85d0b3a5SRichard Henderson } 323*85d0b3a5SRichard Henderson device_initcall(alpha_rtc_init); 324