]>
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 garyj@denx.de | |
7 | * | |
8 | * Based in part in ds1307.c - | |
9 | * (C) Copyright 2001, 2002, 2003 | |
10 | * Wolfgang Denk, DENX Software Engineering, wd@denx.de. | |
11 | * Keith Outwater, keith_outwater@mvis.com` | |
12 | * Steven Scholz, steven.scholz@imc-berlin.de | |
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 | ||
871c18dd | 37 | #if defined(CONFIG_CMD_DATE) |
b6508513 WD |
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 | ||
6d0f6bcf JCPV |
53 | #ifndef CONFIG_SYS_I2C_RTC_ADDR |
54 | #define CONFIG_SYS_I2C_RTC_ADDR 0x32 | |
b6508513 WD |
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 | ||
b6508513 WD |
70 | static int setup_done = 0; |
71 | ||
72 | static int | |
d52fb7e3 | 73 | rs5c372_readram(unsigned char *buf, int len) |
b6508513 WD |
74 | { |
75 | int ret; | |
76 | ||
6d0f6bcf | 77 | ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, len); |
b6508513 WD |
78 | if (ret != 0) { |
79 | printf("%s: failed to read\n", __FUNCTION__); | |
80 | return ret; | |
81 | } | |
82 | ||
83 | if (buf[0] & STATUS_XPT) | |
84 | printf("### Warning: RTC lost power\n"); | |
85 | ||
86 | return ret; | |
87 | } | |
88 | ||
89 | static void | |
90 | rs5c372_enable(void) | |
91 | { | |
92 | unsigned char buf[RS5C372_RAM_SIZE + 1]; | |
93 | int ret; | |
94 | ||
b6508513 WD |
95 | /* note that this returns reg. 15 in buf[1] */ |
96 | ret = rs5c372_readram(&buf[1], RS5C372_RAM_SIZE); | |
97 | if (ret != 0) { | |
98 | printf("%s: failed\n", __FUNCTION__); | |
99 | return; | |
100 | } | |
101 | ||
102 | buf[0] = 0; | |
103 | /* we want to start writing at register 0 so we have to copy the */ | |
104 | /* register contents up one slot */ | |
105 | for (ret = 2; ret < 9; ret++) | |
106 | buf[ret - 1] = buf[ret]; | |
107 | /* registers 0 to 6 (time values) are not touched */ | |
108 | buf[8] = RATE_32768HZ; /* reg. 7 */ | |
109 | buf[9] = 0; /* reg. 8 */ | |
110 | buf[10] = 0; /* reg. 9 */ | |
111 | buf[11] = 0; /* reg. 10 */ | |
112 | buf[12] = 0; /* reg. 11 */ | |
113 | buf[13] = 0; /* reg. 12 */ | |
114 | buf[14] = 0; /* reg. 13 */ | |
115 | buf[15] = 0; /* reg. 14 */ | |
116 | buf[16] = USE_24HOUR_MODE; /* reg. 15 */ | |
6d0f6bcf | 117 | ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, RS5C372_RAM_SIZE+1); |
b6508513 WD |
118 | if (ret != 0) { |
119 | printf("%s: failed\n", __FUNCTION__); | |
120 | return; | |
121 | } | |
122 | setup_done = 1; | |
123 | ||
124 | return; | |
125 | } | |
126 | ||
127 | static void | |
d52fb7e3 | 128 | rs5c372_convert_to_time(struct rtc_time *dt, unsigned char *buf) |
b6508513 WD |
129 | { |
130 | /* buf[0] is register 15 */ | |
131 | dt->tm_sec = bcd2bin(buf[1]); | |
132 | dt->tm_min = bcd2bin(buf[2]); | |
133 | ||
134 | if (TWELVE_HOUR_MODE(buf[0])) { | |
135 | dt->tm_hour = HOURS_12(buf[3]); | |
136 | if (HOURS_AP(buf[3])) /* PM */ | |
137 | dt->tm_hour += 12; | |
138 | } else /* 24-hour-mode */ | |
139 | dt->tm_hour = HOURS_24(buf[3]); | |
140 | ||
141 | dt->tm_mday = bcd2bin(buf[5]); | |
142 | dt->tm_mon = bcd2bin(buf[6]); | |
143 | dt->tm_year = bcd2bin(buf[7]); | |
144 | if (dt->tm_year >= 70) | |
145 | dt->tm_year += 1900; | |
146 | else | |
147 | dt->tm_year += 2000; | |
148 | /* 0 is Sunday */ | |
149 | dt->tm_wday = bcd2bin(buf[4] & 0x07); | |
150 | dt->tm_yday = 0; | |
151 | dt->tm_isdst= 0; | |
152 | ||
153 | if(rtc_debug > 2) { | |
154 | printf("rs5c372_convert_to_time: year = %d\n", dt->tm_year); | |
155 | printf("rs5c372_convert_to_time: mon = %d\n", dt->tm_mon); | |
156 | printf("rs5c372_convert_to_time: mday = %d\n", dt->tm_mday); | |
157 | printf("rs5c372_convert_to_time: hour = %d\n", dt->tm_hour); | |
158 | printf("rs5c372_convert_to_time: min = %d\n", dt->tm_min); | |
159 | printf("rs5c372_convert_to_time: sec = %d\n", dt->tm_sec); | |
160 | } | |
161 | } | |
162 | ||
163 | /* | |
164 | * Get the current time from the RTC | |
165 | */ | |
b73a19e1 | 166 | int |
b6508513 WD |
167 | rtc_get (struct rtc_time *tmp) |
168 | { | |
169 | unsigned char buf[RS5C372_RAM_SIZE]; | |
170 | int ret; | |
171 | ||
172 | if (!setup_done) | |
173 | rs5c372_enable(); | |
174 | ||
175 | if (!setup_done) | |
b73a19e1 | 176 | return -1; |
b6508513 WD |
177 | |
178 | memset(buf, 0, sizeof(buf)); | |
179 | ||
180 | /* note that this returns reg. 15 in buf[0] */ | |
181 | ret = rs5c372_readram(buf, RS5C372_RAM_SIZE); | |
182 | if (ret != 0) { | |
183 | printf("%s: failed\n", __FUNCTION__); | |
b73a19e1 | 184 | return -1; |
b6508513 WD |
185 | } |
186 | ||
187 | rs5c372_convert_to_time(tmp, buf); | |
188 | ||
b73a19e1 | 189 | return 0; |
b6508513 WD |
190 | } |
191 | ||
192 | /* | |
193 | * Set the RTC | |
194 | */ | |
13b4db0e | 195 | int rtc_set (struct rtc_time *tmp) |
b6508513 WD |
196 | { |
197 | unsigned char buf[8], reg15; | |
198 | int ret; | |
199 | ||
200 | if (!setup_done) | |
201 | rs5c372_enable(); | |
202 | ||
203 | if (!setup_done) | |
d1e23194 | 204 | return -1; |
b6508513 WD |
205 | |
206 | if(rtc_debug > 2) { | |
207 | printf("rtc_set: tm_year = %d\n", tmp->tm_year); | |
208 | printf("rtc_set: tm_mon = %d\n", tmp->tm_mon); | |
209 | printf("rtc_set: tm_mday = %d\n", tmp->tm_mday); | |
210 | printf("rtc_set: tm_hour = %d\n", tmp->tm_hour); | |
211 | printf("rtc_set: tm_min = %d\n", tmp->tm_min); | |
212 | printf("rtc_set: tm_sec = %d\n", tmp->tm_sec); | |
213 | } | |
214 | ||
215 | memset(buf, 0, sizeof(buf)); | |
216 | ||
217 | /* only read register 15 */ | |
6d0f6bcf | 218 | ret = i2c_read(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 1); |
b6508513 WD |
219 | |
220 | if (ret == 0) { | |
221 | /* need to save register 15 */ | |
222 | reg15 = buf[0]; | |
223 | buf[0] = 0; /* register address on RS5C372 */ | |
224 | buf[1] = bin2bcd(tmp->tm_sec); | |
225 | buf[2] = bin2bcd(tmp->tm_min); | |
226 | /* need to handle 12 hour mode */ | |
227 | if (TWELVE_HOUR_MODE(reg15)) { | |
228 | if (tmp->tm_hour >= 12) { /* PM */ | |
229 | /* 12 PM is a special case */ | |
230 | if (tmp->tm_hour == 12) | |
231 | buf[3] = bin2bcd(tmp->tm_hour); | |
232 | else | |
233 | buf[3] = bin2bcd(tmp->tm_hour - 12); | |
234 | buf[3] |= 0x20; | |
235 | } | |
236 | } else { | |
237 | buf[3] = bin2bcd(tmp->tm_hour); | |
238 | } | |
239 | ||
240 | buf[4] = bin2bcd(tmp->tm_wday); | |
241 | buf[5] = bin2bcd(tmp->tm_mday); | |
242 | buf[6] = bin2bcd(tmp->tm_mon); | |
243 | if (tmp->tm_year < 1970 || tmp->tm_year > 2069) | |
244 | printf("WARNING: year should be between 1970 and 2069!\n"); | |
245 | buf[7] = bin2bcd(tmp->tm_year % 100); | |
246 | ||
6d0f6bcf | 247 | ret = i2c_write(CONFIG_SYS_I2C_RTC_ADDR, 0, 0, buf, 8); |
d1e23194 | 248 | if (ret != 0) { |
b6508513 | 249 | printf("rs5c372_set_datetime(), i2c_master_send() returned %d\n",ret); |
d1e23194 JCPV |
250 | return -1; |
251 | } | |
252 | } else { | |
253 | return -1; | |
b6508513 WD |
254 | } |
255 | ||
d1e23194 | 256 | return 0; |
b6508513 WD |
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 | ||
a593814f | 291 | #endif |