xref: /OK3568_Linux_fs/u-boot/drivers/rtc/ds1306.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * (C) Copyright 2002 SIXNET, dge@sixnetio.com.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * (C) Copyright 2004, Li-Pro.Net <www.li-pro.net>
5*4882a593Smuzhiyun  * Stephan Linz <linz@li-pro.net>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun /*
11*4882a593Smuzhiyun  * Date & Time support for DS1306 RTC using SPI:
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  *    - SXNI855T:    it uses its own soft SPI here in this file
14*4882a593Smuzhiyun  *    - all other:   use the external spi_xfer() function
15*4882a593Smuzhiyun  *                   (see include/spi.h)
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <common.h>
19*4882a593Smuzhiyun #include <command.h>
20*4882a593Smuzhiyun #include <rtc.h>
21*4882a593Smuzhiyun #include <spi.h>
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #if defined(CONFIG_CMD_DATE)
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #define	RTC_SECONDS		0x00
26*4882a593Smuzhiyun #define	RTC_MINUTES		0x01
27*4882a593Smuzhiyun #define	RTC_HOURS		0x02
28*4882a593Smuzhiyun #define	RTC_DAY_OF_WEEK		0x03
29*4882a593Smuzhiyun #define	RTC_DATE_OF_MONTH	0x04
30*4882a593Smuzhiyun #define	RTC_MONTH		0x05
31*4882a593Smuzhiyun #define	RTC_YEAR		0x06
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #define	RTC_SECONDS_ALARM0	0x07
34*4882a593Smuzhiyun #define	RTC_MINUTES_ALARM0	0x08
35*4882a593Smuzhiyun #define	RTC_HOURS_ALARM0	0x09
36*4882a593Smuzhiyun #define	RTC_DAY_OF_WEEK_ALARM0	0x0a
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define	RTC_SECONDS_ALARM1	0x0b
39*4882a593Smuzhiyun #define	RTC_MINUTES_ALARM1	0x0c
40*4882a593Smuzhiyun #define	RTC_HOURS_ALARM1	0x0d
41*4882a593Smuzhiyun #define	RTC_DAY_OF_WEEK_ALARM1	0x0e
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define	RTC_CONTROL		0x0f
44*4882a593Smuzhiyun #define	RTC_STATUS		0x10
45*4882a593Smuzhiyun #define	RTC_TRICKLE_CHARGER	0x11
46*4882a593Smuzhiyun 
47*4882a593Smuzhiyun #define	RTC_USER_RAM_BASE	0x20
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun /* ************************************************************************* */
50*4882a593Smuzhiyun #ifdef CONFIG_SXNI855T		/* !!! SHOULD BE CHANGED TO NEW CODE !!! */
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun static void soft_spi_send (unsigned char n);
53*4882a593Smuzhiyun static unsigned char soft_spi_read (void);
54*4882a593Smuzhiyun static void init_spi (void);
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun /*-----------------------------------------------------------------------
57*4882a593Smuzhiyun  * Definitions
58*4882a593Smuzhiyun  */
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define	PB_SPISCK	0x00000002	/* PB 30 */
61*4882a593Smuzhiyun #define PB_SPIMOSI	0x00000004	/* PB 29 */
62*4882a593Smuzhiyun #define PB_SPIMISO	0x00000008	/* PB 28 */
63*4882a593Smuzhiyun #define PB_SPI_CE	0x00010000	/* PB 15 */
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun /* read clock time from DS1306 and return it in *tmp */
rtc_get(struct rtc_time * tmp)68*4882a593Smuzhiyun int rtc_get (struct rtc_time *tmp)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
71*4882a593Smuzhiyun 	unsigned char spi_byte;	/* Data Byte */
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	init_spi ();		/* set port B for software SPI */
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	/* Now we can enable the DS1306 RTC */
76*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdat |= PB_SPI_CE;
77*4882a593Smuzhiyun 	udelay (10);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	/* Shift out the address (0) of the time in the Clock Chip */
80*4882a593Smuzhiyun 	soft_spi_send (0);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	/* Put the clock readings into the rtc_time structure */
83*4882a593Smuzhiyun 	tmp->tm_sec = bcd2bin (soft_spi_read ());	/* Read seconds */
84*4882a593Smuzhiyun 	tmp->tm_min = bcd2bin (soft_spi_read ());	/* Read minutes */
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	/* Hours are trickier */
87*4882a593Smuzhiyun 	spi_byte = soft_spi_read ();	/* Read Hours into temporary value */
88*4882a593Smuzhiyun 	if (spi_byte & 0x40) {
89*4882a593Smuzhiyun 		/* 12 hour mode bit is set (time is in 1-12 format) */
90*4882a593Smuzhiyun 		if (spi_byte & 0x20) {
91*4882a593Smuzhiyun 			/* since PM we add 11 to get 0-23 for hours */
92*4882a593Smuzhiyun 			tmp->tm_hour = (bcd2bin (spi_byte & 0x1F)) + 11;
93*4882a593Smuzhiyun 		} else {
94*4882a593Smuzhiyun 			/* since AM we subtract 1 to get 0-23 for hours */
95*4882a593Smuzhiyun 			tmp->tm_hour = (bcd2bin (spi_byte & 0x1F)) - 1;
96*4882a593Smuzhiyun 		}
97*4882a593Smuzhiyun 	} else {
98*4882a593Smuzhiyun 		/* Otherwise, 0-23 hour format */
99*4882a593Smuzhiyun 		tmp->tm_hour = (bcd2bin (spi_byte & 0x3F));
100*4882a593Smuzhiyun 	}
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	soft_spi_read ();	/* Read and discard Day of week */
103*4882a593Smuzhiyun 	tmp->tm_mday = bcd2bin (soft_spi_read ());	/* Read Day of the Month */
104*4882a593Smuzhiyun 	tmp->tm_mon = bcd2bin (soft_spi_read ());	/* Read Month */
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	/* Read Year and convert to this century */
107*4882a593Smuzhiyun 	tmp->tm_year = bcd2bin (soft_spi_read ()) + 2000;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	/* Now we can disable the DS1306 RTC */
110*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;	/* Disable DS1306 Chip */
111*4882a593Smuzhiyun 	udelay (10);
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	rtc_calc_weekday(tmp);	/* Determine the day of week */
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	debug ("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
116*4882a593Smuzhiyun 	       tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
117*4882a593Smuzhiyun 	       tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun /* set clock time in DS1306 RTC and in MPC8xx RTC */
rtc_set(struct rtc_time * tmp)125*4882a593Smuzhiyun int rtc_set (struct rtc_time *tmp)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	init_spi ();		/* set port B for software SPI */
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	/* Now we can enable the DS1306 RTC */
132*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdat |= PB_SPI_CE;	/* Enable DS1306 Chip */
133*4882a593Smuzhiyun 	udelay (10);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	/* First disable write protect in the clock chip control register */
136*4882a593Smuzhiyun 	soft_spi_send (0x8F);	/* send address of the control register */
137*4882a593Smuzhiyun 	soft_spi_send (0x00);	/* send control register contents */
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	/* Now disable the DS1306 to terminate the write */
140*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;
141*4882a593Smuzhiyun 	udelay (10);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	/* Now enable the DS1306 to initiate a new write */
144*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdat |= PB_SPI_CE;
145*4882a593Smuzhiyun 	udelay (10);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/* Next, send the address of the clock time write registers */
148*4882a593Smuzhiyun 	soft_spi_send (0x80);	/* send address of the first time register */
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	/* Use Burst Mode to send all of the time data to the clock */
151*4882a593Smuzhiyun 	bin2bcd (tmp->tm_sec);
152*4882a593Smuzhiyun 	soft_spi_send (bin2bcd (tmp->tm_sec));	/* Send Seconds */
153*4882a593Smuzhiyun 	soft_spi_send (bin2bcd (tmp->tm_min));	/* Send Minutes */
154*4882a593Smuzhiyun 	soft_spi_send (bin2bcd (tmp->tm_hour));	/* Send Hour */
155*4882a593Smuzhiyun 	soft_spi_send (bin2bcd (tmp->tm_wday));	/* Send Day of the Week */
156*4882a593Smuzhiyun 	soft_spi_send (bin2bcd (tmp->tm_mday));	/* Send Day of Month */
157*4882a593Smuzhiyun 	soft_spi_send (bin2bcd (tmp->tm_mon));	/* Send Month */
158*4882a593Smuzhiyun 	soft_spi_send (bin2bcd (tmp->tm_year - 2000));	/* Send Year */
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	/* Now we can disable the Clock chip to terminate the burst write */
161*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;	/* Disable DS1306 Chip */
162*4882a593Smuzhiyun 	udelay (10);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	/* Now we can enable the Clock chip to initiate a new write */
165*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdat |= PB_SPI_CE;	/* Enable DS1306 Chip */
166*4882a593Smuzhiyun 	udelay (10);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	/* First we Enable write protect in the clock chip control register */
169*4882a593Smuzhiyun 	soft_spi_send (0x8F);	/* send address of the control register */
170*4882a593Smuzhiyun 	soft_spi_send (0x40);	/* send out Control Register contents */
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	/* Now disable the DS1306 */
173*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdat &= ~PB_SPI_CE;	/*  Disable DS1306 Chip */
174*4882a593Smuzhiyun 	udelay (10);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	/* Set standard MPC8xx clock to the same time so Linux will
177*4882a593Smuzhiyun 	 * see the time even if it doesn't have a DS1306 clock driver.
178*4882a593Smuzhiyun 	 * This helps with experimenting with standard kernels.
179*4882a593Smuzhiyun 	 */
180*4882a593Smuzhiyun 	{
181*4882a593Smuzhiyun 		ulong tim;
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 		tim = rtc_mktime(tmp);
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 		immap->im_sitk.sitk_rtck = KAPWR_KEY;
186*4882a593Smuzhiyun 		immap->im_sit.sit_rtc = tim;
187*4882a593Smuzhiyun 	}
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	debug ("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
190*4882a593Smuzhiyun 	       tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
191*4882a593Smuzhiyun 	       tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	return 0;
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun /* Initialize Port B for software SPI */
init_spi(void)199*4882a593Smuzhiyun static void init_spi (void)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun 	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	/* Force output pins to begin at logic 0 */
204*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdat &= ~(PB_SPI_CE | PB_SPIMOSI | PB_SPISCK);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	/* Set these 3 signals as outputs */
207*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdir |= (PB_SPIMOSI | PB_SPI_CE | PB_SPISCK);
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	immap->im_cpm.cp_pbdir &= ~PB_SPIMISO;	/* Make MISO pin an input */
210*4882a593Smuzhiyun 	udelay (10);
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun /* NOTE: soft_spi_send() assumes that the I/O lines are configured already */
soft_spi_send(unsigned char n)216*4882a593Smuzhiyun static void soft_spi_send (unsigned char n)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun 	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
219*4882a593Smuzhiyun 	unsigned char bitpos;	/* bit position to receive */
220*4882a593Smuzhiyun 	unsigned char i;	/* Loop Control */
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	/* bit position to send, start with most significant bit */
223*4882a593Smuzhiyun 	bitpos = 0x80;
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	/* Send 8 bits to software SPI */
226*4882a593Smuzhiyun 	for (i = 0; i < 8; i++) {	/* Loop for 8 bits */
227*4882a593Smuzhiyun 		immap->im_cpm.cp_pbdat |= PB_SPISCK;	/* Raise SCK */
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 		if (n & bitpos)
230*4882a593Smuzhiyun 			immap->im_cpm.cp_pbdat |= PB_SPIMOSI;	/* Set MOSI to 1 */
231*4882a593Smuzhiyun 		else
232*4882a593Smuzhiyun 			immap->im_cpm.cp_pbdat &= ~PB_SPIMOSI;	/* Set MOSI to 0 */
233*4882a593Smuzhiyun 		udelay (10);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 		immap->im_cpm.cp_pbdat &= ~PB_SPISCK;	/* Lower SCK */
236*4882a593Smuzhiyun 		udelay (10);
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 		bitpos >>= 1;	/* Shift for next bit position */
239*4882a593Smuzhiyun 	}
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun /* NOTE: soft_spi_read() assumes that the I/O lines are configured already */
soft_spi_read(void)245*4882a593Smuzhiyun static unsigned char soft_spi_read (void)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	volatile immap_t *immap = (immap_t *) CONFIG_SYS_IMMR;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	unsigned char spi_byte = 0;	/* Return value, assume success */
250*4882a593Smuzhiyun 	unsigned char bitpos;	/* bit position to receive */
251*4882a593Smuzhiyun 	unsigned char i;	/* Loop Control */
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun 	/* bit position to receive, start with most significant bit */
254*4882a593Smuzhiyun 	bitpos = 0x80;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	/* Read 8 bits here */
257*4882a593Smuzhiyun 	for (i = 0; i < 8; i++) {	/* Do 8 bits in loop */
258*4882a593Smuzhiyun 		immap->im_cpm.cp_pbdat |= PB_SPISCK;	/* Raise SCK */
259*4882a593Smuzhiyun 		udelay (10);
260*4882a593Smuzhiyun 		if (immap->im_cpm.cp_pbdat & PB_SPIMISO)	/* Get a bit of data */
261*4882a593Smuzhiyun 			spi_byte |= bitpos;	/* Set data accordingly */
262*4882a593Smuzhiyun 		immap->im_cpm.cp_pbdat &= ~PB_SPISCK;	/* Lower SCK */
263*4882a593Smuzhiyun 		udelay (10);
264*4882a593Smuzhiyun 		bitpos >>= 1;	/* Shift for next bit position */
265*4882a593Smuzhiyun 	}
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	return spi_byte;	/* Return the byte read */
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
271*4882a593Smuzhiyun 
rtc_reset(void)272*4882a593Smuzhiyun void rtc_reset (void)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	return;			/* nothing to do */
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun #else  /* not CONFIG_SXNI855T */
278*4882a593Smuzhiyun /* ************************************************************************* */
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun static unsigned char rtc_read (unsigned char reg);
281*4882a593Smuzhiyun static void rtc_write (unsigned char reg, unsigned char val);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun static struct spi_slave *slave;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun /* read clock time from DS1306 and return it in *tmp */
rtc_get(struct rtc_time * tmp)286*4882a593Smuzhiyun int rtc_get (struct rtc_time *tmp)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	unsigned char sec, min, hour, mday, wday, mon, year;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	/*
291*4882a593Smuzhiyun 	 * Assuming Vcc = 2.0V (lowest speed)
292*4882a593Smuzhiyun 	 *
293*4882a593Smuzhiyun 	 * REVISIT: If we add an rtc_init() function we can do this
294*4882a593Smuzhiyun 	 * step just once.
295*4882a593Smuzhiyun 	 */
296*4882a593Smuzhiyun 	if (!slave) {
297*4882a593Smuzhiyun 		slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
298*4882a593Smuzhiyun 				SPI_MODE_3 | SPI_CS_HIGH);
299*4882a593Smuzhiyun 		if (!slave)
300*4882a593Smuzhiyun 			return;
301*4882a593Smuzhiyun 	}
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	if (spi_claim_bus(slave))
304*4882a593Smuzhiyun 		return;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	sec = rtc_read (RTC_SECONDS);
307*4882a593Smuzhiyun 	min = rtc_read (RTC_MINUTES);
308*4882a593Smuzhiyun 	hour = rtc_read (RTC_HOURS);
309*4882a593Smuzhiyun 	mday = rtc_read (RTC_DATE_OF_MONTH);
310*4882a593Smuzhiyun 	wday = rtc_read (RTC_DAY_OF_WEEK);
311*4882a593Smuzhiyun 	mon = rtc_read (RTC_MONTH);
312*4882a593Smuzhiyun 	year = rtc_read (RTC_YEAR);
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	spi_release_bus(slave);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	debug ("Get RTC year: %02x mon: %02x mday: %02x wday: %02x "
317*4882a593Smuzhiyun 	       "hr: %02x min: %02x sec: %02x\n",
318*4882a593Smuzhiyun 	       year, mon, mday, wday, hour, min, sec);
319*4882a593Smuzhiyun 	debug ("Alarms[0]: wday: %02x hour: %02x min: %02x sec: %02x\n",
320*4882a593Smuzhiyun 	       rtc_read (RTC_DAY_OF_WEEK_ALARM0),
321*4882a593Smuzhiyun 	       rtc_read (RTC_HOURS_ALARM0),
322*4882a593Smuzhiyun 	       rtc_read (RTC_MINUTES_ALARM0), rtc_read (RTC_SECONDS_ALARM0));
323*4882a593Smuzhiyun 	debug ("Alarms[1]: wday: %02x hour: %02x min: %02x sec: %02x\n",
324*4882a593Smuzhiyun 	       rtc_read (RTC_DAY_OF_WEEK_ALARM1),
325*4882a593Smuzhiyun 	       rtc_read (RTC_HOURS_ALARM1),
326*4882a593Smuzhiyun 	       rtc_read (RTC_MINUTES_ALARM1), rtc_read (RTC_SECONDS_ALARM1));
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	tmp->tm_sec = bcd2bin (sec & 0x7F);	/* convert Seconds */
329*4882a593Smuzhiyun 	tmp->tm_min = bcd2bin (min & 0x7F);	/* convert Minutes */
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 	/* convert Hours */
332*4882a593Smuzhiyun 	tmp->tm_hour = (hour & 0x40)
333*4882a593Smuzhiyun 		? ((hour & 0x20)	/* 12 hour mode */
334*4882a593Smuzhiyun 		   ? bcd2bin (hour & 0x1F) + 11	/* PM */
335*4882a593Smuzhiyun 		   : bcd2bin (hour & 0x1F) - 1	/* AM */
336*4882a593Smuzhiyun 		)
337*4882a593Smuzhiyun 		: bcd2bin (hour & 0x3F);	/* 24 hour mode */
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	tmp->tm_mday = bcd2bin (mday & 0x3F);	/* convert Day of the Month */
340*4882a593Smuzhiyun 	tmp->tm_mon = bcd2bin (mon & 0x1F);	/* convert Month */
341*4882a593Smuzhiyun 	tmp->tm_year = bcd2bin (year) + 2000;	/* convert Year */
342*4882a593Smuzhiyun 	tmp->tm_wday = bcd2bin (wday & 0x07) - 1;	/* convert Day of the Week */
343*4882a593Smuzhiyun 	tmp->tm_yday = 0;
344*4882a593Smuzhiyun 	tmp->tm_isdst = 0;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	debug ("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
347*4882a593Smuzhiyun 	       tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
348*4882a593Smuzhiyun 	       tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	return 0;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun /* set clock time from *tmp in DS1306 RTC */
rtc_set(struct rtc_time * tmp)356*4882a593Smuzhiyun int rtc_set (struct rtc_time *tmp)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun 	/* Assuming Vcc = 2.0V (lowest speed) */
359*4882a593Smuzhiyun 	if (!slave) {
360*4882a593Smuzhiyun 		slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
361*4882a593Smuzhiyun 				SPI_MODE_3 | SPI_CS_HIGH);
362*4882a593Smuzhiyun 		if (!slave)
363*4882a593Smuzhiyun 			return;
364*4882a593Smuzhiyun 	}
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	if (spi_claim_bus(slave))
367*4882a593Smuzhiyun 		return;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	debug ("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
370*4882a593Smuzhiyun 	       tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
371*4882a593Smuzhiyun 	       tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	rtc_write (RTC_SECONDS, bin2bcd (tmp->tm_sec));
374*4882a593Smuzhiyun 	rtc_write (RTC_MINUTES, bin2bcd (tmp->tm_min));
375*4882a593Smuzhiyun 	rtc_write (RTC_HOURS, bin2bcd (tmp->tm_hour));
376*4882a593Smuzhiyun 	rtc_write (RTC_DAY_OF_WEEK, bin2bcd (tmp->tm_wday + 1));
377*4882a593Smuzhiyun 	rtc_write (RTC_DATE_OF_MONTH, bin2bcd (tmp->tm_mday));
378*4882a593Smuzhiyun 	rtc_write (RTC_MONTH, bin2bcd (tmp->tm_mon));
379*4882a593Smuzhiyun 	rtc_write (RTC_YEAR, bin2bcd (tmp->tm_year - 2000));
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	spi_release_bus(slave);
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun /* reset the DS1306 */
rtc_reset(void)387*4882a593Smuzhiyun void rtc_reset (void)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun 	/* Assuming Vcc = 2.0V (lowest speed) */
390*4882a593Smuzhiyun 	if (!slave) {
391*4882a593Smuzhiyun 		slave = spi_setup_slave(0, CONFIG_SYS_SPI_RTC_DEVID, 600000,
392*4882a593Smuzhiyun 				SPI_MODE_3 | SPI_CS_HIGH);
393*4882a593Smuzhiyun 		if (!slave)
394*4882a593Smuzhiyun 			return;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	if (spi_claim_bus(slave))
398*4882a593Smuzhiyun 		return;
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	/* clear the control register */
401*4882a593Smuzhiyun 	rtc_write (RTC_CONTROL, 0x00);	/* 1st step: reset WP */
402*4882a593Smuzhiyun 	rtc_write (RTC_CONTROL, 0x00);	/* 2nd step: reset 1Hz, AIE1, AIE0 */
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun 	/* reset all alarms */
405*4882a593Smuzhiyun 	rtc_write (RTC_SECONDS_ALARM0, 0x00);
406*4882a593Smuzhiyun 	rtc_write (RTC_SECONDS_ALARM1, 0x00);
407*4882a593Smuzhiyun 	rtc_write (RTC_MINUTES_ALARM0, 0x00);
408*4882a593Smuzhiyun 	rtc_write (RTC_MINUTES_ALARM1, 0x00);
409*4882a593Smuzhiyun 	rtc_write (RTC_HOURS_ALARM0, 0x00);
410*4882a593Smuzhiyun 	rtc_write (RTC_HOURS_ALARM1, 0x00);
411*4882a593Smuzhiyun 	rtc_write (RTC_DAY_OF_WEEK_ALARM0, 0x00);
412*4882a593Smuzhiyun 	rtc_write (RTC_DAY_OF_WEEK_ALARM1, 0x00);
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	spi_release_bus(slave);
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
418*4882a593Smuzhiyun 
rtc_read(unsigned char reg)419*4882a593Smuzhiyun static unsigned char rtc_read (unsigned char reg)
420*4882a593Smuzhiyun {
421*4882a593Smuzhiyun 	int ret;
422*4882a593Smuzhiyun 
423*4882a593Smuzhiyun 	ret = spi_w8r8(slave, reg);
424*4882a593Smuzhiyun 	return ret < 0 ? 0 : ret;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun /* ------------------------------------------------------------------------- */
428*4882a593Smuzhiyun 
rtc_write(unsigned char reg,unsigned char val)429*4882a593Smuzhiyun static void rtc_write (unsigned char reg, unsigned char val)
430*4882a593Smuzhiyun {
431*4882a593Smuzhiyun 	unsigned char dout[2];	/* SPI Output Data Bytes */
432*4882a593Smuzhiyun 	unsigned char din[2];	/* SPI Input Data Bytes */
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	dout[0] = 0x80 | reg;
435*4882a593Smuzhiyun 	dout[1] = val;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	spi_xfer (slave, 16, dout, din, SPI_XFER_BEGIN | SPI_XFER_END);
438*4882a593Smuzhiyun }
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun #endif /* end of code exclusion (see #ifdef CONFIG_SXNI855T above) */
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun #endif
443