diff options
Diffstat (limited to 'arch/mips/sibyte/swarm/rtc_xicor1241.c')
-rw-r--r-- | arch/mips/sibyte/swarm/rtc_xicor1241.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/arch/mips/sibyte/swarm/rtc_xicor1241.c b/arch/mips/sibyte/swarm/rtc_xicor1241.c new file mode 100644 index 00000000000..981d21f16e6 --- /dev/null +++ b/arch/mips/sibyte/swarm/rtc_xicor1241.c | |||
@@ -0,0 +1,203 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2000, 2001 Broadcom Corporation | ||
3 | * | ||
4 | * Copyright (C) 2002 MontaVista Software Inc. | ||
5 | * Author: jsun@mvista.com or jsun@junsun.net | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | #include <linux/bcd.h> | ||
13 | #include <linux/types.h> | ||
14 | #include <linux/time.h> | ||
15 | |||
16 | #include <asm/time.h> | ||
17 | #include <asm/addrspace.h> | ||
18 | #include <asm/io.h> | ||
19 | |||
20 | #include <asm/sibyte/sb1250.h> | ||
21 | #include <asm/sibyte/sb1250_regs.h> | ||
22 | #include <asm/sibyte/sb1250_smbus.h> | ||
23 | |||
24 | |||
25 | /* Xicor 1241 definitions */ | ||
26 | |||
27 | /* | ||
28 | * Register bits | ||
29 | */ | ||
30 | |||
31 | #define X1241REG_SR_BAT 0x80 /* currently on battery power */ | ||
32 | #define X1241REG_SR_RWEL 0x04 /* r/w latch is enabled, can write RTC */ | ||
33 | #define X1241REG_SR_WEL 0x02 /* r/w latch is unlocked, can enable r/w now */ | ||
34 | #define X1241REG_SR_RTCF 0x01 /* clock failed */ | ||
35 | #define X1241REG_BL_BP2 0x80 /* block protect 2 */ | ||
36 | #define X1241REG_BL_BP1 0x40 /* block protect 1 */ | ||
37 | #define X1241REG_BL_BP0 0x20 /* block protect 0 */ | ||
38 | #define X1241REG_BL_WD1 0x10 | ||
39 | #define X1241REG_BL_WD0 0x08 | ||
40 | #define X1241REG_HR_MIL 0x80 /* military time format */ | ||
41 | |||
42 | /* | ||
43 | * Register numbers | ||
44 | */ | ||
45 | |||
46 | #define X1241REG_BL 0x10 /* block protect bits */ | ||
47 | #define X1241REG_INT 0x11 /* */ | ||
48 | #define X1241REG_SC 0x30 /* Seconds */ | ||
49 | #define X1241REG_MN 0x31 /* Minutes */ | ||
50 | #define X1241REG_HR 0x32 /* Hours */ | ||
51 | #define X1241REG_DT 0x33 /* Day of month */ | ||
52 | #define X1241REG_MO 0x34 /* Month */ | ||
53 | #define X1241REG_YR 0x35 /* Year */ | ||
54 | #define X1241REG_DW 0x36 /* Day of Week */ | ||
55 | #define X1241REG_Y2K 0x37 /* Year 2K */ | ||
56 | #define X1241REG_SR 0x3F /* Status register */ | ||
57 | |||
58 | #define X1241_CCR_ADDRESS 0x6F | ||
59 | |||
60 | #define SMB_CSR(reg) ((u8 *) (IOADDR(A_SMB_REGISTER(1, reg)))) | ||
61 | |||
62 | static int xicor_read(uint8_t addr) | ||
63 | { | ||
64 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
65 | ; | ||
66 | |||
67 | bus_writeq((addr >> 8) & 0x7, SMB_CSR(R_SMB_CMD)); | ||
68 | bus_writeq((addr & 0xff), SMB_CSR(R_SMB_DATA)); | ||
69 | bus_writeq((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR2BYTE), | ||
70 | SMB_CSR(R_SMB_START)); | ||
71 | |||
72 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
73 | ; | ||
74 | |||
75 | bus_writeq((V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_RD1BYTE), | ||
76 | SMB_CSR(R_SMB_START)); | ||
77 | |||
78 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
79 | ; | ||
80 | |||
81 | if (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { | ||
82 | /* Clear error bit by writing a 1 */ | ||
83 | bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); | ||
84 | return -1; | ||
85 | } | ||
86 | |||
87 | return (bus_readq(SMB_CSR(R_SMB_DATA)) & 0xff); | ||
88 | } | ||
89 | |||
90 | static int xicor_write(uint8_t addr, int b) | ||
91 | { | ||
92 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
93 | ; | ||
94 | |||
95 | bus_writeq(addr, SMB_CSR(R_SMB_CMD)); | ||
96 | bus_writeq((addr & 0xff) | ((b & 0xff) << 8), SMB_CSR(R_SMB_DATA)); | ||
97 | bus_writeq(V_SMB_ADDR(X1241_CCR_ADDRESS) | V_SMB_TT_WR3BYTE, | ||
98 | SMB_CSR(R_SMB_START)); | ||
99 | |||
100 | while (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_BUSY) | ||
101 | ; | ||
102 | |||
103 | if (bus_readq(SMB_CSR(R_SMB_STATUS)) & M_SMB_ERROR) { | ||
104 | /* Clear error bit by writing a 1 */ | ||
105 | bus_writeq(M_SMB_ERROR, SMB_CSR(R_SMB_STATUS)); | ||
106 | return -1; | ||
107 | } else { | ||
108 | return 0; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | int xicor_set_time(unsigned long t) | ||
113 | { | ||
114 | struct rtc_time tm; | ||
115 | int tmp; | ||
116 | |||
117 | to_tm(t, &tm); | ||
118 | |||
119 | /* unlock writes to the CCR */ | ||
120 | xicor_write(X1241REG_SR, X1241REG_SR_WEL); | ||
121 | xicor_write(X1241REG_SR, X1241REG_SR_WEL | X1241REG_SR_RWEL); | ||
122 | |||
123 | /* trivial ones */ | ||
124 | tm.tm_sec = BIN2BCD(tm.tm_sec); | ||
125 | xicor_write(X1241REG_SC, tm.tm_sec); | ||
126 | |||
127 | tm.tm_min = BIN2BCD(tm.tm_min); | ||
128 | xicor_write(X1241REG_MN, tm.tm_min); | ||
129 | |||
130 | tm.tm_mday = BIN2BCD(tm.tm_mday); | ||
131 | xicor_write(X1241REG_DT, tm.tm_mday); | ||
132 | |||
133 | /* tm_mon starts from 0, *ick* */ | ||
134 | tm.tm_mon ++; | ||
135 | tm.tm_mon = BIN2BCD(tm.tm_mon); | ||
136 | xicor_write(X1241REG_MO, tm.tm_mon); | ||
137 | |||
138 | /* year is split */ | ||
139 | tmp = tm.tm_year / 100; | ||
140 | tm.tm_year %= 100; | ||
141 | xicor_write(X1241REG_YR, tm.tm_year); | ||
142 | xicor_write(X1241REG_Y2K, tmp); | ||
143 | |||
144 | /* hour is the most tricky one */ | ||
145 | tmp = xicor_read(X1241REG_HR); | ||
146 | if (tmp & X1241REG_HR_MIL) { | ||
147 | /* 24 hour format */ | ||
148 | tm.tm_hour = BIN2BCD(tm.tm_hour); | ||
149 | tmp = (tmp & ~0x3f) | (tm.tm_hour & 0x3f); | ||
150 | } else { | ||
151 | /* 12 hour format, with 0x2 for pm */ | ||
152 | tmp = tmp & ~0x3f; | ||
153 | if (tm.tm_hour >= 12) { | ||
154 | tmp |= 0x20; | ||
155 | tm.tm_hour -= 12; | ||
156 | } | ||
157 | tm.tm_hour = BIN2BCD(tm.tm_hour); | ||
158 | tmp |= tm.tm_hour; | ||
159 | } | ||
160 | xicor_write(X1241REG_HR, tmp); | ||
161 | |||
162 | xicor_write(X1241REG_SR, 0); | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | unsigned long xicor_get_time(void) | ||
168 | { | ||
169 | unsigned int year, mon, day, hour, min, sec, y2k; | ||
170 | |||
171 | sec = xicor_read(X1241REG_SC); | ||
172 | min = xicor_read(X1241REG_MN); | ||
173 | hour = xicor_read(X1241REG_HR); | ||
174 | |||
175 | if (hour & X1241REG_HR_MIL) { | ||
176 | hour &= 0x3f; | ||
177 | } else { | ||
178 | if (hour & 0x20) | ||
179 | hour = (hour & 0xf) + 0x12; | ||
180 | } | ||
181 | |||
182 | day = xicor_read(X1241REG_DT); | ||
183 | mon = xicor_read(X1241REG_MO); | ||
184 | year = xicor_read(X1241REG_YR); | ||
185 | y2k = xicor_read(X1241REG_Y2K); | ||
186 | |||
187 | sec = BCD2BIN(sec); | ||
188 | min = BCD2BIN(min); | ||
189 | hour = BCD2BIN(hour); | ||
190 | day = BCD2BIN(day); | ||
191 | mon = BCD2BIN(mon); | ||
192 | year = BCD2BIN(year); | ||
193 | y2k = BCD2BIN(y2k); | ||
194 | |||
195 | year += (y2k * 100); | ||
196 | |||
197 | return mktime(year, mon, day, hour, min, sec); | ||
198 | } | ||
199 | |||
200 | int xicor_probe(void) | ||
201 | { | ||
202 | return (xicor_read(X1241REG_SC) != -1); | ||
203 | } | ||