xref: /openbmc/u-boot/drivers/rtc/ds1302.c (revision ad5b5801)
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_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 int
257 rtc_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);      /* read burst */
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 
290 int 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; /* dont halt */
303 	bbclk.WP=1; /* write protect when we're done */
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);           /* disable write protect */
327 	write_ser_drv(0xbe,(unsigned char *)&bbclk, 8);     /* write burst */
328 
329 	return 0;
330 }
331 
332 #endif
333