/* Set the current date and time inthe real time clock. */ void set_rtc_time(struct rtc_time *t) { void __iomem *regs = mstk48t02_regs; u8 tmp; spin_lock_irq(&mostek_lock); tmp = mostek_read(regs + MOSTEK_CREG); tmp |= MSTK_CREG_WRITE; mostek_write(regs + MOSTEK_CREG, tmp); MSTK_SET_REG_SEC(regs,t->sec); MSTK_SET_REG_MIN(regs,t->min); MSTK_SET_REG_HOUR(regs,t->hour); MSTK_SET_REG_DOW(regs,t->dow); MSTK_SET_REG_DOM(regs,t->dom); MSTK_SET_REG_MONTH(regs,t->month); MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO); tmp = mostek_read(regs + MOSTEK_CREG); tmp &= ~MSTK_CREG_WRITE; mostek_write(regs + MOSTEK_CREG, tmp); spin_unlock_irq(&mostek_lock); }
/* Set the current date and time inthe real time clock. */ void set_rtc_time(struct rtc_time *t) { unsigned long regs = mstk48t02_regs; unsigned long flags; u8 tmp; save_flags(flags); cli(); tmp = mostek_read(regs + MOSTEK_CREG); tmp |= MSTK_CREG_WRITE; mostek_write(regs + MOSTEK_CREG, tmp); MSTK_SET_REG_SEC(regs,t->sec); MSTK_SET_REG_MIN(regs,t->min); MSTK_SET_REG_HOUR(regs,t->hour); MSTK_SET_REG_DOW(regs,t->dow); MSTK_SET_REG_DOM(regs,t->dom); MSTK_SET_REG_MONTH(regs,t->month); MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO); tmp = mostek_read(regs + MOSTEK_CREG); tmp &= ~MSTK_CREG_WRITE; mostek_write(regs + MOSTEK_CREG, tmp); restore_flags(flags); }
/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */ static void __init kick_start_clock(void) { struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; unsigned char sec; int i, count; prom_printf("CLOCK: Clock was stopped. Kick start "); spin_lock_irq(&mostek_lock); /* Turn on the kick start bit to start the oscillator. */ regs->creg |= MSTK_CREG_WRITE; regs->sec &= ~MSTK_STOP; regs->hour |= MSTK_KICK_START; regs->creg &= ~MSTK_CREG_WRITE; spin_unlock_irq(&mostek_lock); /* Delay to allow the clock oscillator to start. */ sec = MSTK_REG_SEC(regs); for (i = 0; i < 3; i++) { while (sec == MSTK_REG_SEC(regs)) for (count = 0; count < 100000; count++) /* nothing */ ; prom_printf("."); sec = regs->sec; } prom_printf("\n"); spin_lock_irq(&mostek_lock); /* Turn off kick start and set a "valid" time and date. */ regs->creg |= MSTK_CREG_WRITE; regs->hour &= ~MSTK_KICK_START; MSTK_SET_REG_SEC(regs,0); MSTK_SET_REG_MIN(regs,0); MSTK_SET_REG_HOUR(regs,0); MSTK_SET_REG_DOW(regs,5); MSTK_SET_REG_DOM(regs,1); MSTK_SET_REG_MONTH(regs,8); MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO); regs->creg &= ~MSTK_CREG_WRITE; spin_unlock_irq(&mostek_lock); /* Ensure the kick start bit is off. If it isn't, turn it off. */ while (regs->hour & MSTK_KICK_START) { prom_printf("CLOCK: Kick start still on!\n"); spin_lock_irq(&mostek_lock); regs->creg |= MSTK_CREG_WRITE; regs->hour &= ~MSTK_KICK_START; regs->creg &= ~MSTK_CREG_WRITE; spin_unlock_irq(&mostek_lock); } prom_printf("CLOCK: Kick start procedure successful.\n"); }
/* * BUG: This routine does not handle hour overflow properly; it just * sets the minutes. Usually you won't notice until after reboot! */ static int set_rtc_mmss(unsigned long nowtime) { int real_seconds, real_minutes, mostek_minutes; struct mostek48t02 *regs = (struct mostek48t02 *)mstk48t02_regs; unsigned long flags; #ifdef CONFIG_SUN4 struct intersil *iregs = intersil_clock; int temp; #endif /* Not having a register set can lead to trouble. */ if (!regs) { #ifdef CONFIG_SUN4 if(!iregs) return -1; else { temp = iregs->clk.int_csec; mostek_minutes = iregs->clk.int_min; real_seconds = nowtime % 60; real_minutes = nowtime / 60; if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1) real_minutes += 30; /* correct for half hour time zone */ real_minutes %= 60; if (abs(real_minutes - mostek_minutes) < 30) { intersil_stop(iregs); iregs->clk.int_sec=real_seconds; iregs->clk.int_min=real_minutes; intersil_start(iregs); } else { printk(KERN_WARNING "set_rtc_mmss: can't update from %d to %d\n", mostek_minutes, real_minutes); return -1; } return 0; } #endif } spin_lock_irqsave(&mostek_lock, flags); /* Read the current RTC minutes. */ regs->creg |= MSTK_CREG_READ; mostek_minutes = MSTK_REG_MIN(regs); regs->creg &= ~MSTK_CREG_READ; /* * since we're only adjusting minutes and seconds, * don't interfere with hour overflow. This avoids * messing with unknown time zones but requires your * RTC not to be off by more than 15 minutes */ real_seconds = nowtime % 60; real_minutes = nowtime / 60; if (((abs(real_minutes - mostek_minutes) + 15)/30) & 1) real_minutes += 30; /* correct for half hour time zone */ real_minutes %= 60; if (abs(real_minutes - mostek_minutes) < 30) { regs->creg |= MSTK_CREG_WRITE; MSTK_SET_REG_SEC(regs,real_seconds); MSTK_SET_REG_MIN(regs,real_minutes); regs->creg &= ~MSTK_CREG_WRITE; spin_unlock_irqrestore(&mostek_lock, flags); return 0; } else { spin_unlock_irqrestore(&mostek_lock, flags); return -1; } }