]>
Commit | Line | Data |
---|---|---|
b6508513 WD |
1 | /* |
2 | * rs5c372.c | |
3 | * | |
4 | * Device driver for Ricoh's Real Time Controller RS5C372A. | |
5 | * | |
6 | * Copyright (C) 2004 Gary Jennejohn [email protected] | |
7 | * | |
8 | * Based in part in ds1307.c - | |
9 | * (C) Copyright 2001, 2002, 2003 | |
10 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
11 | * Keith Outwater, [email protected]` | |
12 | * Steven Scholz, [email protected] | |
13 | * | |
14 | * See file CREDITS for list of people who contributed to this | |
15 | * project. | |
16 | * | |
17 | * This program is free software; you can redistribute it and/or modify | |
18 | * it under the terms of the GNU General Public License version 2 as | |
19 | * published by the Free Software Foundation. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |
29 | * MA 02111-1307 USA | |
30 | */ | |
31 | ||
32 | #include <common.h> | |
33 | #include <command.h> | |
34 | #include <rtc.h> | |
35 | #include <i2c.h> | |
36 | ||
37 | #if defined(CONFIG_RTC_RS5C372A) && (CONFIG_COMMANDS & CFG_CMD_DATE) | |
38 | /* | |
39 | * Reads are always done starting with register 15, which requires some | |
40 | * jumping-through-hoops to access the data correctly. | |
41 | * | |
42 | * Writes are always done starting with register 0. | |
43 | */ | |
44 | ||
45 | #define DEBUG 0 | |
46 | ||
47 | #if DEBUG | |
48 | static unsigned int rtc_debug = DEBUG; | |
49 | #else | |
50 | #define rtc_debug 0 /* gcc will remove all the debug code for us */ | |
51 | #endif | |
52 | ||
53 | #ifndef CFG_I2C_RTC_ADDR | |
54 | #define CFG_I2C_RTC_ADDR 0x32 | |
55 | #endif | |
56 | ||
57 | #define RS5C372_RAM_SIZE 0x10 | |
58 | #define RATE_32000HZ 0x80 /* Rate Select 32.000KHz */ | |
59 | #define RATE_32768HZ 0x00 /* Rate Select 32.768KHz */ | |
60 | ||
61 | #define STATUS_XPT 0x10 /* data invalid because voltage was 0 */ | |
62 | ||
63 | #define USE_24HOUR_MODE 0x20 | |
64 | #define TWELVE_HOUR_MODE(n) ((((n) >> 5) & 1) == 0) | |
65 | #define HOURS_AP(n) (((n) >> 5) & 1) | |
66 | #define HOURS_12(n) bcd2bin((n) & 0x1F) | |
67 | #define HOURS_24(n) bcd2bin((n) & 0x3F) | |
68 | ||
69 | ||
70 | static uchar bin2bcd (unsigned int n); | |
71 | static unsigned bcd2bin (uchar c); | |
72 | ||
73 | static int setup_done = 0; | |
74 | ||
75 | static int | |
d52fb7e3 | 76 | rs5c372_readram(unsigned char *buf, int len) |
b6508513 WD |
77 | { |
78 | int ret; | |
79 | ||
80 | ret = i2c_read(CFG_I2C_RTC_ADDR, 0, 0, buf, len); | |
81 | if (ret != 0) { | |
82 | printf("%s: failed to read\n", __FUNCTION__); | |
83 | return ret; | |
84 | } | |
85 | ||
86 | if (buf[0] & STATUS_XPT) | |
87 | printf("### Warning: RTC lost power\n"); | |
88 | ||
89 | return ret; | |
90 | } | |
91 | ||
92 | static void | |
93 | rs5c372_enable(void) | |
94 | { | |
95 | unsigned char buf[RS5C372_RAM_SIZE + 1]; | |
96 | int ret; | |
97 | ||
b6508513 WD |
98 | /* note that this returns reg. 15 in buf[1] */ |
99 | ret = rs5c372_readram(&buf[1], RS5C372_RAM_SIZE); | |
100 | if (ret != 0) { | |
101 | printf("%s: failed\n", __FUNCTION__); | |
102 | return; | |
103 | } | |
104 | ||
105 | buf[0] = 0; | |
106 | /* we want to start writing at register 0 so we have to copy the */ | |
107 | /* register contents up one slot */ | |
108 | for (ret = 2; ret < 9; ret++) | |
109 | buf[ret - 1] = buf[ret]; | |
110 | /* registers 0 to 6 (time values) are not touched */ | |
111 | buf[8] = RATE_32768HZ; /* reg. 7 */ | |
112 | buf[9] = 0; /* reg. 8 */ | |
113 | buf[10] = 0; /* reg. 9 */ | |
114 | buf[11] = 0; /* reg. 10 */ | |
115 | buf[12] = 0; /* reg. 11 */ | |
116 | buf[13] = 0; /* reg. 12 */ | |
117 | buf[14] = 0; /* reg. 13 */ | |
118 | buf[15] = 0; /* reg. 14 */ | |
119 | buf[16] = USE_24HOUR_MODE; /* reg. 15 */ | |
120 | ret = i2c_write(CFG_I2C_RTC_ADDR, 0, 0, buf, RS5C372_RAM_SIZE+1); | |
121 | if (ret != 0) { | |
122 | printf("%s: failed\n", __FUNCTION__); | |
123 | return; | |
124 | } | |
125 | setup_done = 1; | |
126 | ||
127 | return; | |
128 | } | |
129 | ||
130 | static void | |
d52fb7e3 | 131 | rs5c372_convert_to_time(struct rtc_time *dt, unsigned char *buf) |
b6508513 WD |
132 | { |
133 | /* buf[0] is register 15 */ | |
134 | dt->tm_sec = bcd2bin(buf[1]); | |
135 | dt->tm_min = bcd2bin(buf[2]); | |
136 | ||
137 | if (TWELVE_HOUR_MODE(buf[0])) { | |
138 | dt->tm_hour = HOURS_12(buf[3]); | |
139 | if (HOURS_AP(buf[3])) /* PM */ | |
140 | dt->tm_hour += 12; | |
141 | } else /* 24-hour-mode */ | |
142 | dt->tm_hour = HOURS_24(buf[3]); | |
143 | ||
144 | dt->tm_mday = bcd2bin(buf[5]); | |
145 | dt->tm_mon = bcd2bin(buf[6]); | |
146 | dt->tm_year = bcd2bin(buf[7]); | |
147 | if (dt->tm_year >= 70) | |
148 | dt->tm_year += 1900; | |
149 | else | |
150 | dt->tm_year += 2000; | |
151 | /* 0 is Sunday */ | |
152 | dt->tm_wday = bcd2bin(buf[4] & 0x07); | |
153 | dt->tm_yday = 0; | |
154 | dt->tm_isdst= 0; | |
155 | ||
156 | if(rtc_debug > 2) { | |
157 | printf("rs5c372_convert_to_time: year = %d\n", dt->tm_year); | |
158 | printf("rs5c372_convert_to_time: mon = %d\n", dt->tm_mon); | |
159 | printf("rs5c372_convert_to_time: mday = %d\n", dt->tm_mday); | |
160 | printf("rs5c372_convert_to_time: hour = %d\n", dt->tm_hour); | |
161 | printf("rs5c372_convert_to_time: min = %d\n", dt->tm_min); | |
162 | printf("rs5c372_convert_to_time: sec = %d\n", dt->tm_sec); | |
163 | } | |
164 | } | |
165 | ||
166 | /* | |
167 | * Get the current time from the RTC | |
168 | */ | |
169 | void | |
170 | rtc_get (struct rtc_time *tmp) | |
171 | { | |
172 | unsigned char buf[RS5C372_RAM_SIZE]; | |
173 | int ret; | |
174 | ||
175 | if (!setup_done) | |
176 | rs5c372_enable(); | |
177 | ||
178 | if (!setup_done) | |
179 | return; | |
180 | ||
181 | memset(buf, 0, sizeof(buf)); | |
182 | ||
183 | /* note that this returns reg. 15 in buf[0] */ | |
184 | ret = rs5c372_readram(buf, RS5C372_RAM_SIZE); | |
185 | if (ret != 0) { | |
186 | printf("%s: failed\n", __FUNCTION__); | |
187 | return; | |
188 | } | |
189 | ||
190 | rs5c372_convert_to_time(tmp, buf); | |
191 | ||
192 | return; | |
193 | } | |
194 | ||
195 | /* | |
196 | * Set the RTC | |
197 | */ | |
198 | void | |
199 | rtc_set (struct rtc_time *tmp) | |
200 | { | |
201 | unsigned char buf[8], reg15; | |
202 | int ret; | |
203 | ||
204 | if (!setup_done) | |
205 | rs5c372_enable(); | |
206 | ||
207 | if (!setup_done) | |
208 | return; | |
209 | ||
210 | if(rtc_debug > 2) { | |
211 | printf("rtc_set: tm_year = %d\n", tmp->tm_year); | |
212 | printf("rtc_set: tm_mon = %d\n", tmp->tm_mon); | |
213 | printf("rtc_set: tm_mday = %d\n", tmp->tm_mday); | |
214 | printf("rtc_set: tm_hour = %d\n", tmp->tm_hour); | |
215 | printf("rtc_set: tm_min = %d\n", tmp->tm_min); | |
216 | printf("rtc_set: tm_sec = %d\n", tmp->tm_sec); | |
217 | } | |
218 | ||
219 | memset(buf, 0, sizeof(buf)); | |
220 | ||
221 | /* only read register 15 */ | |
222 | ret = i2c_read(CFG_I2C_RTC_ADDR, 0, 0, buf, 1); | |
223 | ||
224 | if (ret == 0) { | |
225 | /* need to save register 15 */ | |
226 | reg15 = buf[0]; | |
227 | buf[0] = 0; /* register address on RS5C372 */ | |
228 | buf[1] = bin2bcd(tmp->tm_sec); | |
229 | buf[2] = bin2bcd(tmp->tm_min); | |
230 | /* need to handle 12 hour mode */ | |
231 | if (TWELVE_HOUR_MODE(reg15)) { | |
232 | if (tmp->tm_hour >= 12) { /* PM */ | |
233 | /* 12 PM is a special case */ | |
234 | if (tmp->tm_hour == 12) | |
235 | buf[3] = bin2bcd(tmp->tm_hour); | |
236 | else | |
237 | buf[3] = bin2bcd(tmp->tm_hour - 12); | |
238 | buf[3] |= 0x20; | |
239 | } | |
240 | } else { | |
241 | buf[3] = bin2bcd(tmp->tm_hour); | |
242 | } | |
243 | ||
244 | buf[4] = bin2bcd(tmp->tm_wday); | |
245 | buf[5] = bin2bcd(tmp->tm_mday); | |
246 | buf[6] = bin2bcd(tmp->tm_mon); | |
247 | if (tmp->tm_year < 1970 || tmp->tm_year > 2069) | |
248 | printf("WARNING: year should be between 1970 and 2069!\n"); | |
249 | buf[7] = bin2bcd(tmp->tm_year % 100); | |
250 | ||
251 | ret = i2c_write(CFG_I2C_RTC_ADDR, 0, 0, buf, 8); | |
252 | if (ret != 0) | |
253 | printf("rs5c372_set_datetime(), i2c_master_send() returned %d\n",ret); | |
254 | } | |
255 | ||
256 | return; | |
257 | } | |
258 | ||
259 | /* | |
260 | * Reset the RTC. We set the date back to 1970-01-01. | |
261 | */ | |
262 | void | |
263 | rtc_reset (void) | |
264 | { | |
265 | struct rtc_time tmp; | |
266 | ||
267 | if (!setup_done) | |
268 | rs5c372_enable(); | |
269 | ||
270 | if (!setup_done) | |
271 | return; | |
272 | ||
273 | tmp.tm_year = 1970; | |
274 | tmp.tm_mon = 1; | |
275 | /* Jan. 1, 1970 was a Thursday */ | |
276 | tmp.tm_wday= 4; | |
277 | tmp.tm_mday= 1; | |
278 | tmp.tm_hour = 0; | |
279 | tmp.tm_min = 0; | |
280 | tmp.tm_sec = 0; | |
281 | ||
282 | rtc_set(&tmp); | |
283 | ||
284 | printf ("RTC: %4d-%02d-%02d %2d:%02d:%02d UTC\n", | |
285 | tmp.tm_year, tmp.tm_mon, tmp.tm_mday, | |
286 | tmp.tm_hour, tmp.tm_min, tmp.tm_sec); | |
287 | ||
288 | return; | |
289 | } | |
290 | ||
291 | static unsigned int | |
292 | bcd2bin (unsigned char n) | |
293 | { | |
294 | return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F)); | |
295 | } | |
296 | ||
297 | static unsigned char | |
298 | bin2bcd (unsigned int n) | |
299 | { | |
300 | return (((n / 10) << 4) | (n % 10)); | |
301 | } | |
302 | #endif /* defined(CONFIG_RTC_RS5C372A) && (CONFIG_COMMANDS & CFG_CMD_DATE) */ |