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