to make u-boot work for fat32 filesystem
[jz_uboot.git] / rtc / ds1302.c
blob98dce899a97f7998b11f58e8c7897ba9f7e0b95a
1 /*
2 * ds1302.c - Support for the Dallas Semiconductor DS1302 Timekeeping Chip
4 * Rex G. Feany <rfeany@zumanetworks.com>
6 */
8 #include <common.h>
9 #include <command.h>
10 #include <rtc.h>
12 #if defined(CONFIG_RTC_DS1302) && (CONFIG_COMMANDS & CFG_CMD_DATE)
14 /* GPP Pins */
15 #define DATA 0x200
16 #define SCLK 0x400
17 #define RST 0x800
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)
23 #define CLOCK_HIGH rtc_go_high(SCLK)
24 #define CLOCK_LOW rtc_go_low(SCLK)
26 #define DATA_HIGH rtc_go_high(DATA)
27 #define DATA_LOW rtc_go_low(DATA)
28 #define DATA_READ (GTREGREAD(GPP_VALUE) & DATA)
30 #undef RTC_DEBUG
32 #ifdef RTC_DEBUG
33 # define DPRINTF(x,args...) printf("ds1302: " x , ##args)
34 static inline void DUMP(const char *ptr, int num)
36 while (num--) printf("%x ", *ptr++);
37 printf("]\n");
39 #else
40 # define DPRINTF(x,args...)
41 # define DUMP(ptr, num)
42 #endif
44 /* time data format for DS1302 */
45 struct ds1302_st
47 unsigned char CH:1; /* clock halt 1=stop 0=start */
48 unsigned char sec10:3;
49 unsigned char sec:4;
51 unsigned char zero0:1;
52 unsigned char min10:3;
53 unsigned char min:4;
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;
60 unsigned char zero2:2;
61 unsigned char date10:2;
62 unsigned char date:4;
64 unsigned char zero3:3;
65 unsigned char month10:1;
66 unsigned char month:4;
68 unsigned char zero4:5;
69 unsigned char day:3; /* day of week */
71 unsigned char year10:4;
72 unsigned char year:4;
74 unsigned char WP:1; /* write protect 1=protect 0=unprot */
75 unsigned char zero5:7;
78 static int ds1302_initted=0;
80 /* Pin control */
81 static inline void
82 rtc_go_high(unsigned int mask)
84 unsigned int f = GTREGREAD(GPP_VALUE) | mask;
86 GT_REG_WRITE(GPP_VALUE, f);
89 static inline void
90 rtc_go_low(unsigned int mask)
92 unsigned int f = GTREGREAD(GPP_VALUE) & ~mask;
94 GT_REG_WRITE(GPP_VALUE, f);
97 static inline void
98 rtc_go_input(unsigned int mask)
100 unsigned int f = GTREGREAD(GPP_IO_CONTROL) & ~mask;
102 GT_REG_WRITE(GPP_IO_CONTROL, f);
105 static inline void
106 rtc_go_output(unsigned int mask)
108 unsigned int f = GTREGREAD(GPP_IO_CONTROL) | mask;
110 GT_REG_WRITE(GPP_IO_CONTROL, f);
113 /* Access data in RTC */
115 static void
116 write_byte(unsigned char b)
118 int i;
119 unsigned char mask=1;
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;
131 static unsigned char
132 read_byte(void)
134 int i;
135 unsigned char mask=1;
136 unsigned char b=0;
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;
146 return b;
149 static void
150 read_ser_drv(unsigned char addr, unsigned char *buf, int count)
152 int i;
153 #ifdef RTC_DEBUG
154 char *foo = buf;
155 #endif
157 DPRINTF("READ 0x%x bytes @ 0x%x [ ", count, addr);
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);
170 DUMP(foo, count);
173 static void
174 write_ser_drv(unsigned char addr, unsigned char *buf, int count)
176 int i;
178 DPRINTF("WRITE 0x%x bytes @ 0x%x [ ", count, addr);
179 DUMP(buf, count);
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);
191 void
192 rtc_init(void)
194 struct ds1302_st bbclk;
195 unsigned char b;
196 int mod;
198 DPRINTF("init\n");
200 rtc_go_output(DATA|SCLK|RST);
202 /* disable write protect */
203 b = 0;
204 write_ser_drv(0x8e,&b,1);
206 /* enable trickle */
207 b = 0xa5; /* 1010.0101 */
208 write_ser_drv(0x90,&b,1);
210 /* read burst */
211 read_ser_drv(0xbe, (unsigned char *)&bbclk, 8);
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;
221 if (bbclk.fmt) {
222 printf("ds1302: Clock was in 12 hour mode, fixing\n");
223 bbclk.fmt=0;
224 mod=1;
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;
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);
244 DPRINTF("init done\n");
246 ds1302_initted=1;
249 void
250 rtc_reset(void)
252 if(!ds1302_initted) rtc_init();
253 /* TODO */
256 void
257 rtc_get(struct rtc_time *tmp)
259 struct ds1302_st bbclk;
261 if(!ds1302_initted) rtc_init();
263 read_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* read burst */
265 if (bbclk.CH) {
266 printf("ds1302: rtc_get: Clock was halted, clock probably "
267 "corrupt\n");
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;
278 tmp->tm_yday = 0;
279 tmp->tm_isdst= 0;
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 );
286 void
287 rtc_set(struct rtc_time *tmp)
289 struct ds1302_st bbclk;
290 unsigned char b=0;
292 if(!ds1302_initted) rtc_init();
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);
298 memset(&bbclk,0,sizeof(bbclk));
299 bbclk.CH=0; /* dont halt */
300 bbclk.WP=1; /* write protect when we're done */
302 bbclk.sec10=tmp->tm_sec/10;
303 bbclk.sec=tmp->tm_sec%10;
305 bbclk.min10=tmp->tm_min/10;
306 bbclk.min=tmp->tm_min%10;
308 bbclk.hr10=tmp->tm_hour/10;
309 bbclk.hr=tmp->tm_hour%10;
311 bbclk.day=tmp->tm_wday;
313 bbclk.date10=tmp->tm_mday/10;
314 bbclk.date=tmp->tm_mday%10;
316 bbclk.month10=tmp->tm_mon/10;
317 bbclk.month=tmp->tm_mon%10;
319 tmp->tm_year -= 1900;
320 bbclk.year10=tmp->tm_year/10;
321 bbclk.year=tmp->tm_year%10;
323 write_ser_drv(0x8e,&b,1); /* disable write protect */
324 write_ser_drv(0xbe,(unsigned char *)&bbclk, 8); /* write burst */
327 #endif