Merge with git://www.denx.de/git/u-boot.git
[platform/kernel/u-boot.git] / rtc / ds1302.c
1 /*
2  * ds1302.c - Support for the Dallas Semiconductor DS1302 Timekeeping Chip
3  *
4  * Rex G. Feany <rfeany@zumanetworks.com>
5  *
6  */
7
8 #include <common.h>
9 #include <command.h>
10 #include <rtc.h>
11
12 #if defined(CONFIG_RTC_DS1302) && (CONFIG_COMMANDS & CFG_CMD_DATE)
13
14 /* GPP Pins */
15 #define DATA            0x200
16 #define SCLK            0x400
17 #define RST             0x800
18
19 /* Happy Fun Defines(tm) */
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)
34 static 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 /* time data format for DS1302 */
45 struct ds1302_st
46 {
47         unsigned char CH:1;             /* clock halt 1=stop 0=start */
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;            /* 1=12 hour 0=24 hour */
56         unsigned char zero1:1;
57         unsigned char hr10:2;   /* 10 (0-2) or am/pm (am/pm, 0-1) */
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;            /* day of week */
70
71         unsigned char year10:4;
72         unsigned char year:4;
73
74         unsigned char WP:1;             /* write protect 1=protect 0=unprot */
75         unsigned char zero5:7;
76 };
77
78 static int ds1302_initted=0;
79
80 /* Pin control */
81 static inline void
82 rtc_go_high(unsigned int mask)
83 {
84         unsigned int f = GTREGREAD(GPP_VALUE) | mask;
85
86         GT_REG_WRITE(GPP_VALUE, f);
87 }
88
89 static inline void
90 rtc_go_low(unsigned int mask)
91 {
92         unsigned int f = GTREGREAD(GPP_VALUE) & ~mask;
93
94         GT_REG_WRITE(GPP_VALUE, f);
95 }
96
97 static inline void
98 rtc_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
105 static inline void
106 rtc_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 /* Access data in RTC */
114
115 static void
116 write_byte(unsigned char b)
117 {
118         int i;
119         unsigned char mask=1;
120
121         for(i=0;i<8;i++) {
122                 CLOCK_LOW;                      /* Lower clock */
123                 (b&mask)?DATA_HIGH:DATA_LOW;    /* set data */
124                 udelay(1);
125                 CLOCK_HIGH;             /* latch data with rising clock */
126                 udelay(1);
127                 mask=mask<<1;
128         }
129 }
130
131 static unsigned char
132 read_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; /* if this bit is high, set in b */
142                 CLOCK_HIGH;             /* clock out next bit */
143                 udelay(1);
144                 mask=mask<<1;
145         }
146         return b;
147 }
148
149 static void
150 read_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;        /* READ */
160         N_RESET;
161         udelay(4);
162         write_byte(addr);
163         rtc_go_input(DATA); /* Put gpp pin into input mode */
164         udelay(1);
165         for(i=0;i<count;i++) *(buf++)=read_byte();
166         RESET;
167         rtc_go_output(DATA);/* Reset gpp for output */
168         udelay(4);
169
170         DUMP(foo, count);
171 }
172
173 static void
174 write_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;       /* WRITE */
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
191 void
192 rtc_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         /* disable write protect */
203         b = 0;
204         write_ser_drv(0x8e,&b,1);
205
206         /* enable trickle */
207         b = 0xa5;       /* 1010.0101 */
208         write_ser_drv(0x90,&b,1);
209
210         /* read burst */
211         read_ser_drv(0xbe, (unsigned char *)&bbclk, 8);
212
213         /* Sanity checks */
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;    /* 2000 - why not? ;) */
230                 bbclk.year=0;
231                 mod=1;
232         }
233
234         /* Write out the changes if needed */
235         if (mod) {
236                 /* enable write protect */
237                 bbclk.WP = 1;
238                 write_ser_drv(0xbe,(unsigned char *)&bbclk,8);
239         } else {
240                 /* Else just turn write protect on */
241                 b = 0x80;
242                 write_ser_drv(0x8e,&b,1);
243         }
244         DPRINTF("init done\n");
245
246         ds1302_initted=1;
247 }
248
249 void
250 rtc_reset(void)
251 {
252         if(!ds1302_initted) rtc_init();
253         /* TODO */
254 }
255
256 void
257 rtc_get(struct rtc_time *tmp)
258 {
259         struct ds1302_st bbclk;
260
261         if(!ds1302_initted) rtc_init();
262
263         read_ser_drv(0xbe,(unsigned char *)&bbclk, 8);      /* read burst */
264
265         if (bbclk.CH) {
266                 printf("ds1302: rtc_get: Clock was halted, clock probably "
267                         "corrupt\n");
268         }
269
270         tmp->tm_sec=10*bbclk.sec10+bbclk.sec;
271         tmp->tm_min=10*bbclk.min10+bbclk.min;
272         tmp->tm_hour=10*bbclk.hr10+bbclk.hr;
273         tmp->tm_wday=bbclk.day;
274         tmp->tm_mday=10*bbclk.date10+bbclk.date;
275         tmp->tm_mon=10*bbclk.month10+bbclk.month;
276         tmp->tm_year=10*bbclk.year10+bbclk.year + 1900;
277
278         tmp->tm_yday = 0;
279         tmp->tm_isdst= 0;
280
281         DPRINTF("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
282                 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
283                 tmp->tm_hour, tmp->tm_min, tmp->tm_sec );
284 }
285
286 void
287 rtc_set(struct rtc_time *tmp)
288 {
289         struct ds1302_st bbclk;
290         unsigned char b=0;
291
292         if(!ds1302_initted) rtc_init();
293
294         DPRINTF("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
295                 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
296                 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
297
298         memset(&bbclk,0,sizeof(bbclk));
299         bbclk.CH=0; /* dont halt */
300         bbclk.WP=1; /* write protect when we're done */
301
302         bbclk.sec10=tmp->tm_sec/10;
303         bbclk.sec=tmp->tm_sec%10;
304
305         bbclk.min10=tmp->tm_min/10;
306         bbclk.min=tmp->tm_min%10;
307
308         bbclk.hr10=tmp->tm_hour/10;
309         bbclk.hr=tmp->tm_hour%10;
310
311         bbclk.day=tmp->tm_wday;
312
313         bbclk.date10=tmp->tm_mday/10;
314         bbclk.date=tmp->tm_mday%10;
315
316         bbclk.month10=tmp->tm_mon/10;
317         bbclk.month=tmp->tm_mon%10;
318
319         tmp->tm_year -= 1900;
320         bbclk.year10=tmp->tm_year/10;
321         bbclk.year=tmp->tm_year%10;
322
323         write_ser_drv(0x8e,&b,1);           /* disable write protect */
324         write_ser_drv(0xbe,(unsigned char *)&bbclk, 8);     /* write burst */
325 }
326
327 #endif