]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - rtc/rs5c372.c
Code Cleanup
[karo-tx-uboot.git] / rtc / rs5c372.c
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
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
76 rs5c372_readram(char *buf, int len)
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
98
99         /* note that this returns reg. 15 in buf[1] */
100         ret = rs5c372_readram(&buf[1], RS5C372_RAM_SIZE);
101         if (ret != 0) {
102                 printf("%s: failed\n", __FUNCTION__);
103                 return;
104         }
105
106         buf[0] = 0;
107         /* we want to start writing at register 0 so we have to copy the */
108         /* register contents up one slot */
109         for (ret = 2; ret < 9; ret++)
110                 buf[ret - 1] = buf[ret];
111         /* registers 0 to 6 (time values) are not touched */
112         buf[8] = RATE_32768HZ; /* reg. 7 */
113         buf[9] = 0; /* reg. 8 */
114         buf[10] = 0; /* reg. 9 */
115         buf[11] = 0; /* reg. 10 */
116         buf[12] = 0; /* reg. 11 */
117         buf[13] = 0; /* reg. 12 */
118         buf[14] = 0; /* reg. 13 */
119         buf[15] = 0; /* reg. 14 */
120         buf[16] = USE_24HOUR_MODE; /* reg. 15 */
121         ret = i2c_write(CFG_I2C_RTC_ADDR, 0, 0, buf, RS5C372_RAM_SIZE+1);
122         if (ret != 0) {
123                 printf("%s: failed\n", __FUNCTION__);
124                 return;
125         }
126         setup_done = 1;
127
128         return;
129 }
130
131 static void
132 rs5c372_convert_to_time(struct rtc_time *dt, char *buf)
133 {
134         /* buf[0] is register 15 */
135         dt->tm_sec = bcd2bin(buf[1]);
136         dt->tm_min = bcd2bin(buf[2]);
137
138         if (TWELVE_HOUR_MODE(buf[0])) {
139                 dt->tm_hour = HOURS_12(buf[3]);
140                 if (HOURS_AP(buf[3])) /* PM */
141                         dt->tm_hour += 12;
142         } else /* 24-hour-mode */
143                 dt->tm_hour = HOURS_24(buf[3]);
144
145         dt->tm_mday = bcd2bin(buf[5]);
146         dt->tm_mon = bcd2bin(buf[6]);
147         dt->tm_year = bcd2bin(buf[7]);
148         if (dt->tm_year >= 70)
149                 dt->tm_year += 1900;
150         else
151                 dt->tm_year += 2000;
152         /* 0 is Sunday */
153         dt->tm_wday = bcd2bin(buf[4] & 0x07);
154         dt->tm_yday = 0;
155         dt->tm_isdst= 0;
156
157         if(rtc_debug > 2) {
158                 printf("rs5c372_convert_to_time: year = %d\n", dt->tm_year);
159                 printf("rs5c372_convert_to_time: mon  = %d\n", dt->tm_mon);
160                 printf("rs5c372_convert_to_time: mday = %d\n", dt->tm_mday);
161                 printf("rs5c372_convert_to_time: hour = %d\n", dt->tm_hour);
162                 printf("rs5c372_convert_to_time: min  = %d\n", dt->tm_min);
163                 printf("rs5c372_convert_to_time: sec  = %d\n", dt->tm_sec);
164         }
165 }
166
167 /*
168  * Get the current time from the RTC
169  */
170 void
171 rtc_get (struct rtc_time *tmp)
172 {
173         unsigned char buf[RS5C372_RAM_SIZE];
174         int ret;
175
176         if (!setup_done)
177                 rs5c372_enable();
178
179         if (!setup_done)
180                 return;
181
182         memset(buf, 0, sizeof(buf));
183
184         /* note that this returns reg. 15 in buf[0] */
185         ret = rs5c372_readram(buf, RS5C372_RAM_SIZE);
186         if (ret != 0) {
187                 printf("%s: failed\n", __FUNCTION__);
188                 return;
189         }
190
191         rs5c372_convert_to_time(tmp, buf);
192
193         return;
194 }
195
196 /*
197  * Set the RTC
198  */
199 void
200 rtc_set (struct rtc_time *tmp)
201 {
202         unsigned char buf[8], reg15;
203         int ret;
204
205         if (!setup_done)
206                 rs5c372_enable();
207
208         if (!setup_done)
209                 return;
210
211         if(rtc_debug > 2) {
212                 printf("rtc_set: tm_year = %d\n", tmp->tm_year);
213                 printf("rtc_set: tm_mon  = %d\n", tmp->tm_mon);
214                 printf("rtc_set: tm_mday = %d\n", tmp->tm_mday);
215                 printf("rtc_set: tm_hour = %d\n", tmp->tm_hour);
216                 printf("rtc_set: tm_min  = %d\n", tmp->tm_min);
217                 printf("rtc_set: tm_sec  = %d\n", tmp->tm_sec);
218         }
219
220         memset(buf, 0, sizeof(buf));
221
222         /* only read register 15 */
223         ret = i2c_read(CFG_I2C_RTC_ADDR, 0, 0, buf, 1);
224
225         if (ret == 0) {
226                 /* need to save register 15 */
227                 reg15 = buf[0];
228                 buf[0] = 0;     /* register address on RS5C372 */
229                 buf[1] = bin2bcd(tmp->tm_sec);
230                 buf[2] = bin2bcd(tmp->tm_min);
231                 /* need to handle 12 hour mode */
232                 if (TWELVE_HOUR_MODE(reg15)) {
233                         if (tmp->tm_hour >= 12) { /* PM */
234                                 /* 12 PM is a special case */
235                                 if (tmp->tm_hour == 12)
236                                         buf[3] = bin2bcd(tmp->tm_hour);
237                                 else
238                                         buf[3] = bin2bcd(tmp->tm_hour - 12);
239                                 buf[3] |= 0x20;
240                         }
241                 } else {
242                         buf[3] = bin2bcd(tmp->tm_hour);
243                 }
244
245                 buf[4] = bin2bcd(tmp->tm_wday);
246                 buf[5] = bin2bcd(tmp->tm_mday);
247                 buf[6] = bin2bcd(tmp->tm_mon);
248                 if (tmp->tm_year < 1970 || tmp->tm_year > 2069)
249                         printf("WARNING: year should be between 1970 and 2069!\n");
250                 buf[7] = bin2bcd(tmp->tm_year % 100);
251
252                 ret = i2c_write(CFG_I2C_RTC_ADDR, 0, 0, buf, 8);
253                 if (ret != 0)
254                         printf("rs5c372_set_datetime(), i2c_master_send() returned %d\n",ret);
255         }
256
257         return;
258 }
259
260 /*
261  * Reset the RTC. We set the date back to 1970-01-01.
262  */
263 void
264 rtc_reset (void)
265 {
266         struct rtc_time tmp;
267
268         if (!setup_done)
269                 rs5c372_enable();
270
271         if (!setup_done)
272                 return;
273
274         tmp.tm_year = 1970;
275         tmp.tm_mon = 1;
276         /* Jan. 1, 1970 was a Thursday */
277         tmp.tm_wday= 4;
278         tmp.tm_mday= 1;
279         tmp.tm_hour = 0;
280         tmp.tm_min = 0;
281         tmp.tm_sec = 0;
282
283         rtc_set(&tmp);
284
285         printf ("RTC:   %4d-%02d-%02d %2d:%02d:%02d UTC\n",
286                 tmp.tm_year, tmp.tm_mon, tmp.tm_mday,
287                 tmp.tm_hour, tmp.tm_min, tmp.tm_sec);
288
289         return;
290 }
291
292 static unsigned int
293 bcd2bin (unsigned char n)
294 {
295         return ((((n >> 4) & 0x0F) * 10) + (n & 0x0F));
296 }
297
298 static unsigned char
299 bin2bcd (unsigned int n)
300 {
301         return (((n / 10) << 4) | (n % 10));
302 }
303 #endif /* defined(CONFIG_RTC_RS5C372A) && (CONFIG_COMMANDS & CFG_CMD_DATE) */