OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [sh/] [kernel/] [rtc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * linux/arch/sh/kernel/rtc.c -- SH3 / SH4 on-chip RTC support
3
 *
4
 *  Copyright (C) 2000  Philipp Rumpf <prumpf@tux.org>
5
 *  Copyright (C) 1999  Tetsuya Okada & Niibe Yutaka
6
 */
7
 
8
#include <linux/init.h>
9
#include <linux/kernel.h>
10
#include <linux/sched.h>
11
#include <linux/time.h>
12
 
13
#include <asm/io.h>
14
#include <asm/rtc.h>
15
 
16
#ifndef BCD_TO_BIN
17
#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
18
#endif
19
 
20
#ifndef BIN_TO_BCD
21
#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
22
#endif
23
 
24
void sh_rtc_gettimeofday(struct timeval *tv)
25
{
26
        unsigned int sec128, sec, min, hr, wk, day, mon, yr, yr100, badval;
27
 
28
 again:
29
        do {
30
                ctrl_outb(0, RCR1);  /* Clear CF-bit */
31
                sec128 = ctrl_inb(R64CNT);
32
                sec = ctrl_inb(RSECCNT);
33
                min = ctrl_inb(RMINCNT);
34
                hr  = ctrl_inb(RHRCNT);
35
                wk  = ctrl_inb(RWKCNT);
36
                day = ctrl_inb(RDAYCNT);
37
                mon = ctrl_inb(RMONCNT);
38
#if defined(__SH4__)
39
                yr  = ctrl_inw(RYRCNT);
40
                yr100 = (yr >> 8);
41
                yr &= 0xff;
42
#else
43
                yr  = ctrl_inb(RYRCNT);
44
                yr100 = (yr == 0x99) ? 0x19 : 0x20;
45
#endif
46
        } while ((ctrl_inb(RCR1) & RCR1_CF) != 0);
47
 
48
#if RTC_BIT_INVERTED != 0
49
        /* Work around to avoid reading incorrect value. */
50
        if (sec128 == RTC_BIT_INVERTED) {
51
                schedule_timeout(1);
52
                goto again;
53
        }
54
#endif
55
 
56
        badval = ((yr & 15) > 9 || (mon & 15) > 9 || (day & 15) > 9 ||
57
                 (hr & 15) > 9 || (min & 15) > 9 || (sec & 15) > 9);
58
 
59
        if (!badval) {
60
                BCD_TO_BIN(yr100);
61
                BCD_TO_BIN(yr);
62
                BCD_TO_BIN(mon);
63
                BCD_TO_BIN(day);
64
                BCD_TO_BIN(hr);
65
                BCD_TO_BIN(min);
66
                BCD_TO_BIN(sec);
67
        }
68
 
69
        if (badval || yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
70
            hr > 23 || min > 59 || sec > 59 || (yr100 != 19 && yr100 != 20)) {
71
                printk(KERN_ERR
72
                       "SH RTC: invalid value, resetting to 1 Jan 2000\n");
73
                ctrl_outb(RCR2_RESET, RCR2);  /* Reset & Stop */
74
                ctrl_outb(0, RSECCNT);
75
                ctrl_outb(0, RMINCNT);
76
                ctrl_outb(0, RHRCNT);
77
                ctrl_outb(6, RWKCNT);
78
                ctrl_outb(1, RDAYCNT);
79
                ctrl_outb(1, RMONCNT);
80
#if defined(__SH4__)
81
                ctrl_outw(0x2000, RYRCNT);
82
#else
83
                ctrl_outb(0, RYRCNT);
84
#endif
85
                ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2);  /* Start */
86
                goto again;
87
        }
88
 
89
#if RTC_BIT_INVERTED != 0
90
        if ((sec128 & RTC_BIT_INVERTED))
91
                sec--;
92
#endif
93
 
94
        tv->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
95
        tv->tv_usec = (sec128 * 1000000) / 128;
96
}
97
 
98
int sh_rtc_settimeofday(const struct timeval *tv)
99
{
100
        unsigned long nowtime = tv->tv_sec;
101
        int retval = 0;
102
        int real_seconds, real_minutes, cmos_minutes;
103
 
104
        ctrl_outb(RCR2_RESET, RCR2);  /* Reset pre-scaler & stop RTC */
105
 
106
        cmos_minutes = ctrl_inb(RMINCNT);
107
        BCD_TO_BIN(cmos_minutes);
108
 
109
        /*
110
         * since we're only adjusting minutes and seconds,
111
         * don't interfere with hour overflow. This avoids
112
         * messing with unknown time zones but requires your
113
         * RTC not to be off by more than 15 minutes
114
         */
115
        real_seconds = nowtime % 60;
116
        real_minutes = nowtime / 60;
117
        if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
118
                real_minutes += 30;     /* correct for half hour time zone */
119
        real_minutes %= 60;
120
 
121
        if (abs(real_minutes - cmos_minutes) < 30) {
122
                BIN_TO_BCD(real_seconds);
123
                BIN_TO_BCD(real_minutes);
124
                ctrl_outb(real_seconds, RSECCNT);
125
                ctrl_outb(real_minutes, RMINCNT);
126
        } else {
127
                printk(KERN_WARNING
128
                       "set_rtc_time: can't update from %d to %d\n",
129
                       cmos_minutes, real_minutes);
130
                retval = -1;
131
        }
132
 
133
        ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2);  /* Start RTC */
134
 
135
        return retval;
136
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.