aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc/kernel/time.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sparc/kernel/time.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'arch/sparc/kernel/time.c')
-rw-r--r--arch/sparc/kernel/time.c641
1 files changed, 641 insertions, 0 deletions
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
new file mode 100644
index 000000000000..6486cbf2efe9
--- /dev/null
+++ b/arch/sparc/kernel/time.c
@@ -0,0 +1,641 @@
1/* $Id: time.c,v 1.60 2002/01/23 14:33:55 davem Exp $
2 * linux/arch/sparc/kernel/time.c
3 *
4 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
5 * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
6 *
7 * Chris Davis (cdavis@cois.on.ca) 03/27/1998
8 * Added support for the intersil on the sun4/4200
9 *
10 * Gleb Raiko (rajko@mech.math.msu.su) 08/18/1998
11 * Support for MicroSPARC-IIep, PCI CPU.
12 *
13 * This file handles the Sparc specific time handling details.
14 *
15 * 1997-09-10 Updated NTP code according to technical memorandum Jan '96
16 * "A Kernel Model for Precision Timekeeping" by Dave Mills
17 */
18#include <linux/config.h>
19#include <linux/errno.h>
20#include <linux/module.h>
21#include <linux/sched.h>
22#include <linux/kernel.h>
23#include <linux/param.h>
24#include <linux/string.h>
25#include <linux/mm.h>
26#include <linux/interrupt.h>
27#include <linux/time.h>
28#include <linux/timex.h>
29#include <linux/init.h>
30#include <linux/pci.h>
31#include <linux/ioport.h>
32#include <linux/profile.h>
33
34#include <asm/oplib.h>
35#include <asm/segment.h>
36#include <asm/timer.h>
37#include <asm/mostek.h>
38#include <asm/system.h>
39#include <asm/irq.h>
40#include <asm/io.h>
41#include <asm/idprom.h>
42#include <asm/machines.h>
43#include <asm/sun4paddr.h>
44#include <asm/page.h>
45#include <asm/pcic.h>
46
47extern unsigned long wall_jiffies;
48
49u64 jiffies_64 = INITIAL_JIFFIES;
50
51EXPORT_SYMBOL(jiffies_64);
52
53DEFINE_SPINLOCK(rtc_lock);
54enum sparc_clock_type sp_clock_typ;
55DEFINE_SPINLOCK(mostek_lock);
56void __iomem *mstk48t02_regs = NULL;
57static struct mostek48t08 *mstk48t08_regs = NULL;
58static int set_rtc_mmss(unsigned long);
59static int sbus_do_settimeofday(struct timespec *tv);
60
61#ifdef CONFIG_SUN4
62struct intersil *intersil_clock;
63#define intersil_cmd(intersil_reg, intsil_cmd) intersil_reg->int_cmd_reg = \
64 (intsil_cmd)
65
66#define intersil_intr(intersil_reg, intsil_cmd) intersil_reg->int_intr_reg = \
67 (intsil_cmd)
68
69#define intersil_start(intersil_reg) intersil_cmd(intersil_reg, \
70 ( INTERSIL_START | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
71 INTERSIL_INTR_ENABLE))
72
73#define intersil_stop(intersil_reg) intersil_cmd(intersil_reg, \
74 ( INTERSIL_STOP | INTERSIL_32K | INTERSIL_NORMAL | INTERSIL_24H |\
75 INTERSIL_INTR_ENABLE))
76
77#define intersil_read_intr(intersil_reg, towhere) towhere = \
78 intersil_reg->int_intr_reg
79
80#endif
81
82unsigned long profile_pc(struct pt_regs *regs)
83{
84 extern char __copy_user_begin[], __copy_user_end[];
85 extern char __atomic_begin[], __atomic_end[];
86 extern char __bzero_begin[], __bzero_end[];
87 extern char __bitops_begin[], __bitops_end[];
88
89 unsigned long pc = regs->pc;
90
91 if (in_lock_functions(pc) ||
92 (pc >= (unsigned long) __copy_user_begin &&
93 pc < (unsigned long) __copy_user_end) ||
94 (pc >= (unsigned long) __atomic_begin &&
95 pc < (unsigned long) __atomic_end) ||
96 (pc >= (unsigned long) __bzero_begin &&
97 pc < (unsigned long) __bzero_end) ||
98 (pc >= (unsigned long) __bitops_begin &&
99 pc < (unsigned long) __bitops_end))
100 pc = regs->u_regs[UREG_RETPC];
101 return pc;
102}
103
104__volatile__ unsigned int *master_l10_counter;
105__volatile__ unsigned int *master_l10_limit;
106
107/*
108 * timer_interrupt() needs to keep up the real-time clock,
109 * as well as call the "do_timer()" routine every clocktick
110 */
111
112#define TICK_SIZE (tick_nsec / 1000)
113
114irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
115{
116 /* last time the cmos clock got updated */
117 static long last_rtc_update;
118
119#ifndef CONFIG_SMP
120 profile_tick(CPU_PROFILING, regs);
121#endif
122
123 /* Protect counter clear so that do_gettimeoffset works */
124 write_seqlock(&xtime_lock);
125#ifdef CONFIG_SUN4
126 if((idprom->id_machtype == (SM_SUN4 | SM_4_260)) ||
127 (idprom->id_machtype == (SM_SUN4 | SM_4_110))) {
128 int temp;
129 intersil_read_intr(intersil_clock, temp);
130 /* re-enable the irq */
131 enable_pil_irq(10);
132 }
133#endif
134 clear_clock_irq();
135
136 do_timer(regs);
137#ifndef CONFIG_SMP
138 update_process_times(user_mode(regs));
139#endif
140
141
142 /* Determine when to update the Mostek clock. */
143 if ((time_status & STA_UNSYNC) == 0 &&
144 xtime.tv_sec > last_rtc_update + 660 &&
145 (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
146 (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
147 if (set_rtc_mmss(xtime.tv_sec) == 0)
148 last_rtc_update = xtime.tv_sec;
149 else
150 last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
151 }
152 write_sequnlock(&xtime_lock);
153
154 return IRQ_HANDLED;
155}
156
157/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */
158static void __init kick_start_clock(void)
159{
160 struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
161 unsigned char sec;
162 int i, count;
163
164 prom_printf("CLOCK: Clock was stopped. Kick start ");
165
166 spin_lock_irq(&mostek_lock);
167
168 /* Turn on the kick start bit to start the oscillator. */
169 regs->creg |= MSTK_CREG_WRITE;
170 regs->sec &= ~MSTK_STOP;
171 regs->hour |= MSTK_KICK_START;
172 regs->creg &= ~MSTK_CREG_WRITE;
173
174 spin_unlock_irq(&mostek_lock);
175
176 /* Delay to allow the clock oscillator to start. */
177 sec = MSTK_REG_SEC(regs);
178 for (i = 0; i < 3; i++) {
179 while (sec == MSTK_REG_SEC(regs))
180 for (count = 0; count < 100000; count++)
181 /* nothing */ ;
182 prom_printf(".");
183 sec = regs->sec;
184 }
185 prom_printf("\n");
186
187 spin_lock_irq(&mostek_lock);
188
189 /* Turn off kick start and set a "valid" time and date. */
190 regs->creg |= MSTK_CREG_WRITE;
191 regs->hour &= ~MSTK_KICK_START;
192 MSTK_SET_REG_SEC(regs,0);
193 MSTK_SET_REG_MIN(regs,0);
194 MSTK_SET_REG_HOUR(regs,0);
195 MSTK_SET_REG_DOW(regs,5);
196 MSTK_SET_REG_DOM(regs,1);
197 MSTK_SET_REG_MONTH(regs,8);
198 MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);
199 regs->creg &= ~MSTK_CREG_WRITE;
200
201 spin_unlock_irq(&mostek_lock);
202
203 /* Ensure the kick start bit is off. If it isn't, turn it off. */
204 while (regs->hour & MSTK_KICK_START) {
205 prom_printf("CLOCK: Kick start still on!\n");
206
207 spin_lock_irq(&mostek_lock);
208 regs->creg |= MSTK_CREG_WRITE;
209 regs->hour &= ~MSTK_KICK_START;
210 regs->creg &= ~MSTK_CREG_WRITE;
211 spin_unlock_irq(&mostek_lock);
212 }
213
214 prom_printf("CLOCK: Kick start procedure successful.\n");
215}
216
217/* Return nonzero if the clock chip battery is low. */
218static __inline__ int has_low_battery(void)
219{
220 struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
221 unsigned char data1, data2;
222
223 spin_lock_irq(&mostek_lock);
224 data1 = regs->eeprom[0]; /* Read some data. */
225 regs->eeprom[0] = ~data1; /* Write back the complement. */
226 data2 = regs->eeprom[0]; /* Read back the complement. */
227 regs->eeprom[0] = data1; /* Restore the original value. */
228 spin_unlock_irq(&mostek_lock);
229
230 return (data1 == data2); /* Was the write blocked? */
231}
232
233/* Probe for the real time clock chip on Sun4 */
234static __inline__ void sun4_clock_probe(void)
235{
236#ifdef CONFIG_SUN4
237 int temp;
238 struct resource r;
239
240 memset(&r, 0, sizeof(r));
241 if( idprom->id_machtype == (SM_SUN4 | SM_4_330) ) {
242 sp_clock_typ = MSTK48T02;
243 r.start = sun4_clock_physaddr;
244 mstk48t02_regs = sbus_ioremap(&r, 0,
245 sizeof(struct mostek48t02), NULL);
246 mstk48t08_regs = NULL; /* To catch weirdness */
247 intersil_clock = NULL; /* just in case */
248
249 /* Kick start the clock if it is completely stopped. */
250 if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
251 kick_start_clock();
252 } else if( idprom->id_machtype == (SM_SUN4 | SM_4_260)) {
253 /* intersil setup code */
254 printk("Clock: INTERSIL at %8x ",sun4_clock_physaddr);
255 sp_clock_typ = INTERSIL;
256 r.start = sun4_clock_physaddr;
257 intersil_clock = (struct intersil *)
258 sbus_ioremap(&r, 0, sizeof(*intersil_clock), "intersil");
259 mstk48t02_regs = 0; /* just be sure */
260 mstk48t08_regs = NULL; /* ditto */
261 /* initialise the clock */
262
263 intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
264
265 intersil_start(intersil_clock);
266
267 intersil_read_intr(intersil_clock, temp);
268 while (!(temp & 0x80))
269 intersil_read_intr(intersil_clock, temp);
270
271 intersil_read_intr(intersil_clock, temp);
272 while (!(temp & 0x80))
273 intersil_read_intr(intersil_clock, temp);
274
275 intersil_stop(intersil_clock);
276
277 }
278#endif
279}
280
281/* Probe for the mostek real time clock chip. */
282static __inline__ void clock_probe(void)
283{
284 struct linux_prom_registers clk_reg[2];
285 char model[128];
286 register int node, cpuunit, bootbus;
287 struct resource r;
288
289 cpuunit = bootbus = 0;
290 memset(&r, 0, sizeof(r));
291
292 /* Determine the correct starting PROM node for the probe. */
293 node = prom_getchild(prom_root_node);
294 switch (sparc_cpu_model) {
295 case sun4c:
296 break;
297 case sun4m:
298 node = prom_getchild(prom_searchsiblings(node, "obio"));
299 break;
300 case sun4d:
301 node = prom_getchild(bootbus = prom_searchsiblings(prom_getchild(cpuunit = prom_searchsiblings(node, "cpu-unit")), "bootbus"));
302 break;
303 default:
304 prom_printf("CLOCK: Unsupported architecture!\n");
305 prom_halt();
306 }
307
308 /* Find the PROM node describing the real time clock. */
309 sp_clock_typ = MSTK_INVALID;
310 node = prom_searchsiblings(node,"eeprom");
311 if (!node) {
312 prom_printf("CLOCK: No clock found!\n");
313 prom_halt();
314 }
315
316 /* Get the model name and setup everything up. */
317 model[0] = '\0';
318 prom_getstring(node, "model", model, sizeof(model));
319 if (strcmp(model, "mk48t02") == 0) {
320 sp_clock_typ = MSTK48T02;
321 if (prom_getproperty(node, "reg", (char *) clk_reg, sizeof(clk_reg)) == -1) {
322 prom_printf("clock_probe: FAILED!\n");
323 prom_halt();
324 }
325 if (sparc_cpu_model == sun4d)
326 prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1);
327 else
328 prom_apply_obio_ranges(clk_reg, 1);
329 /* Map the clock register io area read-only */
330 r.flags = clk_reg[0].which_io;
331 r.start = clk_reg[0].phys_addr;
332 mstk48t02_regs = sbus_ioremap(&r, 0,
333 sizeof(struct mostek48t02), "mk48t02");
334 mstk48t08_regs = NULL; /* To catch weirdness */
335 } else if (strcmp(model, "mk48t08") == 0) {
336 sp_clock_typ = MSTK48T08;
337 if(prom_getproperty(node, "reg", (char *) clk_reg,
338 sizeof(clk_reg)) == -1) {
339 prom_printf("clock_probe: FAILED!\n");
340 prom_halt();
341 }
342 if (sparc_cpu_model == sun4d)
343 prom_apply_generic_ranges (bootbus, cpuunit, clk_reg, 1);
344 else
345 prom_apply_obio_ranges(clk_reg, 1);
346 /* Map the clock register io area read-only */
347 /* XXX r/o attribute is somewhere in r.flags */
348 r.flags = clk_reg[0].which_io;
349 r.start = clk_reg[0].phys_addr;
350 mstk48t08_regs = (struct mostek48t08 *) sbus_ioremap(&r, 0,
351 sizeof(struct mostek48t08), "mk48t08");
352
353 mstk48t02_regs = &mstk48t08_regs->regs;
354 } else {
355 prom_printf("CLOCK: Unknown model name '%s'\n",model);
356 prom_halt();
357 }
358
359 /* Report a low battery voltage condition. */
360 if (has_low_battery())
361 printk(KERN_CRIT "NVRAM: Low battery voltage!\n");
362
363 /* Kick start the clock if it is completely stopped. */
364 if (mostek_read(mstk48t02_regs + MOSTEK_SEC) & MSTK_STOP)
365 kick_start_clock();
366}
367
368void __init sbus_time_init(void)
369{
370 unsigned int year, mon, day, hour, min, sec;
371 struct mostek48t02 *mregs;
372
373#ifdef CONFIG_SUN4
374 int temp;
375 struct intersil *iregs;
376#endif
377
378 BTFIXUPSET_CALL(bus_do_settimeofday, sbus_do_settimeofday, BTFIXUPCALL_NORM);
379 btfixup();
380
381 if (ARCH_SUN4)
382 sun4_clock_probe();
383 else
384 clock_probe();
385
386 sparc_init_timers(timer_interrupt);
387
388#ifdef CONFIG_SUN4
389 if(idprom->id_machtype == (SM_SUN4 | SM_4_330)) {
390#endif
391 mregs = (struct mostek48t02 *)mstk48t02_regs;
392 if(!mregs) {
393 prom_printf("Something wrong, clock regs not mapped yet.\n");
394 prom_halt();
395 }
396 spin_lock_irq(&mostek_lock);
397 mregs->creg |= MSTK_CREG_READ;
398 sec = MSTK_REG_SEC(mregs);
399 min = MSTK_REG_MIN(mregs);
400 hour = MSTK_REG_HOUR(mregs);
401 day = MSTK_REG_DOM(mregs);
402 mon = MSTK_REG_MONTH(mregs);
403 year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );
404 xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
405 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
406 set_normalized_timespec(&wall_to_monotonic,
407 -xtime.tv_sec, -xtime.tv_nsec);
408 mregs->creg &= ~MSTK_CREG_READ;
409 spin_unlock_irq(&mostek_lock);
410#ifdef CONFIG_SUN4
411 } else if(idprom->id_machtype == (SM_SUN4 | SM_4_260) ) {
412 /* initialise the intersil on sun4 */
413
414 iregs=intersil_clock;
415 if(!iregs) {
416 prom_printf("Something wrong, clock regs not mapped yet.\n");
417 prom_halt();
418 }
419
420 intersil_intr(intersil_clock,INTERSIL_INT_100HZ);
421 disable_pil_irq(10);
422 intersil_stop(iregs);
423 intersil_read_intr(intersil_clock, temp);
424
425 temp = iregs->clk.int_csec;
426
427 sec = iregs->clk.int_sec;
428 min = iregs->clk.int_min;
429 hour = iregs->clk.int_hour;
430 day = iregs->clk.int_day;
431 mon = iregs->clk.int_month;
432 year = MSTK_CVT_YEAR(iregs->clk.int_year);
433
434 enable_pil_irq(10);
435 intersil_start(iregs);
436
437 xtime.tv_sec = mktime(year, mon, day, hour, min, sec);
438 xtime.tv_nsec = (INITIAL_JIFFIES % HZ) * (NSEC_PER_SEC / HZ);
439 set_normalized_timespec(&wall_to_monotonic,
440 -xtime.tv_sec, -xtime.tv_nsec);
441 printk("%u/%u/%u %u:%u:%u\n",day,mon,year,hour,min,sec);
442 }
443#endif
444
445 /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */
446 local_irq_enable();
447}
448
449void __init time_init(void)
450{
451#ifdef CONFIG_PCI
452 extern void pci_time_init(void);
453 if (pcic_present()) {
454 pci_time_init();
455 return;
456 }
457#endif
458 sbus_time_init();
459}
460
461extern __inline__ unsigned long do_gettimeoffset(void)
462{
463 return (*master_l10_counter >> 10) & 0x1fffff;
464}
465
466/*
467 * Returns nanoseconds
468 * XXX This is a suboptimal implementation.
469 */
470unsigned long long sched_clock(void)
471{
472 return (unsigned long long)jiffies * (1000000000 / HZ);
473}
474
475/* Ok, my cute asm atomicity trick doesn't work anymore.
476 * There are just too many variables that need to be protected
477 * now (both members of xtime, wall_jiffies, et al.)
478 */
479void do_gettimeofday(struct timeval *tv)
480{
481 unsigned long flags;
482 unsigned long seq;
483 unsigned long usec, sec;
484 unsigned long max_ntp_tick = tick_usec - tickadj;
485
486 do {
487 unsigned long lost;
488
489 seq = read_seqbegin_irqsave(&xtime_lock, flags);
490 usec = do_gettimeoffset();
491 lost = jiffies - wall_jiffies;
492
493 /*
494 * If time_adjust is negative then NTP is slowing the clock
495 * so make sure not to go into next possible interval.
496 * Better to lose some accuracy than have time go backwards..
497 */
498 if (unlikely(time_adjust < 0)) {
499 usec = min(usec, max_ntp_tick);
500
501 if (lost)
502 usec += lost * max_ntp_tick;
503 }
504 else if (unlikely(lost))
505 usec += lost * tick_usec;
506
507 sec = xtime.tv_sec;
508 usec += (xtime.tv_nsec / 1000);
509 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
510
511 while (usec >= 1000000) {
512 usec -= 1000000;
513 sec++;
514 }
515
516 tv->tv_sec = sec;
517 tv->tv_usec = usec;
518}
519
520EXPORT_SYMBOL(do_gettimeofday);
521
522int do_settimeofday(struct timespec *tv)
523{
524 int ret;
525
526 write_seqlock_irq(&xtime_lock);
527 ret = bus_do_settimeofday(tv);
528 write_sequnlock_irq(&xtime_lock);
529 clock_was_set();
530 return ret;
531}
532
533EXPORT_SYMBOL(do_settimeofday);
534
535static int sbus_do_settimeofday(struct timespec *tv)
536{
537 time_t wtm_sec, sec = tv->tv_sec;
538 long wtm_nsec, nsec = tv->tv_nsec;
539
540 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
541 return -EINVAL;
542
543 /*
544 * This is revolting. We need to set "xtime" correctly. However, the
545 * value in this location is the value at the most recent update of
546 * wall time. Discover what correction gettimeofday() would have
547 * made, and then undo it!
548 */
549 nsec -= 1000 * (do_gettimeoffset() +
550 (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ));
551
552 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
553 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
554
555 set_normalized_timespec(&xtime, sec, nsec);
556 set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
557
558 time_adjust = 0; /* stop active adjtime() */
559 time_status |= STA_UNSYNC;
560 time_maxerror = NTP_PHASE_LIMIT;
561 time_esterror = NTP_PHASE_LIMIT;
562 return 0;
563}
564
565/*
566 * BUG: This routine does not handle hour overflow properly; it just
567 * sets the minutes. Usually you won't notice until after reboot!
568 */
569static int set_rtc_mmss(unsigned long nowtime)
570{
571 int real_seconds, real_minutes, mostek_minutes;
572 struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs;
573 unsigned long flags;
574#ifdef CONFIG_SUN4
575 struct intersil *iregs = intersil_clock;
576 int temp;
577#endif
578
579 /* Not having a register set can lead to trouble. */
580 if (!regs) {
581#ifdef CONFIG_SUN4
582 if(!iregs)
583 return -1;
584 else {
585 temp = iregs->clk.int_csec;
586
587 mostek_minutes = iregs->clk.int_min;
588
589 real_seconds = nowtime % 60;
590 real_minutes = nowtime / 60;
591 if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
592 real_minutes += 30; /* correct for half hour time zone */
593 real_minutes %= 60;
594
595 if (abs(real_minutes - mostek_minutes) < 30) {
596 intersil_stop(iregs);
597 iregs->clk.int_sec=real_seconds;
598 iregs->clk.int_min=real_minutes;
599 intersil_start(iregs);
600 } else {
601 printk(KERN_WARNING
602 "set_rtc_mmss: can't update from %d to %d\n",
603 mostek_minutes, real_minutes);
604 return -1;
605 }
606
607 return 0;
608 }
609#endif
610 }
611
612 spin_lock_irqsave(&mostek_lock, flags);
613 /* Read the current RTC minutes. */
614 regs->creg |= MSTK_CREG_READ;
615 mostek_minutes = MSTK_REG_MIN(regs);
616 regs->creg &= ~MSTK_CREG_READ;
617
618 /*
619 * since we're only adjusting minutes and seconds,
620 * don't interfere with hour overflow. This avoids
621 * messing with unknown time zones but requires your
622 * RTC not to be off by more than 15 minutes
623 */
624 real_seconds = nowtime % 60;
625 real_minutes = nowtime / 60;
626 if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1)
627 real_minutes += 30; /* correct for half hour time zone */
628 real_minutes %= 60;
629
630 if (abs(real_minutes - mostek_minutes) < 30) {
631 regs->creg |= MSTK_CREG_WRITE;
632 MSTK_SET_REG_SEC(regs,real_seconds);
633 MSTK_SET_REG_MIN(regs,real_minutes);
634 regs->creg &= ~MSTK_CREG_WRITE;
635 spin_unlock_irqrestore(&mostek_lock, flags);
636 return 0;
637 } else {
638 spin_unlock_irqrestore(&mostek_lock, flags);
639 return -1;
640 }
641}