kogiidena | 94c0fa5 | 2006-09-27 14:53:35 +0900 | [diff] [blame] | 1 | /* |
| 2 | * arch/sh/boards/landisk/rtc.c -- RTC support |
| 3 | * |
| 4 | * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> |
| 5 | * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka |
| 6 | */ |
| 7 | /* |
| 8 | * modifed by kogiidena |
| 9 | * 2005.09.16 |
| 10 | */ |
kogiidena | 94c0fa5 | 2006-09-27 14:53:35 +0900 | [diff] [blame] | 11 | #include <linux/init.h> |
| 12 | #include <linux/kernel.h> |
| 13 | #include <linux/sched.h> |
| 14 | #include <linux/time.h> |
| 15 | #include <linux/delay.h> |
| 16 | #include <linux/spinlock.h> |
Paul Mundt | af514ca | 2006-09-27 17:11:32 +0900 | [diff] [blame] | 17 | #include <linux/bcd.h> |
| 18 | #include <asm/rtc.h> |
kogiidena | 94c0fa5 | 2006-09-27 14:53:35 +0900 | [diff] [blame] | 19 | |
kogiidena | 94c0fa5 | 2006-09-27 14:53:35 +0900 | [diff] [blame] | 20 | extern spinlock_t rtc_lock; |
| 21 | |
| 22 | extern void |
| 23 | rs5c313_set_cmos_time(unsigned int BCD_yr, unsigned int BCD_mon, |
| 24 | unsigned int BCD_day, unsigned int BCD_hr, |
| 25 | unsigned int BCD_min, unsigned int BCD_sec); |
| 26 | |
| 27 | extern unsigned long |
| 28 | rs5c313_get_cmos_time(unsigned int *BCD_yr, unsigned int *BCD_mon, |
| 29 | unsigned int *BCD_day, unsigned int *BCD_hr, |
| 30 | unsigned int *BCD_min, unsigned int *BCD_sec); |
| 31 | |
| 32 | void landisk_rtc_gettimeofday(struct timespec *tv) |
| 33 | { |
| 34 | unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec; |
| 35 | unsigned long flags; |
| 36 | |
| 37 | spin_lock_irqsave(&rtc_lock, flags); |
| 38 | tv->tv_sec = rs5c313_get_cmos_time |
| 39 | (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec); |
| 40 | tv->tv_nsec = 0; |
| 41 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 42 | } |
| 43 | |
| 44 | int landisk_rtc_settimeofday(const time_t secs) |
| 45 | { |
| 46 | int retval = 0; |
| 47 | int real_seconds, real_minutes, cmos_minutes; |
| 48 | unsigned long flags; |
| 49 | unsigned long nowtime = secs; |
| 50 | unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec; |
| 51 | |
| 52 | spin_lock_irqsave(&rtc_lock, flags); |
| 53 | |
| 54 | rs5c313_get_cmos_time |
| 55 | (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec); |
| 56 | cmos_minutes = BCD_min; |
| 57 | BCD_TO_BIN(cmos_minutes); |
| 58 | |
| 59 | /* |
| 60 | * since we're only adjusting minutes and seconds, |
| 61 | * don't interfere with hour overflow. This avoids |
| 62 | * messing with unknown time zones but requires your |
| 63 | * RTC not to be off by more than 15 minutes |
| 64 | */ |
| 65 | real_seconds = nowtime % 60; |
| 66 | real_minutes = nowtime / 60; |
| 67 | if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1) |
| 68 | real_minutes += 30; /* correct for half hour time zone */ |
| 69 | real_minutes %= 60; |
| 70 | |
| 71 | if (abs(real_minutes - cmos_minutes) < 30) { |
| 72 | BIN_TO_BCD(real_seconds); |
| 73 | BIN_TO_BCD(real_minutes); |
| 74 | rs5c313_set_cmos_time(BCD_yr, BCD_mon, BCD_day, BCD_hr, |
| 75 | real_minutes, real_seconds); |
| 76 | } else { |
| 77 | printk(KERN_WARNING |
| 78 | "set_rtc_time: can't update from %d to %d\n", |
| 79 | cmos_minutes, real_minutes); |
| 80 | retval = -1; |
| 81 | } |
| 82 | |
| 83 | spin_unlock_irqrestore(&rtc_lock, flags); |
| 84 | return retval; |
| 85 | } |
| 86 | |
kogiidena | 94c0fa5 | 2006-09-27 14:53:35 +0900 | [diff] [blame] | 87 | void landisk_time_init(void) |
| 88 | { |
Paul Mundt | af514ca | 2006-09-27 17:11:32 +0900 | [diff] [blame] | 89 | rtc_sh_get_time = landisk_rtc_gettimeofday; |
| 90 | rtc_sh_set_time = landisk_rtc_settimeofday; |
kogiidena | 94c0fa5 | 2006-09-27 14:53:35 +0900 | [diff] [blame] | 91 | } |