1
2
3
4
5
6
7
8#include <common.h>
9#include <command.h>
10#include <rtc.h>
11
12#if defined(CONFIG_CMD_DATE)
13
14
15#define DATA 0x200
16#define SCLK 0x400
17#define RST 0x800
18
19
20#define RESET rtc_go_low(RST), rtc_go_low(SCLK)
21#define N_RESET rtc_go_high(RST), rtc_go_low(SCLK)
22
23#define CLOCK_HIGH rtc_go_high(SCLK)
24#define CLOCK_LOW rtc_go_low(SCLK)
25
26#define DATA_HIGH rtc_go_high(DATA)
27#define DATA_LOW rtc_go_low(DATA)
28#define DATA_READ (GTREGREAD(GPP_VALUE) & DATA)
29
30#undef RTC_DEBUG
31
32#ifdef RTC_DEBUG
33# define DPRINTF(x,args...) printf("ds1302: " x , ##args)
34static inline void DUMP(const char *ptr, int num)
35{
36 while (num--) printf("%x ", *ptr++);
37 printf("]\n");
38}
39#else
40# define DPRINTF(x,args...)
41# define DUMP(ptr, num)
42#endif
43
44
45struct ds1302_st
46{
47 unsigned char CH:1;
48 unsigned char sec10:3;
49 unsigned char sec:4;
50
51 unsigned char zero0:1;
52 unsigned char min10:3;
53 unsigned char min:4;
54
55 unsigned char fmt:1;
56 unsigned char zero1:1;
57 unsigned char hr10:2;
58 unsigned char hr:4;
59
60 unsigned char zero2:2;
61 unsigned char date10:2;
62 unsigned char date:4;
63
64 unsigned char zero3:3;
65 unsigned char month10:1;
66 unsigned char month:4;
67
68 unsigned char zero4:5;
69 unsigned char day:3;
70
71 unsigned char year10:4;
72 unsigned char year:4;
73
74 unsigned char WP:1;
75 unsigned char zero5:7;
76};
77
78static int ds1302_initted=0;
79
80
81static inline void
82rtc_go_high(unsigned int mask)
83{
84 unsigned int f = GTREGREAD(GPP_VALUE) | mask;
85
86 GT_REG_WRITE(GPP_VALUE, f);
87}
88
89static inline void
90rtc_go_low(unsigned int mask)
91{
92 unsigned int f = GTREGREAD(GPP_VALUE) & ~mask;
93
94 GT_REG_WRITE(GPP_VALUE, f);
95}
96
97static inline void
98rtc_go_input(unsigned int mask)
99{
100 unsigned int f = GTREGREAD(GPP_IO_CONTROL) & ~mask;
101
102 GT_REG_WRITE(GPP_IO_CONTROL, f);
103}
104
105static inline void
106rtc_go_output(unsigned int mask)
107{
108 unsigned int f = GTREGREAD(GPP_IO_CONTROL) | mask;
109
110 GT_REG_WRITE(GPP_IO_CONTROL, f);
111}
112
113
114
115static void
116write_byte(unsigned char b)
117{
118 int i;
119 unsigned char mask=1;
120
121 for(i=0;i<8;i++) {
122 CLOCK_LOW;
123 (b&mask)?DATA_HIGH:DATA_LOW;
124 udelay(1);
125 CLOCK_HIGH;
126 udelay(1);
127 mask=mask<<1;
128 }
129}
130
131static unsigned char
132read_byte(void)
133{
134 int i;
135 unsigned char mask=1;
136 unsigned char b=0;
137
138 for(i=0;i<8;i++) {
139 CLOCK_LOW;
140 udelay(1);
141 if (DATA_READ) b|=mask;
142 CLOCK_HIGH;
143 udelay(1);
144 mask=mask<<1;
145 }
146 return b;
147}
148
149static void
150read_ser_drv(unsigned char addr, unsigned char *buf, int count)
151{
152 int i;
153#ifdef RTC_DEBUG
154 char *foo = buf;
155#endif
156
157 DPRINTF("READ 0x%x bytes @ 0x%x [ ", count, addr);
158
159 addr|=1;
160 N_RESET;
161 udelay(4);
162 write_byte(addr);
163 rtc_go_input(DATA);
164 udelay(1);
165 for(i=0;i<count;i++) *(buf++)=read_byte();
166 RESET;
167 rtc_go_output(DATA);
168 udelay(4);
169
170 DUMP(foo, count);
171}
172
173static void
174write_ser_drv(unsigned char addr, unsigned char *buf, int count)
175{
176 int i;
177
178 DPRINTF("WRITE 0x%x bytes @ 0x%x [ ", count, addr);
179 DUMP(buf, count);
180
181 addr&=~1;
182 N_RESET;
183 udelay(4);
184 write_byte(addr);
185 for(i=0;i<count;i++) write_byte(*(buf++));
186 RESET;
187 udelay(4);
188
189}
190
191void
192rtc_init(void)
193{
194 struct ds1302_st bbclk;
195 unsigned char b;
196 int mod;
197
198 DPRINTF("init\n");
199
200 rtc_go_output(DATA|SCLK|RST);
201
202
203 b = 0;
204 write_ser_drv(0x8e,&b,1);
205
206
207 b = 0xa5;
208 write_ser_drv(0x90,&b,1);
209
210
211 read_ser_drv(0xbe, (unsigned char *)&bbclk, 8);
212
213
214 mod = 0;
215 if (bbclk.CH) {
216 printf("ds1302: Clock was halted, starting clock\n");
217 bbclk.CH=0;
218 mod=1;
219 }
220
221 if (bbclk.fmt) {
222 printf("ds1302: Clock was in 12 hour mode, fixing\n");
223 bbclk.fmt=0;
224 mod=1;
225 }
226
227 if (bbclk.year>9) {
228 printf("ds1302: Year was corrupted, fixing\n");
229 bbclk.year10=100/10;
230 bbclk.year=0;
231 mod=1;
232 }
233
234
235 if (mod) {
236
237 bbclk.WP = 1;
238 write_ser_drv(0xbe,(unsigned char *)&bbclk,8);
239 } else {
240
241 b = 0x80;
242 write_ser_drv(0x8e,&b,1);
243 }
244 DPRINTF("init done\n");
245
246 ds1302_initted=1;
247}
248
249void
250rtc_reset(void)
251{
252 if(!ds1302_initted) rtc_init();
253
254}
255
256int
257rtc_get(struct rtc_time *tmp)
258{
259 int rel = 0;
260 struct ds1302_st bbclk;
261
262 if(!ds1302_initted) rtc_init();
263
264 read_ser_drv(0xbe,(unsigned char *)&bbclk, 8);
265
266 if (bbclk.CH) {
267 printf("ds1302: rtc_get: Clock was halted, clock probably "
268 "corrupt\n");
269 rel = -1;
270 }
271
272 tmp->tm_sec=10*bbclk.sec10+bbclk.sec;
273 tmp->tm_min=10*bbclk.min10+bbclk.min;
274 tmp->tm_hour=10*bbclk.hr10+bbclk.hr;
275 tmp->tm_wday=bbclk.day;
276 tmp->tm_mday=10*bbclk.date10+bbclk.date;
277 tmp->tm_mon=10*bbclk.month10+bbclk.month;
278 tmp->tm_year=10*bbclk.year10+bbclk.year + 1900;
279
280 tmp->tm_yday = 0;
281 tmp->tm_isdst= 0;
282
283 DPRINTF("Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
284 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
285 tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
286
287 return rel;
288}
289
290int rtc_set(struct rtc_time *tmp)
291{
292 struct ds1302_st bbclk;
293 unsigned char b=0;
294
295 if(!ds1302_initted) rtc_init();
296
297 DPRINTF("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n",
298 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
299 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
300
301 memset(&bbclk,0,sizeof(bbclk));
302 bbclk.CH=0;
303 bbclk.WP=1;
304
305 bbclk.sec10=tmp->tm_sec/10;
306 bbclk.sec=tmp->tm_sec%10;
307
308 bbclk.min10=tmp->tm_min/10;
309 bbclk.min=tmp->tm_min%10;
310
311 bbclk.hr10=tmp->tm_hour/10;
312 bbclk.hr=tmp->tm_hour%10;
313
314 bbclk.day=tmp->tm_wday;
315
316 bbclk.date10=tmp->tm_mday/10;
317 bbclk.date=tmp->tm_mday%10;
318
319 bbclk.month10=tmp->tm_mon/10;
320 bbclk.month=tmp->tm_mon%10;
321
322 tmp->tm_year -= 1900;
323 bbclk.year10=tmp->tm_year/10;
324 bbclk.year=tmp->tm_year%10;
325
326 write_ser_drv(0x8e,&b,1);
327 write_ser_drv(0xbe,(unsigned char *)&bbclk, 8);
328
329 return 0;
330}
331
332#endif
333