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